1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "dice/cbor_reader.h"
16
17 enum CborType {
18 CBOR_TYPE_UINT = 0,
19 CBOR_TYPE_NINT = 1,
20 CBOR_TYPE_BSTR = 2,
21 CBOR_TYPE_TSTR = 3,
22 CBOR_TYPE_ARRAY = 4,
23 CBOR_TYPE_MAP = 5,
24 CBOR_TYPE_TAG = 6,
25 CBOR_TYPE_SIMPLE = 7,
26 };
27
CborReadWouldOverflow(size_t size,struct CborIn * in)28 static bool CborReadWouldOverflow(size_t size, struct CborIn* in) {
29 return size > SIZE_MAX - in->cursor || in->cursor + size > in->buffer_size;
30 }
31
CborPeekIntialValueAndArgument(struct CborIn * in,uint8_t * size,enum CborType * type,uint64_t * val)32 static enum CborReadResult CborPeekIntialValueAndArgument(struct CborIn* in,
33 uint8_t* size,
34 enum CborType* type,
35 uint64_t* val) {
36 uint8_t initial_byte;
37 uint8_t additional_information;
38 uint64_t value;
39 uint8_t bytes = 1;
40 if (CborInAtEnd(in)) {
41 return CBOR_READ_RESULT_END;
42 }
43 initial_byte = in->buffer[in->cursor];
44 *type = initial_byte >> 5;
45 additional_information = initial_byte & 0x1f;
46 if (additional_information <= 23) {
47 value = additional_information;
48 } else if (additional_information <= 27) {
49 bytes += 1 << (additional_information - 24);
50 if (CborReadWouldOverflow(bytes, in)) {
51 return CBOR_READ_RESULT_END;
52 }
53 value = 0;
54 if (bytes == 2) {
55 value |= in->buffer[in->cursor + 1];
56 } else if (bytes == 3) {
57 value |= (uint16_t)in->buffer[in->cursor + 1] << 8;
58 value |= (uint16_t)in->buffer[in->cursor + 2];
59 } else if (bytes == 5) {
60 value |= (uint32_t)in->buffer[in->cursor + 1] << 24;
61 value |= (uint32_t)in->buffer[in->cursor + 2] << 16;
62 value |= (uint32_t)in->buffer[in->cursor + 3] << 8;
63 value |= (uint32_t)in->buffer[in->cursor + 4];
64 } else if (bytes == 9) {
65 value |= (uint64_t)in->buffer[in->cursor + 1] << 56;
66 value |= (uint64_t)in->buffer[in->cursor + 2] << 48;
67 value |= (uint64_t)in->buffer[in->cursor + 3] << 40;
68 value |= (uint64_t)in->buffer[in->cursor + 4] << 32;
69 value |= (uint64_t)in->buffer[in->cursor + 5] << 24;
70 value |= (uint64_t)in->buffer[in->cursor + 6] << 16;
71 value |= (uint64_t)in->buffer[in->cursor + 7] << 8;
72 value |= (uint64_t)in->buffer[in->cursor + 8];
73 }
74 } else {
75 // Indefinite lengths and reserved values are not supported.
76 return CBOR_READ_RESULT_MALFORMED;
77 }
78 *val = value;
79 *size = bytes;
80 return CBOR_READ_RESULT_OK;
81 }
82
CborReadSize(struct CborIn * in,enum CborType type,size_t * size)83 static enum CborReadResult CborReadSize(struct CborIn* in, enum CborType type,
84 size_t* size) {
85 uint8_t bytes;
86 enum CborType in_type;
87 uint64_t raw;
88 enum CborReadResult res =
89 CborPeekIntialValueAndArgument(in, &bytes, &in_type, &raw);
90 if (res != CBOR_READ_RESULT_OK) {
91 return res;
92 }
93 if (in_type != type) {
94 return CBOR_READ_RESULT_NOT_FOUND;
95 }
96 if (raw > SIZE_MAX) {
97 return CBOR_READ_RESULT_MALFORMED;
98 }
99 *size = raw;
100 in->cursor += bytes;
101 return CBOR_READ_RESULT_OK;
102 }
103
CborReadStr(struct CborIn * in,enum CborType type,size_t * data_size,const uint8_t ** data)104 static enum CborReadResult CborReadStr(struct CborIn* in, enum CborType type,
105 size_t* data_size,
106 const uint8_t** data) {
107 size_t size;
108 struct CborIn peeker = *in;
109 enum CborReadResult res = CborReadSize(&peeker, type, &size);
110 if (res != CBOR_READ_RESULT_OK) {
111 return res;
112 }
113 if (CborReadWouldOverflow(size, &peeker)) {
114 return CBOR_READ_RESULT_END;
115 }
116 *data_size = size;
117 *data = &in->buffer[peeker.cursor];
118 in->cursor = peeker.cursor + size;
119 return CBOR_READ_RESULT_OK;
120 }
121
CborReadSimple(struct CborIn * in,uint8_t val)122 static enum CborReadResult CborReadSimple(struct CborIn* in, uint8_t val) {
123 uint8_t bytes;
124 enum CborType type;
125 uint64_t raw;
126 enum CborReadResult res =
127 CborPeekIntialValueAndArgument(in, &bytes, &type, &raw);
128 if (res != CBOR_READ_RESULT_OK) {
129 return res;
130 }
131 if (type != CBOR_TYPE_SIMPLE || raw != val) {
132 return CBOR_READ_RESULT_NOT_FOUND;
133 }
134 in->cursor += bytes;
135 return CBOR_READ_RESULT_OK;
136 }
137
CborReadInt(struct CborIn * in,int64_t * val)138 enum CborReadResult CborReadInt(struct CborIn* in, int64_t* val) {
139 uint8_t bytes;
140 enum CborType type;
141 uint64_t raw;
142 enum CborReadResult res =
143 CborPeekIntialValueAndArgument(in, &bytes, &type, &raw);
144 if (res != CBOR_READ_RESULT_OK) {
145 return res;
146 }
147 if (type != CBOR_TYPE_UINT && type != CBOR_TYPE_NINT) {
148 return CBOR_READ_RESULT_NOT_FOUND;
149 }
150 if (raw > INT64_MAX) {
151 return CBOR_READ_RESULT_MALFORMED;
152 }
153 *val = (type == CBOR_TYPE_NINT) ? (-1 - (int64_t)raw) : (int64_t)raw;
154 in->cursor += bytes;
155 return CBOR_READ_RESULT_OK;
156 }
157
CborReadUint(struct CborIn * in,uint64_t * val)158 enum CborReadResult CborReadUint(struct CborIn* in, uint64_t* val) {
159 uint8_t bytes;
160 enum CborType type;
161 enum CborReadResult res =
162 CborPeekIntialValueAndArgument(in, &bytes, &type, val);
163 if (res != CBOR_READ_RESULT_OK) {
164 return res;
165 }
166 if (type != CBOR_TYPE_UINT) {
167 return CBOR_READ_RESULT_NOT_FOUND;
168 }
169 in->cursor += bytes;
170 return CBOR_READ_RESULT_OK;
171 }
172
CborReadBstr(struct CborIn * in,size_t * data_size,const uint8_t ** data)173 enum CborReadResult CborReadBstr(struct CborIn* in, size_t* data_size,
174 const uint8_t** data) {
175 return CborReadStr(in, CBOR_TYPE_BSTR, data_size, data);
176 }
177
CborReadTstr(struct CborIn * in,size_t * size,const char ** str)178 enum CborReadResult CborReadTstr(struct CborIn* in, size_t* size,
179 const char** str) {
180 return CborReadStr(in, CBOR_TYPE_TSTR, size, (const uint8_t**)str);
181 }
182
CborReadArray(struct CborIn * in,size_t * num_elements)183 enum CborReadResult CborReadArray(struct CborIn* in, size_t* num_elements) {
184 return CborReadSize(in, CBOR_TYPE_ARRAY, num_elements);
185 }
186
CborReadMap(struct CborIn * in,size_t * num_pairs)187 enum CborReadResult CborReadMap(struct CborIn* in, size_t* num_pairs) {
188 return CborReadSize(in, CBOR_TYPE_MAP, num_pairs);
189 }
190
CborReadTag(struct CborIn * in,uint64_t * tag)191 enum CborReadResult CborReadTag(struct CborIn* in, uint64_t* tag) {
192 uint8_t bytes;
193 enum CborType type;
194 enum CborReadResult res =
195 CborPeekIntialValueAndArgument(in, &bytes, &type, tag);
196 if (res != CBOR_READ_RESULT_OK) {
197 return res;
198 }
199 if (type != CBOR_TYPE_TAG) {
200 return CBOR_READ_RESULT_NOT_FOUND;
201 }
202 in->cursor += bytes;
203 return CBOR_READ_RESULT_OK;
204 }
205
CborReadFalse(struct CborIn * in)206 enum CborReadResult CborReadFalse(struct CborIn* in) {
207 return CborReadSimple(in, /*val=*/20);
208 }
209
CborReadTrue(struct CborIn * in)210 enum CborReadResult CborReadTrue(struct CborIn* in) {
211 return CborReadSimple(in, /*val=*/21);
212 }
213
CborReadNull(struct CborIn * in)214 enum CborReadResult CborReadNull(struct CborIn* in) {
215 return CborReadSimple(in, /*val=*/22);
216 }
217
CborReadSkip(struct CborIn * in)218 enum CborReadResult CborReadSkip(struct CborIn* in) {
219 struct CborIn peeker = *in;
220 size_t size_stack[CBOR_READ_SKIP_STACK_SIZE];
221 size_t stack_size = 0;
222
223 size_stack[stack_size++] = 1;
224
225 while (stack_size > 0) {
226 // Get the type
227 uint8_t bytes;
228 enum CborType type;
229 uint64_t val;
230 enum CborReadResult res;
231
232 res = CborPeekIntialValueAndArgument(&peeker, &bytes, &type, &val);
233 if (res != CBOR_READ_RESULT_OK) {
234 return res;
235 }
236
237 if (CborReadWouldOverflow(bytes, &peeker)) {
238 return CBOR_READ_RESULT_END;
239 }
240 peeker.cursor += bytes;
241
242 if (--size_stack[stack_size - 1] == 0) {
243 --stack_size;
244 }
245
246 switch (type) {
247 case CBOR_TYPE_UINT:
248 case CBOR_TYPE_NINT:
249 case CBOR_TYPE_SIMPLE:
250 continue;
251 case CBOR_TYPE_BSTR:
252 case CBOR_TYPE_TSTR:
253 if (CborReadWouldOverflow(val, &peeker)) {
254 return CBOR_READ_RESULT_END;
255 }
256 peeker.cursor += val;
257 continue;
258 case CBOR_TYPE_MAP:
259 if (val > UINT64_MAX / 2) {
260 return CBOR_READ_RESULT_END;
261 }
262 val *= 2;
263 break;
264 case CBOR_TYPE_TAG:
265 val = 1;
266 break;
267 case CBOR_TYPE_ARRAY:
268 break;
269 default:
270 return CBOR_READ_RESULT_MALFORMED;
271 }
272
273 // Push a new level of nesting to the stack.
274 if (val == 0) {
275 continue;
276 }
277 if (stack_size == CBOR_READ_SKIP_STACK_SIZE) {
278 return CBOR_READ_RESULT_MALFORMED;
279 }
280 size_stack[stack_size++] = val;
281 }
282
283 in->cursor = peeker.cursor;
284 return CBOR_READ_RESULT_OK;
285 }
286