[tcat] add TCAT Commissioner / Device certs for Thread certification testing (#10211)

This commit is contained in:
Esko Dijk
2024-06-06 20:27:44 +02:00
committed by GitHub
parent 398df8c408
commit 3873c6fcd5
58 changed files with 923 additions and 147 deletions
+39 -32
View File
@@ -42,40 +42,47 @@
#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"
// DeviceCert1 default identity for TCAT certification testing.
// WARNING: storage of private keys in code or program memory MUST NOT be used in production.
// The below code is for testing purposes only. For production, secure key storage must be
// used to store private keys.
#define OT_CLI_TCAT_X509_CERT \
"-----BEGIN CERTIFICATE-----\n" \
"MIIB6TCCAZCgAwIBAgICNekwCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk\n" \
"IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ\n" \
"bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT\n" \
"MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU\n" \
"Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDExFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAx\n" \
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE11h/4vKZXVXv+1GDZo066spItloT\n" \
"dpCi0bux0jvpQSHLdQBIc+40zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdqNLMEkw\n" \
"HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC\n" \
"AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIHWu+Rd1\n" \
"VRlzrD8KbuyJcJFTXh2sQ9UIrFIA7+4e/GVcAiAVBdGqTxbt3TGkBBllpafAUB2/\n" \
"s0GJj7E33oblqy5eHQ==\n" \
"-----END CERTIFICATE-----\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_PRIV_KEY \
"-----BEGIN EC PRIVATE KEY-----\n" \
"MHcCAQEEIIqKM1QTlNaquV74W6Viz/ggXoLqlPOP6LagSyaFO3oUoAoGCCqGSM49\n" \
"AwEHoUQDQgAE11h/4vKZXVXv+1GDZo066spItloTdpCi0bux0jvpQSHLdQBIc+40\n" \
"zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdg==\n" \
"-----END EC PRIVATE KEY-----\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"
#define OT_CLI_TCAT_TRUSTED_ROOT_CERTIFICATE \
"-----BEGIN CERTIFICATE-----\n" \
"MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM\n" \
"HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg\n" \
"R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD\n" \
"VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV\n" \
"BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl\n" \
"YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw\n" \
"CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL\n" \
"x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ\n" \
"0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P\n" \
"AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo\n" \
"hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu\n" \
"eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=\n" \
"-----END CERTIFICATE-----\n"
namespace ot {
+11 -11
View File
@@ -231,7 +231,7 @@ void SecureTransport::HandleReceive(Message &aMessage, const Ip6::MessageInfo &a
}
else
{
// Once DTLS session is started, communicate only with a peer.
// Once DTLS session is started, communicate only with a single peer.
VerifyOrExit((mMessageInfo.GetPeerAddr() == aMessageInfo.GetPeerAddr()) &&
(mMessageInfo.GetPeerPort() == aMessageInfo.GetPeerPort()));
}
@@ -725,28 +725,28 @@ Error SecureTransport::GetThreadAttributeFromCertificate(const mbedtls_x509_crt
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
// Data must be octet string type, see https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
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))
// TODO: extensions with isCritical == 1 that are unknown should lead to rejection of the entire cert.
if (extnOid.len == sizeof(oid) && memcmp(extnOid.p, oid, sizeof(oid)) == 0)
{
continue;
}
if (memcmp(extnOid.p, oid, sizeof(oid)) == 0)
{
*aAttributeLength = len;
// per RFC 5280, octet string must contain ASN.1 Type Length Value octets
VerifyOrExit(len >= 2, error = kErrorParse);
VerifyOrExit(*(p + 1) == len - 2, error = kErrorParse); // check TLV Length, not Type.
*aAttributeLength = len - 2; // strip the ASN.1 Type Length bytes from embedded TLV
if (aAttributeBuffer != nullptr)
{
VerifyOrExit(len <= attributeBufferSize, error = kErrorNoBufs);
memcpy(aAttributeBuffer, p, len);
VerifyOrExit(*aAttributeLength <= attributeBufferSize, error = kErrorNoBufs);
memcpy(aAttributeBuffer, p + 2, *aAttributeLength);
}
error = kErrorNone;
break;
}
p += len;
}
exit:
+1
View File
@@ -240,6 +240,7 @@ public:
enum TcatCertificateAttribute
{
kCertificateDomainName = 1,
kCertificateThreadVersion = 2,
kCertificateAuthorizationField = 3,
kCertificateNetworkName = 4,
kCertificateExtendedPanId = 5,
+11 -1
View File
@@ -337,7 +337,14 @@ void BleSecure::HandleTlsConnected(bool aConnected)
if (mTcatAgent.IsEnabled())
{
IgnoreReturnValue(mTcatAgent.Connected(mTls));
Error err = mTcatAgent.Connected(mTls);
if (err != kErrorNone)
{
mTls.Close();
LogWarn("Rejected TCAT Commissioner, error: %s", ErrorToString(err));
ExitNow();
}
}
}
else
@@ -352,6 +359,9 @@ void BleSecure::HandleTlsConnected(bool aConnected)
}
mConnectCallback.InvokeIfSet(&GetInstance(), aConnected, true);
exit:
return;
}
void BleSecure::HandleTlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
+69 -35
View File
@@ -35,40 +35,43 @@
#include <openthread/ble_secure.h>
#define OT_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_TCAT_X509_CERT \
"-----BEGIN CERTIFICATE-----\n" \
"MIIB6TCCAZCgAwIBAgICNekwCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk\n" \
"IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ\n" \
"bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT\n" \
"MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU\n" \
"Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDExFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAx\n" \
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE11h/4vKZXVXv+1GDZo066spItloT\n" \
"dpCi0bux0jvpQSHLdQBIc+40zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdqNLMEkw\n" \
"HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC\n" \
"AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIHWu+Rd1\n" \
"VRlzrD8KbuyJcJFTXh2sQ9UIrFIA7+4e/GVcAiAVBdGqTxbt3TGkBBllpafAUB2/\n" \
"s0GJj7E33oblqy5eHQ==\n" \
"-----END CERTIFICATE-----\n"
#define OT_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_TCAT_PRIV_KEY \
"-----BEGIN EC PRIVATE KEY-----\n" \
"MHcCAQEEIIqKM1QTlNaquV74W6Viz/ggXoLqlPOP6LagSyaFO3oUoAoGCCqGSM49\n" \
"AwEHoUQDQgAE11h/4vKZXVXv+1GDZo066spItloTdpCi0bux0jvpQSHLdQBIc+40\n" \
"zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdg==\n" \
"-----END EC PRIVATE KEY-----\n"
#define OT_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"
#define OT_TCAT_TRUSTED_ROOT_CERTIFICATE \
"-----BEGIN CERTIFICATE-----\n" \
"MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM\n" \
"HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg\n" \
"R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD\n" \
"VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV\n" \
"BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl\n" \
"YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw\n" \
"CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL\n" \
"x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ\n" \
"0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P\n" \
"AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo\n" \
"hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu\n" \
"eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=\n" \
"-----END CERTIFICATE-----\n"
namespace ot {
@@ -104,9 +107,14 @@ static void HandleBleSecureConnect(otInstance *aInstance, bool aConnected, bool
void TestTcat(void)
{
const char kPskdVendor[] = "J01NM3";
const char kUrl[] = "dummy_url";
constexpr uint16_t kConnectionId = 0;
const char kPskdVendor[] = "J01NM3";
const char kUrl[] = "dummy_url";
constexpr uint16_t kConnectionId = 0;
const int kCertificateThreadVersion = 2;
const int kCertificateAuthorizationField = 3;
const uint8_t expectedTcatAuthField[5] = {0x20, 0x01, 0x01, 0x01, 0x01};
uint8_t attributeBuffer[8];
size_t attributeLen;
TestBleSecure ble;
Instance *instance = testInitInstance();
@@ -129,11 +137,21 @@ void TestTcat(void)
SuccessOrQuit(otBleSecureTcatStart(instance, nullptr));
// Validate connection callbacks when platform informs that peer has connected/disconnected
VerifyOrQuit(!otBleSecureIsConnected(instance));
otPlatBleGapOnConnected(instance, kConnectionId);
VerifyOrQuit(!ble.IsConnected() && ble.IsBleConnectionOpen());
otPlatBleGapOnDisconnected(instance, kConnectionId);
VerifyOrQuit(!ble.IsConnected() && !ble.IsBleConnectionOpen());
// Verify that Thread-attribute parsing isn't available yet when not connected as client or server.
attributeLen = sizeof(attributeBuffer);
VerifyOrQuit(otBleSecureGetThreadAttributeFromPeerCertificate(instance, kCertificateAuthorizationField,
&attributeBuffer[0],
&attributeLen) == kErrorInvalidState);
attributeLen = sizeof(attributeBuffer);
VerifyOrQuit(otBleSecureGetThreadAttributeFromOwnCertificate(
instance, kCertificateThreadVersion, &attributeBuffer[0], &attributeLen) == kErrorInvalidState);
// Validate connection callbacks when calling `otBleSecureDisconnect()`
otPlatBleGapOnConnected(instance, kConnectionId);
VerifyOrQuit(!ble.IsConnected() && ble.IsBleConnectionOpen());
@@ -143,6 +161,22 @@ void TestTcat(void)
// Validate TLS connection can be started only when peer is connected
otPlatBleGapOnConnected(instance, kConnectionId);
SuccessOrQuit(otBleSecureConnect(instance));
VerifyOrQuit(otBleSecureIsConnectionActive(instance));
// Once in TLS client connecting state, the below cert eval functions are available.
// Test that the Thread-specific attributes can be decoded properly.
attributeLen = 1;
SuccessOrQuit(otBleSecureGetThreadAttributeFromOwnCertificate(instance, kCertificateThreadVersion,
&attributeBuffer[0], &attributeLen));
VerifyOrQuit(attributeLen == 1 && attributeBuffer[0] >= kThreadVersion1p4);
static_assert(5 == sizeof(expectedTcatAuthField), "expectedTcatAuthField size incorrect for test");
attributeLen = 5;
SuccessOrQuit(otBleSecureGetThreadAttributeFromOwnCertificate(instance, kCertificateAuthorizationField,
&attributeBuffer[0], &attributeLen));
VerifyOrQuit(attributeLen == 5 && memcmp(&expectedTcatAuthField, &attributeBuffer, attributeLen) == 0);
// Validate TLS connection can be started only when peer is connected
otBleSecureDisconnect(instance);
VerifyOrQuit(otBleSecureConnect(instance) == kErrorInvalidState);
@@ -1,4 +1,4 @@
# BBTC X.509 certificates generation
# TCAT X.509 certificates generation
---
@@ -8,9 +8,24 @@ TCAT uses X.509 Certificate Extensions to provide permissions with certificates.
Extensions were introduced in version 3 of the X.509 standard for certificates. They allow certificates to be customised to applications by supporting the addition of arbitrary fields in the certificate. Each extension, identified by its OID (Object Identifier), is marked as "Critical" or "Non-Critical", and includes the extension-specific data.
## Certificates generation
## Certificates generation (by script)
Thread uses Elliptic Curve Cryptography (ECC), so we use the `ecparam` `openssl` argument to generate the keys.
The directory `auth-generate` contains example scripts and a Makefile to generate TCAT Commissioner certificates and TCAT Device certificates. The scripts can also handle multiple CAs, and provide the most detailed view on how to generate these certificates.
To generate all certificates:
```
cd auth-generate
make
```
This will create an `output` directory with subdirectories for each of the created identities. Each subdirectory can be used as a value for the BBTC Commissioner `--cert_path` argument, if needed.
NOTE: the directory `auth-generate/ca` contains an example CA certificate and private key (for signing). Other CAs can be added in here. This CA is not the same CA used for the TCAT Commissioner and Device identities in the `auth` and `auth-cert` directories! The CA for the latter is privately maintained by Thread Group.
## Certificates generation (manually)
Thread TCAT uses Elliptic Curve Cryptography (ECC), so we use the `ecparam` `openssl` argument to generate the keys.
### Root certificate
@@ -20,19 +35,19 @@ Thread uses Elliptic Curve Cryptography (ECC), so we use the `ecparam` `openssl`
openssl ecparam -genkey -name prime256v1 -out ca_key.pem
```
1. We can then generate the **.csr** (certificate signing request) file, which will contain all the parameters of our final certificate:
2. We can then generate the **.csr** (certificate signing request) file, which will contain all the parameters of our final certificate:
```
openssl req -new -sha256 -key ca_key.pem -out ca.csr
```
1. Finally, we can generate the certificate itself:
3. Finally, we can generate the certificate itself:
```
openssl req -x509 -sha256 -days 365 -key ca_key.pem -in ca.csr -out ca_cert.pem
```
1. See the generated certificate using
4. See the generated certificate using
```
openssl x509 -in ca_cert.pem -text -noout
@@ -46,25 +61,25 @@ openssl x509 -in ca_cert.pem -text -noout
openssl ecparam -genkey -name prime256v1 -out commissioner_key.pem
```
1. Specify additional extensions when generating the .csr (see [sample configuration](#Configurations)):
2. Specify additional extensions when generating the .csr (see [sample configuration](#Configurations)):
```
openssl req -new -sha256 -key commissioner_key.pem -out commissioner.csr -config commissioner.cnf
```
1. Generate the certificate:
3. Generate the certificate:
```
openssl x509 -req -in commissioner.csr -CA ca_cert.pem -CAkey ca_key.pem -out commissioner_cert.pem -days 365 -sha256 -copy_extensions copy
```
1. View the generated certificate using:
4. View the generated certificate using:
```
openssl x509 -in commissioner_cert.pem -text -noout
```
1. View parsed certificate extensions using:
5. View parsed certificate extensions using:
```
openssl asn1parse -inform PEM -in commissioner_cert.pem
@@ -72,7 +87,7 @@ openssl asn1parse -inform PEM -in commissioner_cert.pem
## Configurations
file: `commissioner.cnf` (line `1.3.6.1.4.1.44970.3 = DER:21:01:01:01:01` specifies permissions (all))
file: `commissioner.cnf` (line `1.3.6.1.4.1.44970.3 = DER:21:01:01:01:01` specifies permissions (all)) See scripts in `auth-generate` directory for more details.
```
[ req ]
@@ -85,7 +100,7 @@ req_extensions = v3_req
CN = Commissioner
[v3_req]
1.3.6.1.4.1.44970.3 = DER:21:01:01:01:01
1.3.6.1.4.1.44970.3 = DER:04:05:21:01:01:01:01
authorityKeyIdentifier = none
subjectKeyIdentifier = none
```
+29 -5
View File
@@ -2,7 +2,7 @@
## Overview
This is a Python implementation of Bluetooth-Based Thread Commissioning client, based on Thread's TCAT (Thread Commissioning over Authenticated TLS) functionality.
This is a Python implementation of Bluetooth-Based Thread Commissioning (BBTC) client, based on Thread's TCAT (Thread Commissioning over Authenticated TLS) functionality.
## Installation
@@ -12,8 +12,6 @@ If you don't have the poetry module installed (check with `poetry --version`), i
python3 -m pip install poetry
```
Thread uses Elliptic Curve Cryptography (ECC), so we use the `ecparam` `openssl` argument to generate the keys.
```
poetry install
```
@@ -22,6 +20,12 @@ This will install all the required modules to a virtual environment, which can b
## Usage
To see the supported commandline arguments of BBTC client, use:
```
poetry run python3 bbtc.py --help
```
In order to connect to a TCAT device, enter the project directory and run:
```bash
@@ -43,7 +47,27 @@ poetry run python3 bbtc.py --name 'Thread BLE'
The application will connect to the first matching device discovered and set up a secure TLS channel. The user is then presented with the CLI.
## Commands
## Usage with a specific TCAT Commissioner identity
The TCAT Commissioner's certificate specifies what permissions it has obtained for specific features of managing a TCAT Device. By default, the identity in the `auth` directory is used. In order to use a different TCAT Commissioner certificate (identity), use the `--cert_path` argument, as follows:
```bash
poetry run python3 bbtc.py --cert_path <certs-path> {<device specifier> | --scan}
```
where `<certs-path>` is the directory where the private key, certificate, and CA certificate of the TCAT Commissioner are stored.
For example to use a pre-configured identity `CommCert2` (related to Thread certification tests):
```
poetry run python3 bbtc.py --cert_path ./auth-cert/CommCert2 --name 'Thread BLE'
```
The `auth-cert` directory contains some other identities too, for testing purposes. Refer to Thread TCAT test plan documents for details.
See [GENERATING_CERTIFICATES.md](GENERATING_CERTIFICATES.md) for details on generating own certificates.
## TCAT Commissioner CLI Commands
The application supports the following interactive CLI commands:
@@ -53,4 +77,4 @@ The application supports the following interactive CLI commands:
- `thread stop` - Disable Thread interface.
- `hello` - Send "hello world" application data and read the response.
- `exit` - Close the connection and exit.
- `dataset` - View and manipulate current dataset. See `dataset help` for more information.
- `dataset` - View and manipulate current dataset. Use `dataset help` for more information.
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM
HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg
R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD
VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV
BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl
YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw
CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL
x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ
0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P
AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo
hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu
eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=
-----END CERTIFICATE-----
@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIB1TCCAXugAwIBAgIDDhqDMAoGCCqGSM49BAMCMHExJjAkBgNVBAMMHVRocmVh
ZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQgR3JvdXAg
SW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJV
UzAeFw0yNDA1MDcwOTM5NDVaFw0yNDA1MjEwOTM5NDVaMDoxHzAdBgNVBAMMFlRD
QVQgRXhhbXBsZSBDb21tQ2VydDExFzAVBgNVBAUTDjM1MjMtMTU0My0wMDAxMFkw
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHZq8vhZ816JEhgqe6zZKioMDFbrKEkJl
nRfSJEdfXZYSS94wUFKHzEHcAY3PU4IPTGnF5pusUE41rJa2n8vC76M5MDcwHwYD
VR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwFAYJKwYBBAGC3yoDBAcEBSEB
AQEBMAoGCCqGSM49BAMCA0gAMEUCIHeEfOOEX3jya2+bJMoGEEcFE56eUOjaz9aV
Tt1soEG8AiEA0taHGNpGgjE/b4kLW27dd8H+D/H5kNbq9Jlm9ct078Y=
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIPUEbXoKX2i4zyuvq7IRTVIlMpzf3t3pmlLc4uQprrq6oAoGCCqGSM49
AwEHoUQDQgAEHZq8vhZ816JEhgqe6zZKioMDFbrKEkJlnRfSJEdfXZYSS94wUFKH
zEHcAY3PU4IPTGnF5pusUE41rJa2n8vC7w==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM
HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg
R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD
VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV
BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl
YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw
CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL
x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ
0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P
AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo
hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu
eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=
-----END CERTIFICATE-----
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICLTCCAdSgAwIBAgIDDhqEMAoGCCqGSM49BAMCMHExJjAkBgNVBAMMHVRocmVh
ZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQgR3JvdXAg
SW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJV
UzAeFw0yNDA1MDcwOTM5NDVaFw0yNDA1MjEwOTM5NDVaMDoxHzAdBgNVBAMMFlRD
QVQgRXhhbXBsZSBDb21tQ2VydDIxFzAVBgNVBAUTDjM1MjMtMTU0My0wMDAyMFkw
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBIvT4u0YQu5dka6tscIuV2DF/TpwDmWB
u3bCMa9KF80zbEjkg9Z9mf31Ia6jXjGD5cUosuEpyW8TlQK5WMLfmqOBkTCBjjAf
BgNVHSMEGDAWgBRfqxspaIih1LQxqIZh5+dmWe34GTAcBgkrBgEEAYLfKgEEDxYN
RGVmYXVsdERvbWFpbjAUBgkrBgEEAYLfKgMEBwQFIR8/Pz8wHgYJKwYBBAGC3yoE
BBEMD09wZW5UaHJlYWQtYzY0ZTAXBgkrBgEEAYLfKgUECgQI7xOYwv1QS2cwCgYI
KoZIzj0EAwIDRwAwRAIgHT2+7Uy47WApbpRHzZxOBskSielc8v/iQ2Jh+ZCmhdMC
IDx4gIX537LWrR4AwRVxAbZgYc7dI0r60IYF1nNstifq
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINQLE/8iWwfE4OCnANeNL2hUPFIOa5uHjfw+eXatusAuoAoGCCqGSM49
AwEHoUQDQgAEBIvT4u0YQu5dka6tscIuV2DF/TpwDmWBu3bCMa9KF80zbEjkg9Z9
mf31Ia6jXjGD5cUosuEpyW8TlQK5WMLfmg==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICHjCCAcSgAwIBAgIBATAKBggqhkjOPQQDAjBmMR0wGwYDVQQDDBRUQ0FUIEV4
YW1wbGUgQ0EgJ2NhJzEUMBIGA1UECgwLRXhhbXBsZSBJbmMxFTATBgNVBAcMDEV4
YW1wbGUgQ2l0eTELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVTMB4XDTI0MDUwNTE5
MTAyMloXDTQ0MDQzMDE5MTAyMlowZjEdMBsGA1UEAwwUVENBVCBFeGFtcGxlIENB
ICdjYScxFDASBgNVBAoMC0V4YW1wbGUgSW5jMRUwEwYDVQQHDAxFeGFtcGxlIENp
dHkxCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABFncszwFxinmWPeDoRwFlx8yX0CIxksmjs5YC/ThBcNkqFA53CyjxsHz
wFEn7jMhJM7MzQzNBx5AbAy6ruJ9uf+jYzBhMB8GA1UdEQQYMBaBFGNhLWFkbWlu
QGV4YW1wbGUub3JnMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G
A1UdDgQWBBTgTKehLD14MpkRU+S6azYhYsAkKjAKBggqhkjOPQQDAgNIADBFAiA2
Wp9JGbwiqbW0l0fTS+AKdp6xFXkmuePftuUTsnMKcgIhAPdC1zdx8fHPoTnRLpiH
Pt2/QkcSashR9zOp9MrBnRPb
-----END CERTIFICATE-----
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICJDCCAcmgAwIBAgIDDhqFMAoGCCqGSM49BAMCMGYxHTAbBgNVBAMMFFRDQVQg
RXhhbXBsZSBDQSAnY2EnMRQwEgYDVQQKDAtFeGFtcGxlIEluYzEVMBMGA1UEBwwM
RXhhbXBsZSBDaXR5MQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMwHhcNMjQwNTA3
MDkzOTQ1WhcNMjQwNTIxMDkzOTQ1WjA6MR8wHQYDVQQDDBZUQ0FUIEV4YW1wbGUg
Q29tbUNlcnQzMRcwFQYDVQQFEw4zNTIzLTE1NDMtMDAwMzBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABBMQUVTNWNZ4cFKOFHFdvrcWvDTRU98NyLfWgU28iZTE+sP8
NUdJaom8LbOPmheVBJIH7tn6P8n5s6g6XpDCvTOjgZEwgY4wHwYDVR0jBBgwFoAU
4EynoSw9eDKZEVPkums2IWLAJCowHAYJKwYBBAGC3yoBBA8WDURlZmF1bHREb21h
aW4wFAYJKwYBBAGC3yoDBAcEBSEBAQEBMB4GCSsGAQQBgt8qBAQRDA9PcGVuVGhy
ZWFkLWM2NGUwFwYJKwYBBAGC3yoFBAoECO8TmML9UEtnMAoGCCqGSM49BAMCA0kA
MEYCIQCiVqJRirJq53f2EdbsaEXsquRa5uixF6BlHlwsT/zKdQIhAPytUgQLa0aO
UjrzO+V2JIpJvboAZKYB45x56IfWrNZb
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIE0aPRr+B9R9MZ9SKadjEhIzV7LeoDB4E1Hkhd1mJuzPoAoGCCqGSM49
AwEHoUQDQgAEExBRVM1Y1nhwUo4UcV2+txa8NNFT3w3It9aBTbyJlMT6w/w1R0lq
ibwts4+aF5UEkgfu2fo/yfmzqDpekMK9Mw==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM
HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg
R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD
VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV
BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl
YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw
CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL
x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ
0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P
AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo
hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu
eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=
-----END CERTIFICATE-----
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICLDCCAdOgAwIBAgIDDhqGMAoGCCqGSM49BAMCMHExJjAkBgNVBAMMHVRocmVh
ZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQgR3JvdXAg
SW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJV
UzAeFw0yNDA1MDcwOTM5NDVaFw0yNDA1MjEwOTM5NDVaMDoxHzAdBgNVBAMMFlRD
QVQgRXhhbXBsZSBDb21tQ2VydDQxFzAVBgNVBAUTDjM1MjMtMTU0My0wMDA0MFkw
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgIgp7nkc36xTPKv0lySnQYCyw/SDHjDI
5iRDukFYEVBwRQ1CI20HDZ3iqf/MxXZb3UcLZ4aYylSHJeq8I5jX86OBkDCBjTAf
BgNVHSMEGDAWgBRfqxspaIih1LQxqIZh5+dmWe34GTAaBgkrBgEEAYLfKgEEDRYL
T3RoZXJEb21haW4wFAYJKwYBBAGC3yoDBAcEBSEhBQkRMB8GCSsGAQQBgt8qBAQS
DBBPdGhlclRocmVhZC1jNjRlMBcGCSsGAQQBgt8qBQQKBAjvE5jC/VBLaDAKBggq
hkjOPQQDAgNHADBEAiApGUDXoCYeY8jRTyEwgnm6GuMPuGOBHE2daLOaHd/TtQIg
JfNCGBbf8gQIUfH3bs5OheMj0BDzXmP66nsuF3mnyps=
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIM1pKneJbjUDWNpRPfygf1Wfi/FkzQHv+gN8Co7f+6kioAoGCCqGSM49
AwEHoUQDQgAEgIgp7nkc36xTPKv0lySnQYCyw/SDHjDI5iRDukFYEVBwRQ1CI20H
DZ3iqf/MxXZb3UcLZ4aYylSHJeq8I5jX8w==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM
HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg
R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD
VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV
BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl
YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw
CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL
x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ
0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P
AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo
hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu
eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=
-----END CERTIFICATE-----
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB6TCCAZCgAwIBAgICNekwCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk
IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ
bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT
MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU
Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDExFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAx
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE11h/4vKZXVXv+1GDZo066spItloT
dpCi0bux0jvpQSHLdQBIc+40zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdqNLMEkw
HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC
AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIHWu+Rd1
VRlzrD8KbuyJcJFTXh2sQ9UIrFIA7+4e/GVcAiAVBdGqTxbt3TGkBBllpafAUB2/
s0GJj7E33oblqy5eHQ==
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIqKM1QTlNaquV74W6Viz/ggXoLqlPOP6LagSyaFO3oUoAoGCCqGSM49
AwEHoUQDQgAE11h/4vKZXVXv+1GDZo066spItloTdpCi0bux0jvpQSHLdQBIc+40
zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdg==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB6TCCAZCgAwIBAgICNekwCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk
IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ
bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT
MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU
Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDExFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAx
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE11h/4vKZXVXv+1GDZo066spItloT
dpCi0bux0jvpQSHLdQBIc+40zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdqNLMEkw
HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC
AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIHWu+Rd1
VRlzrD8KbuyJcJFTXh2sQ9UIrFIA7+4e/GVcAiAVBdGqTxbt3TGkBBllpafAUB2/
s0GJj7E33oblqy5eHQ==
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIqKM1QTlNaquV74W6Viz/ggXoLqlPOP6LagSyaFO3oUoAoGCCqGSM49
AwEHoUQDQgAE11h/4vKZXVXv+1GDZo066spItloTdpCi0bux0jvpQSHLdQBIc+40
zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdg==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM
HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg
R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD
VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV
BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl
YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw
CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL
x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ
0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P
AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo
hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu
eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=
-----END CERTIFICATE-----
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB6TCCAZCgAwIBAgICNeowCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk
IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ
bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT
MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU
Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDIxFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAy
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE30GMkqSBj3049NtK6G/MRTqcDxpm
i1LxTpSxFIB7P9HVoVM7Cd9X6bBUp5FrSZI+KHtX2HKtXzmzsdJ3gxAmi6NLMEkw
HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC
AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIAbZzVbC
toNYgSWSgxRGzLRo1YJANqRC7yRtJNKTdQ1ZAiAlgGxEW2lkxCAGPUK1m9Wbb4kl
7AhBhYlK6vZz/omTsQ==
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIP7Al8tJA3QgwD3yIuOSEmJkT3GlWmcHQ59JfhZOjSdUoAoGCCqGSM49
AwEHoUQDQgAE30GMkqSBj3049NtK6G/MRTqcDxpmi1LxTpSxFIB7P9HVoVM7Cd9X
6bBUp5FrSZI+KHtX2HKtXzmzsdJ3gxAmiw==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB6TCCAZCgAwIBAgICNeowCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk
IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ
bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT
MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU
Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDIxFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAy
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE30GMkqSBj3049NtK6G/MRTqcDxpm
i1LxTpSxFIB7P9HVoVM7Cd9X6bBUp5FrSZI+KHtX2HKtXzmzsdJ3gxAmi6NLMEkw
HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC
AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIAbZzVbC
toNYgSWSgxRGzLRo1YJANqRC7yRtJNKTdQ1ZAiAlgGxEW2lkxCAGPUK1m9Wbb4kl
7AhBhYlK6vZz/omTsQ==
-----END CERTIFICATE-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIP7Al8tJA3QgwD3yIuOSEmJkT3GlWmcHQ59JfhZOjSdUoAoGCCqGSM49
AwEHoUQDQgAE30GMkqSBj3049NtK6G/MRTqcDxpmi1LxTpSxFIB7P9HVoVM7Cd9X
6bBUp5FrSZI+KHtX2HKtXzmzsdJ3gxAmiw==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,48 @@
#
# 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.
#
# Makefile for creating TCAT example certificates (except CA).
# Select here which named CAs from the 'ca' directory are used for signing.
#ca = TcatCertCa # for example
otherCa = ca
ca = ca
all: DeviceCert1 DeviceCert2 CommCert1 CommCert2 CommCert3 CommCert4
DeviceCert1 DeviceCert2: ext/DeviceCert1.ext ext/DeviceCert2.ext
./create-cert-tcat-device.sh $@ $(ca)
CommCert1 CommCert2 CommCert4: ext/CommCert1.ext ext/CommCert2.ext ext/CommCert4.ext
./create-cert-tcat-commissioner.sh $@ $(ca)
CommCert3: ext/CommCert3.ext
./create-cert-tcat-commissioner.sh $@ $(otherCa)
clean:
rm -rf ./output
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICHjCCAcSgAwIBAgIBATAKBggqhkjOPQQDAjBmMR0wGwYDVQQDDBRUQ0FUIEV4
YW1wbGUgQ0EgJ2NhJzEUMBIGA1UECgwLRXhhbXBsZSBJbmMxFTATBgNVBAcMDEV4
YW1wbGUgQ2l0eTELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVTMB4XDTI0MDUwNTE5
MTAyMloXDTQ0MDQzMDE5MTAyMlowZjEdMBsGA1UEAwwUVENBVCBFeGFtcGxlIENB
ICdjYScxFDASBgNVBAoMC0V4YW1wbGUgSW5jMRUwEwYDVQQHDAxFeGFtcGxlIENp
dHkxCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABFncszwFxinmWPeDoRwFlx8yX0CIxksmjs5YC/ThBcNkqFA53CyjxsHz
wFEn7jMhJM7MzQzNBx5AbAy6ruJ9uf+jYzBhMB8GA1UdEQQYMBaBFGNhLWFkbWlu
QGV4YW1wbGUub3JnMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G
A1UdDgQWBBTgTKehLD14MpkRU+S6azYhYsAkKjAKBggqhkjOPQQDAgNIADBFAiA2
Wp9JGbwiqbW0l0fTS+AKdp6xFXkmuePftuUTsnMKcgIhAPdC1zdx8fHPoTnRLpiH
Pt2/QkcSashR9zOp9MrBnRPb
-----END CERTIFICATE-----
+60
View File
@@ -0,0 +1,60 @@
#!/bin/bash
#
# 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.
#
# Create the certificate of an example CA for TCAT. This single CA creates both the
# TCAT Device certificates, as well as the TCAT Commissioner certificates that
# work for those TCAT Devices.
if [ $# -ne 1 ]; then
echo "Usage: ./create-cert-ca.sh <NameOfCA>"
exit 1
fi
set -eu
# days certificate is valid
((VALIDITY = 20 * 365))
NAME=${1}
# create csr
openssl req -new -key "ca/${NAME}_key.pem" -out "${NAME}.csr" \
-subj "/CN=TCAT Example CA '${NAME}'/O=Example Inc/L=Example City/ST=CA/C=US"
# self-sign csr
mkdir -p output
openssl x509 -set_serial 0x01 -extfile "ext/${NAME}.ext" \
-extensions "${NAME}" -req -in "${NAME}.csr" \
-signkey "ca/${NAME}_key.pem" -out "ca/${NAME}_cert.pem" \
-days "${VALIDITY}" -sha256
# delete temp files
rm -f "${NAME}.csr"
# show result
openssl x509 -text -in "ca/${NAME}_cert.pem"
@@ -0,0 +1,67 @@
#!/bin/bash
#
# 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.
#
# Script to generate a TCAT Commissioner X509v3 certificate.
if [ $# -ne 2 ]; then
echo "Usage: ./create-cert-tcat-commissioner.sh <NameOfCommissioner> <NameOfCA>"
exit 1
fi
set -eu
# number of days certificate is valid
((VALIDITY = "14"))
echo "create-cert-tcat-commissioner.sh - Using validity param -days ${VALIDITY}"
NAME=${1}
CANAME=${2}
((ID = ${NAME:0-1}))
CACERTFILE="ca/${CANAME}_cert.pem"
echo " TCAT commissioner name : ${NAME}"
echo " TCAT commissioner CA name: ${CANAME}"
echo " Numeric serial ID : ${ID}"
# create csr for TCAT Commissioner
openssl req -new -key "keys/${NAME}_key.pem" -out "${NAME}.csr" -subj \
"/CN=TCAT Example ${NAME}/serialNumber=3523-1543-000${ID}"
# sign csr by CA
mkdir -p "output/${NAME}"
openssl x509 -set_serial "92429${ID}" -CAform PEM -CA "${CACERTFILE}" \
-CAkey "ca/${CANAME}_key.pem" -extfile "ext/${NAME}.ext" -extensions \
"${NAME}" -req -in "${NAME}.csr" -out "output/${NAME}/commissioner_cert.pem" \
-days "${VALIDITY}" -sha256
# delete temp files
rm -f "${NAME}.csr"
# copy supporting files, for immediate use by TCAT Commissioner as 'cert_path'
cp "${CACERTFILE}" "output/${NAME}/ca_cert.pem"
cp "keys/${NAME}_key.pem" "output/${NAME}/commissioner_key.pem"
@@ -0,0 +1,76 @@
#!/bin/bash
#
# 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.
#
# Script to generate a TCAT Device X509v3 certificate.
if [ $# -ne 2 ]; then
echo "Usage: ./create-cert-tcat-device.sh <NameOfDevice> <NameOfCA>"
exit 1
fi
set -eu
# days certificate is valid
SECONDS1=$(date +%s) # time now
SECONDS2=$(date --date="2999-12-31 23:59:59Z" +%s) # target end time
((VALIDITY = "(${SECONDS2}-${SECONDS1})/(24*3600)"))
echo "create-cert-tcat-device.sh - Using validity param -days ${VALIDITY}"
NAME="${1}"
CANAME="${2}"
CACERTFILE="ca/${CANAME}_cert.pem"
((ID = ${NAME:0-1}))
((SERIAL = 13800 + ID))
echo " TCAT device name : ${NAME}"
echo " TCAT device CA name: ${CANAME}"
echo " Numeric serial ID : ${ID}"
# create csr for device.
# conform to 802.1AR guidelines, using only CN + serialNumber when
# manufacturer is already present as CA. CN is not even mandatory, but just good practice.
openssl req -new -key "keys/${NAME}_key.pem" -out "${NAME}.csr" -subj \
"/CN=TCAT Example ${NAME}/serialNumber=4723-9833-000${ID}"
# sign csr by CA
mkdir -p "output/${NAME}"
openssl x509 -set_serial "${SERIAL}" -CAform PEM -CA "${CACERTFILE}" \
-CAkey "ca/${CANAME}_key.pem" -extfile "ext/${NAME}.ext" -extensions \
"${NAME}" -req -in "${NAME}.csr" -out "output/${NAME}/device_cert.pem" \
-days "${VALIDITY}" -sha256
# delete temp files
rm -f "${NAME}.csr"
# copy supporting files, for immediate use by TCAT Commissioner as 'cert_path'.
# Normally a Commissioner must not use Device certs, but for testing purposes this
# option is provided here.
cp "output/${NAME}/device_cert.pem" "output/${NAME}/commissioner_cert.pem"
cp "${CACERTFILE}" "output/${NAME}/ca_cert.pem"
cp "keys/${NAME}_key.pem" "output/${NAME}/commissioner_key.pem"
cp "keys/${NAME}_key.pem" "output/${NAME}/device_key.pem"
@@ -0,0 +1,12 @@
# This file contains X509v3 extension definitions for OpenSSL
# certificate generation.
[ CommCert1 ]
subjectKeyIdentifier = none
authorityKeyIdentifier = keyid
# Include TCAT specified fields
# Because ASN1:OCTETSTRING doesn't work with hex input, we use raw DER here. Tag 0x04 is OCTETSTRING.
# See https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#
1.3.6.1.4.1.44970.3 = DER:04:05:21:01:01:01:01
@@ -0,0 +1,15 @@
# This file contains X509v3 extension definitions for OpenSSL
# certificate generation.
[ CommCert2 ]
subjectKeyIdentifier = none
authorityKeyIdentifier = keyid
# Include TCAT specified fields
# Because ASN1:OCTETSTRING doesn't work with hex input, we use raw DER here. Tag 0x04 is OCTETSTRING.
# See https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#
1.3.6.1.4.1.44970.1 = ASN1:IA5STRING:DefaultDomain
1.3.6.1.4.1.44970.3 = DER:04:05:21:1F:3F:3F:3F
1.3.6.1.4.1.44970.4 = ASN1:UTF8STRING:OpenThread-c64e
1.3.6.1.4.1.44970.5 = DER:04:08:ef:13:98:c2:fd:50:4b:67
@@ -0,0 +1,15 @@
# This file contains X509v3 extension definitions for OpenSSL
# certificate generation.
[ CommCert3 ]
subjectKeyIdentifier = none
authorityKeyIdentifier = keyid
# Include TCAT specified fields
# Because ASN1:OCTETSTRING doesn't work with hex input, we use raw DER here. Tag 0x04 is OCTETSTRING.
# See https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#
1.3.6.1.4.1.44970.1 = ASN1:IA5STRING:DefaultDomain
1.3.6.1.4.1.44970.3 = DER:04:05:21:01:01:01:01
1.3.6.1.4.1.44970.4 = ASN1:UTF8STRING:OpenThread-c64e
1.3.6.1.4.1.44970.5 = DER:04:08:ef:13:98:c2:fd:50:4b:67
@@ -0,0 +1,15 @@
# This file contains X509v3 extension definitions for OpenSSL
# certificate generation.
[ CommCert4 ]
subjectKeyIdentifier = none
authorityKeyIdentifier = keyid
# Include TCAT specified fields
# Because ASN1:OCTETSTRING doesn't work with hex input, we use raw DER here. Tag 0x04 is OCTETSTRING.
# See https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#
1.3.6.1.4.1.44970.1 = ASN1:IA5STRING:OtherDomain
1.3.6.1.4.1.44970.3 = DER:04:05:21:21:05:09:11
1.3.6.1.4.1.44970.4 = ASN1:UTF8STRING:OtherThread-c64e
1.3.6.1.4.1.44970.5 = DER:04:08:ef:13:98:c2:fd:50:4b:68
@@ -0,0 +1,15 @@
# This file contains X509v3 extension definitions for OpenSSL
# certificate generation.
[ DeviceCert1 ]
subjectKeyIdentifier = none
authorityKeyIdentifier = keyid
# Include Thread version field
1.3.6.1.4.1.44970.2 = ASN1:INTEGER:5
# Include TCAT specified fields
# Because ASN1:OCTETSTRING doesn't work with hex input, we use raw DER here. Tag 0x04 is OCTETSTRING.
# See https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#
1.3.6.1.4.1.44970.3 = DER:04:05:20:01:01:01:01
@@ -0,0 +1,15 @@
# This file contains X509v3 extension definitions for OpenSSL
# certificate generation.
[ DeviceCert2 ]
subjectKeyIdentifier = none
authorityKeyIdentifier = keyid
# Include Thread version field
1.3.6.1.4.1.44970.2 = ASN1:INTEGER:5
# Include TCAT specified fields
# Because ASN1:OCTETSTRING doesn't work with hex input, we use raw DER here. Tag 0x04 is OCTETSTRING.
# See https://datatracker.ietf.org/doc/html/rfc5280#section-4.1
#
1.3.6.1.4.1.44970.3 = DER:04:05:20:01:01:01:01
@@ -0,0 +1,9 @@
# This file contains X509v3 extension definitions for OpenSSL
# certificate generation.
[ ca ]
subjectAltName = email:ca-admin@example.org
keyUsage = critical, digitalSignature, keyCertSign, cRLSign
basicConstraints = critical,CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = none
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIPUEbXoKX2i4zyuvq7IRTVIlMpzf3t3pmlLc4uQprrq6oAoGCCqGSM49
AwEHoUQDQgAEHZq8vhZ816JEhgqe6zZKioMDFbrKEkJlnRfSJEdfXZYSS94wUFKH
zEHcAY3PU4IPTGnF5pusUE41rJa2n8vC7w==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEINQLE/8iWwfE4OCnANeNL2hUPFIOa5uHjfw+eXatusAuoAoGCCqGSM49
AwEHoUQDQgAEBIvT4u0YQu5dka6tscIuV2DF/TpwDmWBu3bCMa9KF80zbEjkg9Z9
mf31Ia6jXjGD5cUosuEpyW8TlQK5WMLfmg==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIE0aPRr+B9R9MZ9SKadjEhIzV7LeoDB4E1Hkhd1mJuzPoAoGCCqGSM49
AwEHoUQDQgAEExBRVM1Y1nhwUo4UcV2+txa8NNFT3w3It9aBTbyJlMT6w/w1R0lq
ibwts4+aF5UEkgfu2fo/yfmzqDpekMK9Mw==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIM1pKneJbjUDWNpRPfygf1Wfi/FkzQHv+gN8Co7f+6kioAoGCCqGSM49
AwEHoUQDQgAEgIgp7nkc36xTPKv0lySnQYCyw/SDHjDI5iRDukFYEVBwRQ1CI20H
DZ3iqf/MxXZb3UcLZ4aYylSHJeq8I5jX8w==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIqKM1QTlNaquV74W6Viz/ggXoLqlPOP6LagSyaFO3oUoAoGCCqGSM49
AwEHoUQDQgAE11h/4vKZXVXv+1GDZo066spItloTdpCi0bux0jvpQSHLdQBIc+40
zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdg==
-----END EC PRIVATE KEY-----
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIP7Al8tJA3QgwD3yIuOSEmJkT3GlWmcHQ59JfhZOjSdUoAoGCCqGSM49
AwEHoUQDQgAE30GMkqSBj3049NtK6G/MRTqcDxpmi1LxTpSxFIB7P9HVoVM7Cd9X
6bBUp5FrSZI+KHtX2HKtXzmzsdJ3gxAmiw==
-----END EC PRIVATE KEY-----
+12 -11
View File
@@ -1,13 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICCDCCAa2gAwIBAgIJAIKxygBXoH+5MAoGCCqGSM49BAMCMG8xCzAJBgNVBAYT
AlhYMRAwDgYDVQQIEwdNeVN0YXRlMQ8wDQYDVQQHEwZNeUNpdHkxDzANBgNVBAsT
Bk15VW5pdDERMA8GA1UEChMITXlWZW5kb3IxGTAXBgNVBAMTEHd3dy5teXZlbmRv
ci5jb20wHhcNMjMxMDE2MTAzMzE1WhcNMjYxMDE2MTAzMzE1WjBvMQswCQYDVQQG
EwJYWDEQMA4GA1UECBMHTXlTdGF0ZTEPMA0GA1UEBxMGTXlDaXR5MQ8wDQYDVQQL
EwZNeVVuaXQxETAPBgNVBAoTCE15VmVuZG9yMRkwFwYDVQQDExB3d3cubXl2ZW5k
b3IuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdyzPAXGKeZY94OhHAWX
HzJfQIjGSyaOzlgL9OEFw2SoUDncLKPGwfPAUSfuMyEkzszNDM0HHkBsDLqu4n25
/6MyMDAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU4EynoSw9eDKZEVPkums2
IWLAJCowCgYIKoZIzj0EAwIDSQAwRgIhAMYGGL9xShyE6P9wEU+MAYF6W3CzdrwV
kuerX1encIH2AiEA5rq490NUobM1Au43roxJq1T6Z43LscPVbGZfULD1Jq0=
MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM
HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg
R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD
VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV
BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl
YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw
CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL
x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ
0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P
AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo
hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu
eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=
-----END CERTIFICATE-----
@@ -1,11 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBnzCCAUSgAwIBAgIUQ5RUJMc95ssHQybR6pcx7LXSBzcwCgYIKoZIzj0EAwIw
bzELMAkGA1UEBhMCWFgxEDAOBgNVBAgTB015U3RhdGUxDzANBgNVBAcTBk15Q2l0
eTEPMA0GA1UECxMGTXlVbml0MREwDwYDVQQKEwhNeVZlbmRvcjEZMBcGA1UEAxMQ
d3d3Lm15dmVuZG9yLmNvbTAeFw0yMzEwMTgxNTIyMTZaFw0zMzEwMTUxNTIyMTZa
MBcxFTATBgNVBAMMDENvbW1pc3Npb25lcjBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABDU90Qpae5c+5Diou072S6MMHNv9+Ah9Kmo+mZTT6gQUyRScFey3+6wE08o7
wl6/8EKRgS8TFSihK4mYGxYoN06jFjAUMBIGCSsGAQQBgt8qAwQFIQEBAQEwCgYI
KoZIzj0EAwIDSQAwRgIhAOgQH8wFSe3JtGSmEFLy4fbMhOg+5Mfhqoq95vu2ML/u
AiEAt4BjuFo7GTxQxXl1e8TvMGESPGBKnR7cIT/BCnn2fto=
MIIB1TCCAXugAwIBAgIDDhqDMAoGCCqGSM49BAMCMHExJjAkBgNVBAMMHVRocmVh
ZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQgR3JvdXAg
SW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYDVQQGEwJV
UzAeFw0yNDA1MDcwOTM5NDVaFw0yNDA1MjEwOTM5NDVaMDoxHzAdBgNVBAMMFlRD
QVQgRXhhbXBsZSBDb21tQ2VydDExFzAVBgNVBAUTDjM1MjMtMTU0My0wMDAxMFkw
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHZq8vhZ816JEhgqe6zZKioMDFbrKEkJl
nRfSJEdfXZYSS94wUFKHzEHcAY3PU4IPTGnF5pusUE41rJa2n8vC76M5MDcwHwYD
VR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwFAYJKwYBBAGC3yoDBAcEBSEB
AQEBMAoGCCqGSM49BAMCA0gAMEUCIHeEfOOEX3jya2+bJMoGEEcFE56eUOjaz9aV
Tt1soEG8AiEA0taHGNpGgjE/b4kLW27dd8H+D/H5kNbq9Jlm9ct078Y=
-----END CERTIFICATE-----
@@ -1,8 +1,5 @@
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFOGszqvbs62fRwd3Rnd79wf6fpWxkXLO5YzhEuJ9EV1oAoGCCqGSM49
AwEHoUQDQgAENT3RClp7lz7kOKi7TvZLowwc2/34CH0qaj6ZlNPqBBTJFJwV7Lf7
rATTyjvCXr/wQpGBLxMVKKEriZgbFig3Tg==
MHcCAQEEIPUEbXoKX2i4zyuvq7IRTVIlMpzf3t3pmlLc4uQprrq6oAoGCCqGSM49
AwEHoUQDQgAEHZq8vhZ816JEhgqe6zZKioMDFbrKEkJlnRfSJEdfXZYSS94wUFKH
zEHcAY3PU4IPTGnF5pusUE41rJa2n8vC7w==
-----END EC PRIVATE KEY-----
+34 -14
View File
@@ -28,19 +28,21 @@
import asyncio
import argparse
from os import path
import logging
import os
from ble.ble_connection_constants import BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, \
BBTC_RX_CHAR_UUID, SERVER_COMMON_NAME
BBTC_RX_CHAR_UUID
from ble.ble_stream import BleStream
from ble.udp_stream import UdpStream
from ble.ble_stream_secure import BleStreamSecure
from ble.udp_stream import UdpStream
from ble import ble_scanner
from cli.cli import CLI
from dataset.dataset import ThreadDataset
from cli.command import CommandResult
from utils import select_device_by_user_input
from utils import select_device_by_user_input, quit_with_reason
logger = logging.getLogger(__name__)
async def main():
@@ -48,6 +50,7 @@ async def main():
parser = argparse.ArgumentParser(description='Device parameters')
parser.add_argument('--debug', help='Enable debug logs', action='store_true')
parser.add_argument('--info', help='Enable info logs', action='store_true')
parser.add_argument('--cert_path', help='Path to certificate chain and key', action='store', default='auth')
group = parser.add_mutually_exclusive_group()
group.add_argument('--mac', type=str, help='Device MAC address', action='store')
@@ -57,25 +60,40 @@ async def main():
args = parser.parse_args()
if args.debug:
logging.getLogger('ble_stream').setLevel(logging.DEBUG)
logging.getLogger('ble_stream_secure').setLevel(logging.DEBUG)
logger.setLevel(logging.DEBUG)
logging.getLogger('ble.ble_stream').setLevel(logging.DEBUG)
logging.getLogger('ble.ble_stream_secure').setLevel(logging.DEBUG)
logging.getLogger('ble.udp_stream').setLevel(logging.DEBUG)
elif args.info:
logger.setLevel(logging.INFO)
logging.getLogger('ble.ble_stream').setLevel(logging.INFO)
logging.getLogger('ble.ble_stream_secure').setLevel(logging.INFO)
logging.getLogger('ble.udp_stream').setLevel(logging.INFO)
device = await get_device_by_args(args)
ble_sstream = None
if not (device is None):
if device is not None:
print(f'Connecting to {device}')
ble_sstream = BleStreamSecure(device)
ble_sstream.load_cert(
certfile=path.join(args.cert_path, 'commissioner_cert.pem'),
keyfile=path.join(args.cert_path, 'commissioner_key.pem'),
cafile=path.join(args.cert_path, 'ca_cert.pem'),
certfile=os.path.join(args.cert_path, 'commissioner_cert.pem'),
keyfile=os.path.join(args.cert_path, 'commissioner_key.pem'),
cafile=os.path.join(args.cert_path, 'ca_cert.pem'),
)
logger.info(f"Certificates and key loaded from '{args.cert_path}'")
print('Setting up secure channel...')
await ble_sstream.do_handshake(hostname=SERVER_COMMON_NAME)
print('Done')
print('Setting up secure TLS channel..', end='')
try:
await ble_sstream.do_handshake()
print('\nDone')
ble_sstream.log_cert_identities()
except Exception as e:
print('\nFailed')
logger.error(e)
ble_sstream.log_cert_identities()
quit_with_reason('TLS handshake failure')
ds = ThreadDataset()
cli = CLI(ds, ble_sstream)
@@ -85,13 +103,15 @@ async def main():
user_input = await loop.run_in_executor(None, lambda: input('> '))
if user_input.lower() == 'exit':
print('Disconnecting...')
if ble_sstream is not None:
await ble_sstream.close()
break
try:
result: CommandResult = await cli.evaluate_input(user_input)
if result:
result.pretty_print()
except Exception as e:
print(e)
logger.error(e)
async def get_device_by_args(args):
@@ -29,4 +29,3 @@
BBTC_SERVICE_UUID = 'FFFB'
BBTC_RX_CHAR_UUID = '6BD10D8B-85A7-4E5A-BA2D-C83558A5F220'
BBTC_TX_CHAR_UUID = '7FDDF61F-280A-4773-B448-BA1B8FE0DD69'
SERVER_COMMON_NAME = 'myvendor.com/tcat/mydev'
+42 -4
View File
@@ -26,10 +26,16 @@
POSSIBILITY OF SUCH DAMAGE.
"""
import _ssl
import asyncio
import ssl
import sys
import logging
from tlv.tlv import TLV
from tlv.tcat_tlv import TcatTLVType
import utils
logger = logging.getLogger(__name__)
@@ -41,27 +47,35 @@ class BleStreamSecure:
self.incoming = ssl.MemoryBIO()
self.outgoing = ssl.MemoryBIO()
self.ssl_object = None
self.cert = ''
def load_cert(self, certfile='', keyfile='', cafile=''):
if certfile and keyfile:
self.ssl_context.load_cert_chain(certfile=certfile, keyfile=keyfile)
self.cert = utils.load_cert_pem(certfile)
elif certfile:
self.ssl_context.load_cert_chain(certfile=certfile)
self.cert = utils.load_cert_pem(certfile)
if cafile:
self.ssl_context.load_verify_locations(cafile=cafile)
async def do_handshake(self, hostname):
async def do_handshake(self):
is_debug = logger.getEffectiveLevel() <= logging.DEBUG
self.ssl_object = self.ssl_context.wrap_bio(
incoming=self.incoming,
outgoing=self.outgoing,
server_side=False,
server_hostname=hostname,
server_hostname=None,
)
while True:
try:
if not is_debug:
print('.', end='')
sys.stdout.flush()
self.ssl_object.do_handshake()
break
# SSLWantWrite means ssl wants to send data over the link,
# but might need a receive first
except ssl.SSLWantWriteError:
@@ -71,7 +85,7 @@ class BleStreamSecure:
data = self.outgoing.read()
if data:
await self.stream.send(data)
await asyncio.sleep(0.1)
await asyncio.sleep(0.02)
# SSLWantRead means ssl wants to receive data from the link,
# but might need to send first
@@ -82,7 +96,7 @@ class BleStreamSecure:
output = await self.stream.recv(4096)
if output:
self.incoming.write(output)
await asyncio.sleep(0.1)
await asyncio.sleep(0.02)
async def send(self, bytes):
self.ssl_object.write(bytes)
@@ -117,3 +131,27 @@ class BleStreamSecure:
await self.send(bytes)
res = await self.recv(buffersize=4096, timeout=5)
return res
async def close(self):
if self.ssl_object.session is not None:
data = TLV(TcatTLVType.DISCONNECT.value, bytes()).to_bytes()
await self.send(data)
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
# Should work for Python >= 3.10
try:
cc = self.ssl_object._sslobj.get_unverified_chain()
if cc is None:
logger.info('No TCAT Device cert chain was received (yet).')
return
logger.info(f'TCAT Device cert chain: {len(cc)} certificates received.')
for cert in cc:
logger.info(f' cert info:\n{cert.get_info()}')
peer_cert_der_hex = utils.base64_string(cert.public_bytes(_ssl.ENCODING_DER))
logger.info(f' base64: (paste in https://lapo.it/asn1js/ to decode)\n{peer_cert_der_hex}')
logger.info(f'TCAT Commissioner cert, PEM:\n{self.cert}')
except Exception as e:
logger.warning('Could not display TCAT client cert info (check Python version is >= 3.10?)')
-4
View File
@@ -26,11 +26,7 @@
POSSIBILITY OF SUCH DAMAGE.
"""
from itertools import count, takewhile
from typing import Iterator
import logging
import time
from asyncio import sleep
import socket
logger = logging.getLogger(__name__)
+2 -2
View File
@@ -27,7 +27,7 @@
"""
from ble.ble_connection_constants import BBTC_SERVICE_UUID, BBTC_TX_CHAR_UUID, \
BBTC_RX_CHAR_UUID, SERVER_COMMON_NAME
BBTC_RX_CHAR_UUID
from ble.ble_stream import BleStream
from ble.ble_stream_secure import BleStreamSecure
from ble import ble_scanner
@@ -160,6 +160,6 @@ class ScanCommand(Command):
)
print('Setting up secure channel...')
await ble_sstream.do_handshake(hostname=SERVER_COMMON_NAME)
await ble_sstream.do_handshake()
print('Done')
context['ble_sstream'] = ble_sstream
+1
View File
@@ -31,6 +31,7 @@ from enum import Enum
class TcatTLVType(Enum):
RESPONSE_W_STATUS = 0x01
RESPONSE_W_PAYLOAD = 0x02
DISCONNECT = 0x09
ACTIVE_DATASET = 0x20
DECOMMISSION = 0x60
APPLICATION = 0x82
+11
View File
@@ -26,6 +26,8 @@
POSSIBILITY OF SUCH DAMAGE.
"""
import base64
def get_int_in_range(min_value, max_value):
while True:
@@ -61,3 +63,12 @@ def select_device_by_user_input(tcat_devices):
print('Selected ', device)
return device
def base64_string(bindata):
return base64.b64encode(bindata).decode('ascii')
def load_cert_pem(fn):
with open(fn, 'r') as file:
return file.read()