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