1 #include "cert.h"
2 #include <stdio.h>
3 
cert_field_get(const uint8_t * data,uint32_t length,uint16_t * field_type,const uint8_t ** contents,uint32_t * field_size)4 int cert_field_get(const uint8_t *data, uint32_t length, uint16_t *field_type, const uint8_t **contents, uint32_t *field_size) {
5     uint16_t field_id;
6     uint32_t field_len;
7     uint32_t additional_len;
8 
9     /* sanity checks. */
10     if (data == NULL) {
11         return 1;
12     }
13     if (field_type == NULL && contents == NULL && field_size == NULL) {
14         return 1;
15     }
16     if (length < 2) {
17         return 1;
18     }
19 
20     /* retrieve field id and number of additional bytes we need to read for the field's size */
21     field_id = (((uint16_t)data[0]) << 8) | data[1];
22     if (field_id == 0xFFFF) {
23         return 1;
24     }
25 
26     switch (field_id & 0xF) {
27         case 0xD: additional_len = 1; break;
28         case 0xE: additional_len = 2; break;
29         case 0xF: additional_len = 4; break;
30         default:  additional_len = 0; break;
31     }
32 
33     if (length < 2 + additional_len) {
34         return 1;
35     }
36 
37     /* retrieve data size of field. */
38     switch (field_id & 0xF) {
39         case 0xD:
40             field_len = (uint32_t)data[2];
41             break;
42 
43         case 0xE:
44             field_len = (((uint32_t)data[2]) << 8) | data[3];
45             break;
46 
47         case 0xF:
48             field_len = (((uint32_t)data[2]) << 24) | (((uint32_t)data[3]) << 16) | (((uint32_t)data[4]) << 8) | data[5];
49             break;
50 
51         default:
52             field_len = field_id & 0xF;
53             break;
54     }
55 
56     if (length < 2 + additional_len + field_len) {
57         return 1;
58     }
59 
60     if (field_type != NULL) {
61         /* don't mask out the size indication, it may be useful to the user. */
62         *field_type = field_id;
63     }
64     if (contents != NULL) {
65         *contents = data + 2 + additional_len;
66     }
67     if (field_size != NULL) {
68         *field_size = field_len;
69     }
70 
71     return 0;
72 }
73 
cert_field_next(const uint8_t ** data,uint32_t * length)74 int cert_field_next(const uint8_t **data, uint32_t *length) {
75     int ret;
76     const uint8_t * contents;
77     uint32_t field_size;
78 
79     /* sanity checks. */
80     if (data == NULL) {
81         return 1;
82     }
83     if (length == NULL) {
84         return 1;
85     }
86 
87     ret = cert_field_get(*data, *length, NULL, &contents, &field_size);
88     if (!ret) {
89         *length -= contents + field_size - *data;
90         *data = contents + field_size;
91     }
92 
93     return ret;
94 }
95 
cert_field_find(const uint8_t * data,uint32_t length,uint16_t field_type,const uint8_t ** contents,uint32_t * field_size)96 int cert_field_find(const uint8_t *data, uint32_t length, uint16_t field_type, const uint8_t **contents, uint32_t *field_size) {
97     int ret = 0;
98     uint16_t ft;
99 
100     /* sanity checks. */
101     if (data == NULL) {
102         return 1;
103     }
104     if (length < 2) {
105         return 1;
106     }
107 
108     /* mask out the size indication, it is harmful for finding a field */
109     field_type &= 0xFFF0;
110     ft = 0xFFFF;
111 
112     while (!ret && ft != field_type) {
113         ret = cert_field_get(data, length, &ft, contents, field_size);
114         ft &= 0xFFF0;
115         if (!ret) {
116             ret = cert_field_next(&data, &length);
117         }
118     }
119 
120     return ret;
121 }
122 
cert_field_find_path(const uint8_t * data,uint32_t length,const uint16_t * field_path,uint16_t field_path_len,const uint8_t ** contents,uint32_t * field_size)123 int cert_field_find_path(const uint8_t *data, uint32_t length, const uint16_t *field_path, uint16_t field_path_len, const uint8_t **contents, uint32_t *field_size) {
124     int ret = 0;
125 
126     /* sanity checks. */
127     if (data == NULL) {
128         return 1;
129     }
130     if (field_path == NULL) {
131         return 1;
132     }
133     if (length < 2) {
134         return 1;
135     }
136     if (field_path_len == 0) {
137         return 1;
138     }
139 
140     while (field_path_len != 0 && !ret) {
141         ret = cert_field_find(data, length, *field_path, &data, &length);
142         field_path++;
143         field_path_len--;
144         if (contents != NULL) {
145             *contents = data;
146         }
147         if (field_size != NULL) {
148             *field_size = length;
149         }
150     }
151 
152     return ret;
153 }
154