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