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 20, 2024
1 parent 944a246 commit 299e26b
Show file tree
Hide file tree
Showing 18 changed files with 491 additions and 65 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 @@ -293,6 +294,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
162 changes: 150 additions & 12 deletions src/core/meshcop/tcat_agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ TcatAgent::TcatAgent(Instance &aInstance)
, mCommissionerHasNetworkName(false)
, mCommissionerHasDomainName(false)
, mCommissionerHasExtendedPanId(false)
, mRandomChallenge(0)
{
mJoinerPskd.Clear();
mCurrentServiceName[0] = 0;
Expand All @@ -72,6 +73,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 @@ -87,6 +89,7 @@ void TcatAgent::Stop(void)
mState = kStateDisabled;
mAppDataReceiveCallback.Clear();
mJoinCallback.Clear();
mRandomChallenge = 0;
LogInfo("TCAT agent stopped");
}

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

LogInfo("TCAT agent disconnected");
}
Expand Down Expand Up @@ -424,7 +428,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 @@ -459,6 +477,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 @@ -519,7 +541,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 @@ -540,13 +562,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 @@ -558,13 +580,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 @@ -587,27 +609,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 @@ -617,13 +639,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
35 changes: 27 additions & 8 deletions src/core/meshcop/tcat_agent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,22 +358,40 @@ class TcatAgent : public InstanceLocator, private NonCopyable
Message &aOutgoingMessage,
uint16_t aOffset,
uint16_t aLength,
bool &response);
Error HandleGetNetworkName(Message &aOutgoingMessage, bool &response);
Error HandleGetDeviceId(Message &aOutgoingMessage, bool &response);
Error HandleGetExtPanId(Message &aOutgoingMessage, bool &response);
Error HandleGetProvisioningUrl(Message &aOutgoingMessage, bool &response);
bool &aResponse);
Error HandleGetNetworkName(Message &aOutgoingMessage, bool &aResponse);
Error HandleGetDeviceId(Message &aOutgoingMessage, bool &aResponse);
Error HandleGetExtPanId(Message &aOutgoingMessage, bool &aResponse);
Error HandleGetProvisioningUrl(Message &aOutgoingMessage, bool &aResponse);
Error HandlePresentPskdHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength);
Error HandlePresentPskcHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength);
Error HandlePresentInstallCodeHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength);
Error HandleRequestRandomNumberChallenge(Message &aOutgoingMessage, bool &aResponse);
Error HandleRequestPskdHash(const Message &aIncomingMessage,
Message &aOutgoingMessage,
uint16_t aOffset,
uint16_t aLength,
bool &aResponse);
Error HandleStartThreadInterface(void);

bool CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissionerCommandClassFlags,
CommandClassFlags aDeviceCommandClassFlags,
Dataset *aDataset) const;
Error VerifyHash(const Message &aIncomingMessage,
uint16_t aOffset,
uint16_t aLength,
const void *aBuf,
size_t aBufLen);
void CalculateHash(uint64_t aChallenge, const char *aBuf, size_t aBufLen, Crypto::HmacSha256::Hash &aHash);

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;
static constexpr uint16_t kPingPayloadMaxLength = 512;
static constexpr uint16_t kProvisioningUrlMaxLength = 64;
static constexpr uint16_t kMaxPskdLength = OT_JOINER_MAX_PSKD_LENGTH;
static constexpr uint16_t kTcatMaxDeviceIdSize = OT_TCAT_MAX_DEVICEID_SIZE;

JoinerPskd mJoinerPskd;
Expand All @@ -391,6 +409,7 @@ class TcatAgent : public InstanceLocator, private NonCopyable
bool mCommissionerHasNetworkName : 1;
bool mCommissionerHasDomainName : 1;
bool mCommissionerHasExtendedPanId : 1;
uint64_t mRandomChallenge;

friend class Ble::BleSecure;
};
Expand Down
Loading

0 comments on commit 299e26b

Please sign in to comment.