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