mirror of
https://github.com/espressif/openthread.git
synced 2026-08-09 04:07:47 +00:00
[tcat] implementation of TCAT general class commands (#10700)
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -407,6 +407,16 @@ otError otBleSecureSendApplicationTlv(otInstance *aInstance, uint8_t *aBuf, uint
|
||||
*/
|
||||
otError otBleSecureFlush(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Gets the Install Code Verify Status during the current session.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
* @retval TRUE The install code was correctly verified.
|
||||
* @retval FALSE The install code was not verified.
|
||||
*/
|
||||
bool otBleSecureGetInstallCodeVerifyStatus(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (451)
|
||||
#define OPENTHREAD_API_VERSION (452)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -186,4 +186,9 @@ otError otBleSecureSendApplicationTlv(otInstance *aInstance, uint8_t *aBuf, uint
|
||||
|
||||
otError otBleSecureFlush(otInstance *aInstance) { return AsCoreType(aInstance).Get<Ble::BleSecure>().Flush(); }
|
||||
|
||||
bool otBleSecureGetInstallCodeVerifyStatus(otInstance *aInstance)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Ble::BleSecure>().GetInstallCodeVerifyStatus();
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
|
||||
|
||||
@@ -301,6 +301,14 @@ public:
|
||||
* @param[in] aX509CaCertChainLength The length of chain.
|
||||
*/
|
||||
void SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength);
|
||||
|
||||
/**
|
||||
* Extracts public key from it's own certificate.
|
||||
*
|
||||
* @returns 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)
|
||||
|
||||
+168
-16
@@ -32,6 +32,7 @@
|
||||
*/
|
||||
|
||||
#include "tcat_agent.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
|
||||
|
||||
@@ -59,6 +60,10 @@ TcatAgent::TcatAgent(Instance &aInstance)
|
||||
, mCommissionerHasNetworkName(false)
|
||||
, mCommissionerHasDomainName(false)
|
||||
, mCommissionerHasExtendedPanId(false)
|
||||
, mRandomChallenge(0)
|
||||
, mPskdVerified(false)
|
||||
, mPskcVerified(false)
|
||||
, mInstallCodeVerified(false)
|
||||
{
|
||||
mJoinerPskd.Clear();
|
||||
mCurrentServiceName[0] = 0;
|
||||
@@ -72,6 +77,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;
|
||||
@@ -87,6 +93,10 @@ void TcatAgent::Stop(void)
|
||||
mState = kStateDisabled;
|
||||
mAppDataReceiveCallback.Clear();
|
||||
mJoinCallback.Clear();
|
||||
mRandomChallenge = 0;
|
||||
mPskdVerified = false;
|
||||
mPskcVerified = false;
|
||||
mInstallCodeVerified = false;
|
||||
LogInfo("TCAT agent stopped");
|
||||
}
|
||||
|
||||
@@ -169,6 +179,11 @@ void TcatAgent::Disconnected(void)
|
||||
mState = kStateEnabled;
|
||||
}
|
||||
|
||||
mRandomChallenge = 0;
|
||||
mPskdVerified = false;
|
||||
mPskcVerified = false;
|
||||
mInstallCodeVerified = false;
|
||||
|
||||
LogInfo("TCAT agent disconnected");
|
||||
}
|
||||
|
||||
@@ -190,14 +205,14 @@ bool TcatAgent::CheckCommandClassAuthorizationFlags(CommandClassFlags aCommissio
|
||||
additionalDeviceRequirementMet = true;
|
||||
}
|
||||
|
||||
if (aDeviceCommandClassFlags & kPskdFlag)
|
||||
if (!additionalDeviceRequirementMet && (aDeviceCommandClassFlags & kPskdFlag))
|
||||
{
|
||||
additionalDeviceRequirementMet = true;
|
||||
additionalDeviceRequirementMet = mPskdVerified;
|
||||
}
|
||||
|
||||
if (aDeviceCommandClassFlags & kPskcFlag)
|
||||
if (!additionalDeviceRequirementMet && (aDeviceCommandClassFlags & kPskcFlag))
|
||||
{
|
||||
additionalDeviceRequirementMet = true;
|
||||
additionalDeviceRequirementMet = mPskcVerified;
|
||||
}
|
||||
|
||||
if (mCommissionerHasNetworkName || mCommissionerHasExtendedPanId)
|
||||
@@ -424,7 +439,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;
|
||||
}
|
||||
@@ -459,6 +488,10 @@ Error TcatAgent::HandleSingleTlv(const Message &aIncomingMessage, Message &aOutg
|
||||
statusCode = kStatusUnsupported;
|
||||
break;
|
||||
|
||||
case kErrorSecurity:
|
||||
statusCode = kStatusHashError;
|
||||
break;
|
||||
|
||||
default:
|
||||
statusCode = kStatusGeneralError;
|
||||
break;
|
||||
@@ -519,7 +552,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;
|
||||
@@ -540,13 +573,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();
|
||||
@@ -558,13 +591,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;
|
||||
@@ -587,13 +620,13 @@ 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;
|
||||
|
||||
@@ -601,13 +634,13 @@ Error TcatAgent::HandleGetExtPanId(Message &aOutgoingMessage, bool &response)
|
||||
|
||||
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;
|
||||
@@ -617,13 +650,132 @@ 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);
|
||||
|
||||
SuccessOrExit(error = VerifyHash(aIncomingMessage, aOffset, aLength, mVendorInfo->mPskdString,
|
||||
StringLength(mVendorInfo->mPskdString, kMaxPskdLength)));
|
||||
mPskdVerified = true;
|
||||
|
||||
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>();
|
||||
|
||||
SuccessOrExit(error = VerifyHash(aIncomingMessage, aOffset, aLength, pskc.m8, Pskc::kSize));
|
||||
mPskcVerified = true;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error TcatAgent::HandlePresentInstallCodeHash(const Message &aIncomingMessage, uint16_t aOffset, uint16_t aLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(mVendorInfo->mInstallCode != nullptr, error = kErrorSecurity);
|
||||
|
||||
SuccessOrExit(error = VerifyHash(aIncomingMessage, aOffset, aLength, mVendorInfo->mInstallCode,
|
||||
StringLength(mVendorInfo->mInstallCode, kInstallCodeMaxSize)));
|
||||
mInstallCodeVerified = true;
|
||||
|
||||
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;
|
||||
|
||||
@@ -325,6 +325,14 @@ public:
|
||||
*/
|
||||
Error GetAdvertisementData(uint16_t &aLen, uint8_t *aAdvertisementData);
|
||||
|
||||
/**
|
||||
* @brief Gets the Install Code Verify Status during the current session.
|
||||
*
|
||||
* @retval TRUE The install code was correctly verified.
|
||||
* @retval FALSE The install code was not verified.
|
||||
*/
|
||||
bool GetInstallCodeVerifyStatus(void) const { return mInstallCodeVerified; }
|
||||
|
||||
private:
|
||||
Error Connected(MeshCoP::SecureTransport &aTlsContext);
|
||||
void Disconnected(void);
|
||||
@@ -336,23 +344,42 @@ private:
|
||||
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;
|
||||
static constexpr uint16_t kInstallCodeMaxSize = 255;
|
||||
|
||||
JoinerPskd mJoinerPskd;
|
||||
const VendorInfo *mVendorInfo;
|
||||
@@ -369,6 +396,10 @@ private:
|
||||
bool mCommissionerHasNetworkName : 1;
|
||||
bool mCommissionerHasDomainName : 1;
|
||||
bool mCommissionerHasExtendedPanId : 1;
|
||||
uint64_t mRandomChallenge;
|
||||
bool mPskdVerified : 1;
|
||||
bool mPskcVerified : 1;
|
||||
bool mInstallCodeVerified : 1;
|
||||
|
||||
friend class Ble::BleSecure;
|
||||
};
|
||||
|
||||
@@ -334,6 +334,13 @@ public:
|
||||
return mTls.GetThreadAttributeFromOwnCertificate(aThreadOidDescriptor, aAttributeBuffer, aAttributeLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts public key from it's own certificate.
|
||||
*
|
||||
* @returns Public key from own certificate in form of entire ASN.1 field.
|
||||
*/
|
||||
const mbedtls_asn1_buf &GetOwnPublicKey(void) const { return mTls.GetOwnPublicKey(); }
|
||||
|
||||
/**
|
||||
* Sets the authentication mode for the BLE secure connection. It disables or enables the verification
|
||||
* of peer certificate.
|
||||
@@ -419,6 +426,14 @@ public:
|
||||
*/
|
||||
Error HandleBleMtuUpdate(uint16_t aMtu);
|
||||
|
||||
/**
|
||||
* @brief Gets the Install Code Verify Status during the current session.
|
||||
*
|
||||
* @return TRUE The install code was correctly verfied.
|
||||
* @return FALSE The install code was not verified.
|
||||
*/
|
||||
bool GetInstallCodeVerifyStatus(void) const { return mTcatAgent.GetInstallCodeVerifyStatus(); }
|
||||
|
||||
private:
|
||||
enum BleState : uint8_t
|
||||
{
|
||||
|
||||
@@ -266,4 +266,35 @@ proc fail {message} {
|
||||
error $message
|
||||
}
|
||||
|
||||
proc spawn_tcat_client_for_node {id} {
|
||||
global tcat_ids
|
||||
global spawn_id
|
||||
|
||||
switch_node $id
|
||||
|
||||
send "tcat start\n"
|
||||
expect_line "Done"
|
||||
|
||||
spawn python "tools/tcat_ble_client/bbtc.py" --simulation $id --cert_path "tools/tcat_ble_client/auth"
|
||||
expect_line "Done"
|
||||
|
||||
set tcat_ids($id) $spawn_id
|
||||
|
||||
return $spawn_id
|
||||
}
|
||||
|
||||
proc switch_tcat_client_for_node {id} {
|
||||
global tcat_ids
|
||||
global spawn_id
|
||||
|
||||
send_user "\n# ${id}\n"
|
||||
set spawn_id $tcat_ids($id)
|
||||
}
|
||||
|
||||
proc dispose_tcat_client {id} {
|
||||
switch_tcat_client_for_node $id
|
||||
send "exit\n"
|
||||
expect eof
|
||||
}
|
||||
|
||||
set timeout 10
|
||||
|
||||
@@ -31,7 +31,6 @@ source "tests/scripts/expect/_common.exp"
|
||||
|
||||
spawn_node 1 "cli"
|
||||
|
||||
switch_node 1
|
||||
send "tcat advid ianapen f378\n"
|
||||
expect_line "Done"
|
||||
|
||||
@@ -89,3 +88,5 @@ expect_line "Done"
|
||||
|
||||
send "tcat devid\n"
|
||||
expect_line "Done"
|
||||
|
||||
dispose_all
|
||||
|
||||
@@ -31,13 +31,8 @@ source "tests/scripts/expect/_common.exp"
|
||||
|
||||
spawn_node 1 "cli"
|
||||
|
||||
switch_node 1
|
||||
send "tcat start\n"
|
||||
expect_line "Done"
|
||||
spawn_tcat_client_for_node 1
|
||||
|
||||
spawn python "tools/tcat_ble_client/bbtc.py" --simulation 1 --cert_path "tools/tcat_ble_client/auth"
|
||||
set py_client "$spawn_id"
|
||||
expect_line "Done"
|
||||
send "commission\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x00"
|
||||
@@ -49,8 +44,7 @@ expect_line "\tVALUE:\t0x00"
|
||||
send "decommission\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
|
||||
send "exit\n"
|
||||
expect eof
|
||||
dispose_tcat_client 1
|
||||
|
||||
switch_node 1
|
||||
send "tcat stop\n"
|
||||
@@ -62,3 +56,5 @@ expect_line "Error 23: NotFound"
|
||||
send "networkkey\n"
|
||||
expect_line "00000000000000000000000000000000"
|
||||
expect_line "Done"
|
||||
|
||||
dispose_all
|
||||
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/expect -f
|
||||
#
|
||||
# Copyright (c) 2024, 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.
|
||||
#
|
||||
|
||||
source "tests/scripts/expect/_common.exp"
|
||||
|
||||
spawn_node 1 "cli"
|
||||
|
||||
spawn_tcat_client_for_node 1
|
||||
|
||||
send "commission\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x00"
|
||||
|
||||
send "random_challenge\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
|
||||
expect_line "\tLEN:\t8"
|
||||
|
||||
send "peer_pskd_hash JJJJJJ\n"
|
||||
expect_line "Requested hash is valid."
|
||||
expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
|
||||
expect_line "\tLEN:\t32"
|
||||
|
||||
send "present_hash pskd JJJJJJ\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x00"
|
||||
|
||||
send "present_hash pskd AAAA\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x07"
|
||||
|
||||
send "present_hash install InstallCode\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x00"
|
||||
|
||||
send "present_hash install Code\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x07"
|
||||
|
||||
send "present_hash pskc 5e9b9b360f80b88be2603fb0135c8d65\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x00"
|
||||
|
||||
send "present_hash pskc aaaa\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
expect_line "\tVALUE:\t0x07"
|
||||
|
||||
dispose_tcat_client 1
|
||||
|
||||
switch_node 1
|
||||
send "tcat stop\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "networkkey\n"
|
||||
expect_line "fda7c771a27202e232ecd04cf934f476"
|
||||
expect_line "Done"
|
||||
|
||||
dispose_all
|
||||
@@ -31,13 +31,7 @@ source "tests/scripts/expect/_common.exp"
|
||||
|
||||
spawn_node 1 "cli"
|
||||
|
||||
switch_node 1
|
||||
send "tcat start\n"
|
||||
expect_line "Done"
|
||||
|
||||
spawn python "tools/tcat_ble_client/bbtc.py" --simulation 1 --cert_path "tools/tcat_ble_client/auth"
|
||||
set py_client "$spawn_id"
|
||||
expect_line "Done"
|
||||
spawn_tcat_client_for_node 1
|
||||
|
||||
send "network_name\n"
|
||||
expect_line "\tTYPE:\tRESPONSE_W_STATUS"
|
||||
@@ -83,8 +77,7 @@ expect_line "\tTYPE:\tRESPONSE_W_PAYLOAD"
|
||||
expect_line "\tLEN:\t9"
|
||||
expect_line "\tVALUE:\t0x64756d6d795f75726c"
|
||||
|
||||
send "exit\n"
|
||||
expect eof
|
||||
dispose_tcat_client 1
|
||||
|
||||
switch_node 1
|
||||
send "tcat stop\n"
|
||||
@@ -96,3 +89,5 @@ expect_line "Done"
|
||||
|
||||
wait_for "state" "leader"
|
||||
expect_line "Done"
|
||||
|
||||
dispose_all
|
||||
|
||||
@@ -87,12 +87,10 @@ async def main():
|
||||
print('Setting up secure TLS channel..', end='')
|
||||
try:
|
||||
await ble_sstream.do_handshake()
|
||||
print('\nDone')
|
||||
ble_sstream.log_cert_identities()
|
||||
print('Done')
|
||||
except Exception as e:
|
||||
print('\nFailed')
|
||||
print('Failed')
|
||||
logger.error(e)
|
||||
ble_sstream.log_cert_identities()
|
||||
quit_with_reason('TLS handshake failure')
|
||||
|
||||
ds = ThreadDataset()
|
||||
|
||||
@@ -32,6 +32,8 @@ import ssl
|
||||
import sys
|
||||
import logging
|
||||
|
||||
from cryptography.x509 import load_der_x509_certificate
|
||||
from cryptography.hazmat.primitives.serialization import (Encoding, PublicFormat)
|
||||
from tlv.tlv import TLV
|
||||
from tlv.tcat_tlv import TcatTLVType
|
||||
from time import time
|
||||
@@ -49,6 +51,8 @@ class BleStreamSecure:
|
||||
self.outgoing = ssl.MemoryBIO()
|
||||
self.ssl_object = None
|
||||
self.cert = ''
|
||||
self.peer_challenge = None
|
||||
self._peer_public_key = None
|
||||
|
||||
def load_cert(self, certfile='', keyfile='', cafile=''):
|
||||
if certfile and keyfile:
|
||||
@@ -102,6 +106,11 @@ class BleStreamSecure:
|
||||
else:
|
||||
print('TLS Connection timed out.')
|
||||
return False
|
||||
print('')
|
||||
cert = self.ssl_object.getpeercert(True)
|
||||
cert_obj = load_der_x509_certificate(cert)
|
||||
self._peer_public_key = cert_obj.public_key().public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
|
||||
self.log_cert_identities()
|
||||
return True
|
||||
|
||||
async def send(self, bytes):
|
||||
@@ -142,8 +151,22 @@ class BleStreamSecure:
|
||||
if self.ssl_object.session is not None:
|
||||
logger.debug('sending Disconnect command TLV')
|
||||
data = TLV(TcatTLVType.DISCONNECT.value, bytes()).to_bytes()
|
||||
self.peer_challenge = None
|
||||
self._peer_public_key = None
|
||||
await self.send(data)
|
||||
|
||||
@property
|
||||
def peer_public_key(self):
|
||||
return self._peer_public_key
|
||||
|
||||
@property
|
||||
def peer_challenge(self):
|
||||
return self._peer_challenge
|
||||
|
||||
@peer_challenge.setter
|
||||
def peer_challenge(self, value):
|
||||
self._peer_challenge = value
|
||||
|
||||
def log_cert_identities(self):
|
||||
# using the internal object of the ssl library is necessary to see the cert data in
|
||||
# case of handshake failure - see https://sethmlarson.dev/experimental-python-3.10-apis-and-trust-stores
|
||||
|
||||
@@ -40,6 +40,9 @@ from utils import select_device_by_user_input
|
||||
from os import path
|
||||
from time import time
|
||||
from secrets import token_bytes
|
||||
from hashlib import sha256
|
||||
import hmac
|
||||
import binascii
|
||||
|
||||
|
||||
class HelpCommand(Command):
|
||||
@@ -55,6 +58,10 @@ class HelpCommand(Command):
|
||||
return CommandResultNone()
|
||||
|
||||
|
||||
class DataNotPrepared(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BleCommand(Command):
|
||||
|
||||
@abstractmethod
|
||||
@@ -62,19 +69,22 @@ class BleCommand(Command):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
pass
|
||||
|
||||
async def execute_default(self, args, context):
|
||||
bless: BleStreamSecure = context['ble_sstream']
|
||||
|
||||
print(self.get_log_string())
|
||||
data = self.prepare_data(context)
|
||||
response = await bless.send_with_resp(data)
|
||||
if not response:
|
||||
return
|
||||
tlv_response = TLV.from_bytes(response)
|
||||
return CommandResultTLV(tlv_response)
|
||||
try:
|
||||
data = self.prepare_data(args, context)
|
||||
response = await bless.send_with_resp(data)
|
||||
if not response:
|
||||
return
|
||||
tlv_response = TLV.from_bytes(response)
|
||||
return CommandResultTLV(tlv_response)
|
||||
except DataNotPrepared as err:
|
||||
print('Command failed', err)
|
||||
|
||||
|
||||
class HelloCommand(BleCommand):
|
||||
@@ -85,7 +95,7 @@ class HelloCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Send round trip "Hello world!" message.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
return TLV(TcatTLVType.APPLICATION.value, bytes('Hello world!', 'ascii')).to_bytes()
|
||||
|
||||
|
||||
@@ -97,7 +107,7 @@ class CommissionCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Update the connected device with current dataset.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
dataset: ThreadDataset = context['dataset']
|
||||
dataset_bytes = dataset.to_bytes()
|
||||
return TLV(TcatTLVType.ACTIVE_DATASET.value, dataset_bytes).to_bytes()
|
||||
@@ -111,7 +121,7 @@ class DecommissionCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Stop Thread interface and decommission device from current network.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
return TLV(TcatTLVType.DECOMMISSION.value, bytes()).to_bytes()
|
||||
|
||||
|
||||
@@ -123,7 +133,7 @@ class GetDeviceIdCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Get unique identifier for the TCAT device.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
return TLV(TcatTLVType.GET_DEVICE_ID.value, bytes()).to_bytes()
|
||||
|
||||
|
||||
@@ -135,7 +145,7 @@ class GetExtPanIDCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Get extended PAN ID that is commissioned in the active dataset.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
return TLV(TcatTLVType.GET_EXT_PAN_ID.value, bytes()).to_bytes()
|
||||
|
||||
|
||||
@@ -147,7 +157,7 @@ class GetProvisioningUrlCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Get a URL for an application suited to commission the TCAT device.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
return TLV(TcatTLVType.GET_PROVISIONING_URL.value, bytes()).to_bytes()
|
||||
|
||||
|
||||
@@ -159,10 +169,115 @@ class GetNetworkNameCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Get the Thread network name that is commissioned in the active dataset.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
return TLV(TcatTLVType.GET_NETWORK_NAME.value, bytes()).to_bytes()
|
||||
|
||||
|
||||
class PresentHash(BleCommand):
|
||||
|
||||
def get_log_string(self) -> str:
|
||||
return 'Presenting hash.'
|
||||
|
||||
def get_help_string(self) -> str:
|
||||
return 'Present calculated hash.'
|
||||
|
||||
def prepare_data(self, args, context):
|
||||
type = args[0]
|
||||
code = None
|
||||
tlv_type = None
|
||||
if type == "pskd":
|
||||
code = bytes(args[1], 'utf-8')
|
||||
tlv_type = TcatTLVType.PRESENT_PSKD_HASH.value
|
||||
elif type == "pskc":
|
||||
code = bytes.fromhex(args[1])
|
||||
tlv_type = TcatTLVType.PRESENT_PSKC_HASH.value
|
||||
elif type == "install":
|
||||
code = bytes(args[1], 'utf-8')
|
||||
tlv_type = TcatTLVType.PRESENT_INSTALL_CODE_HASH.value
|
||||
else:
|
||||
raise DataNotPrepared("Hash code name incorrect.")
|
||||
bless: BleStreamSecure = context['ble_sstream']
|
||||
if bless.peer_public_key is None:
|
||||
raise DataNotPrepared("Peer certificate not present.")
|
||||
|
||||
if bless.peer_challenge is None:
|
||||
raise DataNotPrepared("Peer challenge not present.")
|
||||
|
||||
hash = hmac.new(code, digestmod=sha256)
|
||||
hash.update(bless.peer_challenge)
|
||||
hash.update(bless.peer_public_key)
|
||||
|
||||
data = TLV(tlv_type, hash.digest()).to_bytes()
|
||||
return data
|
||||
|
||||
|
||||
class GetPskdHash(Command):
|
||||
|
||||
def get_log_string(self) -> str:
|
||||
return 'Retrieving peer PSKd hash.'
|
||||
|
||||
def get_help_string(self) -> str:
|
||||
return 'Get calculated PSKd hash.'
|
||||
|
||||
async def execute_default(self, args, context):
|
||||
bless: BleStreamSecure = context['ble_sstream']
|
||||
|
||||
print(self.get_log_string())
|
||||
try:
|
||||
if bless.peer_public_key is None:
|
||||
print("Peer certificate not present.")
|
||||
return
|
||||
challenge_size = 8
|
||||
challenge = token_bytes(challenge_size)
|
||||
pskd = bytes(args[0], 'utf-8')
|
||||
data = TLV(TcatTLVType.GET_PSKD_HASH.value, challenge).to_bytes()
|
||||
response = await bless.send_with_resp(data)
|
||||
if not response:
|
||||
return
|
||||
tlv_response = TLV.from_bytes(response)
|
||||
if tlv_response.value != None:
|
||||
hash = hmac.new(pskd, digestmod=sha256)
|
||||
hash.update(challenge)
|
||||
hash.update(bless.peer_public_key)
|
||||
digest = hash.digest()
|
||||
if digest == tlv_response.value:
|
||||
print('Requested hash is valid.')
|
||||
else:
|
||||
print('Requested hash is NOT valid.')
|
||||
return CommandResultTLV(tlv_response)
|
||||
except DataNotPrepared as err:
|
||||
print('Command failed', err)
|
||||
|
||||
|
||||
class GetRandomNumberChallenge(Command):
|
||||
|
||||
def get_log_string(self) -> str:
|
||||
return 'Retrieving random challenge.'
|
||||
|
||||
def get_help_string(self) -> str:
|
||||
return 'Get the device random number challenge.'
|
||||
|
||||
async def execute_default(self, args, context):
|
||||
bless: BleStreamSecure = context['ble_sstream']
|
||||
|
||||
print(self.get_log_string())
|
||||
try:
|
||||
data = TLV(TcatTLVType.GET_RANDOM_NUMBER_CHALLENGE.value, bytes()).to_bytes()
|
||||
response = await bless.send_with_resp(data)
|
||||
if not response:
|
||||
return
|
||||
tlv_response = TLV.from_bytes(response)
|
||||
if tlv_response.value != None:
|
||||
if len(tlv_response.value) == 8:
|
||||
bless.peer_challenge = tlv_response.value
|
||||
else:
|
||||
print('Challenge format invalid.')
|
||||
return CommandResultNone()
|
||||
return CommandResultTLV(tlv_response)
|
||||
except DataNotPrepared as err:
|
||||
print('Command failed', err)
|
||||
|
||||
|
||||
class PingCommand(Command):
|
||||
|
||||
def get_help_string(self) -> str:
|
||||
@@ -202,7 +317,7 @@ class ThreadStartCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Enable thread interface.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
return TLV(TcatTLVType.THREAD_START.value, bytes()).to_bytes()
|
||||
|
||||
|
||||
@@ -214,7 +329,7 @@ class ThreadStopCommand(BleCommand):
|
||||
def get_help_string(self) -> str:
|
||||
return 'Disable thread interface.'
|
||||
|
||||
def prepare_data(self, context):
|
||||
def prepare_data(self, args, context):
|
||||
return TLV(TcatTLVType.THREAD_STOP.value, bytes()).to_bytes()
|
||||
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@ import shlex
|
||||
from argparse import ArgumentParser
|
||||
from ble.ble_stream_secure import BleStreamSecure
|
||||
from cli.base_commands import (HelpCommand, HelloCommand, CommissionCommand, DecommissionCommand, GetDeviceIdCommand,
|
||||
GetExtPanIDCommand, GetNetworkNameCommand, GetProvisioningUrlCommand, PingCommand,
|
||||
ThreadStateCommand, ScanCommand)
|
||||
GetPskdHash, GetExtPanIDCommand, GetNetworkNameCommand, GetProvisioningUrlCommand,
|
||||
PingCommand, GetRandomNumberChallenge, ThreadStateCommand, ScanCommand, PresentHash)
|
||||
from cli.dataset_commands import (DatasetCommand)
|
||||
from dataset.dataset import ThreadDataset
|
||||
from typing import Optional
|
||||
@@ -56,6 +56,9 @@ class CLI:
|
||||
'dataset': DatasetCommand(),
|
||||
'thread': ThreadStateCommand(),
|
||||
'scan': ScanCommand(),
|
||||
'random_challenge': GetRandomNumberChallenge(),
|
||||
'present_hash': PresentHash(),
|
||||
'peer_pskd_hash': GetPskdHash(),
|
||||
}
|
||||
self._context = {
|
||||
'ble_sstream': ble_sstream,
|
||||
|
||||
@@ -37,6 +37,11 @@ class TcatTLVType(Enum):
|
||||
GET_DEVICE_ID = 0x0B
|
||||
GET_EXT_PAN_ID = 0x0C
|
||||
GET_PROVISIONING_URL = 0x0D
|
||||
PRESENT_PSKD_HASH = 0x10
|
||||
PRESENT_PSKC_HASH = 0x11
|
||||
PRESENT_INSTALL_CODE_HASH = 0x12
|
||||
GET_RANDOM_NUMBER_CHALLENGE = 0x13
|
||||
GET_PSKD_HASH = 0x14
|
||||
ACTIVE_DATASET = 0x20
|
||||
DECOMMISSION = 0x60
|
||||
APPLICATION = 0x82
|
||||
|
||||
Reference in New Issue
Block a user