• 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 #include "coap_secure.hpp"
30 
31 #if OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
32 
33 #include "common/locator_getters.hpp"
34 #include "common/log.hpp"
35 #include "common/new.hpp"
36 #include "instance/instance.hpp"
37 #include "meshcop/secure_transport.hpp"
38 
39 #include "thread/thread_netif.hpp"
40 
41 /**
42  * @file
43  *   This file implements the secure CoAP agent.
44  */
45 
46 namespace ot {
47 namespace Coap {
48 
49 RegisterLogModule("CoapSecure");
50 
CoapSecure(Instance & aInstance,bool aLayerTwoSecurity)51 CoapSecure::CoapSecure(Instance &aInstance, bool aLayerTwoSecurity)
52     : CoapBase(aInstance, &CoapSecure::Send)
53     , mDtls(aInstance, aLayerTwoSecurity)
54     , mTransmitTask(aInstance, CoapSecure::HandleTransmit, this)
55 {
56 }
57 
Start(uint16_t aPort)58 Error CoapSecure::Start(uint16_t aPort) { return Start(aPort, /* aMaxAttempts */ 0, nullptr, nullptr); }
59 
Start(uint16_t aPort,uint16_t aMaxAttempts,AutoStopCallback aCallback,void * aContext)60 Error CoapSecure::Start(uint16_t aPort, uint16_t aMaxAttempts, AutoStopCallback aCallback, void *aContext)
61 {
62     Error error;
63 
64     SuccessOrExit(error = Open(aMaxAttempts, aCallback, aContext));
65     error = mDtls.Bind(aPort);
66 
67 exit:
68     return error;
69 }
70 
Start(MeshCoP::SecureTransport::TransportCallback aCallback,void * aContext)71 Error CoapSecure::Start(MeshCoP::SecureTransport::TransportCallback aCallback, void *aContext)
72 {
73     Error error;
74 
75     SuccessOrExit(error = Open(/* aMaxAttemps */ 0, nullptr, nullptr));
76     error = mDtls.Bind(aCallback, aContext);
77 
78 exit:
79     return error;
80 }
81 
Open(uint16_t aMaxAttempts,AutoStopCallback aCallback,void * aContext)82 Error CoapSecure::Open(uint16_t aMaxAttempts, AutoStopCallback aCallback, void *aContext)
83 {
84     Error error = kErrorAlready;
85 
86     SuccessOrExit(mDtls.SetMaxConnectionAttempts(aMaxAttempts, HandleDtlsAutoClose, this));
87     mAutoStopCallback.Set(aCallback, aContext);
88     mConnectedCallback.Clear();
89     SuccessOrExit(mDtls.Open(HandleDtlsReceive, HandleDtlsConnected, this));
90 
91     error = kErrorNone;
92 
93 exit:
94     return error;
95 }
96 
Stop(void)97 void CoapSecure::Stop(void)
98 {
99     mDtls.Close();
100 
101     mTransmitQueue.DequeueAndFreeAll();
102     ClearRequestsAndResponses();
103 }
104 
Connect(const Ip6::SockAddr & aSockAddr,ConnectedCallback aCallback,void * aContext)105 Error CoapSecure::Connect(const Ip6::SockAddr &aSockAddr, ConnectedCallback aCallback, void *aContext)
106 {
107     mConnectedCallback.Set(aCallback, aContext);
108 
109     return mDtls.Connect(aSockAddr);
110 }
111 
SetPsk(const MeshCoP::JoinerPskd & aPskd)112 void CoapSecure::SetPsk(const MeshCoP::JoinerPskd &aPskd)
113 {
114     static_assert(static_cast<uint16_t>(MeshCoP::JoinerPskd::kMaxLength) <=
115                       static_cast<uint16_t>(MeshCoP::SecureTransport::kPskMaxLength),
116                   "The maximum length of DTLS PSK is smaller than joiner PSKd");
117 
118     SuccessOrAssert(mDtls.SetPsk(reinterpret_cast<const uint8_t *>(aPskd.GetAsCString()), aPskd.GetLength()));
119 }
120 
121 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
SendMessage(Message & aMessage,ResponseHandler aHandler,void * aContext,otCoapBlockwiseTransmitHook aTransmitHook,otCoapBlockwiseReceiveHook aReceiveHook)122 Error CoapSecure::SendMessage(Message                    &aMessage,
123                               ResponseHandler             aHandler,
124                               void                       *aContext,
125                               otCoapBlockwiseTransmitHook aTransmitHook,
126                               otCoapBlockwiseReceiveHook  aReceiveHook)
127 {
128     Error error = kErrorNone;
129 
130     VerifyOrExit(IsConnected(), error = kErrorInvalidState);
131 
132     error = CoapBase::SendMessage(aMessage, mDtls.GetMessageInfo(), TxParameters::GetDefault(), aHandler, aContext,
133                                   aTransmitHook, aReceiveHook);
134 
135 exit:
136     return error;
137 }
138 
SendMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,ResponseHandler aHandler,void * aContext,otCoapBlockwiseTransmitHook aTransmitHook,otCoapBlockwiseReceiveHook aReceiveHook)139 Error CoapSecure::SendMessage(Message                    &aMessage,
140                               const Ip6::MessageInfo     &aMessageInfo,
141                               ResponseHandler             aHandler,
142                               void                       *aContext,
143                               otCoapBlockwiseTransmitHook aTransmitHook,
144                               otCoapBlockwiseReceiveHook  aReceiveHook)
145 {
146     return CoapBase::SendMessage(aMessage, aMessageInfo, TxParameters::GetDefault(), aHandler, aContext, aTransmitHook,
147                                  aReceiveHook);
148 }
149 #else  // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
SendMessage(Message & aMessage,ResponseHandler aHandler,void * aContext)150 Error CoapSecure::SendMessage(Message &aMessage, ResponseHandler aHandler, void *aContext)
151 {
152     Error error = kErrorNone;
153 
154     VerifyOrExit(IsConnected(), error = kErrorInvalidState);
155 
156     error = CoapBase::SendMessage(aMessage, mDtls.GetMessageInfo(), aHandler, aContext);
157 
158 exit:
159     return error;
160 }
161 
SendMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,ResponseHandler aHandler,void * aContext)162 Error CoapSecure::SendMessage(Message                &aMessage,
163                               const Ip6::MessageInfo &aMessageInfo,
164                               ResponseHandler         aHandler,
165                               void                   *aContext)
166 {
167     return CoapBase::SendMessage(aMessage, aMessageInfo, aHandler, aContext);
168 }
169 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
170 
Send(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)171 Error CoapSecure::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
172 {
173     OT_UNUSED_VARIABLE(aMessageInfo);
174 
175     mTransmitQueue.Enqueue(aMessage);
176     mTransmitTask.Post();
177 
178     return kErrorNone;
179 }
180 
HandleDtlsConnected(void * aContext,bool aConnected)181 void CoapSecure::HandleDtlsConnected(void *aContext, bool aConnected)
182 {
183     return static_cast<CoapSecure *>(aContext)->HandleDtlsConnected(aConnected);
184 }
185 
HandleDtlsConnected(bool aConnected)186 void CoapSecure::HandleDtlsConnected(bool aConnected) { mConnectedCallback.InvokeIfSet(aConnected); }
187 
HandleDtlsAutoClose(void * aContext)188 void CoapSecure::HandleDtlsAutoClose(void *aContext)
189 {
190     return static_cast<CoapSecure *>(aContext)->HandleDtlsAutoClose();
191 }
192 
HandleDtlsAutoClose(void)193 void CoapSecure::HandleDtlsAutoClose(void)
194 {
195     Stop();
196     mAutoStopCallback.InvokeIfSet();
197 }
198 
HandleDtlsReceive(void * aContext,uint8_t * aBuf,uint16_t aLength)199 void CoapSecure::HandleDtlsReceive(void *aContext, uint8_t *aBuf, uint16_t aLength)
200 {
201     return static_cast<CoapSecure *>(aContext)->HandleDtlsReceive(aBuf, aLength);
202 }
203 
HandleDtlsReceive(uint8_t * aBuf,uint16_t aLength)204 void CoapSecure::HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength)
205 {
206     ot::Message *message = nullptr;
207 
208     VerifyOrExit((message = Get<MessagePool>().Allocate(Message::kTypeIp6, Message::GetHelpDataReserved())) != nullptr);
209     SuccessOrExit(message->AppendBytes(aBuf, aLength));
210 
211     CoapBase::Receive(*message, mDtls.GetMessageInfo());
212 
213 exit:
214     FreeMessage(message);
215 }
216 
HandleTransmit(Tasklet & aTasklet)217 void CoapSecure::HandleTransmit(Tasklet &aTasklet)
218 {
219     static_cast<CoapSecure *>(static_cast<TaskletContext &>(aTasklet).GetContext())->HandleTransmit();
220 }
221 
HandleTransmit(void)222 void CoapSecure::HandleTransmit(void)
223 {
224     Error        error   = kErrorNone;
225     ot::Message *message = mTransmitQueue.GetHead();
226 
227     VerifyOrExit(message != nullptr);
228     mTransmitQueue.Dequeue(*message);
229 
230     if (mTransmitQueue.GetHead() != nullptr)
231     {
232         mTransmitTask.Post();
233     }
234 
235     SuccessOrExit(error = mDtls.Send(*message, message->GetLength()));
236 
237 exit:
238     if (error != kErrorNone)
239     {
240         LogNote("Transmit: %s", ErrorToString(error));
241         message->Free();
242     }
243     else
244     {
245         LogDebg("Transmit: %s", ErrorToString(error));
246     }
247 }
248 
249 } // namespace Coap
250 } // namespace ot
251 
252 #endif // OPENTHREAD_CONFIG_SECURE_TRANSPORT_ENABLE
253