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 #include "coap_secure.hpp"
30
31 #if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
32
33 #include "instance/instance.hpp"
34
35 /**
36 * @file
37 * This file implements the secure CoAP session.
38 */
39
40 namespace ot {
41 namespace Coap {
42
43 RegisterLogModule("CoapSecure");
44
SecureSession(Instance & aInstance,Dtls::Transport & aDtlsTransport)45 SecureSession::SecureSession(Instance &aInstance, Dtls::Transport &aDtlsTransport)
46 : CoapBase(aInstance, Transmit)
47 , Dtls::Session(aDtlsTransport)
48 , mTransmitTask(aInstance, HandleTransmitTask, this)
49 {
50 Dtls::Session::SetConnectCallback(HandleDtlsConnectEvent, this);
51 Dtls::Session::SetReceiveCallback(HandleDtlsReceive, this);
52 }
53
Cleanup(void)54 void SecureSession::Cleanup(void)
55 {
56 ClearAllRequestsAndResponses();
57 mTransmitQueue.DequeueAndFreeAll();
58 mTransmitTask.Unpost();
59 }
60
61 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
62
SendMessage(Message & aMessage,ResponseHandler aHandler,void * aContext,otCoapBlockwiseTransmitHook aTransmitHook,otCoapBlockwiseReceiveHook aReceiveHook)63 Error SecureSession::SendMessage(Message &aMessage,
64 ResponseHandler aHandler,
65 void *aContext,
66 otCoapBlockwiseTransmitHook aTransmitHook,
67 otCoapBlockwiseReceiveHook aReceiveHook)
68 {
69 return IsConnected() ? CoapBase::SendMessage(aMessage, GetMessageInfo(), TxParameters::GetDefault(), aHandler,
70 aContext, aTransmitHook, aReceiveHook)
71 : kErrorInvalidState;
72 }
73
74 #else
75
SendMessage(Message & aMessage,ResponseHandler aHandler,void * aContext)76 Error SecureSession::SendMessage(Message &aMessage, ResponseHandler aHandler, void *aContext)
77 {
78 return IsConnected() ? CoapBase::SendMessage(aMessage, GetMessageInfo(), aHandler, aContext) : kErrorInvalidState;
79 }
80
81 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
82
Transmit(CoapBase & aCoapBase,ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)83 Error SecureSession::Transmit(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
84 {
85 return static_cast<SecureSession &>(aCoapBase).Transmit(aMessage, aMessageInfo);
86 }
87
Transmit(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)88 Error SecureSession::Transmit(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
89 {
90 OT_UNUSED_VARIABLE(aMessageInfo);
91
92 Error error = kErrorNone;
93
94 VerifyOrExit(!GetTransport().IsClosed(), error = kErrorInvalidState);
95
96 mTransmitQueue.Enqueue(aMessage);
97 mTransmitTask.Post();
98
99 exit:
100 return error;
101 }
102
HandleDtlsConnectEvent(ConnectEvent aEvent,void * aContext)103 void SecureSession::HandleDtlsConnectEvent(ConnectEvent aEvent, void *aContext)
104 {
105 static_cast<SecureSession *>(aContext)->HandleDtlsConnectEvent(aEvent);
106 }
107
HandleDtlsConnectEvent(ConnectEvent aEvent)108 void SecureSession::HandleDtlsConnectEvent(ConnectEvent aEvent)
109 {
110 if (aEvent != kConnected)
111 {
112 mTransmitQueue.DequeueAndFreeAll();
113 ClearAllRequestsAndResponses();
114 }
115
116 mConnectCallback.InvokeIfSet(aEvent);
117 }
118
HandleDtlsReceive(void * aContext,uint8_t * aBuf,uint16_t aLength)119 void SecureSession::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
120 {
121 static_cast<SecureSession *>(aContext)->HandleDtlsReceive(aBuf, aLength);
122 }
123
HandleDtlsReceive(uint8_t * aBuf,uint16_t aLength)124 void SecureSession::HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength)
125 {
126 ot::Message *message = nullptr;
127
128 VerifyOrExit((message = Get<MessagePool>().Allocate(Message::kTypeIp6, Message::GetHelpDataReserved())) != nullptr);
129 SuccessOrExit(message->AppendBytes(aBuf, aLength));
130
131 CoapBase::Receive(*message, GetMessageInfo());
132
133 exit:
134 FreeMessage(message);
135 }
136
HandleTransmitTask(Tasklet & aTasklet)137 void SecureSession::HandleTransmitTask(Tasklet &aTasklet)
138 {
139 static_cast<SecureSession *>(static_cast<TaskletContext &>(aTasklet).GetContext())->HandleTransmitTask();
140 }
141
HandleTransmitTask(void)142 void SecureSession::HandleTransmitTask(void)
143 {
144 Error error = kErrorNone;
145 ot::Message *message = mTransmitQueue.GetHead();
146
147 VerifyOrExit(message != nullptr);
148 mTransmitQueue.Dequeue(*message);
149
150 if (mTransmitQueue.GetHead() != nullptr)
151 {
152 mTransmitTask.Post();
153 }
154
155 error = Dtls::Session::Send(*message);
156
157 exit:
158 FreeMessageOnError(message, error);
159 }
160
161 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
162
HandleDtlsAccept(void * aContext,const Ip6::MessageInfo & aMessageInfo)163 MeshCoP::SecureSession *ApplicationCoapSecure::HandleDtlsAccept(void *aContext, const Ip6::MessageInfo &aMessageInfo)
164 {
165 OT_UNUSED_VARIABLE(aMessageInfo);
166
167 return static_cast<ApplicationCoapSecure *>(aContext)->HandleDtlsAccept();
168 }
169
HandleDtlsAccept(void)170 SecureSession *ApplicationCoapSecure::HandleDtlsAccept(void)
171 {
172 return IsSessionInUse() ? nullptr : static_cast<SecureSession *>(this);
173 }
174
175 #endif
176
177 } // namespace Coap
178 } // namespace ot
179
180 #endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
181