[coaps] CoAP Secure Client/Server accessible through OT API (#2716)

This commit is contained in:
Christian Stauffer
2018-09-24 11:22:08 -10:00
committed by Jonathan Hui
parent 5fe9038e33
commit 2ce47a8e9c
28 changed files with 2838 additions and 45 deletions
+1
View File
@@ -52,6 +52,7 @@ set -x
--with-ncp-bus=uart \
--with-examples=posix \
--enable-application-coap \
--enable-application-coap-secure \
--enable-border-router \
--enable-cert-log \
--enable-child-supervision \
+33 -1
View File
@@ -764,6 +764,37 @@ AC_SUBST(OPENTHREAD_ENABLE_MTD_NETWORK_DIAGNOSTIC)
AM_CONDITIONAL([OPENTHREAD_ENABLE_MTD_NETWORK_DIAGNOSTIC], [test "${enable_mtd_network_diagnostic}" = "yes"])
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_MTD_NETWORK_DIAGNOSTIC],[${OPENTHREAD_ENABLE_MTD_NETWORK_DIAGNOSTIC}],[Define to 1 to enable network diagnostic for MTD.])
#
# Application CoAP Secure
#
AC_ARG_ENABLE(application_coap_secure,
[AS_HELP_STRING([--enable-application-coap-secure],[Enable CoAP Secure to an application.@<:@default=no@:>@.])],
[
case "${enableval}" in
no|yes)
enable_application_coap_secure=${enableval}
;;
*)
AC_MSG_ERROR([Invalid value ${enable_application_coap_secure} for --enable-application-coap_secure])
;;
esac
],
[enable_application_coap_secure=no])
if test "$enable_application_coap_secure" = "yes"; then
OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE=1
enable_application_coap="yes"
else
OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE=0
fi
AC_SUBST(OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE)
AM_CONDITIONAL([OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE], [test "${enable_application_coap_secure}" = "yes"])
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE],[${OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE}],[Define to 1 if you want to enable CoAP Secure to an application.])
#
# Thread Commissioner
#
@@ -828,7 +859,7 @@ AC_SUBST(OPENTHREAD_ENABLE_JOINER)
AM_CONDITIONAL([OPENTHREAD_ENABLE_JOINER], [test "${enable_joiner}" = "yes"])
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_JOINER],[${OPENTHREAD_ENABLE_JOINER}],[Define to 1 to enable the joiner role.])
if test "${enable_commissioner}" = "yes" -o "${enable_joiner}" = "yes" -o "${enable_border_agent}" = "yes"; then
if test "${enable_commissioner}" = "yes" -o "${enable_joiner}" = "yes" -o "${enable_border_agent}" = "yes" -o "${enable_application_coap_secure}" = "yes"; then
enable_dtls="yes"
OPENTHREAD_ENABLE_DTLS=1
else
@@ -1787,6 +1818,7 @@ AC_MSG_NOTICE([
OpenThread DHCPv6 Client support : ${enable_dhcp6_client}
OpenThread DNS Client support : ${enable_dns_client}
OpenThread Application CoAP support : ${enable_application_coap}
OpenThread Application CoAP Secure support: ${enable_application_coap_secure}
OpenThread Raw Link-Layer support : ${enable_raw_link_api}
OpenThread Border Agent support : ${enable_border_agent}
OpenThread Border Router support : ${enable_border_router}
+4
View File
@@ -43,6 +43,10 @@ ifeq ($(COAP),1)
configure_OPTIONS += --enable-application-coap
endif
ifeq ($(COAPS),1)
configure_OPTIONS += --enable-application-coap-secure
endif
ifeq ($(COMMISSIONER),1)
configure_OPTIONS += --enable-commissioner
endif
+1
View File
@@ -51,6 +51,7 @@ openthread_headers = \
channel_monitor.h \
child_supervision.h \
cli.h \
coap_secure.h \
coap.h \
commissioner.h \
config.h \
+13
View File
@@ -160,6 +160,9 @@ typedef enum otCoapOptionContentFormat {
OT_COAP_OPTION_CONTENT_FORMAT_OCTET_STREAM = 42, ///< application/octet-stream
OT_COAP_OPTION_CONTENT_FORMAT_EXI = 47, ///< application/exi
OT_COAP_OPTION_CONTENT_FORMAT_JSON = 50, ///< application/json
OT_COAP_OPTION_CONTENT_FORMAT_PKCS10 = 70, ///< application/pkcs10
OT_COAP_OPTION_CONTENT_FORMAT_PKCS7 = 80, ///< application/pkcs7
OT_COAP_OPTION_CONTENT_FORMAT_JWS = 101 ///< application/json-web-signature
} otCoapOptionContentFormat;
#define OT_COAP_HEADER_MAX_LENGTH 128 ///< Max CoAP header length (bytes)
@@ -402,6 +405,16 @@ otCoapType otCoapHeaderGetType(const otCoapHeader *aHeader);
*/
otCoapCode otCoapHeaderGetCode(const otCoapHeader *aHeader);
/**
* This method returns the CoAP Code as human readable string.
*
* @param[in] aHeader A pointer to the CoAP header.
*
* @ returns The CoAP Code as string.
*
*/
const char *otCoapHeaderCodeToString(const otCoapHeader *aHeader);
/**
* This function returns the Message ID value.
*
+324
View File
@@ -0,0 +1,324 @@
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief
* This file defines the top-level functions for the OpenThread CoAP Secure implementation.
*
* @note
* To enable cipher suite DTLS_PSK_WITH_AES_128_CCM_8, MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
* must be enabled in mbedtls-config.h
* To enable cipher suite DTLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED must be enabled in mbedtls-config.h.
*/
#ifndef OPENTHREAD_COAP_SECURE_H_
#define OPENTHREAD_COAP_SECURE_H_
#include <stdint.h>
#include <openthread/coap.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup api-coap-secure
*
* @brief
* This module includes functions that control CoAP Secure (CoAP over DTLS) communication.
*
* The functions in this module are available when application-coap-secure feature
* (`OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE`) is enabled.
*
* @{
*
*/
#define OT_DEFAULT_COAP_SECURE_PORT 5684 ///< Default CoAP Secure port, as specified in RFC 7252
/**
* This function pointer is called when the DTLS connection state changes.
*
* @param[in] aConnected true, if a connection was established, false otherwise.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
typedef void (*otHandleCoapSecureClientConnect)(bool aConnected, void *aContext);
/**
* This function starts the CoAP Secure service.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aPort The local UDP port to bind to.
* @param[in] aContext A pointer to arbitrary context information.
*
* @retval OT_ERROR_NONE Successfully started the CoAP Secure server.
*
*/
otError otCoapSecureStart(otInstance *aInstance, uint16_t aPort, void *aContext);
/**
* This function stops the CoAP Secure server.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval OT_ERROR_NONE Successfully stopped the CoAP Secure server.
*/
otError otCoapSecureStop(otInstance *aInstance);
/**
* This method sets the Pre-Shared Key (PSK) and cipher suite
* DTLS_PSK_WITH_AES_128_CCM_8.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aPSK A pointer to the PSK.
* @param[in] aPskLength The PSK length.
* @param[in] aPskIdentity The Identity Name for the PSK.
* @param[in] aPskIdLength The PSK Identity Length.
*
* @retval OT_ERROR_NONE Successfully set the PSK.
* @retval OT_ERROR_INVALID_ARGS The PSK is invalid.
* @retval OT_ERROR_DISABLED_FEATURE Mbedtls config not enabled
* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
*
*/
otError otCoapSecureSetPsk(otInstance * aInstance,
const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength);
/**
* This method returns the peer x509 certificate base64 encoded.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[out] aPeerCert A pointer to the base64 encoded certificate buffer.
* @param[out] aCertLength The length of the base64 encoded peer certificate.
* @param[in] aCertBufferSize The buffer size of aPeerCert.
*
* @retval OT_ERROR_NONE Successfully get the peer certificate.
* @retval OT_ERROR_DISABLED_FEATURE Mbedtls config not enabled MBEDTLS_BASE64_C.
*
*/
otError otCoapSecureGetPeerCertificateBase64(otInstance * aInstance,
unsigned char *aPeerCert,
uint64_t * aCertLength,
uint64_t aCertBufferSize);
/**
* This method sets the authentication mode for the coap secure connection.
*
* Disable or enable the verification of peer certificate.
* Must be called before start.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aVerifyPeerCertificate true, to verify the peer certificate.
*
*/
void otCoapSecureSetSslAuthMode(otInstance *aInstance, bool aVerifyPeerCertificate);
/**
* This method sets the local device's X509 certificate with corresponding private key for
* DTLS session with DTLS_ECDHE_ECDSA_WITH_AES_128_CCM_8.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aX509Certificate A pointer to the PEM formatted X509 certificate.
* @param[in] aX509Length The length of certificate.
* @param[in] aPrivateKey A pointer to the PEM formatted private key.
* @param[in] aPrivateKeyLength The length of the private key.
*
* @retval OT_ERROR_NONE Successfully set the x509 certificate
* with his private key.
* @retval OT_ERROR_DISABLED_FEATURE Mbedtls config not enabled
* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED.
*
*/
otError otCoapSecureSetCertificate(otInstance * aInstance,
const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength);
/**
* This method sets the trusted top level CAs. It is needed for validating the
* certificate of the peer.
*
* DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aX509CaCertificateChain A pointer to the PEM formatted X509 CA chain.
* @param[in] aX509CaCertChainLength The length of chain.
*
* @retval OT_ERROR_NONE Successfully set the the trusted top level CAs.
*
*/
otError otCoapSecureSetCaCertificateChain(otInstance * aInstance,
const uint8_t *aX509CaCertificateChain,
uint32_t aX509CaCertChainLength);
/**
* This method initializes DTLS session with a peer.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMessageInfo A pointer to a message info structure.
* @param[in] aCallback A pointer to a function that will be called when the DTLS connection
* state changes.
* @param[in] aContext A pointer to arbitrary context information.
*
* @retval OT_ERROR_NONE Successfully started DTLS connection.
*
*/
otError otCoapSecureConnect(otInstance * aInstance,
const otMessageInfo * aMessageInfo,
otHandleCoapSecureClientConnect aHandler,
void * aContext);
/**
* This method stops the DTLS connection.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval OT_ERROR_NONE Successfully stopped the DTLS connection.
*
*/
otError otCoapSecureDisconnect(otInstance *aInstance);
/**
* This method indicates whether or not the DTLS session is connected.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval TRUE The DTLS session is connected.
* @retval FALSE The DTLS session is not connected.
*
*/
bool otCoapSecureIsConnected(otInstance *aInstance);
/**
* This method indicates whether or not the DTLS session is active.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval TRUE If DTLS session is active.
* @retval FALSE If DTLS session is not active.
*
*/
bool otCoapSecureIsConncetionActive(otInstance *aInstance);
/**
* This method sends a CoAP request over secure DTLS connection.
*
* If a response for a request is expected, respective function and context information should be provided.
* If no response is expected, these arguments should be NULL pointers.
* If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMessage A reference to the message to send.
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
* @param[in] aContext A pointer to arbitrary context information.
*
* @retval OT_ERROR_NONE Successfully sent CoAP message.
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
* @retvak OT_ERROR_INVALID_STATE DTLS connection was not initialized.
*
*/
otError otCoapSecureSendRequest(otInstance * aInstance,
otMessage * aMessage,
otCoapResponseHandler aHandler,
void * aContext);
/**
* This function adds a resource to the CoAP Secure server.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aResource A pointer to the resource.
*
* @retval OT_ERROR_NONE Successfully added @p aResource.
* @retval OT_ERROR_ALREADY The @p aResource was already added.
*
*/
otError otCoapSecureAddResource(otInstance *aInstance, otCoapResource *aResource);
/**
* This function removes a resource from the CoAP Secure server.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aResource A pointer to the resource.
*
*/
void otCoapSecureRemoveResource(otInstance *aInstance, otCoapResource *aResource);
/**
* This function sets the default handler for unhandled CoAP Secure requests.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aHandler A function pointer that shall be called when an unhandled request arrives.
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
*
*/
void otCoapSecureSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext);
/**
* This method sets the connected callback to indicate, when
* a Client connect to the CoAP Secure server.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMessageInfo A pointer to a message info structure.
* @param[in] aHandler A pointer to a function that will be called once DTLS connection is established.
*
*/
void otCoapSecureSetClientConnectedCallback(otInstance * aInstance,
otHandleCoapSecureClientConnect aHandler,
void * aContext);
/**
* This function sends a CoAP response from the CoAP Secure server.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMessage A pointer to the CoAP response to send.
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
*
* @retval OT_ERROR_NONE Successfully enqueued the CoAP response message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response.
*
*/
otError otCoapSecureSendResponse(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo);
/**
* @}
*
*/
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OPENTHREAD_COAP_SECURE_H_ */
+2
View File
@@ -144,6 +144,7 @@ libopenthread_cli_ftd_a_CPPFLAGS = \
SOURCES_COMMON = \
cli.cpp \
cli_coap.cpp \
cli_coap_secure.cpp \
cli_console.cpp \
cli_dataset.cpp \
cli_uart.cpp \
@@ -161,6 +162,7 @@ libopenthread_cli_mtd_a_SOURCES = \
noinst_HEADERS = \
cli.hpp \
cli_coap.hpp \
cli_coap_secure.hpp \
cli_console.hpp \
cli_dataset.hpp \
cli_server.hpp \
+100 -1
View File
@@ -14,6 +14,7 @@ OpenThread test scripts use the CLI to execute test cases.
* [childmax](#childmax)
* [childtimeout](#childtimeout)
* [coap](#coap-start)
* [coaps](#coaps-start-checkpeercert)
* [commissioner](#commissioner-start-provisioningurl)
* [contextreusedelay](#contextreusedelay)
* [counter](#counter)
@@ -233,7 +234,7 @@ Coap service started: Done
Stops the application coap service.
```bash
> coap start
> coap stop
Coap service stopped: Done
```
@@ -272,6 +273,104 @@ coap response sent successfully!
Received coap response
```
### coaps start \<checkPeerCert\>
Starts the Application CoAP Secure Service.
* checkPeerCert: Peer Certificate Check can be disabled by typing false.
```bash
> coaps start false
Verify Peer Certificate: false. Coap Secure service started: Done
> coaps start
Verify Peer Certificate: true. Coap Secure service started: Done
```
### coaps stop
Stops the Application CoAP Secure Service.
```bash
> coaps stop
Coap Secure service stopped: Done
```
### coaps set psk \<preSharedKey\> \<keyIdentity\>
Set a pre-shared key with his identifier and the ciphersuite
"DTLS_PSK_WITH_AES_128_CCM_8" for the dtls session.
* preSharedKey: The pre-shared key (PSK) for dtls session.
* keyIdentity: The identifier for the PSK.
```bash
> coaps set psk myPreSharedSecret myIdentifier
Coap Secure set PSK: Done
```
### coaps set x509
Set X.509 Certificate with his private key, which is saved in
src/cli/x509_cert_key.hpp.
```bash
> coaps set x509
Coap Secure set own .X509 certificate: Done
```
### coaps connect \<serverAddress\> \[port\]
Open a dtls session to a CoAP Secure Server.
* serverAddress: IPv6 address of Server
```bash
> coaps connect 2001:1234::321
Coap Secure connect: Done
CoAP Secure connected!
```
### coaps disconnect
Terminate the dtls session to the Server.
```bash
> coaps disconnect
CoAP Secure not connected or disconnected.
Done
```
### coaps \<method\> \<address\> \<uri\> \[type\] \[payload\]
* method: CoAP method to be used (GET/PUT/POST/DELETE).
* address: IPv6 address of the CoAP Secure server to query.
* uri: URI String of the resource on the CoAP server.
* type: Switch between confirmable ("con") and non-confirmable (default).
* payload: In case of PUT/POST/DELETE a payload can be encapsulated.
```bash
> coaps get 2001:1234::321 secret
Sending coap secure request: Done
Received coap secure response
CoapSecure RX Header Informations:
Type 16 (NON CONF)
Code 69 (Coap Code CONTENT)
With payload (hex):
4a756e2031322031353a30373a3336
> coaps put 2001:1234::321 test non-con hello
Sending coap secure request: Done
> coaps post 2001:1234::321 test con
Sending coap secure request: Done
Received coap secure response
CoapSecure RX Header Informations:
Type 32 (NON CONF)
Code 69 (Coap Code CONTENT)
With payload (hex):
4a756e2031322031353a30373a3336
> coaps delete 2001:1234::321 test
Sending coap secure request: Done
```
### commissioner start \<provisioningUrl\>
Start the Commissioner role.
+155
View File
@@ -0,0 +1,155 @@
# OpenThread CLI - COAPS Example
The OpenThread CoAP Secure APIs may be invoked via the OpenThread CLI.
CoAP Secure use DTLS (over UDP) to make an end to end encrypted connection.
### For use PSK with AES128 CCM8
1a. enter your psk and his identifier
```bash
coaps set psk <yourPsk> <PskIdentifier>
```
### For use ECDHE ECDSA with AES128 CCM8
1b. set the private key and .X509 certificate stored in core/cli/x509_cert_key.hpp.
> _optional_: add your [own](#create-ec-private-key) X.509 certificate and private key to 'core/cli/x509_cert_key.hpp'.
```bash
coaps set x509
```
## Start CoAPS Service (for Server and Client)
2. start (init) the coaps api and starts listen on coaps port (5684)
```bash
> coaps start
```
## CoAP Secure Server
* add a coap resource to provide to a coap client
```bash
coaps resource <coapUri>
```
## Connect to a DTLS Server
* connect to a dtls server
```bash
coaps connect <serversIp> (port, if not default)
```
## CoAP Secure Client
* get a resource form the server
```bash
coaps get (serversIp) <coapUri> (Con/NotCon) (payload)
```
> post, put and delete also possible
<> must
() opt
## Complete example for DTLS/CoAP server (Node 1)
In this example the coap server is also the dtls server.
The dtls server waits for incoming connection on coaps port 5684.
The [Node 2](#complete-example-dtlscoap-client-node-2) below is able to connect to this coaps server.
> Note: Node 1 and Node 2 must use the same mode. Either PSK or Certificate based.
```
Node 1
---------
|CoAPS |
|Server | <--Listen on Port 5684-- (Node 2)
| |
---------
```
### with PSK
```bash
coaps set psk secretPSK Client_identity
coaps start
coaps resource test
```
### with Certificate
```bash
coaps set x509
coaps start (false)
coaps resource test
```
* param false: optional, disables peer certificate validation.
## Complete example DTLS/CoAP client (Node 2)
In this example the coap client is also the dtls client.
The dlts client can connect to a coaps server which is listen on coaps port 5684, e.g to the [Node 1](#complete-example-for-dtlscoap-server-node-1) above.
> Note: Node 1 and Node 2 must use the same mode. Either PSK or Certificate based.
```
Node 2
---------
|CoAPS |
|Client |--Connect to Server on Port 5684--> (Node 1)
| |
---------
```
### with PSK
```bash
coaps set psk secretPSK Client_identity
coaps start
coaps connect 2001:620:190:ffa1::321
coaps get test
coaps disconnect
```
### with Certificate
```bash
coaps set x509
coaps start (false)
coaps connect <server_ip>
coaps get test
coaps disconnect
```
* param false: optional, disables peer certificate validation.
## Create own Private Key with a .X509 Certificate
### Create EC Private Key
```bash
openssl ecparam -genkey -out myECKey.pem -name prime256v1 -noout
```
* ecparam: Key for Elliptic Curve Algorithms
* -name: The elliptic curve to chose. a list of available curves `openssl ecparam -list_curves`
* -noout: private key without EC Parameters
### Create .X509 Certificate
```bash
openssl req -x509 -new -key myECKey.pem -out myX509Cert.pem -days 30
```
* -days: validity time of certificate
+21
View File
@@ -80,6 +80,10 @@
#include "cli_coap.hpp"
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#include "cli_coap_secure.hpp"
#endif
#if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART) && OPENTHREAD_POSIX
#include <openthread/platform/debug_uart.h>
#endif
@@ -106,6 +110,9 @@ const struct Command Interpreter::sCommands[] = {
#if OPENTHREAD_ENABLE_APPLICATION_COAP
{"coap", &Interpreter::ProcessCoap},
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
{"coaps", &Interpreter::ProcessCoapSecure},
#endif
#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
{"commissioner", &Interpreter::ProcessCommissioner},
#endif
@@ -287,6 +294,9 @@ Interpreter::Interpreter(Instance *aInstance)
#if OPENTHREAD_ENABLE_APPLICATION_COAP
, mCoap(*this)
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
, mCoapSecure(*this)
#endif
{
#ifdef OTDLL
assert(mApiInstance);
@@ -649,6 +659,17 @@ void Interpreter::ProcessCoap(int argc, char *argv[])
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
void Interpreter::ProcessCoapSecure(int argc, char *argv[])
{
otError error;
error = mCoapSecure.Process(argc, argv);
AppendResult(error);
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#if OPENTHREAD_FTD
void Interpreter::ProcessContextIdReuseDelay(int argc, char *argv[])
{
+14
View File
@@ -50,6 +50,11 @@
#include "cli/cli_coap.hpp"
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#include <coap/coap_header.hpp>
#include "cli/cli_coap_secure.hpp"
#endif
#include "common/code_utils.hpp"
#include "common/instance.hpp"
@@ -94,6 +99,7 @@ struct Command
class Interpreter
{
friend class Coap;
friend class CoapsSecure;
friend class UdpExample;
public:
@@ -192,6 +198,9 @@ private:
#if OPENTHREAD_ENABLE_APPLICATION_COAP
void ProcessCoap(int argc, char *argv[]);
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
void ProcessCoapSecure(int argc, char *argv[]);
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
void ProcessCommissioner(int argc, char *argv[]);
#endif // OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
@@ -436,6 +445,11 @@ private:
Coap mCoap;
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
CoapsSecure mCoapSecure;
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
};
} // namespace Cli
+641
View File
@@ -0,0 +1,641 @@
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements a simple CLI for the CoAP Secure service.
*/
#include "cli_coap_secure.hpp"
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#include <ctype.h>
#include "cli/cli.hpp"
#include "coap/coap_header.hpp"
#include "coap/coap_secure.hpp"
// header for place your x509 certificate and private key
#include "x509_cert_key.hpp"
#include <mbedtls/debug.h>
namespace ot {
namespace Cli {
CoapsSecure::CoapsSecure(Interpreter &aInterpreter)
: mInterpreter(aInterpreter)
, mShutdownFlag(false)
, mUseCertificate(false)
, mPskLength(0)
, mPskIdLength(0)
{
memset(&mResource, 0, sizeof(mResource));
memset(&mPsk, 0, sizeof(mPsk));
memset(&mPskId, 0, sizeof(mPskId));
}
void CoapsSecure::PrintHeaderInfos(otCoapHeader *aHeader) const
{
otCoapCode mCoapCode;
otCoapType mCoapType;
mCoapCode = otCoapHeaderGetCode(aHeader);
mCoapType = otCoapHeaderGetType(aHeader);
mInterpreter.mServer->OutputFormat("\r\n CoapSecure RX Header Information:"
"\r\n Type %d => ",
static_cast<uint16_t>(mCoapType));
switch (mCoapType)
{
case OT_COAP_TYPE_ACKNOWLEDGMENT:
mInterpreter.mServer->OutputFormat("Ack");
break;
case OT_COAP_TYPE_CONFIRMABLE:
mInterpreter.mServer->OutputFormat("Confirmable");
break;
case OT_COAP_TYPE_NON_CONFIRMABLE:
mInterpreter.mServer->OutputFormat("NonConfirmable");
break;
case OT_COAP_TYPE_RESET:
mInterpreter.mServer->OutputFormat("Reset");
break;
default:
break;
}
mInterpreter.mServer->OutputFormat("\r\n Code %d => %s\r\n", static_cast<uint16_t>(mCoapCode),
static_cast<const char *>(otCoapHeaderCodeToString(aHeader)));
}
void CoapsSecure::PrintPayload(otMessage *aMessage) const
{
uint8_t buf[kMaxBufferSize];
uint16_t bytesToPrint;
uint16_t bytesPrinted = 0;
uint16_t length = otMessageGetLength(aMessage) - otMessageGetOffset(aMessage);
if (length > 0)
{
mInterpreter.mServer->OutputFormat(" With payload [UTF8]:\r\n", aMessage);
while (length > 0)
{
bytesToPrint = (length < sizeof(buf)) ? length : sizeof(buf);
otMessageRead(aMessage, otMessageGetOffset(aMessage) + bytesPrinted, buf, bytesToPrint);
for (int i = 0; i < bytesToPrint; i++)
{
mInterpreter.mServer->OutputFormat("%c", buf[i]);
}
mInterpreter.mServer->OutputFormat("\r\n");
length -= bytesToPrint;
bytesPrinted += bytesToPrint;
}
}
else
{
mInterpreter.mServer->OutputFormat(" No payload.");
}
mInterpreter.mServer->OutputFormat("\r\n> ");
}
otError CoapsSecure::Process(int argc, char *argv[])
{
otError error = OT_ERROR_NONE;
otIp6Address coapDestinationIp;
otMessageInfo messageInfo;
bool mVerifyPeerCert = true;
long value;
VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);
if (strcmp(argv[0], "start") == 0)
{
if (argc > 1)
{
if (strcmp(argv[1], "false") == 0)
{
mVerifyPeerCert = false;
}
else if (strcmp(argv[1], "true") != 0)
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
otCoapSecureSetSslAuthMode(mInterpreter.mInstance, mVerifyPeerCert);
SuccessOrExit(error = otCoapSecureStart(mInterpreter.mInstance, OT_DEFAULT_COAP_SECURE_PORT, this));
otCoapSecureSetClientConnectedCallback(mInterpreter.mInstance, &CoapsSecure::HandleClientConnect, this);
#if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
otCoapSecureSetDefaultHandler(mInterpreter.mInstance, &CoapsSecure::DefaultHandle, this);
#endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
if (mUseCertificate)
{
mInterpreter.mServer->OutputFormat("Verify Peer Certificate: %s. Coap Secure service started: ",
mVerifyPeerCert ? "true" : "false");
}
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
}
else if (strcmp(argv[0], "set") == 0)
{
if (argc > 1)
{
if (strcmp(argv[1], "psk") == 0)
{
if (argc > 3)
{
mPskLength = (uint8_t)strlen(argv[2]);
mPskIdLength = (uint8_t)strlen(argv[3]);
memcpy(mPsk, argv[2], mPskLength);
memcpy(mPskId, argv[3], mPskIdLength);
SuccessOrExit(
error = otCoapSecureSetPsk(mInterpreter.mInstance, mPsk, mPskLength, mPskId, mPskIdLength));
mUseCertificate = false;
mInterpreter.mServer->OutputFormat("Coap Secure set PSK: ");
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
else if (strcmp(argv[1], "x509") == 0)
{
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
SuccessOrExit(error = otCoapSecureSetCertificate(
mInterpreter.mInstance, (const uint8_t *)OT_CLI_COAPS_X509_CERT,
sizeof(OT_CLI_COAPS_X509_CERT), (const uint8_t *)OT_CLI_COAPS_PRIV_KEY,
sizeof(OT_CLI_COAPS_PRIV_KEY)));
SuccessOrExit(error = otCoapSecureSetCaCertificateChain(
mInterpreter.mInstance, (const uint8_t *)OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE,
sizeof(OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE)));
mUseCertificate = true;
mInterpreter.mServer->OutputFormat("Coap Secure set own .X509 certificate: ");
#else
ExitNow(error = OT_ERROR_DISABLED_FEATURE);
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
else if (strcmp(argv[0], "connect") == 0)
{
// Destination IPv6 address
if (argc > 1)
{
// parse ipAddr
SuccessOrExit(error = otIp6AddressFromString(argv[1], &coapDestinationIp));
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.mPeerAddr = coapDestinationIp;
messageInfo.mPeerPort = OT_DEFAULT_COAP_SECURE_PORT;
messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
// check for port specification
if (argc > 2)
{
error = Interpreter::ParseLong(argv[2], value);
SuccessOrExit(error);
messageInfo.mPeerPort = static_cast<uint16_t>(value);
}
SuccessOrExit(error = otCoapSecureConnect(mInterpreter.mInstance, &messageInfo,
&CoapsSecure::HandleClientConnect, this));
mInterpreter.mServer->OutputFormat("Coap Secure connect: ");
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
}
else if (strcmp(argv[0], "resource") == 0)
{
mResource.mUriPath = mUriPath;
mResource.mContext = this;
mResource.mHandler = &CoapsSecure::HandleServerResponse;
if (argc > 1)
{
strlcpy(mUriPath, argv[1], kMaxUriLength);
SuccessOrExit(error = otCoapSecureAddResource(mInterpreter.mInstance, &mResource));
}
mInterpreter.mServer->OutputFormat("Resource name is '%s': ", mResource.mUriPath);
}
else if (strcmp(argv[0], "disconnect") == 0)
{
SuccessOrExit(error = otCoapSecureDisconnect(mInterpreter.mInstance));
}
else if (strcmp(argv[0], "stop") == 0)
{
if (otCoapSecureIsConncetionActive(mInterpreter.mInstance))
{
error = otCoapSecureDisconnect(mInterpreter.mInstance);
mShutdownFlag = true;
}
else
{
SuccessOrExit(error = Stop());
}
}
else if (strcmp(argv[0], "help") == 0)
{
mInterpreter.mServer->OutputFormat("CLI CoAPS help:\r\n\r\n");
mInterpreter.mServer->OutputFormat(">'coaps start (false)' "
": start coap secure service, false disable peer cert verification\r\n");
mInterpreter.mServer->OutputFormat(">'coaps set psk <psk> <client id>' "
": set Preshared Key and Client Identity (Ciphresuit PSK_AES128)\r\n");
mInterpreter.mServer->OutputFormat(">'coaps set x509' "
": set X509 Cert und Private Key (Ciphresuit ECDHE_ECDSA_AES128)\r\n");
mInterpreter.mServer->OutputFormat(">'coaps connect <servers ipv6 addr> (port)' "
": start dtls session with a server\r\n");
mInterpreter.mServer->OutputFormat(">'coaps get' 'coaps put' 'coaps post' 'coaps delete' "
": interact with coap resource from server, ipv6 is not need as client\r\n");
mInterpreter.mServer->OutputFormat(
" >> args:(ipv6_addr_srv) <coap_src> and, if you have payload: <con> <payload>\r\n");
mInterpreter.mServer->OutputFormat(">'coaps resource <uri>' "
": add a coap server resource with 'helloWorld' as content.\r\n");
mInterpreter.mServer->OutputFormat(">'coaps disconnect' "
": stop dtls session with a server\r\n");
mInterpreter.mServer->OutputFormat(">'coaps stop' "
": stop coap secure service\r\n");
mInterpreter.mServer->OutputFormat("\r\n legend: <>: must, (): opt "
"\r\n");
mInterpreter.mServer->OutputFormat("\r\n");
}
else
{
error = ProcessRequest(argc, argv);
}
exit:
return error;
}
otError CoapsSecure::Stop(void)
{
otError error = OT_ERROR_ABORT;
otCoapRemoveResource(mInterpreter.mInstance, &mResource);
error = otCoapSecureStop(mInterpreter.mInstance);
mInterpreter.mServer->OutputFormat("Coap Secure service stopped: ");
return error;
}
void OTCALL CoapsSecure::HandleClientConnect(bool aConnected, void *aContext)
{
static_cast<CoapsSecure *>(aContext)->HandleClientConnect(aConnected);
}
void CoapsSecure::HandleClientConnect(bool aConnected)
{
if (aConnected)
{
mInterpreter.mServer->OutputFormat("CoAP Secure connected!\r\n> ");
}
else
{
if (!mShutdownFlag)
{
mInterpreter.mServer->OutputFormat("CoAP Secure not connected or disconnected.\r\n> ");
}
else
{
mInterpreter.mServer->OutputFormat("CoAP Secure disconnected before stop.\r\n> ");
if (Stop() == OT_ERROR_NONE)
{
mInterpreter.mServer->OutputFormat(" Done\r\n> ");
}
else
{
mInterpreter.mServer->OutputFormat(" With error\r\n> ");
}
mShutdownFlag = false;
}
}
OT_UNUSED_VARIABLE(aConnected);
}
void OTCALL CoapsSecure::HandleServerResponse(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo)
{
static_cast<CoapsSecure *>(aContext)->HandleServerResponse(aHeader, aMessage, aMessageInfo);
}
void CoapsSecure::HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
otError error = OT_ERROR_NONE;
otCoapHeader responseHeader;
otMessage * responseMessage;
otCoapCode responseCode = OT_COAP_CODE_EMPTY;
char responseContent[] = "helloWorld";
mInterpreter.mServer->OutputFormat(
"Received coap secure request from [%x:%x:%x:%x:%x:%x:%x:%x]: ",
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[0]), HostSwap16(aMessageInfo->mSockAddr.mFields.m16[1]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[2]), HostSwap16(aMessageInfo->mSockAddr.mFields.m16[3]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[4]), HostSwap16(aMessageInfo->mSockAddr.mFields.m16[5]),
HostSwap16(aMessageInfo->mSockAddr.mFields.m16[6]), HostSwap16(aMessageInfo->mSockAddr.mFields.m16[7]));
switch (otCoapHeaderGetCode(aHeader))
{
case OT_COAP_CODE_GET:
mInterpreter.mServer->OutputFormat("GET");
break;
case OT_COAP_CODE_DELETE:
mInterpreter.mServer->OutputFormat("DELETE");
break;
case OT_COAP_CODE_PUT:
mInterpreter.mServer->OutputFormat("PUT");
break;
case OT_COAP_CODE_POST:
mInterpreter.mServer->OutputFormat("POST");
break;
default:
mInterpreter.mServer->OutputFormat("Undefined\r\n");
return;
}
PrintPayload(aMessage);
if ((otCoapHeaderGetType(aHeader) == OT_COAP_TYPE_CONFIRMABLE) || otCoapHeaderGetCode(aHeader) == OT_COAP_CODE_GET)
{
if (otCoapHeaderGetCode(aHeader) == OT_COAP_CODE_GET)
{
responseCode = OT_COAP_CODE_CONTENT;
}
else
{
responseCode = OT_COAP_CODE_VALID;
}
otCoapHeaderInit(&responseHeader, OT_COAP_TYPE_ACKNOWLEDGMENT, responseCode);
otCoapHeaderSetMessageId(&responseHeader, otCoapHeaderGetMessageId(aHeader));
otCoapHeaderSetToken(&responseHeader, otCoapHeaderGetToken(aHeader), otCoapHeaderGetTokenLength(aHeader));
if (otCoapHeaderGetCode(aHeader) == OT_COAP_CODE_GET)
{
otCoapHeaderSetPayloadMarker(&responseHeader);
}
responseMessage = otCoapNewMessage(mInterpreter.mInstance, &responseHeader);
VerifyOrExit(responseMessage != NULL, error = OT_ERROR_NO_BUFS);
if (otCoapHeaderGetCode(aHeader) == OT_COAP_CODE_GET)
{
SuccessOrExit(error = otMessageAppend(responseMessage, &responseContent, sizeof(responseContent)));
}
SuccessOrExit(error = otCoapSecureSendResponse(mInterpreter.mInstance, responseMessage, aMessageInfo));
}
exit:
if (error != OT_ERROR_NONE && responseMessage != NULL)
{
mInterpreter.mServer->OutputFormat("Cannot send coap secure response message: Error %d: %s\r\n", error,
otThreadErrorToString(error));
otMessageFree(responseMessage);
}
else if (responseCode >= OT_COAP_CODE_RESPONSE_MIN)
{
mInterpreter.mServer->OutputFormat("coap secure response sent successfully!\r\n");
}
}
otError CoapsSecure::ProcessRequest(int argc, char *argv[])
{
otError error = OT_ERROR_NONE;
otMessage * message = NULL;
otMessageInfo messageInfo;
otCoapHeader header;
uint16_t payloadLength = 0;
uint8_t indexShifter = 0;
// Default parameters
char coapUri[kMaxUriLength] = "test";
otCoapType coapType = OT_COAP_TYPE_NON_CONFIRMABLE;
otCoapCode coapCode = OT_COAP_CODE_GET;
otIp6Address coapDestinationIp;
VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);
// CoAP-Code
if (strcmp(argv[0], "get") == 0)
{
coapCode = OT_COAP_CODE_GET;
}
else if (strcmp(argv[0], "post") == 0)
{
coapCode = OT_COAP_CODE_POST;
}
else if (strcmp(argv[0], "put") == 0)
{
coapCode = OT_COAP_CODE_PUT;
}
else if (strcmp(argv[0], "delete") == 0)
{
coapCode = OT_COAP_CODE_DELETE;
}
else
{
ExitNow(error = OT_ERROR_PARSE);
}
// Destination IPv6 address
if (argc > 1)
{
error = otIp6AddressFromString(argv[1], &coapDestinationIp);
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
// Destination IPv6 address not need as client
// if no IPv6 is entered, so ignore it and go away
if (error == OT_ERROR_NONE)
{
indexShifter = 0;
}
else
{
indexShifter = 1;
}
// CoAP-URI
if (argc > (2 - indexShifter))
{
strlcpy(coapUri, argv[2 - indexShifter], kMaxUriLength);
}
// CoAP-Type
if (argc > (3 - indexShifter))
{
if (strcmp(argv[3 - indexShifter], "con") == 0)
{
coapType = OT_COAP_TYPE_CONFIRMABLE;
}
}
otCoapHeaderInit(&header, coapType, coapCode);
otCoapHeaderGenerateToken(&header, ot::Coap::Header::kDefaultTokenLength);
SuccessOrExit(error = otCoapHeaderAppendUriPathOptions(&header, coapUri));
if (argc > (4 - indexShifter))
{
payloadLength = static_cast<uint16_t>(strlen(argv[4 - indexShifter]));
if (payloadLength > 0)
{
otCoapHeaderSetPayloadMarker(&header);
}
}
message = otCoapNewMessage(mInterpreter.mInstance, &header);
VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS);
// add payload
if (payloadLength > 0)
{
SuccessOrExit(error = otMessageAppend(message, argv[4 - indexShifter], payloadLength));
}
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.mPeerAddr = coapDestinationIp;
messageInfo.mPeerPort = OT_DEFAULT_COAP_PORT;
messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (coapCode == OT_COAP_CODE_GET))
{
error = otCoapSecureSendRequest(mInterpreter.mInstance, message, &CoapsSecure::HandleClientResponse, this);
}
else
{
error = otCoapSecureSendRequest(mInterpreter.mInstance, message, NULL, NULL);
}
mInterpreter.mServer->OutputFormat("Sending coap secure request: ");
exit:
if ((error != OT_ERROR_NONE) && (message != NULL))
{
otMessageFree(message);
}
return error;
}
void OTCALL CoapsSecure::HandleClientResponse(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo,
otError aError)
{
static_cast<CoapsSecure *>(aContext)->HandleClientResponse(aHeader, aMessage, aMessageInfo, aError);
}
void CoapsSecure::HandleClientResponse(otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo,
otError aError)
{
if (aError != OT_ERROR_NONE)
{
mInterpreter.mServer->OutputFormat("Error receiving coap secure response message: Error %d: %s\r\n", aError,
otThreadErrorToString(aError));
}
else
{
mInterpreter.mServer->OutputFormat("Received coap secure response");
PrintHeaderInfos(aHeader);
PrintPayload(aMessage);
}
OT_UNUSED_VARIABLE(aHeader);
OT_UNUSED_VARIABLE(aMessageInfo);
}
#if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
void OTCALL CoapsSecure::DefaultHandle(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo)
{
static_cast<CoapsSecure *>(aContext)->DefaultHandle(aHeader, aMessage, aMessageInfo);
}
void CoapsSecure::DefaultHandle(otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessage);
otError error = OT_ERROR_NONE;
otCoapHeader responseHeader;
otMessage * responseMessage;
if (otCoapHeaderGetType(aHeader) == OT_COAP_TYPE_CONFIRMABLE || otCoapHeaderGetCode(aHeader) == OT_COAP_CODE_GET)
{
otCoapHeaderInit(&responseHeader, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_NOT_FOUND);
otCoapHeaderSetMessageId(&responseHeader, otCoapHeaderGetMessageId(aHeader));
otCoapHeaderSetToken(&responseHeader, otCoapHeaderGetToken(aHeader), otCoapHeaderGetTokenLength(aHeader));
responseMessage = otCoapNewMessage(mInterpreter.mInstance, &responseHeader);
VerifyOrExit(responseMessage != NULL, error = OT_ERROR_NO_BUFS);
SuccessOrExit(error = otCoapSecureSendResponse(mInterpreter.mInstance, responseMessage, aMessageInfo));
}
exit:
mInterpreter.mServer->OutputFormat("Default handler called.\r\n> ");
}
#endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
+140
View File
@@ -0,0 +1,140 @@
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file contains definitions for a simple CLI CoAP Secure server and client.
*/
#ifndef CLI_COAP_SECURE_HPP_
#define CLI_COAP_SECURE_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#include "coap/coap_header.hpp"
#include "coap/coap_secure.hpp"
/**
* to test the default handler for not handled requests set to 1.
*/
#define CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER 0
namespace ot {
namespace Cli {
class Interpreter;
/**
* This class implements the CLI CoAP Secure server and client.
*
*/
class CoapsSecure
{
public:
/**
* Constructor
*
* @param[in] aInterpreter The CLI interpreter.
*
*/
CoapsSecure(Interpreter &aInterpreter);
/**
* This method interprets a list of CLI arguments.
*
* @param[in] argc The number of elements in argv.
* @param[in] argv A pointer to an array of command line arguments.
*
*/
otError Process(int argc, char *argv[]);
private:
enum
{
kMaxUriLength = 32,
kMaxBufferSize = 16,
kPskMaxLength = 32,
kPskIdMaxLength = 32
};
void PrintHeaderInfos(otCoapHeader *aHeader) const;
void PrintPayload(otMessage *aMessage) const;
otError ProcessRequest(int argc, char *argv[]);
otError Stop(void);
static void OTCALL HandleServerResponse(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo);
void HandleServerResponse(otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo);
static void OTCALL HandleClientResponse(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo,
otError aError);
void HandleClientResponse(otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo,
otError aError);
#if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
static void OTCALL DefaultHandle(void * aContext,
otCoapHeader * aHeader,
otMessage * aMessage,
const otMessageInfo *aMessageInfo);
void DefaultHandle(otCoapHeader *aHeader, otMessage *aMessage, const otMessageInfo *aMessageInfo);
#endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
static void OTCALL HandleClientConnect(bool aConnected, void *aContext);
void HandleClientConnect(bool aConnected);
otCoapResource mResource;
char mUriPath[kMaxUriLength];
Interpreter &mInterpreter;
bool mShutdownFlag;
bool mUseCertificate;
uint8_t mPsk[kPskMaxLength];
uint8_t mPskLength;
uint8_t mPskId[kPskIdMaxLength];
uint8_t mPskIdLength;
};
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#endif // CLI_COAP_SECURE_HPP_
+117
View File
@@ -0,0 +1,117 @@
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief
* This file contains the X.509 certificate and private key for Application
* CoAP Secure use with cipher suite ECDHE_ECDSA_WITH_AES_128_CCM8.
*/
#ifndef SRC_CLI_X509_CERT_KEY_HPP_
#define SRC_CLI_X509_CERT_KEY_HPP_
#ifdef __cplusplus
extern "C" {
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
/**SERVER
* Generate your own private key and certificate using openssl.
*
* 1. Generate a EC (Elliptic Curve) Private Key.
* 'openssl ecparam -genkey -out myECKey.pem -name prime256v1 -noout'
* 2. Generate a .X509 Certificate (Contains Public Key).
* 'openssl req -x509 -new -key myECKey.pem -out myX509Cert.pem'
*/
/**
* place your X.509 certificate (PEM format) for ssl session
* with ECDHE_ECDSA_WITH_AES_128_CCM_8 here.
*/
#define OT_CLI_COAPS_X509_CERT \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIBrTCCAVICBgDRArfDJTAKBggqhkjOPQQDAjBcMQswCQYDVQQGEwJaWTESMBAG\r\n" \
"A1UECAwJWW91clN0YXRlMRAwDgYDVQQKDAdZb3VyT3JnMRQwEgYDVQQLDAtZb3Vy\r\n" \
"T3JnVW5pdDERMA8GA1UEAwwIVmVuZG9yQ0EwIBcNMTgwNzEzMTIzNzA3WhgPMjI5\r\n" \
"MjA0MjYxMjM3MDdaMGExCzAJBgNVBAYTAlpZMRIwEAYDVQQIDAlZb3VyU3RhdGUx\r\n" \
"EDAOBgNVBAoMB1lvdXJPcmcxFDASBgNVBAsMC1lvdXJPcmdVbml0MRYwFAYDVQQD\r\n" \
"DA1QWEMzLkU3NS0xMDBBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIUtlV99w\r\n" \
"OggiASflg6CVsGMzXMXYrNgQ1piLIybCkrq+YoqJ3mwcbJHWlvxGPxNIQw6i8kzK\r\n" \
"bkC642ZWgBT5MzAKBggqhkjOPQQDAgNJADBGAiEA/1yk69A+37kLBvdOWPDRXGwe\r\n" \
"0AoICTGaLqzB3cF5mtACIQC28WwmzHb5gqe3nOPAM73py1v17EXZj07PU89BAEcb\r\n" \
"yg==\r\n" \
"-----END CERTIFICATE-----\r\n"
/**
* place your private key (PEM format) for ssl session
* with ECDHE_ECDSA_WITH_AES_128_CCM_8 here.
*/
#define OT_CLI_COAPS_PRIV_KEY \
"-----BEGIN EC PRIVATE KEY-----\r\n" \
"MHcCAQEEIFYQh2R7M48qOHePw+VE4b034UlZmWWC/iNAK34sQbucoAoGCCqGSM49\r\n" \
"AwEHoUQDQgAEIUtlV99wOggiASflg6CVsGMzXMXYrNgQ1piLIybCkrq+YoqJ3mwc\r\n" \
"bJHWlvxGPxNIQw6i8kzKbkC642ZWgBT5Mw==\r\n" \
"-----END EC PRIVATE KEY-----\r\n"
/**
* Place peers CA certificate (PEM format) here.
* It's necessary to validate the peers certificate. If you haven't a
* CA certificate, you must run the coaps without checking certificate.
*/
#define OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIICDzCCAbWgAwIBAgIESZYC0jAKBggqhkjOPQQDAjBcMQswCQYDVQQGEwJaWTES\r\n" \
"MBAGA1UECAwJWW91clN0YXRlMRAwDgYDVQQKDAdZb3VyT3JnMRQwEgYDVQQLDAtZ\r\n" \
"b3VyT3JnVW5pdDERMA8GA1UEAwwIVmVuZG9yQ0EwIBcNMTgwNzEzMTE1NjA5WhgP\r\n" \
"MjI5MjA0MjYxMTU2MDlaMFwxCzAJBgNVBAYTAlpZMRIwEAYDVQQIDAlZb3VyU3Rh\r\n" \
"dGUxEDAOBgNVBAoMB1lvdXJPcmcxFDASBgNVBAsMC1lvdXJPcmdVbml0MREwDwYD\r\n" \
"VQQDDAhWZW5kb3JDQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGAAuYcBIgP0\r\n" \
"fMC1Bd+1nAH5S1goR0TaDAIadK4hULQr5LwziuDk9XTQaOTwmWB9iR1eiHC6RY8W\r\n" \
"wyrGBbnEbzujYzBhMB0GA1UdDgQWBBQ+yCpIszhzbmXe2At1GofREjnBxjAfBgNV\r\n" \
"HSMEGDAWgBQ+yCpIszhzbmXe2At1GofREjnBxjAPBgNVHRMBAf8EBTADAQH/MA4G\r\n" \
"A1UdDwEB/wQEAwIBhjAKBggqhkjOPQQDAgNIADBFAiBW60XgdSRD24rbTgdneS+V\r\n" \
"SHVix8LuXunPYW50LmxbrwIhAOw4gMroRIOS26y0TcND03FnyO3wBNF9MjM0hWKQ\r\n" \
"JXk3\r\n" \
"-----END CERTIFICATE-----\r\n" \
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* @}
*
*/
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* SRC_CLI_X509_CERT_KEY_HPP_ */
+1
View File
@@ -107,6 +107,7 @@ SOURCES_COMMON = \
api/channel_monitor_api.cpp \
api/child_supervision_api.cpp \
api/coap_api.cpp \
api/coap_secure_api.cpp \
api/commissioner_api.cpp \
api/crypto_api.cpp \
api/dataset_api.cpp \
+5
View File
@@ -113,6 +113,11 @@ otCoapCode otCoapHeaderGetCode(const otCoapHeader *aHeader)
return static_cast<const Coap::Header *>(aHeader)->GetCode();
}
const char *otCoapHeaderCodeToString(const otCoapHeader *aHeader)
{
return static_cast<const Coap::Header *>(aHeader)->CodeToString();
}
uint16_t otCoapHeaderGetMessageId(const otCoapHeader *aHeader)
{
return static_cast<const Coap::Header *>(aHeader)->GetMessageId();
+241
View File
@@ -0,0 +1,241 @@
/*
* Copyright (c) 2018, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the OpenThread CoAP Secure API.
*/
#include "openthread-core-config.h"
#include <openthread/coap_secure.h>
#include "coap/coap_header.hpp"
#include "coap/coap_secure.hpp"
#include "common/instance.hpp"
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
using namespace ot;
otError otCoapSecureStart(otInstance *aInstance, uint16_t aPort, void *aContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().Start(aPort, NULL, aContext);
}
otError otCoapSecureSetCertificate(otInstance * aInstance,
const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength)
{
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
Instance &instance = *static_cast<Instance *>(aInstance);
if (aX509Cert == NULL || aX509Length == 0 || aPrivateKey == NULL || aPrivateKeyLength == 0)
{
return OT_ERROR_INVALID_ARGS;
}
return instance.GetApplicationCoapSecure().SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength);
#else
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aX509Cert);
OT_UNUSED_VARIABLE(aX509Length);
OT_UNUSED_VARIABLE(aPrivateKey);
OT_UNUSED_VARIABLE(aPrivateKeyLength);
return OT_ERROR_DISABLED_FEATURE;
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
}
otError otCoapSecureSetCaCertificateChain(otInstance * aInstance,
const uint8_t *aX509CaCertificateChain,
uint32_t aX509CaCertChainLength)
{
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
Instance &instance = *static_cast<Instance *>(aInstance);
if (aX509CaCertificateChain == NULL || aX509CaCertChainLength == 0)
{
return OT_ERROR_INVALID_ARGS;
}
return instance.GetApplicationCoapSecure().SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLength);
#else
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aX509CaCertificateChain);
OT_UNUSED_VARIABLE(aX509CaCertChainLength);
return OT_ERROR_DISABLED_FEATURE;
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
}
otError otCoapSecureSetPsk(otInstance * aInstance,
const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength)
{
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
Instance &instance = *static_cast<Instance *>(aInstance);
if (aPsk == NULL || aPskLength == 0 || aPskIdentity == NULL || aPskIdLength == 0)
{
return OT_ERROR_INVALID_ARGS;
}
return instance.GetApplicationCoapSecure().SetPreSharedKey(aPsk, aPskLength, aPskIdentity, aPskIdLength);
#else
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aPsk);
OT_UNUSED_VARIABLE(aPskLength);
OT_UNUSED_VARIABLE(aPskIdentity);
OT_UNUSED_VARIABLE(aPskIdLength);
return OT_ERROR_DISABLED_FEATURE;
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
}
otError otCoapSecureGetPeerCertificateBase64(otInstance * aInstance,
unsigned char *aPeerCert,
uint64_t * aCertLength,
uint64_t aCertBufferSize)
{
#ifdef MBEDTLS_BASE64_C
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().GetPeerCertificateBase64(aPeerCert, (size_t *)aCertLength,
(size_t)aCertBufferSize);
#else
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aPeerCert);
OT_UNUSED_VARIABLE(aCertLength);
OT_UNUSED_VARIABLE(aCertBufferSize);
return OT_ERROR_DISABLED_FEATURE;
#endif // MBEDTLS_BASE64_C
}
void otCoapSecureSetSslAuthMode(otInstance *aInstance, bool aVerifyPeerCertificate)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.GetApplicationCoapSecure().SetSslAuthMode(aVerifyPeerCertificate);
}
otError otCoapSecureConnect(otInstance * aInstance,
const otMessageInfo * aMessageInfo,
otHandleCoapSecureClientConnect aHandler,
void * aContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().Connect(*static_cast<const Ip6::MessageInfo *>(aMessageInfo), aHandler,
aContext);
}
otError otCoapSecureDisconnect(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().Disconnect();
}
bool otCoapSecureIsConnected(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().IsConnected();
}
bool otCoapSecureIsConncetionActive(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().IsConnectionActive();
}
otError otCoapSecureStop(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().Stop();
}
otError otCoapSecureSendRequest(otInstance * aInstance,
otMessage * aMessage,
otCoapResponseHandler aHandler = NULL,
void * aContext = NULL)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().SendMessage(*static_cast<Message *>(aMessage), aHandler, aContext);
}
otError otCoapSecureAddResource(otInstance *aInstance, otCoapResource *aResource)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().AddResource(*static_cast<Coap::Resource *>(aResource));
}
void otCoapSecureRemoveResource(otInstance *aInstance, otCoapResource *aResource)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.GetApplicationCoapSecure().RemoveResource(*static_cast<Coap::Resource *>(aResource));
}
void otCoapSecureSetClientConnectedCallback(otInstance * aInstance,
otHandleCoapSecureClientConnect aHandler,
void * aContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.GetApplicationCoapSecure().SetClientConnectedCallback(aHandler, aContext);
}
void otCoapSecureSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext)
{
Instance &instance = *static_cast<Instance *>(aInstance);
instance.GetApplicationCoapSecure().SetDefaultHandler(aHandler, aContext);
}
otError otCoapSecureSendResponse(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetApplicationCoapSecure().SendMessage(*static_cast<Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
+97
View File
@@ -432,5 +432,102 @@ void Header::SetDefaultResponseHeader(const Header &aRequestHeader)
SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP
const char *Header::CodeToString(void) const
{
const char *mCodeString;
switch (mHeader.mFields.mCode)
{
case OT_COAP_CODE_INTERNAL_ERROR:
mCodeString = "InternalError";
break;
case OT_COAP_CODE_METHOD_NOT_ALLOWED:
mCodeString = "MethodNotAllowed";
break;
case OT_COAP_CODE_CONTENT:
mCodeString = "Content";
break;
case OT_COAP_CODE_EMPTY:
mCodeString = "Empty";
break;
case OT_COAP_CODE_GET:
mCodeString = "Get";
break;
case OT_COAP_CODE_POST:
mCodeString = "Post";
break;
case OT_COAP_CODE_PUT:
mCodeString = "Put";
break;
case OT_COAP_CODE_DELETE:
mCodeString = "Delete";
break;
case OT_COAP_CODE_NOT_FOUND:
mCodeString = "NotFound";
break;
case OT_COAP_CODE_UNSUPPORTED_FORMAT:
mCodeString = "UnsupportedFormat";
break;
case OT_COAP_CODE_RESPONSE_MIN:
mCodeString = "ResponseMin";
break;
case OT_COAP_CODE_CREATED:
mCodeString = "Created";
break;
case OT_COAP_CODE_DELETED:
mCodeString = "Deleted";
break;
case OT_COAP_CODE_VALID:
mCodeString = "Valid";
break;
case OT_COAP_CODE_CHANGED:
mCodeString = "Changed";
break;
case OT_COAP_CODE_BAD_REQUEST:
mCodeString = "BadRequest";
break;
case OT_COAP_CODE_UNAUTHORIZED:
mCodeString = "Unauthorized";
break;
case OT_COAP_CODE_BAD_OPTION:
mCodeString = "BadOption";
break;
case OT_COAP_CODE_FORBIDDEN:
mCodeString = "Forbidden";
break;
case OT_COAP_CODE_NOT_ACCEPTABLE:
mCodeString = "NotAcceptable";
break;
case OT_COAP_CODE_PRECONDITION_FAILED:
mCodeString = "PreconditionFailed";
break;
case OT_COAP_CODE_REQUEST_TOO_LARGE:
mCodeString = "RequestTooLarge";
break;
case OT_COAP_CODE_NOT_IMPLEMENTED:
mCodeString = "NotImplemented";
break;
case OT_COAP_CODE_BAD_GATEWAY:
mCodeString = "BadGateway";
break;
case OT_COAP_CODE_SERVICE_UNAVAILABLE:
mCodeString = "ServiceUnavailable";
break;
case OT_COAP_CODE_GATEWAY_TIMEOUT:
mCodeString = "GatewayTimeout";
break;
case OT_COAP_CODE_PROXY_NOT_SUPPORTED:
mCodeString = "ProxyNotSupported";
break;
default:
mCodeString = "Unknown";
break;
}
return mCodeString;
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
} // namespace Coap
} // namespace ot
+10
View File
@@ -175,6 +175,16 @@ public:
*/
void SetCode(Code aCode) { mHeader.mFields.mCode = static_cast<uint8_t>(aCode); }
#if OPENTHREAD_ENABLE_APPLICATION_COAP
/**
* This method returns the CoAP Code as human readable string.
*
* @ returns The CoAP Code as string.
*
*/
const char *CodeToString(void) const;
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP
/**
* This method returns the Message ID value.
*
+95 -3
View File
@@ -54,9 +54,27 @@ CoapSecure::CoapSecure(Instance &aInstance)
, mTransportContext(NULL)
, mTransmitMessage(NULL)
, mTransmitTask(aInstance, &CoapSecure::HandleUdpTransmit, this)
, mLayerTwoSecurity(false)
{
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
CoapSecure::CoapSecure(Instance & aInstance,
Tasklet::Handler aUdpTransmitHandle,
Timer::Handler aRetransmissionTimer,
Timer::Handler aResponsesQueueTimer)
: CoapBase(aInstance, aRetransmissionTimer, aResponsesQueueTimer)
, mConnectedCallback(NULL)
, mConnectedContext(NULL)
, mTransportCallback(NULL)
, mTransportContext(NULL)
, mTransmitMessage(NULL)
, mTransmitTask(aInstance, aUdpTransmitHandle, this)
, mLayerTwoSecurity(true)
{
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
otError CoapSecure::Start(uint16_t aPort, TransportCallback aCallback, void *aContext)
{
otError error = OT_ERROR_NONE;
@@ -135,6 +153,53 @@ otError CoapSecure::SetPsk(const uint8_t *aPsk, uint8_t aPskLength)
return GetNetif().GetDtls().SetPsk(aPsk, aPskLength);
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
otError CoapSecure::SetCertificate(const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength)
{
return GetNetif().GetDtls().SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength);
}
otError CoapSecure::SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLenth)
{
return GetNetif().GetDtls().SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLenth);
}
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
otError CoapSecure::SetPreSharedKey(const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength)
{
return GetNetif().GetDtls().SetPreSharedKey(aPsk, aPskLength, aPskIdentity, aPskIdLength);
}
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#ifdef MBEDTLS_BASE64_C
otError CoapSecure::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize)
{
return GetNetif().GetDtls().GetPeerCertificateBase64(aPeerCert, aCertLength, aCertBufferSize);
}
#endif // MBEDTLS_BASE64_C
void CoapSecure::SetClientConnectedCallback(ConnectedCallback aCallback, void *aContext)
{
mConnectedCallback = aCallback;
mConnectedContext = aContext;
}
void CoapSecure::SetSslAuthMode(bool aVerifyPeerCertificate)
{
GetNetif().GetDtls().SetSslAuthMode(aVerifyPeerCertificate);
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
otError CoapSecure::SendMessage(Message &aMessage, otCoapResponseHandler aHandler, void *aContext)
{
otError error = OT_ERROR_NONE;
@@ -183,8 +248,8 @@ void CoapSecure::Receive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo
mPeerAddress.SetSockPort(aMessageInfo.GetSockPort());
netif.GetDtls().Start(false, &CoapSecure::HandleDtlsConnected, &CoapSecure::HandleDtlsReceive,
CoapSecure::HandleDtlsSend, this);
VerifyOrExit(netif.GetDtls().Start(false, &CoapSecure::HandleDtlsConnected, &CoapSecure::HandleDtlsReceive,
CoapSecure::HandleDtlsSend, this) == OT_ERROR_NONE);
}
else
{
@@ -248,7 +313,7 @@ otError CoapSecure::HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, uint8_
{
VerifyOrExit((mTransmitMessage = mSocket.NewMessage(0)) != NULL, error = OT_ERROR_NO_BUFS);
mTransmitMessage->SetSubType(aMessageSubType);
mTransmitMessage->SetLinkSecurityEnabled(false);
mTransmitMessage->SetLinkSecurityEnabled(mLayerTwoSecurity);
}
SuccessOrExit(error = mTransmitMessage->Append(aBuf, aLength));
@@ -312,6 +377,33 @@ void CoapSecure::HandleResponsesQueueTimer(Timer &aTimer)
aTimer.GetOwner<CoapSecure>().CoapBase::HandleResponsesQueueTimer();
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
ApplicationCoapSecure::ApplicationCoapSecure(Instance &aInstance)
: CoapSecure(aInstance,
&ApplicationCoapSecure::HandleUdpTransmit,
&ApplicationCoapSecure::HandleRetransmissionTimer,
&ApplicationCoapSecure::HandleResponsesQueueTimer)
{
}
void ApplicationCoapSecure::HandleUdpTransmit(Tasklet &aTasklet)
{
aTasklet.GetOwner<ApplicationCoapSecure>().CoapSecure::HandleUdpTransmit();
}
void ApplicationCoapSecure::HandleRetransmissionTimer(Timer &aTimer)
{
aTimer.GetOwner<ApplicationCoapSecure>().CoapBase::HandleRetransmissionTimer();
}
void ApplicationCoapSecure::HandleResponsesQueueTimer(Timer &aTimer)
{
aTimer.GetOwner<ApplicationCoapSecure>().CoapBase::HandleResponsesQueueTimer();
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
} // namespace Coap
} // namespace ot
+147 -3
View File
@@ -34,6 +34,8 @@
#include "coap/coap.hpp"
#include "meshcop/dtls.hpp"
#include <openthread/coap_secure.h>
/**
* @file
* This file includes definitions for the secure CoAP agent.
@@ -73,6 +75,23 @@ public:
*/
explicit CoapSecure(Instance &aInstance);
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* This constructor initializes the object.
* (Used for Application CoAPS)
*
* @param[in] aInstance A reference to the OpenThread instance.
* @param[in] aUdpTransmitHandle Handler for udp transmit.
* @param[in] aRetransmissionTimer Handler for retransmission.
* @param[in] aResponsesQueueTimer Handler for Queue Responses.
*
*/
explicit CoapSecure(Instance & aInstance,
Tasklet::Handler aUdpTransmitHandle,
Timer::Handler aRetransmissionTimer,
Timer::Handler aResponsesQueueTimer);
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* This method starts the secure CoAP agent.
*
@@ -106,8 +125,9 @@ public:
/**
* This method initializes DTLS session with a peer.
*
* @param[in] aMessageInfo A reference to an address of the peer.
* @param[in] aCallback A pointer to a function that will be called once DTLS connection is established.
* @param[in] aMessageInfo A pointer to a message info structure.
* @param[in] aCallback A pointer to a function that will be called once DTLS connection is
* established.
*
* @retval OT_ERROR_NONE Successfully started DTLS connection.
*
@@ -160,6 +180,101 @@ public:
*/
otError SetPsk(const uint8_t *aPsk, uint8_t aPskLength);
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
/**
* This method sets the Pre Shared Key (PSK) for DTLS sessions
* identified by a PSK.
* DTLS mode "TLS with AES 128 CCM 8" for Application CoAPS.
*
* @param[in] aPsk A pointer to the PSK.
* @param[in] aPskLength The PSK char length.
* @param[in] aPskIdentity The Identity Name for the PSK.
* @param[in] aPskIdLength The PSK Identity Length.
*
* @retval OT_ERROR_NONE Successfully set the PSK.
*
*/
otError SetPreSharedKey(const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength);
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
/**
* This method sets a X509 certificate with corresponding private key for DTLS session.
*
* DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
*
* @param[in] aX509Certificate A pointer to the PEM formatted X509 PEM certificate.
* @param[in] aX509CertLength The length of certificate.
* @param[in] aPrivateKey A pointer to the PEM formatted private key.
* @param[in] aPrivateKeyLength The length of the private key.
*
* @retval OT_ERROR_NONE Successfully set the x509 certificate with his private key.
*
*/
otError SetCertificate(const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength);
/**
* This method sets the trusted top level CAs. It is needed for validate the
* certificate of the peer.
*
* DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
*
* @param[in] aX509CaCertificateChain A pointer to the PEM formatted X509 CA chain.
* @param[in] aX509CaCertChainLength The length of chain.
*
* @retval OT_ERROR_NONE Successfully set the the trusted top level CAs.
*
*/
otError SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength);
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#ifdef MBEDTLS_BASE64_C
/**
* This method returns the peer x509 certificate base64 encoded.
*
* DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
*
* @param[out] aPeerCert A pointer to the base64 encoded certificate buffer.
* @param[out] aCertLength The length of the base64 encoded peer certificate.
* @param[in] aCertBufferSize The buffer size of aPeerCert.
*
* @retval OT_ERROR_NONE Successfully get the peer certificate.
* @retval OT_ERROR_NO_BUFS Can't allocate memory for certificate.
*
*/
otError GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize);
#endif // MBEDTLS_BASE64_C
/**
* This method sets the connected callback to indicate, when
* a Client connect to the CoAP Secure server.
*
* @param[in] aCallback A pointer to a function that will be called once DTLS connection is
* established.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
void SetClientConnectedCallback(ConnectedCallback aCallback, void *aContext);
/**
* This method set the authentication mode for the coap secure connection.
* Disable or enable the verification of peer certificate.
*
* @param[in] aVerifyPeerCertificate true, if the peer certificate should verify.
*
*/
void SetSslAuthMode(bool aVerifyPeerCertificate);
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* This method sends a CoAP message over secure DTLS connection.
*
@@ -218,6 +333,9 @@ public:
*/
const Ip6::MessageInfo &GetPeerMessageInfo(void) const { return mPeerAddress; }
protected:
void HandleUdpTransmit(void);
private:
virtual otError Send(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
@@ -231,7 +349,6 @@ private:
otError HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, uint8_t aMessageSubType);
static void HandleUdpTransmit(Tasklet &aTasklet);
void HandleUdpTransmit(void);
static void HandleRetransmissionTimer(Timer &aTimer);
static void HandleResponsesQueueTimer(Timer &aTimer);
@@ -243,8 +360,35 @@ private:
void * mTransportContext;
Message * mTransmitMessage;
Tasklet mTransmitTask;
bool mLayerTwoSecurity : 1;
};
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* This class implements the application CoAP Secure client and server.
*
*/
class ApplicationCoapSecure : public CoapSecure
{
public:
/**
* This constructor initializes the object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit ApplicationCoapSecure(Instance &aInstance);
private:
static void HandleRetransmissionTimer(Timer &aTimer);
static void HandleResponsesQueueTimer(Timer &aTimer);
static void HandleUdpTransmit(Tasklet &aTasklet);
};
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
} // namespace Coap
} // namespace ot
+3
View File
@@ -67,6 +67,9 @@ Instance::Instance(void)
#if OPENTHREAD_ENABLE_APPLICATION_COAP
, mApplicationCoap(*this)
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
, mApplicationCoapSecure(*this)
#endif
#if OPENTHREAD_ENABLE_CHANNEL_MONITOR
, mChannelMonitor(*this)
#endif
+21
View File
@@ -328,6 +328,16 @@ public:
Coap::ApplicationCoap &GetApplicationCoap(void) { return mApplicationCoap; }
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* This method returns a reference to application COAP Secure object.
*
* @returns A reference to the application COAP Secure object.
*
*/
Coap::ApplicationCoapSecure &GetApplicationCoapSecure(void) { return mApplicationCoapSecure; }
#endif
#if OPENTHREAD_ENABLE_CHANNEL_MONITOR
/**
* This method returns a reference to ChannelMonitor object.
@@ -426,6 +436,10 @@ private:
Coap::ApplicationCoap mApplicationCoap;
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
Coap::ApplicationCoapSecure mApplicationCoapSecure;
#endif
#if OPENTHREAD_ENABLE_CHANNEL_MONITOR
Utils::ChannelMonitor mChannelMonitor;
#endif
@@ -571,6 +585,13 @@ template <> inline Coap::ApplicationCoap &Instance::Get(void)
}
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
template <> inline Coap::ApplicationCoapSecure &Instance::Get(void)
{
return GetApplicationCoapSecure();
}
#endif
#if OPENTHREAD_ENABLE_COMMISSIONER && OPENTHREAD_FTD
template <> inline MeshCoP::Commissioner &Instance::Get(void)
{
+382 -29
View File
@@ -56,6 +56,7 @@ namespace MeshCoP {
Dtls::Dtls(Instance &aInstance)
: InstanceLocator(aInstance)
, mPskLength(0)
, mVerifyPeerCertificate(true)
, mStarted(false)
, mTimer(aInstance, &Dtls::HandleTimer, this)
, mTimerIntermediate(0)
@@ -68,15 +69,42 @@ Dtls::Dtls(Instance &aInstance)
, mSendHandler(NULL)
, mContext(NULL)
, mClient(false)
, mGuardTimerSet(false)
, mMessageSubType(Message::kSubTypeNone)
, mMessageDefaultSubType(Message::kSubTypeNone)
{
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
mPreSharedKey = NULL;
mPreSharedKeyIdentity = NULL;
mPreSharedKeyIdLength = 0;
mPreSharedKeyLength = 0;
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
mCaChainSrc = NULL;
mCaChainLength = 0;
mOwnCertSrc = NULL;
mOwnCertLength = 0;
mPrivateKeySrc = NULL;
mPrivateKeyLength = 0;
memset(&mCaChain, 0, sizeof(mCaChain));
memset(&mOwnCert, 0, sizeof(mOwnCert));
memset(&mPrivateKey, 0, sizeof(mPrivateKey));
mbedtls_x509_crt_init(&mCaChain);
mbedtls_x509_crt_init(&mOwnCert);
mbedtls_pk_init(&mPrivateKey);
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
memset(mCipherSuites, 0, sizeof(mCipherSuites));
memset(mPsk, 0, sizeof(mPsk));
memset(&mEntropy, 0, sizeof(mEntropy));
memset(&mCtrDrbg, 0, sizeof(mCtrDrbg));
memset(&mSsl, 0, sizeof(mSsl));
memset(&mConf, 0, sizeof(mConf));
memset(&mCookieCtx, 0, sizeof(mCookieCtx));
mProvisioningUrl.Init();
}
@@ -111,9 +139,8 @@ otError Dtls::Start(bool aClient,
SendHandler aSendHandler,
void * aContext)
{
static const int ciphersuites[2] = {0xC0FF, 0}; // EC-JPAKE cipher suite
otExtAddress eui64;
int rval;
otExtAddress eui64;
int rval;
mConnectedHandler = aConnectedHandler;
mReceiveHandler = aReceiveHandler;
@@ -123,6 +150,9 @@ otError Dtls::Start(bool aClient,
mReceiveMessage = NULL;
mMessageSubType = Message::kSubTypeNone;
// do not handle new connection before guard time expired
VerifyOrExit(mGuardTimerSet == false, rval = MBEDTLS_ERR_SSL_TIMEOUT);
mbedtls_ssl_init(&mSsl);
mbedtls_ssl_config_init(&mConf);
mbedtls_ctr_drbg_init(&mCtrDrbg);
@@ -141,10 +171,23 @@ otError Dtls::Start(bool aClient,
MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT);
VerifyOrExit(rval == 0);
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
if (mVerifyPeerCertificate && mCipherSuites[0] == MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8)
{
mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_REQUIRED);
}
else
{
mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_NONE);
}
#else
OT_UNUSED_VARIABLE(mVerifyPeerCertificate);
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
mbedtls_ssl_conf_rng(&mConf, mbedtls_ctr_drbg_random, &mCtrDrbg);
mbedtls_ssl_conf_min_version(&mConf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
mbedtls_ssl_conf_max_version(&mConf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
mbedtls_ssl_conf_ciphersuites(&mConf, ciphersuites);
mbedtls_ssl_conf_ciphersuites(&mConf, mCipherSuites);
mbedtls_ssl_conf_export_keys_cb(&mConf, HandleMbedtlsExportKeys, this);
mbedtls_ssl_conf_handshake_timeout(&mConf, 8000, 60000);
mbedtls_ssl_conf_dbg(&mConf, HandleMbedtlsDebug, this);
@@ -165,29 +208,108 @@ otError Dtls::Start(bool aClient,
mbedtls_ssl_set_bio(&mSsl, this, &Dtls::HandleMbedtlsTransmit, HandleMbedtlsReceive, NULL);
mbedtls_ssl_set_timer_cb(&mSsl, this, &Dtls::HandleMbedtlsSetTimer, HandleMbedtlsGetTimer);
rval = mbedtls_ssl_set_hs_ecjpake_password(&mSsl, mPsk, mPskLength);
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
rval = mbedtls_ssl_set_hs_ecjpake_password(&mSsl, mPsk, mPskLength);
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
else
{
rval = SetApplicationCoapSecureKeys();
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
VerifyOrExit(rval == 0);
mStarted = true;
Process();
otLogInfoMeshCoP(GetInstance(), "DTLS started");
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
otLogInfoMeshCoP(GetInstance(), "DTLS started");
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
else
{
otLogInfoCoap(GetInstance(), "Application Coap Secure DTLS started");
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
exit:
return MapError(rval);
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
int Dtls::SetApplicationCoapSecureKeys(void)
{
int rval = 0;
VerifyOrExit(&mCipherSuites[0] != NULL, rval = MBEDTLS_ERR_SSL_BAD_INPUT_DATA);
switch (mCipherSuites[0])
{
case MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
if (mCaChainSrc != NULL)
{
rval = mbedtls_x509_crt_parse(&mCaChain, (const unsigned char *)mCaChainSrc, (size_t)mCaChainLength);
VerifyOrExit(rval == 0);
mbedtls_ssl_conf_ca_chain(&mConf, &mCaChain, NULL);
}
if (mOwnCertSrc != NULL && mPrivateKeySrc != NULL)
{
rval = mbedtls_x509_crt_parse(&mOwnCert, (const unsigned char *)mOwnCertSrc, (size_t)mOwnCertLength);
VerifyOrExit(rval == 0);
rval = mbedtls_pk_parse_key(&mPrivateKey, (const unsigned char *)mPrivateKeySrc, (size_t)mPrivateKeyLength,
NULL, 0);
VerifyOrExit(rval == 0);
rval = mbedtls_ssl_conf_own_cert(&mConf, &mOwnCert, &mPrivateKey);
VerifyOrExit(rval == 0);
}
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
break;
case MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8:
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
rval = mbedtls_ssl_conf_psk(&mConf, (unsigned char *)mPreSharedKey, mPreSharedKeyLength,
(unsigned char *)mPreSharedKeyIdentity, mPreSharedKeyIdLength);
VerifyOrExit(rval == 0);
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
break;
default:
otLogCritCoap(GetInstance(), "Application Coap Secure DTLS: Not supported cipher.");
rval = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
ExitNow();
break;
}
exit:
return rval;
}
void Dtls::SetSslAuthMode(bool aVerifyPeerCertificate)
{
mVerifyPeerCertificate = aVerifyPeerCertificate;
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
otError Dtls::Stop(void)
{
mbedtls_ssl_close_notify(&mSsl);
Close();
return OT_ERROR_NONE;
}
void Dtls::Close(void)
{
// guard time, that the possible close notify
// not open an invalid (new) connection
mGuardTimerSet = true;
mTimer.Start(kGuardTimeNewConnectionMilli);
VerifyOrExit(mStarted);
mStarted = false;
mbedtls_ssl_free(&mSsl);
mbedtls_ssl_config_free(&mConf);
@@ -195,6 +317,14 @@ void Dtls::Close(void)
mbedtls_entropy_free(&mEntropy);
mbedtls_ssl_cookie_free(&mCookieCtx);
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
mbedtls_x509_crt_free(&mCaChain);
mbedtls_x509_crt_free(&mOwnCert);
mbedtls_pk_free(&mPrivateKey);
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
if (mConnectedHandler != NULL)
{
mConnectedHandler(mContext, false);
@@ -216,12 +346,101 @@ otError Dtls::SetPsk(const uint8_t *aPsk, uint8_t aPskLength)
VerifyOrExit(aPskLength <= sizeof(mPsk), error = OT_ERROR_INVALID_ARGS);
memcpy(mPsk, aPsk, aPskLength);
mPskLength = aPskLength;
mPskLength = aPskLength;
mCipherSuites[0] = MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8;
mCipherSuites[1] = 0;
exit:
return error;
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
otError Dtls::SetCertificate(const uint8_t *aX509Certificate,
uint32_t aX509CertLength,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength)
{
otError error = OT_ERROR_NONE;
assert(aX509CertLength > 0);
assert(aX509Certificate != NULL);
assert(aPrivateKeyLength > 0);
assert(aPrivateKey != NULL);
mOwnCertSrc = aX509Certificate;
mOwnCertLength = aX509CertLength;
mPrivateKeySrc = aPrivateKey;
mPrivateKeyLength = aPrivateKeyLength;
mCipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
mCipherSuites[1] = 0;
return error;
}
otError Dtls::SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength)
{
otError error = OT_ERROR_NONE;
assert(aX509CaCertChainLength > 0);
assert(aX509CaCertificateChain != NULL);
mCaChainSrc = aX509CaCertificateChain;
mCaChainLength = aX509CaCertChainLength;
return error;
}
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
otError Dtls::SetPreSharedKey(const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength)
{
otError error = OT_ERROR_NONE;
assert(aPsk != NULL);
assert(aPskIdentity != NULL);
assert(aPskLength > 0);
assert(aPskIdLength > 0);
mPreSharedKey = aPsk;
mPreSharedKeyLength = aPskLength;
mPreSharedKeyIdentity = aPskIdentity;
mPreSharedKeyIdLength = aPskIdLength;
mCipherSuites[0] = MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8;
mCipherSuites[1] = 0;
return error;
}
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#ifdef MBEDTLS_BASE64_C
otError Dtls::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(IsConnected() == true, error = OT_ERROR_INVALID_STATE);
VerifyOrExit(mbedtls_base64_encode(aPeerCert, aCertBufferSize, aCertLength, mSsl.session->peer_cert->raw.p,
mSsl.session->peer_cert->raw.len) == 0,
error = OT_ERROR_NO_BUFS);
exit:
return error;
}
#endif // MBEDTLS_BASE64_C
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
otError Dtls::SetClientId(const uint8_t *aClientId, uint8_t aLength)
{
int rval = mbedtls_ssl_set_client_transport_id(&mSsl, aClientId, aLength);
@@ -277,7 +496,16 @@ int Dtls::HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength)
otError error;
int rval = 0;
otLogInfoMeshCoP(GetInstance(), "Dtls::HandleMbedtlsTransmit");
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
otLogInfoMeshCoP(GetInstance(), "Dtls::HandleMbedtlsTransmit");
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
else
{
otLogInfoCoap(GetInstance(), "Dtls::ApplicationCoapSecure HandleMbedtlsTransmit");
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
error = mSendHandler(mContext, aBuf, static_cast<uint16_t>(aLength), mMessageSubType);
@@ -311,7 +539,16 @@ int Dtls::HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength)
{
int rval;
otLogInfoMeshCoP(GetInstance(), "Dtls::HandleMbedtlsReceive");
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
otLogInfoMeshCoP(GetInstance(), "Dtls::HandleMbedtlsReceive");
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
else
{
otLogInfoCoap(GetInstance(), "Dtls:: ApplicationCoapSecure HandleMbedtlsReceive");
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
VerifyOrExit(mReceiveMessage != NULL && mReceiveLength != 0, rval = MBEDTLS_ERR_SSL_WANT_READ);
@@ -337,7 +574,16 @@ int Dtls::HandleMbedtlsGetTimer(void)
{
int rval;
otLogInfoMeshCoP(GetInstance(), "Dtls::HandleMbedtlsGetTimer");
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
otLogInfoMeshCoP(GetInstance(), "Dtls::HandleMbedtlsGetTimer");
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
else
{
otLogInfoCoap(GetInstance(), "Dtls:: ApplicationCoapSecure HandleMbedtlsGetTimer");
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
if (!mTimerSet)
{
@@ -366,7 +612,16 @@ void Dtls::HandleMbedtlsSetTimer(void *aContext, uint32_t aIntermediate, uint32_
void Dtls::HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish)
{
otLogInfoMeshCoP(GetInstance(), "Dtls::SetTimer");
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
otLogInfoMeshCoP(GetInstance(), "Dtls::SetTimer");
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
else
{
otLogInfoCoap(GetInstance(), "Dtls::ApplicationCoapSecure SetTimer");
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
if (aFinish == 0)
{
@@ -407,7 +662,16 @@ int Dtls::HandleMbedtlsExportKeys(const unsigned char *aMasterSecret,
GetNetif().GetKeyManager().SetKek(kek);
otLogInfoMeshCoP(GetInstance(), "Generated KEK");
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
otLogInfoMeshCoP(GetInstance(), "Generated KEK");
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
else
{
otLogInfoCoap(GetInstance(), "ApplicationCoapSecure Generated KEK");
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
OT_UNUSED_VARIABLE(aMasterSecret);
return 0;
@@ -420,7 +684,15 @@ void Dtls::HandleTimer(Timer &aTimer)
void Dtls::HandleTimer(void)
{
Process();
if (!mGuardTimerSet)
{
Process();
}
else
{
mGuardTimerSet = false;
mTimer.Stop();
}
}
void Dtls::Process(void)
@@ -492,7 +764,10 @@ void Dtls::Process(void)
}
mbedtls_ssl_session_reset(&mSsl);
mbedtls_ssl_set_hs_ecjpake_password(&mSsl, mPsk, mPskLength);
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
mbedtls_ssl_set_hs_ecjpake_password(&mSsl, mPsk, mPskLength);
}
break;
}
}
@@ -511,15 +786,69 @@ otError Dtls::MapError(int rval)
switch (rval)
{
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
case MBEDTLS_ERR_PK_TYPE_MISMATCH:
case MBEDTLS_ERR_PK_FILE_IO_ERROR:
case MBEDTLS_ERR_PK_KEY_INVALID_VERSION:
case MBEDTLS_ERR_PK_KEY_INVALID_FORMAT:
case MBEDTLS_ERR_PK_UNKNOWN_PK_ALG:
case MBEDTLS_ERR_PK_PASSWORD_REQUIRED:
case MBEDTLS_ERR_PK_PASSWORD_MISMATCH:
case MBEDTLS_ERR_PK_INVALID_PUBKEY:
case MBEDTLS_ERR_PK_INVALID_ALG:
case MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE:
case MBEDTLS_ERR_PK_BAD_INPUT_DATA:
case MBEDTLS_ERR_X509_SIG_MISMATCH:
case MBEDTLS_ERR_X509_BAD_INPUT_DATA:
case MBEDTLS_ERR_X509_FILE_IO_ERROR:
case MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT:
case MBEDTLS_ERR_X509_INVALID_VERSION:
case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG:
case MBEDTLS_ERR_X509_INVALID_SERIAL:
case MBEDTLS_ERR_X509_UNKNOWN_OID:
case MBEDTLS_ERR_X509_INVALID_FORMAT:
case MBEDTLS_ERR_X509_INVALID_ALG:
case MBEDTLS_ERR_X509_INVALID_NAME:
case MBEDTLS_ERR_X509_INVALID_DATE:
case MBEDTLS_ERR_X509_INVALID_SIGNATURE:
case MBEDTLS_ERR_X509_INVALID_EXTENSIONS:
case MBEDTLS_ERR_X509_UNKNOWN_VERSION:
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
case MBEDTLS_ERR_SSL_BAD_INPUT_DATA:
error = OT_ERROR_INVALID_ARGS;
break;
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
case MBEDTLS_ERR_PK_ALLOC_FAILED:
case MBEDTLS_ERR_X509_BUFFER_TOO_SMALL:
case MBEDTLS_ERR_X509_ALLOC_FAILED:
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
case MBEDTLS_ERR_SSL_ALLOC_FAILED:
case MBEDTLS_ERR_SSL_WANT_WRITE:
error = OT_ERROR_NO_BUFS;
break;
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
case MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE:
case MBEDTLS_ERR_PK_SIG_LEN_MISMATCH:
case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE:
case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
case MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED:
case MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED:
error = OT_ERROR_SECURITY;
break;
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
case MBEDTLS_ERR_X509_FATAL_ERROR:
error = OT_ERROR_FAILED;
break;
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
case MBEDTLS_ERR_SSL_TIMEOUT:
error = OT_ERROR_BUSY;
break;
default:
assert(rval >= 0);
break;
@@ -534,25 +863,49 @@ void Dtls::HandleMbedtlsDebug(void *ctx, int level, const char *, int, const cha
OT_UNUSED_VARIABLE(pThis);
OT_UNUSED_VARIABLE(str);
switch (level)
if (pThis->mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
case 1:
otLogCritMbedTls(pThis->GetInstance(), "%s", str);
break;
switch (level)
{
case 1:
otLogCritMbedTls(pThis->GetInstance(), "%s", str);
break;
case 2:
otLogWarnMbedTls(pThis->GetInstance(), "%s", str);
break;
case 2:
otLogWarnMbedTls(pThis->GetInstance(), "%s", str);
break;
case 3:
otLogInfoMbedTls(pThis->GetInstance(), "%s", str);
break;
case 3:
otLogInfoMbedTls(pThis->GetInstance(), "%s", str);
break;
case 4:
default:
otLogDebgMbedTls(pThis->GetInstance(), "%s", str);
break;
case 4:
default:
otLogDebgMbedTls(pThis->GetInstance(), "%s", str);
break;
}
}
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
else
{
switch (level)
{
case 1:
otLogCritCoap(pThis->GetInstance(), "ApplicationCoapSecure Mbedtls: %s", str);
break;
case 2:
otLogWarnCoap(pThis->GetInstance(), "ApplicationCoapSecure Mbedtls: %s", str);
break;
case 3:
otLogInfoCoap(pThis->GetInstance(), "ApplicationCoapSecure Mbedtls: %s", str);
break;
case 4:
default:
otLogDebgCoap(pThis->GetInstance(), "ApplicationCoapSecure Mbedtls: %s", str);
break;
}
}
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
}
} // namespace MeshCoP
+150 -7
View File
@@ -44,6 +44,16 @@
#include <mbedtls/ssl.h>
#include <mbedtls/ssl_cookie.h>
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#include <mbedtls/base64.h>
#include <mbedtls/x509.h>
#include <mbedtls/x509_crl.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/x509_csr.h>
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/timer.hpp"
@@ -59,8 +69,13 @@ class Dtls : public InstanceLocator
public:
enum
{
kPskMaxLength = 32,
kPskMaxLength = 32,
kGuardTimeNewConnectionMilli = 2000,
#if !OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
kApplicationDataMaxLength = 512,
#else
kApplicationDataMaxLength = OPENTHREAD_CONFIG_DTLS_APPLICATION_DATA_MAX_LENGTH,
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
};
/**
@@ -104,11 +119,15 @@ public:
/**
* This method starts the DTLS service.
*
* @param[in] aClient TRUE if operating as a client, FALSE if operating as a server.
* @param[in] aConnectedHandler A pointer to the connected handler.
* @param[in] aReceiveHandler A pointer to the receive handler.
* @param[in] aSendHandler A pointer to the send handler.
* @param[in] aContext A pointer to application-specific context.
* For CoAP Secure API do first:
* Set X509 Pk and Cert for use DTLS mode ECDHE ECDSA with AES 128 CCM 8 or
* set PreShared Key for use DTLS mode PSK with AES 128 CCM 8.
*
* @param[in] aClient TRUE if operating as a client, FALSE if operating as a server.
* @param[in] aConnectedHandler A pointer to the connected handler.
* @param[in] aReceiveHandler A pointer to the receive handler.
* @param[in] aSendHandler A pointer to the send handler.
* @param[in] aContext A pointer to application-specific context.
*
* @retval OT_ERROR_NONE Successfully started the DTLS service.
*
@@ -130,7 +149,7 @@ public:
/**
* This method indicates whether or not the DTLS service is active.
*
* @returns TRUE if the DTLS service is active, FALSE otherwise.
* @returns true if the DTLS service is active, false otherwise.
*
*/
bool IsStarted(void);
@@ -146,6 +165,94 @@ public:
*/
otError SetPsk(const uint8_t *aPsk, uint8_t aPskLength);
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
/**
* This method sets the Pre-Shared Key (PSK) for DTLS sessions-
* identified by a PSK.
*
* DTLS mode "PSK with AES 128 CCM 8" for Application CoAPS.
*
* @param[in] aPsk A pointer to the PSK.
* @param[in] aPskLength The PSK char length.
* @param[in] aPskIdentity The Identity Name for the PSK.
* @param[in] aPskIdLength The PSK Identity Length.
*
* @retval OT_ERROR_NONE Successfully set the PSK.
*
*/
otError SetPreSharedKey(const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength);
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
/**
* This method sets a reference to the own x509 certificate with corresponding private key.
*
* DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
*
* @param[in] aX509Certificate A pointer to the PEM formatted X509 certificate.
* @param[in] aX509CertLength The length of certificate.
* @param[in] aPrivateKey A pointer to the PEM formatted private key.
* @param[in] aPrivateKeyLength The length of the private key.
*
* @retval OT_ERROR_NONE Successfully set the x509 certificate with his private key.
*
*/
otError SetCertificate(const uint8_t *aX509Certificate,
uint32_t aX509CertLength,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength);
/**
* This method sets the trusted top level CAs. It is needed for validate the
* certificate of the peer.
*
* DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
*
* @param[in] aX509CaCertificateChain A pointer to the PEM formatted X509 CA chain.
* @param[in] aX509CaCertChainLength The length of chain.
*
* @retval OT_ERROR_NONE Successfully set the the trusted top level CAs.
*
*/
otError SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength);
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#ifdef MBEDTLS_BASE64_C
/**
* This method returns the peer x509 certificate base64 encoded.
*
* DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
*
* @param[out] aPeerCert A pointer to the base64 encoded certificate buffer.
* @param[out] aCertLength The length of the base64 encoded peer certificate.
* @param[in] aCertBufferSize The buffer size of aPeerCert.
*
* @retval OT_ERROR_NONE Successfully get the peer certificate.
* @retval OT_ERROR_NO_BUFS Can't allocate memory for certificate.
*
*/
otError GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize);
#endif // MBEDTLS_BASE64_C
/**
* This method set the authentication mode for a dtls connection.
*
* Disable or enable the verification of peer certificate.
* Must called before start.
*
* @param[in] aVerifyPeerCertificate true, if the peer certificate should verify.
*
*/
void SetSslAuthMode(bool aVerifyPeerCertificate);
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* This method sets the Client ID used for generating the Hello Cookie.
*
@@ -208,6 +315,16 @@ public:
private:
static otError MapError(int rval);
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* Set keys and/or certificates for dtls session dependent of used cipher suite.
*
* @retval mbedtls error, 0 if successfully.
*
*/
int SetApplicationCoapSecureKeys(void);
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
static void HandleMbedtlsDebug(void *ctx, int level, const char *file, int line, const char *str);
static int HandleMbedtlsGetTimer(void *aContext);
@@ -242,9 +359,34 @@ private:
void Close(void);
void Process(void);
int mCipherSuites[2];
uint8_t mPsk[kPskMaxLength];
uint8_t mPskLength;
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
const uint8_t * mCaChainSrc;
uint32_t mCaChainLength;
const uint8_t * mOwnCertSrc;
uint32_t mOwnCertLength;
const uint8_t * mPrivateKeySrc;
uint32_t mPrivateKeyLength;
mbedtls_x509_crt mCaChain;
mbedtls_x509_crt mOwnCert;
mbedtls_pk_context mPrivateKey;
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
const uint8_t *mPreSharedKey;
const uint8_t *mPreSharedKeyIdentity;
uint16_t mPreSharedKeyLength;
uint16_t mPreSharedKeyIdLength;
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
bool mVerifyPeerCertificate;
mbedtls_entropy_context mEntropy;
mbedtls_ctr_drbg_context mCtrDrbg;
mbedtls_ssl_context mSsl;
@@ -265,6 +407,7 @@ private:
SendHandler mSendHandler;
void * mContext;
bool mClient;
bool mGuardTimerSet;
uint8_t mMessageSubType;
uint8_t mMessageDefaultSubType;
+15 -1
View File
@@ -1067,8 +1067,12 @@
*
*/
#ifndef OPENTHREAD_CONFIG_HEAP_SIZE
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#define OPENTHREAD_CONFIG_HEAP_SIZE (1800 * sizeof(void *))
#else
#define OPENTHREAD_CONFIG_HEAP_SIZE (1536 * sizeof(void *))
#endif
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#endif // OPENTHREAD_CONFIG_HEAP_SIZE
/**
* @def OPENTHREAD_CONFIG_HEAP_SIZE_NO_DTLS
@@ -1080,6 +1084,16 @@
#define OPENTHREAD_CONFIG_HEAP_SIZE_NO_DTLS 384
#endif
/**
* @def OPENTHREAD_CONFIG_DTLS_APPLICATION_DATA_MAX_LENGTH
*
* The size of dtls application data when the CoAP Secure API is enabled.
*
*/
#ifndef OPENTHREAD_CONFIG_DTLS_APPLICATION_DATA_MAX_LENGTH
#define OPENTHREAD_CONFIG_DTLS_APPLICATION_DATA_MAX_LENGTH 1400
#endif
/**
* @def OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB
*
+1
View File
@@ -62,6 +62,7 @@ libmbedcrypto_a_SOURCES = \
repo/library/md_wrap.c \
repo/library/memory_buffer_alloc.c \
repo/library/oid.c \
repo/library/pem.c \
repo/library/pk.c \
repo/library/pk_wrap.c \
repo/library/pkparse.c \
+104
View File
@@ -527,6 +527,15 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
*/
//#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* Enable the PSK ciphersuite for Application Coap Secure.
*/
#ifndef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
*
@@ -699,6 +708,29 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
*/
//#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* Enables ciphersuite ECDHE ECDSA with x.509 certificate
* for Application Coap Secure.
*/
#ifndef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
/**
* To increase the security with ECDHE ECDSA enable
* X509 CHECK KEY USAGE.
* Not required!
*/
#ifndef MBEDTLS_X509_CHECK_KEY_USAGE
//#define MBEDTLS_X509_CHECK_KEY_USAGE
#endif // MBEDTLS_X509_CHECK_KEY_USAGE
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
*
@@ -1569,6 +1601,18 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
*/
//#define MBEDTLS_BASE64_C
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* Requiered by ciphersuite ECDHE ECDSA with x.509 certificate
* used by Application CoAP Secure.
*/
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#ifndef MBEDTLS_BASE64_C
#define MBEDTLS_BASE64_C
#endif // MBEDTLS_BASE64_C
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* \def MBEDTLS_BIGNUM_C
*
@@ -1786,6 +1830,17 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
#define MBEDTLS_ECDH_C
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
/**
* Required for ECDHE_ECDSA by Application CoAPS.
*/
#ifndef MBEDTLS_ECDH_C
#define MBEDTLS_ECDH_C
#endif // MBEDTLS_ECDH_C
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* \def MBEDTLS_ECDSA_C
*
@@ -1803,6 +1858,17 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
#define MBEDTLS_ECDSA_C
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* Required for ECDHA ECDSA by Application CoAPS.
*/
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#ifndef MBEDTLS_ECDSA_C
#define MBEDTLS_ECDSA_C
#endif // MBEDTLS_ECDSA_C
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* \def MBEDTLS_ECJPAKE_C
*
@@ -2056,6 +2122,18 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
*/
//#define MBEDTLS_PEM_PARSE_C
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* Requiered by ciphersuite ECDHE ECDSA with x.509 certificate
* used by Application CoAP Secure.
*/
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#ifndef MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PEM_PARSE_C
#endif // MBEDTLS_PEM_PARSE_C
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* \def MBEDTLS_PEM_WRITE_C
*
@@ -2411,6 +2489,17 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
#define MBEDTLS_X509_USE_C
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* Required for ECDHE ECDSA by Application CoAPS.
*/
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#ifndef MBEDTLS_X509_USE_C
#define MBEDTLS_X509_USE_C
#endif // MBEDTLS_X509_USE_C
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* \def MBEDTLS_X509_CRT_PARSE_C
*
@@ -2429,6 +2518,17 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
#define MBEDTLS_X509_CRT_PARSE_C
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* Required for ECDHE ECDSA by Application CoAPS.
*/
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
#ifndef MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_CRT_PARSE_C
#endif // MBEDTLS_X509_CRT_PARSE_C
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif // OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
/**
* \def MBEDTLS_X509_CRL_PARSE_C
*
@@ -2591,7 +2691,11 @@ __inline int windows_kernel_snprintf(char * s, size_t n, const char * format, ..
//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */
/* SSL options */
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#define MBEDTLS_SSL_MAX_CONTENT_LEN 900 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
#else
#define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
#endif
//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */
//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */