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