1 /* 2 * Copyright (c) 2016, 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 /** 30 * @file 31 * This file includes definitions for using mbedTLS. 32 */ 33 34 #ifndef SECURE_TRANSPORT_HPP_ 35 #define SECURE_TRANSPORT_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #ifdef OPENTHREAD_CONFIG_TLS_API_ENABLE 40 #error `OPENTHREAD_CONFIG_TLS_API_ENABLE` must not be defined directly, it is determined from `COAP_SECURE_API_ENABLE` and `BLE_TCAT_ENABLE` 41 #endif 42 43 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE || OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 44 #define OPENTHREAD_CONFIG_TLS_API_ENABLE 1 45 #else 46 #define OPENTHREAD_CONFIG_TLS_API_ENABLE 0 47 #endif 48 49 #include <mbedtls/net_sockets.h> 50 #include <mbedtls/ssl.h> 51 #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_COOKIE_C) 52 #include <mbedtls/ssl_cookie.h> 53 #endif 54 #include <mbedtls/version.h> 55 56 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 57 #ifndef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED 58 #error OPENTHREAD_CONFIG_BLE_TCAT_ENABLE requires MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED 59 #endif 60 #endif 61 62 #if OPENTHREAD_CONFIG_TLS_API_ENABLE 63 #if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 64 #include <mbedtls/base64.h> 65 #endif 66 #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED 67 #include <mbedtls/x509.h> 68 #include <mbedtls/x509_crl.h> 69 #include <mbedtls/x509_crt.h> 70 #include <mbedtls/x509_csr.h> 71 #endif 72 #endif 73 74 #include <openthread/coap_secure.h> 75 76 #include "common/callback.hpp" 77 #include "common/linked_list.hpp" 78 #include "common/locator.hpp" 79 #include "common/log.hpp" 80 #include "common/message.hpp" 81 #include "common/non_copyable.hpp" 82 #include "common/random.hpp" 83 #include "common/timer.hpp" 84 #include "crypto/sha256.hpp" 85 #include "meshcop/meshcop.hpp" 86 #include "meshcop/meshcop_tlvs.hpp" 87 #include "net/socket.hpp" 88 #include "net/udp6.hpp" 89 90 namespace ot { 91 92 namespace MeshCoP { 93 94 class SecureTransport; 95 class Dtls; 96 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 97 class Tls; 98 #endif 99 100 /** 101 * Represents a secure session. 102 */ 103 class SecureSession : private LinkedListEntry<SecureSession>, private NonCopyable 104 { 105 friend class LinkedListEntry<SecureSession>; 106 friend class LinkedList<SecureSession>; 107 friend class SecureTransport; 108 friend class Dtls; 109 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 110 friend class Tls; 111 #endif 112 113 public: 114 typedef otCoapSecureConnectEvent ConnectEvent; ///< A connect event. 115 116 static constexpr ConnectEvent kConnected = OT_COAP_SECURE_CONNECTED; 117 static constexpr ConnectEvent kDisconnectedPeerClosed = OT_COAP_SECURE_DISCONNECTED_PEER_CLOSED; 118 static constexpr ConnectEvent kDisconnectedLocalClosed = OT_COAP_SECURE_DISCONNECTED_LOCAL_CLOSED; 119 static constexpr ConnectEvent kDisconnectedMaxAttempts = OT_COAP_SECURE_DISCONNECTED_MAX_ATTEMPTS; 120 static constexpr ConnectEvent kDisconnectedError = OT_COAP_SECURE_DISCONNECTED_ERROR; 121 122 /** 123 * Function pointer which is called reporting a session connection event. 124 */ 125 typedef otHandleCoapSecureClientConnect ConnectHandler; 126 127 /** 128 * Pointer is called when data is received from the session. 129 * 130 * @param[in] aContext A pointer to application-specific context. 131 * @param[in] aBuf A pointer to the received data buffer. 132 * @param[in] aLength Number of bytes in the received data buffer. 133 */ 134 typedef void (*ReceiveHandler)(void *aContext, uint8_t *aBuf, uint16_t aLength); 135 136 /** 137 * Sets the connection event callback. 138 * 139 * @param[in] aConnectHandler A pointer to a function that is called when connected or disconnected. 140 * @param[in] aContext A pointer to arbitrary context information. 141 */ SetConnectCallback(ConnectHandler aConnectHandler,void * aContext)142 void SetConnectCallback(ConnectHandler aConnectHandler, void *aContext) 143 { 144 mConnectedCallback.Set(aConnectHandler, aContext); 145 } 146 147 /** 148 * Sets the receive callback. 149 * 150 * @param[in] aReceiveHandler A pointer to a function that is called to receive payload. 151 * @param[in] aContext A pointer to arbitrary context information. 152 */ SetReceiveCallback(ReceiveHandler aReceiveHandler,void * aContext)153 void SetReceiveCallback(ReceiveHandler aReceiveHandler, void *aContext) 154 { 155 mReceiveCallback.Set(aReceiveHandler, aContext); 156 } 157 158 /** 159 * Establishes a secure session (as client). 160 * 161 * On success, ownership of the session is passed to the associated secure transport (`GetTransport()`). 162 * The transport will then manage the session. Once the session is disconnected and removed from the transport, the 163 * secure transport signals this using the `RemoveSessionCallback` callback, where ownership is 164 * released. 165 * 166 * @param[in] aSockAddr The server address to connect to. 167 * 168 * @retval kErrorNone Successfully started session establishment 169 * @retval kErrorInvalidState Transport is not ready. 170 * @retval kErrorNoBufs Has reached max number of allowed connection attempts. 171 */ 172 Error Connect(const Ip6::SockAddr &aSockAddr); 173 174 /** 175 * Disconnects the session. 176 */ Disconnect(void)177 void Disconnect(void) { Disconnect(kDisconnectedLocalClosed); } 178 179 /** 180 * Sends message to the secure session. 181 * 182 * When successful (returning `kErrorNone`), this method takes over the ownership of @p aMessage and will free 183 * it after transmission. Otherwise, the caller keeps the ownership of @p aMessage. 184 * 185 * @param[in] aMessage A message to send. 186 * 187 * @retval kErrorNone Successfully sent the message. 188 * @retval kErrorNoBufs @p aMessage is too long. 189 */ 190 Error Send(Message &aMessage); 191 192 /** 193 * Returns the session's peer address. 194 * 195 * @return The session's message info. 196 */ GetMessageInfo(void) const197 const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; } 198 199 /** 200 * Indicates whether or not the session is active (connected, connecting, or disconnecting). 201 * 202 * @retval TRUE If session is active. 203 * @retval FALSE If session is not active. 204 */ IsConnectionActive(void) const205 bool IsConnectionActive(void) const { return (mState != kStateDisconnected); } 206 207 /** 208 * Indicates whether or not the session is connected. 209 * 210 * @retval TRUE The session is connected. 211 * @retval FALSE The session is not connected. 212 */ IsConnected(void) const213 bool IsConnected(void) const { return (mState == kStateConnected); } 214 215 /** 216 * Gets the `SecureTransport` used by this session. 217 * 218 * @return The `SecureTransport` instance associated with this session. 219 */ GetTransport(void)220 SecureTransport &GetTransport(void) { return mTransport; } 221 222 protected: 223 explicit SecureSession(SecureTransport &aTransport); 224 IsSessionInUse(void) const225 bool IsSessionInUse(void) const { return (mNext != this); } 226 227 private: 228 static constexpr uint32_t kGuardTimeNewConnectionMilli = 2000; 229 static constexpr uint16_t kMaxContentLen = OPENTHREAD_CONFIG_DTLS_MAX_CONTENT_LEN; 230 231 #if !OPENTHREAD_CONFIG_TLS_API_ENABLE 232 static constexpr uint16_t kApplicationDataMaxLength = 1152; 233 #else 234 static constexpr uint16_t kApplicationDataMaxLength = OPENTHREAD_CONFIG_DTLS_APPLICATION_DATA_MAX_LENGTH; 235 #endif 236 237 enum State : uint8_t 238 { 239 kStateDisconnected, 240 kStateInitializing, 241 kStateConnecting, 242 kStateConnected, 243 kStateDisconnecting, 244 }; 245 246 void Init(void); IsDisconnected(void) const247 bool IsDisconnected(void) const { return mState == kStateDisconnected; } IsInitializing(void) const248 bool IsInitializing(void) const { return mState == kStateInitializing; } IsConnecting(void) const249 bool IsConnecting(void) const { return mState == kStateConnecting; } IsDisconnecting(void) const250 bool IsDisconnecting(void) const { return mState == kStateDisconnecting; } IsConnectingOrConnected(void) const251 bool IsConnectingOrConnected(void) const { return mState == kStateConnecting || mState == kStateConnected; } MarkAsNotUsed(void)252 void MarkAsNotUsed(void) { mNext = this; } 253 void SetState(State aState); Matches(const Ip6::MessageInfo & aInfo) const254 bool Matches(const Ip6::MessageInfo &aInfo) const { return mMessageInfo.HasSamePeerAddrAndPort(aInfo); } Matches(State aState) const255 bool Matches(State aState) const { return (mState == aState); } 256 void Accept(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 257 void HandleTransportReceive(Message &aMessage); 258 Error Setup(void); 259 void Disconnect(ConnectEvent aEvent); 260 void HandleTimer(TimeMilli aNow); 261 void Process(void); 262 void FreeMbedtls(void); 263 264 static int HandleMbedtlsGetTimer(void *aContext); 265 int HandleMbedtlsGetTimer(void); 266 static void HandleMbedtlsSetTimer(void *aContext, uint32_t aIntermediate, uint32_t aFinish); 267 void HandleMbedtlsSetTimer(uint32_t aIntermediate, uint32_t aFinish); 268 static int HandleMbedtlsReceive(void *aContext, unsigned char *aBuf, size_t aLength); 269 int HandleMbedtlsReceive(unsigned char *aBuf, size_t aLength); 270 static int HandleMbedtlsTransmit(void *aContext, const unsigned char *aBuf, size_t aLength); 271 int HandleMbedtlsTransmit(const unsigned char *aBuf, size_t aLength); 272 273 static bool IsMbedtlsHandshakeOver(mbedtls_ssl_context *aSslContext); 274 275 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) 276 static const char *StateToString(State aState); 277 #endif 278 279 bool mTimerSet : 1; 280 bool mIsServer : 1; 281 State mState; 282 Message::SubType mMessageSubType; 283 ConnectEvent mConnectEvent; 284 TimeMilli mTimerIntermediate; 285 TimeMilli mTimerFinish; 286 SecureSession *mNext; 287 SecureTransport &mTransport; 288 Message *mReceiveMessage; 289 Ip6::MessageInfo mMessageInfo; 290 Callback<ConnectHandler> mConnectedCallback; 291 Callback<ReceiveHandler> mReceiveCallback; 292 mbedtls_ssl_config mConf; 293 mbedtls_ssl_context mSsl; 294 #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_COOKIE_C) 295 mbedtls_ssl_cookie_ctx mCookieCtx; 296 #endif 297 }; 298 299 /** 300 * Represents a secure transport, used as base class for `Dtls` and `Tls`. 301 */ 302 class SecureTransport : private NonCopyable 303 { 304 friend class SecureSession; 305 306 public: 307 static constexpr uint8_t kPskMaxLength = 32; ///< Maximum PSK length. 308 309 /** 310 * Pointer is called to send encrypted message. 311 * 312 * @param[in] aContext A pointer to arbitrary context information. 313 * @param[in] aMessage A reference to the message to send. 314 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 315 */ 316 typedef Error (*TransportCallback)(void *aContext, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 317 318 /** 319 * Callback to notify when the socket is automatically closed due to reaching the maximum number of connection 320 * attempts (set from `SetMaxConnectionAttempts()`). 321 * 322 * @param[in] aContext A pointer to arbitrary context information. 323 */ 324 typedef void (*AutoCloseCallback)(void *aContext); 325 326 /** 327 * Callback to accept a new session connection request, providing the secure session to use. 328 * 329 * This method returns a pointer to a new `SecureSession` to use for the new session. The `SecureTransport` takes 330 * over the ownership of the given `SecureSession`. Once the session is disconnected and removed from the transport, 331 * the secure transport signals this using the `RemoveSessionCallback` callback, where ownership is released. 332 * 333 * `nullptr` can be returned to reject the new session connection request. 334 * 335 * @param[in] aContex A pointer to arbitrary context information. 336 * @param[in] aMessageInfo The message info from the new session connection request message. 337 * 338 * @returns A pointer to `SecureSession` to use for new session or `nullptr` if new connection is rejected. 339 */ 340 typedef SecureSession *(*AcceptCallback)(void *aContext, const Ip6::MessageInfo &aMessageInfo); 341 342 /** 343 * Callback to signal a session is removed, releasing the ownership of the session (by `SecureTransport`). 344 * 345 * @param[in] aContex A pointer to arbitrary context information. 346 * @param[in] aSesssion The session being removed. 347 */ 348 typedef void (*RemoveSessionCallback)(void *aContext, SecureSession &aSesssion); 349 350 #if OPENTHREAD_CONFIG_TLS_API_ENABLE 351 /** 352 * Represents an API extension for a `SecureTransport` (DTLS or TLS). 353 * 354 * The `Extension` provides support for additional cipher suites along with related methods to configure them. 355 * This class decouples this functionality from the common `SecureTransport` object, allowing this to be added 356 * to any class. 357 * 358 * The general pattern to use the `Extension` class is to have it be inherited by classes that want to provide the 359 * same methods for configuring ciphers (e.g. `SetPreSharedKey()` or `SetCertificate()`). An `Extension` should 360 * then be associated with a `SecureTransport` (or any of its subclasses). 361 */ 362 class Extension 363 { 364 friend SecureTransport; 365 friend SecureSession; 366 367 public: 368 #ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED 369 /** 370 * Sets the Pre-Shared Key (PSK) for sessions-identified by a PSK. 371 * 372 * DTLS mode "PSK with AES 128 CCM 8" for Application CoAPS. 373 * 374 * @param[in] aPsk A pointer to the PSK. 375 * @param[in] aPskLength The PSK char length. 376 * @param[in] aPskIdentity The Identity Name for the PSK. 377 * @param[in] aPskIdLength The PSK Identity Length. 378 */ 379 void SetPreSharedKey(const uint8_t *aPsk, 380 uint16_t aPskLength, 381 const uint8_t *aPskIdentity, 382 uint16_t aPskIdLength); 383 #endif 384 385 #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED 386 /** 387 * Sets a reference to the own x509 certificate with corresponding private key. 388 * 389 * DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS. 390 * 391 * @param[in] aX509Certificate A pointer to the PEM formatted X509 certificate. 392 * @param[in] aX509CertLength The length of certificate. 393 * @param[in] aPrivateKey A pointer to the PEM formatted private key. 394 * @param[in] aPrivateKeyLength The length of the private key. 395 */ 396 void SetCertificate(const uint8_t *aX509Certificate, 397 uint32_t aX509CertLength, 398 const uint8_t *aPrivateKey, 399 uint32_t aPrivateKeyLength); 400 401 /** 402 * Sets the trusted top level CAs. It is needed for validate the certificate of the peer. 403 * 404 * DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS. 405 * 406 * @param[in] aX509CaCertificateChain A pointer to the PEM formatted X509 CA chain. 407 * @param[in] aX509CaCertChainLength The length of chain. 408 */ 409 void SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength); 410 411 /** 412 * Extracts public key from it's own certificate. 413 * 414 * @returns Public key from own certificate in form of entire ASN.1 field. 415 */ GetOwnPublicKey(void) const416 const mbedtls_asn1_buf &GetOwnPublicKey(void) const { return mEcdheEcdsaInfo.mOwnCert.pk_raw; } 417 418 #endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED 419 420 #if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 421 /** 422 * Returns the peer x509 certificate base64 encoded. 423 * 424 * DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS. 425 * 426 * @param[out] aPeerCert A pointer to the base64 encoded certificate buffer. 427 * @param[out] aCertLength The length of the base64 encoded peer certificate. 428 * @param[in] aCertBufferSize The buffer size of aPeerCert. 429 * 430 * @retval kErrorInvalidState Not connected yet. 431 * @retval kErrorNone Successfully get the peer certificate. 432 * @retval kErrorNoBufs Can't allocate memory for certificate. 433 */ 434 Error GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize); 435 #endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 436 437 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 438 /** 439 * Returns an attribute value identified by its OID from the subject 440 * of the peer x509 certificate. The peer OID is provided in binary format. 441 * The attribute length is set if the attribute was successfully read or zero 442 * if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard 443 * if the attribute was successfully read. 444 * 445 * @param[in] aOid A pointer to the OID to be found. 446 * @param[in] aOidLength The length of the OID. 447 * @param[out] aAttributeBuffer A pointer to the attribute buffer. 448 * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. 449 * On output, the length of the attribute written to the buffer. 450 * @param[out] aAsn1Type A pointer to the ASN.1 type of the attribute written to the buffer. 451 * 452 * @retval kErrorInvalidState Not connected yet. 453 * @retval kErrorInvalidArgs Invalid attribute length. 454 * @retval kErrorNone Successfully read attribute. 455 * @retval kErrorNoBufs Insufficient memory for storing the attribute value. 456 */ 457 Error GetPeerSubjectAttributeByOid(const char *aOid, 458 size_t aOidLength, 459 uint8_t *aAttributeBuffer, 460 size_t *aAttributeLength, 461 int *aAsn1Type); 462 463 /** 464 * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of 465 * the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor. 466 * The attribute length is set if the attribute was successfully read or zero if unsuccessful. 467 * Requires a connection to be active. 468 * 469 * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. 470 * @param[out] aAttributeBuffer A pointer to the attribute buffer. 471 * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. 472 * On output, the length of the attribute written to the buffer. 473 * 474 * @retval kErrorNone Successfully read attribute. 475 * @retval kErrorInvalidArgs Invalid attribute length. 476 * @retval kErrorNotFound The requested attribute was not found. 477 * @retval kErrorNoBufs Insufficient memory for storing the attribute value. 478 * @retval kErrorInvalidState Not connected yet. 479 * @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127. 480 * @retval kErrorParse The certificate extensions could not be parsed. 481 */ 482 Error GetThreadAttributeFromPeerCertificate(int aThreadOidDescriptor, 483 uint8_t *aAttributeBuffer, 484 size_t *aAttributeLength); 485 #endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) 486 487 /** 488 * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of 489 * the own x509 certificate, where the last digit x is set to aThreadOidDescriptor. 490 * The attribute length is set if the attribute was successfully read or zero if unsuccessful. 491 * Requires a connection to be active. 492 * 493 * @param[in] aThreadOidDescriptor The last digit of the Thread attribute OID. 494 * @param[out] aAttributeBuffer A pointer to the attribute buffer. 495 * @param[in,out] aAttributeLength On input, the size the max size of @p aAttributeBuffer. 496 * On output, the length of the attribute written to the buffer. 497 * 498 * @retval kErrorNone Successfully read attribute. 499 * @retval kErrorInvalidArgs Invalid attribute length. 500 * @retval kErrorNotFound The requested attribute was not found. 501 * @retval kErrorNoBufs Insufficient memory for storing the attribute value. 502 * @retval kErrorInvalidState Not connected yet. 503 * @retval kErrorNotImplemented The value of aThreadOidDescriptor is >127. 504 * @retval kErrorParse The certificate extensions could not be parsed. 505 */ 506 Error GetThreadAttributeFromOwnCertificate(int aThreadOidDescriptor, 507 uint8_t *aAttributeBuffer, 508 size_t *aAttributeLength); 509 510 /** 511 * Set the authentication mode for a connection. 512 * 513 * Disable or enable the verification of peer certificate. 514 * Must called before start. 515 * 516 * @param[in] aVerifyPeerCertificate true, if the peer certificate should verify. 517 */ SetSslAuthMode(bool aVerifyPeerCertificate)518 void SetSslAuthMode(bool aVerifyPeerCertificate) 519 { 520 mSecureTransport.mVerifyPeerCertificate = aVerifyPeerCertificate; 521 } 522 523 protected: Extension(SecureTransport & aSecureTransport)524 explicit Extension(SecureTransport &aSecureTransport) 525 : mSecureTransport(aSecureTransport) 526 { 527 } 528 529 private: 530 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) 531 struct EcdheEcdsaInfo : public Clearable<EcdheEcdsaInfo> 532 { EcdheEcdsaInfoot::MeshCoP::SecureTransport::Extension::EcdheEcdsaInfo533 EcdheEcdsaInfo(void) { Clear(); } 534 void Init(void); 535 void Free(void); 536 int SetSecureKeys(mbedtls_ssl_config &aConfig); 537 538 const uint8_t *mCaChainSrc; 539 const uint8_t *mOwnCertSrc; 540 const uint8_t *mPrivateKeySrc; 541 uint32_t mOwnCertLength; 542 uint32_t mCaChainLength; 543 uint32_t mPrivateKeyLength; 544 mbedtls_x509_crt mCaChain; 545 mbedtls_x509_crt mOwnCert; 546 mbedtls_pk_context mPrivateKey; 547 }; 548 #endif 549 550 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) 551 struct PskInfo : public Clearable<PskInfo> 552 { PskInfoot::MeshCoP::SecureTransport::Extension::PskInfo553 PskInfo(void) { Clear(); } 554 int SetSecureKeys(mbedtls_ssl_config &aConfig) const; 555 556 const uint8_t *mPreSharedKey; 557 const uint8_t *mPreSharedKeyIdentity; 558 uint16_t mPreSharedKeyLength; 559 uint16_t mPreSharedKeyIdLength; 560 }; 561 #endif 562 563 int SetApplicationSecureKeys(mbedtls_ssl_config &aConfig); 564 Error GetThreadAttributeFromCertificate(const mbedtls_x509_crt *aCert, 565 int aThreadOidDescriptor, 566 uint8_t *aAttributeBuffer, 567 size_t *aAttributeLength); 568 569 SecureTransport &mSecureTransport; 570 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) 571 EcdheEcdsaInfo mEcdheEcdsaInfo; 572 #endif 573 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) 574 PskInfo mPskInfo; 575 #endif 576 }; 577 #endif // OPENTHREAD_CONFIG_TLS_API_ENABLE 578 579 /** 580 * Opens the transport. 581 * 582 * @retval kErrorNone Successfully opened the socket. 583 * @retval kErrorAlready The connection is already open. 584 */ 585 Error Open(void); 586 587 /** 588 * Sets the maximum number of allowed connection requests before socket is automatically closed. 589 * 590 * This method can be called when socket is closed. Otherwise `kErrorInvalidSatet` is returned. 591 * 592 * If @p aMaxAttempts is zero, no limit is applied and connections are allowed until the socket is closed. This is 593 * the default behavior if `SetMaxConnectionAttempts()` is not called. 594 * 595 * @param[in] aMaxAttempts Maximum number of allowed connection attempts. 596 * @param[in] aCallback Callback to notify when max number of attempts has reached and socket is closed. 597 * @param[in] aContext A pointer to arbitrary context to use with `AutoCloseCallback`. 598 * 599 * @retval kErrorNone Successfully set the maximum allowed connection attempts and callback. 600 * @retval kErrorInvalidState Socket is not closed. 601 */ 602 Error SetMaxConnectionAttempts(uint16_t aMaxAttempts, AutoCloseCallback aCallback, void *aContext); 603 604 /** 605 * Sets the `AcceptCallback` used to accept new session connection requests. 606 * 607 * @param[in] aCallback The `AcceptCallback`. 608 * @param[in] aConext A pointer to arbitrary context to use with `AcceptCallback`. 609 */ SetAcceptCallback(AcceptCallback aCallback,void * aContext)610 void SetAcceptCallback(AcceptCallback aCallback, void *aContext) { mAcceptCallback.Set(aCallback, aContext); } 611 612 /** 613 * Sets the `RemoveSessionCallback` used to signal when a session is removed. 614 * 615 * @param[in] aCallback The `RemoveSessionCallback`. 616 * @param[in] aConext A pointer to arbitrary context to use with `RemoveSessionCallback`. 617 */ SetRemoveSessionCallback(RemoveSessionCallback aCallback,void * aContext)618 void SetRemoveSessionCallback(RemoveSessionCallback aCallback, void *aContext) 619 { 620 mRemoveSessionCallback.Set(aCallback, aContext); 621 } 622 623 /** 624 * Binds this DTLS to a UDP port. 625 * 626 * @param[in] aPort The port to bind. 627 * 628 * @retval kErrorNone Successfully bound the socket. 629 * @retval kErrorInvalidState The socket is not open. 630 * @retval kErrorAlready Already bound. 631 */ 632 Error Bind(uint16_t aPort); 633 634 /** 635 * Gets the UDP port of this session. 636 * 637 * @returns UDP port number. 638 */ GetUdpPort(void) const639 uint16_t GetUdpPort(void) const { return mSocket.GetSockName().GetPort(); } 640 641 /** 642 * Binds with a transport callback. 643 * 644 * @param[in] aCallback A pointer to a function for sending messages. 645 * @param[in] aContext A pointer to arbitrary context information. 646 * 647 * @retval kErrorNone Successfully bound the socket. 648 * @retval kErrorInvalidState The socket is not open. 649 * @retval kErrorAlready Already bound. 650 */ 651 Error Bind(TransportCallback aCallback, void *aContext); 652 653 /** 654 * Indicates whether or not the secure transpose socket is closed. 655 * 656 * @retval TRUE The secure transport socket closed. 657 * @retval FALSE The secure transport socket is not closed. 658 */ IsClosed(void) const659 bool IsClosed(void) const { return !mIsOpen; } 660 661 /** 662 * Closes the socket. 663 */ 664 void Close(void); 665 666 /** 667 * Sets the PSK. 668 * 669 * @param[in] aPsk A pointer to the PSK. 670 * 671 * @retval kErrorNone Successfully set the PSK. 672 * @retval kErrorInvalidArgs The PSK is invalid. 673 */ 674 Error SetPsk(const uint8_t *aPsk, uint8_t aPskLength); 675 676 /** 677 * Sets the PSK. 678 * 679 * @param[in] aPskd A Joiner PSKd. 680 */ 681 void SetPsk(const JoinerPskd &aPskd); 682 683 /** 684 * Checks and handles a received message provided to the SecureTransport object. If checks based on 685 * the message info and current connection state pass, the message is processed. 686 * 687 * @param[in] aMessage A reference to the message to receive. 688 * @param[in] aMessageInfo A reference to the message info associated with @p aMessage. 689 */ 690 void HandleReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); 691 692 /** 693 * Get the list of sessions associated with the `SecureTransport`. 694 * 695 * @returns The list of associated sessions. 696 */ GetSessions(void)697 LinkedList<SecureSession> &GetSessions(void) { return mSessions; } 698 699 protected: 700 SecureTransport(Instance &aInstance, LinkSecurityMode aLayerTwoSecurity, bool aDatagramTransport); 701 702 #if OPENTHREAD_CONFIG_TLS_API_ENABLE SetExtension(Extension & aExtension)703 void SetExtension(Extension &aExtension) { mExtension = &aExtension; } 704 #endif 705 706 private: 707 static constexpr size_t kSecureTransportKeyBlockSize = 40; 708 static constexpr size_t kSecureTransportRandomBufferSize = 32; 709 710 enum CipherSuite : uint8_t 711 { 712 kEcjpakeWithAes128Ccm8, 713 #if OPENTHREAD_CONFIG_TLS_API_ENABLE && defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) 714 kPskWithAes128Ccm8, 715 #endif 716 #if OPENTHREAD_CONFIG_TLS_API_ENABLE && defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) 717 kEcdheEcdsaWithAes128Ccm8, 718 kEcdheEcdsaWithAes128GcmSha256, 719 #endif 720 kUnspecifiedCipherSuite, 721 }; 722 723 void RemoveDisconnectedSessions(void); 724 void DecremenetRemainingConnectionAttempts(void); 725 bool HasNoRemainingConnectionAttempts(void) const; 726 int Transmit(const unsigned char *aBuf, 727 size_t aLength, 728 const Ip6::MessageInfo &aMessageInfo, 729 Message::SubType aMessageSubType); 730 731 static void HandleMbedtlsDebug(void *aContext, int aLevel, const char *aFile, int aLine, const char *aStr); 732 void HandleMbedtlsDebug(int aLevel, const char *aFile, int aLine, const char *aStr); 733 734 #ifdef MBEDTLS_SSL_EXPORT_KEYS 735 #if (MBEDTLS_VERSION_NUMBER >= 0x03000000) 736 737 static void HandleMbedtlsExportKeys(void *aContext, 738 mbedtls_ssl_key_export_type aType, 739 const unsigned char *aMasterSecret, 740 size_t aMasterSecretLen, 741 const unsigned char aClientRandom[32], 742 const unsigned char aServerRandom[32], 743 mbedtls_tls_prf_types aTlsPrfType); 744 745 void HandleMbedtlsExportKeys(mbedtls_ssl_key_export_type aType, 746 const unsigned char *aMasterSecret, 747 size_t aMasterSecretLen, 748 const unsigned char aClientRandom[32], 749 const unsigned char aServerRandom[32], 750 mbedtls_tls_prf_types aTlsPrfType); 751 752 #else 753 754 static int HandleMbedtlsExportKeys(void *aContext, 755 const unsigned char *aMasterSecret, 756 const unsigned char *aKeyBlock, 757 size_t aMacLength, 758 size_t aKeyLength, 759 size_t aIvLength); 760 int HandleMbedtlsExportKeys(const unsigned char *aMasterSecret, 761 const unsigned char *aKeyBlock, 762 size_t aMacLength, 763 size_t aKeyLength, 764 size_t aIvLength); 765 766 #endif // (MBEDTLS_VERSION_NUMBER >= 0x03000000) 767 #endif // MBEDTLS_SSL_EXPORT_KEYS 768 769 static void HandleUpdateTask(Tasklet &aTasklet); 770 void HandleUpdateTask(void); 771 static void HandleTimer(Timer &aTimer); 772 void HandleTimer(void); 773 774 using TransportSocket = Ip6::Udp::SocketIn<SecureTransport, &SecureTransport::HandleReceive>; 775 776 #if (MBEDTLS_VERSION_NUMBER >= 0x03010000) 777 static const uint16_t kGroups[]; 778 #else 779 static const mbedtls_ecp_group_id kCurves[]; 780 #endif 781 782 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) || defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) 783 #if (MBEDTLS_VERSION_NUMBER >= 0x03020000) 784 static const uint16_t kSignatures[]; 785 #else 786 static const int kHashes[]; 787 #endif 788 #endif 789 790 static const int kCipherSuites[][2]; 791 792 bool mLayerTwoSecurity : 1; 793 bool mDatagramTransport : 1; 794 bool mIsOpen : 1; 795 bool mIsClosing : 1; 796 bool mVerifyPeerCertificate : 1; 797 CipherSuite mCipherSuite; 798 uint8_t mPskLength; 799 uint16_t mMaxConnectionAttempts; 800 uint16_t mRemainingConnectionAttempts; 801 LinkedList<SecureSession> mSessions; 802 TransportSocket mSocket; 803 uint8_t mPsk[kPskMaxLength]; 804 TimerMilliContext mTimer; 805 TaskletContext mUpdateTask; 806 Callback<AutoCloseCallback> mAutoCloseCallback; 807 Callback<AcceptCallback> mAcceptCallback; 808 Callback<RemoveSessionCallback> mRemoveSessionCallback; 809 Callback<TransportCallback> mTransportCallback; 810 #if OPENTHREAD_CONFIG_TLS_API_ENABLE 811 Extension *mExtension; 812 #endif 813 }; 814 815 /** 816 * Defines DTLS `Transport` and `Session`. 817 */ 818 class Dtls 819 { 820 public: 821 class Session; 822 823 /** 824 * Represents a DTLS transport. 825 */ 826 class Transport : public SecureTransport 827 { 828 friend class Session; 829 830 public: 831 /** 832 * Initializes the `Dtls::Transport` object. 833 * 834 * @param[in] aInstance A reference to the OpenThread instance. 835 * @param[in] aLayerTwoSecurity Specifies whether to use layer two security or not. 836 */ Transport(Instance & aInstance,LinkSecurityMode aLayerTwoSecurity)837 Transport(Instance &aInstance, LinkSecurityMode aLayerTwoSecurity) 838 : SecureTransport(aInstance, aLayerTwoSecurity, /* aDatagramTransport */ true) 839 { 840 } 841 }; 842 843 /** 844 * Represents a DTLS session. 845 */ 846 class Session : public SecureSession 847 { 848 public: 849 /** 850 * Initializes the `Dtls::Session` object. 851 * 852 * @param[in] aTransport The DTLS transport to use for this session. 853 */ Session(Transport & aTransport)854 Session(Transport &aTransport) 855 : SecureSession(aTransport) 856 { 857 } 858 859 /** 860 * Returns the DTLS transport used by this session. 861 * 862 * @returns The DTLS transport associated with this session. 863 */ GetTransport(void)864 Transport &GetTransport(void) { return static_cast<Transport &>(SecureSession::GetTransport()); } 865 }; 866 }; 867 868 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE 869 870 /** 871 * Represents a TLS instance. 872 */ 873 class Tls : public SecureTransport, public SecureSession 874 { 875 public: 876 /** 877 * Initializes the `Tls` object. 878 * 879 * @param[in] aInstance A reference to the OpenThread instance. 880 * @param[in] aLayerTwoSecurity Specifies whether to use layer two security or not. 881 * @param[in] aExtension An extension providing additional configuration methods. 882 */ Tls(Instance & aInstance,LinkSecurityMode aLayerTwoSecurity,Extension & aExtension)883 Tls(Instance &aInstance, LinkSecurityMode aLayerTwoSecurity, Extension &aExtension) 884 : SecureTransport(aInstance, aLayerTwoSecurity, /* aDatagramTransport */ false) 885 , SecureSession(*static_cast<SecureTransport *>(this)) 886 { 887 SetExtension(aExtension); 888 SetAcceptCallback(&HandleAccept, this); 889 } 890 891 private: 892 static SecureSession *HandleAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo); 893 SecureSession *HandleAccept(void); 894 }; 895 896 #endif 897 898 } // namespace MeshCoP 899 } // namespace ot 900 901 #endif // SECURE_TRANSPORT_HPP_ 902