• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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