1 /*
2 * Copyright (C) 2025 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 "cred_tlv_parser.h"
17 #include <stddef.h>
18
19 #define MAX_CRED_TLV_LENGTH (4800 * 1024)
20
ParseCredTlvHead(CredTlvBase * tlv,HcParcel * parcel)21 HcBool ParseCredTlvHead(CredTlvBase *tlv, HcParcel *parcel)
22 {
23 #ifdef IS_BIG_ENDIAN
24 if (!ParcelReadUint16Revert(parcel, &tlv->tag)) {
25 return HC_FALSE;
26 }
27 #else
28 if (!ParcelReadUint16(parcel, &tlv->tag)) {
29 return HC_FALSE;
30 }
31 #endif
32
33 if (tlv->tag != tlv->checkTag) {
34 return HC_FALSE;
35 }
36 #ifdef IS_BIG_ENDIAN
37 if (!ParcelReadUint32Revert(parcel, &tlv->length)) {
38 return HC_FALSE;
39 }
40 #else
41 if (!ParcelReadUint32(parcel, &tlv->length)) {
42 return HC_FALSE;
43 }
44 #endif
45 if (tlv->length > MAX_CRED_TLV_LENGTH) {
46 return HC_FALSE;
47 }
48 return HC_TRUE;
49 }
50
ParseCredTlvNode(CredTlvBase * tlv,HcParcel * parcel,HcBool strict)51 int64_t ParseCredTlvNode(CredTlvBase *tlv, HcParcel *parcel, HcBool strict)
52 {
53 if (!ParseCredTlvHead(tlv, parcel)) {
54 return CRED_TLV_FAIL;
55 } else {
56 if (GetParcelDataSize(parcel) < tlv->length) {
57 return CRED_TLV_FAIL;
58 }
59
60 int64_t ret = tlv->parse(tlv, parcel, strict);
61 if (ret < 0 || ret > MAX_CRED_TLV_LENGTH) {
62 return CRED_TLV_FAIL;
63 } else {
64 return ret + sizeof(tlv->tag) + sizeof(tlv->length);
65 }
66 }
67 }
68
GetlenCredTlvNode(CredTlvBase * tlv)69 int64_t GetlenCredTlvNode(CredTlvBase *tlv)
70 {
71 int64_t bodyLen = tlv->getlen(tlv);
72 if (bodyLen < 0 || bodyLen > MAX_CRED_TLV_LENGTH) {
73 return CRED_TLV_FAIL;
74 } else {
75 tlv->length = bodyLen + sizeof(tlv->tag) + sizeof(tlv->length);
76 return tlv->length;
77 }
78 }
79
DeinitCredTlvNode(CredTlvBase * tlv)80 void DeinitCredTlvNode(CredTlvBase *tlv)
81 {
82 if (tlv != NULL) {
83 tlv->deinit(tlv);
84 }
85 }
86
EncodeCredTlvNode(CredTlvBase * tlv,HcParcel * parcel,HcBool isRoot)87 int64_t EncodeCredTlvNode(CredTlvBase *tlv, HcParcel *parcel, HcBool isRoot)
88 {
89 int64_t bodyLen = tlv->getlen(tlv);
90 if (bodyLen < 0 || bodyLen > MAX_CRED_TLV_LENGTH) {
91 return CRED_TLV_FAIL;
92 } else if (bodyLen == 0) {
93 if (isRoot) {
94 ResetParcel(parcel, sizeof(uint16_t) + sizeof(uint32_t), 0);
95 }
96 #ifdef IS_BIG_ENDIAN
97 ParcelWriteUint16Revert(parcel, tlv->checkTag);
98 ParcelWriteUint32Revert(parcel, bodyLen);
99 #else
100 ParcelWriteUint16(parcel, tlv->checkTag);
101 ParcelWriteUint32(parcel, bodyLen);
102 #endif
103 return sizeof(tlv->tag) + sizeof(tlv->length);
104 } else { // has value
105 if (isRoot) {
106 ResetParcel(parcel, sizeof(uint16_t) + sizeof(uint32_t) + bodyLen, 0);
107 }
108 int64_t encodeLen;
109 tlv->length = (uint32_t)bodyLen;
110 #ifdef IS_BIG_ENDIAN
111 ParcelWriteUint16Revert(parcel, tlv->checkTag);
112 ParcelWriteUint32Revert(parcel, tlv->length);
113 #else
114 ParcelWriteUint16(parcel, tlv->checkTag);
115 ParcelWriteUint32(parcel, tlv->length);
116 #endif
117 encodeLen = tlv->encode(tlv, parcel);
118 if (encodeLen < 0 || encodeLen > MAX_CRED_TLV_LENGTH) {
119 return CRED_TLV_FAIL;
120 } else {
121 return encodeLen + sizeof(tlv->tag) + sizeof(tlv->length);
122 }
123 }
124 }
125
GetEmptyStructNode(CredTlvBase * tlv,unsigned short tag)126 static CredTlvBase* GetEmptyStructNode(CredTlvBase *tlv, unsigned short tag)
127 {
128 if (tlv == NULL) {
129 return NULL;
130 }
131
132 unsigned int index;
133 unsigned int memberCount = *(unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offsetCount));
134 unsigned int *offset = (unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offset));
135 for (index = 0; index < memberCount; ++index) {
136 CredTlvBase *tlvChild = (CredTlvBase *)(((char *)tlv) + offset[index]);
137 if (tlvChild->checkTag == tag && tlvChild->hasValue == 0) {
138 return tlvChild;
139 }
140 }
141
142 return NULL;
143 }
144
CheckStructNodeAllHasValue(CredTlvBase * tlv)145 static int64_t CheckStructNodeAllHasValue(CredTlvBase *tlv)
146 {
147 if (tlv == NULL) {
148 return 0;
149 } else {
150 unsigned int index;
151 unsigned int memberCount = *(unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offsetCount));
152 unsigned int *offset = (unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offset));
153 for (index = 0; index < memberCount; ++index) {
154 CredTlvBase *tlvChild = (CredTlvBase *)(((char *)tlv) + offset[index]);
155 if (tlvChild->hasValue == 0) {
156 return -1;
157 }
158 }
159 }
160
161 return 0;
162 }
163
SetStructNodeHasValue(CredTlvBase * tlv)164 static void SetStructNodeHasValue(CredTlvBase *tlv)
165 {
166 if (tlv != NULL) {
167 tlv->hasValue = 1;
168 }
169 }
170
ParseAndSkipTlvUnknownNode(HcParcel * parcel)171 static int64_t ParseAndSkipTlvUnknownNode(HcParcel *parcel)
172 {
173 // read tag
174 uint16_t tag = 0;
175 if (!ParcelReadUint16(parcel, &tag)) {
176 return CRED_TLV_FAIL;
177 }
178
179 // read length
180 uint32_t length = 0;
181 if (!ParcelReadUint32(parcel, &length)) {
182 return CRED_TLV_FAIL;
183 }
184
185 // pop data
186 if (!ParcelPopFront(parcel, length)) {
187 return CRED_TLV_FAIL;
188 }
189
190 return sizeof(tag) + sizeof(length) + length;
191 }
192
ParseCredTlvStruct(CredTlvBase * tlv,HcParcel * parcel,HcBool strict)193 int64_t ParseCredTlvStruct(CredTlvBase *tlv, HcParcel *parcel, HcBool strict)
194 {
195 int64_t childTotalLength = 0;
196 do {
197 uint16_t tag = 0;
198 if (!ParcelReadWithoutPopData(parcel, &tag, sizeof(tag))) {
199 return CRED_TLV_FAIL;
200 }
201 CredTlvBase *tlvChild = GetEmptyStructNode(tlv, tag);
202 if (tlvChild == NULL) {
203 if (strict) {
204 return CRED_TLV_FAIL;
205 }
206
207 int64_t unknownChildLength = ParseAndSkipTlvUnknownNode(parcel);
208 if (unknownChildLength < 0 || unknownChildLength > MAX_CRED_TLV_LENGTH) {
209 return CRED_TLV_FAIL;
210 }
211 childTotalLength += unknownChildLength;
212 if (childTotalLength > MAX_CRED_TLV_LENGTH) {
213 return CRED_TLV_FAIL;
214 }
215 } else {
216 int64_t childLength = ParseCredTlvNode(tlvChild, parcel, strict);
217 if (childLength < 0 || childLength > MAX_CRED_TLV_LENGTH) {
218 return CRED_TLV_FAIL;
219 }
220 SetStructNodeHasValue(tlvChild);
221 childTotalLength += childLength;
222 if (childTotalLength > MAX_CRED_TLV_LENGTH) {
223 return CRED_TLV_FAIL;
224 }
225 }
226 } while (childTotalLength < tlv->length);
227
228 if (childTotalLength > tlv->length) {
229 return CRED_TLV_FAIL;
230 }
231
232 if (strict && CheckStructNodeAllHasValue(tlv) != 0) {
233 return CRED_TLV_FAIL;
234 }
235
236 return childTotalLength;
237 }
238
EncodeCredTlvStruct(CredTlvBase * tlv,HcParcel * parcel)239 int64_t EncodeCredTlvStruct(CredTlvBase *tlv, HcParcel *parcel)
240 {
241 unsigned int index;
242 unsigned int memberCount = *(unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offsetCount));
243 unsigned int *offset = (unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offset));
244
245 uint32_t totalLen = 0;
246 for (index = 0; index < memberCount; ++index) {
247 CredTlvBase *tlvChild = (CredTlvBase *)(((char *)tlv) + offset[index]);
248 int64_t childLen = EncodeCredTlvNode(tlvChild, parcel, HC_FALSE);
249 if (childLen < 0 || childLen > MAX_CRED_TLV_LENGTH) {
250 return CRED_TLV_FAIL;
251 } else {
252 totalLen += childLen;
253 }
254 if (totalLen > MAX_CRED_TLV_LENGTH) {
255 return CRED_TLV_FAIL;
256 }
257 }
258
259 return totalLen;
260 }
261
GetLenCredTlvStruct(CredTlvBase * tlv)262 int64_t GetLenCredTlvStruct(CredTlvBase *tlv)
263 {
264 unsigned int index;
265 unsigned int memberCount = *(unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offsetCount));
266 unsigned int *offset = (unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offset));
267 int64_t childTotalLength = 0;
268
269 for (index = 0; index < memberCount; ++index) {
270 CredTlvBase *tlvChild = (CredTlvBase *)(((char *)tlv) + offset[index]);
271 int64_t childLength = GetlenCredTlvNode(tlvChild);
272 if (childLength <= 0 || childLength > MAX_CRED_TLV_LENGTH) {
273 return CRED_TLV_FAIL;
274 } else {
275 childTotalLength += childLength;
276 }
277 if (childTotalLength > MAX_CRED_TLV_LENGTH) {
278 return CRED_TLV_FAIL;
279 }
280 }
281
282 return childTotalLength;
283 }
284
DeinitCredTlvStruct(CredTlvBase * tlv)285 void DeinitCredTlvStruct(CredTlvBase *tlv)
286 {
287 unsigned int index;
288 unsigned int memberCount = *(unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offsetCount));
289 unsigned int *offset = (unsigned int *)((char *)tlv + offsetof(CredTlvOffsetExample, offset));
290
291 for (index = 0; index < memberCount; ++index) {
292 CredTlvBase *tlvChild = (CredTlvBase *)(((char *)tlv) + offset[index]);
293 DeinitCredTlvNode(tlvChild);
294 }
295 }
296
DecodeCredTlvMessage(CredTlvBase * msg,HcParcel * parcel,HcBool strict)297 HcBool DecodeCredTlvMessage(CredTlvBase *msg, HcParcel *parcel, HcBool strict)
298 {
299 if (msg == NULL || parcel == NULL) {
300 return HC_FALSE;
301 } else {
302 int64_t msgLen = ParseCredTlvNode(msg, parcel, strict);
303 if (msgLen > MAX_CRED_TLV_LENGTH) {
304 return HC_FALSE;
305 }
306 if ((int64_t)(msg->length + sizeof(msg->length) + sizeof(msg->tag)) != msgLen) {
307 return HC_FALSE;
308 }
309
310 if (GetParcelDataSize(parcel) != 0) {
311 return HC_FALSE;
312 }
313 }
314
315 return HC_TRUE;
316 }
317
318
EncodeCredTlvMessage(CredTlvBase * msg,HcParcel * parcel)319 HcBool EncodeCredTlvMessage(CredTlvBase *msg, HcParcel *parcel)
320 {
321 if (msg == NULL || parcel == NULL) {
322 return HC_FALSE;
323 } else {
324 if (EncodeCredTlvNode(msg, parcel, HC_TRUE) < 0) {
325 return HC_FALSE;
326 }
327 }
328
329 return HC_TRUE;
330 }
331
ParseCredTlvBuffer(CredTlvBase * tlv,HcParcel * parcel,HcBool strict)332 int64_t ParseCredTlvBuffer(CredTlvBase *tlv, HcParcel *parcel, HcBool strict)
333 {
334 (void)strict;
335 CredTlvBuffer *realTlv = (CredTlvBuffer *)(tlv);
336 if (tlv->length == 0 || ParcelReadParcel(parcel, &realTlv->data, tlv->length, HC_FALSE)) {
337 return tlv->length;
338 } else {
339 return CRED_TLV_FAIL;
340 }
341 }
342
GetlenCredTlvBuffer(CredTlvBase * tlv)343 int64_t GetlenCredTlvBuffer(CredTlvBase *tlv)
344 {
345 CredTlvBuffer *realTlv = (CredTlvBuffer *)(tlv);
346 return (int64_t)GetParcelDataSize(&realTlv->data);
347 }
348
EncodeCredTlvBuffer(CredTlvBase * tlv,HcParcel * parcel)349 int64_t EncodeCredTlvBuffer(CredTlvBase *tlv, HcParcel *parcel)
350 {
351 CredTlvBuffer *realTlv = (CredTlvBuffer *)(tlv);
352 int64_t len = GetlenCredTlvBuffer(tlv);
353 if (len <= 0 || len > MAX_CRED_TLV_LENGTH) {
354 return CRED_TLV_FAIL;
355 }
356
357 if (ParcelReadParcel(&realTlv->data, parcel, len, HC_TRUE)) {
358 return len;
359 } else {
360 return CRED_TLV_FAIL;
361 }
362 }
363
DeinitCredTlvBuffer(CredTlvBase * tlv)364 void DeinitCredTlvBuffer(CredTlvBase *tlv)
365 {
366 DeleteParcel(&((CredTlvBuffer *)tlv)->data);
367 }
368
InitCredTlvBuffer(CredTlvBuffer * tlv,unsigned short checkTag)369 void InitCredTlvBuffer(CredTlvBuffer *tlv, unsigned short checkTag)
370 {
371 (void)memset_s(&tlv->base, sizeof(tlv->base), 0, sizeof(tlv->base));
372 tlv->base.parse = ParseCredTlvBuffer;
373 tlv->base.getlen = GetlenCredTlvBuffer;
374 tlv->base.encode = EncodeCredTlvBuffer;
375 tlv->base.deinit = DeinitCredTlvBuffer;
376 tlv->base.checkTag = checkTag;
377 tlv->data = CreateParcel(PARCEL_DEFAULT_LENGTH, PARCEL_DEFAULT_ALLOC_UNIT);
378 }
379
ParseCredTlvString(CredTlvBase * tlv,HcParcel * parcel,HcBool strict)380 int64_t ParseCredTlvString(CredTlvBase *tlv, HcParcel *parcel, HcBool strict)
381 {
382 (void)strict;
383 CredTlvString *realTlv = (CredTlvString *)(tlv);
384 ClearParcel(&realTlv->data.parcel);
385 if (tlv->length == 0 || ParcelReadParcel(parcel, &realTlv->data.parcel, tlv->length, HC_FALSE)) {
386 return tlv->length;
387 } else {
388 return CRED_TLV_FAIL;
389 }
390 }
391
GetlenCredTlvString(CredTlvBase * tlv)392 int64_t GetlenCredTlvString(CredTlvBase *tlv)
393 {
394 CredTlvString *realTlv = (CredTlvString *)(tlv);
395 return (int64_t)GetParcelDataSize(&realTlv->data.parcel);
396 }
397
EncodeCredTlvString(CredTlvBase * tlv,HcParcel * parcel)398 int64_t EncodeCredTlvString(CredTlvBase *tlv, HcParcel *parcel)
399 {
400 CredTlvString *realTlv = (CredTlvString *)(tlv);
401 int64_t len = GetlenCredTlvString(tlv);
402 if (len <= 0 || len > MAX_CRED_TLV_LENGTH) {
403 return CRED_TLV_FAIL;
404 }
405
406 if (ParcelReadParcel(&realTlv->data.parcel, parcel, len, HC_TRUE)) {
407 return len;
408 } else {
409 return CRED_TLV_FAIL;
410 }
411 }
412
DeinitCredTlvString(CredTlvBase * tlv)413 void DeinitCredTlvString(CredTlvBase *tlv)
414 {
415 DeleteString(&((CredTlvString*)tlv)->data);
416 }
417
InitCredTlvString(CredTlvString * tlv,unsigned short checkTag)418 void InitCredTlvString(CredTlvString *tlv, unsigned short checkTag)
419 {
420 (void)memset_s(&tlv->base, sizeof(tlv->base), 0, sizeof(tlv->base));
421 tlv->base.parse = ParseCredTlvString;
422 tlv->base.getlen = GetlenCredTlvString;
423 tlv->base.encode = EncodeCredTlvString;
424 tlv->base.deinit = DeinitCredTlvString;
425 tlv->base.checkTag = checkTag;
426 tlv->data = CreateString();
427 }
428
GetCredTag(unsigned short checkTag,unsigned short defaultTag)429 unsigned short GetCredTag(unsigned short checkTag, unsigned short defaultTag)
430 {
431 if (checkTag == USE_DEFAULT_TAG) {
432 return defaultTag;
433 } else {
434 return checkTag;
435 }
436 }
437
DeinitCredTlvFixMember(CredTlvBase * tlv)438 void DeinitCredTlvFixMember(CredTlvBase* tlv)
439 {
440 (void)tlv;
441 return;
442 }
443
444 #ifdef IS_BIG_ENDIAN
445 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvInt64, NEED_REVERT)
446 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvInt32, NEED_REVERT)
447 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvInt16, NEED_REVERT)
448 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvInt8, NEED_REVERT)
449 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvUint64, NEED_REVERT)
450 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvUint32, NEED_REVERT)
451 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvUint16, NEED_REVERT)
452 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvUint8, NEED_REVERT)
453 #else
454 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvInt64, NO_REVERT)
455 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvInt32, NO_REVERT)
456 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvInt16, NO_REVERT)
457 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvInt8, NO_REVERT)
458 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvUint64, NO_REVERT)
459 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvUint32, NO_REVERT)
460 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvUint16, NO_REVERT)
461 DEFINE_CRED_TLV_FIX_LENGTH_TYPE(CredTlvUint8, NO_REVERT)
462 #endif
463