xref: /aosp_15_r20/external/openthread/src/core/coap/coap_secure.hpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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 #ifndef COAP_SECURE_HPP_
30 #define COAP_SECURE_HPP_
31 
32 #include "openthread-core-config.h"
33 
34 #if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
35 
36 #include "coap/coap.hpp"
37 #include "common/callback.hpp"
38 #include "meshcop/meshcop.hpp"
39 #include "meshcop/secure_transport.hpp"
40 
41 #include <openthread/coap_secure.h>
42 
43 /**
44  * @file
45  *   This file includes definitions for the secure CoAP agent.
46  */
47 
48 namespace ot {
49 
50 namespace Coap {
51 
52 class CoapSecure : public CoapBase
53 {
54 public:
55     /**
56      * Function pointer which is called reporting a connection event (when connection established or disconnected)
57      *
58      */
59     typedef otHandleCoapSecureClientConnect ConnectEventCallback;
60 
61     /**
62      * Callback to notify when the agent is automatically stopped due to reaching the maximum number of connection
63      * attempts.
64      *
65      */
66     typedef otCoapSecureAutoStopCallback AutoStopCallback;
67 
68     /**
69      * Initializes the object.
70      *
71      * @param[in]  aInstance           A reference to the OpenThread instance.
72      * @param[in]  aLayerTwoSecurity   Specifies whether to use layer two security or not.
73      *
74      */
75     explicit CoapSecure(Instance &aInstance, bool aLayerTwoSecurity = false);
76 
77     /**
78      * Starts the secure CoAP agent.
79      *
80      * @param[in]  aPort      The local UDP port to bind to.
81      *
82      * @retval kErrorNone        Successfully started the CoAP agent.
83      * @retval kErrorAlready     Already started.
84      *
85      */
86     Error Start(uint16_t aPort);
87 
88     /**
89      * Starts the secure CoAP agent and sets the maximum number of allowed connection attempts before stopping the
90      * agent automatically.
91      *
92      * @param[in] aPort           The local UDP port to bind to.
93      * @param[in] aMaxAttempts    Maximum number of allowed connection request attempts. Zero indicates no limit.
94      * @param[in] aCallback       Callback to notify if max number of attempts has reached and agent is stopped.
95      * @param[in] aContext        A pointer to arbitrary context to use with `AutoStopCallback`.
96      *
97      * @retval kErrorNone        Successfully started the CoAP agent.
98      * @retval kErrorAlready     Already started.
99      *
100      */
101     Error Start(uint16_t aPort, uint16_t aMaxAttempts, AutoStopCallback aCallback, void *aContext);
102 
103     /**
104      * Starts the secure CoAP agent, but do not use socket to transmit/receive messages.
105      *
106      * @param[in]  aCallback  A pointer to a function for sending messages.
107      * @param[in]  aContext   A pointer to arbitrary context information.
108      *
109      * @retval kErrorNone        Successfully started the CoAP agent.
110      * @retval kErrorAlready     Already started.
111      *
112      */
113     Error Start(MeshCoP::SecureTransport::TransportCallback aCallback, void *aContext);
114 
115     /**
116      * Sets connected callback of this secure CoAP agent.
117      *
118      * @param[in]  aCallback  A pointer to a function to get called when connection state changes.
119      * @param[in]  aContext   A pointer to arbitrary context information.
120      *
121      */
SetConnectEventCallback(ConnectEventCallback aCallback,void * aContext)122     void SetConnectEventCallback(ConnectEventCallback aCallback, void *aContext)
123     {
124         mConnectEventCallback.Set(aCallback, aContext);
125     }
126 
127     /**
128      * Stops the secure CoAP agent.
129      *
130      */
131     void Stop(void);
132 
133     /**
134      * Initializes DTLS session with a peer.
135      *
136      * @param[in]  aSockAddr               A reference to the remote socket address,
137      * @param[in]  aCallback               A pointer to a function that will be called once DTLS connection is
138      * established.
139      *
140      * @retval kErrorNone  Successfully started DTLS connection.
141      *
142      */
143     Error Connect(const Ip6::SockAddr &aSockAddr, ConnectEventCallback aCallback, void *aContext);
144 
145     /**
146      * Indicates whether or not the DTLS session is active.
147      *
148      * @retval TRUE  If DTLS session is active.
149      * @retval FALSE If DTLS session is not active.
150      *
151      */
IsConnectionActive(void) const152     bool IsConnectionActive(void) const { return mDtls.IsConnectionActive(); }
153 
154     /**
155      * Indicates whether or not the DTLS session is connected.
156      *
157      * @retval TRUE   The DTLS session is connected.
158      * @retval FALSE  The DTLS session is not connected.
159      *
160      */
IsConnected(void) const161     bool IsConnected(void) const { return mDtls.IsConnected(); }
162 
163     /**
164      * Indicates whether or not the DTLS session is closed.
165      *
166      * @retval TRUE   The DTLS session is closed
167      * @retval FALSE  The DTLS session is not closed.
168      *
169      */
IsClosed(void) const170     bool IsClosed(void) const { return mDtls.IsClosed(); }
171 
172     /**
173      * Stops the DTLS connection.
174      *
175      */
Disconnect(void)176     void Disconnect(void) { mDtls.Disconnect(); }
177 
178     /**
179      * Returns a reference to the DTLS object.
180      *
181      * @returns  A reference to the DTLS object.
182      *
183      */
GetDtls(void)184     MeshCoP::SecureTransport &GetDtls(void) { return mDtls; }
185 
186     /**
187      * Gets the UDP port of this agent.
188      *
189      * @returns  UDP port number.
190      *
191      */
GetUdpPort(void) const192     uint16_t GetUdpPort(void) const { return mDtls.GetUdpPort(); }
193 
194     /**
195      * Sets the PSK.
196      *
197      * @param[in]  aPsk        A pointer to the PSK.
198      * @param[in]  aPskLength  The PSK length.
199      *
200      * @retval kErrorNone         Successfully set the PSK.
201      * @retval kErrorInvalidArgs  The PSK is invalid.
202      *
203      */
SetPsk(const uint8_t * aPsk,uint8_t aPskLength)204     Error SetPsk(const uint8_t *aPsk, uint8_t aPskLength) { return mDtls.SetPsk(aPsk, aPskLength); }
205 
206     /**
207      * Sets the PSK.
208      *
209      * @param[in]  aPskd  A Joiner PSKd.
210      *
211      */
212     void SetPsk(const MeshCoP::JoinerPskd &aPskd);
213 
214 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
215 
216 #ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
217     /**
218      * Sets the Pre-Shared Key (PSK) for DTLS sessions identified by a PSK.
219      *
220      * DTLS mode "TLS with AES 128 CCM 8" for Application CoAPS.
221      *
222      * @param[in]  aPsk          A pointer to the PSK.
223      * @param[in]  aPskLength    The PSK char length.
224      * @param[in]  aPskIdentity  The Identity Name for the PSK.
225      * @param[in]  aPskIdLength  The PSK Identity Length.
226      *
227      */
SetPreSharedKey(const uint8_t * aPsk,uint16_t aPskLength,const uint8_t * aPskIdentity,uint16_t aPskIdLength)228     void SetPreSharedKey(const uint8_t *aPsk, uint16_t aPskLength, const uint8_t *aPskIdentity, uint16_t aPskIdLength)
229     {
230         mDtls.SetPreSharedKey(aPsk, aPskLength, aPskIdentity, aPskIdLength);
231     }
232 #endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
233 
234 #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
235     /**
236      * Sets a X509 certificate with corresponding private key for DTLS session.
237      *
238      * DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
239      *
240      * @param[in]  aX509Cert          A pointer to the PEM formatted X509 PEM certificate.
241      * @param[in]  aX509Length        The length of certificate.
242      * @param[in]  aPrivateKey        A pointer to the PEM formatted private key.
243      * @param[in]  aPrivateKeyLength  The length of the private key.
244      *
245      */
SetCertificate(const uint8_t * aX509Cert,uint32_t aX509Length,const uint8_t * aPrivateKey,uint32_t aPrivateKeyLength)246     void SetCertificate(const uint8_t *aX509Cert,
247                         uint32_t       aX509Length,
248                         const uint8_t *aPrivateKey,
249                         uint32_t       aPrivateKeyLength)
250     {
251         mDtls.SetCertificate(aX509Cert, aX509Length, aPrivateKey, aPrivateKeyLength);
252     }
253 
254     /**
255      * Sets the trusted top level CAs. It is needed for validate the certificate of the peer.
256      *
257      * DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
258      *
259      * @param[in]  aX509CaCertificateChain  A pointer to the PEM formatted X509 CA chain.
260      * @param[in]  aX509CaCertChainLength   The length of chain.
261      *
262      */
SetCaCertificateChain(const uint8_t * aX509CaCertificateChain,uint32_t aX509CaCertChainLength)263     void SetCaCertificateChain(const uint8_t *aX509CaCertificateChain, uint32_t aX509CaCertChainLength)
264     {
265         mDtls.SetCaCertificateChain(aX509CaCertificateChain, aX509CaCertChainLength);
266     }
267 #endif // MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
268 
269 #if defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
270     /**
271      * Returns the peer x509 certificate base64 encoded.
272      *
273      * DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
274      *
275      * @param[out]  aPeerCert        A pointer to the base64 encoded certificate buffer.
276      * @param[out]  aCertLength      The length of the base64 encoded peer certificate.
277      * @param[in]   aCertBufferSize  The buffer size of aPeerCert.
278      *
279      * @retval kErrorNone    Successfully get the peer certificate.
280      * @retval kErrorNoBufs  Can't allocate memory for certificate.
281      *
282      */
GetPeerCertificateBase64(unsigned char * aPeerCert,size_t * aCertLength,size_t aCertBufferSize)283     Error GetPeerCertificateBase64(unsigned char *aPeerCert, size_t *aCertLength, size_t aCertBufferSize)
284     {
285         return mDtls.GetPeerCertificateBase64(aPeerCert, aCertLength, aCertBufferSize);
286     }
287 #endif // defined(MBEDTLS_BASE64_C) && defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
288 
289     /**
290      * Sets the authentication mode for the CoAP secure connection. It disables or enables the verification
291      * of peer certificate.
292      *
293      * @param[in]  aVerifyPeerCertificate  true, if the peer certificate should be verified
294      *
295      */
SetSslAuthMode(bool aVerifyPeerCertificate)296     void SetSslAuthMode(bool aVerifyPeerCertificate) { mDtls.SetSslAuthMode(aVerifyPeerCertificate); }
297 
298 #endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
299 
300 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
301     /**
302      * Sends a CoAP message over secure DTLS connection.
303      *
304      * If a response for a request is expected, respective function and context information should be provided.
305      * If no response is expected, these arguments should be NULL pointers.
306      * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
307      *
308      * @param[in]  aMessage      A reference to the message to send.
309      * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
310      * @param[in]  aContext      A pointer to arbitrary context information.
311      * @param[in]  aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
312      * @param[in]  aReceiveHook  A pointer to a hook function for incoming block-wise transfer.
313      *
314      * @retval kErrorNone          Successfully sent CoAP message.
315      * @retval kErrorNoBufs        Failed to allocate retransmission data.
316      * @retval kErrorInvalidState  DTLS connection was not initialized.
317      *
318      */
319     Error SendMessage(Message                    &aMessage,
320                       ResponseHandler             aHandler      = nullptr,
321                       void                       *aContext      = nullptr,
322                       otCoapBlockwiseTransmitHook aTransmitHook = nullptr,
323                       otCoapBlockwiseReceiveHook  aReceiveHook  = nullptr);
324 
325     /**
326      * Sends a CoAP message over secure DTLS connection.
327      *
328      * If a response for a request is expected, respective function and context information should be provided.
329      * If no response is expected, these arguments should be NULL pointers.
330      * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
331      *
332      * @param[in]  aMessage      A reference to the message to send.
333      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
334      * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
335      * @param[in]  aContext      A pointer to arbitrary context information.
336      * @param[in]  aTransmitHook A pointer to a hook function for outgoing block-wise transfer.
337      * @param[in]  aReceiveHook  A pointer to a hook function for incoming block-wise transfer.
338      *
339      * @retval kErrorNone          Successfully sent CoAP message.
340      * @retval kErrorNoBufs        Failed to allocate retransmission data.
341      * @retval kErrorInvalidState  DTLS connection was not initialized.
342      *
343      */
344     Error SendMessage(Message                    &aMessage,
345                       const Ip6::MessageInfo     &aMessageInfo,
346                       ResponseHandler             aHandler      = nullptr,
347                       void                       *aContext      = nullptr,
348                       otCoapBlockwiseTransmitHook aTransmitHook = nullptr,
349                       otCoapBlockwiseReceiveHook  aReceiveHook  = nullptr);
350 #else  // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
351     /**
352      * Sends a CoAP message over secure DTLS connection.
353      *
354      * If a response for a request is expected, respective function and context information should be provided.
355      * If no response is expected, these arguments should be nullptr pointers.
356      * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
357      *
358      * @param[in]  aMessage      A reference to the message to send.
359      * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
360      * @param[in]  aContext      A pointer to arbitrary context information.
361      *
362      * @retval kErrorNone          Successfully sent CoAP message.
363      * @retval kErrorNoBufs        Failed to allocate retransmission data.
364      * @retval kErrorInvalidState  DTLS connection was not initialized.
365      *
366      */
367     Error SendMessage(Message &aMessage, ResponseHandler aHandler = nullptr, void *aContext = nullptr);
368 
369     /**
370      * Sends a CoAP message over secure DTLS connection.
371      *
372      * If a response for a request is expected, respective function and context information should be provided.
373      * If no response is expected, these arguments should be nullptr pointers.
374      * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
375      *
376      * @param[in]  aMessage      A reference to the message to send.
377      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
378      * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
379      * @param[in]  aContext      A pointer to arbitrary context information.
380      *
381      * @retval kErrorNone          Successfully sent CoAP message.
382      * @retval kErrorNoBufs        Failed to allocate retransmission data.
383      * @retval kErrorInvalidState  DTLS connection was not initialized.
384      *
385      */
386     Error SendMessage(Message                &aMessage,
387                       const Ip6::MessageInfo &aMessageInfo,
388                       ResponseHandler         aHandler = nullptr,
389                       void                   *aContext = nullptr);
390 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
391 
392     /**
393      * Is used to pass UDP messages to the secure CoAP server.
394      *
395      * @param[in]  aMessage      A reference to the received message.
396      * @param[in]  aMessageInfo  A reference to the message info associated with @p aMessage.
397      *
398      */
HandleUdpReceive(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)399     void HandleUdpReceive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
400     {
401         return mDtls.HandleReceive(aMessage, aMessageInfo);
402     }
403 
404     /**
405      * Returns the DTLS session's peer address.
406      *
407      * @return DTLS session's message info.
408      *
409      */
GetMessageInfo(void) const410     const Ip6::MessageInfo &GetMessageInfo(void) const { return mDtls.GetMessageInfo(); }
411 
412 private:
413     Error Open(uint16_t aMaxAttempts, AutoStopCallback aCallback, void *aContext);
414 
Send(CoapBase & aCoapBase,ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)415     static Error Send(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
416     {
417         return static_cast<CoapSecure &>(aCoapBase).Send(aMessage, aMessageInfo);
418     }
419     Error Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
420 
421     static void HandleDtlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent, void *aContext);
422     void        HandleDtlsConnectEvent(MeshCoP::SecureTransport::ConnectEvent aEvent);
423 
424     static void HandleDtlsAutoClose(void *aContext);
425     void        HandleDtlsAutoClose(void);
426 
427     static void HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength);
428     void        HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength);
429 
430     static void HandleTransmit(Tasklet &aTasklet);
431     void        HandleTransmit(void);
432 
433     MeshCoP::SecureTransport       mDtls;
434     Callback<ConnectEventCallback> mConnectEventCallback;
435     Callback<AutoStopCallback>     mAutoStopCallback;
436     ot::MessageQueue               mTransmitQueue;
437     TaskletContext                 mTransmitTask;
438 };
439 
440 } // namespace Coap
441 } // namespace ot
442 
443 #endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
444 
445 #endif // COAP_SECURE_HPP_
446