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