[tcat] initial commit of bluetooth-based commissioning (#9210)

This commit introduces first implementation of Bluetooth based
comissioning for thread devices.

Co-authored-by: Arnulf Rupp <a.rupp@inventronicsglobal.com>
Co-authored-by: Piotr Jasinski <piotr.jasinski@nordicsemi.no>
This commit is contained in:
Przemysław Bida
2023-12-04 21:09:25 +01:00
committed by GitHub
parent 3d01ffa65c
commit 5cab15840d
46 changed files with 4068 additions and 214 deletions
+1
View File
@@ -172,6 +172,7 @@ ot_option(OT_ASSERT OPENTHREAD_CONFIG_ASSERT_ENABLE "assert function OT_ASSERT()
ot_option(OT_BACKBONE_ROUTER OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE "backbone router functionality")
ot_option(OT_BACKBONE_ROUTER_DUA_NDPROXYING OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE "BBR DUA ND Proxy")
ot_option(OT_BACKBONE_ROUTER_MULTICAST_ROUTING OPENTHREAD_CONFIG_BACKBONE_ROUTER_MULTICAST_ROUTING_ENABLE "BBR MR")
ot_option(OT_BLE_TCAT OPENTHREAD_CONFIG_BLE_TCAT_ENABLE "Ble based thread commissioning")
ot_option(OT_BORDER_AGENT OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE "border agent")
ot_option(OT_BORDER_AGENT_ID OPENTHREAD_CONFIG_BORDER_AGENT_ID_ENABLE "create and save border agent ID")
ot_option(OT_BORDER_ROUTER OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE "border router")
+3
View File
@@ -81,6 +81,9 @@ if (openthread_enable_core_config_args) {
# Enable backbone router functionality
openthread_config_backbone_router_enable = false
# Enable BLE based commissioning functionality
openthread_config_ble_tcat_enable = false
# Enable border agent support
openthread_config_border_agent_enable = false
@@ -59,6 +59,7 @@ set(OT_PLATFORM_DEFINES ${OT_PLATFORM_DEFINES} PARENT_SCOPE)
add_library(openthread-simulation
alarm.c
ble.c
crypto.c
diag.c
dns.c
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2023, 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.
*/
#include <openthread/platform/ble.h>
otError otPlatBleEnable(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleDisable(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aInterval);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapAdvStop(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapDisconnect(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aMtu);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aHandle);
OT_UNUSED_VARIABLE(aPacket);
return OT_ERROR_NOT_IMPLEMENTED;
}
+3
View File
@@ -41,6 +41,7 @@ source_set("openthread") {
public = [
"backbone_router.h",
"backbone_router_ftd.h",
"ble_secure.h",
"border_agent.h",
"border_router.h",
"border_routing.h",
@@ -84,6 +85,7 @@ source_set("openthread") {
"ping_sender.h",
"platform/alarm-micro.h",
"platform/alarm-milli.h",
"platform/ble.h",
"platform/border_routing.h",
"platform/crypto.h",
"platform/debug_uart.h",
@@ -115,6 +117,7 @@ source_set("openthread") {
"srp_client_buffers.h",
"srp_server.h",
"tasklet.h",
"tcat.h",
"tcp.h",
"tcp_ext.h",
"thread.h",
+434
View File
@@ -0,0 +1,434 @@
/*
* Copyright (c) 2023, 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 BLE Secure implementation.
*
* @note
* The functions in this module require the build-time feature `OPENTHREAD_CONFIG_BLE_TCAT_ENABLE=1`.
*
* @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_BLE_SECURE_H_
#define OPENTHREAD_BLE_SECURE_H_
#include <stdint.h>
#include <openthread/message.h>
#include <openthread/tcat.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup api-ble-secure
*
* @brief
* This module includes functions that control BLE Secure (TLS over BLE) communication.
*
* The functions in this module are available when BLE Secure API feature
* (`OPENTHREAD_CONFIG_BLE_TCAT_ENABLE`) is enabled.
*
* @{
*
*/
/**
* Pointer to call when ble secure connection state changes.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aConnected TRUE, if a secure connection was established, FALSE otherwise.
* @param[in] aBleConnectionOpen TRUE if a BLE connection was established to carry a TLS data stream, FALSE
* otherwise.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
typedef void (*otHandleBleSecureConnect)(otInstance *aInstance,
bool aConnected,
bool aBleConnectionOpen,
void *aContext);
/**
* Pointer to call when data was received over a BLE Secure TLS connection.
*
*/
typedef otHandleTcatApplicationDataReceive otHandleBleSecureReceive;
/**
* Starts the BLE Secure service.
* When TLV mode is active, the function @p aReceiveHandler will be called once a complete TLV was received and the
* message offset points to the TLV value.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aConnectHandler A pointer to a function that will be called when the connection
* state changes.
* @param[in] aReceiveHandler A pointer to a function that will be called once data has been received
* over the TLS connection.
* @param[in] aTlvMode A boolean value indicating if line mode shall be activated.
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
*
* @retval OT_ERROR_NONE Successfully started the BLE Secure server.
* @retval OT_ERROR_ALREADY The service was stated already.
*
*/
otError otBleSecureStart(otInstance *aInstance,
otHandleBleSecureConnect aConnectHandler,
otHandleBleSecureReceive aReceiveHandler,
bool aTlvMode,
void *aContext);
/**
* Enables the TCAT protocol over BLE Secure.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aVendorInfo A pointer to the Vendor Information (must remain valid after the method call, may be
* NULL).
* @param[in] aHandler A pointer to a function that is called when the join operation completes.
*
* @retval OT_ERROR_NONE Successfully started the BLE Secure Joiner role.
* @retval OT_ERROR_INVALID_ARGS @p aElevationPsk or @p aVendorInfo is invalid.
* @retval OT_ERROR_INVALID_STATE The BLE function has not been started or line mode is not selected.
*
*/
otError otBleSecureTcatStart(otInstance *aInstance, const otTcatVendorInfo *aVendorInfo, otHandleTcatJoin aHandler);
/**
* Stops the BLE Secure server.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
*/
void otBleSecureStop(otInstance *aInstance);
/**
* Sets the Pre-Shared Key (PSK) and cipher suite
* TLS_PSK_WITH_AES_128_CCM_8.
*
* @note Requires the build-time feature `MBEDTLS_KEY_EXCHANGE_PSK_ENABLED` to be enabled.
*
* @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.
*
*/
void otBleSecureSetPsk(otInstance *aInstance,
const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength);
/**
* Returns the peer x509 certificate base64 encoded.
*
* @note Requires the build-time features `MBEDTLS_BASE64_C` and
* `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[out] aPeerCert A pointer to the base64 encoded certificate buffer.
* @param[in,out] aCertLength On input, the size the max size of @p aPeerCert.
* On output, the length of the base64 encoded peer certificate.
*
* @retval OT_ERROR_NONE Successfully get the peer certificate.
* @retval OT_ERROR_INVALID_ARGS @p aInstance or @p aCertLength is invalid.
* @retval OT_ERROR_INVALID_STATE Not connected yet.
* @retval OT_ERROR_NO_BUFS Can't allocate memory for certificate.
*
*/
otError otBleSecureGetPeerCertificateBase64(otInstance *aInstance, unsigned char *aPeerCert, size_t *aCertLength);
/**
* Returns an attribute value identified by its OID from the subject
* of the peer x509 certificate. The peer OID is provided in binary format.
* The attribute length is set if the attribute was successfully read or zero
* if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard
* if the attribute was successfully read.
*
* @note Requires the build-time feature
* `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aOid A pointer to the OID to be found.
* @param[in] aOidLength The length of the OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
* @param[out] aAsn1Type A pointer to the ASN.1 type of the attribute written to the buffer.
*
* @retval OT_ERROR_INVALID_STATE Not connected yet.
* @retval OT_ERROR_INVALID_ARGS Invalid attribute length.
* @retval OT_ERROR_NONE Successfully read attribute.
* @retval OT_ERROR_NO_BUFS Insufficient memory for storing the attribute value.
*
*/
otError otBleSecureGetPeerSubjectAttributeByOid(otInstance *aInstance,
const char *aOid,
size_t aOidLength,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength,
int *aAsn1Type);
/**
* Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of
* the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor.
* The attribute length is set if the attribute was successfully read or zero if unsuccessful.
* Requires a connection to be active.
*
* @note Requires the build-time feature
* `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` to be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
*
* @retval OT_ERROR_NONE Successfully read attribute.
* @retval OT_ERROR_INVALID_ARGS Invalid attribute length.
* @retval OT_NOT_FOUND The requested attribute was not found.
* @retval OT_ERROR_NO_BUFS Insufficient memory for storing the attribute value.
* @retval OT_ERROR_INVALID_STATE Not connected yet.
* @retval OT_ERROR_NOT_IMPLEMENTED The value of aThreadOidDescriptor is >127.
* @retval OT_ERROR_PARSE The certificate extensions could not be parsed.
*
*/
otError otBleSecureGetThreadAttributeFromPeerCertificate(otInstance *aInstance,
int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength);
/**
* Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of
* the own x509 certificate, where the last digit x is set to aThreadOidDescriptor.
* The attribute length is set if the attribute was successfully read or zero if unsuccessful.
* Requires a connection to be active.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
*
* @retval OT_ERROR_NONE Successfully read attribute.
* @retval OT_ERROR_INVALID_ARGS Invalid attribute length.
* @retval OT_NOT_FOUND The requested attribute was not found.
* @retval OT_ERROR_NO_BUFS Insufficient memory for storing the attribute value.
* @retval OT_ERROR_INVALID_STATE Not connected yet.
* @retval OT_ERROR_NOT_IMPLEMENTED The value of aThreadOidDescriptor is >127.
* @retval OT_ERROR_PARSE The certificate extensions could not be parsed.
*
*/
otError otBleSecureGetThreadAttributeFromOwnCertificate(otInstance *aInstance,
int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength);
/**
* Sets the authentication mode for the BLE 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 otBleSecureSetSslAuthMode(otInstance *aInstance, bool aVerifyPeerCertificate);
/**
* Sets the local device's X509 certificate with corresponding private key for
* TLS session with TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8.
*
* @note Requires `MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=1`.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aX509Cert 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.
*
*/
void otBleSecureSetCertificate(otInstance *aInstance,
const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength);
/**
* Sets the trusted top level CAs. It is needed for validating the
* certificate of the peer.
*
* TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE.
*
* @note Requires `MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=1`.
*
* @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.
*
*/
void otBleSecureSetCaCertificateChain(otInstance *aInstance,
const uint8_t *aX509CaCertificateChain,
uint32_t aX509CaCertChainLength);
/**
* Initializes TLS session with a peer using an already open BLE connection.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval OT_ERROR_NONE Successfully started TLS connection.
*
*/
otError otBleSecureConnect(otInstance *aInstance);
/**
* Stops the BLE and TLS connection.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
*/
void otBleSecureDisconnect(otInstance *aInstance);
/**
* Indicates whether or not the TLS session is active (connected or conneting).
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval TRUE If TLS session is active.
* @retval FALSE If TLS session is not active.
*
*/
bool otBleSecureIsConnectionActive(otInstance *aInstance);
/**
* Indicates whether or not the TLS session is connected.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval TRUE The TLS session is connected.
* @retval FALSE The TLS session is not connected.
*
*/
bool otBleSecureIsConnected(otInstance *aInstance);
/**
* Indicates whether or not the TCAT agent is enabled.
*
* @retval TRUE The TCAT agent is enabled.
* @retval FALSE The TCAT agent is not enabled.
*
*/
bool otBleSecureIsTcatEnabled(otInstance *aInstance);
/**
* Indicates whether or not a TCAT command class is authorized.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aCommandClass A command class to check.
*
* @retval TRUE The command class is authorized.
* @retval FALSE The command class is not authorized.
*
*/
bool otBleSecureIsCommandClassAuthorized(otInstance *aInstance, otTcatCommandClass aCommandClass);
/**
* Sends a secure BLE message.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMessage A pointer to the message to send.
*
* If the return value is OT_ERROR_NONE, OpenThread takes ownership of @p aMessage, and the caller should no longer
* reference @p aMessage. If the return value is not OT_ERROR_NONE, the caller retains ownership of @p aMessage,
* including freeing @p aMessage if the message buffer is no longer needed.
*
* @retval OT_ERROR_NONE Successfully sent message.
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory.
* @retval OT_ERROR_INVALID_STATE TLS connection was not initialized.
*
*/
otError otBleSecureSendMessage(otInstance *aInstance, otMessage *aMessage);
/**
* Sends a secure BLE data packet.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV.
* @param[in] aLength A number indicating the length of the data buffer.
*
* @retval OT_ERROR_NONE Successfully sent data.
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory.
* @retval OT_ERROR_INVALID_STATE TLS connection was not initialized.
*
*/
otError otBleSecureSend(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength);
/**
* Sends a secure BLE data packet containing a TCAT Send Application Data TLV.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV.
* @param[in] aLength A number indicating the length of the data buffer.
*
* @retval OT_ERROR_NONE Successfully sent data.
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory.
* @retval OT_ERROR_INVALID_STATE TLS connection was not initialized.
*
*/
otError otBleSecureSendApplicationTlv(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength);
/**
* Flushes the send buffer.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval OT_ERROR_NONE Successfully flushed output buffer.
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer memory.
* @retval OT_ERROR_INVALID_STATE TLS connection was not initialized.
*
*/
otError otBleSecureFlush(otInstance *aInstance);
/**
* @}
*
*/
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OPENTHREAD_BLE_SECURE_H_ */
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (380)
#define OPENTHREAD_API_VERSION (381)
/**
* @addtogroup api-instance
+293
View File
@@ -0,0 +1,293 @@
/*
* Copyright (c) 2023, 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 a OpenThread BLE GATT peripheral interface driver.
*
*/
#ifndef OPENTHREAD_PLATFORM_BLE_H_
#define OPENTHREAD_PLATFORM_BLE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <openthread/error.h>
#include <openthread/instance.h>
/**
* @addtogroup plat-ble
*
* @brief
* This module includes the platform abstraction for BLE Host communication.
* The platform needs to implement Bluetooth LE 4.2 or higher.
*
* @{
*
*/
/**
* Time slot duration on PHY layer in microseconds (0.625ms).
*
*/
#define OT_BLE_TIMESLOT_UNIT 625
/**
* Minimum allowed interval for advertising packet in OT_BLE_ADV_INTERVAL_UNIT units (20ms).
*
*/
#define OT_BLE_ADV_INTERVAL_MIN 0x0020
/**
* Maximum allowed interval for advertising packet in OT_BLE_ADV_INTERVAL_UNIT units (10.24s).
*
*/
#define OT_BLE_ADV_INTERVAL_MAX 0x4000
/**
* Default interval for advertising packet (ms).
*
*/
#define OT_BLE_ADV_INTERVAL_DEFAULT 100
/**
* Unit used to calculate interval duration (0.625ms).
*
*/
#define OT_BLE_ADV_INTERVAL_UNIT OT_BLE_TIMESLOT_UNIT
/**
* Maximum allowed ATT MTU size (must be >= 23).
*
*/
#define OT_BLE_ATT_MTU_MAX 67
/**
* Default power value for BLE.
*/
#define OT_BLE_DEFAULT_POWER 0
/**
* Represents a BLE packet.
*
*/
typedef struct otBleRadioPacket
{
uint8_t *mValue; ///< The value of an attribute
uint16_t mLength; ///< Length of the @p mValue.
int8_t mPower; ///< Transmit/receive power in dBm.
} otBleRadioPacket;
/*******************************************************************************
* @section Bluetooth Low Energy management.
******************************************************************************/
/**
* Enable the Bluetooth Low Energy radio.
*
* @note BLE Device should use the highest ATT_MTU supported that does not
* exceed OT_BLE_ATT_MTU_MAX octets.
*
* @param[in] aInstance The OpenThread instance structure.
*
* @retval OT_ERROR_NONE Successfully enabled.
* @retval OT_ERROR_FAILED The BLE radio could not be enabled.
*/
otError otPlatBleEnable(otInstance *aInstance);
/**
* Disable the Bluetooth Low Energy radio.
*
* When disabled, the BLE stack will flush event queues and not generate new
* events. The BLE peripheral is turned off or put into a low power sleep
* state. Any dynamic memory used by the stack should be released,
* but static memory may remain reserved.
*
* @param[in] aInstance The OpenThread instance structure.
*
* @retval OT_ERROR_NONE Successfully transitioned to disabled.
* @retval OT_ERROR_FAILED The BLE radio could not be disabled.
*
*/
otError otPlatBleDisable(otInstance *aInstance);
/****************************************************************************
* @section Bluetooth Low Energy GAP.
***************************************************************************/
/**
* Starts BLE Advertising procedure.
*
* The BLE device shall use undirected advertising with no filter applied.
* A single BLE Advertising packet must be sent on all advertising
* channels (37, 38 and 39).
*
* @note This function shall be used only for BLE Peripheral role.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aInterval The interval between subsequent advertising packets
* in OT_BLE_ADV_INTERVAL_UNIT units.
* Shall be within OT_BLE_ADV_INTERVAL_MIN and
* OT_BLE_ADV_INTERVAL_MAX range or OT_BLE_ADV_INTERVAL_DEFAULT
* for a default value set at compile time.
*
* @retval OT_ERROR_NONE Advertising procedure has been started.
* @retval OT_ERROR_INVALID_STATE BLE Device is in invalid state.
* @retval OT_ERROR_INVALID_ARGS Invalid interval value has been supplied.
*
*/
otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval);
/**
* Stops BLE Advertising procedure.
*
* @note This function shall be used only for BLE Peripheral role.
*
* @param[in] aInstance The OpenThread instance structure.
*
* @retval OT_ERROR_NONE Advertising procedure has been stopped.
* @retval OT_ERROR_INVALID_STATE BLE Device is in invalid state.
*
*/
otError otPlatBleGapAdvStop(otInstance *aInstance);
/**
* The BLE driver calls this method to notify OpenThread that a BLE Central Device has
* been connected.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aConnectionId The identifier of the open connection.
*
*/
extern void otPlatBleGapOnConnected(otInstance *aInstance, uint16_t aConnectionId);
/**
* The BLE driver calls this method to notify OpenThread that the BLE Central Device
* has been disconnected.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aConnectionId The identifier of the closed connection.
*
*/
extern void otPlatBleGapOnDisconnected(otInstance *aInstance, uint16_t aConnectionId);
/**
* Disconnects BLE connection.
*
* The BLE device shall use the Remote User Terminated Connection (0x13) reason
* code when disconnecting from the peer BLE device..
*
* @param[in] aInstance The OpenThread instance structure.
*
* @retval OT_ERROR_NONE Disconnection procedure has been started.
* @retval OT_ERROR_INVALID_STATE BLE Device is in invalid state.
*
*/
otError otPlatBleGapDisconnect(otInstance *aInstance);
/*******************************************************************************
* @section Bluetooth Low Energy GATT Common.
*******************************************************************************/
/**
* Reads currently use value of ATT_MTU.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[out] aMtu A pointer to output the current ATT_MTU value.
*
* @retval OT_ERROR_NONE ATT_MTU value has been placed in @p aMtu.
* @retval OT_ERROR_FAILED BLE Device cannot determine its ATT_MTU.
*
*/
otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu);
/**
* The BLE driver calls this method to notify OpenThread that ATT_MTU has been updated.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aMtu The updated ATT_MTU value.
*
*/
extern void otPlatBleGattOnMtuUpdate(otInstance *aInstance, uint16_t aMtu);
/*******************************************************************************
* @section Bluetooth Low Energy GATT Server.
******************************************************************************/
/**
* Sends ATT Handle Value Indication.
*
* @note This function shall be used only for GATT Server.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aHandle The handle of the attribute to be indicated.
* @param[in] aPacket A pointer to the packet contains value to be indicated.
*
* @retval OT_ERROR_NONE ATT Handle Value Indication has been sent.
* @retval OT_ERROR_INVALID_STATE BLE Device is in invalid state.
* @retval OT_ERROR_INVALID_ARGS Invalid handle value, data or data length has been supplied.
* @retval OT_ERROR_NO_BUFS No available internal buffer found.
*
*/
otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket);
/**
* The BLE driver calls this method to notify OpenThread that an ATT Write Request
* packet has been received.
*
* @note This function shall be used only for GATT Server.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aHandle The handle of the attribute to be written.
* @param[in] aPacket A pointer to the packet contains value to be written to the attribute.
*
*/
extern void otPlatBleGattServerOnWriteRequest(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket);
/**
* @}
*
*/
#ifdef __cplusplus
} // end of extern "C"
#endif
#endif // OPENTHREAD_PLATFORM_BLE_H_
+170
View File
@@ -0,0 +1,170 @@
/*
* Copyright (c) 2023, 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 TCAT.
*
* @note
* The functions in this module require the build-time feature `OPENTHREAD_CONFIG_BLE_TCAT_ENABLE=1`.
*
* @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_TCAT_H_
#define OPENTHREAD_TCAT_H_
#include <stdint.h>
#include <openthread/message.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup api-ble-secure
*
* @brief
* This module includes functions that implement TCAT communication.
*
* The functions in this module are available when TCAT feature
* (`OPENTHREAD_CONFIG_BLE_TCAT_ENABLE`) is enabled.
*
* @{
*
*/
#define OT_TCAT_MAX_SERVICE_NAME_LENGTH \
15 ///< Maximum string length of a UDP or TCP service name (does not include null char).
/**
* Represents TCAT status code.
*
*/
typedef enum otTcatStatusCode
{
OT_TCAT_STATUS_SUCCESS = 0, ///< Command or request was successfully processed
OT_TCAT_STATUS_UNSUPPORTED = 1, ///< Requested command or received TLV is not supported
OT_TCAT_STATUS_PARSE_ERROR = 2, ///< Request / command could not be parsed correctly
OT_TCAT_STATUS_VALUE_ERROR = 3, ///< The value of the transmitted TLV has an error
OT_TCAT_STATUS_GENERAL_ERROR = 4, ///< An error not matching any other category occurred
OT_TCAT_STATUS_BUSY = 5, ///< Command cannot be executed because the resource is busy
OT_TCAT_STATUS_UNDEFINED = 6, ///< The requested value, data or service is not defined (currently) or not present
OT_TCAT_STATUS_HASH_ERROR = 7, ///< The hash value presented by the commissioner was incorrect
OT_TCAT_STATUS_UNAUTHORIZED = 16, ///< Sender does not have sufficient authorization for the given command
} otTcatStatusCode;
/**
* Represents TCAT application protocol.
*
*/
typedef enum otTcatApplicationProtocol
{
OT_TCAT_APPLICATION_PROTOCOL_NONE = 0, ///< Message which has been sent without activating the TCAT agent
OT_TCAT_APPLICATION_PROTOCOL_STATUS = 1, ///< Message directed to a UDP service
OT_TCAT_APPLICATION_PROTOCOL_TCP = 2, ///< Message directed to a TCP service
} otTcatApplicationProtocol;
/**
* Represents a TCAT command class.
*
*/
typedef enum otTcatCommandClass
{
OT_TCAT_COMMAND_CLASS_GENERAL = 0, ///< TCAT commands related to general operations
OT_TCAT_COMMAND_CLASS_COMMISSIONING = 1, ///< TCAT commands related to commissioning
OT_TCAT_COMMAND_CLASS_EXTRACTION = 2, ///< TCAT commands related to key extraction
OT_TCAT_COMMAND_CLASS_DECOMMISSIONING = 3, ///< TCAT commands related to de-commissioning
OT_TCAT_COMMAND_CLASS_APPLICATION = 4, ///< TCAT commands related to application layer
} otTcatCommandClass;
/**
* This structure represents a TCAT vendor information.
*
* The content of this structure MUST persist and remain unchanged while a TCAT session is running.
*
*/
typedef struct otTcatVendorInfo
{
const char *mProvisioningUrl; ///< Provisioning URL path string
const char *mVendorName; ///< Vendor name string
const char *mVendorModel; ///< Vendor model string
const char *mVendorSwVersion; ///< Vendor software version string
const char *mVendorData; ///< Vendor specific data string
const char *mPskdString; ///< Vendor managed pre-shared key for device
const char *mInstallCode; ///< Vendor managed install code string
const char *mDeviceId; ///< Vendor managed device ID string (if NULL: device ID is set to EUI-64 in binary format)
} otTcatVendorInfo;
/**
* Pointer to call when application data was received over a TCAT TLS connection.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aMessage A pointer to the message.
* @param[in] aOffset The offset where the application data begins.
* @param[in] aTcatApplicationProtocol The protocol type of the message received.
* @param[in] aServiceName The name of the service the message is direced to.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
typedef void (*otHandleTcatApplicationDataReceive)(otInstance *aInstance,
const otMessage *aMessage,
int32_t aOffset,
otTcatApplicationProtocol aTcatApplicationProtocol,
const char *aServiceName,
void *aContext);
/**
* Pointer to call to notify the completion of a join operation.
*
* @param[in] aError OT_ERROR_NONE if the join process succeeded.
* OT_ERROR_SECURITY if the join process failed due to security credentials.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
typedef void (*otHandleTcatJoin)(otError aError, void *aContext);
/**
* @}
*
*/
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* OPENTHREAD_TCAT_H_ */
+3
View File
@@ -201,6 +201,9 @@ build_all_features()
# Build with RAM settings
reset_source
"$(dirname "$0")"/cmake-build simulation -DOT_SETTINGS_RAM=ON
reset_source
"$(dirname "$0")"/cmake-build simulation -DOT_BLE_TCAT=ON
}
build_nest_common()
+1
View File
@@ -48,6 +48,7 @@ set(COMMON_SOURCES
cli_output.cpp
cli_srp_client.cpp
cli_srp_server.cpp
cli_tcat.cpp
cli_tcp.cpp
cli_udp.cpp
)
+1
View File
@@ -117,6 +117,7 @@ Done
- [sntp](#sntp-query-sntp-server-ip-sntp-server-port)
- [state](#state)
- [srp](README_SRP.md)
- [tcat](README_TCAT.md)
- [tcp](README_TCP.md)
- [thread](#thread-start)
- [timeinqueue](#timeinqueue)
+37
View File
@@ -0,0 +1,37 @@
# OpenThread CLI - TCAT Example
## Command List
- help [#help]
- start [#start]
- stop [#stop]
### help
print help
```bash
tcat help
help
start
stop
Done
```
### start
Start tcat server and ble advertisement.
```bash
tcat start
Done
```
### stop
Stop tcat server and ble advertisement.
```bash
tcat stop
Done
```
+10
View File
@@ -148,6 +148,9 @@ Interpreter::Interpreter(Instance *aInstance, otCliOutputCallback aCallback, voi
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
, mLinkMetrics(aInstance, *this)
#endif
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
, mTcat(aInstance, *this)
#endif
#if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE
, mLocateInProgress(false)
#endif
@@ -7240,6 +7243,10 @@ exit:
return error;
}
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
template <> otError Interpreter::Process<Cmd("tcat")>(Arg aArgs[]) { return mTcat.Process(aArgs); }
#endif
#if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE
template <> otError Interpreter::Process<Cmd("tcp")>(Arg aArgs[]) { return mTcp.Process(aArgs); }
#endif
@@ -8509,6 +8516,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
CmdEntry("srp"),
#endif
CmdEntry("state"),
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
CmdEntry("tcat"),
#endif
#if OPENTHREAD_CONFIG_TCP_ENABLE && OPENTHREAD_CONFIG_CLI_TCP_ENABLE
CmdEntry("tcp"),
#endif
+4
View File
@@ -71,6 +71,7 @@
#include "cli/cli_output.hpp"
#include "cli/cli_srp_client.hpp"
#include "cli/cli_srp_server.hpp"
#include "cli/cli_tcat.hpp"
#include "cli/cli_tcp.hpp"
#include "cli/cli_udp.hpp"
#if OPENTHREAD_CONFIG_COAP_API_ENABLE
@@ -594,6 +595,9 @@ private:
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
LinkMetrics mLinkMetrics;
#endif
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
Tcat mTcat;
#endif
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
+10
View File
@@ -58,6 +58,16 @@
#define OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH 384
#endif
/**
* @def OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
*
* Indicates whether TCAT should be enabled in the CLI tool.
*
*/
#ifndef OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
#define OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_CLI_TCP_ENABLE
*
+178
View File
@@ -0,0 +1,178 @@
/*
* Copyright (c) 2023, 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.
*/
#include "openthread-core-config.h"
#include "cli/cli_output.hpp"
#include "cli/cli_tcat.hpp"
#include <openthread/ble_secure.h>
#include <mbedtls/oid.h>
#include <openthread/tcat.h>
#include <openthread/platform/ble.h>
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
#define OT_CLI_TCAT_X509_CERT \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIBmDCCAT+gAwIBAgIEAQIDBDAKBggqhkjOPQQDAjBvMQswCQYDVQQGEwJYWDEQ\r\n" \
"MA4GA1UECBMHTXlTdGF0ZTEPMA0GA1UEBxMGTXlDaXR5MQ8wDQYDVQQLEwZNeVVu\r\n" \
"aXQxETAPBgNVBAoTCE15VmVuZG9yMRkwFwYDVQQDExB3d3cubXl2ZW5kb3IuY29t\r\n" \
"MB4XDTIzMTAxNjEwMzk1NFoXDTI0MTAxNjEwMzk1NFowIjEgMB4GA1UEAxMXbXl2\r\n" \
"ZW5kb3IuY29tL3RjYXQvbXlkZXYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQB\r\n" \
"aWwFDNj1bpQIdN+Kp2cHWw55U/+fa+OmZnoy1B4BOT+822jdwPBuyXWAQoBdYdQJ\r\n" \
"ff4RgmhczyV4PhArPIuAoxYwFDASBgkrBgEEAYLfKgMEBQABAQEBMAoGCCqGSM49\r\n" \
"BAMCA0cAMEQCIBEHxiEDij26y6V77Q311Gj4CZAuZuPGXZpnzL2BLk7bAiAlFk6G\r\n" \
"mYGzkcrYyssFI9HlPgrisWoMmgummaTtCuvrEw==\r\n" \
"-----END CERTIFICATE-----\r\n"
#define OT_CLI_TCAT_PRIV_KEY \
"-----BEGIN EC PRIVATE KEY-----\r\n" \
"MHcCAQEEIDeJ6lVQKiOIBxKwTZp6TkU5QVHt9pvXOR9CGpPBI3DhoAoGCCqGSM49\r\n" \
"AwEHoUQDQgAEAWlsBQzY9W6UCHTfiqdnB1sOeVP/n2vjpmZ6MtQeATk/vNto3cDw\r\n" \
"bsl1gEKAXWHUCX3+EYJoXM8leD4QKzyLgA==\r\n" \
"-----END EC PRIVATE KEY-----\r\n"
#define OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE \
"-----BEGIN CERTIFICATE-----\r\n" \
"MIICCDCCAa2gAwIBAgIJAIKxygBXoH+5MAoGCCqGSM49BAMCMG8xCzAJBgNVBAYT\r\n" \
"AlhYMRAwDgYDVQQIEwdNeVN0YXRlMQ8wDQYDVQQHEwZNeUNpdHkxDzANBgNVBAsT\r\n" \
"Bk15VW5pdDERMA8GA1UEChMITXlWZW5kb3IxGTAXBgNVBAMTEHd3dy5teXZlbmRv\r\n" \
"ci5jb20wHhcNMjMxMDE2MTAzMzE1WhcNMjYxMDE2MTAzMzE1WjBvMQswCQYDVQQG\r\n" \
"EwJYWDEQMA4GA1UECBMHTXlTdGF0ZTEPMA0GA1UEBxMGTXlDaXR5MQ8wDQYDVQQL\r\n" \
"EwZNeVVuaXQxETAPBgNVBAoTCE15VmVuZG9yMRkwFwYDVQQDExB3d3cubXl2ZW5k\r\n" \
"b3IuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdyzPAXGKeZY94OhHAWX\r\n" \
"HzJfQIjGSyaOzlgL9OEFw2SoUDncLKPGwfPAUSfuMyEkzszNDM0HHkBsDLqu4n25\r\n" \
"/6MyMDAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU4EynoSw9eDKZEVPkums2\r\n" \
"IWLAJCowCgYIKoZIzj0EAwIDSQAwRgIhAMYGGL9xShyE6P9wEU+MAYF6W3CzdrwV\r\n" \
"kuerX1encIH2AiEA5rq490NUobM1Au43roxJq1T6Z43LscPVbGZfULD1Jq0=\r\n" \
"-----END CERTIFICATE-----\r\n"
namespace ot {
namespace Cli {
otTcatVendorInfo sVendorInfo;
const char kPskdVendor[] = "J01NM3";
const char kUrl[] = "dummy_url";
static void HandleBleSecureReceive(otInstance *aInstance,
const otMessage *aMessage,
int32_t aOffset,
otTcatApplicationProtocol aTcatApplicationProtocol,
const char *aServiceName,
void *aContext)
{
OT_UNUSED_VARIABLE(aContext);
OT_UNUSED_VARIABLE(aTcatApplicationProtocol);
OT_UNUSED_VARIABLE(aServiceName);
static constexpr int kTextMaxLen = 100;
static constexpr uint8_t kBufPrefixLen = 5;
uint16_t nLen;
uint8_t buf[kTextMaxLen];
nLen = otMessageRead(aMessage, (uint16_t)aOffset, buf + kBufPrefixLen, sizeof(buf) - kBufPrefixLen - 1);
memcpy(buf, "RECV:", kBufPrefixLen);
buf[nLen + kBufPrefixLen] = 0;
IgnoreReturnValue(otBleSecureSendApplicationTlv(aInstance, buf, (uint16_t)strlen((char *)buf)));
IgnoreReturnValue(otBleSecureFlush(aInstance));
}
template <> otError Tcat::Process<Cmd("start")>(Arg aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
otError error = OT_ERROR_NONE;
sVendorInfo.mPskdString = kPskdVendor;
sVendorInfo.mProvisioningUrl = kUrl;
otBleSecureSetCertificate(GetInstancePtr(), reinterpret_cast<const uint8_t *>(OT_CLI_TCAT_X509_CERT),
sizeof(OT_CLI_TCAT_X509_CERT), reinterpret_cast<const uint8_t *>(OT_CLI_TCAT_PRIV_KEY),
sizeof(OT_CLI_TCAT_PRIV_KEY));
otBleSecureSetCaCertificateChain(GetInstancePtr(),
reinterpret_cast<const uint8_t *>(OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE),
sizeof(OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE));
otBleSecureSetSslAuthMode(GetInstancePtr(), true);
SuccessOrExit(error = otBleSecureStart(GetInstancePtr(), nullptr, HandleBleSecureReceive, true, nullptr));
SuccessOrExit(error = otBleSecureTcatStart(GetInstancePtr(), &sVendorInfo, nullptr));
exit:
return error;
}
template <> otError Tcat::Process<Cmd("stop")>(Arg aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
otError error = OT_ERROR_NONE;
otBleSecureStop(GetInstancePtr());
return error;
}
otError Tcat::Process(Arg aArgs[])
{
#define CmdEntry(aCommandString) \
{ \
aCommandString, &Tcat::Process<Cmd(aCommandString)> \
}
static constexpr Command kCommands[] = {CmdEntry("start"), CmdEntry("stop")};
static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
otError error = OT_ERROR_NONE;
const Command *command;
if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
{
OutputCommandTable(kCommands);
ExitNow(error = aArgs[0].IsEmpty() ? error : OT_ERROR_NONE);
}
command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
VerifyOrExit(command != nullptr);
error = (this->*command->mHandler)(aArgs + 1);
exit:
return error;
}
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2023, 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.
*/
#ifndef CLI_TCAT_HPP_
#define CLI_TCAT_HPP_
#include "openthread-core-config.h"
#include "cli/cli_output.hpp"
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
namespace ot {
namespace Cli {
/**
* Implements the Tcat CLI interpreter.
*
*/
class Tcat : private Output
{
public:
typedef Utils::CmdLineParser::Arg Arg;
/**
* Constructor
*
* @param[in] aInstance The OpenThread Instance.
* @param[in] aOutputImplementer An `OutputImplementer`.
*
*/
Tcat(otInstance *aInstance, OutputImplementer &aOutputImplementer)
: Output(aInstance, aOutputImplementer)
{
}
/**
* Processes a CLI sub-command.
*
* @param[in] aArgs An array of command line arguments.
*
* @retval OT_ERROR_NONE Successfully executed the CLI command.
* @retval OT_ERROR_PENDING The CLI command was successfully started but final result is pending.
* @retval OT_ERROR_INVALID_COMMAND Invalid or unknown CLI command.
* @retval OT_ERROR_INVALID_ARGS Invalid arguments.
* @retval ... Error during execution of the CLI command.
*
*/
otError Process(Arg aArgs[]);
private:
using Command = CommandEntry<Tcat>;
template <CommandId kCommandId> otError Process(Arg aArgs[]);
};
} // namespace Cli
} // namespace ot
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE && OPENTHREAD_CONFIG_CLI_BLE_SECURE_ENABLE
#endif // CLI_TCAT_HPP_
+12 -3
View File
@@ -74,6 +74,10 @@ if (openthread_enable_core_config_args) {
defines += [ "OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE=1" ]
}
if (openthread_config_ble_tcat_enable) {
defines += [ "OPENTHREAD_CONFIG_BLE_TCAT_ENABLE=1" ]
}
if (openthread_config_border_agent_enable) {
defines += [ "OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE=1" ]
}
@@ -301,6 +305,7 @@ config("core_config") {
openthread_core_files = [
"api/backbone_router_api.cpp",
"api/backbone_router_ftd_api.cpp",
"api/ble_secure_api.cpp",
"api/border_agent_api.cpp",
"api/border_router_api.cpp",
"api/border_routing_api.cpp",
@@ -510,8 +515,6 @@ openthread_core_files = [
"meshcop/dataset_manager_ftd.cpp",
"meshcop/dataset_updater.cpp",
"meshcop/dataset_updater.hpp",
"meshcop/dtls.cpp",
"meshcop/dtls.hpp",
"meshcop/energy_scan_client.cpp",
"meshcop/energy_scan_client.hpp",
"meshcop/extended_panid.cpp",
@@ -530,6 +533,10 @@ openthread_core_files = [
"meshcop/network_name.hpp",
"meshcop/panid_query_client.cpp",
"meshcop/panid_query_client.hpp",
"meshcop/secure_transport.cpp",
"meshcop/secure_transport.hpp",
"meshcop/tcat_agent.cpp",
"meshcop/tcat_agent.hpp",
"meshcop/timestamp.cpp",
"meshcop/timestamp.hpp",
"net/checksum.cpp",
@@ -585,6 +592,8 @@ openthread_core_files = [
"net/tcp6_ext.hpp",
"net/udp6.cpp",
"net/udp6.hpp",
"radio/ble_secure.cpp",
"radio/ble_secure.hpp",
"radio/max_power_table.hpp",
"radio/radio.cpp",
"radio/radio.hpp",
@@ -789,7 +798,6 @@ source_set("libopenthread_core_config") {
"config/dns_client.h",
"config/dns_dso.h",
"config/dnssd_server.h",
"config/dtls.h",
"config/history_tracker.h",
"config/ip6.h",
"config/joiner.h",
@@ -811,6 +819,7 @@ source_set("libopenthread_core_config") {
"config/platform.h",
"config/power_calibration.h",
"config/radio_link.h",
"config/secure_transport.h",
"config/sntp_client.h",
"config/srp_client.h",
"config/srp_server.h",
+4 -1
View File
@@ -33,6 +33,7 @@ set(COMMON_INCLUDES
set(COMMON_SOURCES
api/backbone_router_api.cpp
api/backbone_router_ftd_api.cpp
api/ble_secure_api.cpp
api/border_agent_api.cpp
api/border_router_api.cpp
api/border_routing_api.cpp
@@ -148,7 +149,6 @@ set(COMMON_SOURCES
meshcop/dataset_manager.cpp
meshcop/dataset_manager_ftd.cpp
meshcop/dataset_updater.cpp
meshcop/dtls.cpp
meshcop/energy_scan_client.cpp
meshcop/extended_panid.cpp
meshcop/joiner.cpp
@@ -158,6 +158,8 @@ set(COMMON_SOURCES
meshcop/meshcop_tlvs.cpp
meshcop/network_name.cpp
meshcop/panid_query_client.cpp
meshcop/secure_transport.cpp
meshcop/tcat_agent.cpp
meshcop/timestamp.cpp
net/checksum.cpp
net/dhcp6_client.cpp
@@ -185,6 +187,7 @@ set(COMMON_SOURCES
net/tcp6.cpp
net/tcp6_ext.cpp
net/udp6.cpp
radio/ble_secure.cpp
radio/radio.cpp
radio/radio_callbacks.cpp
radio/radio_platform.cpp
+184
View File
@@ -0,0 +1,184 @@
/*
* Copyright (c) 2023, 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 BLE Secure API.
*/
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#include <openthread/ble_secure.h>
#include <openthread/platform/ble.h>
#include "common/as_core_type.hpp"
#include "common/code_utils.hpp"
#include "common/locator_getters.hpp"
#include "meshcop/tcat_agent.hpp"
#include "radio/ble_secure.hpp"
using namespace ot;
otError otBleSecureStart(otInstance *aInstance,
otHandleBleSecureConnect aConnectHandler,
otHandleBleSecureReceive aReceiveHandler,
bool aTlvMode,
void *aContext)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().Start(aConnectHandler, aReceiveHandler, aTlvMode, aContext);
}
otError otBleSecureTcatStart(otInstance *aInstance, const otTcatVendorInfo *aVendorInfo, otHandleTcatJoin aHandler)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().TcatStart(AsCoreType(aVendorInfo), aHandler);
}
void otBleSecureStop(otInstance *aInstance) { AsCoreType(aInstance).Get<Ble::BleSecure>().Stop(); }
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
void otBleSecureSetPsk(otInstance *aInstance,
const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength)
{
AssertPointerIsNotNull(aPsk);
AssertPointerIsNotNull(aPskIdentity);
OT_ASSERT(aPskLength != 0 && aPskIdLength != 0);
AsCoreType(aInstance).Get<Ble::BleSecure>().SetPreSharedKey(aPsk, aPskLength, aPskIdentity, aPskIdLength);
}
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
otError otBleSecureGetPeerCertificateBase64(otInstance *aInstance, unsigned char *aPeerCert, size_t *aCertLength)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().GetPeerCertificateBase64(aPeerCert, aCertLength);
}
#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
otError otBleSecureGetPeerSubjectAttributeByOid(otInstance *aInstance,
const char *aOid,
size_t aOidLength,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength,
int *aAsn1Type)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().GetPeerSubjectAttributeByOid(aOid, aOidLength, aAttributeBuffer,
aAttributeLength, aAsn1Type);
}
otError otBleSecureGetThreadAttributeFromPeerCertificate(otInstance *aInstance,
int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().GetThreadAttributeFromPeerCertificate(
aThreadOidDescriptor, aAttributeBuffer, aAttributeLength);
}
#endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
otError otBleSecureGetThreadAttributeFromOwnCertificate(otInstance *aInstance,
int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().GetThreadAttributeFromOwnCertificate(
aThreadOidDescriptor, aAttributeBuffer, aAttributeLength);
}
void otBleSecureSetSslAuthMode(otInstance *aInstance, bool aVerifyPeerCertificate)
{
AsCoreType(aInstance).Get<Ble::BleSecure>().SetSslAuthMode(aVerifyPeerCertificate);
}
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
void otBleSecureSetCertificate(otInstance *aInstance,
const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength)
{
OT_ASSERT(aX509Cert != nullptr && aX509Length != 0 && aPrivateKey != nullptr && aPrivateKeyLength != 0);
AsCoreType(aInstance).Get<Ble::BleSecure>().SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength);
}
void otBleSecureSetCaCertificateChain(otInstance *aInstance,
const uint8_t *aX509CaCertificateChain,
uint32_t aX509CaCertChainLength)
{
OT_ASSERT(aX509CaCertificateChain != nullptr && aX509CaCertChainLength != 0);
AsCoreType(aInstance).Get<Ble::BleSecure>().SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLength);
}
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
otError otBleSecureConnect(otInstance *aInstance) { return AsCoreType(aInstance).Get<Ble::BleSecure>().Connect(); }
void otBleSecureDisconnect(otInstance *aInstance) { AsCoreType(aInstance).Get<Ble::BleSecure>().Disconnect(); }
bool otBleSecureIsConnectionActive(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().IsConnectionActive();
}
bool otBleSecureIsConnected(otInstance *aInstance) { return AsCoreType(aInstance).Get<Ble::BleSecure>().IsConnected(); }
bool otBleSecureIsTcatEnabled(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().IsTcatEnabled();
}
bool otBleSecureIsCommandClassAuthorized(otInstance *aInstance, otTcatCommandClass aCommandClass)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().IsCommandClassAuthorized(
static_cast<Ble::BleSecure::CommandClass>(aCommandClass));
}
otError otBleSecureSendMessage(otInstance *aInstance, otMessage *aMessage)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().SendMessage(AsCoreType(aMessage));
}
otError otBleSecureSend(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().Send(aBuf, aLength);
}
otError otBleSecureSendApplicationTlv(otInstance *aInstance, uint8_t *aBuf, uint16_t aLength)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().SendApplicationTlv(aBuf, aLength);
}
otError otBleSecureFlush(otInstance *aInstance) { return AsCoreType(aInstance).Get<Ble::BleSecure>().Flush(); }
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
+6 -5
View File
@@ -28,13 +28,14 @@
#include "coap_secure.hpp"
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
#include "common/locator_getters.hpp"
#include "common/log.hpp"
#include "common/new.hpp"
#include "instance/instance.hpp"
#include "meshcop/dtls.hpp"
#include "meshcop/secure_transport.hpp"
#include "thread/thread_netif.hpp"
/**
@@ -67,7 +68,7 @@ exit:
return error;
}
Error CoapSecure::Start(MeshCoP::Dtls::TransportCallback aCallback, void *aContext)
Error CoapSecure::Start(MeshCoP::SecureTransport::TransportCallback aCallback, void *aContext)
{
Error error = kErrorNone;
@@ -98,7 +99,7 @@ Error CoapSecure::Connect(const Ip6::SockAddr &aSockAddr, ConnectedCallback aCal
void CoapSecure::SetPsk(const MeshCoP::JoinerPskd &aPskd)
{
static_assert(static_cast<uint16_t>(MeshCoP::JoinerPskd::kMaxLength) <=
static_cast<uint16_t>(MeshCoP::Dtls::kPskMaxLength),
static_cast<uint16_t>(MeshCoP::SecureTransport::kPskMaxLength),
"The maximum length of DTLS PSK is smaller than joiner PSKd");
SuccessOrAssert(mDtls.SetPsk(reinterpret_cast<const uint8_t *>(aPskd.GetAsCString()), aPskd.GetLength()));
@@ -224,4 +225,4 @@ exit:
} // namespace Coap
} // namespace ot
#endif // OPENTHREAD_CONFIG_DTLS_ENABLE
#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
+6 -6
View File
@@ -31,12 +31,12 @@
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
#include "coap/coap.hpp"
#include "common/callback.hpp"
#include "meshcop/dtls.hpp"
#include "meshcop/meshcop.hpp"
#include "meshcop/secure_transport.hpp"
#include <openthread/coap_secure.h>
@@ -91,7 +91,7 @@ public:
* @retval kErrorAlready Already started.
*
*/
Error Start(MeshCoP::Dtls::TransportCallback aCallback, void *aContext);
Error Start(MeshCoP::SecureTransport::TransportCallback aCallback, void *aContext);
/**
* Sets connected callback of this secure CoAP agent.
@@ -153,7 +153,7 @@ public:
* @returns A reference to the DTLS object.
*
*/
MeshCoP::Dtls &GetDtls(void) { return mDtls; }
MeshCoP::SecureTransport &GetDtls(void) { return mDtls; }
/**
* Gets the UDP port of this agent.
@@ -409,7 +409,7 @@ private:
static void HandleTransmit(Tasklet &aTasklet);
void HandleTransmit(void);
MeshCoP::Dtls mDtls;
MeshCoP::SecureTransport mDtls;
Callback<ConnectedCallback> mConnectedCallback;
ot::MessageQueue mTransmitQueue;
TaskletContext mTransmitTask;
@@ -418,6 +418,6 @@ private:
} // namespace Coap
} // namespace ot
#endif // OPENTHREAD_CONFIG_DTLS_ENABLE
#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
#endif // COAP_SECURE_HPP_
+2 -1
View File
@@ -286,7 +286,8 @@ public:
kTypeSupervision = 2, ///< A child supervision frame.
kTypeMacEmptyData = 3, ///< An empty MAC data frame.
kTypeIp4 = 4, ///< A full uncompressed IPv4 packet, for NAT64.
kTypeOther = 5, ///< Other (data) message.
kTypeBle = 5, ///< A BLE payload message.
kTypeOther = 6, ///< Other (data) message.
};
/**
+2 -2
View File
@@ -178,8 +178,8 @@
* Define as 1 to enable support for TLS over TCP.
*
*/
#ifndef OPENTHREAD_CONFIG_TLS_ENABLE
#define OPENTHREAD_CONFIG_TLS_ENABLE OPENTHREAD_CONFIG_TCP_ENABLE
#if (OPENTHREAD_CONFIG_TCP_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE) && !defined(OPENTHREAD_CONFIG_TLS_ENABLE)
#define OPENTHREAD_CONFIG_TLS_ENABLE 1
#endif
/**
@@ -122,7 +122,7 @@
#endif
#ifdef OPENTHREAD_ENABLE_DTLS
#error "OPENTHREAD_ENABLE_DTLS was replaced by OPENTHREAD_CONFIG_DTLS_ENABLE."
#error "OPENTHREAD_ENABLE_DTLS was replaced by OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE."
#endif
#ifdef OPENTHREAD_ENABLE_JAM_DETECTION
@@ -28,12 +28,12 @@
/**
* @file
* This file includes compile-time configurations for DTLS.
* This file includes compile-time configurations for TLS/DTLS.
*
*/
#ifndef CONFIG_DTLS_H_
#define CONFIG_DTLS_H_
#ifndef CONFIG_SECURE_TRANSPORT_H_
#define CONFIG_SECURE_TRANSPORT_H_
#include "config/border_agent.h"
#include "config/coap.h"
@@ -51,15 +51,19 @@
#endif
/**
* @def OPENTHREAD_CONFIG_DTLS_ENABLE
* @def OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
*
* Define to 1 to enable DTLS.
* Define to 1 to enable DTLS/TLS.
*
*/
#ifndef OPENTHREAD_CONFIG_DTLS_ENABLE
#define OPENTHREAD_CONFIG_DTLS_ENABLE \
#ifndef OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
#define OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE \
(OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE || OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || \
OPENTHREAD_CONFIG_COMMISSIONER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE)
OPENTHREAD_CONFIG_COMMISSIONER_ENABLE || OPENTHREAD_CONFIG_JOINER_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE)
#endif
#endif // CONFIG_DTLS_H_
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#error "OPENTHREAD_CONFIG_DTLS_ENABLE is deprecated please use OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE instead"
#endif
#endif // CONFIG_SECURE_TRANSPORT_H_
+5 -2
View File
@@ -156,7 +156,7 @@ Instance::Instance(void)
#if OPENTHREAD_CONFIG_COMMISSIONER_ENABLE && OPENTHREAD_FTD
, mCommissioner(*this)
#endif
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
, mTmfSecureAgent(*this)
#endif
#if OPENTHREAD_CONFIG_JOINER_ENABLE
@@ -211,6 +211,9 @@ Instance::Instance(void)
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
, mApplicationCoapSecure(*this, /* aLayerTwoSecurity */ true)
#endif
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
, mApplicationBleSecure(*this)
#endif
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
, mPingSender(*this)
#endif
@@ -456,7 +459,7 @@ void Instance::GetBufferInfo(BufferInfo &aInfo)
Get<Tmf::Agent>().GetRequestMessages().GetInfo(aInfo.mCoapQueue);
Get<Tmf::Agent>().GetCachedResponses().GetInfo(aInfo.mCoapQueue);
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
Get<Tmf::SecureAgent>().GetRequestMessages().GetInfo(aInfo.mCoapSecureQueue);
Get<Tmf::SecureAgent>().GetCachedResponses().GetInfo(aInfo.mCoapSecureQueue);
#endif
+11 -2
View File
@@ -97,6 +97,7 @@
#include "net/sntp_client.hpp"
#include "net/srp_client.hpp"
#include "net/srp_server.hpp"
#include "radio/ble_secure.hpp"
#include "thread/address_resolver.hpp"
#include "thread/announce_begin_server.hpp"
#include "thread/announce_sender.hpp"
@@ -547,7 +548,7 @@ private:
MeshCoP::Commissioner mCommissioner;
#endif
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
Tmf::SecureAgent mTmfSecureAgent;
#endif
@@ -618,6 +619,10 @@ private:
Coap::CoapSecure mApplicationCoapSecure;
#endif
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
Ble::BleSecure mApplicationBleSecure;
#endif
#if OPENTHREAD_CONFIG_PING_SENDER_ENABLE
Utils::PingSender mPingSender;
#endif
@@ -830,7 +835,7 @@ template <> inline Ip6::Mpl &Instance::Get(void) { return mIp6.mMpl; }
template <> inline Tmf::Agent &Instance::Get(void) { return mTmfAgent; }
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
template <> inline Tmf::SecureAgent &Instance::Get(void) { return mTmfSecureAgent; }
#endif
@@ -1017,6 +1022,10 @@ template <> inline Nat64::Translator &Instance::Get(void) { return mNat64Transla
template <> inline Srp::Server &Instance::Get(void) { return mSrpServer; }
#endif
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
template <> inline Ble::BleSecure &Instance::Get(void) { return mApplicationBleSecure; }
#endif
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
+1 -1
View File
@@ -50,9 +50,9 @@
#include "common/timer.hpp"
#include "mac/mac_types.hpp"
#include "meshcop/announce_begin_client.hpp"
#include "meshcop/dtls.hpp"
#include "meshcop/energy_scan_client.hpp"
#include "meshcop/panid_query_client.hpp"
#include "meshcop/secure_transport.hpp"
#include "net/ip6_address.hpp"
#include "net/udp6.hpp"
#include "thread/key_manager.hpp"
+1 -1
View File
@@ -49,9 +49,9 @@
#include "common/message.hpp"
#include "common/non_copyable.hpp"
#include "mac/mac_types.hpp"
#include "meshcop/dtls.hpp"
#include "meshcop/meshcop.hpp"
#include "meshcop/meshcop_tlvs.hpp"
#include "meshcop/secure_transport.hpp"
#include "thread/discover_scanner.hpp"
#include "thread/tmf.hpp"
@@ -31,7 +31,7 @@
* This file implements the necessary hooks for mbedTLS.
*/
#include "dtls.hpp"
#include "secure_transport.hpp"
#include <mbedtls/debug.h>
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
@@ -52,42 +52,43 @@
#include "instance/instance.hpp"
#include "thread/thread_netif.hpp"
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
namespace ot {
namespace MeshCoP {
RegisterLogModule("Dtls");
RegisterLogModule("SecTransport");
#if (MBEDTLS_VERSION_NUMBER >= 0x03010000)
const uint16_t Dtls::sGroups[] = {MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, MBEDTLS_SSL_IANA_TLS_GROUP_NONE};
const uint16_t SecureTransport::sGroups[] = {MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1, MBEDTLS_SSL_IANA_TLS_GROUP_NONE};
#else
const mbedtls_ecp_group_id Dtls::sCurves[] = {MBEDTLS_ECP_DP_SECP256R1, MBEDTLS_ECP_DP_NONE};
const mbedtls_ecp_group_id SecureTransport::sCurves[] = {MBEDTLS_ECP_DP_SECP256R1, MBEDTLS_ECP_DP_NONE};
#endif
#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) || defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED)
#if (MBEDTLS_VERSION_NUMBER >= 0x03020000)
const uint16_t Dtls::sSignatures[] = {MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256, MBEDTLS_TLS1_3_SIG_NONE};
const uint16_t SecureTransport::sSignatures[] = {MBEDTLS_TLS1_3_SIG_ECDSA_SECP256R1_SHA256, MBEDTLS_TLS1_3_SIG_NONE};
#else
const int Dtls::sHashes[] = {MBEDTLS_MD_SHA256, MBEDTLS_MD_NONE};
const int SecureTransport::sHashes[] = {MBEDTLS_MD_SHA256, MBEDTLS_MD_NONE};
#endif
#endif
Dtls::Dtls(Instance &aInstance, bool aLayerTwoSecurity)
SecureTransport::SecureTransport(Instance &aInstance, bool aLayerTwoSecurity, bool aDatagramTransport)
: InstanceLocator(aInstance)
, mState(kStateClosed)
, mPskLength(0)
, mVerifyPeerCertificate(true)
, mTimer(aInstance, Dtls::HandleTimer, this)
, mTimer(aInstance, SecureTransport::HandleTimer, this)
, mTimerIntermediate(0)
, mTimerSet(false)
, mLayerTwoSecurity(aLayerTwoSecurity)
, mDatagramTransport(aDatagramTransport)
, mReceiveMessage(nullptr)
, mSocket(aInstance)
, mMessageSubType(Message::kSubTypeNone)
, mMessageDefaultSubType(Message::kSubTypeNone)
{
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
mPreSharedKey = nullptr;
mPreSharedKeyIdentity = nullptr;
@@ -118,12 +119,15 @@ Dtls::Dtls(Instance &aInstance, bool aLayerTwoSecurity)
#endif
}
void Dtls::FreeMbedtls(void)
void SecureTransport::FreeMbedtls(void)
{
#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_COOKIE_C)
mbedtls_ssl_cookie_free(&mCookieCtx);
if (mDatagramTransport)
{
mbedtls_ssl_cookie_free(&mCookieCtx);
}
#endif
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
mbedtls_x509_crt_free(&mCaChain);
mbedtls_x509_crt_free(&mOwnCert);
@@ -134,13 +138,13 @@ void Dtls::FreeMbedtls(void)
mbedtls_ssl_free(&mSsl);
}
Error Dtls::Open(ReceiveHandler aReceiveHandler, ConnectedHandler aConnectedHandler, void *aContext)
Error SecureTransport::Open(ReceiveHandler aReceiveHandler, ConnectedHandler aConnectedHandler, void *aContext)
{
Error error;
VerifyOrExit(mState == kStateClosed, error = kErrorAlready);
SuccessOrExit(error = mSocket.Open(&Dtls::HandleUdpReceive, this));
SuccessOrExit(error = mSocket.Open(&SecureTransport::HandleUdpReceive, this));
mConnectedCallback.Set(aConnectedHandler, aContext);
mReceiveCallback.Set(aReceiveHandler, aContext);
@@ -150,7 +154,7 @@ exit:
return error;
}
Error Dtls::Connect(const Ip6::SockAddr &aSockAddr)
Error SecureTransport::Connect(const Ip6::SockAddr &aSockAddr)
{
Error error;
@@ -165,24 +169,30 @@ exit:
return error;
}
void Dtls::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
void SecureTransport::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
static_cast<Dtls *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
static_cast<SecureTransport *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
}
void Dtls::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
void SecureTransport::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
switch (mState)
{
case Dtls::kStateClosed:
case SecureTransport::kStateClosed:
ExitNow();
case Dtls::kStateOpen:
case SecureTransport::kStateOpen:
IgnoreError(mSocket.Connect(Ip6::SockAddr(aMessageInfo.GetPeerAddr(), aMessageInfo.GetPeerPort())));
mMessageInfo.SetPeerAddr(aMessageInfo.GetPeerAddr());
mMessageInfo.SetPeerPort(aMessageInfo.GetPeerPort());
mMessageInfo.SetIsHostInterface(aMessageInfo.IsHostInterface());
mMessageInfo.SetSockAddr(aMessageInfo.GetSockAddr());
if (Get<ThreadNetif>().HasUnicastAddress(aMessageInfo.GetSockAddr()))
{
mMessageInfo.SetSockAddr(aMessageInfo.GetSockAddr());
}
mMessageInfo.SetSockPort(aMessageInfo.GetSockPort());
SuccessOrExit(Setup(false));
@@ -196,7 +206,7 @@ void Dtls::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageI
}
#ifdef MBEDTLS_SSL_SRV_C
if (mState == Dtls::kStateConnecting)
if (mState == SecureTransport::kStateConnecting)
{
IgnoreError(SetClientId(mMessageInfo.GetPeerAddr().mFields.m8, sizeof(mMessageInfo.GetPeerAddr().mFields)));
}
@@ -208,9 +218,9 @@ exit:
return;
}
uint16_t Dtls::GetUdpPort(void) const { return mSocket.GetSockName().GetPort(); }
uint16_t SecureTransport::GetUdpPort(void) const { return mSocket.GetSockName().GetPort(); }
Error Dtls::Bind(uint16_t aPort)
Error SecureTransport::Bind(uint16_t aPort)
{
Error error;
@@ -223,7 +233,7 @@ exit:
return error;
}
Error Dtls::Bind(TransportCallback aCallback, void *aContext)
Error SecureTransport::Bind(TransportCallback aCallback, void *aContext)
{
Error error = kErrorNone;
@@ -237,7 +247,7 @@ exit:
return error;
}
Error Dtls::Setup(bool aClient)
Error SecureTransport::Setup(bool aClient)
{
int rval;
@@ -248,7 +258,7 @@ Error Dtls::Setup(bool aClient)
mbedtls_ssl_init(&mSsl);
mbedtls_ssl_config_init(&mConf);
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
mbedtls_x509_crt_init(&mCaChain);
mbedtls_x509_crt_init(&mOwnCert);
@@ -256,15 +266,20 @@ Error Dtls::Setup(bool aClient)
#endif
#endif
#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_COOKIE_C)
mbedtls_ssl_cookie_init(&mCookieCtx);
if (mDatagramTransport)
{
mbedtls_ssl_cookie_init(&mCookieCtx);
}
#endif
rval = mbedtls_ssl_config_defaults(&mConf, aClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT);
rval = mbedtls_ssl_config_defaults(
&mConf, aClient ? MBEDTLS_SSL_IS_CLIENT : MBEDTLS_SSL_IS_SERVER,
mDatagramTransport ? MBEDTLS_SSL_TRANSPORT_DATAGRAM : MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
VerifyOrExit(rval == 0);
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
if (mVerifyPeerCertificate && mCipherSuites[0] == MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8)
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
if (mVerifyPeerCertificate && (mCipherSuites[0] == MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ||
mCipherSuites[0] == MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256))
{
mbedtls_ssl_conf_authmode(&mConf, MBEDTLS_SSL_VERIFY_REQUIRED);
}
@@ -313,7 +328,7 @@ Error Dtls::Setup(bool aClient)
mbedtls_ssl_conf_dbg(&mConf, HandleMbedtlsDebug, this);
#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_COOKIE_C)
if (!aClient)
if (!aClient && mDatagramTransport)
{
rval = mbedtls_ssl_cookie_setup(&mCookieCtx, Crypto::MbedTls::CryptoSecurePrng, nullptr);
VerifyOrExit(rval == 0);
@@ -325,17 +340,21 @@ Error Dtls::Setup(bool aClient)
rval = mbedtls_ssl_setup(&mSsl, &mConf);
VerifyOrExit(rval == 0);
mbedtls_ssl_set_bio(&mSsl, this, &Dtls::HandleMbedtlsTransmit, HandleMbedtlsReceive, nullptr);
mbedtls_ssl_set_timer_cb(&mSsl, this, &Dtls::HandleMbedtlsSetTimer, HandleMbedtlsGetTimer);
mbedtls_ssl_set_bio(&mSsl, this, &SecureTransport::HandleMbedtlsTransmit, HandleMbedtlsReceive, nullptr);
if (mDatagramTransport)
{
mbedtls_ssl_set_timer_cb(&mSsl, this, &SecureTransport::HandleMbedtlsSetTimer, HandleMbedtlsGetTimer);
}
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
rval = mbedtls_ssl_set_hs_ecjpake_password(&mSsl, mPsk, mPskLength);
}
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
else
{
rval = SetApplicationCoapSecureKeys();
rval = SetApplicationSecureKeys();
}
#endif
VerifyOrExit(rval == 0);
@@ -348,10 +367,10 @@ Error Dtls::Setup(bool aClient)
{
LogInfo("DTLS started");
}
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
else
{
LogInfo("Application Coap Secure DTLS started");
LogInfo("Application Secure (D)TLS started");
}
#endif
@@ -369,14 +388,16 @@ exit:
return Crypto::MbedTls::MapError(rval);
}
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
int Dtls::SetApplicationCoapSecureKeys(void)
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
int SecureTransport::SetApplicationSecureKeys(void)
{
int rval = 0;
switch (mCipherSuites[0])
{
case MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
case MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
if (mCaChainSrc != nullptr)
{
@@ -426,9 +447,9 @@ exit:
return rval;
}
#endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#endif // OPENTHREAD_CONFIG_TLS_API_ENABLE
void Dtls::Close(void)
void SecureTransport::Close(void)
{
Disconnect();
@@ -440,7 +461,7 @@ void Dtls::Close(void)
mTimer.Stop();
}
void Dtls::Disconnect(void)
void SecureTransport::Disconnect(void)
{
VerifyOrExit(mState == kStateConnecting || mState == kStateConnected);
@@ -457,7 +478,7 @@ exit:
return;
}
Error Dtls::SetPsk(const uint8_t *aPsk, uint8_t aPskLength)
Error SecureTransport::SetPsk(const uint8_t *aPsk, uint8_t aPskLength)
{
Error error = kErrorNone;
@@ -472,13 +493,13 @@ exit:
return error;
}
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
void Dtls::SetCertificate(const uint8_t *aX509Certificate,
uint32_t aX509CertLength,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength)
void SecureTransport::SetCertificate(const uint8_t *aX509Certificate,
uint32_t aX509CertLength,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength)
{
OT_ASSERT(aX509CertLength > 0);
OT_ASSERT(aX509Certificate != nullptr);
@@ -491,11 +512,19 @@ void Dtls::SetCertificate(const uint8_t *aX509Certificate,
mPrivateKeySrc = aPrivateKey;
mPrivateKeyLength = aPrivateKeyLength;
mCipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
if (mDatagramTransport)
{
mCipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8;
}
else
{
mCipherSuites[0] = MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
}
mCipherSuites[1] = 0;
}
void Dtls::SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength)
void SecureTransport::SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength)
{
OT_ASSERT(aX509CaCertChainLength > 0);
OT_ASSERT(aX509CaCertificateChain != nullptr);
@@ -507,7 +536,10 @@ void Dtls::SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
void Dtls::SetPreSharedKey(const uint8_t *aPsk, uint16_t aPskLength, const uint8_t *aPskIdentity, uint16_t aPskIdLength)
void SecureTransport::SetPreSharedKey(const uint8_t *aPsk,
uint16_t aPskLength,
const uint8_t *aPskIdentity,
uint16_t aPskIdLength)
{
OT_ASSERT(aPsk != nullptr);
OT_ASSERT(aPskIdentity != nullptr);
@@ -525,7 +557,7 @@ void Dtls::SetPreSharedKey(const uint8_t *aPsk, uint16_t aPskLength, const uint8
#endif
#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
Error Dtls::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize)
Error SecureTransport::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize)
{
Error error = kErrorNone;
@@ -550,17 +582,153 @@ exit:
}
#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
#endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
Error SecureTransport::GetPeerSubjectAttributeByOid(const char *aOid,
size_t aOidLength,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength,
int *aAsn1Type)
{
Error error = kErrorNone;
const mbedtls_asn1_named_data *data;
size_t length;
size_t attributeBufferSize;
mbedtls_x509_crt *peerCert = const_cast<mbedtls_x509_crt *>(mbedtls_ssl_get_peer_cert(&mSsl));
VerifyOrExit(aAttributeLength != nullptr, error = kErrorInvalidArgs);
attributeBufferSize = *aAttributeLength;
*aAttributeLength = 0;
VerifyOrExit(aAttributeBuffer != nullptr, error = kErrorNoBufs);
VerifyOrExit(peerCert != nullptr, error = kErrorInvalidState);
data = mbedtls_asn1_find_named_data(&peerCert->subject, aOid, aOidLength);
VerifyOrExit(data != nullptr, error = kErrorNotFound);
length = data->val.len;
VerifyOrExit(length <= attributeBufferSize, error = kErrorNoBufs);
if (aAttributeLength != nullptr)
{
*aAttributeLength = length;
}
if (aAsn1Type != nullptr)
{
*aAsn1Type = data->val.tag;
}
memcpy(aAttributeBuffer, data->val.p, length);
exit:
return error;
}
Error SecureTransport::GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength)
{
const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(&mSsl);
return GetThreadAttributeFromCertificate(cert, aThreadOidDescriptor, aAttributeBuffer, aAttributeLength);
}
#endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
Error SecureTransport::GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength)
{
const mbedtls_x509_crt *cert = &mOwnCert;
return GetThreadAttributeFromCertificate(cert, aThreadOidDescriptor, aAttributeBuffer, aAttributeLength);
}
Error SecureTransport::GetThreadAttributeFromCertificate(const mbedtls_x509_crt *aCert,
int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength)
{
Error error = kErrorNotFound;
char oid[9] = {0x2B, 0x06, 0x01, 0x04, 0x01, static_cast<char>(0x82), static_cast<char>(0xDF),
0x2A, 0x00}; // 1.3.6.1.4.1.44970.0
mbedtls_x509_buf v3_ext;
unsigned char *p, *end, *endExtData;
size_t len;
size_t attributeBufferSize;
mbedtls_x509_buf extnOid;
int ret, isCritical;
VerifyOrExit(aAttributeLength != nullptr, error = kErrorInvalidArgs);
attributeBufferSize = *aAttributeLength;
*aAttributeLength = 0;
VerifyOrExit(aCert != nullptr, error = kErrorInvalidState);
v3_ext = aCert->v3_ext;
p = v3_ext.p;
VerifyOrExit(p != nullptr, error = kErrorInvalidState);
end = p + v3_ext.len;
VerifyOrExit(mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0,
error = kErrorParse);
VerifyOrExit(end == p + len, error = kErrorParse);
VerifyOrExit(aThreadOidDescriptor < 128, error = kErrorNotImplemented);
oid[sizeof(oid) - 1] = static_cast<char>(aThreadOidDescriptor);
while (p < end)
{
isCritical = 0;
VerifyOrExit(mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0,
error = kErrorParse);
endExtData = p + len;
// Get extension ID
VerifyOrExit(mbedtls_asn1_get_tag(&p, endExtData, &extnOid.len, MBEDTLS_ASN1_OID) == 0, error = kErrorParse);
extnOid.tag = MBEDTLS_ASN1_OID;
extnOid.p = p;
p += extnOid.len;
// Get optional critical
ret = mbedtls_asn1_get_bool(&p, endExtData, &isCritical);
VerifyOrExit(ret == 0 || ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG, error = kErrorParse);
// Data should be octet string type
VerifyOrExit(mbedtls_asn1_get_tag(&p, endExtData, &len, MBEDTLS_ASN1_OCTET_STRING) == 0, error = kErrorParse);
VerifyOrExit(endExtData == p + len, error = kErrorParse);
if (isCritical || extnOid.len != sizeof(oid))
{
continue;
}
if (memcmp(extnOid.p, oid, sizeof(oid)) == 0)
{
*aAttributeLength = len;
if (aAttributeBuffer != nullptr)
{
VerifyOrExit(len <= attributeBufferSize, error = kErrorNoBufs);
memcpy(aAttributeBuffer, p, len);
}
error = kErrorNone;
break;
}
}
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_TLS_API_ENABLE
#ifdef MBEDTLS_SSL_SRV_C
Error Dtls::SetClientId(const uint8_t *aClientId, uint8_t aLength)
Error SecureTransport::SetClientId(const uint8_t *aClientId, uint8_t aLength)
{
int rval = mbedtls_ssl_set_client_transport_id(&mSsl, aClientId, aLength);
return Crypto::MbedTls::MapError(rval);
}
#endif
Error Dtls::Send(Message &aMessage, uint16_t aLength)
Error SecureTransport::Send(Message &aMessage, uint16_t aLength)
{
Error error = kErrorNone;
uint8_t buffer[kApplicationDataMaxLength];
@@ -583,7 +751,7 @@ exit:
return error;
}
void Dtls::Receive(Message &aMessage)
void SecureTransport::Receive(Message &aMessage)
{
mReceiveMessage = &aMessage;
@@ -592,28 +760,28 @@ void Dtls::Receive(Message &aMessage)
mReceiveMessage = nullptr;
}
int Dtls::HandleMbedtlsTransmit(void *aContext, const unsigned char *aBuf, size_t aLength)
int SecureTransport::HandleMbedtlsTransmit(void *aContext, const unsigned char *aBuf, size_t aLength)
{
return static_cast<Dtls *>(aContext)->HandleMbedtlsTransmit(aBuf, aLength);
return static_cast<SecureTransport *>(aContext)->HandleMbedtlsTransmit(aBuf, aLength);
}
int Dtls::HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength)
int SecureTransport::HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength)
{
Error error;
int rval = 0;
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
LogDebg("HandleMbedtlsTransmit");
LogDebg("HandleMbedtlsTransmit DTLS");
}
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
else
{
LogDebg("ApplicationCoapSecure HandleMbedtlsTransmit");
LogDebg("HandleMbedtlsTransmit TLS");
}
#endif
error = HandleDtlsSend(aBuf, static_cast<uint16_t>(aLength), mMessageSubType);
error = HandleSecureTransportSend(aBuf, static_cast<uint16_t>(aLength), mMessageSubType);
// Restore default sub type.
mMessageSubType = mMessageDefaultSubType;
@@ -637,23 +805,23 @@ int Dtls::HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength)
return rval;
}
int Dtls::HandleMbedtlsReceive(void *aContext, unsigned char *aBuf, size_t aLength)
int SecureTransport::HandleMbedtlsReceive(void *aContext, unsigned char *aBuf, size_t aLength)
{
return static_cast<Dtls *>(aContext)->HandleMbedtlsReceive(aBuf, aLength);
return static_cast<SecureTransport *>(aContext)->HandleMbedtlsReceive(aBuf, aLength);
}
int Dtls::HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength)
int SecureTransport::HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength)
{
int rval;
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
LogDebg("HandleMbedtlsReceive");
LogDebg("HandleMbedtlsReceive DTLS");
}
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
else
{
LogDebg("ApplicationCoapSecure HandleMbedtlsReceive");
LogDebg("HandleMbedtlsReceive TLS");
}
#endif
@@ -672,9 +840,12 @@ exit:
return rval;
}
int Dtls::HandleMbedtlsGetTimer(void *aContext) { return static_cast<Dtls *>(aContext)->HandleMbedtlsGetTimer(); }
int SecureTransport::HandleMbedtlsGetTimer(void *aContext)
{
return static_cast<SecureTransport *>(aContext)->HandleMbedtlsGetTimer();
}
int Dtls::HandleMbedtlsGetTimer(void)
int SecureTransport::HandleMbedtlsGetTimer(void)
{
int rval;
@@ -682,10 +853,10 @@ int Dtls::HandleMbedtlsGetTimer(void)
{
LogDebg("HandleMbedtlsGetTimer");
}
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
else
{
LogDebg("ApplicationCoapSecure HandleMbedtlsGetTimer");
LogDebg("HandleMbedtlsGetTimer");
}
#endif
@@ -709,21 +880,21 @@ int Dtls::HandleMbedtlsGetTimer(void)
return rval;
}
void Dtls::HandleMbedtlsSetTimer(void *aContext, uint32_t aIntermediate, uint32_t aFinish)
void SecureTransport::HandleMbedtlsSetTimer(void *aContext, uint32_t aIntermediate, uint32_t aFinish)
{
static_cast<Dtls *>(aContext)->HandleMbedtlsSetTimer(aIntermediate, aFinish);
static_cast<SecureTransport *>(aContext)->HandleMbedtlsSetTimer(aIntermediate, aFinish);
}
void Dtls::HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish)
void SecureTransport::HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish)
{
if (mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
{
LogDebg("SetTimer");
LogDebg("SetTimer DTLS");
}
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
else
{
LogDebg("ApplicationCoapSecure SetTimer");
LogDebg("SetTimer TLS");
}
#endif
@@ -742,42 +913,42 @@ void Dtls::HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish)
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
void Dtls::HandleMbedtlsExportKeys(void *aContext,
mbedtls_ssl_key_export_type aType,
const unsigned char *aMasterSecret,
size_t aMasterSecretLen,
const unsigned char aClientRandom[32],
const unsigned char aServerRandom[32],
mbedtls_tls_prf_types aTlsPrfType)
void SecureTransport::HandleMbedtlsExportKeys(void *aContext,
mbedtls_ssl_key_export_type aType,
const unsigned char *aMasterSecret,
size_t aMasterSecretLen,
const unsigned char aClientRandom[32],
const unsigned char aServerRandom[32],
mbedtls_tls_prf_types aTlsPrfType)
{
static_cast<Dtls *>(aContext)->HandleMbedtlsExportKeys(aType, aMasterSecret, aMasterSecretLen, aClientRandom,
aServerRandom, aTlsPrfType);
static_cast<SecureTransport *>(aContext)->HandleMbedtlsExportKeys(aType, aMasterSecret, aMasterSecretLen,
aClientRandom, aServerRandom, aTlsPrfType);
}
void Dtls::HandleMbedtlsExportKeys(mbedtls_ssl_key_export_type aType,
const unsigned char *aMasterSecret,
size_t aMasterSecretLen,
const unsigned char aClientRandom[32],
const unsigned char aServerRandom[32],
mbedtls_tls_prf_types aTlsPrfType)
void SecureTransport::HandleMbedtlsExportKeys(mbedtls_ssl_key_export_type aType,
const unsigned char *aMasterSecret,
size_t aMasterSecretLen,
const unsigned char aClientRandom[32],
const unsigned char aServerRandom[32],
mbedtls_tls_prf_types aTlsPrfType)
{
Crypto::Sha256::Hash kek;
Crypto::Sha256 sha256;
unsigned char keyBlock[kDtlsKeyBlockSize];
unsigned char randBytes[2 * kDtlsRandomBufferSize];
unsigned char keyBlock[kSecureTransportKeyBlockSize];
unsigned char randBytes[2 * kSecureTransportRandomBufferSize];
VerifyOrExit(mCipherSuites[0] == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8);
VerifyOrExit(aType == MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET);
memcpy(randBytes, aServerRandom, kDtlsRandomBufferSize);
memcpy(randBytes + kDtlsRandomBufferSize, aClientRandom, kDtlsRandomBufferSize);
memcpy(randBytes, aServerRandom, kSecureTransportRandomBufferSize);
memcpy(randBytes + kSecureTransportRandomBufferSize, aClientRandom, kSecureTransportRandomBufferSize);
// Retrieve the Key block from Master secret
mbedtls_ssl_tls_prf(aTlsPrfType, aMasterSecret, aMasterSecretLen, "key expansion", randBytes, sizeof(randBytes),
keyBlock, sizeof(keyBlock));
sha256.Start();
sha256.Update(keyBlock, kDtlsKeyBlockSize);
sha256.Update(keyBlock, kSecureTransportKeyBlockSize);
sha256.Finish(kek);
LogDebg("Generated KEK");
@@ -789,22 +960,22 @@ exit:
#else
int Dtls::HandleMbedtlsExportKeys(void *aContext,
const unsigned char *aMasterSecret,
const unsigned char *aKeyBlock,
size_t aMacLength,
size_t aKeyLength,
size_t aIvLength)
int SecureTransport::HandleMbedtlsExportKeys(void *aContext,
const unsigned char *aMasterSecret,
const unsigned char *aKeyBlock,
size_t aMacLength,
size_t aKeyLength,
size_t aIvLength)
{
return static_cast<Dtls *>(aContext)->HandleMbedtlsExportKeys(aMasterSecret, aKeyBlock, aMacLength, aKeyLength,
aIvLength);
return static_cast<SecureTransport *>(aContext)->HandleMbedtlsExportKeys(aMasterSecret, aKeyBlock, aMacLength,
aKeyLength, aIvLength);
}
int Dtls::HandleMbedtlsExportKeys(const unsigned char *aMasterSecret,
const unsigned char *aKeyBlock,
size_t aMacLength,
size_t aKeyLength,
size_t aIvLength)
int SecureTransport::HandleMbedtlsExportKeys(const unsigned char *aMasterSecret,
const unsigned char *aKeyBlock,
size_t aMacLength,
size_t aKeyLength,
size_t aIvLength)
{
OT_UNUSED_VARIABLE(aMasterSecret);
@@ -826,12 +997,12 @@ exit:
#endif // (MBEDTLS_VERSION_NUMBER >= 0x03000000)
void Dtls::HandleTimer(Timer &aTimer)
void SecureTransport::HandleTimer(Timer &aTimer)
{
static_cast<Dtls *>(static_cast<TimerMilliContext &>(aTimer).GetContext())->HandleTimer();
static_cast<SecureTransport *>(static_cast<TimerMilliContext &>(aTimer).GetContext())->HandleTimer();
}
void Dtls::HandleTimer(void)
void SecureTransport::HandleTimer(void)
{
switch (mState)
{
@@ -852,7 +1023,7 @@ void Dtls::HandleTimer(void)
}
}
void Dtls::Process(void)
void SecureTransport::Process(void)
{
uint8_t buf[OPENTHREAD_CONFIG_DTLS_MAX_CONTENT_LEN];
bool shouldDisconnect = false;
@@ -938,12 +1109,12 @@ exit:
}
}
void Dtls::HandleMbedtlsDebug(void *aContext, int aLevel, const char *aFile, int aLine, const char *aStr)
void SecureTransport::HandleMbedtlsDebug(void *aContext, int aLevel, const char *aFile, int aLine, const char *aStr)
{
static_cast<Dtls *>(aContext)->HandleMbedtlsDebug(aLevel, aFile, aLine, aStr);
static_cast<SecureTransport *>(aContext)->HandleMbedtlsDebug(aLevel, aFile, aLine, aStr);
}
void Dtls::HandleMbedtlsDebug(int aLevel, const char *aFile, int aLine, const char *aStr)
void SecureTransport::HandleMbedtlsDebug(int aLevel, const char *aFile, int aLine, const char *aStr)
{
OT_UNUSED_VARIABLE(aStr);
OT_UNUSED_VARIABLE(aFile);
@@ -970,7 +1141,9 @@ void Dtls::HandleMbedtlsDebug(int aLevel, const char *aFile, int aLine, const ch
}
}
Error Dtls::HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, Message::SubType aMessageSubType)
Error SecureTransport::HandleSecureTransportSend(const uint8_t *aBuf,
uint16_t aLength,
Message::SubType aMessageSubType)
{
Error error = kErrorNone;
ot::Message *message = nullptr;
@@ -1004,4 +1177,4 @@ exit:
} // namespace MeshCoP
} // namespace ot
#endif // OPENTHREAD_CONFIG_DTLS_ENABLE
#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
@@ -31,17 +31,33 @@
* This file includes definitions for using mbedTLS.
*/
#ifndef DTLS_HPP_
#define DTLS_HPP_
#ifndef SECURE_TRANSPORT_HPP_
#define SECURE_TRANSPORT_HPP_
#include "openthread-core-config.h"
#ifdef OPENTHREAD_CONFIG_TLS_API_ENABLE
#error `OPENTHREAD_CONFIG_TLS_API_ENABLE` must not be defined directly, it is determined from `COAP_SECURE_API_ENABLE` and `BLE_TCAT_ENABLE`
#endif
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#define OPENTHREAD_CONFIG_TLS_API_ENABLE 1
#else
#define OPENTHREAD_CONFIG_TLS_API_ENABLE 0
#endif
#include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h>
#include <mbedtls/ssl_cookie.h>
#include <mbedtls/version.h>
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#ifndef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#error OPENTHREAD_CONFIG_BLE_TCAT_ENABLE requires MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif
#endif
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
#include <mbedtls/base64.h>
#endif
@@ -67,19 +83,20 @@ namespace ot {
namespace MeshCoP {
class Dtls : public InstanceLocator
class SecureTransport : public InstanceLocator
{
public:
static constexpr uint8_t kPskMaxLength = 32; ///< Maximum PSK length.
/**
* Initializes the DTLS object.
* Initializes the SecureTransport object.
*
* @param[in] aInstance A reference to the OpenThread instance.
* @param[in] aLayerTwoSecurity Specifies whether to use layer two security or not.
* @param[in] aDatagramTransport Specifies if dtls of tls connection should be used.
*
*/
explicit Dtls(Instance &aInstance, bool aLayerTwoSecurity);
explicit SecureTransport(Instance &aInstance, bool aLayerTwoSecurity, bool aDatagramTransport = true);
/**
* Pointer is called when a connection is established or torn down.
@@ -91,7 +108,7 @@ public:
typedef void (*ConnectedHandler)(void *aContext, bool aConnected);
/**
* Pointer is called when data is received from the DTLS session.
* Pointer is called when data is received from the session.
*
* @param[in] aContext A pointer to application-specific context.
* @param[in] aBuf A pointer to the received data buffer.
@@ -111,14 +128,14 @@ public:
typedef Error (*TransportCallback)(void *aContext, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
/**
* Opens the DTLS socket.
* Opens the socket.
*
* @param[in] aReceiveHandler A pointer to a function that is called to receive DTLS payload.
* @param[in] aReceiveHandler A pointer to a function that is called to receive payload.
* @param[in] aConnectedHandler A pointer to a function that is called when connected or disconnected.
* @param[in] aContext A pointer to arbitrary context information.
*
* @retval kErrorNone Successfully opened the socket.
* @retval kErrorAlready The DTLS is already open.
* @retval kErrorAlready The connection is already open.
*
*/
Error Open(ReceiveHandler aReceiveHandler, ConnectedHandler aConnectedHandler, void *aContext);
@@ -128,8 +145,8 @@ public:
*
* @param[in] aPort The port to bind.
*
* @retval kErrorNone Successfully bound the DTLS socket.
* @retval kErrorInvalidState The DTLS socket is not open.
* @retval kErrorNone Successfully bound the socket.
* @retval kErrorInvalidState The socket is not open.
* @retval kErrorAlready Already bound.
*
*/
@@ -144,20 +161,20 @@ public:
uint16_t GetUdpPort(void) const;
/**
* Binds this DTLS with a transport callback.
* Binds with a transport callback.
*
* @param[in] aCallback A pointer to a function for sending messages.
* @param[in] aContext A pointer to arbitrary context information.
*
* @retval kErrorNone Successfully bound the DTLS socket.
* @retval kErrorInvalidState The DTLS socket is not open.
* @retval kErrorNone Successfully bound the socket.
* @retval kErrorInvalidState The socket is not open.
* @retval kErrorAlready Already bound.
*
*/
Error Bind(TransportCallback aCallback, void *aContext);
/**
* Establishes a DTLS session.
* Establishes a secure session.
*
* For CoAP Secure API do first:
* Set X509 Pk and Cert for use DTLS mode ECDHE ECDSA with AES 128 CCM 8 or
@@ -165,38 +182,38 @@ public:
*
* @param[in] aSockAddr A reference to the remote sockaddr.
*
* @retval kErrorNone Successfully started DTLS handshake.
* @retval kErrorInvalidState The DTLS socket is not open.
* @retval kErrorNone Successfully started handshake.
* @retval kErrorInvalidState The socket is not open.
*
*/
Error Connect(const Ip6::SockAddr &aSockAddr);
/**
* Indicates whether or not the DTLS session is active.
* Indicates whether or not the session is active.
*
* @retval TRUE If DTLS session is active.
* @retval FALSE If DTLS session is not active.
* @retval TRUE If session is active.
* @retval FALSE If session is not active.
*
*/
bool IsConnectionActive(void) const { return mState >= kStateConnecting; }
/**
* Indicates whether or not the DTLS session is connected.
* Indicates whether or not the session is connected.
*
* @retval TRUE The DTLS session is connected.
* @retval FALSE The DTLS session is not connected.
* @retval TRUE The session is connected.
* @retval FALSE The session is not connected.
*
*/
bool IsConnected(void) const { return mState == kStateConnected; }
/**
* Disconnects the DTLS session.
* Disconnects the session.
*
*/
void Disconnect(void);
/**
* Closes the DTLS socket.
* Closes the socket.
*
*/
void Close(void);
@@ -212,10 +229,10 @@ public:
*/
Error SetPsk(const uint8_t *aPsk, uint8_t aPskLength);
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
/**
* Sets the Pre-Shared Key (PSK) for DTLS sessions-
* Sets the Pre-Shared Key (PSK) for sessions-
* identified by a PSK.
*
* DTLS mode "PSK with AES 128 CCM 8" for Application CoAPS.
@@ -280,8 +297,84 @@ public:
Error GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize);
#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/**
* Set the authentication mode for a dtls connection.
* Returns an attribute value identified by its OID from the subject
* of the peer x509 certificate. The peer OID is provided in binary format.
* The attribute length is set if the attribute was successfully read or zero
* if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard
* if the attribute was successfully read.
*
* @param[in] aOid A pointer to the OID to be found.
* @param[in] aOidLength The length of the OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
* @param[out] aAsn1Type A pointer to the ASN.1 type of the attribute written to the buffer.
*
* @retval kErrorInvalidState Not connected yet.
* @retval kErrorInvalidArgs Invalid attribute length.
* @retval kErrorNone Successfully read attribute.
* @retval kErrorNoBufs Insufficient memory for storing the attribute value.
*
*/
Error GetPeerSubjectAttributeByOid(const char *aOid,
size_t aOidLength,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength,
int *aAsn1Type);
/**
* Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of
* the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor.
* The attribute length is set if the attribute was successfully read or zero if unsuccessful.
* Requires a connection to be active.
*
* @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
*
* @retval kErrorNone Successfully read attribute.
* @retval kErrorInvalidArgs Invalid attribute length.
* @retval kErrorNotFound The requested attribute was not found.
* @retval kErrorNoBufs Insufficient memory for storing the attribute value.
* @retval kErrorInvalidState Not connected yet.
* @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127.
* @retval kErrorParse The certificate extensions could not be parsed.
*
*/
Error GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength);
#endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/**
* Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of
* the own x509 certificate, where the last digit x is set to aThreadOidDescriptor.
* The attribute length is set if the attribute was successfully read or zero if unsuccessful.
* Requires a connection to be active.
*
* @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
*
* @retval kErrorNone Successfully read attribute.
* @retval kErrorInvalidArgs Invalid attribute length.
* @retval kErrorNotFound The requested attribute was not found.
* @retval kErrorNoBufs Insufficient memory for storing the attribute value.
* @retval kErrorInvalidState Not connected yet.
* @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127.
* @retval kErrorParse The certificate extensions could not be parsed.
*
*/
Error GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength);
/**
* Set the authentication mode for a connection.
*
* Disable or enable the verification of peer certificate.
* Must called before start.
@@ -290,7 +383,7 @@ public:
*
*/
void SetSslAuthMode(bool aVerifyPeerCertificate) { mVerifyPeerCertificate = aVerifyPeerCertificate; }
#endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#endif // OPENTHREAD_CONFIG_TLS_API_ENABLE
#ifdef MBEDTLS_SSL_SRV_C
/**
@@ -306,19 +399,19 @@ public:
#endif
/**
* Sends data within the DTLS session.
* Sends data within the session.
*
* @param[in] aMessage A message to send via DTLS.
* @param[in] aMessage A message to send via connection.
* @param[in] aLength Number of bytes in the data buffer.
*
* @retval kErrorNone Successfully sent the data via the DTLS session.
* @retval kErrorNone Successfully sent the data via the session.
* @retval kErrorNoBufs A message is too long.
*
*/
Error Send(Message &aMessage, uint16_t aLength);
/**
* Provides a received DTLS message to the DTLS object.
* Provides a received message to the SecureTransport object.
*
* @param[in] aMessage A reference to the message.
*
@@ -335,9 +428,9 @@ public:
void SetDefaultMessageSubType(Message::SubType aMessageSubType) { mMessageDefaultSubType = aMessageSubType; }
/**
* Returns the DTLS session's peer address.
* Returns the session's peer address.
*
* @return DTLS session's message info.
* @return session's message info.
*
*/
const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; }
@@ -349,34 +442,39 @@ private:
{
kStateClosed, // UDP socket is closed.
kStateOpen, // UDP socket is open.
kStateInitializing, // The DTLS service is initializing.
kStateConnecting, // The DTLS service is establishing a connection.
kStateConnected, // The DTLS service has a connection established.
kStateCloseNotify, // The DTLS service is closing a connection.
kStateInitializing, // The service is initializing.
kStateConnecting, // The service is establishing a connection.
kStateConnected, // The service has a connection established.
kStateCloseNotify, // The service is closing a connection.
};
static constexpr uint32_t kGuardTimeNewConnectionMilli = 2000;
#if !OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if !OPENTHREAD_CONFIG_TLS_API_ENABLE
static constexpr uint16_t kApplicationDataMaxLength = 1152;
#else
static constexpr uint16_t kApplicationDataMaxLength = OPENTHREAD_CONFIG_DTLS_APPLICATION_DATA_MAX_LENGTH;
#endif
static constexpr size_t kDtlsKeyBlockSize = 40;
static constexpr size_t kDtlsRandomBufferSize = 32;
static constexpr size_t kSecureTransportKeyBlockSize = 40;
static constexpr size_t kSecureTransportRandomBufferSize = 32;
void FreeMbedtls(void);
Error Setup(bool aClient);
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
/**
* Set keys and/or certificates for dtls session dependent of used cipher suite.
*
* @retval mbedtls error, 0 if successfully.
*
*/
int SetApplicationCoapSecureKeys(void);
int SetApplicationSecureKeys(void);
Error GetThreadAttributeFromCertificate(const mbedtls_x509_crt *aCert,
int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength);
#endif
static void HandleMbedtlsDebug(void *aContext, int aLevel, const char *aFile, int aLine, const char *aStr);
@@ -434,8 +532,8 @@ private:
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
void HandleDtlsReceive(const uint8_t *aBuf, uint16_t aLength);
Error HandleDtlsSend(const uint8_t *aBuf, uint16_t aLength, Message::SubType aMessageSubType);
void HandleSecureTransportReceive(const uint8_t *aBuf, uint16_t aLength);
Error HandleSecureTransportSend(const uint8_t *aBuf, uint16_t aLength, Message::SubType aMessageSubType);
void Process(void);
@@ -459,7 +557,7 @@ private:
#endif
#endif
#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
#if OPENTHREAD_CONFIG_TLS_API_ENABLE
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
const uint8_t *mCaChainSrc;
uint32_t mCaChainLength;
@@ -494,16 +592,19 @@ private:
bool mTimerSet : 1;
bool mLayerTwoSecurity : 1;
bool mDatagramTransport : 1;
Message *mReceiveMessage;
Callback<ConnectedHandler> mConnectedCallback;
Callback<ReceiveHandler> mReceiveCallback;
void *mContext;
Ip6::MessageInfo mMessageInfo;
Ip6::Udp::Socket mSocket;
Callback<TransportCallback> mTransportCallback;
void *mTransportContext;
Message::SubType mMessageSubType;
Message::SubType mMessageDefaultSubType;
@@ -512,4 +613,4 @@ private:
} // namespace MeshCoP
} // namespace ot
#endif // DTLS_HPP_
#endif // SECURE_TRANSPORT_HPP_
+516
View File
@@ -0,0 +1,516 @@
/*
* Copyright (c) 2023, 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 TCAT Agent service.
*/
#include "tcat_agent.hpp"
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#include <stdio.h>
#include "common/array.hpp"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/encoding.hpp"
#include "common/locator_getters.hpp"
#include "common/string.hpp"
#include "instance/instance.hpp"
#include "radio/radio.hpp"
#include "thread/thread_netif.hpp"
#include "thread/uri_paths.hpp"
#include "utils/otns.hpp"
namespace ot {
namespace MeshCoP {
RegisterLogModule("TcatAgent");
bool TcatAgent::VendorInfo::IsValid(void) const
{
return mProvisioningUrl == nullptr || IsValidUtf8String(mProvisioningUrl) || mPskdString != nullptr;
}
TcatAgent::TcatAgent(Instance &aInstance)
: InstanceLocator(aInstance)
, mVendorInfo(nullptr)
, mCurrentApplicationProtocol(kApplicationProtocolNone)
, mState(kStateDisabled)
, mAlreadyCommissioned(false)
, mCommissionerHasNetworkName(false)
, mCommissionerHasDomainName(false)
, mCommissionerHasExtendedPanId(false)
{
mJoinerPskd.Clear();
mCurrentServiceName[0] = 0;
}
Error TcatAgent::Start(const TcatAgent::VendorInfo &aVendorInfo,
AppDataReceiveCallback aAppDataReceiveCallback,
JoinCallback aHandler,
void *aContext)
{
Error error = kErrorNone;
LogInfo("Starting");
VerifyOrExit(aVendorInfo.IsValid(), error = kErrorInvalidArgs);
SuccessOrExit(error = mJoinerPskd.SetFrom(aVendorInfo.mPskdString));
mAppDataReceiveCallback.Set(aAppDataReceiveCallback, aContext);
mJoinCallback.Set(aHandler, aContext);
mVendorInfo = &aVendorInfo;
mCurrentApplicationProtocol = kApplicationProtocolNone;
mState = kStateEnabled;
mAlreadyCommissioned = false;
exit:
LogError("start TCAT agent", error);
return error;
}
void TcatAgent::Stop(void)
{
mCurrentApplicationProtocol = kApplicationProtocolNone;
mState = kStateDisabled;
mAlreadyCommissioned = false;
mAppDataReceiveCallback.Clear();
mJoinCallback.Clear();
LogInfo("TCAT agent stopped");
}
Error TcatAgent::Connected(MeshCoP::SecureTransport &aTlsContext)
{
size_t len;
Error error;
VerifyOrExit(IsEnabled(), error = kErrorInvalidState);
len = sizeof(mCommissionerAuthorizationField);
SuccessOrExit(
error = aTlsContext.GetThreadAttributeFromPeerCertificate(
kCertificateAuthorizationField, reinterpret_cast<uint8_t *>(&mCommissionerAuthorizationField), &len));
VerifyOrExit(len == sizeof(mCommissionerAuthorizationField), error = kErrorParse);
VerifyOrExit((mCommissionerAuthorizationField.mHeader & kCommissionerFlag) == 1, error = kErrorParse);
len = sizeof(mDeviceAuthorizationField);
SuccessOrExit(error = aTlsContext.GetThreadAttributeFromOwnCertificate(
kCertificateAuthorizationField, reinterpret_cast<uint8_t *>(&mDeviceAuthorizationField), &len));
VerifyOrExit(len == sizeof(mDeviceAuthorizationField), error = kErrorParse);
VerifyOrExit((mDeviceAuthorizationField.mHeader & kCommissionerFlag) == 0, error = kErrorParse);
mCommissionerHasDomainName = false;
mCommissionerHasNetworkName = false;
mCommissionerHasExtendedPanId = false;
len = sizeof(mCommissionerDomainName) - 1;
if (aTlsContext.GetThreadAttributeFromPeerCertificate(
kCertificateDomainName, reinterpret_cast<uint8_t *>(&mCommissionerDomainName), &len) == kErrorNone)
{
mCommissionerDomainName.m8[len] = '\0';
mCommissionerHasDomainName = true;
}
len = sizeof(mCommissionerNetworkName) - 1;
if (aTlsContext.GetThreadAttributeFromPeerCertificate(
kCertificateNetworkName, reinterpret_cast<uint8_t *>(&mCommissionerNetworkName), &len) == kErrorNone)
{
mCommissionerNetworkName.m8[len] = '\0';
mCommissionerHasNetworkName = true;
}
len = sizeof(mCommissionerExtendedPanId);
if (aTlsContext.GetThreadAttributeFromPeerCertificate(
kCertificateExtendedPanId, reinterpret_cast<uint8_t *>(&mCommissionerExtendedPanId), &len) == kErrorNone)
{
if (len == sizeof(mCommissionerExtendedPanId))
{
mCommissionerHasExtendedPanId = true;
}
}
mCurrentApplicationProtocol = kApplicationProtocolNone;
mCurrentServiceName[0] = 0;
mState = kStateConnected;
mAlreadyCommissioned = Get<ActiveDatasetManager>().IsCommissioned();
LogInfo("TCAT agent connected");
exit:
return error;
}
void TcatAgent::Disconnected(void)
{
mCurrentApplicationProtocol = kApplicationProtocolNone;
mAlreadyCommissioned = false;
if (mState != kStateDisabled)
{
mState = kStateEnabled;
}
LogInfo("TCAT agent disconnected");
}
bool TcatAgent::CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags,
CommandClassFlags aDeviceCommandClassFlags,
Dataset *aDataset) const
{
bool authorized = false;
bool additionalDeviceRequirementMet = false;
bool domainNamesMatch = false;
bool networkNamesMatch = false;
bool extendedPanIdsMatch = false;
VerifyOrExit(IsConnected());
VerifyOrExit(aCommissionerCommandClassFlags & kAccessFlag);
if (aDeviceCommandClassFlags & kAccessFlag)
{
additionalDeviceRequirementMet = true;
}
if (aDeviceCommandClassFlags & kPskdFlag)
{
additionalDeviceRequirementMet = true;
}
if (aDeviceCommandClassFlags & kPskcFlag)
{
additionalDeviceRequirementMet = true;
}
if (mCommissionerHasNetworkName || mCommissionerHasExtendedPanId)
{
Dataset::Info datasetInfo;
Error datasetError = kErrorNone;
if (aDataset == nullptr)
{
datasetError = Get<ActiveDatasetManager>().Read(datasetInfo);
}
else
{
aDataset->ConvertTo(datasetInfo);
}
if (datasetError == kErrorNone)
{
if (datasetInfo.IsNetworkNamePresent() && mCommissionerHasNetworkName &&
(datasetInfo.GetNetworkName() == mCommissionerNetworkName))
{
networkNamesMatch = true;
}
if (datasetInfo.IsExtendedPanIdPresent() && mCommissionerHasExtendedPanId &&
(datasetInfo.GetExtendedPanId() == mCommissionerExtendedPanId))
{
extendedPanIdsMatch = true;
}
}
}
if (!networkNamesMatch)
{
VerifyOrExit((aCommissionerCommandClassFlags & kNetworkNameFlag) == 0);
}
else if (aDeviceCommandClassFlags & kNetworkNameFlag)
{
additionalDeviceRequirementMet = true;
}
if (!extendedPanIdsMatch)
{
VerifyOrExit((aCommissionerCommandClassFlags & kExtendedPanIdFlag) == 0);
}
else if (aDeviceCommandClassFlags & kExtendedPanIdFlag)
{
additionalDeviceRequirementMet = true;
}
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
VerifyOrExit((aCommissionerCommandClassFlags & kThreadDomainFlag) == 0);
#endif
if (!domainNamesMatch)
{
VerifyOrExit((aCommissionerCommandClassFlags & kThreadDomainFlag) == 0);
}
else if (aDeviceCommandClassFlags & kThreadDomainFlag)
{
additionalDeviceRequirementMet = true;
}
if (additionalDeviceRequirementMet)
{
authorized = true;
}
exit:
return authorized;
}
bool TcatAgent::IsCommandClassAuthorized(CommandClass aCommandClass) const
{
bool authorized = false;
switch (aCommandClass)
{
case kGeneral:
authorized = true;
break;
case kCommissioning:
authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mCommissioningFlags,
mDeviceAuthorizationField.mCommissioningFlags, nullptr);
break;
case kExtraction:
authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mExtractionFlags,
mDeviceAuthorizationField.mExtractionFlags, nullptr);
break;
case kTlvDecommissioning:
authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mDecommissioningFlags,
mDeviceAuthorizationField.mDecommissioningFlags, nullptr);
break;
case kApplication:
authorized = CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mApplicationFlags,
mDeviceAuthorizationField.mApplicationFlags, nullptr);
break;
case kInvalid:
authorized = false;
break;
}
return authorized;
}
TcatAgent::CommandClass TcatAgent::GetCommandClass(uint8_t aTlvType) const
{
static constexpr int kGeneralTlvs = 0x1F;
static constexpr int kCommissioningTlvs = 0x3F;
static constexpr int kExtractionTlvs = 0x5F;
static constexpr int kTlvDecommissioningTlvs = 0x7F;
static constexpr int kApplicationTlvs = 0x9F;
if (aTlvType <= kGeneralTlvs)
{
return kGeneral;
}
else if (aTlvType <= kCommissioningTlvs)
{
return kCommissioning;
}
else if (aTlvType <= kExtractionTlvs)
{
return kExtraction;
}
else if (aTlvType <= kTlvDecommissioningTlvs)
{
return kTlvDecommissioning;
}
else if (aTlvType <= kApplicationTlvs)
{
return kApplication;
}
else
{
return kInvalid;
}
}
bool TcatAgent::CanProcessTlv(uint8_t aTlvType) const
{
CommandClass tlvCommandClass = GetCommandClass(aTlvType);
return IsCommandClassAuthorized(tlvCommandClass);
}
Error TcatAgent::HandleSingleTlv(const Message &aIncommingMessage, Message &aOutgoingMessage)
{
Error error = kErrorParse;
ot::Tlv tlv;
uint16_t offset = aIncommingMessage.GetOffset();
uint16_t length;
bool response = false;
VerifyOrExit(IsConnected(), error = kErrorInvalidState);
SuccessOrExit(error = aIncommingMessage.Read(offset, tlv));
if (tlv.IsExtended())
{
ot::ExtendedTlv extTlv;
SuccessOrExit(error = aIncommingMessage.Read(offset, extTlv));
length = extTlv.GetLength();
offset += sizeof(ot::ExtendedTlv);
}
else
{
length = tlv.GetLength();
offset += sizeof(ot::Tlv);
}
if (!CanProcessTlv(tlv.GetType()))
{
error = kErrorRejected;
}
else
{
switch (tlv.GetType())
{
case kTlvDisconnect:
error = kErrorAbort;
break;
case kTlvSetActiveOperationalDataset:
error = HandleSetActiveOperationalDataset(aIncommingMessage, offset, length);
break;
case kTlvStartThreadInterface:
error = HandleStartThreadInterface();
break;
case kTlvStopThreadInterface:
error = otThreadSetEnabled(&GetInstance(), false);
break;
case kTlvSendApplicationData:
LogInfo("Application data len:%d, offset:%d", length, offset);
mAppDataReceiveCallback.InvokeIfSet(&GetInstance(), &aIncommingMessage, offset,
MapEnum(mCurrentApplicationProtocol), mCurrentServiceName);
response = true;
error = kErrorNone;
break;
default:
error = kErrorInvalidCommand;
}
}
if (!response)
{
StatusCode statusCode;
switch (error)
{
case kErrorNone:
statusCode = kStatusSuccess;
break;
case kErrorInvalidState:
statusCode = kStatusUndefined;
break;
case kErrorParse:
statusCode = kStatusParseError;
break;
case kErrorInvalidCommand:
statusCode = kStatusUnsupported;
break;
case kErrorRejected:
statusCode = kStatusUnauthorized;
break;
case kErrorNotImplemented:
statusCode = kStatusUnsupported;
break;
default:
statusCode = kStatusGeneralError;
break;
}
SuccessOrExit(error = ot::Tlv::Append<ResponseWithStatusTlv>(aOutgoingMessage, statusCode));
}
exit:
return error;
}
Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncommingMessage, uint16_t aOffset, uint16_t aLength)
{
Dataset dataset;
otOperationalDatasetTlvs datasetTlvs;
Error error;
SuccessOrExit(error = dataset.ReadFromMessage(aIncommingMessage, aOffset, aLength));
if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mApplicationFlags,
mDeviceAuthorizationField.mApplicationFlags, &dataset))
{
error = kErrorRejected;
ExitNow();
}
dataset.ConvertTo(datasetTlvs);
error = Get<ActiveDatasetManager>().Save(datasetTlvs);
exit:
return error;
}
Error TcatAgent::HandleStartThreadInterface(void)
{
Error error;
Dataset::Info datasetInfo;
VerifyOrExit(Get<ActiveDatasetManager>().Read(datasetInfo) == kErrorNone, error = kErrorInvalidState);
VerifyOrExit(datasetInfo.IsNetworkKeyPresent(), error = kErrorInvalidState);
#if OPENTHREAD_CONFIG_LINK_RAW_ENABLE
VerifyOrExit(!Get<Mac::LinkRaw>().IsEnabled(), error = kErrorInvalidState);
#endif
Get<ThreadNetif>().Up();
error = Get<Mle::MleRouter>().Start();
exit:
return error;
}
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
void TcatAgent::LogError(const char *aActionText, Error aError)
{
if (aError != kErrorNone)
{
LogWarn("Failed to %s: %s", aActionText, ErrorToString(aError));
}
}
#endif
} // namespace MeshCoP
} // namespace ot
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
+374
View File
@@ -0,0 +1,374 @@
/*
* Copyright (c) 2023, 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
* Implements the TCAT Agent service.
*/
#ifndef TCAT_AGENT_HPP_
#define TCAT_AGENT_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#include <openthread/tcat.h>
#include <openthread/platform/ble.h>
#include "common/as_core_type.hpp"
#include "common/callback.hpp"
#include "common/locator.hpp"
#include "common/log.hpp"
#include "common/message.hpp"
#include "common/non_copyable.hpp"
#include "mac/mac_types.hpp"
#include "meshcop/dataset.hpp"
#include "meshcop/meshcop.hpp"
#include "meshcop/meshcop_tlvs.hpp"
#include "meshcop/secure_transport.hpp"
namespace ot {
namespace Ble {
class BleSecure;
}
namespace MeshCoP {
class TcatAgent : public InstanceLocator, private NonCopyable
{
public:
/**
* Pointer to call when application data was received over the TLS connection.
*
* Please see otHandleTcatApplicationDataReceive for details.
*
*/
typedef otHandleTcatApplicationDataReceive AppDataReceiveCallback;
/**
* Pointer to call to notify the completion of a join operation.
*
* Please see otHandleTcatJoin for details.
*
*/
typedef otHandleTcatJoin JoinCallback;
/**
* Represents a TCAT command class.
*
*/
enum CommandClass
{
kGeneral = OT_TCAT_COMMAND_CLASS_GENERAL, ///< TCAT commands related to general operations
kCommissioning = OT_TCAT_COMMAND_CLASS_COMMISSIONING, ///< TCAT commands related to commissioning
kExtraction = OT_TCAT_COMMAND_CLASS_EXTRACTION, ///< TCAT commands related to key extraction
kTlvDecommissioning = OT_TCAT_COMMAND_CLASS_DECOMMISSIONING, ///< TCAT commands related to de-commissioning
kApplication = OT_TCAT_COMMAND_CLASS_APPLICATION, ///< TCAT commands related to application layer
kInvalid ///< TCAT command belongs to reserved pool or is invalid
};
/**
* The certificate authorization field header type to indicate the type and version of the certificate.
*
*/
enum CertificateAuthorizationFieldHeader : uint8_t
{
kCommissionerFlag = 1 << 0, ///< TCAT commissioner ('1') or device ('0')
kHeaderVersion = 0xD0, ///< Header version (3 bits)
};
/**
* The command class flag type to indicate which requirements apply for a given command class.
*
*/
enum CommandClassFlags : uint8_t
{
kAccessFlag = 1 << 0, ///< Access to the command class (device: without without additional requirements).
kPskdFlag = 1 << 1, ///< Access requires proof-of-possession of the device's PSKd
kNetworkNameFlag = 1 << 2, ///< Access requires matching network name
kExtendedPanIdFlag = 1 << 3, ///< Access requires matching XPANID
kThreadDomainFlag = 1 << 4, ///< Access requires matching XPANID
kPskcFlag = 1 << 5, ///< Access requires proof-of-possession of the device's PSKc
};
/**
*
* Represents a data structure for storing TCAT Commissioner authorization information in the
* certificate ASN.1 field 1.3.6.1.4.1.44970.3.
*
*/
OT_TOOL_PACKED_BEGIN
struct CertificateAuthorizationField
{
CertificateAuthorizationFieldHeader mHeader; ///< Typ and version
CommandClassFlags mCommissioningFlags; ///< Command class flags
CommandClassFlags mExtractionFlags; ///< Command class flags
CommandClassFlags mDecommissioningFlags; ///< Command class flags
CommandClassFlags mApplicationFlags; ///< Command class flags
} OT_TOOL_PACKED_END;
typedef CertificateAuthorizationField CertificateAuthorizationField;
/**
* Represents the TCAT vendor information.
*
*/
class VendorInfo : public otTcatVendorInfo
{
public:
/**
* Validates whether the TCAT vendor information is valid.
*
* @returns Whether the parameters are valid.
*
*/
bool IsValid(void) const;
};
/**
* TCAT TLV Types.
*
*/
enum TlvType : uint8_t
{
// Command Class General
kTlvResponseWithStatus = 1, ///< TCAT response with status value TLV
kTlvResponseWithPayload = 2, ///< TCAT response with payload TLV
kTlvResponseEvent = 3, ///< TCAT response event TLV (reserved)
kTlvGetNetworkName = 8, ///< TCAT network name query TLV
kTlvDisconnect = 9, ///< TCAT disconnect request TLV
kTlvPing = 10, ///< TCAT ping request TLV
kTlvGetDeviceId = 11, ///< TCAT device ID query TLV
kTlvGetExtendedPanID = 12, ///< TCAT extended PAN ID query TLV
kTlvPresentPskdHash = 16, ///< TCAT commissioner rights elevation request TLV using PSKd hash
kTlvPresentPskcHash = 17, ///< TCAT commissioner rights elevation request TLV using PSKc hash
kTlvPresentInstallCodeHash = 18, ///< TCAT commissioner rights elevation request TLV using install code
kTlvRequestRandomNumChallenge = 19, ///< TCAT random number challenge query TLV
kTlvRequestPskdHash = 20, ///< TCAT PSKd hash request TLV
// Command Class Commissioning
kTlvSetActiveOperationalDataset = 32, ///< TCAT active operational dataset TLV
kTlvSetActiveOperationalDatasetAlternative = 33, ///< TCAT active operational dataset alternative #1 TLV
kTlvGetProvisioningTlvs = 36, ///< TCAT provisioning TLVs query TLV
kTlvGetCommissionerCertificate = 37, ///< TCAT commissioner certificate query TLV
kTlvGetDiagnosticTlvs = 38, ///< TCAT diagnostics TLVs query TLV
kTlvStartThreadInterface = 39, ///< TCAT start thread interface request TLV
kTlvStopThreadInterface = 40, ///< TCAT stop thread interface request TLV
// Command Class Extraction
kTlvGetActiveOperationalDataset = 64, ///< TCAT active oerational dataset query TLV
kTlvGetActiveOperationalDatasetAlternative = 65, ///< TCAT active oerational dataset alternative #1 query TLV
// Command Class Decommissioning
kTlvDecommission = 96, ///< TCAT decommission request TLV
// Command Class Application
kTlvSelectApplicationLayerUdp = 128, ///< TCAT select UDP protocol application layer request TLV
kTlvSelectApplicationLayerTcp = 129, ///< TCAT select TCP protocol application layer request TLV
kTlvSendApplicationData = 130, ///< TCAT send application data TLV
kTlvSendVendorSpecificData = 159, ///< TCAT send vendor specific command or data TLV
// Command Class CCM
kTlvSetLDevIdOperationalCert = 160, ///< TCAT LDevID operational certificate TLV
kTlvSetLDevIdPrivateKey = 161, ///< TCAT LDevID operational certificate pricate key TLV
kTlvSetDomainCaCert = 162, ///< TCAT domain CA certificate TLV
};
/**
* TCAT Response Types.
*
*/
enum StatusCode : uint8_t
{
kStatusSuccess = OT_TCAT_STATUS_SUCCESS, ///< Command or request was successfully processed
kStatusUnsupported = OT_TCAT_STATUS_UNSUPPORTED, ///< Requested command or received TLV is not supported
kStatusParseError = OT_TCAT_STATUS_PARSE_ERROR, ///< Request / command could not be parsed correctly
kStatusValueError = OT_TCAT_STATUS_VALUE_ERROR, ///< The value of the transmitted TLV has an error
kStatusGeneralError = OT_TCAT_STATUS_GENERAL_ERROR, ///< An error not matching any other category occurred
kStatusBusy = OT_TCAT_STATUS_BUSY, ///< Command cannot be executed because the resource is busy
kStatusUndefined = OT_TCAT_STATUS_UNDEFINED, ///< The requested value, data or service is not defined
///< (currently) or not present
kStatusHashError = OT_TCAT_STATUS_HASH_ERROR, ///< The hash value presented by the commissioner was incorrect
kStatusUnauthorized =
OT_TCAT_STATUS_UNAUTHORIZED, ///< Sender does not have sufficient authorization for the given command
};
/**
* Represents TCAT application protocol.
*
*/
enum TcatApplicationProtocol : uint8_t
{
kApplicationProtocolNone =
OT_TCAT_APPLICATION_PROTOCOL_NONE, ///< Message which has been sent without activating the TCAT agent
kApplicationProtocolUdp = OT_TCAT_APPLICATION_PROTOCOL_STATUS, ///< Message directed to a UDP service
kApplicationProtocolTcp = OT_TCAT_APPLICATION_PROTOCOL_TCP, ///< Message directed to a TCP service
};
/**
* Represents a TCAT certificate V3 extension attribute (OID 1.3.6.1.4.1.44970.x).
*
*/
enum TcatCertificateAttribute
{
kCertificateDomainName = 1,
kCertificateAuthorizationField = 3,
kCertificateNetworkName = 4,
kCertificateExtendedPanId = 5,
};
/**
* Represents TCAT status.
*
*/
enum State : uint8_t
{
kStateDisabled,
kStateEnabled,
kStateConnected,
};
/**
* Initializes the Joiner object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit TcatAgent(Instance &aInstance);
/**
* Enables the TCAT protocol.
*
* @param[in] aVendorInfo A pointer to the Vendor Information (must remain valid after the method
* call, may be NULL).
* @param[in] aAppDataReceiveCallback A pointer to a function that is called when the user data is received.
* @param[in] aHandler A pointer to a function that is called when the join operation completes.
* @param[in] aContext A context pointer.
*
* @retval kErrorNone Successfully started the TCAT agent.
* @retval kErrorInvalidArgs The aVendorInfo is invalid.
*
*/
Error Start(const VendorInfo &aVendorInfo,
AppDataReceiveCallback aAppDataReceiveCallback,
JoinCallback aHandler,
void *aContext);
/**
* Stops the TCAT protocol.
*
*/
void Stop(void);
/**
* Indicates whether or not the TCAT agent is enabled.
*
* @retval TRUE The TCAT agent is enabled.
* @retval FALSE The TCAT agent is not enabled.
*
*/
bool IsEnabled(void) const { return mState != kStateDisabled; }
/**
* Indicates whether or not the TCAT agent is connected.
*
* @retval TRUE The TCAT agent is connected.
* @retval FALSE The TCAT agent is not connected.
*
*/
bool IsConnected(void) const { return mState == kStateConnected; }
/**
* Indicates whether or not a command class is authorized.
*
* @param[in] aCommandClass Command class to subject for authorization check.
*
* @retval TRUE The command class is authorized.
* @retval FALSE The command class is not authorized.
*
*/
bool IsCommandClassAuthorized(CommandClass aCommandClass) const;
private:
Error Connected(MeshCoP::SecureTransport &aTlsContext);
void Disconnected(void);
Error HandleSingleTlv(const Message &aIncommingMessage, Message &aOutgoingMessage);
Error HandleSetActiveOperationalDataset(const Message &aIncommingMessage, uint16_t aOffset, uint16_t aLength);
Error HandleStartThreadInterface(void);
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_WARN)
void LogError(const char *aActionText, Error aError);
#else
void LogError(const char *, Error) {}
#endif
bool CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags,
CommandClassFlags aDeviceCommandClassFlags,
Dataset *aDataset) const;
bool CanProcessTlv(uint8_t aTlvType) const;
CommandClass GetCommandClass(uint8_t aTlvType) const;
static constexpr uint16_t kJoinerUdpPort = OPENTHREAD_CONFIG_JOINER_UDP_PORT;
JoinerPskd mJoinerPskd;
const VendorInfo *mVendorInfo;
Callback<JoinCallback> mJoinCallback;
Callback<AppDataReceiveCallback> mAppDataReceiveCallback;
CertificateAuthorizationField mCommissionerAuthorizationField;
CertificateAuthorizationField mDeviceAuthorizationField;
TcatApplicationProtocol mCurrentApplicationProtocol;
NetworkName mCommissionerNetworkName;
NetworkName mCommissionerDomainName;
ExtendedPanId mCommissionerExtendedPanId;
char mCurrentServiceName[OT_TCAT_MAX_SERVICE_NAME_LENGTH + 1];
State mState;
bool mAlreadyCommissioned : 1;
bool mCommissionerHasNetworkName : 1;
bool mCommissionerHasDomainName : 1;
bool mCommissionerHasExtendedPanId : 1;
friend class Ble::BleSecure;
};
} // namespace MeshCoP
DefineCoreType(otTcatVendorInfo, MeshCoP::TcatAgent::VendorInfo);
DefineMapEnum(otTcatApplicationProtocol, MeshCoP::TcatAgent::TcatApplicationProtocol);
typedef UintTlvInfo<MeshCoP::TcatAgent::kTlvResponseWithStatus, uint8_t> ResponseWithStatusTlv;
} // namespace ot
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#endif // TCAT_AGENT_HPP_
+1 -1
View File
@@ -88,7 +88,6 @@
#include "config/dns_client.h"
#include "config/dns_dso.h"
#include "config/dnssd_server.h"
#include "config/dtls.h"
#include "config/history_tracker.h"
#include "config/ip6.h"
#include "config/joiner.h"
@@ -109,6 +108,7 @@
#include "config/platform.h"
#include "config/power_calibration.h"
#include "config/radio_link.h"
#include "config/secure_transport.h"
#include "config/sntp_client.h"
#include "config/srp_client.h"
#include "config/srp_server.h"
+544
View File
@@ -0,0 +1,544 @@
/*
* Copyright (c) 2023, 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.
*/
#include "ble_secure.hpp"
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#include <openthread/platform/ble.h>
#include "common/locator_getters.hpp"
#include "common/log.hpp"
#include "common/tlvs.hpp"
#include "instance/instance.hpp"
#include "meshcop/secure_transport.hpp"
using namespace ot;
/**
* @file
* This file implements the secure Ble agent.
*/
namespace ot {
namespace Ble {
RegisterLogModule("BleSecure");
BleSecure::BleSecure(Instance &aInstance)
: InstanceLocator(aInstance)
, mTls(aInstance, false, false)
, mTcatAgent(aInstance)
, mTlvMode(false)
, mReceivedMessage(nullptr)
, mSendMessage(nullptr)
, mTransmitTask(aInstance)
, mBleState(kStopped)
, mMtuSize(kInitialMtuSize)
{
}
Error BleSecure::Start(ConnectCallback aConnectHandler, ReceiveCallback aReceiveHandler, bool aTlvMode, void *aContext)
{
Error error = kErrorNone;
VerifyOrExit(mBleState == kStopped, error = kErrorAlready);
mConnectCallback.Set(aConnectHandler, aContext);
mReceiveCallback.Set(aReceiveHandler, aContext);
mTlvMode = aTlvMode;
mMtuSize = kInitialMtuSize;
SuccessOrExit(error = otPlatBleEnable(&GetInstance()));
SuccessOrExit(error = otPlatBleGapAdvStart(&GetInstance(), OT_BLE_ADV_INTERVAL_DEFAULT));
SuccessOrExit(error = mTls.Open(&BleSecure::HandleTlsReceive, &BleSecure::HandleTlsConnected, this));
SuccessOrExit(error = mTls.Bind(HandleTransport, this));
exit:
if (error == kErrorNone)
{
mBleState = kAdvertising;
}
return error;
}
Error BleSecure::TcatStart(const MeshCoP::TcatAgent::VendorInfo &aVendorInfo,
MeshCoP::TcatAgent::JoinCallback aJoinHandler)
{
return mTcatAgent.Start(aVendorInfo, mReceiveCallback.GetHandler(), aJoinHandler, mReceiveCallback.GetContext());
}
void BleSecure::Stop(void)
{
VerifyOrExit(mBleState != kStopped);
SuccessOrExit(otPlatBleGapAdvStop(&GetInstance()));
SuccessOrExit(otPlatBleDisable(&GetInstance()));
mBleState = kStopped;
mMtuSize = kInitialMtuSize;
if (mTcatAgent.IsEnabled())
{
mTcatAgent.Stop();
}
mTls.Close();
mTransmitQueue.DequeueAndFreeAll();
mConnectCallback.Clear();
mReceiveCallback.Clear();
FreeMessage(mReceivedMessage);
mReceivedMessage = nullptr;
FreeMessage(mSendMessage);
mSendMessage = nullptr;
exit:
return;
}
Error BleSecure::Connect(void)
{
Ip6::SockAddr sockaddr;
return mTls.Connect(sockaddr);
}
void BleSecure::Disconnect(void)
{
if (mTls.IsConnected())
{
mTls.Disconnect();
}
if (mBleState == kConnected)
{
IgnoreReturnValue(otPlatBleGapDisconnect(&GetInstance()));
}
}
void BleSecure::SetPsk(const MeshCoP::JoinerPskd &aPskd)
{
static_assert(static_cast<uint16_t>(MeshCoP::JoinerPskd::kMaxLength) <=
static_cast<uint16_t>(MeshCoP::SecureTransport::kPskMaxLength),
"The maximum length of TLS PSK is smaller than joiner PSKd");
SuccessOrAssert(mTls.SetPsk(reinterpret_cast<const uint8_t *>(aPskd.GetAsCString()), aPskd.GetLength()));
}
#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
Error BleSecure::GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength)
{
Error error;
VerifyOrExit(aCertLength != nullptr, error = kErrorInvalidArgs);
error = mTls.GetPeerCertificateBase64(aPeerCert, aCertLength, *aCertLength);
exit:
return error;
}
#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
Error BleSecure::SendMessage(ot::Message &aMessage)
{
Error error = kErrorNone;
VerifyOrExit(IsConnected(), error = kErrorInvalidState);
if (mSendMessage == nullptr)
{
mSendMessage = Get<MessagePool>().Allocate(Message::kTypeBle);
VerifyOrExit(mSendMessage != nullptr, error = kErrorNoBufs);
}
SuccessOrExit(error = mSendMessage->AppendBytesFromMessage(aMessage, 0, aMessage.GetLength()));
SuccessOrExit(error = Flush());
exit:
aMessage.Free();
return error;
}
Error BleSecure::Send(uint8_t *aBuf, uint16_t aLength)
{
Error error = kErrorNone;
VerifyOrExit(IsConnected(), error = kErrorInvalidState);
if (mSendMessage == nullptr)
{
mSendMessage = Get<MessagePool>().Allocate(Message::kTypeBle);
VerifyOrExit(mSendMessage != nullptr, error = kErrorNoBufs);
}
SuccessOrExit(error = mSendMessage->AppendBytes(aBuf, aLength));
exit:
return error;
}
Error BleSecure::SendApplicationTlv(uint8_t *aBuf, uint16_t aLength)
{
Error error = kErrorNone;
if (aLength > Tlv::kBaseTlvMaxLength)
{
ot::ExtendedTlv tlv;
tlv.SetType(ot::MeshCoP::TcatAgent::kTlvSendApplicationData);
tlv.SetLength(aLength);
SuccessOrExit(error = Send(reinterpret_cast<uint8_t *>(&tlv), sizeof(tlv)));
}
else
{
ot::Tlv tlv;
tlv.SetType(ot::MeshCoP::TcatAgent::kTlvSendApplicationData);
tlv.SetLength((uint8_t)aLength);
SuccessOrExit(error = Send(reinterpret_cast<uint8_t *>(&tlv), sizeof(tlv)));
}
error = Send(aBuf, aLength);
exit:
return error;
}
Error BleSecure::Flush(void)
{
Error error = kErrorNone;
VerifyOrExit(IsConnected(), error = kErrorInvalidState);
VerifyOrExit(mSendMessage->GetLength() != 0, error = kErrorNone);
mTransmitQueue.Enqueue(*mSendMessage);
mTransmitTask.Post();
mSendMessage = nullptr;
exit:
return error;
}
Error BleSecure::HandleBleReceive(uint8_t *aBuf, uint16_t aLength)
{
ot::Message *message = nullptr;
Ip6::MessageInfo messageInfo;
Error error = kErrorNone;
if ((message = Get<MessagePool>().Allocate(Message::kTypeBle, 0)) == nullptr)
{
error = kErrorNoBufs;
ExitNow();
}
SuccessOrExit(error = message->AppendBytes(aBuf, aLength));
// Cannot call Receive(..) directly because Setup(..) and mState are private
mTls.HandleUdpReceive(*message, messageInfo);
exit:
FreeMessage(message);
return error;
}
void BleSecure::HandleBleConnected(uint16_t aConnectionId)
{
OT_UNUSED_VARIABLE(aConnectionId);
mBleState = kConnected;
IgnoreReturnValue(otPlatBleGattMtuGet(&GetInstance(), &mMtuSize));
mConnectCallback.InvokeIfSet(&GetInstance(), IsConnected(), true);
}
void BleSecure::HandleBleDisconnected(uint16_t aConnectionId)
{
OT_UNUSED_VARIABLE(aConnectionId);
mBleState = kAdvertising;
mMtuSize = kInitialMtuSize;
if (IsConnected())
{
Disconnect(); // Stop TLS connection
}
mConnectCallback.InvokeIfSet(&GetInstance(), false, false);
}
Error BleSecure::HandleBleMtuUpdate(uint16_t aMtu)
{
Error error = kErrorNone;
if (aMtu <= OT_BLE_ATT_MTU_MAX)
{
mMtuSize = aMtu;
}
else
{
mMtuSize = OT_BLE_ATT_MTU_MAX;
error = kErrorInvalidArgs;
}
return error;
}
void BleSecure::HandleTlsConnected(void *aContext, bool aConnected)
{
return static_cast<BleSecure *>(aContext)->HandleTlsConnected(aConnected);
}
void BleSecure::HandleTlsConnected(bool aConnected)
{
if (aConnected)
{
if (mReceivedMessage == nullptr)
{
mReceivedMessage = Get<MessagePool>().Allocate(Message::kTypeBle);
}
if (mTcatAgent.IsEnabled())
{
IgnoreReturnValue(mTcatAgent.Connected(mTls));
}
}
else
{
FreeMessage(mReceivedMessage);
mReceivedMessage = nullptr;
if (mTcatAgent.IsEnabled())
{
mTcatAgent.Disconnected();
}
}
mConnectCallback.InvokeIfSet(&GetInstance(), aConnected, true);
}
void BleSecure::HandleTlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
{
return static_cast<BleSecure *>(aContext)->HandleTlsReceive(aBuf, aLength);
}
void BleSecure::HandleTlsReceive(uint8_t *aBuf, uint16_t aLength)
{
VerifyOrExit(mReceivedMessage != nullptr);
if (!mTlvMode)
{
SuccessOrExit(mReceivedMessage->AppendBytes(aBuf, aLength));
mReceiveCallback.InvokeIfSet(&GetInstance(), mReceivedMessage, 0, OT_TCAT_APPLICATION_PROTOCOL_NONE, "");
IgnoreReturnValue(mReceivedMessage->SetLength(0));
}
else
{
ot::Tlv tlv;
uint32_t requiredBytes = sizeof(Tlv);
uint32_t offset;
while (aLength > 0)
{
if (mReceivedMessage->GetLength() < requiredBytes)
{
uint32_t missingBytes = requiredBytes - mReceivedMessage->GetLength();
if (missingBytes > aLength)
{
SuccessOrExit(mReceivedMessage->AppendBytes(aBuf, aLength));
break;
}
else
{
SuccessOrExit(mReceivedMessage->AppendBytes(aBuf, (uint16_t)missingBytes));
aLength -= missingBytes;
aBuf += missingBytes;
}
}
IgnoreReturnValue(mReceivedMessage->Read(0, tlv));
if (tlv.IsExtended())
{
ot::ExtendedTlv extTlv;
requiredBytes = sizeof(extTlv);
if (mReceivedMessage->GetLength() < requiredBytes)
{
continue;
}
IgnoreReturnValue(mReceivedMessage->Read(0, extTlv));
requiredBytes = extTlv.GetSize();
offset = sizeof(extTlv);
}
else
{
requiredBytes = tlv.GetSize();
offset = sizeof(tlv);
}
if (mReceivedMessage->GetLength() < requiredBytes)
{
continue;
}
// TLV fully loaded
if (mTcatAgent.IsEnabled())
{
ot::Message *message;
Error error = kErrorNone;
message = Get<MessagePool>().Allocate(Message::kTypeBle);
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
error = mTcatAgent.HandleSingleTlv(*mReceivedMessage, *message);
if (message->GetLength() != 0)
{
IgnoreReturnValue(SendMessage(*message));
}
if (error == kErrorAbort)
{
Disconnect();
Stop();
ExitNow();
}
}
else
{
mReceivedMessage->SetOffset((uint16_t)offset);
mReceiveCallback.InvokeIfSet(&GetInstance(), mReceivedMessage, (int32_t)offset,
OT_TCAT_APPLICATION_PROTOCOL_NONE, "");
}
SuccessOrExit(mReceivedMessage->SetLength(0)); // also sets the offset to 0
requiredBytes = sizeof(Tlv);
}
}
exit:
return;
}
void BleSecure::HandleTransmit(void)
{
Error error = kErrorNone;
ot::Message *message = mTransmitQueue.GetHead();
VerifyOrExit(message != nullptr);
mTransmitQueue.Dequeue(*message);
if (mTransmitQueue.GetHead() != nullptr)
{
mTransmitTask.Post();
}
SuccessOrExit(error = mTls.Send(*message, message->GetLength()));
exit:
if (error != kErrorNone)
{
LogNote("Transmit: %s", ErrorToString(error));
message->Free();
}
else
{
LogDebg("Transmit: %s", ErrorToString(error));
}
}
Error BleSecure::HandleTransport(void *aContext, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
OT_UNUSED_VARIABLE(aMessageInfo);
return static_cast<BleSecure *>(aContext)->HandleTransport(aMessage);
}
Error BleSecure::HandleTransport(ot::Message &aMessage)
{
otBleRadioPacket packet;
uint16_t len = aMessage.GetLength();
uint16_t offset = 0;
Error error = kErrorNone;
while (len > 0)
{
if (len <= mMtuSize - kGattOverhead)
{
packet.mLength = len;
}
else
{
packet.mLength = mMtuSize - kGattOverhead;
}
if (packet.mLength > kPacketBufferSize)
{
packet.mLength = kPacketBufferSize;
}
IgnoreReturnValue(aMessage.Read(offset, mPacketBuffer, packet.mLength));
packet.mValue = mPacketBuffer;
packet.mPower = OT_BLE_DEFAULT_POWER;
SuccessOrExit(error = otPlatBleGattServerIndicate(&GetInstance(), kTxBleHandle, &packet));
len -= packet.mLength;
offset += packet.mLength;
}
aMessage.Free();
exit:
return error;
}
} // namespace Ble
} // namespace ot
void otPlatBleGattServerOnWriteRequest(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket)
{
OT_UNUSED_VARIABLE(aHandle); // Only a single handle is expected for RX
VerifyOrExit(aPacket != nullptr);
IgnoreReturnValue(AsCoreType(aInstance).Get<Ble::BleSecure>().HandleBleReceive(aPacket->mValue, aPacket->mLength));
exit:
return;
}
void otPlatBleGapOnConnected(otInstance *aInstance, uint16_t aConnectionId)
{
AsCoreType(aInstance).Get<Ble::BleSecure>().HandleBleConnected(aConnectionId);
}
void otPlatBleGapOnDisconnected(otInstance *aInstance, uint16_t aConnectionId)
{
AsCoreType(aInstance).Get<Ble::BleSecure>().HandleBleDisconnected(aConnectionId);
}
void otPlatBleGattOnMtuUpdate(otInstance *aInstance, uint16_t aMtu)
{
IgnoreReturnValue(AsCoreType(aInstance).Get<Ble::BleSecure>().HandleBleMtuUpdate(aMtu));
}
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
+489
View File
@@ -0,0 +1,489 @@
/*
* Copyright (c) 2023, 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.
*/
#ifndef BLE_SECURE_HPP_
#define BLE_SECURE_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#include <openthread/ble_secure.h>
#include "meshcop/meshcop.hpp"
#include "meshcop/secure_transport.hpp"
#include "meshcop/tcat_agent.hpp"
/**
* @file
* Includes definitions for the secure BLE agent.
*/
namespace ot {
namespace Ble {
class BleSecure : public InstanceLocator, private NonCopyable
{
public:
/**
* Pointer to call when the secure BLE connection state changes.
*
* Please see otHandleBleSecureConnect for details.
*
*/
typedef otHandleBleSecureConnect ConnectCallback;
/**
* Pointer to call when data was received over the TLS connection.
* If line mode is activated the function is called only after EOL has been received.
*
* Please see otHandleBleSecureReceive for details.
*
*/
typedef otHandleBleSecureReceive ReceiveCallback;
/**
* Represents a TCAT command class.
*
*/
typedef MeshCoP::TcatAgent::CommandClass CommandClass;
/**
* Constructor initializes the object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit BleSecure(Instance &aInstance);
/**
* Starts the secure BLE agent.
*
* @param[in] aConnectHandler A pointer to a function that will be called when the connection
* state changes.
* @param[in] aReceiveHandler A pointer to a function that will be called once data has been received
* over the TLS connection.
* @param[in] aTlvMode A boolean value indicating if line mode shall be activated.
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
*
* @retval kErrorNone Successfully started the BLE agent.
* @retval kErrorAlready Already started.
*
*/
Error Start(ConnectCallback aConnectHandler, ReceiveCallback aReceiveHandler, bool aTlvMode, void *aContext);
/**
* Enables the TCAT protocol over BLE Secure.
*
* @param[in] aVendorInfo A reference to the Vendor Information (must remain valid after the method call)
* @param[in] aHandler Callback to a function that is called when the join operation completes.
*
* @retval kErrorNone Successfully started the BLE Secure Joiner role.
* @retval kErrorInvalidArgs The aVendorInfo is invalid.
* @retval kErrorInvaidState The BLE function has not been started or line mode is not selected.
*
*/
Error TcatStart(const MeshCoP::TcatAgent::VendorInfo &aVendorInfo, MeshCoP::TcatAgent::JoinCallback aHandler);
/**
* Stops the secure BLE agent.
*
*/
void Stop(void);
/**
* Initializes TLS session with a peer using an already open BLE connection.
*
* @retval kErrorNone Successfully started TLS connection.
*
*/
Error Connect(void);
/**
* Stops the BLE and TLS connection.
*
*/
void Disconnect(void);
/**
* Indicates whether or not the TLS session is active (connected or conneting).
*
* @retval TRUE If TLS session is active.
* @retval FALSE If TLS session is not active.
*
*/
bool IsConnectionActive(void) const { return mTls.IsConnectionActive(); }
/**
* Indicates whether or not the TLS session is connected.
*
* @retval TRUE The TLS session is connected.
* @retval FALSE The TLS session is not connected.
*
*/
bool IsConnected(void) const { return mTls.IsConnected(); }
/**
* Indicates whether or not the TCAT agent is enabled.
*
* @retval TRUE The TCAT agent is enabled.
* @retval FALSE The TCAT agent is not enabled.
*
*/
bool IsTcatEnabled(void) const { return mTcatAgent.IsEnabled(); }
/**
* Indicates whether or not a TCAT command class is authorized.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aCommandClass A command class to check.
*
* @retval TRUE The command class is authorized.
* @retval FALSE The command class is not authorized.
*
*/
bool IsCommandClassAuthorized(CommandClass aCommandClass) const
{
return mTcatAgent.IsCommandClassAuthorized(aCommandClass);
}
/**
* Sets the PSK.
*
* @param[in] aPsk A pointer to the PSK.
* @param[in] aPskLength The PSK length.
*
* @retval kErrorNone Successfully set the PSK.
* @retval kErrorInvalidArgs The PSK is invalid.
*
*/
Error SetPsk(const uint8_t *aPsk, uint8_t aPskLength) { return mTls.SetPsk(aPsk, aPskLength); }
/**
* Sets the PSK.
*
* @param[in] aPskd A Joiner PSKd.
*
*/
void SetPsk(const MeshCoP::JoinerPskd &aPskd);
#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
/**
* Sets the Pre-Shared Key (PSK) for TLS sessions identified by a PSK.
*
* TLS mode "TLS with AES 128 CCM 8" for secure BLE.
*
* @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.
*
*/
void SetPreSharedKey(const uint8_t *aPsk, uint16_t aPskLength, const uint8_t *aPskIdentity, uint16_t aPskIdLength)
{
mTls.SetPreSharedKey(aPsk, aPskLength, aPskIdentity, aPskIdLength);
}
#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
/**
* Sets a X509 certificate with corresponding private key for TLS session.
*
* TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE.
*
* @param[in] aX509Cert A pointer to the PEM formatted X509 PEM 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.
*
*/
void SetCertificate(const uint8_t *aX509Cert,
uint32_t aX509Length,
const uint8_t *aPrivateKey,
uint32_t aPrivateKeyLength)
{
mTls.SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength);
}
/**
* Sets the trusted top level CAs. It is needed for validate the certificate of the peer.
*
* TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE.
*
* @param[in] aX509CaCertificateChain A pointer to the PEM formatted X509 CA chain.
* @param[in] aX509CaCertChainLength The length of chain.
*
*/
void SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength)
{
mTls.SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLength);
}
#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/**
* Returns the peer x509 certificate base64 encoded.
*
* TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE.
*
* @param[out] aPeerCert A pointer to the base64 encoded certificate buffer.
* @param[out] aCertLength On input, the size the max size of @p aPeerCert.
* On output, the length of the base64 encoded peer certificate.
*
* @retval kErrorNone Successfully get the peer certificate.
* @retval kErrorInvalidArgs @p aInstance or @p aCertLength is invalid.
* @retval kErrorInvalidState Not connected yet.
* @retval kErrorNoBufs Can't allocate memory for certificate.
*
*/
Error GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength);
#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/**
* Returns an attribute value identified by its OID from the subject
* of the peer x509 certificate. The peer OID is provided in binary format.
* The attribute length is set if the attribute was successfully read or zero
* if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard
* if the attribute was successfully read.
*
* @param[in] aOid A pointer to the OID to be found.
* @param[in] aOidLength The length of the OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
* @param[out] aAsn1Type A pointer to the ASN.1 type of the attribute written to the buffer.
*
* @retval kErrorInvalidState Not connected yet.
* @retval kErrorNone Successfully read attribute.
* @retval kErrorNoBufs Insufficient memory for storing the attribute value.
*
*/
Error GetPeerSubjectAttributeByOid(const char *aOid,
size_t aOidLength,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength,
int *aAsn1Type)
{
return mTls.GetPeerSubjectAttributeByOid(aOid, aOidLength, aAttributeBuffer, aAttributeLength, aAsn1Type);
}
/**
* Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of
* the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor.
* The attribute length is set if the attribute was successfully read or zero if unsuccessful.
* Requires a connection to be active.
*
* @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
*
* @retval kErrorNone Successfully read attribute.
* @retval kErrorNotFound The requested attribute was not found.
* @retval kErrorNoBufs Insufficient memory for storing the attribute value.
* @retval kErrorInvalidState Not connected yet.
* @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127.
* @retval kErrorParse The certificate extensions could not be parsed.
*
*/
Error GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength)
{
return mTls.GetThreadAttributeFromPeerCertificate(aThreadOidDescriptor, aAttributeBuffer, aAttributeLength);
}
#endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/**
* Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of
* the own x509 certificate, where the last digit x is set to aThreadOidDescriptor.
* The attribute length is set if the attribute was successfully read or zero if unsuccessful.
* Requires a connection to be active.
*
* @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID.
* @param[out] aAttributeBuffer A pointer to the attribute buffer.
* @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer.
* On output, the length of the attribute written to the buffer.
*
* @retval kErrorNone Successfully read attribute.
* @retval kErrorNotFound The requested attribute was not found.
* @retval kErrorNoBufs Insufficient memory for storing the attribute value.
* @retval kErrorInvalidState Not connected yet.
* @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127.
* @retval kErrorParse The certificate extensions could not be parsed.
*
*/
Error GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor,
uint8_t *aAttributeBuffer,
size_t *aAttributeLength)
{
return mTls.GetThreadAttributeFromOwnCertificate(aThreadOidDescriptor, aAttributeBuffer, aAttributeLength);
}
/**
* Sets the authentication mode for the BLE secure connection. It disables or enables the verification
* of peer certificate.
*
* @param[in] aVerifyPeerCertificate true, if the peer certificate should be verified
*
*/
void SetSslAuthMode(bool aVerifyPeerCertificate) { mTls.SetSslAuthMode(aVerifyPeerCertificate); }
/**
* Sends a secure BLE message.
*
* @param[in] aMessage A pointer to the message to send.
*
* If the return value is kErrorNone, OpenThread takes ownership of @p aMessage, and the caller should no longer
* reference @p aMessage. If the return value is not kErrorNone, the caller retains ownership of @p aMessage,
* including freeing @p aMessage if the message buffer is no longer needed.
*
* @retval kErrorNone Successfully sent message.
* @retval kErrorNoBufs Failed to allocate buffer memory.
* @retval kErrorInvalidState TLS connection was not initialized.
*
*/
Error SendMessage(Message &aMessage);
/**
* Sends a secure BLE data packet.
*
* @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV.
* @param[in] aLength A number indicating the length of the data buffer.
*
* @retval kErrorNone Successfully sent data.
* @retval kErrorNoBufs Failed to allocate buffer memory.
* @retval kErrorInvalidState TLS connection was not initialized.
*
*/
Error Send(uint8_t *aBuf, uint16_t aLength);
/**
* Sends a secure BLE data packet containing a TCAT Send Application Data TLV.
*
* @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV.
* @param[in] aLength A number indicating the length of the data buffer.
*
* @retval kErrorNone Successfully sent data.
* @retval kErrorNoBufs Failed to allocate buffer memory.
* @retval kErrorInvalidState TLS connection was not initialized.
*
*/
Error SendApplicationTlv(uint8_t *aBuf, uint16_t aLength);
/**
* Sends all remaining bytes in the send buffer.
*
* @retval kErrorNone Successfully enqueued data into the output interface.
* @retval kErrorNoBufs Failed to allocate buffer memory.
* @retval kErrorInvalidState TLS connection was not initialized.
*
*/
Error Flush(void);
/**
* Used to pass data received over a BLE link to the secure BLE server.
*
* @param[in] aBuf A pointer to the data received.
* @param[in] aLength A number indicating the length of the data buffer.
*
*/
Error HandleBleReceive(uint8_t *aBuf, uint16_t aLength);
/**
* Used to notify the secure BLE server that a BLE Device has been connected.
*
* @param[in] aConnectionId The identifier of the open connection.
*
*/
void HandleBleConnected(uint16_t aConnectionId);
/**
* Used to notify the secure BLE server that the BLE Device has been disconnected.
*
* @param[in] aConnectionId The identifier of the open connection.
*
*/
void HandleBleDisconnected(uint16_t aConnectionId);
/**
* Used to notify the secure BLE server that the BLE Device has updated ATT_MTU size.
*
* @param[in] aMtu The updated ATT_MTU value.
*
*/
Error HandleBleMtuUpdate(uint16_t aMtu);
private:
enum BleState : uint8_t
{
kStopped = 0, // Ble secure not started.
kAdvertising = 1, // Ble secure not advertising.
kConnected = 2, // Ble secure not connected.
};
static constexpr uint8_t kInitialMtuSize = 23; // ATT_MTU
static constexpr uint8_t kGattOverhead = 3; // BLE GATT payload fits MTU size - 3 bytes
static constexpr uint8_t kPacketBufferSize = OT_BLE_ATT_MTU_MAX - kGattOverhead;
static constexpr uint16_t kTxBleHandle = 0; // Characteristics Handle for TX (not used)
static void HandleTlsConnected(void *aContext, bool aConnected);
void HandleTlsConnected(bool aConnected);
static void HandleTlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength);
void HandleTlsReceive(uint8_t *aBuf, uint16_t aLength);
void HandleTransmit(void);
static Error HandleTransport(void *aContext, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
Error HandleTransport(ot::Message &aMessage);
using TxTask = TaskletIn<BleSecure, &BleSecure::HandleTransmit>;
MeshCoP::SecureTransport mTls;
MeshCoP::TcatAgent mTcatAgent;
Callback<ConnectCallback> mConnectCallback;
Callback<ReceiveCallback> mReceiveCallback;
bool mTlvMode;
ot::Message *mReceivedMessage;
ot::Message *mSendMessage;
ot::MessageQueue mTransmitQueue;
TxTask mTransmitTask;
uint8_t mPacketBuffer[kPacketBufferSize];
BleState mBleState;
uint16_t mMtuSize;
};
} // namespace Ble
} // namespace ot
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#endif // BLE_SECURE_HPP_
+1 -1
View File
@@ -97,7 +97,7 @@ void ThreadNetif::Down(void)
#if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
Get<Dns::ServiceDiscovery::Server>().Stop();
#endif
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
Get<Tmf::SecureAgent>().Stop();
#endif
IgnoreError(Get<Tmf::Agent>().Stop());
+2 -2
View File
@@ -271,7 +271,7 @@ Message::Priority Agent::DscpToPriority(uint8_t aDscp)
return priority;
}
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
SecureAgent::SecureAgent(Instance &aInstance)
: Coap::CoapSecure(aInstance)
@@ -329,7 +329,7 @@ bool SecureAgent::HandleResource(const char *aUriPath, Message &aMessage, const
return didHandle;
}
#endif // OPENTHREAD_CONFIG_DTLS_ENABLE
#endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
} // namespace Tmf
} // namespace ot
+1 -1
View File
@@ -214,7 +214,7 @@ private:
static Error Filter(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, void *aContext);
};
#if OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
/**
* Implements functionality of the secure TMF agent.
+1 -1
View File
@@ -227,7 +227,7 @@ public:
size_t GetFreeSize(void) const { return mMemory.mFreeSize; }
private:
#if OPENTHREAD_CONFIG_TLS_ENABLE || OPENTHREAD_CONFIG_DTLS_ENABLE
#if OPENTHREAD_CONFIG_TLS_ENABLE || OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
static constexpr uint16_t kMemorySize = OPENTHREAD_CONFIG_HEAP_INTERNAL_SIZE;
#else
static constexpr uint16_t kMemorySize = OPENTHREAD_CONFIG_HEAP_INTERNAL_SIZE_NO_DTLS;
+1
View File
@@ -125,6 +125,7 @@ endif()
add_library(openthread-posix
alarm.cpp
backtrace.cpp
ble.cpp
configuration.cpp
config_file.cpp
daemon.cpp
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2023, 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.
*/
#include <openthread/platform/ble.h>
otError otPlatBleEnable(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleDisable(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aInterval);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapAdvStop(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapDisconnect(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aMtu);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aHandle);
OT_UNUSED_VARIABLE(aPacket);
return OT_ERROR_NOT_IMPLEMENTED;
}
+50
View File
@@ -35,6 +35,9 @@
#include <stdio.h>
#include <sys/time.h>
#ifdef OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#include <openthread/platform/ble.h>
#endif
enum
{
@@ -681,5 +684,52 @@ OT_TOOL_WEAK otPlatMcuPowerState otPlatGetMcuPowerState(otInstance *aInstance) {
OT_TOOL_WEAK otError otPlatSetMcuPowerState(otInstance *aInstance, otPlatMcuPowerState aState) { return OT_ERROR_NONE; }
#endif // OPENTHREAD_CONFIG_NCP_ENABLE_MCU_POWER_STATE_CONTROL
#ifdef OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
otError otPlatBleEnable(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleDisable(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapAdvStart(otInstance *aInstance, uint16_t aInterval)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aInterval);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapAdvStop(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGapDisconnect(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGattMtuGet(otInstance *aInstance, uint16_t *aMtu)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aMtu);
return OT_ERROR_NOT_IMPLEMENTED;
}
otError otPlatBleGattServerIndicate(otInstance *aInstance, uint16_t aHandle, const otBleRadioPacket *aPacket)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aHandle);
OT_UNUSED_VARIABLE(aPacket);
return OT_ERROR_NOT_IMPLEMENTED;
}
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
} // extern "C"
+4
View File
@@ -92,6 +92,10 @@
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#endif
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
#endif
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_BASE64_C
#define MBEDTLS_ECDH_C