• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "stdlib.h"
17 #include "securec.h"
18 #include "attest_coap_def.h"
19 #include "attest_utils.h"
20 #include "attest_utils_log.h"
21 #include "attest_coap.h"
22 
23 #define USHORT_MAX 0xFFFF
24 
CoapCreateHead(CoapPacket * pkt,uint8_t code,uint32_t transType,CoapRWBuffer * buf)25 static int32_t CoapCreateHead(CoapPacket* pkt, uint8_t code, uint32_t transType, CoapRWBuffer* buf)
26 {
27     ATTEST_LOG_DEBUG("[CoapCreateHead] Start");
28     if (pkt == NULL || buf == NULL) {
29         ATTEST_LOG_ERROR("[CoapCreateHead] Invalid parameter");
30         return COAP_ERR_CODE_INVALID_ARGUMENT;
31     }
32 
33     /* set transType */
34     pkt->transType = transType;
35     if (buf->size < HEADER_LEN) {
36         ATTEST_LOG_ERROR("[CoapCreateHead] Header overruns the buffer");
37         return COAP_ERR_CODE_PACKET_EXCEED_MAX_PDU;
38     }
39     pkt->hdr.code = code;
40 
41     /* LEN + TKL + CODE is 2 bytes */
42     buf->len = HEADER_LEN;
43     pkt->len = HEADER_LEN;
44 
45     /* rwBuffer 1 is the 8 bit of the code */
46     buf->rwBuffer[1] = (char)pkt->hdr.code;
47     ATTEST_LOG_DEBUG("[CoapCreateHead] End");
48     return COAP_ERR_CODE_NONE;
49 }
50 
CoapCreateToken(uint8_t token[],uint8_t * tkl)51 static int32_t CoapCreateToken(uint8_t token[], uint8_t* tkl)
52 {
53     if (token == NULL || tkl == NULL || (*tkl > MAX_TOK_LEN)) {
54         ATTEST_LOG_ERROR("[CoapCreateToken] Invalid parameter");
55         return COAP_ERR_CODE_INVALID_ARGUMENT;
56     }
57     if (*tkl == 0) {
58         *tkl = (uint8_t)((GetRandomNum() % BITS_PER_BYTE) + 1); // create a random digit, range: 1~8
59     }
60     for (size_t i = 0; i < *tkl; i++) {
61         token[i] = (uint8_t)(GetRandomNum() % (MAX_VALUE_ONE_BYTE + 1)); // create a random value, range: 0~255
62     }
63     return 0;
64 }
65 
CoapAddToken(CoapPacket * pkt,const CoapBuffer * token,CoapRWBuffer * buf)66 static int32_t CoapAddToken(CoapPacket* pkt, const CoapBuffer* token, CoapRWBuffer* buf)
67 {
68     ATTEST_LOG_DEBUG("[CoapAddToken] Start");
69     if (pkt == NULL || token == NULL || ((token->len != 0) && token->buffer == NULL) ||
70         buf == NULL || buf->rwBuffer == NULL || (buf->len != HEADER_LEN)) {
71         ATTEST_LOG_ERROR("[CoapAddToken] Invalid parameter");
72         return COAP_ERR_CODE_INVALID_ARGUMENT;
73     }
74 
75     if (token->len > MAX_TOK_LEN) {
76         ATTEST_LOG_ERROR("[CoapAddToken] Length symbol exceed the limit");
77         return COAP_ERR_CODE_INVALID_TOKEN_LEN;
78     }
79 
80     if ((buf->len + token->len) > buf->size) {
81         ATTEST_LOG_ERROR("[CoapAddToken] Symbol overruns the buffer");
82         return COAP_ERR_CODE_PACKET_EXCEED_MAX_PDU;
83     }
84 
85     pkt->tok.len = token->len;
86     pkt->hdr.tkl = pkt->tok.len & 0x0F;
87     pkt->tok.buffer = (const uint8_t*)&buf->rwBuffer[buf->len];
88     if (token->len) {
89         /* update header with tokenLen
90         * Token length is the low 4 bit of the third Byte
91         */
92         buf->rwBuffer[0] = (char)((uint8_t)(buf->rwBuffer[0] & 0xF0) | pkt->hdr.tkl); /* rwBuffer 0 is the first Byte */
93         if (memcpy_s(&buf->rwBuffer[buf->len], pkt->hdr.tkl, token->buffer, token->len) != 0) {
94             return COAP_ERR_CODE_INVALID_ARGUMENT;
95         }
96     }
97     buf->len += token->len;
98     pkt->len = buf->len;
99     ATTEST_LOG_DEBUG("[CoapAddToken] End");
100     return COAP_ERR_CODE_NONE;
101 }
102 
CoapGetOptionParam(const uint16_t value,uint8_t * param)103 static void CoapGetOptionParam(const uint16_t value, uint8_t* param)
104 {
105     if (param == NULL) {
106         ATTEST_LOG_ERROR("[CoapGetOptionParam] Invalid parameter");
107         return;
108     }
109 
110     /* Option length
111      * 4-bit unsigned integer. A value between 0 and 12 inclusive indicates the length of the message in bytes
112      * starting with the first bit of the Options field. Three values are reserved for special constructs:
113      *     13: An 8-bit unsigned integer (Extended Length) follows the initial byte and indicates the length
114      *         of options/payload minus 13.
115      *     14: A 16-bit unsigned integer (Extended Length) in networks byte order follows the initial byte and
116      *         indicates the length of options/payload minus 269.
117      */
118     if (value < COAP_MESSAGE_OFFSET_ONE_BYTE) {
119         *param = (uint8_t)(0xFF & value);
120     } else {
121         *param = (value < COAP_MESSAGE_DIFF_VALUE_TWO_BYTES) ? COAP_MESSAGE_OFFSET_ONE_BYTE :
122                  COAP_MESSAGE_OFFSET_TWO_BYTES;
123     }
124 }
125 
CoapGetExtensionLen(uint8_t param,size_t * length)126 int32_t CoapGetExtensionLen(uint8_t param, size_t *length)
127 {
128     if (length == NULL) {
129         return COAP_ERR_CODE_INVALID_ARGUMENT;
130     }
131     if (param == COAP_MESSAGE_OFFSET_ONE_BYTE) {
132         *length = COAP_MESSAGE_LENGTH_ONE_BYTE;
133     } else if (param == COAP_MESSAGE_OFFSET_TWO_BYTES) {
134         *length = COAP_MESSAGE_LENGTH_TWO_BYTES;
135     } else if (param == COAP_MESSAGE_OFFSET_FOUR_BYTES) {
136         return COAP_ERR_CODE_EXTENDED_LENGTH_INVALID;
137     }
138     return COAP_ERR_CODE_NONE;
139 }
140 
CoapEncodeExtensionMsg(uint8_t param,size_t contentLen,uint32_t * index,CoapRWBuffer * buf)141 static int32_t CoapEncodeExtensionMsg(uint8_t param, size_t contentLen, uint32_t *index, CoapRWBuffer *buf)
142 {
143     if (buf->rwBuffer == NULL) {
144         ATTEST_LOG_ERROR("[CoapEncodeExtensionMsg] Invalid parameter");
145         return COAP_ERR_CODE_INVALID_ARGUMENT;
146     }
147     if (param == COAP_MESSAGE_OFFSET_ONE_BYTE && contentLen >= COAP_MESSAGE_DIFF_VALUE_BYTE) {
148         if ((buf->len + COAP_MESSAGE_LENGTH_ONE_BYTE) > buf->size) {
149             ATTEST_LOG_ERROR("[CoapEncodeExtensionMsg] Extension msg overruns the buffer size");
150             return COAP_ERR_CODE_PACKET_EXCEED_MAX_PDU;
151         }
152         buf->rwBuffer[(*index)++] = (char)(contentLen - COAP_MESSAGE_DIFF_VALUE_BYTE);
153     } else if (param == COAP_MESSAGE_OFFSET_TWO_BYTES && contentLen >= COAP_MESSAGE_DIFF_VALUE_TWO_BYTES) {
154         if ((buf->len + COAP_MESSAGE_LENGTH_TWO_BYTES) > buf->size) {
155             ATTEST_LOG_ERROR("[CoapEncodeExtensionMsg] Extension msg  overruns the buffer size");
156             return COAP_ERR_CODE_PACKET_EXCEED_MAX_PDU;
157         }
158         buf->rwBuffer[(*index)++] = (char)((contentLen - COAP_MESSAGE_DIFF_VALUE_TWO_BYTES) >> BITS_PER_BYTE);
159         buf->rwBuffer[(*index)++] = (char)(0xFF & (contentLen - COAP_MESSAGE_DIFF_VALUE_TWO_BYTES));
160     } else if (param == COAP_MESSAGE_OFFSET_FOUR_BYTES) {
161         return COAP_ERR_CODE_EXTENDED_LENGTH_INVALID;
162     }
163     return COAP_ERR_CODE_NONE;
164 }
165 
166 /* return total option length: (i.e., 1 + (extensions len) + (option value len)) */
CoapGetOptionLength(const CoapOption * opt,uint16_t runningDelta)167 static uint32_t CoapGetOptionLength(const CoapOption* opt, uint16_t runningDelta)
168 {
169     if (opt == NULL) {
170         ATTEST_LOG_ERROR("[CoapGetOptionLength] Invalid parameter");
171         return COAP_ERR_CODE_INVALID_ARGUMENT;
172     }
173     uint32_t optionLen = 1;
174     uint8_t delta = 0;
175     uint8_t len = 0;
176 
177     CoapGetOptionParam((uint16_t)(opt->num - runningDelta), &delta);
178     CoapGetOptionParam((uint16_t)opt->len, &len);
179 
180     if (delta == COAP_MESSAGE_OFFSET_ONE_BYTE) {
181         optionLen += 1;
182     } else if (delta == COAP_MESSAGE_OFFSET_TWO_BYTES) {
183         optionLen += COAP_MESSAGE_LENGTH_TWO_BYTES;
184     }
185     if (len == COAP_MESSAGE_OFFSET_ONE_BYTE) {
186         optionLen += 1;
187     } else if (len == COAP_MESSAGE_OFFSET_TWO_BYTES) {
188         optionLen += COAP_MESSAGE_LENGTH_TWO_BYTES;
189     }
190     return (uint32_t)(optionLen + opt->len);
191 }
192 
CheckOptionParameter(CoapPacket * pkt,const CoapOption * opt,CoapRWBuffer * buf)193 static int32_t CheckOptionParameter(CoapPacket* pkt, const CoapOption* opt, CoapRWBuffer* buf)
194 {
195     uint16_t runningDelta = 0;
196     if (pkt == NULL || buf == NULL || opt == NULL) {
197         ATTEST_LOG_ERROR("[CheckOptionParameter] Invalid parameter");
198         return COAP_ERR_CODE_INVALID_ARGUMENT;
199     }
200 
201     if (buf->rwBuffer == NULL || opt->optionBuffer == NULL) {
202         ATTEST_LOG_ERROR("[CheckOptionParameter] Invalid parameter");
203         return COAP_ERR_CODE_INVALID_ARGUMENT;
204     }
205     /* Coap header should have been created */
206     if (buf->len < HEADER_LEN) {
207         ATTEST_LOG_ERROR("[CheckOptionParameter] Invalid parameter");
208         return COAP_ERR_CODE_INVALID_ARGUMENT;
209     }
210     if ((opt->len > USHORT_MAX) || (pkt->optsCnt > COAP_MAX_OPTION)) {
211         ATTEST_LOG_ERROR("[CheckOptionParameter] Option length or number of options exceed the limit");
212         return COAP_ERR_CODE_BAD_REQUEST;
213     }
214     /* option received is out-of-order */
215     if (pkt->optsCnt) {
216         if (pkt->opts[pkt->optsCnt - 1].num > opt->num) {
217             ATTEST_LOG_ERROR("[CheckOptionParameter] Option out of order");
218             return COAP_ERR_CODE_BAD_REQUEST;
219         }
220         runningDelta = pkt->opts[pkt->optsCnt - 1].num;
221     }
222     uint16_t optionLen = (uint16_t)CoapGetOptionLength(opt, runningDelta);
223     if ((buf->len + optionLen) > buf->size) {
224         ATTEST_LOG_ERROR("[CheckOptionParameter] Option overruns the buffer size");
225         return COAP_ERR_CODE_PACKET_EXCEED_MAX_PDU;
226     }
227     return COAP_ERR_CODE_NONE;
228 }
229 
CoapAddOption(CoapPacket * pkt,const CoapOption * opt,CoapRWBuffer * buf)230 static int32_t CoapAddOption(CoapPacket* pkt, const CoapOption* opt, CoapRWBuffer* buf)
231 {
232     ATTEST_LOG_DEBUG("[CoapAddOption] Start");
233     uint8_t delta;
234     uint8_t len;
235     int32_t ret = CheckOptionParameter(pkt, opt, buf);
236     if (ret != 0) {
237         return ret;
238     }
239     /* Add Delta & extensions */
240     uint16_t prevOptType = (uint16_t)((pkt->optsCnt) ? pkt->opts[pkt->optsCnt - 1].num : 0);
241     if (opt->num < prevOptType) {
242         return COAP_ERR_CODE_INVALID_ARGUMENT;
243     }
244     uint16_t optdelta = (uint16_t)(opt->num - prevOptType);
245     CoapGetOptionParam(optdelta, &delta);
246     CoapGetOptionParam((uint16_t)opt->len, &len);
247 
248     if ((buf->len + 1) > buf->size) {
249         ATTEST_LOG_ERROR("[CoapAddOption] Option overruns the buffer size");
250         return COAP_ERR_CODE_PACKET_EXCEED_MAX_PDU;
251     }
252 
253     buf->rwBuffer[buf->len++] = (char)(0xFF & ((delta << COAP_BITS_OPTION_DELTA) | len));
254 
255     if ((ret = CoapEncodeExtensionMsg(delta, optdelta, &buf->len, buf)) != 0) {
256         return ret;
257     }
258     if ((ret = CoapEncodeExtensionMsg(len, opt->len, &buf->len, buf)) != 0) {
259         return ret;
260     }
261 
262     /* Add Option Value */
263     if ((opt->len > 0) && ((buf->len + opt->len) < buf->size)) {
264         if (memcpy_s(&buf->rwBuffer[buf->len], buf->size - buf->len, opt->optionBuffer, opt->len) != 0) {
265             return COAP_ERR_CODE_INVALID_ARGUMENT;
266         }
267     }
268     pkt->opts[pkt->optsCnt].optionBuffer = (const uint8_t*)&buf->rwBuffer[buf->len];
269     pkt->opts[pkt->optsCnt].num = opt->num;
270     pkt->opts[pkt->optsCnt].len = opt->len;
271     buf->len += opt->len;
272     pkt->len = buf->len;
273     pkt->optsCnt++;
274     ATTEST_LOG_DEBUG("[CoapAddOption] End");
275     return COAP_ERR_CODE_NONE;
276 }
277 
CoapAddOptions(CoapPacket * pkt,const CoapPacketParam * param,CoapRWBuffer * buf)278 static int32_t CoapAddOptions(CoapPacket* pkt, const CoapPacketParam* param, CoapRWBuffer *buf)
279 {
280     if (param->opts == NULL) {
281         return COAP_ERR_CODE_INVALID_ARGUMENT;
282     }
283     int32_t ret = 0;
284     if (param->optsCnt > COAP_MAX_OPTION) {
285         ATTEST_LOG_ERROR("[CoapAddOptions] Options exceed the limit");
286         return COAP_ERR_CODE_SERVER_ERROR;
287     }
288     for (size_t i = 0; i < param->optsCnt; i++) {
289         if ((ret = CoapAddOption(pkt, &param->opts[i], buf)) != 0) {
290             ATTEST_LOG_ERROR("[CoapAddOptions] Add coap option failed");
291             break;
292         } // need to check if content_type is NONE, sending payload is allowed ?
293     }
294     return ret;
295 }
296 
CoapAddData(CoapPacket * pkt,const CoapBuffer * payload,CoapRWBuffer * buf)297 static int32_t CoapAddData(CoapPacket* pkt, const CoapBuffer* payload, CoapRWBuffer* buf)
298 {
299     ATTEST_LOG_DEBUG("[CoapAddData] Start");
300     if ((pkt == NULL) || (payload == NULL) || (buf == NULL)) {
301         ATTEST_LOG_ERROR("[CoapAddData] Invalid parameter");
302         return COAP_ERR_CODE_INVALID_ARGUMENT;
303     }
304 
305     if ((buf->rwBuffer == NULL) || ((payload->len != 0) && (payload->buffer == NULL))) {
306         ATTEST_LOG_ERROR("[CoapAddData] Invalid parameter");
307         return COAP_ERR_CODE_INVALID_ARGUMENT;
308     }
309 
310     /* Coap header should have been created */
311     if (buf->len < HEADER_LEN) {
312         ATTEST_LOG_ERROR("[CoapAddData] Invalid coap head");
313         return COAP_ERR_CODE_INVALID_ARGUMENT;
314     }
315 
316     if ((payload->len > 0xFFFF) || ((buf->len + payload->len + 1) > buf->size)) {
317         ATTEST_LOG_ERROR("[CoapAddData] Payload overruns the buffer");
318         return COAP_ERR_CODE_PACKET_EXCEED_MAX_PDU;
319     }
320 
321     pkt->payload.len = payload->len;
322     if (payload->len) {
323         pkt->payload.len = payload->len;
324         buf->rwBuffer[(buf->len)++] = 0xFF; /* adding Marker */
325         pkt->payload.buffer = (const uint8_t*)&buf->rwBuffer[buf->len];
326         if (memcpy_s(&buf->rwBuffer[buf->len], MAX_MESSAGE_LEN, payload->buffer, payload->len) != 0) {
327             ATTEST_LOG_ERROR("[CoapAddData] Coap payload failed");
328             return COAP_ERR_CODE_INVALID_ARGUMENT;
329         }
330     }
331     buf->len += payload->len;
332     pkt->len = buf->len;
333     ATTEST_LOG_DEBUG("[CoapAddData] End");
334     return COAP_ERR_CODE_NONE;
335 }
336 
CoapCopyMessage(CoapPacket * pkt,CoapRWBuffer * buf,CoapRWBuffer * outBuf)337 static int32_t CoapCopyMessage(CoapPacket* pkt, CoapRWBuffer *buf, CoapRWBuffer *outBuf)
338 {
339     ATTEST_LOG_DEBUG("[CoapCopyMessage] Start");
340     if (pkt == NULL || buf == NULL || outBuf->rwBuffer == NULL) {
341         ATTEST_LOG_ERROR("[CoapCopyMessage] Invalid parameter");
342         return COAP_ERR_CODE_INVALID_ARGUMENT;
343     }
344     if (pkt->len < LENTKL_LEN) {
345         return COAP_ERR_CODE_INVALID_ARGUMENT;
346     }
347     if (pkt->tok.len + HEADER_LEN > buf->len) {
348         return COAP_ERR_CODE_INVALID_ARGUMENT;
349     }
350     uint8_t len = 0;
351     uint32_t index = 0;
352     size_t msgLen = 0;
353     int32_t ret = 0;
354     size_t contentLen = buf->len - pkt->tok.len - HEADER_LEN;
355     CoapGetOptionParam(contentLen, &len);
356     outBuf->rwBuffer[index++] = (char)((uint8_t)(buf->rwBuffer[0] & 0x0F) | ((len & 0x0F) << COAP_BITS_HEADER_LEN));
357 
358     if ((ret = CoapGetExtensionLen(len, &msgLen)) != 0) {
359         return ret;
360     }
361     if ((ret = CoapEncodeExtensionMsg(len, contentLen, &index, outBuf)) != 0) {
362         return ret;
363     }
364 
365     ret = memcpy_s(outBuf->rwBuffer + index, pkt->len - LENTKL_LEN,
366         buf->rwBuffer + LENTKL_LEN, pkt->len - LENTKL_LEN);
367     if (ret != ATTEST_OK) {
368         ATTEST_LOG_ERROR("[CoapCopyMessage] Invalid parameter");
369         return COAP_ERR_CODE_INVALID_ARGUMENT;
370     }
371     pkt->len = buf->len + msgLen;
372     pkt->hdr.len += len;
373     outBuf->len = pkt->len;
374     ATTEST_LOG_DEBUG("[CoapCopyMessage] End");
375     return COAP_ERR_CODE_NONE;
376 }
377 
CoapEncode(CoapPacket * pkt,const CoapPacketParam * param,const CoapBuffer * token,const CoapBuffer * payload,CoapRWBuffer * outBuf)378 static int32_t CoapEncode(CoapPacket* pkt, const CoapPacketParam* param, const CoapBuffer* token,
379     const CoapBuffer* payload, CoapRWBuffer* outBuf)
380 {
381     ATTEST_LOG_DEBUG("[CoapEncode] Start");
382     if (pkt == NULL || param == NULL || payload == NULL || outBuf == NULL) {
383         ATTEST_LOG_ERROR("[CoapEncode] Invalid parameter");
384         return COAP_ERR_CODE_INVALID_ARGUMENT;
385     }
386     int32_t ret;
387     CoapRWBuffer buf;
388     (void)memset_s(&buf, sizeof(CoapRWBuffer), 0, sizeof(CoapRWBuffer));
389     buf.rwBuffer = (char*)ATTEST_MEM_MALLOC(sizeof(char) * MAX_MESSAGE_LEN);
390     if (buf.rwBuffer == NULL) {
391         ATTEST_LOG_ERROR("[CoapEncode] Malloc memory failed");
392         return ATTEST_ERR;
393     }
394     buf.size = MAX_MESSAGE_LEN;
395     do {
396         if ((ret = CoapCreateHead(pkt, param->code, param->transType, &buf)) != 0) {
397             ATTEST_LOG_ERROR("[CoapEncode] Create coap header failed");
398             break;
399         }
400         /* Empty Message Validation */
401         if ((param->code == 0) && ((token != NULL) || (param->opts != NULL) || (payload != NULL))) {
402             ATTEST_LOG_ERROR("[CoapEncode] Invalid empty message");
403             ret = COAP_ERR_CODE_INVALID_EMPTY_MESSAGE;
404             break;
405         }
406         if (token != NULL) {
407             if ((ret = CoapAddToken(pkt, token, &buf)) != 0) {
408                 ATTEST_LOG_ERROR("[CoapEncode] Add coap token failed");
409                 break;
410             }
411         }
412         if ((ret = CoapAddOptions(pkt, param, &buf)) != 0) {
413             ATTEST_LOG_ERROR("[CoapEncode] Add options failed");
414             break;
415         }
416         if ((ret = CoapAddData(pkt, payload, &buf)) != 0) {
417             ATTEST_LOG_ERROR("[CoapEncode] Add coap data failed");
418             break;
419         }
420         if ((ret = CoapCopyMessage(pkt, &buf, outBuf)) != 0) { // copy buf to outBuff
421             ATTEST_LOG_ERROR("[CoapEncode] Copy message failed");
422             break;
423         }
424     } while (0);
425     ATTEST_MEM_FREE(buf.rwBuffer);
426     if (ret != 0) {
427         return ret;
428     }
429     ATTEST_LOG_DEBUG("[CoapEncode] End");
430     return COAP_ERR_CODE_NONE;
431 }
432 
CoapBuildMessage(CoapPacket * coapPacket,CoapPacketParam * coapPacketParam,CoapBuffer * payload,char * buff,uint32_t * len)433 int32_t CoapBuildMessage(CoapPacket* coapPacket, CoapPacketParam* coapPacketParam, CoapBuffer* payload,
434                          char* buff, uint32_t* len)
435 {
436     if (coapPacket == NULL || coapPacketParam == NULL || buff == NULL || len == NULL || payload == NULL) {
437         ATTEST_LOG_ERROR("[CoapBuildMessage] Invalid parameter");
438         return COAP_ERR_CODE_INVALID_ARGUMENT;
439     }
440     if (payload->buffer == NULL || payload->len >= *len) {
441         ATTEST_LOG_ERROR("[CoapBuildMessage] Payload is too big");
442         return COAP_ERR_CODE_INVALID_ARGUMENT;
443     }
444     CoapRWBuffer outputBuf;
445     CoapBuffer inputPayload;
446     CoapBuffer inputToken;
447     uint8_t tkl = PKT_TOKEN_LEN;
448     uint8_t token[PKT_TOKEN_LEN] = {0};
449 
450     (void)memset_s(&outputBuf, sizeof(CoapRWBuffer), 0, sizeof(CoapRWBuffer));
451     (void)memset_s(&inputPayload, sizeof(CoapBuffer), 0, sizeof(CoapBuffer));
452     (void)memset_s(&inputToken, sizeof(CoapBuffer), 0, sizeof(CoapBuffer));
453 
454     outputBuf.rwBuffer = buff;
455     outputBuf.size = *len;
456     inputPayload.buffer = payload->buffer;
457     inputPayload.len = payload->len;
458 
459     if (payload->len >= *len) {
460         ATTEST_LOG_ERROR("[CoapBuildMessage] Payload is too big");
461         return ATTEST_ERR;
462     }
463 
464     if (CoapCreateToken(token, &tkl) != 0) {
465         ATTEST_LOG_ERROR("[CoapBuildMessage] Create token failed");
466         return ATTEST_ERR;
467     }
468 
469     inputToken.buffer = token;
470     inputToken.len = tkl;
471 
472     int32_t ret;
473     if ((ret = CoapEncode(coapPacket, coapPacketParam, &inputToken, &inputPayload, &outputBuf)) != 0) {
474         ATTEST_LOG_ERROR("[CoapBuildMessage] Encode coap message failed");
475         return ret;
476     }
477 
478     *len = outputBuf.len;
479     (void)memset_s(token, sizeof(token), 0, sizeof(token));
480     ATTEST_LOG_DEBUG("[CoapBuildMessage] End");
481     return ret;
482 }
483 
CoapParseOptionExtension(uint16_t * value,const uint8_t ** p,uint8_t * hlen,size_t bufLen)484 static int32_t CoapParseOptionExtension(uint16_t* value, const uint8_t** p, uint8_t* hlen, size_t bufLen)
485 {
486     if (value == NULL || *p == NULL || hlen == NULL) {
487         ATTEST_LOG_ERROR("[CoapParseOptionExtension] Invalid parameter");
488         return COAP_ERR_CODE_INVALID_ARGUMENT;
489     }
490     if (*value == COAP_MESSAGE_OFFSET_ONE_BYTE) { /* The delta is 13, the length is 1 byte */
491         (*hlen)++;
492         if (bufLen < *hlen) {
493             ATTEST_LOG_ERROR("[CoapParseOptionExtension] Option extended delta or length overruns the buffer");
494             return COAP_ERR_CODE_OPTION_TOO_SHORT_FOR_HEADER;
495         }
496         *value = (uint16_t)((*p)[1] + COAP_MESSAGE_OFFSET_ONE_BYTE);
497         (*p)++;
498         return COAP_ERR_CODE_NONE;
499     }
500 
501     if (*value == COAP_MESSAGE_OFFSET_TWO_BYTES) { /* The delta is 14, the length is 2 bytes */
502         (*hlen) += COAP_MESSAGE_LENGTH_TWO_BYTES;
503         if (bufLen < *hlen) {
504             ATTEST_LOG_ERROR("[CoapParseOptionExtension] Option extended delta or length overruns the buffer");
505             return COAP_ERR_CODE_OPTION_TOO_SHORT_FOR_HEADER;
506         }
507         if (((uint32_t)((*p)[1] << BITS_PER_BYTE) | (*p)[COAP_OPTION_EXTENSION_LEN]) >
508             (MAX_VALUE_TWO_BYTES - COAP_MESSAGE_DIFF_VALUE_TWO_BYTES)) {
509             ATTEST_LOG_ERROR("[CoapParseOptionExtension] Option extend delta or length value is out of range");
510             return COAP_ERR_CODE_BAD_REQUEST;
511         }
512         *value = (uint16_t)((((*p)[1] << BITS_PER_BYTE) | (*p)[COAP_OPTION_EXTENSION_LEN]) +
513                  COAP_MESSAGE_DIFF_VALUE_TWO_BYTES);
514         (*p) += COAP_MESSAGE_LENGTH_TWO_BYTES;
515         return COAP_ERR_CODE_NONE;
516     }
517 
518     if (*value == COAP_MESSAGE_OFFSET_FOUR_BYTES) {
519         ATTEST_LOG_ERROR("[CoapParseOptionExtension] Option delta or length is invalid");
520         return COAP_ERR_CODE_OPTION_DELTA_INVALID;
521     }
522     return COAP_ERR_CODE_NONE;
523 }
524 
CoapParseOption(CoapOption * option,uint16_t * runningDelta,const uint8_t ** buf,size_t bufLen)525 static int32_t CoapParseOption(CoapOption* option, uint16_t* runningDelta, const uint8_t** buf, size_t bufLen)
526 {
527     if (option == NULL || runningDelta == NULL || *buf == NULL) {
528         ATTEST_LOG_ERROR("[CoapParseOption] Invalid parameter");
529         return COAP_ERR_CODE_INVALID_ARGUMENT;
530     }
531     uint8_t headLen = 1;
532     uint16_t len;
533     uint16_t delta;
534     const uint8_t *p = *buf;
535 
536     if (bufLen < headLen) {
537         ATTEST_LOG_ERROR("[CoapParseOption] Option header overruns the buffer");
538         return COAP_ERR_CODE_OPTION_TOO_SHORT_FOR_HEADER;
539     }
540     delta = (p[0] & 0xF0) >> COAP_BITS_OPTION_DELTA;
541     len = p[0] & 0x0F;
542     int32_t ret;
543     if ((ret = CoapParseOptionExtension(&delta, &p, &headLen, bufLen)) != 0) {
544         ATTEST_LOG_ERROR("[CoapParseOption] Invalid option delta");
545         return ret;
546     }
547     if ((ret = CoapParseOptionExtension(&len, &p, &headLen, bufLen)) != 0) {
548         ATTEST_LOG_ERROR("[CoapParseOption] Invalid option length");
549         return ret;
550     }
551     if ((p + 1 + len) > (*buf + bufLen)) {
552         ATTEST_LOG_ERROR("[CoapParseOption] Opton too big than buffer");
553         return COAP_ERR_CODE_OPTION_TOO_BIG;
554     }
555 
556     option->num = (uint16_t)(delta + *runningDelta);
557     option->optionBuffer = p + 1;
558     option->len = len;
559     // advance buf
560     *buf = p + 1 + len;
561     (*runningDelta) += delta;
562     return COAP_ERR_CODE_NONE;
563 }
564 
CoapParseOptionAndPayload(CoapOption * options,uint8_t * numOptions,CoapBuffer * payload,const CoapHead * hdr,CoapBuffer * buffer)565 static int32_t CoapParseOptionAndPayload(CoapOption* options, uint8_t* numOptions, CoapBuffer* payload,
566     const CoapHead* hdr, CoapBuffer *buffer)
567 {
568     if (options == NULL || numOptions == NULL || payload == NULL || hdr == NULL || buffer == NULL) {
569         ATTEST_LOG_ERROR("[CoapParseOptionAndPayload] Invalid parameter");
570         return COAP_ERR_CODE_INVALID_ARGUMENT;
571     }
572     uint8_t optionIndex = 0;
573     uint16_t delta = 0;
574     const uint8_t* p = buffer->buffer + CODE_LEN + hdr->tkl;
575     const uint8_t* end = buffer->buffer + buffer->len;
576 
577     if (p > end) {
578         ATTEST_LOG_ERROR("[CoapParseOptionAndPayload] Option or payload overruns packet size");
579         return COAP_ERR_CODE_OPTION_OVERRUNS_PACKET;
580     }
581 
582     while ((p < end) && (*p != 0xFF) && (optionIndex < COAP_MAX_OPTION)) {
583         int32_t ret = CoapParseOption(&options[optionIndex], &delta, &p, (size_t)(long)(end-p));
584         if (ret != 0) {
585             return ret;
586         }
587         optionIndex++;
588     }
589 
590     if ((p < end) && (*p != 0xFF) && (optionIndex == COAP_MAX_OPTION)) {
591         ATTEST_LOG_ERROR("[CoapParseOptionAndPayload] Option greater than maximum limit");
592         return COAP_ERR_CODE_SERVER_ERROR;
593     }
594     *numOptions = optionIndex;
595     if (*p == 0xFF) {
596         if (p + 1 < end) {
597             payload->buffer = p + 1;
598             payload->len = (size_t)(long)(end - (p + 1));
599         } else {
600             ATTEST_LOG_ERROR("[CoapParseOptionAndPayload] Packet have payload maker but no payload");
601             return COAP_ERR_CODE_INVALID_PACKET;
602         }
603     } else {
604         payload->buffer = NULL;
605         payload->len = 0;
606     }
607 
608     return COAP_ERR_CODE_NONE;
609 }
610 
CoapDecode(CoapPacket * pkt,const uint8_t * buf,size_t bufLen)611 int32_t CoapDecode(CoapPacket* pkt, const uint8_t* buf, size_t bufLen)
612 {
613     ATTEST_LOG_DEBUG("[CoapDecode] Start");
614     if (pkt == NULL || buf == NULL || bufLen > MAX_MESSAGE_LEN) {
615         ATTEST_LOG_ERROR("[CoapDecode] Invalid parameter");
616         return COAP_ERR_CODE_INVALID_ARGUMENT;
617     }
618     if (bufLen < HEADER_LEN) {
619         ATTEST_LOG_ERROR("[CoapDecode] Buffer length is smaller than coap header length");
620         return COAP_ERR_CODE_HEADER_TOO_SHORT;
621     }
622     pkt->hdr.code = buf[0]; /* The first Byte is code */
623 
624     if (pkt->hdr.tkl > MAX_TOK_LEN) {
625         ATTEST_LOG_ERROR("[CoapDecode] Length of symbol exceed the limit");
626         return COAP_ERR_CODE_INVALID_TOKEN_LEN;
627     }
628     if (bufLen > HEADER_LEN && pkt->hdr.code == 0) {
629         return COAP_ERR_CODE_INVALID_EMPTY_MESSAGE;
630     }
631 
632     if (pkt->hdr.tkl == 0) {
633         pkt->tok.buffer = NULL;
634         pkt->tok.len = 0;
635     } else if ((size_t)(pkt->hdr.tkl + HEADER_LEN) > bufLen) {
636         return COAP_ERR_CODE_TOKEN_TOO_SHORT;
637     } else {
638         pkt->tok.buffer = &buf[1];
639         pkt->tok.len = pkt->hdr.tkl;
640     }
641     CoapBuffer buffer;
642     (void)memset_s(&buffer, sizeof(CoapBuffer), 0, sizeof(CoapBuffer));
643     buffer.buffer = buf;
644     buffer.len = bufLen;
645 
646     int32_t ret = CoapParseOptionAndPayload(pkt->opts, &(pkt->optsCnt), &(pkt->payload), &pkt->hdr, &buffer);
647     if (ret != 0) {
648         ATTEST_LOG_ERROR("[CoapDecode] Parse option or payload failed");
649         return ret;
650     }
651     ATTEST_LOG_DEBUG("[CoapDecode] End");
652     return COAP_ERR_CODE_NONE;
653 }
654