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