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