Skip to content

Commit

Permalink
[tcat] Implement extraction of active dataset and commissioner cert.
Browse files Browse the repository at this point in the history
Commit adds implementation of:
	- 0x40 Tcat tlv extraction of active dataset,
	- 0x25 Tcat tlv extraction of commissioner certificate.

Includes also refactoring of `BleCommand` adds new method `process_response`.
This simplifies:
- `GetPskdHash`
- `GetRandomNumberChallenge`
  • Loading branch information
Przemyslaw Bida committed Dec 9, 2024
1 parent 7accae0 commit 0e71f3c
Show file tree
Hide file tree
Showing 17 changed files with 391 additions and 170 deletions.
20 changes: 20 additions & 0 deletions include/openthread/ble_secure.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,26 @@ void otBleSecureSetPsk(otInstance *aInstance,
*/
otError otBleSecureGetPeerCertificateBase64(otInstance *aInstance, unsigned char *aPeerCert, size_t *aCertLength);

/**
* Returns the peer x509 certificate base64 encoded.
*
* @note Requires the build-time feature `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` to
* be enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[out] aPeerCert A pointer to the DER encoded certificate
* buffer.
* @param[in,out] aCertLength On input, the size the max size of @p
* aPeerCert. On output, the length of the DER 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 otBleSecureGetPeerCertificateRaw(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.
Expand Down
2 changes: 1 addition & 1 deletion include/openthread/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (465)
#define OPENTHREAD_API_VERSION (466)

/**
* @addtogroup api-instance
Expand Down
27 changes: 14 additions & 13 deletions include/openthread/platform/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,20 @@ extern "C" {
*/
enum
{
OT_SETTINGS_KEY_ACTIVE_DATASET = 0x0001, ///< Active Operational Dataset.
OT_SETTINGS_KEY_PENDING_DATASET = 0x0002, ///< Pending Operational Dataset.
OT_SETTINGS_KEY_NETWORK_INFO = 0x0003, ///< Thread network information.
OT_SETTINGS_KEY_PARENT_INFO = 0x0004, ///< Parent information.
OT_SETTINGS_KEY_CHILD_INFO = 0x0005, ///< Child information.
OT_SETTINGS_KEY_SLAAC_IID_SECRET_KEY = 0x0007, ///< SLAAC key to generate semantically opaque IID.
OT_SETTINGS_KEY_DAD_INFO = 0x0008, ///< Duplicate Address Detection (DAD) information.
OT_SETTINGS_KEY_SRP_ECDSA_KEY = 0x000b, ///< SRP client ECDSA public/private key pair.
OT_SETTINGS_KEY_SRP_CLIENT_INFO = 0x000c, ///< The SRP client info (selected SRP server address).
OT_SETTINGS_KEY_SRP_SERVER_INFO = 0x000d, ///< The SRP server info (UDP port).
OT_SETTINGS_KEY_BR_ULA_PREFIX = 0x000f, ///< BR ULA prefix.
OT_SETTINGS_KEY_BR_ON_LINK_PREFIXES = 0x0010, ///< BR local on-link prefixes.
OT_SETTINGS_KEY_BORDER_AGENT_ID = 0x0011, ///< Unique Border Agent/Router ID.
OT_SETTINGS_KEY_ACTIVE_DATASET = 0x0001, ///< Active Operational Dataset.
OT_SETTINGS_KEY_PENDING_DATASET = 0x0002, ///< Pending Operational Dataset.
OT_SETTINGS_KEY_NETWORK_INFO = 0x0003, ///< Thread network information.
OT_SETTINGS_KEY_PARENT_INFO = 0x0004, ///< Parent information.
OT_SETTINGS_KEY_CHILD_INFO = 0x0005, ///< Child information.
OT_SETTINGS_KEY_SLAAC_IID_SECRET_KEY = 0x0007, ///< SLAAC key to generate semantically opaque IID.
OT_SETTINGS_KEY_DAD_INFO = 0x0008, ///< Duplicate Address Detection (DAD) information.
OT_SETTINGS_KEY_SRP_ECDSA_KEY = 0x000b, ///< SRP client ECDSA public/private key pair.
OT_SETTINGS_KEY_SRP_CLIENT_INFO = 0x000c, ///< The SRP client info (selected SRP server address).
OT_SETTINGS_KEY_SRP_SERVER_INFO = 0x000d, ///< The SRP server info (UDP port).
OT_SETTINGS_KEY_BR_ULA_PREFIX = 0x000f, ///< BR ULA prefix.
OT_SETTINGS_KEY_BR_ON_LINK_PREFIXES = 0x0010, ///< BR local on-link prefixes.
OT_SETTINGS_KEY_BORDER_AGENT_ID = 0x0011, ///< Unique Border Agent/Router ID.
OT_SETTINGS_KEY_TCAT_COMMISSIONER_CERTIFICATE = 0x0012, ///< Unique TCAT Commissioner certificate.

// Deprecated and reserved key values:
//
Expand Down
5 changes: 5 additions & 0 deletions src/core/api/ble_secure_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ otError otBleSecureGetPeerCertificateBase64(otInstance *aInstance, unsigned char
#endif

#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
otError otBleSecureGetPeerCertificateRaw(otInstance *aInstance, unsigned char *aPeerCert, size_t *aCertLength)
{
return AsCoreType(aInstance).Get<Ble::BleSecure>().GetPeerCertificateRaw(aPeerCert, aCertLength, *aCertLength);
}

otError otBleSecureGetPeerSubjectAttributeByOid(otInstance *aInstance,
const char *aOid,
size_t aOidLength,
Expand Down
53 changes: 34 additions & 19 deletions src/core/common/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

#include "settings.hpp"

#include "common/code_utils.hpp"
#include "common/error.hpp"
#include "instance/instance.hpp"

namespace ot {
Expand Down Expand Up @@ -151,24 +153,25 @@ const char *SettingsBase::ActionToString(Action aAction)
const char *SettingsBase::KeyToString(Key aKey)
{
static const char *const kKeyStrings[] = {
"", // (0) (Unused)
"ActiveDataset", // (1) kKeyActiveDataset
"PendingDataset", // (2) kKeyPendingDataset
"NetworkInfo", // (3) kKeyNetworkInfo
"ParentInfo", // (4) kKeyParentInfo
"ChildInfo", // (5) kKeyChildInfo
"", // (6) Removed (previously auto-start).
"SlaacIidSecretKey", // (7) kKeySlaacIidSecretKey
"DadInfo", // (8) kKeyDadInfo
"", // (9) Removed (previously OMR prefix).
"", // (10) Removed (previously on-link prefix).
"SrpEcdsaKey", // (11) kKeySrpEcdsaKey
"SrpClientInfo", // (12) kKeySrpClientInfo
"SrpServerInfo", // (13) kKeySrpServerInfo
"", // (14) Removed (previously NAT64 prefix)
"BrUlaPrefix", // (15) kKeyBrUlaPrefix
"BrOnLinkPrefixes", // (16) kKeyBrOnLinkPrefixes
"BorderAgentId" // (17) kKeyBorderAgentId
"", // (0) (Unused)
"ActiveDataset", // (1) kKeyActiveDataset
"PendingDataset", // (2) kKeyPendingDataset
"NetworkInfo", // (3) kKeyNetworkInfo
"ParentInfo", // (4) kKeyParentInfo
"ChildInfo", // (5) kKeyChildInfo
"", // (6) Removed (previously auto-start).
"SlaacIidSecretKey", // (7) kKeySlaacIidSecretKey
"DadInfo", // (8) kKeyDadInfo
"", // (9) Removed (previously OMR prefix).
"", // (10) Removed (previously on-link prefix).
"SrpEcdsaKey", // (11) kKeySrpEcdsaKey
"SrpClientInfo", // (12) kKeySrpClientInfo
"SrpServerInfo", // (13) kKeySrpServerInfo
"", // (14) Removed (previously NAT64 prefix)
"BrUlaPrefix", // (15) kKeyBrUlaPrefix
"BrOnLinkPrefixes", // (16) kKeyBrOnLinkPrefixes
"BorderAgentId", // (17) kKeyBorderAgentId
"TcatCommissionerCertificate" // (18) kKeyTcatCommissionerCertificate
};

struct EnumCheck
Expand All @@ -192,9 +195,10 @@ const char *SettingsBase::KeyToString(Key aKey)
ValidateNextEnum(kKeyBrUlaPrefix);
ValidateNextEnum(kKeyBrOnLinkPrefixes);
ValidateNextEnum(kKeyBorderAgentId);
ValidateNextEnum(kKeyTcatCommissionerCertificate);
};

static_assert(kLastKey == kKeyBorderAgentId, "kLastKey is not valid");
static_assert(kLastKey == kKeyTcatCommissionerCertificate, "kLastKey is not valid");

OT_ASSERT(aKey <= kLastKey);

Expand Down Expand Up @@ -263,6 +267,17 @@ void Settings::DeleteOperationalDataset(MeshCoP::Dataset::Type aType)
OT_ASSERT(error != kErrorNotImplemented);
}

#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
void Settings::SaveTcatCommissionerCertificate(uint8_t *aCert, uint16_t aCertLen)
{
Error error = Get<SettingsDriver>().Set(kKeyTcatCommissionerCertificate, aCert, aCertLen);

Log(kActionSave, error, kKeyTcatCommissionerCertificate);

SuccessOrAssert(error);
}
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE

#if OPENTHREAD_FTD
Error Settings::AddChildInfo(const ChildInfo &aChildInfo)
{
Expand Down
56 changes: 42 additions & 14 deletions src/core/common/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,22 +106,24 @@ class SettingsBase : public InstanceLocator
*/
enum Key : uint16_t
{
kKeyActiveDataset = OT_SETTINGS_KEY_ACTIVE_DATASET,
kKeyPendingDataset = OT_SETTINGS_KEY_PENDING_DATASET,
kKeyNetworkInfo = OT_SETTINGS_KEY_NETWORK_INFO,
kKeyParentInfo = OT_SETTINGS_KEY_PARENT_INFO,
kKeyChildInfo = OT_SETTINGS_KEY_CHILD_INFO,
kKeySlaacIidSecretKey = OT_SETTINGS_KEY_SLAAC_IID_SECRET_KEY,
kKeyDadInfo = OT_SETTINGS_KEY_DAD_INFO,
kKeySrpEcdsaKey = OT_SETTINGS_KEY_SRP_ECDSA_KEY,
kKeySrpClientInfo = OT_SETTINGS_KEY_SRP_CLIENT_INFO,
kKeySrpServerInfo = OT_SETTINGS_KEY_SRP_SERVER_INFO,
kKeyBrUlaPrefix = OT_SETTINGS_KEY_BR_ULA_PREFIX,
kKeyBrOnLinkPrefixes = OT_SETTINGS_KEY_BR_ON_LINK_PREFIXES,
kKeyBorderAgentId = OT_SETTINGS_KEY_BORDER_AGENT_ID,
kKeyActiveDataset = OT_SETTINGS_KEY_ACTIVE_DATASET,
kKeyPendingDataset = OT_SETTINGS_KEY_PENDING_DATASET,
kKeyNetworkInfo = OT_SETTINGS_KEY_NETWORK_INFO,
kKeyParentInfo = OT_SETTINGS_KEY_PARENT_INFO,
kKeyChildInfo = OT_SETTINGS_KEY_CHILD_INFO,
kKeySlaacIidSecretKey = OT_SETTINGS_KEY_SLAAC_IID_SECRET_KEY,
kKeyDadInfo = OT_SETTINGS_KEY_DAD_INFO,
kKeySrpEcdsaKey = OT_SETTINGS_KEY_SRP_ECDSA_KEY,
kKeySrpClientInfo = OT_SETTINGS_KEY_SRP_CLIENT_INFO,
kKeySrpServerInfo = OT_SETTINGS_KEY_SRP_SERVER_INFO,
kKeyBrUlaPrefix = OT_SETTINGS_KEY_BR_ULA_PREFIX,
kKeyBrOnLinkPrefixes = OT_SETTINGS_KEY_BR_ON_LINK_PREFIXES,
kKeyBorderAgentId = OT_SETTINGS_KEY_BORDER_AGENT_ID,
kKeyTcatCommissionerCertificate = OT_SETTINGS_KEY_TCAT_COMMISSIONER_CERTIFICATE,
};

static constexpr Key kLastKey = kKeyBorderAgentId; ///< The last (numerically) enumerator value in `Key`.
static constexpr Key kLastKey =
kKeyTcatCommissionerCertificate; ///< The last (numerically) enumerator value in `Key`.

static_assert(static_cast<uint16_t>(kLastKey) < static_cast<uint16_t>(OT_SETTINGS_KEY_VENDOR_RESERVED_MIN),
"Core settings keys overlap with vendor reserved keys");
Expand Down Expand Up @@ -802,6 +804,32 @@ class Settings : public SettingsBase, private NonCopyable
*/
void DeleteOperationalDataset(MeshCoP::Dataset::Type aType);

#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
/**
* Stores the Tcat Commissioner certificate.
*
* @param[in] aCert The Dataset type (active or pending) to read.
* @param[in] aCertLen Certificate length.
*
*/
void SaveTcatCommissionerCertificate(uint8_t *aCert, uint16_t aCertLen);

/**
* Reads the Tcat Commissioner certificate.
*
* @param[in] aCert The Dataset type (active or pending) to read.
* @param[out] aCertLen Certificate length.
*
* @retval kErrorNone Successfully read the Dataset.
* @retval kErrorNotFound No corresponding value in the setting store.
* @retval kErrorNoBuffs Buffer has not enough space to store the data.
*/
Error GetTcatCommissionerCertificate(uint8_t *aCert, uint16_t &aCertLen)
{
return Get<SettingsDriver>().Get(kKeyTcatCommissionerCertificate, aCert, &aCertLen);
}
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE

/**
* Reads a specified settings entry.
*
Expand Down
38 changes: 38 additions & 0 deletions src/core/meshcop/secure_transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,44 @@ Error SecureTransport::Extension::GetPeerCertificateBase64(unsigned char *aPeerC
#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)

#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
Error SecureTransport::Extension::GetPeerCertificateRaw(unsigned char *aPeerCert,
size_t *aCertLength,
size_t aCertBufferSize)
{
Error error = kErrorNone;

VerifyOrExit(mSecureTransport.IsStateConnected(), error = kErrorInvalidState);

#if (MBEDTLS_VERSION_NUMBER >= 0x03010000)
VerifyOrExit(mSecureTransport.mSsl.MBEDTLS_PRIVATE(session)->MBEDTLS_PRIVATE(peer_cert)->raw.len < aCertBufferSize,
error = kErrorNoBufs);

*aCertLength = mSecureTransport.mSsl.MBEDTLS_PRIVATE(session)->MBEDTLS_PRIVATE(peer_cert)->raw.len;
memcpy(aPeerCert, mSecureTransport.mSsl.MBEDTLS_PRIVATE(session)->MBEDTLS_PRIVATE(peer_cert)->raw.p, *aCertLength);

#else
VerifyOrExit(mSecureTransport.mSsl.MBEDTLS_PRIVATE(session)
->MBEDTLS_PRIVATE(peer_cert)
->MBEDTLS_PRIVATE(raw)
.MBEDTLS_PRIVATE(len) < aCertBufferSize,
error = kErrorNoBufs);

*aCertLength = mSecureTransport.mSsl.MBEDTLS_PRIVATE(session)
->MBEDTLS_PRIVATE(peer_cert)
->MBEDTLS_PRIVATE(raw)
.MBEDTLS_PRIVATE(len);
memcpy(aPeerCert,
mSecureTransport.mSsl.MBEDTLS_PRIVATE(session)
->MBEDTLS_PRIVATE(peer_cert)
->MBEDTLS_PRIVATE(raw)
.MBEDTLS_PRIVATE(p),
*aCertLength);
#endif

exit:
return error;
}

Error SecureTransport::Extension::GetPeerSubjectAttributeByOid(const char *aOid,
size_t aOidLength,
uint8_t *aAttributeBuffer,
Expand Down
13 changes: 13 additions & 0 deletions src/core/meshcop/secure_transport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,19 @@ class SecureTransport : public InstanceLocator
#endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)

#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
/**
* Returns the peer x509 certificate DER encoded.
*
* @param[out] aPeerCert A pointer to the base64 encoded certificate buffer.
* @param[out] aCertLength The length of the base64 encoded peer certificate.
* @param[in] aCertBufferSize The buffer size of aPeerCert.
*
* @retval kErrorInvalidState Not connected yet.
* @retval kErrorNone Successfully get the peer certificate.
* @retval kErrorNoBufs Can't allocate memory for certificate.
*/
Error GetPeerCertificateRaw(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize);

/**
* Returns an attribute value identified by its OID from the subject
* of the peer x509 certificate. The peer OID is provided in binary format.
Expand Down
62 changes: 59 additions & 3 deletions src/core/meshcop/tcat_agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
*/

#include "tcat_agent.hpp"
#include <openthread/platform/settings.h>
#include "common/code_utils.hpp"
#include "crypto/storage.hpp"

Expand Down Expand Up @@ -405,6 +406,10 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutg
error = HandleSetActiveOperationalDataset(aIncomingMessage, offset, length);
break;

case kTlvGetActiveOperationalDataset:
error = HandleGetActiveOperationalDataset(aOutgoingMessage, response);
break;

case kTlvStartThreadInterface:
error = HandleStartThreadInterface();
break;
Expand Down Expand Up @@ -455,6 +460,9 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutg
case kTlvRequestPskdHash:
error = HandleRequestPskdHash(aIncomingMessage, aOutgoingMessage, offset, length, response);
break;
case kTlvGetCommissionerCertificate:
error = HandleGetCommissionerCertificate(aOutgoingMessage, response);
break;
default:
error = kErrorInvalidCommand;
}
Expand Down Expand Up @@ -507,9 +515,11 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutg

Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength)
{
Dataset dataset;
OffsetRange offsetRange;
Error error;
Dataset dataset;
OffsetRange offsetRange;
Error error;
unsigned char buf[1024];
size_t bufLen = sizeof(buf);

offsetRange.Init(aOffset, aLength);
SuccessOrExit(error = dataset.SetFrom(aIncomingMessage, offsetRange));
Expand All @@ -524,6 +534,52 @@ Error TcatAgent::HandleSetActiveOperationalDataset(const Message &aIncomingMessa

Get<ActiveDatasetManager>().SaveLocal(dataset);

SuccessOrExit(error = otBleSecureGetPeerCertificateRaw(&GetInstance(), buf, &bufLen));
Get<Settings>().SaveTcatCommissionerCertificate(buf, (uint16_t)bufLen);
exit:
return error;
}

Error TcatAgent::HandleGetActiveOperationalDataset(Message &aOutgoingMessage, bool &aResponse)
{
Error error = kErrorNone;
Dataset dataset;
Dataset::Tlvs datasetTlvs;

if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mApplicationFlags,
mDeviceAuthorizationField.mApplicationFlags, &dataset))
{
error = kErrorRejected;
ExitNow();
}

SuccessOrExit(error = Get<ActiveDatasetManager>().Read(datasetTlvs));
SuccessOrExit(
error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, datasetTlvs.mTlvs, datasetTlvs.mLength));
aResponse = true;

exit:
return error;
}

Error TcatAgent::HandleGetCommissionerCertificate(Message &aOutgoingMessage, bool &aResponse)
{
Error error = kErrorNone;
Dataset dataset;
unsigned char buf[1024];
uint16_t bufLen = sizeof(buf);

if (!CheckCommandClassAuthorizationFlags(mCommissionerAuthorizationField.mApplicationFlags,
mDeviceAuthorizationField.mApplicationFlags, &dataset))
{
error = kErrorRejected;
ExitNow();
}

VerifyOrExit(kErrorNone == Get<Settings>().GetTcatCommissionerCertificate(buf, bufLen), error = kErrorInvalidState);
SuccessOrExit(error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, buf, bufLen));
aResponse = true;

exit:
return error;
}
Expand Down
Loading

0 comments on commit 0e71f3c

Please sign in to comment.