Skip to content

Commit

Permalink
[tcat] implementation of TCAT general class commands.
Browse files Browse the repository at this point in the history
Commit introduces implementation of missing general class commands:
- PresentPskdHash
- PresentPskcHash
- PresentInstallCodeHash
- RequestRandomNumChallenge
- RequestPskdHash

Also include minor fixes in Tcat python client and refactoring of expect
tests for tcat.
  • Loading branch information
canisLupus1313 committed Sep 18, 2024
1 parent d60ec88 commit 7b405b5
Show file tree
Hide file tree
Showing 18 changed files with 493 additions and 66 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/posix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
- name: Bootstrap
run: |
sudo apt-get --no-install-recommends install -y expect ninja-build lcov socat
pip install bleak
pip install bleak 'cryptography==43.0.0'
- name: Run RCP Mode
run: |
ulimit -c unlimited
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/simulation-1.1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ jobs:
- name: Bootstrap
run: |
sudo apt-get --no-install-recommends install -y expect ninja-build lcov socat
pip install bleak
pip install bleak 'cryptography==43.0.0'
- name: Run
run: |
ulimit -c unlimited
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/simulation-1.4.yml
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ jobs:
- name: Bootstrap
run: |
sudo apt-get --no-install-recommends install -y expect ninja-build lcov socat
pip install bleak
pip install bleak 'cryptography==43.0.0'
- name: Run RCP Mode
run: |
ulimit -c unlimited
Expand Down
6 changes: 4 additions & 2 deletions src/cli/cli_tcat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,9 @@ namespace Cli {
otTcatAdvertisedDeviceId sAdvertisedDeviceIds[OT_TCAT_DEVICE_ID_MAX];
otTcatGeneralDeviceId sGeneralDeviceId;

const char kPskdVendor[] = "JJJJJJ";
const char kUrl[] = "dummy_url";
const char kPskdVendor[] = "JJJJJJ";
const char kInstallVendor[] = "InstallCode";
const char kUrl[] = "dummy_url";

static bool IsDeviceIdSet(void)
{
Expand Down Expand Up @@ -250,6 +251,7 @@ template <> otError Tcat::Process<Cmd("start")>(Arg aArgs[])
ClearAllBytes(mVendorInfo);
mVendorInfo.mPskdString = kPskdVendor;
mVendorInfo.mProvisioningUrl = kUrl;
mVendorInfo.mInstallCode = kInstallVendor;

if (IsDeviceIdSet())
{
Expand Down
9 changes: 9 additions & 0 deletions src/core/meshcop/secure_transport.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,15 @@ class SecureTransport : public InstanceLocator
*
*/
void SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength);

/**
* Extracts public key from it's own certificate.
*
* @return public key from own certificate in form of entire ASN.1 field.
*
*/
const mbedtls_asn1_buf &GetOwnPublicKey(void) const { return mOwnCert.pk_raw; }

#endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED

#if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
Expand Down
166 changes: 153 additions & 13 deletions src/core/meshcop/tcat_agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
*/

#include "tcat_agent.hpp"
#include <openthread/tcat.h>
#include "common/error.hpp"
#include "meshcop/network_name.hpp"
#include "openthread/tcat.h"
#include "thread/key_manager.hpp"

#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE

Expand Down Expand Up @@ -70,6 +72,7 @@ TcatAgent::TcatAgent(Instance &aInstance)
, mCommissionerHasNetworkName(false)
, mCommissionerHasDomainName(false)
, mCommissionerHasExtendedPanId(false)
, mRandomChallenge(0)
{
mJoinerPskd.Clear();
mCurrentServiceName[0] = 0;
Expand All @@ -83,6 +86,7 @@ Error TcatAgent::Start(AppDataReceiveCallback aAppDataReceiveCallback, JoinCallb
VerifyOrExit(mVendorInfo != nullptr, error = kErrorFailed);
mAppDataReceiveCallback.Set(aAppDataReceiveCallback, aContext);
mJoinCallback.Set(aHandler, aContext);
mRandomChallenge = 0;

mCurrentApplicationProtocol = kApplicationProtocolNone;
mState = kStateEnabled;
Expand All @@ -98,6 +102,7 @@ void TcatAgent::Stop(void)
mState = kStateDisabled;
mAppDataReceiveCallback.Clear();
mJoinCallback.Clear();
mRandomChallenge = 0;
LogInfo("TCAT agent stopped");
}

Expand Down Expand Up @@ -179,6 +184,7 @@ void TcatAgent::Disconnected(void)
{
mState = kStateEnabled;
}
mRandomChallenge = 0;

LogInfo("TCAT agent disconnected");
}
Expand Down Expand Up @@ -435,7 +441,21 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutg
case kTlvGetProvisioningURL:
error = HandleGetProvisioningUrl(aOutgoingMessage, response);
break;

case kTlvPresentPskdHash:
error = HandlePresentPskdHash(aIncomingMessage, offset, length);
break;
case kTlvPresentPskcHash:
error = HandlePresentPskcHash(aIncomingMessage, offset, length);
break;
case kTlvPresentInstallCodeHash:
error = HandlePresentInstallCodeHash(aIncomingMessage, offset, length);
break;
case kTlvRequestRandomNumChallenge:
error = HandleRequestRandomNumberChallenge(aOutgoingMessage, response);
break;
case kTlvRequestPskdHash:
error = HandleRequestPskdHash(aIncomingMessage, aOutgoingMessage, offset, length, response);
break;
default:
error = kErrorInvalidCommand;
}
Expand Down Expand Up @@ -470,6 +490,10 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutg
statusCode = kStatusUnsupported;
break;

case kErrorSecurity:
statusCode = kStatusHashError;
break;

default:
statusCode = kStatusGeneralError;
break;
Expand Down Expand Up @@ -530,7 +554,7 @@ Error TcatAgent::HandlePing(const Message &aIncomingMessage,
Message &aOutgoingMessage,
uint16_t aOffset,
uint16_t aLength,
bool &response)
bool &aResponse)
{
Error error = kErrorNone;
ot::ExtendedTlv extTlv;
Expand All @@ -551,13 +575,13 @@ Error TcatAgent::HandlePing(const Message &aIncomingMessage,
}

SuccessOrExit(error = aOutgoingMessage.AppendBytesFromMessage(aIncomingMessage, aOffset, aLength));
response = true;
aResponse = true;

exit:
return error;
}

Error TcatAgent::HandleGetNetworkName(Message &aOutgoingMessage, bool &response)
Error TcatAgent::HandleGetNetworkName(Message &aOutgoingMessage, bool &aResponse)
{
Error error = kErrorNone;
MeshCoP::NameData nameData = Get<MeshCoP::NetworkNameManager>().GetNetworkName().GetAsData();
Expand All @@ -569,13 +593,13 @@ Error TcatAgent::HandleGetNetworkName(Message &aOutgoingMessage, bool &response)

SuccessOrExit(
error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, nameData.GetBuffer(), nameData.GetLength()));
response = true;
aResponse = true;

exit:
return error;
}

Error TcatAgent::HandleGetDeviceId(Message &aOutgoingMessage, bool &response)
Error TcatAgent::HandleGetDeviceId(Message &aOutgoingMessage, bool &aResponse)
{
const uint8_t *deviceId;
uint16_t length = 0;
Expand All @@ -598,27 +622,27 @@ Error TcatAgent::HandleGetDeviceId(Message &aOutgoingMessage, bool &response)

SuccessOrExit(error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, deviceId, length));

response = true;
aResponse = true;

exit:
return error;
}

Error TcatAgent::HandleGetExtPanId(Message &aOutgoingMessage, bool &response)
Error TcatAgent::HandleGetExtPanId(Message &aOutgoingMessage, bool &aResponse)
{
Error error;

VerifyOrExit(Get<ActiveDatasetManager>().IsCommissioned(), error = kErrorInvalidState);

SuccessOrExit(error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload,
&Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId(), sizeof(ExtendedPanId)));
response = true;
aResponse = true;

exit:
return error;
}

Error TcatAgent::HandleGetProvisioningUrl(Message &aOutgoingMessage, bool &response)
Error TcatAgent::HandleGetProvisioningUrl(Message &aOutgoingMessage, bool &aResponse)
{
Error error = kErrorNone;
uint16_t length;
Expand All @@ -628,13 +652,129 @@ Error TcatAgent::HandleGetProvisioningUrl(Message &aOutgoingMessage, bool &respo
length = StringLength(mVendorInfo->mProvisioningUrl, kProvisioningUrlMaxLength);
VerifyOrExit(length > 0 && length <= Tlv::kBaseTlvMaxLength, error = kErrorInvalidState);

error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, mVendorInfo->mProvisioningUrl, length);
response = true;
SuccessOrExit(error =
Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, mVendorInfo->mProvisioningUrl, length));
aResponse = true;

exit:
return error;
}

Error TcatAgent::HandlePresentPskdHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength)
{
Error error = kErrorNone;

VerifyOrExit(mVendorInfo->mPskdString != nullptr, error = kErrorSecurity);

error = VerifyHash(aIncomingMessage, aOffset, aLength, mVendorInfo->mPskdString,
StringLength(mVendorInfo->mPskdString, kMaxPskdLength));

exit:
return error;
}

Error TcatAgent::HandlePresentPskcHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength)
{
Error error = kErrorNone;
Dataset::Info datasetInfo;
Pskc pskc;

VerifyOrExit(Get<ActiveDatasetManager>().Read(datasetInfo) == kErrorNone, error = kErrorSecurity);
VerifyOrExit(datasetInfo.IsPresent<Dataset::kPskc>(), error = kErrorSecurity);
pskc = datasetInfo.Get<Dataset::kPskc>();

error = VerifyHash(aIncomingMessage, aOffset, aLength, pskc.m8, Pskc::kSize);

exit:
return error;
}

Error TcatAgent::HandlePresentInstallCodeHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength)
{
Error error = kErrorNone;

VerifyOrExit(mVendorInfo->mInstallCode != nullptr, error = kErrorSecurity);

error = VerifyHash(aIncomingMessage, aOffset, aLength, mVendorInfo->mInstallCode,
StringLength(mVendorInfo->mInstallCode, 255));

exit:
return error;
}

Error TcatAgent::HandleRequestRandomNumberChallenge(Message &aOutgoingMessage, bool &aResponse)
{
Error error = kErrorNone;

SuccessOrExit(error = Random::Crypto::Fill(mRandomChallenge));

SuccessOrExit(
error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, &mRandomChallenge, sizeof(mRandomChallenge)));
aResponse = true;
exit:
return error;
}

Error TcatAgent::HandleRequestPskdHash(const Message &aIncomingMessage,
Message &aOutgoingMessage,
uint16_t aOffset,
uint16_t aLength,
bool &aResponse)
{
Error error = kErrorNone;
uint64_t providedChallenge = 0;
Crypto::HmacSha256::Hash hash;

VerifyOrExit(StringLength(mVendorInfo->mPskdString, kMaxPskdLength) != 0, error = kErrorFailed);
VerifyOrExit(aLength == sizeof(providedChallenge), error = kErrorParse);

SuccessOrExit(error = aIncomingMessage.Read(aOffset, &providedChallenge, aLength));

CalculateHash(providedChallenge, mVendorInfo->mPskdString, StringLength(mVendorInfo->mPskdString, kMaxPskdLength),
hash);

SuccessOrExit(error = Tlv::AppendTlv(aOutgoingMessage, kTlvResponseWithPayload, hash.GetBytes(),
Crypto::HmacSha256::Hash::kSize));
aResponse = true;

exit:
return error;
}

Error TcatAgent::VerifyHash(const Message &aIncomingMessage,
uint16_t aOffset,
uint16_t aLength,
const void *aBuf,
size_t aBufLen)
{
Error error = kErrorNone;
Crypto::HmacSha256::Hash hash;

VerifyOrExit(aLength == Crypto::HmacSha256::Hash::kSize, error = kErrorSecurity);
VerifyOrExit(mRandomChallenge != 0, error = kErrorSecurity);

CalculateHash(mRandomChallenge, reinterpret_cast<const char *>(aBuf), aBufLen, hash);

VerifyOrExit(aIncomingMessage.Compare(aOffset, hash), error = kErrorSecurity);

exit:
return error;
}

void TcatAgent::CalculateHash(uint64_t aChallenge, const char *aBuf, size_t aBufLen, Crypto::HmacSha256::Hash &aHash)
{
const mbedtls_asn1_buf &rawKey = Get<Ble::BleSecure>().GetOwnPublicKey();
Crypto::Key cryptoKey;
Crypto::HmacSha256 hmac;

cryptoKey.Set(reinterpret_cast<const uint8_t *>(aBuf), static_cast<uint16_t>(aBufLen));

hmac.Start(cryptoKey);
hmac.Update(aChallenge);
hmac.Update(rawKey.p, static_cast<uint16_t>(rawKey.len));
hmac.Finish(aHash);
}

Error TcatAgent::HandleStartThreadInterface(void)
{
Error error;
Expand Down
Loading

0 comments on commit 7b405b5

Please sign in to comment.