1 /* 2 * Copyright (c) 2023, 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 #ifndef BLE_SECURE_HPP_ 30 #define BLE_SECURE_HPP_ 31 32 #include "openthread-core-config.h" 33 34 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 35 36 #include <openthread/ble_secure.h> 37 38 #include "meshcop/meshcop.hpp" 39 #include "meshcop/secure_transport.hpp" 40 #include "meshcop/tcat_agent.hpp" 41 42 /** 43 * @file 44 * Includes definitions for the secure BLE agent. 45 */ 46 47 namespace ot { 48 49 namespace Ble { 50 51 class BleSecure : public InstanceLocator, private NonCopyable 52 { 53 public: 54 /** 55 * Pointer to call when the secure BLE connection state changes. 56 * 57 * Please see otHandleBleSecureConnect for details. 58 * 59 */ 60 typedef otHandleBleSecureConnect ConnectCallback; 61 62 /** 63 * Pointer to call when data was received over the TLS connection. 64 * If line mode is activated the function is called only after EOL has been received. 65 * 66 * Please see otHandleBleSecureReceive for details. 67 * 68 */ 69 typedef otHandleBleSecureReceive ReceiveCallback; 70 71 /** 72 * Represents a TCAT command class. 73 * 74 */ 75 typedef MeshCoP::TcatAgent::CommandClass CommandClass; 76 77 /** 78 * Constructor initializes the object. 79 * 80 * @param[in] aInstance A reference to the OpenThread instance. 81 * 82 */ 83 explicit BleSecure(Instance &aInstance); 84 85 /** 86 * Starts the secure BLE agent. 87 * 88 * @param[in] aConnectHandler A pointer to a function that will be called when the connection 89 * state changes. 90 * @param[in] aReceiveHandler A pointer to a function that will be called once data has been received 91 * over the TLS connection. 92 * @param[in] aTlvMode A boolean value indicating if line mode shall be activated. 93 * @param[in] aContext A pointer to arbitrary context information. May be NULL if not used. 94 * 95 * @retval kErrorNone Successfully started the BLE agent. 96 * @retval kErrorAlready Already started. 97 * 98 */ 99 Error Start(ConnectCallback aConnectHandler, ReceiveCallback aReceiveHandler, bool aTlvMode, void *aContext); 100 101 /** 102 * Enables the TCAT protocol over BLE Secure. 103 * 104 * @param[in] aVendorInfo A reference to the Vendor Information (must remain valid after the method call) 105 * @param[in] aHandler Callback to a function that is called when the join operation completes. 106 * 107 * @retval kErrorNone Successfully started the BLE Secure Joiner role. 108 * @retval kErrorInvalidArgs The aVendorInfo is invalid. 109 * @retval kErrorInvaidState The BLE function has not been started or line mode is not selected. 110 * 111 */ 112 Error TcatStart(const MeshCoP::TcatAgent::VendorInfo &aVendorInfo, MeshCoP::TcatAgent::JoinCallback aHandler); 113 114 /** 115 * Stops the secure BLE agent. 116 * 117 */ 118 void Stop(void); 119 120 /** 121 * Initializes TLS session with a peer using an already open BLE connection. 122 * 123 * @retval kErrorNone Successfully started TLS connection. 124 * 125 */ 126 Error Connect(void); 127 128 /** 129 * Stops the BLE and TLS connection. 130 * 131 */ 132 void Disconnect(void); 133 134 /** 135 * Indicates whether or not the TLS session is active (connected or conneting). 136 * 137 * @retval TRUE If TLS session is active. 138 * @retval FALSE If TLS session is not active. 139 * 140 */ IsConnectionActive(void) const141 bool IsConnectionActive(void) const { return mTls.IsConnectionActive(); } 142 143 /** 144 * Indicates whether or not the TLS session is connected. 145 * 146 * @retval TRUE The TLS session is connected. 147 * @retval FALSE The TLS session is not connected. 148 * 149 */ IsConnected(void) const150 bool IsConnected(void) const { return mTls.IsConnected(); } 151 152 /** 153 * Indicates whether or not the TCAT agent is enabled. 154 * 155 * @retval TRUE The TCAT agent is enabled. 156 * @retval FALSE The TCAT agent is not enabled. 157 * 158 */ IsTcatEnabled(void) const159 bool IsTcatEnabled(void) const { return mTcatAgent.IsEnabled(); } 160 161 /** 162 * Indicates whether or not a TCAT command class is authorized. 163 * 164 * @param[in] aInstance A pointer to an OpenThread instance. 165 * @param[in] aCommandClass A command class to check. 166 * 167 * @retval TRUE The command class is authorized. 168 * @retval FALSE The command class is not authorized. 169 * 170 */ IsCommandClassAuthorized(CommandClass aCommandClass) const171 bool IsCommandClassAuthorized(CommandClass aCommandClass) const 172 { 173 return mTcatAgent.IsCommandClassAuthorized(aCommandClass); 174 } 175 176 /** 177 * Sets the PSK. 178 * 179 * @param[in] aPsk A pointer to the PSK. 180 * @param[in] aPskLength The PSK length. 181 * 182 * @retval kErrorNone Successfully set the PSK. 183 * @retval kErrorInvalidArgs The PSK is invalid. 184 * 185 */ SetPsk(const uint8_t * aPsk,uint8_t aPskLength)186 Error SetPsk(const uint8_t *aPsk, uint8_t aPskLength) { return mTls.SetPsk(aPsk, aPskLength); } 187 188 /** 189 * Sets the PSK. 190 * 191 * @param[in] aPskd A Joiner PSKd. 192 * 193 */ 194 void SetPsk(const MeshCoP::JoinerPskd &aPskd); 195 196 #ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED 197 /** 198 * Sets the Pre-Shared Key (PSK) for TLS sessions identified by a PSK. 199 * 200 * TLS mode "TLS with AES 128 CCM 8" for secure BLE. 201 * 202 * @param[in] aPsk A pointer to the PSK. 203 * @param[in] aPskLength The PSK char length. 204 * @param[in] aPskIdentity The Identity Name for the PSK. 205 * @param[in] aPskIdLength The PSK Identity Length. 206 * 207 */ SetPreSharedKey(const uint8_t * aPsk,uint16_t aPskLength,const uint8_t * aPskIdentity,uint16_t aPskIdLength)208 void SetPreSharedKey(const uint8_t *aPsk, uint16_t aPskLength, const uint8_t *aPskIdentity, uint16_t aPskIdLength) 209 { 210 mTls.SetPreSharedKey(aPsk, aPskLength, aPskIdentity, aPskIdLength); 211 } 212 #endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED 213 214 #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED 215 /** 216 * Sets a X509 certificate with corresponding private key for TLS session. 217 * 218 * TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE. 219 * 220 * @param[in] aX509Cert A pointer to the PEM formatted X509 PEM certificate. 221 * @param[in] aX509Length The length of certificate. 222 * @param[in] aPrivateKey A pointer to the PEM formatted private key. 223 * @param[in] aPrivateKeyLength The length of the private key. 224 * 225 */ SetCertificate(const uint8_t * aX509Cert,uint32_t aX509Length,const uint8_t * aPrivateKey,uint32_t aPrivateKeyLength)226 void SetCertificate(const uint8_t *aX509Cert, 227 uint32_t aX509Length, 228 const uint8_t *aPrivateKey, 229 uint32_t aPrivateKeyLength) 230 { 231 mTls.SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength); 232 } 233 234 /** 235 * Sets the trusted top level CAs. It is needed for validate the certificate of the peer. 236 * 237 * TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE. 238 * 239 * @param[in] aX509CaCertificateChain A pointer to the PEM formatted X509 CA chain. 240 * @param[in] aX509CaCertChainLength The length of chain. 241 * 242 */ SetCaCertificateChain(const uint8_t * aX509CaCertificateChain,uint32_t aX509CaCertChainLength)243 void SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength) 244 { 245 mTls.SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLength); 246 } 247 #endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED 248 249 #if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 250 /** 251 * Returns the peer x509 certificate base64 encoded. 252 * 253 * TLS mode "ECDHE ECDSA with AES 128 CCM 8" for secure BLE. 254 * 255 * @param[out] aPeerCert A pointer to the base64 encoded certificate buffer. 256 * @param[out] aCertLength On input, the size the max size of @p aPeerCert. 257 * On output, the length of the base64 encoded peer certificate. 258 * 259 * @retval kErrorNone Successfully get the peer certificate. 260 * @retval kErrorInvalidArgs @p aInstance or @p aCertLength is invalid. 261 * @retval kErrorInvalidState Not connected yet. 262 * @retval kErrorNoBufs Can't allocate memory for certificate. 263 * 264 */ 265 Error GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength); 266 #endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 267 268 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 269 /** 270 * Returns an attribute value identified by its OID from the subject 271 * of the peer x509 certificate. The peer OID is provided in binary format. 272 * The attribute length is set if the attribute was successfully read or zero 273 * if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard 274 * if the attribute was successfully read. 275 * 276 * @param[in] aOid A pointer to the OID to be found. 277 * @param[in] aOidLength The length of the OID. 278 * @param[out] aAttributeBuffer A pointer to the attribute buffer. 279 * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. 280 * On output, the length of the attribute written to the buffer. 281 * @param[out] aAsn1Type A pointer to the ASN.1 type of the attribute written to the buffer. 282 * 283 * @retval kErrorInvalidState Not connected yet. 284 * @retval kErrorNone Successfully read attribute. 285 * @retval kErrorNoBufs Insufficient memory for storing the attribute value. 286 * 287 */ GetPeerSubjectAttributeByOid(const char * aOid,size_t aOidLength,uint8_t * aAttributeBuffer,size_t * aAttributeLength,int * aAsn1Type)288 Error GetPeerSubjectAttributeByOid(const char *aOid, 289 size_t aOidLength, 290 uint8_t *aAttributeBuffer, 291 size_t *aAttributeLength, 292 int *aAsn1Type) 293 { 294 return mTls.GetPeerSubjectAttributeByOid(aOid, aOidLength, aAttributeBuffer, aAttributeLength, aAsn1Type); 295 } 296 297 /** 298 * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of 299 * the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor. 300 * The attribute length is set if the attribute was successfully read or zero if unsuccessful. 301 * Requires a connection to be active. 302 * 303 * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. 304 * @param[out] aAttributeBuffer A pointer to the attribute buffer. 305 * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. 306 * On output, the length of the attribute written to the buffer. 307 * 308 * @retval kErrorNone Successfully read attribute. 309 * @retval kErrorNotFound The requested attribute was not found. 310 * @retval kErrorNoBufs Insufficient memory for storing the attribute value. 311 * @retval kErrorInvalidState Not connected yet. 312 * @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127. 313 * @retval kErrorParse The certificate extensions could not be parsed. 314 * 315 */ GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor,uint8_t * aAttributeBuffer,size_t * aAttributeLength)316 Error GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor, 317 uint8_t *aAttributeBuffer, 318 size_t *aAttributeLength) 319 { 320 return mTls.GetThreadAttributeFromPeerCertificate(aThreadOidDescriptor, aAttributeBuffer, aAttributeLength); 321 } 322 #endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 323 324 /** 325 * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of 326 * the own x509 certificate, where the last digit x is set to aThreadOidDescriptor. 327 * The attribute length is set if the attribute was successfully read or zero if unsuccessful. 328 * Requires a connection to be active. 329 * 330 * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. 331 * @param[out] aAttributeBuffer A pointer to the attribute buffer. 332 * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. 333 * On output, the length of the attribute written to the buffer. 334 * 335 * @retval kErrorNone Successfully read attribute. 336 * @retval kErrorNotFound The requested attribute was not found. 337 * @retval kErrorNoBufs Insufficient memory for storing the attribute value. 338 * @retval kErrorInvalidState Not connected yet. 339 * @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127. 340 * @retval kErrorParse The certificate extensions could not be parsed. 341 * 342 */ GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor,uint8_t * aAttributeBuffer,size_t * aAttributeLength)343 Error GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor, 344 uint8_t *aAttributeBuffer, 345 size_t *aAttributeLength) 346 { 347 return mTls.GetThreadAttributeFromOwnCertificate(aThreadOidDescriptor, aAttributeBuffer, aAttributeLength); 348 } 349 350 /** 351 * Sets the authentication mode for the BLE secure connection. It disables or enables the verification 352 * of peer certificate. 353 * 354 * @param[in] aVerifyPeerCertificate true, if the peer certificate should be verified 355 * 356 */ SetSslAuthMode(bool aVerifyPeerCertificate)357 void SetSslAuthMode(bool aVerifyPeerCertificate) { mTls.SetSslAuthMode(aVerifyPeerCertificate); } 358 359 /** 360 * Sends a secure BLE message. 361 * 362 * @param[in] aMessage A pointer to the message to send. 363 * 364 * If the return value is kErrorNone, OpenThread takes ownership of @p aMessage, and the caller should no longer 365 * reference @p aMessage. If the return value is not kErrorNone, the caller retains ownership of @p aMessage, 366 * including freeing @p aMessage if the message buffer is no longer needed. 367 * 368 * @retval kErrorNone Successfully sent message. 369 * @retval kErrorNoBufs Failed to allocate buffer memory. 370 * @retval kErrorInvalidState TLS connection was not initialized. 371 * 372 */ 373 Error SendMessage(Message &aMessage); 374 375 /** 376 * Sends a secure BLE data packet. 377 * 378 * @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV. 379 * @param[in] aLength A number indicating the length of the data buffer. 380 * 381 * @retval kErrorNone Successfully sent data. 382 * @retval kErrorNoBufs Failed to allocate buffer memory. 383 * @retval kErrorInvalidState TLS connection was not initialized. 384 * 385 */ 386 Error Send(uint8_t *aBuf, uint16_t aLength); 387 388 /** 389 * Sends a secure BLE data packet containing a TCAT Send Application Data TLV. 390 * 391 * @param[in] aBuf A pointer to the data to send as the Value of the TCAT Send Application Data TLV. 392 * @param[in] aLength A number indicating the length of the data buffer. 393 * 394 * @retval kErrorNone Successfully sent data. 395 * @retval kErrorNoBufs Failed to allocate buffer memory. 396 * @retval kErrorInvalidState TLS connection was not initialized. 397 * 398 */ 399 Error SendApplicationTlv(uint8_t *aBuf, uint16_t aLength); 400 401 /** 402 * Sends all remaining bytes in the send buffer. 403 * 404 * @retval kErrorNone Successfully enqueued data into the output interface. 405 * @retval kErrorNoBufs Failed to allocate buffer memory. 406 * @retval kErrorInvalidState TLS connection was not initialized. 407 * 408 */ 409 Error Flush(void); 410 411 /** 412 * Used to pass data received over a BLE link to the secure BLE server. 413 * 414 * @param[in] aBuf A pointer to the data received. 415 * @param[in] aLength A number indicating the length of the data buffer. 416 * 417 */ 418 Error HandleBleReceive(uint8_t *aBuf, uint16_t aLength); 419 420 /** 421 * Used to notify the secure BLE server that a BLE Device has been connected. 422 * 423 * @param[in] aConnectionId The identifier of the open connection. 424 * 425 */ 426 void HandleBleConnected(uint16_t aConnectionId); 427 428 /** 429 * Used to notify the secure BLE server that the BLE Device has been disconnected. 430 * 431 * @param[in] aConnectionId The identifier of the open connection. 432 * 433 */ 434 void HandleBleDisconnected(uint16_t aConnectionId); 435 436 /** 437 * Used to notify the secure BLE server that the BLE Device has updated ATT_MTU size. 438 * 439 * @param[in] aMtu The updated ATT_MTU value. 440 * 441 */ 442 Error HandleBleMtuUpdate(uint16_t aMtu); 443 444 private: 445 enum BleState : uint8_t 446 { 447 kStopped = 0, // Ble secure not started. 448 kAdvertising = 1, // Ble secure not advertising. 449 kConnected = 2, // Ble secure not connected. 450 }; 451 452 static constexpr uint8_t kInitialMtuSize = 23; // ATT_MTU 453 static constexpr uint8_t kGattOverhead = 3; // BLE GATT payload fits MTU size - 3 bytes 454 static constexpr uint8_t kPacketBufferSize = OT_BLE_ATT_MTU_MAX - kGattOverhead; 455 static constexpr uint16_t kTxBleHandle = 0; // Characteristics Handle for TX (not used) 456 457 static void HandleTlsConnected(void *aContext, bool aConnected); 458 void HandleTlsConnected(bool aConnected); 459 460 static void HandleTlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength); 461 void HandleTlsReceive(uint8_t *aBuf, uint16_t aLength); 462 463 void HandleTransmit(void); 464 465 static Error HandleTransport(void *aContext, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 466 Error HandleTransport(ot::Message &aMessage); 467 468 using TxTask = TaskletIn<BleSecure, &BleSecure::HandleTransmit>; 469 470 MeshCoP::SecureTransport mTls; 471 MeshCoP::TcatAgent mTcatAgent; 472 Callback<ConnectCallback> mConnectCallback; 473 Callback<ReceiveCallback> mReceiveCallback; 474 bool mTlvMode; 475 ot::Message *mReceivedMessage; 476 ot::Message *mSendMessage; 477 ot::MessageQueue mTransmitQueue; 478 TxTask mTransmitTask; 479 uint8_t mPacketBuffer[kPacketBufferSize]; 480 BleState mBleState; 481 uint16_t mMtuSize; 482 }; 483 484 } // namespace Ble 485 } // namespace ot 486 487 #endif // OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 488 489 #endif // BLE_SECURE_HPP_ 490