1 /*
2  *  Copyright (c) 2018, 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  * @brief
32  *  This file defines the top-level functions for the OpenThread CoAP Secure implementation.
33  *
34  *  @note
35  *   The functions in this module require the build-time feature `OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE=1`.
36  *
37  *  @note
38  *   To enable cipher suite DTLS_PSK_WITH_AES_128_CCM_8, MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
39  *    must be enabled in mbedtls-config.h
40  *   To enable cipher suite DTLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
41  *    MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED must be enabled in mbedtls-config.h.
42  */
43 
44 #ifndef OPENTHREAD_COAP_SECURE_H_
45 #define OPENTHREAD_COAP_SECURE_H_
46 
47 #include <stdint.h>
48 
49 #include <openthread/coap.h>
50 
51 #ifdef __cplusplus
52 extern "C" {
53 #endif
54 
55 /**
56  * @addtogroup api-coap-secure
57  *
58  * @brief
59  *   This module includes functions that control CoAP Secure (CoAP over DTLS) communication.
60  *
61  *   The functions in this module are available when CoAP Secure API feature
62  *   (`OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE`) is enabled.
63  *
64  * @{
65  */
66 
67 #define OT_DEFAULT_COAP_SECURE_PORT 5684 ///< Default CoAP Secure port, as specified in RFC 7252
68 
69 /**
70  * CoAP secure connection event types.
71  */
72 typedef enum otCoapSecureConnectEvent
73 {
74     OT_COAP_SECURE_CONNECTED = 0,             ///< Connection established
75     OT_COAP_SECURE_DISCONNECTED_PEER_CLOSED,  ///< Disconnected by peer
76     OT_COAP_SECURE_DISCONNECTED_LOCAL_CLOSED, ///< Disconnected locally
77     OT_COAP_SECURE_DISCONNECTED_MAX_ATTEMPTS, ///< Disconnected due to reaching the max connection attempts
78     OT_COAP_SECURE_DISCONNECTED_ERROR,        ///< Disconnected due to an error
79 } otCoapSecureConnectEvent;
80 
81 /**
82  * Pointer is called when the DTLS connection state changes.
83  *
84  * @param[in]  aEvent      The connection event.
85  * @param[in]  aContext    A pointer to arbitrary context information.
86  */
87 typedef void (*otHandleCoapSecureClientConnect)(otCoapSecureConnectEvent aEvent, void *aContext);
88 
89 /**
90  * Callback function pointer to notify when the CoAP secure agent is automatically stopped due to reaching the maximum
91  * number of connection attempts.
92  *
93  * @param[in] aContext    A pointer to arbitrary context information.
94  */
95 typedef void (*otCoapSecureAutoStopCallback)(void *aContext);
96 
97 /**
98  * Starts the CoAP Secure service.
99  *
100  * @param[in]  aInstance  A pointer to an OpenThread instance.
101  * @param[in]  aPort      The local UDP port to bind to.
102  *
103  * @retval OT_ERROR_NONE  Successfully started the CoAP Secure server.
104  */
105 otError otCoapSecureStart(otInstance *aInstance, uint16_t aPort);
106 
107 /**
108  * Starts the CoAP secure service and sets the maximum number of allowed connection attempts before stopping the
109  * agent automatically.
110  *
111  * @param[in] aInstance       A pointer to an OpenThread instance.
112  * @param[in] aPort           The local UDP port to bind to.
113  * @param[in] aMaxAttempts    Maximum number of allowed connection request attempts. Zero indicates no limit.
114  * @param[in] aCallback       Callback to notify if max number of attempts has reached and agent is stopped.
115  * @param[in] aContext        A pointer to arbitrary context to use with @p aCallback.
116  *
117  * @retval OT_ERROR_NONE        Successfully started the CoAP agent.
118  * @retval OT_ERROR_ALREADY     Already started.
119  */
120 otError otCoapSecureStartWithMaxConnAttempts(otInstance                  *aInstance,
121                                              uint16_t                     aPort,
122                                              uint16_t                     aMaxAttempts,
123                                              otCoapSecureAutoStopCallback aCallback,
124                                              void                        *aContext);
125 
126 /**
127  * Stops the CoAP Secure server.
128  *
129  * @param[in]  aInstance  A pointer to an OpenThread instance.
130  */
131 void otCoapSecureStop(otInstance *aInstance);
132 
133 /**
134  * Sets the Pre-Shared Key (PSK) and cipher suite
135  * DTLS_PSK_WITH_AES_128_CCM_8.
136  *
137  * @note This function requires the build-time feature `MBEDTLS_KEY_EXCHANGE_PSK_ENABLED` to be enabled.
138  *
139  * @param[in]  aInstance     A pointer to an OpenThread instance.
140  * @param[in]  aPsk          A pointer to the PSK.
141  * @param[in]  aPskLength    The PSK length.
142  * @param[in]  aPskIdentity  The Identity Name for the PSK.
143  * @param[in]  aPskIdLength  The PSK Identity Length.
144  */
145 void otCoapSecureSetPsk(otInstance    *aInstance,
146                         const uint8_t *aPsk,
147                         uint16_t       aPskLength,
148                         const uint8_t *aPskIdentity,
149                         uint16_t       aPskIdLength);
150 
151 /**
152  * Returns the peer x509 certificate base64 encoded.
153  *
154  * @note This function requires the build-time features `MBEDTLS_BASE64_C` and
155  *       `MBEDTLS_SSL_KEEP_PEER_CERTIFICATE` to be enabled.
156  *
157  * @param[in]   aInstance        A pointer to an OpenThread instance.
158  * @param[out]  aPeerCert        A pointer to the base64 encoded certificate buffer.
159  * @param[out]  aCertLength      The length of the base64 encoded peer certificate.
160  * @param[in]   aCertBufferSize  The buffer size of aPeerCert.
161  *
162  * @retval OT_ERROR_INVALID_STATE   Not connected yet.
163  * @retval OT_ERROR_NONE            Successfully get the peer certificate.
164  * @retval OT_ERROR_NO_BUFS         Can't allocate memory for certificate.
165  */
166 otError otCoapSecureGetPeerCertificateBase64(otInstance    *aInstance,
167                                              unsigned char *aPeerCert,
168                                              size_t        *aCertLength,
169                                              size_t         aCertBufferSize);
170 
171 /**
172  * Sets the authentication mode for the coap secure connection.
173  *
174  * Disable or enable the verification of peer certificate.
175  * Must be called before start.
176  *
177  * @param[in]   aInstance               A pointer to an OpenThread instance.
178  * @param[in]   aVerifyPeerCertificate  true, to verify the peer certificate.
179  */
180 void otCoapSecureSetSslAuthMode(otInstance *aInstance, bool aVerifyPeerCertificate);
181 
182 /**
183  * Sets the local device's X509 certificate with corresponding private key for
184  * DTLS session with DTLS_ECDHE_ECDSA_WITH_AES_128_CCM_8.
185  *
186  * @note This function requires `MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=1`.
187  *
188  * @param[in]  aInstance          A pointer to an OpenThread instance.
189  * @param[in]  aX509Cert          A pointer to the PEM formatted X509 certificate.
190  * @param[in]  aX509Length        The length of certificate.
191  * @param[in]  aPrivateKey        A pointer to the PEM formatted private key.
192  * @param[in]  aPrivateKeyLength  The length of the private key.
193  */
194 void otCoapSecureSetCertificate(otInstance    *aInstance,
195                                 const uint8_t *aX509Cert,
196                                 uint32_t       aX509Length,
197                                 const uint8_t *aPrivateKey,
198                                 uint32_t       aPrivateKeyLength);
199 
200 /**
201  * Sets the trusted top level CAs. It is needed for validating the
202  * certificate of the peer.
203  *
204  * DTLS mode "ECDHE ECDSA with AES 128 CCM 8" for Application CoAPS.
205  *
206  * @note This function requires `MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED=1`.
207  *
208  * @param[in]  aInstance                A pointer to an OpenThread instance.
209  * @param[in]  aX509CaCertificateChain  A pointer to the PEM formatted X509 CA chain.
210  * @param[in]  aX509CaCertChainLength   The length of chain.
211  */
212 void otCoapSecureSetCaCertificateChain(otInstance    *aInstance,
213                                        const uint8_t *aX509CaCertificateChain,
214                                        uint32_t       aX509CaCertChainLength);
215 
216 /**
217  * Initializes DTLS session with a peer.
218  *
219  * @param[in]  aInstance               A pointer to an OpenThread instance.
220  * @param[in]  aSockAddr               A pointer to the remote socket address.
221  * @param[in]  aHandler                A pointer to a function that will be called when the DTLS connection
222  *                                     state changes.
223  * @param[in]  aContext                A pointer to arbitrary context information.
224  *
225  * @retval OT_ERROR_NONE  Successfully started DTLS connection.
226  */
227 otError otCoapSecureConnect(otInstance                     *aInstance,
228                             const otSockAddr               *aSockAddr,
229                             otHandleCoapSecureClientConnect aHandler,
230                             void                           *aContext);
231 
232 /**
233  * Stops the DTLS connection.
234  *
235  * @param[in]  aInstance  A pointer to an OpenThread instance.
236  */
237 void otCoapSecureDisconnect(otInstance *aInstance);
238 
239 /**
240  * Indicates whether or not the DTLS session is connected.
241  *
242  * @param[in]  aInstance  A pointer to an OpenThread instance.
243  *
244  * @retval TRUE   The DTLS session is connected.
245  * @retval FALSE  The DTLS session is not connected.
246  */
247 bool otCoapSecureIsConnected(otInstance *aInstance);
248 
249 /**
250  * Indicates whether or not the DTLS session is active.
251  *
252  * @param[in]  aInstance  A pointer to an OpenThread instance.
253  *
254  * @retval TRUE  If DTLS session is active.
255  * @retval FALSE If DTLS session is not active.
256  */
257 bool otCoapSecureIsConnectionActive(otInstance *aInstance);
258 
259 /**
260  * Indicates whether or not the DTLS session is closed.
261  *
262  * @param[in]  aInstance  A pointer to an OpenThread instance.
263  *
264  * @retval TRUE   The DTLS session is closed.
265  * @retval FALSE  The DTLS session is not closed.
266  */
267 bool otCoapSecureIsClosed(otInstance *aInstance);
268 
269 /**
270  * Sends a CoAP request block-wise over secure DTLS connection.
271  *
272  * Is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
273  * is enabled.
274  *
275  * If a response for a request is expected, respective function and context information should be provided.
276  * If no response is expected, these arguments should be NULL pointers.
277  * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
278  *
279  * @param[in]  aInstance     A pointer to an OpenThread instance.
280  * @param[in]  aMessage      A reference to the message to send.
281  * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
282  * @param[in]  aContext      A pointer to arbitrary context information.
283  * @param[in]  aTransmitHook A function pointer that is called on Block1 response reception.
284  * @param[in]  aReceiveHook  A function pointer that is called on Block2 response reception.
285  *
286  * @retval OT_ERROR_NONE           Successfully sent CoAP message.
287  * @retval OT_ERROR_NO_BUFS        Failed to allocate retransmission data.
288  * @retval OT_ERROR_INVALID_STATE  DTLS connection was not initialized.
289  */
290 otError otCoapSecureSendRequestBlockWise(otInstance                 *aInstance,
291                                          otMessage                  *aMessage,
292                                          otCoapResponseHandler       aHandler,
293                                          void                       *aContext,
294                                          otCoapBlockwiseTransmitHook aTransmitHook,
295                                          otCoapBlockwiseReceiveHook  aReceiveHook);
296 
297 /**
298  * Sends a CoAP request over secure DTLS connection.
299  *
300  * If a response for a request is expected, respective function and context information should be provided.
301  * If no response is expected, these arguments should be NULL pointers.
302  * If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
303  *
304  * @param[in]  aInstance     A pointer to an OpenThread instance.
305  * @param[in]  aMessage      A reference to the message to send.
306  * @param[in]  aHandler      A function pointer that shall be called on response reception or time-out.
307  * @param[in]  aContext      A pointer to arbitrary context information.
308  *
309  * @retval OT_ERROR_NONE           Successfully sent CoAP message.
310  * @retval OT_ERROR_NO_BUFS        Failed to allocate retransmission data.
311  * @retval OT_ERROR_INVALID_STATE  DTLS connection was not initialized.
312  */
313 otError otCoapSecureSendRequest(otInstance           *aInstance,
314                                 otMessage            *aMessage,
315                                 otCoapResponseHandler aHandler,
316                                 void                 *aContext);
317 
318 /**
319  * Adds a resource to the CoAP Secure server.
320  *
321  * @param[in]  aInstance  A pointer to an OpenThread instance.
322  * @param[in]  aResource  A pointer to the resource.
323  */
324 void otCoapSecureAddResource(otInstance *aInstance, otCoapResource *aResource);
325 
326 /**
327  * Removes a resource from the CoAP Secure server.
328  *
329  * @param[in]  aInstance  A pointer to an OpenThread instance.
330  * @param[in]  aResource  A pointer to the resource.
331  */
332 void otCoapSecureRemoveResource(otInstance *aInstance, otCoapResource *aResource);
333 
334 /**
335  * Adds a block-wise resource to the CoAP Secure server.
336  *
337  * @param[in]  aInstance  A pointer to an OpenThread instance.
338  * @param[in]  aResource  A pointer to the resource.
339  */
340 void otCoapSecureAddBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource);
341 
342 /**
343  * Removes a block-wise resource from the CoAP Secure server.
344  *
345  * @param[in]  aInstance  A pointer to an OpenThread instance.
346  * @param[in]  aResource  A pointer to the resource.
347  */
348 void otCoapSecureRemoveBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResource *aResource);
349 
350 /**
351  * Sets the default handler for unhandled CoAP Secure requests.
352  *
353  * @param[in]  aInstance  A pointer to an OpenThread instance.
354  * @param[in]  aHandler   A function pointer that shall be called when an unhandled request arrives.
355  * @param[in]  aContext   A pointer to arbitrary context information. May be NULL if not used.
356  */
357 void otCoapSecureSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext);
358 
359 /**
360  * Sets the connect event callback to indicate when
361  * a Client connection to the CoAP Secure server has changed.
362  *
363  * @param[in]  aInstance     A pointer to an OpenThread instance.
364  * @param[in]  aHandler      A pointer to a function that will be called once DTLS connection has changed.
365  * @param[in]  aContext      A pointer to arbitrary context information. May be NULL if not used.
366  */
367 void otCoapSecureSetClientConnectEventCallback(otInstance                     *aInstance,
368                                                otHandleCoapSecureClientConnect aHandler,
369                                                void                           *aContext);
370 
371 /**
372  * Sends a CoAP response block-wise from the CoAP Secure server.
373  *
374  * Is available when OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE configuration
375  * is enabled.
376  *
377  * @param[in]  aInstance     A pointer to an OpenThread instance.
378  * @param[in]  aMessage      A pointer to the CoAP response to send.
379  * @param[in]  aMessageInfo  A pointer to the message info associated with @p aMessage.
380  * @param[in]  aContext      A pointer to arbitrary context information. May be NULL if not used.
381  * @param[in]  aTransmitHook A function pointer that is called on Block1 request reception.
382  *
383  * @retval OT_ERROR_NONE     Successfully enqueued the CoAP response message.
384  * @retval OT_ERROR_NO_BUFS  Insufficient buffers available to send the CoAP response.
385  */
386 otError otCoapSecureSendResponseBlockWise(otInstance                 *aInstance,
387                                           otMessage                  *aMessage,
388                                           const otMessageInfo        *aMessageInfo,
389                                           void                       *aContext,
390                                           otCoapBlockwiseTransmitHook aTransmitHook);
391 
392 /**
393  * Sends a CoAP response from the CoAP Secure server.
394  *
395  * @param[in]  aInstance     A pointer to an OpenThread instance.
396  * @param[in]  aMessage      A pointer to the CoAP response to send.
397  * @param[in]  aMessageInfo  A pointer to the message info associated with @p aMessage.
398  *
399  * @retval OT_ERROR_NONE     Successfully enqueued the CoAP response message.
400  * @retval OT_ERROR_NO_BUFS  Insufficient buffers available to send the CoAP response.
401  */
402 otError otCoapSecureSendResponse(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo);
403 
404 /**
405  * @}
406  */
407 
408 #ifdef __cplusplus
409 } // extern "C"
410 #endif
411 
412 #endif /* OPENTHREAD_COAP_SECURE_H_ */
413