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