1 /*
2 * Copyright (c) 2024, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "openthread-core-config.h"
30
31 #include "test_platform.h"
32 #include "test_util.h"
33
34 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
35
36 #include <openthread/ble_secure.h>
37
38 #define OT_TCAT_X509_CERT \
39 "-----BEGIN CERTIFICATE-----\n" \
40 "MIIB6TCCAZCgAwIBAgICNekwCgYIKoZIzj0EAwIwcTEmMCQGA1UEAwwdVGhyZWFk\n" \
41 "IENlcnRpZmljYXRpb24gRGV2aWNlQ0ExGTAXBgNVBAoMEFRocmVhZCBHcm91cCBJ\n" \
42 "bmMxEjAQBgNVBAcMCVNhbiBSYW1vbjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVT\n" \
43 "MCAXDTI0MDUwNzA5Mzk0NVoYDzI5OTkxMjMxMDkzOTQ1WjA8MSEwHwYDVQQDDBhU\n" \
44 "Q0FUIEV4YW1wbGUgRGV2aWNlQ2VydDExFzAVBgNVBAUTDjQ3MjMtOTgzMy0wMDAx\n" \
45 "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE11h/4vKZXVXv+1GDZo066spItloT\n" \
46 "dpCi0bux0jvpQSHLdQBIc+40zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdqNLMEkw\n" \
47 "HwYDVR0jBBgwFoAUX6sbKWiIodS0MaiGYefnZlnt+BkwEAYJKwYBBAGC3yoCBAMC\n" \
48 "AQUwFAYJKwYBBAGC3yoDBAcEBSABAQEBMAoGCCqGSM49BAMCA0cAMEQCIHWu+Rd1\n" \
49 "VRlzrD8KbuyJcJFTXh2sQ9UIrFIA7+4e/GVcAiAVBdGqTxbt3TGkBBllpafAUB2/\n" \
50 "s0GJj7E33oblqy5eHQ==\n" \
51 "-----END CERTIFICATE-----\n"
52
53 #define OT_TCAT_PRIV_KEY \
54 "-----BEGIN EC PRIVATE KEY-----\n" \
55 "MHcCAQEEIIqKM1QTlNaquV74W6Viz/ggXoLqlPOP6LagSyaFO3oUoAoGCCqGSM49\n" \
56 "AwEHoUQDQgAE11h/4vKZXVXv+1GDZo066spItloTdpCi0bux0jvpQSHLdQBIc+40\n" \
57 "zVCxMDRUvbX//vJKGsSJKOVUlCojQ2wIdg==\n" \
58 "-----END EC PRIVATE KEY-----\n"
59
60 #define OT_TCAT_TRUSTED_ROOT_CERTIFICATE \
61 "-----BEGIN CERTIFICATE-----\n" \
62 "MIICOzCCAeGgAwIBAgIJAKOc2hehOGoBMAoGCCqGSM49BAMCMHExJjAkBgNVBAMM\n" \
63 "HVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJlYWQg\n" \
64 "R3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQswCQYD\n" \
65 "VQQGEwJVUzAeFw0yNDA1MDMyMDAyMThaFw00NDA0MjgyMDAyMThaMHExJjAkBgNV\n" \
66 "BAMMHVRocmVhZCBDZXJ0aWZpY2F0aW9uIERldmljZUNBMRkwFwYDVQQKDBBUaHJl\n" \
67 "YWQgR3JvdXAgSW5jMRIwEAYDVQQHDAlTYW4gUmFtb24xCzAJBgNVBAgMAkNBMQsw\n" \
68 "CQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGy850VBIPTkN3oL\n" \
69 "x++zIUsZk2k26w4fuieFz9oNvjdb5W14+Yf3mvGWsl4NHyLxqhmamVAR4h7zWRlZ\n" \
70 "0XyMVpKjYjBgMB4GA1UdEQQXMBWBE3RvbUB0aHJlYWRncm91cC5vcmcwDgYDVR0P\n" \
71 "AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFF+rGyloiKHUtDGo\n" \
72 "hmHn52ZZ7fgZMAoGCCqGSM49BAMCA0gAMEUCIQCTq1qjPZs9fAJB6ppTXs588Pnu\n" \
73 "eVFOwC8bd//D99KiHAIgU84kwFHIyDvFqu6y+u1hFqBGsiuTmKwZ2PHhVe/xK1k=\n" \
74 "-----END CERTIFICATE-----\n"
75
76 namespace ot {
77
78 class TestBleSecure
79 {
80 public:
TestBleSecure(void)81 TestBleSecure(void)
82 : mIsConnected(false)
83 , mIsBleConnectionOpen(false)
84 {
85 }
86
HandleBleSecureConnect(bool aConnected,bool aBleConnectionOpen)87 void HandleBleSecureConnect(bool aConnected, bool aBleConnectionOpen)
88 {
89 mIsConnected = aConnected;
90 mIsBleConnectionOpen = aBleConnectionOpen;
91 }
92
IsConnected(void) const93 bool IsConnected(void) const { return mIsConnected; }
IsBleConnectionOpen(void) const94 bool IsBleConnectionOpen(void) const { return mIsBleConnectionOpen; }
95
96 private:
97 bool mIsConnected;
98 bool mIsBleConnectionOpen;
99 };
100
HandleBleSecureConnect(otInstance * aInstance,bool aConnected,bool aBleConnectionOpen,void * aContext)101 static void HandleBleSecureConnect(otInstance *aInstance, bool aConnected, bool aBleConnectionOpen, void *aContext)
102 {
103 OT_UNUSED_VARIABLE(aInstance);
104
105 static_cast<TestBleSecure *>(aContext)->HandleBleSecureConnect(aConnected, aBleConnectionOpen);
106 }
107
TestTcat(void)108 void TestTcat(void)
109 {
110 const char kPskdVendor[] = "J01NM3";
111 const char kUrl[] = "dummy_url";
112 constexpr uint16_t kConnectionId = 0;
113 const int kCertificateThreadVersion = 2;
114 const int kCertificateAuthorizationField = 3;
115 const uint8_t expectedTcatAuthField[5] = {0x20, 0x01, 0x01, 0x01, 0x01};
116 uint8_t attributeBuffer[8];
117 size_t attributeLen;
118
119 TestBleSecure ble;
120 Instance *instance = testInitInstance();
121
122 otTcatVendorInfo vendorInfo = {.mProvisioningUrl = kUrl, .mPskdString = kPskdVendor};
123
124 otBleSecureSetCertificate(instance, reinterpret_cast<const uint8_t *>(OT_TCAT_X509_CERT), sizeof(OT_TCAT_X509_CERT),
125 reinterpret_cast<const uint8_t *>(OT_TCAT_PRIV_KEY), sizeof(OT_TCAT_PRIV_KEY));
126
127 otBleSecureSetCaCertificateChain(instance, reinterpret_cast<const uint8_t *>(OT_TCAT_TRUSTED_ROOT_CERTIFICATE),
128 sizeof(OT_TCAT_TRUSTED_ROOT_CERTIFICATE));
129
130 otBleSecureSetSslAuthMode(instance, true);
131
132 // Validate BLE secure and Tcat start APIs
133 SuccessOrQuit(otBleSecureSetTcatVendorInfo(instance, &vendorInfo));
134 VerifyOrQuit(otBleSecureTcatStart(instance, nullptr) == kErrorInvalidState);
135 SuccessOrQuit(otBleSecureStart(instance, HandleBleSecureConnect, nullptr, true, &ble));
136 VerifyOrQuit(otBleSecureStart(instance, HandleBleSecureConnect, nullptr, true, nullptr) == kErrorAlready);
137 SuccessOrQuit(otBleSecureTcatStart(instance, nullptr));
138
139 // Validate connection callbacks when platform informs that peer has connected/disconnected
140 VerifyOrQuit(!otBleSecureIsConnected(instance));
141 otPlatBleGapOnConnected(instance, kConnectionId);
142 VerifyOrQuit(!ble.IsConnected() && ble.IsBleConnectionOpen());
143 otPlatBleGapOnDisconnected(instance, kConnectionId);
144 VerifyOrQuit(!ble.IsConnected() && !ble.IsBleConnectionOpen());
145
146 // Verify that Thread-attribute parsing isn't available yet when not connected as client or server.
147 attributeLen = sizeof(attributeBuffer);
148 VerifyOrQuit(otBleSecureGetThreadAttributeFromPeerCertificate(instance, kCertificateAuthorizationField,
149 &attributeBuffer[0],
150 &attributeLen) == kErrorInvalidState);
151 attributeLen = sizeof(attributeBuffer);
152 VerifyOrQuit(otBleSecureGetThreadAttributeFromOwnCertificate(
153 instance, kCertificateThreadVersion, &attributeBuffer[0], &attributeLen) == kErrorInvalidState);
154
155 // Validate connection callbacks when calling `otBleSecureDisconnect()`
156 otPlatBleGapOnConnected(instance, kConnectionId);
157 VerifyOrQuit(!ble.IsConnected() && ble.IsBleConnectionOpen());
158 otBleSecureDisconnect(instance);
159 VerifyOrQuit(!ble.IsConnected() && !ble.IsBleConnectionOpen());
160
161 // Validate TLS connection can be started only when peer is connected
162 otPlatBleGapOnConnected(instance, kConnectionId);
163 SuccessOrQuit(otBleSecureConnect(instance));
164 VerifyOrQuit(otBleSecureIsConnectionActive(instance));
165
166 // Once in TLS client connecting state, the below cert eval functions are available.
167 // Test that the Thread-specific attributes can be decoded properly.
168 attributeLen = 1;
169 SuccessOrQuit(otBleSecureGetThreadAttributeFromOwnCertificate(instance, kCertificateThreadVersion,
170 &attributeBuffer[0], &attributeLen));
171 VerifyOrQuit(attributeLen == 1 && attributeBuffer[0] >= kThreadVersion1p4);
172
173 static_assert(5 == sizeof(expectedTcatAuthField), "expectedTcatAuthField size incorrect for test");
174 attributeLen = 5;
175 SuccessOrQuit(otBleSecureGetThreadAttributeFromOwnCertificate(instance, kCertificateAuthorizationField,
176 &attributeBuffer[0], &attributeLen));
177 VerifyOrQuit(attributeLen == 5 && memcmp(&expectedTcatAuthField, &attributeBuffer, attributeLen) == 0);
178
179 // Validate TLS connection can be started only when peer is connected
180 otBleSecureDisconnect(instance);
181 VerifyOrQuit(otBleSecureConnect(instance) == kErrorInvalidState);
182
183 // Validate Tcat state changes after stopping BLE secure
184 VerifyOrQuit(otBleSecureIsTcatEnabled(instance));
185 otBleSecureStop(instance);
186 VerifyOrQuit(!otBleSecureIsTcatEnabled(instance));
187
188 testFreeInstance(instance);
189 }
190
191 } // namespace ot
192
193 #endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
194
main(void)195 int main(void)
196 {
197 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
198 ot::TestTcat();
199 printf("All tests passed\n");
200 #else
201 printf("Tcat is not enabled\n");
202 return -1;
203 #endif
204 return 0;
205 }
206