• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 : public 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 the DER encoded peer x509 certificate.
440          *
441          * @param[out]  aPeerCert        A pointer to the DER encoded certificate buffer.
442          * @param[out]  aCertLength      The length of the DER encoded peer certificate.
443          * @param[in]   aCertBufferSize  The buffer size of aPeerCert.
444          *
445          * @retval kErrorInvalidState   Not connected yet.
446          * @retval kErrorNone           Successfully get the peer certificate.
447          * @retval kErrorNoBufs         Can't allocate memory for certificate.
448          */
449         Error GetPeerCertificateDer(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize);
450 
451         /**
452          * Returns an attribute value identified by its OID from the subject
453          * of the peer x509 certificate. The peer OID is provided in binary format.
454          * The attribute length is set if the attribute was successfully read or zero
455          * if unsuccessful. The ASN.1 type as is set as defineded in the ITU-T X.690 standard
456          * if the attribute was successfully read.
457          *
458          * @param[in]     aOid                A pointer to the OID to be found.
459          * @param[in]     aOidLength          The length of the OID.
460          * @param[out]    aAttributeBuffer    A pointer to the attribute buffer.
461          * @param[in,out] aAttributeLength    On input, the size the max size of @p aAttributeBuffer.
462          *                                    On output, the length of the attribute written to the buffer.
463          * @param[out]    aAsn1Type           A pointer to the ASN.1 type of the attribute written to the buffer.
464          *
465          * @retval kErrorInvalidState   Not connected yet.
466          * @retval kErrorInvalidArgs    Invalid attribute length.
467          * @retval kErrorNone           Successfully read attribute.
468          * @retval kErrorNoBufs         Insufficient memory for storing the attribute value.
469          */
470         Error GetPeerSubjectAttributeByOid(const char *aOid,
471                                            size_t      aOidLength,
472                                            uint8_t    *aAttributeBuffer,
473                                            size_t     *aAttributeLength,
474                                            int        *aAsn1Type);
475 
476         /**
477          * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of
478          * the peer x509 certificate, where the last digit x is set to aThreadOidDescriptor.
479          * The attribute length is set if the attribute was successfully read or zero if unsuccessful.
480          * Requires a connection to be active.
481          *
482          * @param[in]      aThreadOidDescriptor  The last digit of the Thread attribute OID.
483          * @param[out]     aAttributeBuffer      A pointer to the attribute buffer.
484          * @param[in,out]  aAttributeLength      On input, the size the max size of @p aAttributeBuffer.
485          *                                           On output, the length of the attribute written to the buffer.
486          *
487          * @retval kErrorNone             Successfully read attribute.
488          * @retval kErrorInvalidArgs      Invalid attribute length.
489          * @retval kErrorNotFound         The requested attribute was not found.
490          * @retval kErrorNoBufs           Insufficient memory for storing the attribute value.
491          * @retval kErrorInvalidState     Not connected yet.
492          * @retval kErrorNotImplemented   The value of aThreadOidDescriptor is >127.
493          * @retval kErrorParse            The certificate extensions could not be parsed.
494          */
495         Error GetThreadAttributeFromPeerCertificate(int      aThreadOidDescriptor,
496                                                     uint8_t *aAttributeBuffer,
497                                                     size_t  *aAttributeLength);
498 #endif // defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
499 
500         /**
501          * Returns an attribute value for the OID 1.3.6.1.4.1.44970.x from the v3 extensions of
502          * the own x509 certificate, where the last digit x is set to aThreadOidDescriptor.
503          * The attribute length is set if the attribute was successfully read or zero if unsuccessful.
504          * Requires a connection to be active.
505          *
506          * @param[in]      aThreadOidDescriptor  The last digit of the Thread attribute OID.
507          * @param[out]     aAttributeBuffer      A pointer to the attribute buffer.
508          * @param[in,out]  aAttributeLength      On input, the size the max size of @p aAttributeBuffer.
509          *                                       On output, the length of the attribute written to the buffer.
510          *
511          * @retval kErrorNone             Successfully read attribute.
512          * @retval kErrorInvalidArgs      Invalid attribute length.
513          * @retval kErrorNotFound         The requested attribute was not found.
514          * @retval kErrorNoBufs           Insufficient memory for storing the attribute value.
515          * @retval kErrorInvalidState     Not connected yet.
516          * @retval kErrorNotImplemented   The value of aThreadOidDescriptor is >127.
517          * @retval kErrorParse            The certificate extensions could not be parsed.
518          */
519         Error GetThreadAttributeFromOwnCertificate(int      aThreadOidDescriptor,
520                                                    uint8_t *aAttributeBuffer,
521                                                    size_t  *aAttributeLength);
522 
523         /**
524          * Set the authentication mode for a connection.
525          *
526          * Disable or enable the verification of peer certificate.
527          * Must called before start.
528          *
529          * @param[in]  aVerifyPeerCertificate  true, if the peer certificate should verify.
530          */
SetSslAuthMode(bool aVerifyPeerCertificate)531         void SetSslAuthMode(bool aVerifyPeerCertificate)
532         {
533             mSecureTransport.mVerifyPeerCertificate = aVerifyPeerCertificate;
534         }
535 
536     protected:
Extension(SecureTransport & aSecureTransport)537         explicit Extension(SecureTransport &aSecureTransport)
538             : mSecureTransport(aSecureTransport)
539         {
540         }
541 
542     private:
543 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
544         struct EcdheEcdsaInfo : public Clearable<EcdheEcdsaInfo>
545         {
EcdheEcdsaInfoot::MeshCoP::SecureTransport::Extension::EcdheEcdsaInfo546             EcdheEcdsaInfo(void) { Clear(); }
547             void Init(void);
548             void Free(void);
549             int  SetSecureKeys(mbedtls_ssl_config &aConfig);
550 
551             const uint8_t     *mCaChainSrc;
552             const uint8_t     *mOwnCertSrc;
553             const uint8_t     *mPrivateKeySrc;
554             uint32_t           mOwnCertLength;
555             uint32_t           mCaChainLength;
556             uint32_t           mPrivateKeyLength;
557             mbedtls_x509_crt   mCaChain;
558             mbedtls_x509_crt   mOwnCert;
559             mbedtls_pk_context mPrivateKey;
560         };
561 #endif
562 
563 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
564         struct PskInfo : public Clearable<PskInfo>
565         {
PskInfoot::MeshCoP::SecureTransport::Extension::PskInfo566             PskInfo(void) { Clear(); }
567             int SetSecureKeys(mbedtls_ssl_config &aConfig) const;
568 
569             const uint8_t *mPreSharedKey;
570             const uint8_t *mPreSharedKeyIdentity;
571             uint16_t       mPreSharedKeyLength;
572             uint16_t       mPreSharedKeyIdLength;
573         };
574 #endif
575 
576         int   SetApplicationSecureKeys(mbedtls_ssl_config &aConfig);
577         Error GetThreadAttributeFromCertificate(const mbedtls_x509_crt *aCert,
578                                                 int                     aThreadOidDescriptor,
579                                                 uint8_t                *aAttributeBuffer,
580                                                 size_t                 *aAttributeLength);
581 
582         SecureTransport &mSecureTransport;
583 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
584         EcdheEcdsaInfo mEcdheEcdsaInfo;
585 #endif
586 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
587         PskInfo mPskInfo;
588 #endif
589     };
590 #endif // OPENTHREAD_CONFIG_TLS_API_ENABLE
591 
592     /**
593      * Opens the transport.
594      *
595      * @param[in] aNetifIdentifier A network interface identifier. If not explicitly provided, kNetifUnspecified will
596      *                             be used by default.
597      *
598      * @retval kErrorNone     Successfully opened the socket.
599      * @retval kErrorAlready  The connection is already open.
600      */
601     Error Open(Ip6::NetifIdentifier aNetifIdentifier = Ip6::NetifIdentifier::kNetifUnspecified);
602 
603     /**
604      * Sets the maximum number of allowed connection requests before socket is automatically closed.
605      *
606      * This method can be called when socket is closed. Otherwise `kErrorInvalidSatet` is returned.
607      *
608      * If @p aMaxAttempts is zero, no limit is applied and connections are allowed until the socket is closed. This is
609      * the default behavior if `SetMaxConnectionAttempts()` is not called.
610      *
611      * @param[in] aMaxAttempts    Maximum number of allowed connection attempts.
612      * @param[in] aCallback       Callback to notify when max number of attempts has reached and socket is closed.
613      * @param[in] aContext        A pointer to arbitrary context to use with `AutoCloseCallback`.
614      *
615      * @retval kErrorNone          Successfully set the maximum allowed connection attempts and callback.
616      * @retval kErrorInvalidState  Socket is not closed.
617      */
618     Error SetMaxConnectionAttempts(uint16_t aMaxAttempts, AutoCloseCallback aCallback, void *aContext);
619 
620     /**
621      * Sets the `AcceptCallback` used to accept new session connection requests.
622      *
623      * @param[in] aCallback   The `AcceptCallback`.
624      * @param[in] aConext     A pointer to arbitrary context to use with `AcceptCallback`.
625      */
SetAcceptCallback(AcceptCallback aCallback,void * aContext)626     void SetAcceptCallback(AcceptCallback aCallback, void *aContext) { mAcceptCallback.Set(aCallback, aContext); }
627 
628     /**
629      * Sets the `RemoveSessionCallback` used to signal when a session is removed.
630      *
631      * @param[in] aCallback   The `RemoveSessionCallback`.
632      * @param[in] aConext     A pointer to arbitrary context to use with `RemoveSessionCallback`.
633      */
SetRemoveSessionCallback(RemoveSessionCallback aCallback,void * aContext)634     void SetRemoveSessionCallback(RemoveSessionCallback aCallback, void *aContext)
635     {
636         mRemoveSessionCallback.Set(aCallback, aContext);
637     }
638 
639     /**
640      * Binds this DTLS to a UDP port.
641      *
642      * @param[in]  aPort              The port to bind.
643      *
644      * @retval kErrorNone           Successfully bound the socket.
645      * @retval kErrorInvalidState   The socket is not open.
646      * @retval kErrorAlready        Already bound.
647      */
648     Error Bind(uint16_t aPort);
649 
650     /**
651      * Gets the UDP port of this session.
652      *
653      * @returns  UDP port number.
654      */
GetUdpPort(void) const655     uint16_t GetUdpPort(void) const { return mSocket.GetSockName().GetPort(); }
656 
657     /**
658      * Binds with a transport callback.
659      *
660      * @param[in]  aCallback  A pointer to a function for sending messages.
661      * @param[in]  aContext   A pointer to arbitrary context information.
662      *
663      * @retval kErrorNone           Successfully bound the socket.
664      * @retval kErrorInvalidState   The socket is not open.
665      * @retval kErrorAlready        Already bound.
666      */
667     Error Bind(TransportCallback aCallback, void *aContext);
668 
669     /**
670      * Indicates whether or not the secure transpose socket is closed.
671      *
672      * @retval TRUE   The secure transport socket closed.
673      * @retval FALSE  The secure transport socket is not closed.
674      */
IsClosed(void) const675     bool IsClosed(void) const { return !mIsOpen; }
676 
677     /**
678      * Closes the socket.
679      */
680     void Close(void);
681 
682     /**
683      * Sets the PSK.
684      *
685      * @param[in]  aPsk  A pointer to the PSK.
686      *
687      * @retval kErrorNone          Successfully set the PSK.
688      * @retval kErrorInvalidArgs   The PSK is invalid.
689      */
690     Error SetPsk(const uint8_t *aPsk, uint8_t aPskLength);
691 
692     /**
693      * Sets the PSK.
694      *
695      * @param[in]  aPskd  A Joiner PSKd.
696      */
697     void SetPsk(const JoinerPskd &aPskd);
698 
699     /**
700      * Checks and handles a received message provided to the SecureTransport object. If checks based on
701      * the message info and current connection state pass, the message is processed.
702      *
703      * @param[in]  aMessage  A reference to the message to receive.
704      * @param[in]  aMessageInfo A reference to the message info associated with @p aMessage.
705      */
706     void HandleReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
707 
708     /**
709      * Get the list of sessions associated with the `SecureTransport`.
710      *
711      * @returns The list of associated sessions.
712      */
GetSessions(void)713     LinkedList<SecureSession> &GetSessions(void) { return mSessions; }
714 
715 protected:
716     SecureTransport(Instance &aInstance, LinkSecurityMode aLayerTwoSecurity, bool aDatagramTransport);
717 
718 #if OPENTHREAD_CONFIG_TLS_API_ENABLE
SetExtension(Extension & aExtension)719     void SetExtension(Extension &aExtension) { mExtension = &aExtension; }
720 #endif
721 
722 private:
723     static constexpr size_t kSecureTransportKeyBlockSize     = 40;
724     static constexpr size_t kSecureTransportRandomBufferSize = 32;
725 
726     enum CipherSuite : uint8_t
727     {
728         kEcjpakeWithAes128Ccm8,
729 #if OPENTHREAD_CONFIG_TLS_API_ENABLE && defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
730         kPskWithAes128Ccm8,
731 #endif
732 #if OPENTHREAD_CONFIG_TLS_API_ENABLE && defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
733         kEcdheEcdsaWithAes128Ccm8,
734         kEcdheEcdsaWithAes128GcmSha256,
735 #endif
736         kUnspecifiedCipherSuite,
737     };
738 
739     void RemoveDisconnectedSessions(void);
740     void DecremenetRemainingConnectionAttempts(void);
741     bool HasNoRemainingConnectionAttempts(void) const;
742     int  Transmit(const unsigned char    *aBuf,
743                   size_t                  aLength,
744                   const Ip6::MessageInfo &aMessageInfo,
745                   Message::SubType        aMessageSubType);
746 
747     static void HandleMbedtlsDebug(void *aContext, int aLevel, const char *aFile, int aLine, const char *aStr);
748     void        HandleMbedtlsDebug(int aLevel, const char *aFile, int aLine, const char *aStr);
749 
750 #ifdef MBEDTLS_SSL_EXPORT_KEYS
751 #if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
752 
753     static void HandleMbedtlsExportKeys(void                       *aContext,
754                                         mbedtls_ssl_key_export_type aType,
755                                         const unsigned char        *aMasterSecret,
756                                         size_t                      aMasterSecretLen,
757                                         const unsigned char         aClientRandom[32],
758                                         const unsigned char         aServerRandom[32],
759                                         mbedtls_tls_prf_types       aTlsPrfType);
760 
761     void HandleMbedtlsExportKeys(mbedtls_ssl_key_export_type aType,
762                                  const unsigned char        *aMasterSecret,
763                                  size_t                      aMasterSecretLen,
764                                  const unsigned char         aClientRandom[32],
765                                  const unsigned char         aServerRandom[32],
766                                  mbedtls_tls_prf_types       aTlsPrfType);
767 
768 #else
769 
770     static int       HandleMbedtlsExportKeys(void                *aContext,
771                                              const unsigned char *aMasterSecret,
772                                              const unsigned char *aKeyBlock,
773                                              size_t               aMacLength,
774                                              size_t               aKeyLength,
775                                              size_t               aIvLength);
776     int              HandleMbedtlsExportKeys(const unsigned char *aMasterSecret,
777                                              const unsigned char *aKeyBlock,
778                                              size_t               aMacLength,
779                                              size_t               aKeyLength,
780                                              size_t               aIvLength);
781 
782 #endif // (MBEDTLS_VERSION_NUMBER >= 0x03000000)
783 #endif // MBEDTLS_SSL_EXPORT_KEYS
784 
785     static void HandleUpdateTask(Tasklet &aTasklet);
786     void        HandleUpdateTask(void);
787     static void HandleTimer(Timer &aTimer);
788     void        HandleTimer(void);
789 
790     using TransportSocket = Ip6::Udp::SocketIn<SecureTransport, &SecureTransport::HandleReceive>;
791 
792 #if (MBEDTLS_VERSION_NUMBER >= 0x03010000)
793     static const uint16_t kGroups[];
794 #else
795     static const mbedtls_ecp_group_id kCurves[];
796 #endif
797 
798 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) || defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED)
799 #if (MBEDTLS_VERSION_NUMBER >= 0x03020000)
800     static const uint16_t kSignatures[];
801 #else
802     static const int kHashes[];
803 #endif
804 #endif
805 
806     static const int kCipherSuites[][2];
807 
808     bool                            mLayerTwoSecurity : 1;
809     bool                            mDatagramTransport : 1;
810     bool                            mIsOpen : 1;
811     bool                            mIsClosing : 1;
812     bool                            mVerifyPeerCertificate : 1;
813     CipherSuite                     mCipherSuite;
814     uint8_t                         mPskLength;
815     uint16_t                        mMaxConnectionAttempts;
816     uint16_t                        mRemainingConnectionAttempts;
817     LinkedList<SecureSession>       mSessions;
818     TransportSocket                 mSocket;
819     uint8_t                         mPsk[kPskMaxLength];
820     TimerMilliContext               mTimer;
821     TaskletContext                  mUpdateTask;
822     Callback<AutoCloseCallback>     mAutoCloseCallback;
823     Callback<AcceptCallback>        mAcceptCallback;
824     Callback<RemoveSessionCallback> mRemoveSessionCallback;
825     Callback<TransportCallback>     mTransportCallback;
826 #if OPENTHREAD_CONFIG_TLS_API_ENABLE
827     Extension *mExtension;
828 #endif
829 };
830 
831 /**
832  * Defines DTLS `Transport` and `Session`.
833  */
834 class Dtls
835 {
836 public:
837     class Session;
838 
839     /**
840      * Represents a DTLS transport.
841      */
842     class Transport : public SecureTransport
843     {
844         friend class Session;
845 
846     public:
847         /**
848          * Initializes the `Dtls::Transport` object.
849          *
850          * @param[in]  aInstance            A reference to the OpenThread instance.
851          * @param[in]  aLayerTwoSecurity    Specifies whether to use layer two security or not.
852          */
Transport(Instance & aInstance,LinkSecurityMode aLayerTwoSecurity)853         Transport(Instance &aInstance, LinkSecurityMode aLayerTwoSecurity)
854             : SecureTransport(aInstance, aLayerTwoSecurity, /* aDatagramTransport */ true)
855         {
856         }
857     };
858 
859     /**
860      * Represents a DTLS session.
861      */
862     class Session : public SecureSession
863     {
864     public:
865         /**
866          * Initializes the `Dtls::Session` object.
867          *
868          * @param[in] aTransport  The DTLS transport to use for this session.
869          */
Session(Transport & aTransport)870         Session(Transport &aTransport)
871             : SecureSession(aTransport)
872         {
873         }
874 
875         /**
876          * Returns the DTLS transport used by this session.
877          *
878          * @returns The DTLS transport associated with this session.
879          */
GetTransport(void)880         Transport &GetTransport(void) { return static_cast<Transport &>(SecureSession::GetTransport()); }
881     };
882 };
883 
884 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
885 
886 /**
887  * Represents a TLS instance.
888  */
889 class Tls : public SecureTransport, public SecureSession
890 {
891 public:
892     /**
893      * Initializes the `Tls` object.
894      *
895      * @param[in]  aInstance            A reference to the OpenThread instance.
896      * @param[in]  aLayerTwoSecurity    Specifies whether to use layer two security or not.
897      * @param[in]  aExtension           An extension providing additional configuration methods.
898      */
Tls(Instance & aInstance,LinkSecurityMode aLayerTwoSecurity,Extension & aExtension)899     Tls(Instance &aInstance, LinkSecurityMode aLayerTwoSecurity, Extension &aExtension)
900         : SecureTransport(aInstance, aLayerTwoSecurity, /* aDatagramTransport */ false)
901         , SecureSession(*static_cast<SecureTransport *>(this))
902     {
903         SetExtension(aExtension);
904         SetAcceptCallback(&HandleAccept, this);
905     }
906 
907 private:
908     static SecureSession *HandleAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo);
909     SecureSession        *HandleAccept(void);
910 };
911 
912 #endif
913 
914 } // namespace MeshCoP
915 } // namespace ot
916 
917 #endif // SECURE_TRANSPORT_HPP_
918