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 * This file implements a simple CLI for the CoAP Secure service.
32 */
33
34 #include "cli_coap_secure.hpp"
35
36 #if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
37
38 #include <mbedtls/debug.h>
39 #include <openthread/random_noncrypto.h>
40
41 #include "cli/cli.hpp"
42
43 // header for place your x509 certificate and private key
44 #include "x509_cert_key.hpp"
45
46 namespace ot {
47 namespace Cli {
48
CoapSecure(otInstance * aInstance,OutputImplementer & aOutputImplementer)49 CoapSecure::CoapSecure(otInstance *aInstance, OutputImplementer &aOutputImplementer)
50 : Output(aInstance, aOutputImplementer)
51 , mShutdownFlag(false)
52 , mUseCertificate(false)
53 , mPskLength(0)
54 , mPskIdLength(0)
55 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
56 , mBlockCount(1)
57 #endif
58 {
59 memset(&mResource, 0, sizeof(mResource));
60 memset(&mPsk, 0, sizeof(mPsk));
61 memset(&mPskId, 0, sizeof(mPskId));
62 memset(&mUriPath, 0, sizeof(mUriPath));
63 strncpy(mResourceContent, "0", sizeof(mResourceContent));
64 mResourceContent[sizeof(mResourceContent) - 1] = '\0';
65 }
66
PrintPayload(otMessage * aMessage)67 void CoapSecure::PrintPayload(otMessage *aMessage)
68 {
69 uint8_t buf[kMaxBufferSize];
70 uint16_t bytesToPrint;
71 uint16_t bytesPrinted = 0;
72 uint16_t length = otMessageGetLength(aMessage) - otMessageGetOffset(aMessage);
73
74 if (length > 0)
75 {
76 OutputFormat(" with payload: ");
77
78 while (length > 0)
79 {
80 bytesToPrint = Min(length, static_cast<uint16_t>(sizeof(buf)));
81 otMessageRead(aMessage, otMessageGetOffset(aMessage) + bytesPrinted, buf, bytesToPrint);
82
83 OutputBytes(buf, static_cast<uint8_t>(bytesToPrint));
84
85 length -= bytesToPrint;
86 bytesPrinted += bytesToPrint;
87 }
88 }
89
90 OutputNewLine();
91 }
92
Process(Arg aArgs[])93 template <> otError CoapSecure::Process<Cmd("resource")>(Arg aArgs[])
94 {
95 otError error = OT_ERROR_NONE;
96
97 if (!aArgs[0].IsEmpty())
98 {
99 VerifyOrExit(aArgs[0].GetLength() < kMaxUriLength, error = OT_ERROR_INVALID_ARGS);
100
101 mResource.mUriPath = mUriPath;
102 mResource.mContext = this;
103 mResource.mHandler = &CoapSecure::HandleRequest;
104
105 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
106 mResource.mReceiveHook = &CoapSecure::BlockwiseReceiveHook;
107 mResource.mTransmitHook = &CoapSecure::BlockwiseTransmitHook;
108
109 if (!aArgs[1].IsEmpty())
110 {
111 SuccessOrExit(error = aArgs[1].ParseAsUint32(mBlockCount));
112 }
113 #endif
114
115 strncpy(mUriPath, aArgs[0].GetCString(), sizeof(mUriPath) - 1);
116 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
117 otCoapSecureAddBlockWiseResource(GetInstancePtr(), &mResource);
118 #else
119 otCoapSecureAddResource(GetInstancePtr(), &mResource);
120 #endif
121 }
122 else
123 {
124 OutputLine("%s", mResource.mUriPath != nullptr ? mResource.mUriPath : "");
125 }
126
127 exit:
128 return error;
129 }
130
Process(Arg aArgs[])131 template <> otError CoapSecure::Process<Cmd("set")>(Arg aArgs[])
132 {
133 otError error = OT_ERROR_NONE;
134
135 if (!aArgs[0].IsEmpty())
136 {
137 VerifyOrExit(aArgs[0].GetLength() < sizeof(mResourceContent), error = OT_ERROR_INVALID_ARGS);
138 strncpy(mResourceContent, aArgs[0].GetCString(), sizeof(mResourceContent));
139 mResourceContent[sizeof(mResourceContent) - 1] = '\0';
140 }
141 else
142 {
143 OutputLine("%s", mResourceContent);
144 }
145
146 exit:
147 return error;
148 }
149
Process(Arg aArgs[])150 template <> otError CoapSecure::Process<Cmd("start")>(Arg aArgs[])
151 {
152 otError error = OT_ERROR_NONE;
153 bool verifyPeerCert = true;
154
155 if (!aArgs[0].IsEmpty())
156 {
157 if (aArgs[0] == "false")
158 {
159 verifyPeerCert = false;
160 }
161 else
162 {
163 VerifyOrExit(aArgs[0] == "true", error = OT_ERROR_INVALID_ARGS);
164 }
165 }
166
167 otCoapSecureSetSslAuthMode(GetInstancePtr(), verifyPeerCert);
168 otCoapSecureSetClientConnectedCallback(GetInstancePtr(), &CoapSecure::HandleConnected, this);
169
170 #if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
171 otCoapSecureSetDefaultHandler(GetInstancePtr(), &CoapSecure::DefaultHandler, this);
172 #endif
173
174 error = otCoapSecureStart(GetInstancePtr(), OT_DEFAULT_COAP_SECURE_PORT);
175
176 exit:
177 return error;
178 }
179
Process(Arg aArgs[])180 template <> otError CoapSecure::Process<Cmd("stop")>(Arg aArgs[])
181 {
182 OT_UNUSED_VARIABLE(aArgs);
183
184 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
185 otCoapRemoveBlockWiseResource(GetInstancePtr(), &mResource);
186 #else
187 otCoapRemoveResource(GetInstancePtr(), &mResource);
188 #endif
189
190 if (otCoapSecureIsConnectionActive(GetInstancePtr()))
191 {
192 otCoapSecureDisconnect(GetInstancePtr());
193 mShutdownFlag = true;
194 }
195 else
196 {
197 Stop();
198 }
199
200 return OT_ERROR_NONE;
201 }
202
Process(Arg aArgs[])203 template <> otError CoapSecure::Process<Cmd("get")>(Arg aArgs[]) { return ProcessRequest(aArgs, OT_COAP_CODE_GET); }
204
Process(Arg aArgs[])205 template <> otError CoapSecure::Process<Cmd("post")>(Arg aArgs[]) { return ProcessRequest(aArgs, OT_COAP_CODE_POST); }
206
Process(Arg aArgs[])207 template <> otError CoapSecure::Process<Cmd("put")>(Arg aArgs[]) { return ProcessRequest(aArgs, OT_COAP_CODE_PUT); }
208
Process(Arg aArgs[])209 template <> otError CoapSecure::Process<Cmd("delete")>(Arg aArgs[])
210 {
211 return ProcessRequest(aArgs, OT_COAP_CODE_DELETE);
212 }
213
ProcessRequest(Arg aArgs[],otCoapCode aCoapCode)214 otError CoapSecure::ProcessRequest(Arg aArgs[], otCoapCode aCoapCode)
215 {
216 otError error = OT_ERROR_NONE;
217 otMessage *message = nullptr;
218 uint16_t payloadLength = 0;
219
220 // Default parameters
221 char coapUri[kMaxUriLength];
222 otCoapType coapType = OT_COAP_TYPE_NON_CONFIRMABLE;
223 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
224 bool coapBlock = false;
225 otCoapBlockSzx coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_16;
226 BlockType coapBlockType = (aCoapCode == OT_COAP_CODE_GET) ? kBlockType2 : kBlockType1;
227 #endif
228
229 VerifyOrExit(!aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
230 VerifyOrExit(aArgs[0].GetLength() < sizeof(coapUri), error = OT_ERROR_INVALID_ARGS);
231 strcpy(coapUri, aArgs[0].GetCString());
232
233 if (!aArgs[1].IsEmpty())
234 {
235 if (aArgs[1] == "con")
236 {
237 coapType = OT_COAP_TYPE_CONFIRMABLE;
238 }
239 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
240 else if (aArgs[1] == "block-16")
241 {
242 coapType = OT_COAP_TYPE_CONFIRMABLE;
243 coapBlock = true;
244 coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_16;
245 }
246 else if (aArgs[1] == "block-32")
247 {
248 coapType = OT_COAP_TYPE_CONFIRMABLE;
249 coapBlock = true;
250 coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_32;
251 }
252 else if (aArgs[1] == "block-64")
253 {
254 coapType = OT_COAP_TYPE_CONFIRMABLE;
255 coapBlock = true;
256 coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_64;
257 }
258 else if (aArgs[1] == "block-128")
259 {
260 coapType = OT_COAP_TYPE_CONFIRMABLE;
261 coapBlock = true;
262 coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_128;
263 }
264 else if (aArgs[1] == "block-256")
265 {
266 coapType = OT_COAP_TYPE_CONFIRMABLE;
267 coapBlock = true;
268 coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_256;
269 }
270 else if (aArgs[1] == "block-512")
271 {
272 coapType = OT_COAP_TYPE_CONFIRMABLE;
273 coapBlock = true;
274 coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_512;
275 }
276 else if (aArgs[1] == "block-1024")
277 {
278 coapType = OT_COAP_TYPE_CONFIRMABLE;
279 coapBlock = true;
280 coapBlockSize = OT_COAP_OPTION_BLOCK_SZX_1024;
281 }
282 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
283 }
284
285 message = otCoapNewMessage(GetInstancePtr(), nullptr);
286 VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
287
288 otCoapMessageInit(message, coapType, aCoapCode);
289 otCoapMessageGenerateToken(message, OT_COAP_DEFAULT_TOKEN_LENGTH);
290 SuccessOrExit(error = otCoapMessageAppendUriPathOptions(message, coapUri));
291
292 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
293 if (coapBlock)
294 {
295 if (coapBlockType == kBlockType1)
296 {
297 SuccessOrExit(error = otCoapMessageAppendBlock1Option(message, 0, true, coapBlockSize));
298 }
299 else
300 {
301 SuccessOrExit(error = otCoapMessageAppendBlock2Option(message, 0, false, coapBlockSize));
302 }
303 }
304 #endif
305
306 if (!aArgs[2].IsEmpty())
307 {
308 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
309 if (coapBlock)
310 {
311 SuccessOrExit(error = aArgs[2].ParseAsUint32(mBlockCount));
312 }
313 else
314 {
315 #endif
316 payloadLength = aArgs[2].GetLength();
317
318 if (payloadLength > 0)
319 {
320 SuccessOrExit(error = otCoapMessageSetPayloadMarker(message));
321 }
322 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
323 }
324 #endif
325 }
326
327 if (payloadLength > 0)
328 {
329 SuccessOrExit(error = otMessageAppend(message, aArgs[2].GetCString(), payloadLength));
330 }
331
332 if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (aCoapCode == OT_COAP_CODE_GET))
333 {
334 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
335 if (coapBlock)
336 {
337 error =
338 otCoapSecureSendRequestBlockWise(GetInstancePtr(), message, &CoapSecure::HandleResponse, this,
339 &CoapSecure::BlockwiseTransmitHook, &CoapSecure::BlockwiseReceiveHook);
340 }
341 else
342 {
343 #endif
344 error = otCoapSecureSendRequest(GetInstancePtr(), message, &CoapSecure::HandleResponse, this);
345 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
346 }
347 #endif
348 }
349 else
350 {
351 error = otCoapSecureSendRequest(GetInstancePtr(), message, nullptr, nullptr);
352 }
353
354 exit:
355
356 if ((error != OT_ERROR_NONE) && (message != nullptr))
357 {
358 otMessageFree(message);
359 }
360
361 return error;
362 }
363
Process(Arg aArgs[])364 template <> otError CoapSecure::Process<Cmd("connect")>(Arg aArgs[])
365 {
366 otError error;
367 otSockAddr sockaddr;
368
369 memset(&sockaddr, 0, sizeof(sockaddr));
370 SuccessOrExit(error = aArgs[0].ParseAsIp6Address(sockaddr.mAddress));
371 sockaddr.mPort = OT_DEFAULT_COAP_SECURE_PORT;
372
373 if (!aArgs[1].IsEmpty())
374 {
375 SuccessOrExit(error = aArgs[1].ParseAsUint16(sockaddr.mPort));
376 }
377
378 SuccessOrExit(error = otCoapSecureConnect(GetInstancePtr(), &sockaddr, &CoapSecure::HandleConnected, this));
379
380 exit:
381 return error;
382 }
383
Process(Arg aArgs[])384 template <> otError CoapSecure::Process<Cmd("disconnect")>(Arg aArgs[])
385 {
386 OT_UNUSED_VARIABLE(aArgs);
387
388 otCoapSecureDisconnect(GetInstancePtr());
389
390 return OT_ERROR_NONE;
391 }
392
393 #ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
Process(Arg aArgs[])394 template <> otError CoapSecure::Process<Cmd("psk")>(Arg aArgs[])
395 {
396 otError error = OT_ERROR_NONE;
397 uint16_t length;
398
399 VerifyOrExit(!aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
400
401 length = aArgs[0].GetLength();
402 VerifyOrExit(length <= sizeof(mPsk), error = OT_ERROR_INVALID_ARGS);
403 mPskLength = static_cast<uint8_t>(length);
404 memcpy(mPsk, aArgs[0].GetCString(), mPskLength);
405
406 length = aArgs[1].GetLength();
407 VerifyOrExit(length <= sizeof(mPskId), error = OT_ERROR_INVALID_ARGS);
408 mPskIdLength = static_cast<uint8_t>(length);
409 memcpy(mPskId, aArgs[1].GetCString(), mPskIdLength);
410
411 otCoapSecureSetPsk(GetInstancePtr(), mPsk, mPskLength, mPskId, mPskIdLength);
412 mUseCertificate = false;
413
414 exit:
415 return error;
416 }
417 #endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
418
419 #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
Process(Arg aArgs[])420 template <> otError CoapSecure::Process<Cmd("x509")>(Arg aArgs[])
421 {
422 OT_UNUSED_VARIABLE(aArgs);
423
424 otCoapSecureSetCertificate(GetInstancePtr(), reinterpret_cast<const uint8_t *>(OT_CLI_COAPS_X509_CERT),
425 sizeof(OT_CLI_COAPS_X509_CERT), reinterpret_cast<const uint8_t *>(OT_CLI_COAPS_PRIV_KEY),
426 sizeof(OT_CLI_COAPS_PRIV_KEY));
427
428 otCoapSecureSetCaCertificateChain(GetInstancePtr(),
429 reinterpret_cast<const uint8_t *>(OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE),
430 sizeof(OT_CLI_COAPS_TRUSTED_ROOT_CERTIFICATE));
431 mUseCertificate = true;
432
433 return OT_ERROR_NONE;
434 }
435 #endif
436
Process(Arg aArgs[])437 otError CoapSecure::Process(Arg aArgs[])
438 {
439 #define CmdEntry(aCommandString) \
440 { \
441 aCommandString, &CoapSecure::Process<Cmd(aCommandString)> \
442 }
443
444 static constexpr Command kCommands[] = {
445 CmdEntry("connect"), CmdEntry("delete"), CmdEntry("disconnect"), CmdEntry("get"), CmdEntry("post"),
446 #ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
447 CmdEntry("psk"),
448 #endif
449 CmdEntry("put"), CmdEntry("resource"), CmdEntry("set"), CmdEntry("start"), CmdEntry("stop"),
450 #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
451 CmdEntry("x509"),
452 #endif
453 };
454
455 #undef CmdEntry
456
457 static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
458
459 otError error = OT_ERROR_INVALID_COMMAND;
460 const Command *command;
461
462 if (aArgs[0].IsEmpty() || (aArgs[0] == "help"))
463 {
464 OutputCommandTable(kCommands);
465 ExitNow(error = aArgs[0].IsEmpty() ? OT_ERROR_INVALID_ARGS : OT_ERROR_NONE);
466 }
467
468 command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
469 VerifyOrExit(command != nullptr);
470
471 error = (this->*command->mHandler)(aArgs + 1);
472
473 exit:
474 return error;
475 }
476
Stop(void)477 void CoapSecure::Stop(void)
478 {
479 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
480 otCoapRemoveBlockWiseResource(GetInstancePtr(), &mResource);
481 #else
482 otCoapRemoveResource(GetInstancePtr(), &mResource);
483 #endif
484 otCoapSecureStop(GetInstancePtr());
485 }
486
HandleConnected(bool aConnected,void * aContext)487 void CoapSecure::HandleConnected(bool aConnected, void *aContext)
488 {
489 static_cast<CoapSecure *>(aContext)->HandleConnected(aConnected);
490 }
491
HandleConnected(bool aConnected)492 void CoapSecure::HandleConnected(bool aConnected)
493 {
494 if (aConnected)
495 {
496 OutputLine("coaps connected");
497 }
498 else
499 {
500 OutputLine("coaps disconnected");
501
502 if (mShutdownFlag)
503 {
504 Stop();
505 mShutdownFlag = false;
506 }
507 }
508 }
509
HandleRequest(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)510 void CoapSecure::HandleRequest(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
511 {
512 static_cast<CoapSecure *>(aContext)->HandleRequest(aMessage, aMessageInfo);
513 }
514
HandleRequest(otMessage * aMessage,const otMessageInfo * aMessageInfo)515 void CoapSecure::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
516 {
517 otError error = OT_ERROR_NONE;
518 otMessage *responseMessage = nullptr;
519 otCoapCode responseCode = OT_COAP_CODE_EMPTY;
520 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
521 uint64_t blockValue = 0;
522 bool blockPresent = false;
523 otCoapOptionIterator iterator;
524 #endif
525
526 OutputFormat("coaps request from ");
527 OutputIp6Address(aMessageInfo->mPeerAddr);
528 OutputFormat(" ");
529
530 switch (otCoapMessageGetCode(aMessage))
531 {
532 case OT_COAP_CODE_GET:
533 OutputFormat("GET");
534 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
535 SuccessOrExit(error = otCoapOptionIteratorInit(&iterator, aMessage));
536 if (otCoapOptionIteratorGetFirstOptionMatching(&iterator, OT_COAP_OPTION_BLOCK2) != nullptr)
537 {
538 SuccessOrExit(error = otCoapOptionIteratorGetOptionUintValue(&iterator, &blockValue));
539 blockPresent = true;
540 }
541 #endif
542 break;
543
544 case OT_COAP_CODE_DELETE:
545 OutputFormat("DELETE");
546 break;
547
548 case OT_COAP_CODE_PUT:
549 OutputFormat("PUT");
550 break;
551
552 case OT_COAP_CODE_POST:
553 OutputFormat("POST");
554 break;
555
556 default:
557 OutputLine("Undefined");
558 return;
559 }
560
561 PrintPayload(aMessage);
562
563 if ((otCoapMessageGetType(aMessage) == OT_COAP_TYPE_CONFIRMABLE) ||
564 (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET))
565 {
566 if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
567 {
568 responseCode = OT_COAP_CODE_CONTENT;
569 }
570 else
571 {
572 responseCode = OT_COAP_CODE_VALID;
573 }
574
575 responseMessage = otCoapNewMessage(GetInstancePtr(), nullptr);
576 VerifyOrExit(responseMessage != nullptr, error = OT_ERROR_NO_BUFS);
577
578 SuccessOrExit(
579 error = otCoapMessageInitResponse(responseMessage, aMessage, OT_COAP_TYPE_ACKNOWLEDGMENT, responseCode));
580
581 if (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET)
582 {
583 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
584 if (blockPresent)
585 {
586 SuccessOrExit(error = otCoapMessageAppendBlock2Option(responseMessage,
587 static_cast<uint32_t>(blockValue >> 4), true,
588 static_cast<otCoapBlockSzx>(blockValue & 0x7)));
589 }
590 #endif
591 SuccessOrExit(error = otCoapMessageSetPayloadMarker(responseMessage));
592 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
593 if (!blockPresent)
594 {
595 #endif
596 SuccessOrExit(error = otMessageAppend(responseMessage, &mResourceContent,
597 static_cast<uint16_t>(strlen(mResourceContent))));
598 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
599 }
600 #endif
601 }
602
603 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
604 if (blockPresent)
605 {
606 SuccessOrExit(error = otCoapSecureSendResponseBlockWise(GetInstancePtr(), responseMessage, aMessageInfo,
607 this, mResource.mTransmitHook));
608 }
609 else
610 {
611 #endif
612 SuccessOrExit(error = otCoapSecureSendResponse(GetInstancePtr(), responseMessage, aMessageInfo));
613 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
614 }
615 #endif
616 }
617
618 exit:
619
620 if (error != OT_ERROR_NONE)
621 {
622 if (responseMessage != nullptr)
623 {
624 OutputLine("coaps send response error %d: %s", error, otThreadErrorToString(error));
625 otMessageFree(responseMessage);
626 }
627 }
628 else if (responseCode >= OT_COAP_CODE_RESPONSE_MIN)
629 {
630 OutputLine("coaps response sent");
631 }
632 }
633
HandleResponse(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo,otError aError)634 void CoapSecure::HandleResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError)
635 {
636 static_cast<CoapSecure *>(aContext)->HandleResponse(aMessage, aMessageInfo, aError);
637 }
638
HandleResponse(otMessage * aMessage,const otMessageInfo * aMessageInfo,otError aError)639 void CoapSecure::HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError)
640 {
641 OT_UNUSED_VARIABLE(aMessageInfo);
642
643 if (aError != OT_ERROR_NONE)
644 {
645 OutputLine("coaps receive response error %d: %s", aError, otThreadErrorToString(aError));
646 }
647 else
648 {
649 OutputFormat("coaps response from ");
650 OutputIp6Address(aMessageInfo->mPeerAddr);
651
652 PrintPayload(aMessage);
653 }
654 }
655
656 #if CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
DefaultHandler(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)657 void CoapSecure::DefaultHandler(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
658 {
659 static_cast<CoapSecure *>(aContext)->DefaultHandler(aMessage, aMessageInfo);
660 }
661
DefaultHandler(otMessage * aMessage,const otMessageInfo * aMessageInfo)662 void CoapSecure::DefaultHandler(otMessage *aMessage, const otMessageInfo *aMessageInfo)
663 {
664 otError error = OT_ERROR_NONE;
665 otMessage *responseMessage = nullptr;
666
667 if ((otCoapMessageGetType(aMessage) == OT_COAP_TYPE_CONFIRMABLE) ||
668 (otCoapMessageGetCode(aMessage) == OT_COAP_CODE_GET))
669 {
670 responseMessage = otCoapNewMessage(GetInstancePtr(), nullptr);
671 VerifyOrExit(responseMessage != nullptr, error = OT_ERROR_NO_BUFS);
672
673 SuccessOrExit(error = otCoapMessageInitResponse(responseMessage, aMessage, OT_COAP_TYPE_NON_CONFIRMABLE,
674 OT_COAP_CODE_NOT_FOUND));
675
676 SuccessOrExit(error = otCoapSecureSendResponse(GetInstancePtr(), responseMessage, aMessageInfo));
677 }
678
679 exit:
680 if (error != OT_ERROR_NONE && responseMessage != nullptr)
681 {
682 otMessageFree(responseMessage);
683 }
684 }
685 #endif // CLI_COAP_SECURE_USE_COAP_DEFAULT_HANDLER
686
687 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
BlockwiseReceiveHook(void * aContext,const uint8_t * aBlock,uint32_t aPosition,uint16_t aBlockLength,bool aMore,uint32_t aTotalLength)688 otError CoapSecure::BlockwiseReceiveHook(void *aContext,
689 const uint8_t *aBlock,
690 uint32_t aPosition,
691 uint16_t aBlockLength,
692 bool aMore,
693 uint32_t aTotalLength)
694 {
695 return static_cast<CoapSecure *>(aContext)->BlockwiseReceiveHook(aBlock, aPosition, aBlockLength, aMore,
696 aTotalLength);
697 }
698
BlockwiseReceiveHook(const uint8_t * aBlock,uint32_t aPosition,uint16_t aBlockLength,bool aMore,uint32_t aTotalLength)699 otError CoapSecure::BlockwiseReceiveHook(const uint8_t *aBlock,
700 uint32_t aPosition,
701 uint16_t aBlockLength,
702 bool aMore,
703 uint32_t aTotalLength)
704 {
705 OT_UNUSED_VARIABLE(aMore);
706 OT_UNUSED_VARIABLE(aTotalLength);
707
708 OutputLine("received block: Num %i Len %i", aPosition / aBlockLength, aBlockLength);
709
710 for (uint16_t i = 0; i < aBlockLength / 16; i++)
711 {
712 OutputBytesLine(&aBlock[i * 16], 16);
713 }
714
715 return OT_ERROR_NONE;
716 }
717
BlockwiseTransmitHook(void * aContext,uint8_t * aBlock,uint32_t aPosition,uint16_t * aBlockLength,bool * aMore)718 otError CoapSecure::BlockwiseTransmitHook(void *aContext,
719 uint8_t *aBlock,
720 uint32_t aPosition,
721 uint16_t *aBlockLength,
722 bool *aMore)
723 {
724 return static_cast<CoapSecure *>(aContext)->BlockwiseTransmitHook(aBlock, aPosition, aBlockLength, aMore);
725 }
726
BlockwiseTransmitHook(uint8_t * aBlock,uint32_t aPosition,uint16_t * aBlockLength,bool * aMore)727 otError CoapSecure::BlockwiseTransmitHook(uint8_t *aBlock, uint32_t aPosition, uint16_t *aBlockLength, bool *aMore)
728 {
729 static uint32_t blockCount = 0;
730 OT_UNUSED_VARIABLE(aPosition);
731
732 // Send a random payload
733 otRandomNonCryptoFillBuffer(aBlock, *aBlockLength);
734
735 OutputLine("send block: Num %i Len %i", blockCount, *aBlockLength);
736
737 for (uint16_t i = 0; i < *aBlockLength / 16; i++)
738 {
739 OutputBytesLine(&aBlock[i * 16], 16);
740 }
741
742 if (blockCount == mBlockCount - 1)
743 {
744 blockCount = 0;
745 *aMore = false;
746 }
747 else
748 {
749 *aMore = true;
750 blockCount++;
751 }
752
753 return OT_ERROR_NONE;
754 }
755 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
756
757 } // namespace Cli
758 } // namespace ot
759
760 #endif // OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE
761