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