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, ¶m->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