/src/samba/lib/util/asn1.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | simple ASN1 routines |
4 | | Copyright (C) Andrew Tridgell 2001 |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include "replace.h" |
21 | | #include "system/locale.h" |
22 | | #include "lib/util/asn1.h" |
23 | | #include "lib/util/debug.h" |
24 | | #include "lib/util/samba_util.h" |
25 | | #include "lib/util/smb_strtox.h" |
26 | | |
27 | | struct nesting { |
28 | | off_t start; |
29 | | size_t taglen; /* for parsing */ |
30 | | struct nesting *next; |
31 | | }; |
32 | | |
33 | | |
34 | | struct asn1_data { |
35 | | uint8_t *data; |
36 | | size_t length; |
37 | | off_t ofs; |
38 | | struct nesting *nesting; |
39 | | bool has_error; |
40 | | unsigned depth; |
41 | | unsigned max_depth; |
42 | | }; |
43 | | |
44 | | /* allocate an asn1 structure */ |
45 | | struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx, unsigned max_depth) |
46 | 4.13k | { |
47 | 4.13k | struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data); |
48 | 4.13k | if (ret == NULL) { |
49 | 0 | DBG_ERR("asn1_init failed! out of memory\n"); |
50 | 0 | return ret; |
51 | 0 | } |
52 | 4.13k | ret->max_depth = max_depth; |
53 | 4.13k | return ret; |
54 | 4.13k | } |
55 | | |
56 | | /* free an asn1 structure */ |
57 | | void asn1_free(struct asn1_data *data) |
58 | 486 | { |
59 | 486 | talloc_free(data); |
60 | 486 | } |
61 | | |
62 | | bool asn1_has_error(const struct asn1_data *data) |
63 | 1.28k | { |
64 | 1.28k | return data->has_error; |
65 | 1.28k | } |
66 | | |
67 | | void asn1_set_error(struct asn1_data *data) |
68 | 0 | { |
69 | 0 | data->has_error = true; |
70 | 0 | } |
71 | | |
72 | | bool asn1_has_nesting(const struct asn1_data *data) |
73 | 11 | { |
74 | 11 | return data->nesting != NULL; |
75 | 11 | } |
76 | | |
77 | | off_t asn1_current_ofs(const struct asn1_data *data) |
78 | 0 | { |
79 | 0 | return data->ofs; |
80 | 0 | } |
81 | | |
82 | | /* write to the ASN1 buffer, advancing the buffer pointer */ |
83 | | bool asn1_write(struct asn1_data *data, const void *p, int _len) |
84 | 0 | { |
85 | 0 | size_t len, ofs, newlen; |
86 | |
|
87 | 0 | if (data->has_error) return false; |
88 | | |
89 | 0 | if (_len < 0) { |
90 | 0 | goto error; |
91 | 0 | } |
92 | 0 | len = _len; |
93 | |
|
94 | 0 | if (data->ofs < 0) { |
95 | 0 | goto error; |
96 | 0 | } |
97 | 0 | ofs = data->ofs; |
98 | |
|
99 | 0 | newlen = ofs + len; |
100 | 0 | if (newlen < ofs) { |
101 | 0 | goto error; |
102 | 0 | } |
103 | | |
104 | 0 | if (data->length < newlen) { |
105 | 0 | uint8_t *newp; |
106 | 0 | newp = talloc_realloc(data, data->data, uint8_t, newlen); |
107 | 0 | if (!newp) { |
108 | 0 | goto error; |
109 | 0 | } |
110 | 0 | data->data = newp; |
111 | 0 | data->length = newlen; |
112 | 0 | } |
113 | 0 | if (len > 0) { |
114 | 0 | memcpy(data->data + data->ofs, p, len); |
115 | 0 | data->ofs += len; |
116 | 0 | } |
117 | 0 | return true; |
118 | 0 | error: |
119 | 0 | data->has_error = true; |
120 | 0 | return false; |
121 | 0 | } |
122 | | |
123 | | /* useful fn for writing a uint8_t */ |
124 | | bool asn1_write_uint8(struct asn1_data *data, uint8_t v) |
125 | 0 | { |
126 | 0 | return asn1_write(data, &v, 1); |
127 | 0 | } |
128 | | |
129 | | /* push a tag onto the asn1 data buffer. Used for nested structures */ |
130 | | bool asn1_push_tag(struct asn1_data *data, uint8_t tag) |
131 | 0 | { |
132 | 0 | struct nesting *nesting; |
133 | |
|
134 | 0 | if (!asn1_write_uint8(data, tag)) { |
135 | 0 | return false; |
136 | 0 | } |
137 | 0 | nesting = talloc(data, struct nesting); |
138 | 0 | if (!nesting) { |
139 | 0 | data->has_error = true; |
140 | 0 | return false; |
141 | 0 | } |
142 | | |
143 | 0 | nesting->start = data->ofs; |
144 | 0 | nesting->next = data->nesting; |
145 | 0 | data->nesting = nesting; |
146 | 0 | return asn1_write_uint8(data, 0xff); |
147 | 0 | } |
148 | | |
149 | | /* pop a tag */ |
150 | | bool asn1_pop_tag(struct asn1_data *data) |
151 | 0 | { |
152 | 0 | struct nesting *nesting; |
153 | 0 | size_t len; |
154 | |
|
155 | 0 | if (data->has_error) { |
156 | 0 | return false; |
157 | 0 | } |
158 | | |
159 | 0 | nesting = data->nesting; |
160 | |
|
161 | 0 | if (!nesting) { |
162 | 0 | data->has_error = true; |
163 | 0 | return false; |
164 | 0 | } |
165 | 0 | len = data->ofs - (nesting->start+1); |
166 | | /* yes, this is ugly. We don't know in advance how many bytes the length |
167 | | of a tag will take, so we assumed 1 byte. If we were wrong then we |
168 | | need to correct our mistake */ |
169 | 0 | if (len > 0xFFFFFF) { |
170 | 0 | data->data[nesting->start] = 0x84; |
171 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
172 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
173 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
174 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
175 | 0 | memmove(data->data+nesting->start+5, data->data+nesting->start+1, len); |
176 | 0 | data->data[nesting->start+1] = (len>>24) & 0xFF; |
177 | 0 | data->data[nesting->start+2] = (len>>16) & 0xFF; |
178 | 0 | data->data[nesting->start+3] = (len>>8) & 0xFF; |
179 | 0 | data->data[nesting->start+4] = len&0xff; |
180 | 0 | } else if (len > 0xFFFF) { |
181 | 0 | data->data[nesting->start] = 0x83; |
182 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
183 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
184 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
185 | 0 | memmove(data->data+nesting->start+4, data->data+nesting->start+1, len); |
186 | 0 | data->data[nesting->start+1] = (len>>16) & 0xFF; |
187 | 0 | data->data[nesting->start+2] = (len>>8) & 0xFF; |
188 | 0 | data->data[nesting->start+3] = len&0xff; |
189 | 0 | } else if (len > 255) { |
190 | 0 | data->data[nesting->start] = 0x82; |
191 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
192 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
193 | 0 | memmove(data->data+nesting->start+3, data->data+nesting->start+1, len); |
194 | 0 | data->data[nesting->start+1] = len>>8; |
195 | 0 | data->data[nesting->start+2] = len&0xff; |
196 | 0 | } else if (len > 127) { |
197 | 0 | data->data[nesting->start] = 0x81; |
198 | 0 | if (!asn1_write_uint8(data, 0)) return false; |
199 | 0 | memmove(data->data+nesting->start+2, data->data+nesting->start+1, len); |
200 | 0 | data->data[nesting->start+1] = len; |
201 | 0 | } else { |
202 | 0 | data->data[nesting->start] = len; |
203 | 0 | } |
204 | | |
205 | 0 | data->nesting = nesting->next; |
206 | 0 | talloc_free(nesting); |
207 | 0 | return true; |
208 | 0 | } |
209 | | |
210 | | /* "i" is the one's complement representation, as is the normal result of an |
211 | | * implicit signed->unsigned conversion */ |
212 | | |
213 | | static bool push_int_bigendian(struct asn1_data *data, unsigned int i, bool negative) |
214 | 0 | { |
215 | 0 | uint8_t lowest = i & 0xFF; |
216 | |
|
217 | 0 | i = i >> 8; |
218 | 0 | if (i != 0) |
219 | 0 | if (!push_int_bigendian(data, i, negative)) |
220 | 0 | return false; |
221 | | |
222 | 0 | if (data->nesting->start+1 == data->ofs) { |
223 | | |
224 | | /* We did not write anything yet, looking at the highest |
225 | | * valued byte */ |
226 | |
|
227 | 0 | if (negative) { |
228 | | /* Don't write leading 0xff's */ |
229 | 0 | if (lowest == 0xFF) |
230 | 0 | return true; |
231 | | |
232 | 0 | if ((lowest & 0x80) == 0) { |
233 | | /* The only exception for a leading 0xff is if |
234 | | * the highest bit is 0, which would indicate |
235 | | * a positive value */ |
236 | 0 | if (!asn1_write_uint8(data, 0xff)) |
237 | 0 | return false; |
238 | 0 | } |
239 | 0 | } else { |
240 | 0 | if (lowest & 0x80) { |
241 | | /* The highest bit of a positive integer is 1, |
242 | | * this would indicate a negative number. Push |
243 | | * a 0 to indicate a positive one */ |
244 | 0 | if (!asn1_write_uint8(data, 0)) |
245 | 0 | return false; |
246 | 0 | } |
247 | 0 | } |
248 | 0 | } |
249 | | |
250 | 0 | return asn1_write_uint8(data, lowest); |
251 | 0 | } |
252 | | |
253 | | /* write an Integer without the tag framing. Needed for example for the LDAP |
254 | | * Abandon Operation */ |
255 | | |
256 | | bool asn1_write_implicit_Integer(struct asn1_data *data, int i) |
257 | 0 | { |
258 | 0 | if (data->has_error) { |
259 | 0 | return false; |
260 | 0 | } |
261 | | |
262 | 0 | if (i == -1) { |
263 | | /* -1 is special as it consists of all-0xff bytes. In |
264 | | push_int_bigendian this is the only case that is not |
265 | | properly handled, as all 0xff bytes would be handled as |
266 | | leading ones to be ignored. */ |
267 | 0 | return asn1_write_uint8(data, 0xff); |
268 | 0 | } else { |
269 | 0 | return push_int_bigendian(data, i, i<0); |
270 | 0 | } |
271 | 0 | } |
272 | | |
273 | | |
274 | | /* write an integer */ |
275 | | bool asn1_write_Integer(struct asn1_data *data, int i) |
276 | 0 | { |
277 | 0 | bool ok = !asn1_has_error(data); |
278 | 0 | ok = ok && asn1_push_tag(data, ASN1_INTEGER); |
279 | 0 | ok = ok && asn1_write_implicit_Integer(data, i); |
280 | 0 | ok = ok && asn1_pop_tag(data); |
281 | 0 | return ok; |
282 | 0 | } |
283 | | |
284 | | /* write a BIT STRING */ |
285 | | bool asn1_write_BitString(struct asn1_data *data, const void *p, size_t length, uint8_t padding) |
286 | 0 | { |
287 | 0 | bool ok = !asn1_has_error(data); |
288 | 0 | ok = ok && asn1_push_tag(data, ASN1_BIT_STRING); |
289 | 0 | ok = ok && asn1_write_uint8(data, padding); |
290 | 0 | ok = ok && asn1_write(data, p, length); |
291 | 0 | ok = ok && asn1_pop_tag(data); |
292 | 0 | return ok; |
293 | 0 | } |
294 | | |
295 | | bool ber_write_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *OID) |
296 | 0 | { |
297 | 0 | unsigned long int v, v2; |
298 | 0 | const char *p = (const char *)OID; |
299 | 0 | char *newp; |
300 | 0 | int i; |
301 | 0 | int error = 0; |
302 | |
|
303 | 0 | if (!isdigit(*p)) return false; |
304 | 0 | v = smb_strtoul(p, &newp, 10, &error, SMB_STR_STANDARD); |
305 | 0 | if (newp[0] != '.' || error != 0) { |
306 | 0 | return false; |
307 | 0 | } |
308 | 0 | p = newp + 1; |
309 | |
|
310 | 0 | if (!isdigit(*p)) return false; |
311 | 0 | v2 = smb_strtoul(p, &newp, 10, &error, SMB_STR_STANDARD); |
312 | 0 | if (newp[0] != '.' || error != 0) { |
313 | 0 | return false; |
314 | 0 | } |
315 | 0 | p = newp + 1; |
316 | | |
317 | | /*the ber representation can't use more space than the string one */ |
318 | 0 | *blob = data_blob_talloc(mem_ctx, NULL, strlen(OID)); |
319 | 0 | if (!blob->data) return false; |
320 | | |
321 | 0 | blob->data[0] = 40*v + v2; |
322 | |
|
323 | 0 | i = 1; |
324 | 0 | while (*p) { |
325 | 0 | if (!isdigit(*p)) return false; |
326 | 0 | v = smb_strtoul(p, &newp, 10, &error, SMB_STR_STANDARD); |
327 | 0 | if (newp[0] == '.' || error != 0) { |
328 | 0 | p = newp + 1; |
329 | 0 | if (!*p) { |
330 | | /* empty last component */ |
331 | 0 | data_blob_free(blob); |
332 | 0 | return false; |
333 | 0 | } |
334 | 0 | } else if (newp[0] == '\0') { |
335 | 0 | p = newp; |
336 | 0 | } else { |
337 | 0 | data_blob_free(blob); |
338 | 0 | return false; |
339 | 0 | } |
340 | 0 | if (v >= (1<<28)) blob->data[i++] = (0x80 | ((v>>28)&0x7f)); |
341 | 0 | if (v >= (1<<21)) blob->data[i++] = (0x80 | ((v>>21)&0x7f)); |
342 | 0 | if (v >= (1<<14)) blob->data[i++] = (0x80 | ((v>>14)&0x7f)); |
343 | 0 | if (v >= (1<<7)) blob->data[i++] = (0x80 | ((v>>7)&0x7f)); |
344 | 0 | blob->data[i++] = (v&0x7f); |
345 | 0 | } |
346 | | |
347 | 0 | blob->length = i; |
348 | |
|
349 | 0 | return true; |
350 | 0 | } |
351 | | |
352 | | /** |
353 | | * Serialize partial OID string. |
354 | | * Partial OIDs are in the form: |
355 | | * 1:2.5.6:0x81 |
356 | | * 1:2.5.6:0x8182 |
357 | | */ |
358 | | bool ber_write_partial_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const char *partial_oid) |
359 | 0 | { |
360 | 0 | TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); |
361 | 0 | char *oid = talloc_strdup(tmp_ctx, partial_oid); |
362 | 0 | char *p; |
363 | | |
364 | | /* truncate partial part so ber_write_OID_String() works */ |
365 | 0 | p = strchr(oid, ':'); |
366 | 0 | if (p) { |
367 | 0 | *p = '\0'; |
368 | 0 | p++; |
369 | 0 | } |
370 | |
|
371 | 0 | if (!ber_write_OID_String(mem_ctx, blob, oid)) { |
372 | 0 | talloc_free(tmp_ctx); |
373 | 0 | return false; |
374 | 0 | } |
375 | | |
376 | | /* Add partially encoded sub-identifier */ |
377 | 0 | if (p) { |
378 | 0 | DATA_BLOB tmp_blob = strhex_to_data_blob(tmp_ctx, p); |
379 | 0 | if (!data_blob_append(mem_ctx, blob, tmp_blob.data, |
380 | 0 | tmp_blob.length)) { |
381 | 0 | talloc_free(tmp_ctx); |
382 | 0 | return false; |
383 | 0 | } |
384 | 0 | } |
385 | | |
386 | 0 | talloc_free(tmp_ctx); |
387 | |
|
388 | 0 | return true; |
389 | 0 | } |
390 | | |
391 | | /* write an object ID to a ASN1 buffer */ |
392 | | bool asn1_write_OID(struct asn1_data *data, const char *OID) |
393 | 0 | { |
394 | 0 | DATA_BLOB blob; |
395 | |
|
396 | 0 | if (!asn1_push_tag(data, ASN1_OID)) return false; |
397 | | |
398 | 0 | if (!ber_write_OID_String(NULL, &blob, OID)) { |
399 | 0 | data->has_error = true; |
400 | 0 | return false; |
401 | 0 | } |
402 | | |
403 | 0 | if (!asn1_write(data, blob.data, blob.length)) { |
404 | 0 | data_blob_free(&blob); |
405 | 0 | data->has_error = true; |
406 | 0 | return false; |
407 | 0 | } |
408 | 0 | data_blob_free(&blob); |
409 | 0 | return asn1_pop_tag(data); |
410 | 0 | } |
411 | | |
412 | | /* write an octet string */ |
413 | | bool asn1_write_OctetString(struct asn1_data *data, const void *p, size_t length) |
414 | 0 | { |
415 | 0 | bool ok = !asn1_has_error(data); |
416 | 0 | ok = ok && asn1_push_tag(data, ASN1_OCTET_STRING); |
417 | 0 | ok = ok && asn1_write(data, p, length); |
418 | 0 | ok = ok && asn1_pop_tag(data); |
419 | 0 | return ok; |
420 | 0 | } |
421 | | |
422 | | /* write a LDAP string */ |
423 | | bool asn1_write_LDAPString(struct asn1_data *data, const char *s) |
424 | 0 | { |
425 | 0 | return asn1_write(data, s, strlen(s)); |
426 | 0 | } |
427 | | |
428 | | /* write a LDAP string from a DATA_BLOB */ |
429 | | bool asn1_write_DATA_BLOB_LDAPString(struct asn1_data *data, const DATA_BLOB *s) |
430 | 0 | { |
431 | 0 | return asn1_write(data, s->data, s->length); |
432 | 0 | } |
433 | | |
434 | | /* write a general string */ |
435 | | bool asn1_write_GeneralString(struct asn1_data *data, const char *s) |
436 | 0 | { |
437 | 0 | bool ok = !asn1_has_error(data); |
438 | 0 | ok = ok && asn1_push_tag(data, ASN1_GENERAL_STRING); |
439 | 0 | ok = ok && asn1_write_LDAPString(data, s); |
440 | 0 | ok = ok && asn1_pop_tag(data); |
441 | 0 | return ok; |
442 | 0 | } |
443 | | |
444 | | bool asn1_write_ContextSimple(struct asn1_data *data, uint8_t num, DATA_BLOB *blob) |
445 | 0 | { |
446 | 0 | bool ok = !asn1_has_error(data); |
447 | 0 | ok = ok && asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(num)); |
448 | 0 | ok = ok && asn1_write(data, blob->data, blob->length); |
449 | 0 | ok = ok && asn1_pop_tag(data); |
450 | 0 | return ok; |
451 | 0 | } |
452 | | |
453 | | /* write a BOOLEAN */ |
454 | | bool asn1_write_BOOLEAN(struct asn1_data *data, bool v) |
455 | 0 | { |
456 | 0 | bool ok = !asn1_has_error(data); |
457 | 0 | ok = ok && asn1_push_tag(data, ASN1_BOOLEAN); |
458 | 0 | ok = ok && asn1_write_uint8(data, v ? 0xFF : 0); |
459 | 0 | ok = ok && asn1_pop_tag(data); |
460 | 0 | return ok; |
461 | 0 | } |
462 | | |
463 | | bool asn1_read_BOOLEAN(struct asn1_data *data, bool *v) |
464 | 796 | { |
465 | 796 | uint8_t tmp = 0; |
466 | 796 | if (!asn1_start_tag(data, ASN1_BOOLEAN)) return false; |
467 | 786 | *v = false; |
468 | 786 | if (!asn1_read_uint8(data, &tmp)) return false; |
469 | 780 | if (tmp == 0xFF) { |
470 | 92 | *v = true; |
471 | 92 | } |
472 | 780 | return asn1_end_tag(data); |
473 | 786 | } |
474 | | |
475 | | /* write a BOOLEAN in a simple context */ |
476 | | bool asn1_write_BOOLEAN_context(struct asn1_data *data, bool v, int context) |
477 | 0 | { |
478 | 0 | bool ok = !asn1_has_error(data); |
479 | 0 | ok = ok && asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(context)); |
480 | 0 | ok = ok && asn1_write_uint8(data, v ? 0xFF : 0); |
481 | 0 | ok = ok && asn1_pop_tag(data); |
482 | 0 | return ok; |
483 | 0 | } |
484 | | |
485 | | bool asn1_read_BOOLEAN_context(struct asn1_data *data, bool *v, int context) |
486 | 69 | { |
487 | 69 | uint8_t tmp = 0; |
488 | 69 | if (!asn1_start_tag(data, ASN1_CONTEXT_SIMPLE(context))) return false; |
489 | 59 | *v = false; |
490 | 59 | if (!asn1_read_uint8(data, &tmp)) return false; |
491 | 52 | if (tmp == 0xFF) { |
492 | 18 | *v = true; |
493 | 18 | } |
494 | 52 | return asn1_end_tag(data); |
495 | 59 | } |
496 | | |
497 | | /* check a BOOLEAN */ |
498 | | bool asn1_check_BOOLEAN(struct asn1_data *data, bool v) |
499 | 0 | { |
500 | 0 | uint8_t b = 0; |
501 | |
|
502 | 0 | if (!asn1_read_uint8(data, &b)) return false; |
503 | 0 | if (b != ASN1_BOOLEAN) { |
504 | 0 | data->has_error = true; |
505 | 0 | return false; |
506 | 0 | } |
507 | 0 | if (!asn1_read_uint8(data, &b)) return false; |
508 | 0 | if (b != v) { |
509 | 0 | data->has_error = true; |
510 | 0 | return false; |
511 | 0 | } |
512 | 0 | return !data->has_error; |
513 | 0 | } |
514 | | |
515 | | |
516 | | /* load a struct asn1_data structure with a lump of data, ready to be parsed */ |
517 | | bool asn1_load(struct asn1_data *data, DATA_BLOB blob) |
518 | 1.15k | { |
519 | | /* |
520 | | * Save the maximum depth |
521 | | */ |
522 | 1.15k | unsigned max_depth = data->max_depth; |
523 | | |
524 | 1.15k | *data = (struct asn1_data){ |
525 | 1.15k | .data = talloc_memdup(data, blob.data, blob.length), |
526 | 1.15k | .length = blob.length, |
527 | 1.15k | .max_depth = max_depth, |
528 | 1.15k | }; |
529 | | |
530 | 1.15k | if (data->data == NULL) { |
531 | 0 | data->has_error = true; |
532 | 0 | return false; |
533 | 0 | } |
534 | | |
535 | 1.15k | return true; |
536 | 1.15k | } |
537 | | |
538 | | /* Peek into an ASN1 buffer, not advancing the pointer */ |
539 | | static bool asn1_peek(struct asn1_data *data, void *p, int len) |
540 | 9.72M | { |
541 | 9.72M | size_t ofs, end; |
542 | | |
543 | 9.72M | if (data->has_error) |
544 | 25 | return false; |
545 | | |
546 | 9.72M | if (len < 0) { |
547 | 0 | return false; |
548 | 0 | } |
549 | | |
550 | 9.72M | if (data->ofs < 0) { |
551 | 0 | data->has_error = true; |
552 | 0 | return false; |
553 | 0 | } |
554 | 9.72M | ofs = data->ofs; |
555 | | |
556 | 9.72M | end = ofs + len; |
557 | 9.72M | if (end < ofs) { |
558 | 0 | return false; |
559 | 0 | } |
560 | | |
561 | 9.72M | if (end > data->length) { |
562 | | /* we need to mark the buffer as consumed, so the caller knows |
563 | | this was an out of data error, and not a decode error */ |
564 | 928 | data->ofs = data->length; |
565 | 928 | return false; |
566 | 928 | } |
567 | | |
568 | 9.72M | memcpy(p, data->data + data->ofs, len); |
569 | 9.72M | return true; |
570 | 9.72M | } |
571 | | |
572 | | /* read from a ASN1 buffer, advancing the buffer pointer */ |
573 | | bool asn1_read(struct asn1_data *data, void *p, int len) |
574 | 9.51M | { |
575 | 9.51M | if (!asn1_peek(data, p, len)) { |
576 | 878 | data->has_error = true; |
577 | 878 | return false; |
578 | 878 | } |
579 | | |
580 | 9.51M | data->ofs += len; |
581 | 9.51M | return true; |
582 | 9.51M | } |
583 | | |
584 | | /* read a uint8_t from a ASN1 buffer */ |
585 | | bool asn1_read_uint8(struct asn1_data *data, uint8_t *v) |
586 | 9.25M | { |
587 | 9.25M | return asn1_read(data, v, 1); |
588 | 9.25M | } |
589 | | |
590 | | bool asn1_peek_uint8(struct asn1_data *data, uint8_t *v) |
591 | 206k | { |
592 | 206k | return asn1_peek(data, v, 1); |
593 | 206k | } |
594 | | |
595 | | bool asn1_peek_tag(struct asn1_data *data, uint8_t tag) |
596 | 157k | { |
597 | 157k | uint8_t b; |
598 | | |
599 | 157k | if (asn1_tag_remaining(data) <= 0) { |
600 | 10.8k | return false; |
601 | 10.8k | } |
602 | | |
603 | 146k | if (!asn1_peek_uint8(data, &b)) |
604 | 0 | return false; |
605 | | |
606 | 146k | return (b == tag); |
607 | 146k | } |
608 | | |
609 | | /* |
610 | | * just get the needed size the tag would consume |
611 | | */ |
612 | | static bool asn1_peek_tag_needed_size(struct asn1_data *data, uint8_t tag, |
613 | | size_t *size) |
614 | 0 | { |
615 | 0 | off_t start_ofs = data->ofs; |
616 | 0 | uint8_t b; |
617 | 0 | size_t taglen = 0; |
618 | |
|
619 | 0 | if (data->has_error) { |
620 | 0 | return false; |
621 | 0 | } |
622 | | |
623 | 0 | if (!asn1_read_uint8(data, &b)) { |
624 | 0 | data->ofs = start_ofs; |
625 | 0 | data->has_error = false; |
626 | 0 | return false; |
627 | 0 | } |
628 | | |
629 | 0 | if (b != tag) { |
630 | 0 | data->ofs = start_ofs; |
631 | 0 | data->has_error = false; |
632 | 0 | return false; |
633 | 0 | } |
634 | | |
635 | 0 | if (!asn1_read_uint8(data, &b)) { |
636 | 0 | data->ofs = start_ofs; |
637 | 0 | data->has_error = false; |
638 | 0 | return false; |
639 | 0 | } |
640 | | |
641 | 0 | if (b & 0x80) { |
642 | 0 | int n = b & 0x7f; |
643 | 0 | if (!asn1_read_uint8(data, &b)) { |
644 | 0 | data->ofs = start_ofs; |
645 | 0 | data->has_error = false; |
646 | 0 | return false; |
647 | 0 | } |
648 | 0 | if (n > 4) { |
649 | | /* |
650 | | * We should not allow more than 4 bytes |
651 | | * for the encoding of the tag length. |
652 | | * |
653 | | * Otherwise we'd overflow the taglen |
654 | | * variable on 32 bit systems. |
655 | | */ |
656 | 0 | data->ofs = start_ofs; |
657 | 0 | data->has_error = false; |
658 | 0 | return false; |
659 | 0 | } |
660 | 0 | taglen = b; |
661 | 0 | while (n > 1) { |
662 | 0 | size_t tmp_taglen; |
663 | |
|
664 | 0 | if (!asn1_read_uint8(data, &b)) { |
665 | 0 | data->ofs = start_ofs; |
666 | 0 | data->has_error = false; |
667 | 0 | return false; |
668 | 0 | } |
669 | | |
670 | 0 | tmp_taglen = (taglen << 8) | b; |
671 | |
|
672 | 0 | if ((tmp_taglen >> 8) != taglen) { |
673 | | /* overflow */ |
674 | 0 | data->ofs = start_ofs; |
675 | 0 | data->has_error = false; |
676 | 0 | return false; |
677 | 0 | } |
678 | 0 | taglen = tmp_taglen; |
679 | |
|
680 | 0 | n--; |
681 | 0 | } |
682 | 0 | } else { |
683 | 0 | taglen = b; |
684 | 0 | } |
685 | | |
686 | 0 | *size = (data->ofs - start_ofs) + taglen; |
687 | |
|
688 | 0 | data->ofs = start_ofs; |
689 | 0 | data->has_error = false; |
690 | 0 | return true; |
691 | 0 | } |
692 | | |
693 | | /* start reading a nested asn1 structure */ |
694 | | bool asn1_start_tag(struct asn1_data *data, uint8_t tag) |
695 | 309k | { |
696 | 309k | uint8_t b; |
697 | 309k | struct nesting *nesting; |
698 | | |
699 | | /* |
700 | | * Check the depth of the parse tree and prevent it from growing |
701 | | * too large. |
702 | | */ |
703 | 309k | data->depth++; |
704 | 309k | if (data->depth > data->max_depth) { |
705 | 2 | data->has_error = true; |
706 | 2 | return false; |
707 | 2 | } |
708 | | |
709 | 309k | if (!asn1_read_uint8(data, &b)) |
710 | 480 | return false; |
711 | | |
712 | 308k | if (b != tag) { |
713 | 352 | data->has_error = true; |
714 | 352 | return false; |
715 | 352 | } |
716 | 308k | nesting = talloc(data, struct nesting); |
717 | 308k | if (!nesting) { |
718 | 0 | data->has_error = true; |
719 | 0 | return false; |
720 | 0 | } |
721 | | |
722 | 308k | if (!asn1_read_uint8(data, &b)) { |
723 | 174 | return false; |
724 | 174 | } |
725 | | |
726 | 308k | if (b & 0x80) { |
727 | 4.42k | int n = b & 0x7f; |
728 | 4.42k | if (!asn1_read_uint8(data, &b)) |
729 | 49 | return false; |
730 | 4.37k | nesting->taglen = b; |
731 | 15.0k | while (n > 1) { |
732 | 10.8k | size_t taglen; |
733 | | |
734 | 10.8k | if (!asn1_read_uint8(data, &b)) |
735 | 161 | return false; |
736 | | |
737 | 10.6k | taglen = (nesting->taglen << 8) | b; |
738 | | |
739 | 10.6k | if ((taglen >> 8) != nesting->taglen) { |
740 | | /* overflow */ |
741 | 62 | data->has_error = true; |
742 | 62 | return false; |
743 | 62 | } |
744 | 10.6k | nesting->taglen = taglen; |
745 | | |
746 | 10.6k | n--; |
747 | 10.6k | } |
748 | 303k | } else { |
749 | 303k | nesting->taglen = b; |
750 | 303k | } |
751 | 308k | nesting->start = data->ofs; |
752 | 308k | nesting->next = data->nesting; |
753 | 308k | data->nesting = nesting; |
754 | 308k | if (asn1_tag_remaining(data) == -1) { |
755 | 436 | return false; |
756 | 436 | } |
757 | 307k | return !data->has_error; |
758 | 308k | } |
759 | | |
760 | | /* stop reading a tag */ |
761 | | bool asn1_end_tag(struct asn1_data *data) |
762 | 289k | { |
763 | 289k | struct nesting *nesting; |
764 | | |
765 | 289k | if (data->depth == 0) { |
766 | 0 | smb_panic("Unbalanced ASN.1 Tag nesting"); |
767 | 0 | } |
768 | 289k | data->depth--; |
769 | | /* make sure we read it all */ |
770 | 289k | if (asn1_tag_remaining(data) != 0) { |
771 | 1.63k | data->has_error = true; |
772 | 1.63k | return false; |
773 | 1.63k | } |
774 | | |
775 | 287k | nesting = data->nesting; |
776 | | |
777 | 287k | if (!nesting) { |
778 | 0 | data->has_error = true; |
779 | 0 | return false; |
780 | 0 | } |
781 | | |
782 | 287k | data->nesting = nesting->next; |
783 | 287k | talloc_free(nesting); |
784 | 287k | return true; |
785 | 287k | } |
786 | | |
787 | | /* work out how many bytes are left in this nested tag */ |
788 | | int asn1_tag_remaining(struct asn1_data *data) |
789 | 9.77M | { |
790 | 9.77M | size_t consumed, remaining_tag, remaining_data; |
791 | 9.77M | if (data->has_error) { |
792 | 1.05k | return -1; |
793 | 1.05k | } |
794 | | |
795 | 9.77M | if (!data->nesting) { |
796 | 0 | goto error; |
797 | 0 | } |
798 | | |
799 | 9.77M | if (data->ofs < data->nesting->start) { |
800 | 0 | goto error; |
801 | 0 | } |
802 | 9.77M | consumed = data->ofs - data->nesting->start; |
803 | | |
804 | 9.77M | if (data->nesting->taglen < consumed) { |
805 | 1.40k | goto error; |
806 | 1.40k | } |
807 | 9.77M | remaining_tag = data->nesting->taglen - consumed; |
808 | | |
809 | 9.77M | if ((data->ofs < 0) || (data->length < (size_t)data->ofs)) { |
810 | 0 | goto error; |
811 | 0 | } |
812 | 9.77M | remaining_data = data->length - data->ofs; |
813 | | |
814 | 9.77M | if (remaining_tag > remaining_data) { |
815 | 436 | goto error; |
816 | 436 | } |
817 | 9.77M | if (remaining_tag > INT_MAX) { |
818 | 0 | goto error; |
819 | 0 | } |
820 | 9.77M | return remaining_tag; |
821 | 1.83k | error: |
822 | 1.83k | data->has_error = true; |
823 | 1.83k | return -1; |
824 | 9.77M | } |
825 | | |
826 | | /** |
827 | | * Internal implementation for reading binary OIDs |
828 | | * Reading is done as far in the buffer as valid OID |
829 | | * till buffer ends or not valid sub-identifier is found. |
830 | | */ |
831 | | static bool _ber_read_OID_String_impl(TALLOC_CTX *mem_ctx, DATA_BLOB blob, |
832 | | char **OID, size_t *bytes_eaten) |
833 | 5.10k | { |
834 | 5.10k | size_t i; |
835 | 5.10k | uint8_t *b; |
836 | 5.10k | unsigned int v; |
837 | 5.10k | char *tmp_oid = NULL; |
838 | | |
839 | 5.10k | if (blob.length < 2) return false; |
840 | | |
841 | 1.26k | b = blob.data; |
842 | | |
843 | 1.26k | tmp_oid = talloc_asprintf(mem_ctx, "%u.%u", b[0]/40, b[0]%40); |
844 | | |
845 | 1.26k | if (bytes_eaten != NULL) { |
846 | 1.26k | *bytes_eaten = 0; |
847 | 1.26k | } |
848 | | |
849 | 1.37M | for(i = 1, v = 0; i < blob.length; i++) { |
850 | 1.37M | v = (v<<7) | (b[i]&0x7f); |
851 | 1.37M | if ( ! (b[i] & 0x80)) { |
852 | 1.05M | talloc_asprintf_addbuf(&tmp_oid, ".%u", v); |
853 | 1.05M | v = 0; |
854 | 1.05M | if (bytes_eaten) |
855 | 1.05M | *bytes_eaten = i+1; |
856 | 1.05M | } |
857 | 1.37M | } |
858 | | |
859 | 1.26k | if (tmp_oid == NULL) { |
860 | 0 | goto nomem; |
861 | 0 | } |
862 | | |
863 | 1.26k | *OID = tmp_oid; |
864 | 1.26k | return true; |
865 | | |
866 | 0 | nomem: |
867 | 0 | return false; |
868 | 1.26k | } |
869 | | |
870 | | /* read an object ID from a data blob */ |
871 | | bool ber_read_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, char **OID) |
872 | 229 | { |
873 | 229 | size_t bytes_eaten; |
874 | | |
875 | 229 | if (!_ber_read_OID_String_impl(mem_ctx, blob, OID, &bytes_eaten)) |
876 | 25 | return false; |
877 | | |
878 | 204 | return (bytes_eaten == blob.length); |
879 | 229 | } |
880 | | |
881 | | /** |
882 | | * Deserialize partial OID string. |
883 | | * Partial OIDs are in the form: |
884 | | * 1:2.5.6:0x81 |
885 | | * 1:2.5.6:0x8182 |
886 | | */ |
887 | | bool ber_read_partial_OID_String(TALLOC_CTX *mem_ctx, DATA_BLOB blob, |
888 | | char **partial_oid) |
889 | 4.87k | { |
890 | 4.87k | size_t bytes_left; |
891 | 4.87k | size_t bytes_eaten; |
892 | 4.87k | char *identifier = NULL; |
893 | 4.87k | char *tmp_oid = NULL; |
894 | | |
895 | 4.87k | if (!_ber_read_OID_String_impl(mem_ctx, blob, &tmp_oid, &bytes_eaten)) |
896 | 3.81k | return false; |
897 | | |
898 | 1.05k | if (bytes_eaten < blob.length) { |
899 | 279 | bytes_left = blob.length - bytes_eaten; |
900 | 279 | identifier = hex_encode_talloc(mem_ctx, &blob.data[bytes_eaten], bytes_left); |
901 | 279 | if (!identifier) goto nomem; |
902 | | |
903 | 279 | *partial_oid = talloc_asprintf_append_buffer(tmp_oid, ":0x%s", identifier); |
904 | 279 | if (!*partial_oid) goto nomem; |
905 | 279 | TALLOC_FREE(identifier); |
906 | 779 | } else { |
907 | 779 | *partial_oid = tmp_oid; |
908 | 779 | } |
909 | | |
910 | 1.05k | return true; |
911 | | |
912 | 0 | nomem: |
913 | 0 | TALLOC_FREE(identifier); |
914 | 0 | TALLOC_FREE(tmp_oid); |
915 | 0 | return false; |
916 | 1.05k | } |
917 | | |
918 | | /* read an object ID from a ASN1 buffer */ |
919 | | bool asn1_read_OID(struct asn1_data *data, TALLOC_CTX *mem_ctx, char **OID) |
920 | 274 | { |
921 | 274 | DATA_BLOB blob; |
922 | 274 | int len; |
923 | | |
924 | 274 | if (!asn1_start_tag(data, ASN1_OID)) return false; |
925 | | |
926 | 235 | len = asn1_tag_remaining(data); |
927 | 235 | if (len < 0) { |
928 | 0 | data->has_error = true; |
929 | 0 | return false; |
930 | 0 | } |
931 | | |
932 | 235 | blob = data_blob(NULL, len); |
933 | 235 | if (!blob.data) { |
934 | 6 | data->has_error = true; |
935 | 6 | return false; |
936 | 6 | } |
937 | | |
938 | 229 | if (!asn1_read(data, blob.data, len)) { |
939 | 0 | data_blob_free(&blob); |
940 | 0 | return false; |
941 | 0 | } |
942 | | |
943 | 229 | if (!asn1_end_tag(data)) { |
944 | 0 | data_blob_free(&blob); |
945 | 0 | return false; |
946 | 0 | } |
947 | | |
948 | 229 | if (!ber_read_OID_String(mem_ctx, blob, OID)) { |
949 | 78 | data->has_error = true; |
950 | 78 | data_blob_free(&blob); |
951 | 78 | return false; |
952 | 78 | } |
953 | | |
954 | 151 | data_blob_free(&blob); |
955 | 151 | return true; |
956 | 229 | } |
957 | | |
958 | | /* check that the next object ID is correct */ |
959 | | bool asn1_check_OID(struct asn1_data *data, const char *OID) |
960 | 274 | { |
961 | 274 | char *id; |
962 | | |
963 | 274 | if (!asn1_read_OID(data, data, &id)) return false; |
964 | | |
965 | 151 | if (strcmp(id, OID) != 0) { |
966 | 151 | talloc_free(id); |
967 | 151 | data->has_error = true; |
968 | 151 | return false; |
969 | 151 | } |
970 | 0 | talloc_free(id); |
971 | 0 | return true; |
972 | 151 | } |
973 | | |
974 | | /* read a LDAPString from a ASN1 buffer */ |
975 | | bool asn1_read_LDAPString(struct asn1_data *data, |
976 | | TALLOC_CTX *mem_ctx, |
977 | | char **_s) |
978 | 48.3k | { |
979 | 48.3k | int len; |
980 | 48.3k | char *s = NULL; |
981 | 48.3k | bool ok; |
982 | | |
983 | 48.3k | len = asn1_tag_remaining(data); |
984 | 48.3k | if (len < 0) { |
985 | 0 | data->has_error = true; |
986 | 0 | return false; |
987 | 0 | } |
988 | 48.3k | s = talloc_array(mem_ctx, char, len + 1); |
989 | 48.3k | if (s == NULL) { |
990 | 0 | data->has_error = true; |
991 | 0 | return false; |
992 | 0 | } |
993 | 48.3k | s[len] = 0; |
994 | | |
995 | 48.3k | ok = asn1_read(data, s, len); |
996 | 48.3k | if (!ok) { |
997 | 0 | TALLOC_FREE(s); |
998 | 0 | return false; |
999 | 0 | } |
1000 | | |
1001 | 48.3k | *_s = s; |
1002 | 48.3k | return true; |
1003 | 48.3k | } |
1004 | | |
1005 | | |
1006 | | /* read a GeneralString from a ASN1 buffer */ |
1007 | | bool asn1_read_GeneralString(struct asn1_data *data, |
1008 | | TALLOC_CTX *mem_ctx, |
1009 | | char **_s) |
1010 | 0 | { |
1011 | 0 | char *s = NULL; |
1012 | 0 | bool ok = false; |
1013 | |
|
1014 | 0 | if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) return false; |
1015 | 0 | if (!asn1_read_LDAPString(data, mem_ctx, &s)) return false; |
1016 | | |
1017 | 0 | ok = asn1_end_tag(data); |
1018 | 0 | if (!ok) { |
1019 | 0 | TALLOC_FREE(s); |
1020 | 0 | return false; |
1021 | 0 | } |
1022 | | |
1023 | 0 | *_s = s; |
1024 | 0 | return true; |
1025 | 0 | } |
1026 | | |
1027 | | |
1028 | | static bool asn1_read_blob_tag(struct asn1_data *data, TALLOC_CTX *mem_ctx, |
1029 | | uint8_t tag, DATA_BLOB *blob) |
1030 | 209k | { |
1031 | 209k | int len; |
1032 | 209k | ZERO_STRUCTP(blob); |
1033 | 209k | if (!asn1_start_tag(data, tag)) return false; |
1034 | 208k | len = asn1_tag_remaining(data); |
1035 | 208k | if (len < 0) { |
1036 | 0 | data->has_error = true; |
1037 | 0 | return false; |
1038 | 0 | } |
1039 | 208k | *blob = data_blob_talloc(mem_ctx, NULL, len+1); |
1040 | 208k | if (!blob->data || blob->length < (unsigned)len) { |
1041 | 0 | data->has_error = true; |
1042 | 0 | return false; |
1043 | 0 | } |
1044 | 208k | if (!asn1_read(data, blob->data, len)) goto err; |
1045 | 208k | if (!asn1_end_tag(data)) goto err; |
1046 | 208k | blob->length--; |
1047 | 208k | blob->data[len] = 0; |
1048 | 208k | return true; |
1049 | | |
1050 | 0 | err: |
1051 | |
|
1052 | 0 | data_blob_free(blob); |
1053 | 0 | return false; |
1054 | 208k | } |
1055 | | |
1056 | | /* read a octet string blob */ |
1057 | | bool asn1_read_OctetString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob) |
1058 | 209k | { |
1059 | 209k | return asn1_read_blob_tag(data, mem_ctx, ASN1_OCTET_STRING, blob); |
1060 | 209k | } |
1061 | | |
1062 | | bool asn1_read_ContextSimple(struct asn1_data *data, TALLOC_CTX *mem_ctx, uint8_t num, |
1063 | | DATA_BLOB *blob) |
1064 | 214 | { |
1065 | 214 | return asn1_read_blob_tag(data, mem_ctx, ASN1_CONTEXT_SIMPLE(num), blob); |
1066 | 214 | } |
1067 | | |
1068 | | /* read an integer without tag*/ |
1069 | | bool asn1_read_implicit_Integer(struct asn1_data *data, int *i) |
1070 | 4.51k | { |
1071 | 4.51k | uint8_t b; |
1072 | 4.51k | uint32_t x = 0; |
1073 | 4.51k | bool first_byte = true; |
1074 | | |
1075 | 4.51k | *i = 0; |
1076 | | |
1077 | 7.16M | while (!data->has_error && asn1_tag_remaining(data)>0) { |
1078 | 7.16M | if (!asn1_read_uint8(data, &b)) return false; |
1079 | 7.16M | if (first_byte) { |
1080 | 444 | if (b & 0x80) { |
1081 | | /* Number is negative. */ |
1082 | 127 | x = (uint32_t)-1; |
1083 | 127 | } |
1084 | 444 | first_byte = false; |
1085 | 444 | } |
1086 | 7.16M | x = (x << 8) + b; |
1087 | 7.16M | } |
1088 | 4.51k | *i = (int)x; |
1089 | | |
1090 | 4.51k | return !data->has_error; |
1091 | 4.51k | } |
1092 | | |
1093 | | /* read an integer */ |
1094 | | bool asn1_read_Integer(struct asn1_data *data, int *i) |
1095 | 4.45k | { |
1096 | 4.45k | *i = 0; |
1097 | | |
1098 | 4.45k | if (!asn1_start_tag(data, ASN1_INTEGER)) return false; |
1099 | 4.26k | if (!asn1_read_implicit_Integer(data, i)) return false; |
1100 | 4.26k | return asn1_end_tag(data); |
1101 | 4.26k | } |
1102 | | |
1103 | | /* read a BIT STRING */ |
1104 | | bool asn1_read_BitString(struct asn1_data *data, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, uint8_t *padding) |
1105 | 0 | { |
1106 | 0 | int len; |
1107 | 0 | ZERO_STRUCTP(blob); |
1108 | 0 | if (!asn1_start_tag(data, ASN1_BIT_STRING)) return false; |
1109 | 0 | len = asn1_tag_remaining(data); |
1110 | 0 | if (len < 0) { |
1111 | 0 | data->has_error = true; |
1112 | 0 | return false; |
1113 | 0 | } |
1114 | 0 | if (!asn1_read_uint8(data, padding)) return false; |
1115 | | |
1116 | 0 | *blob = data_blob_talloc(mem_ctx, NULL, len+1); |
1117 | 0 | if (!blob->data || blob->length < (unsigned)len) { |
1118 | 0 | data->has_error = true; |
1119 | 0 | return false; |
1120 | 0 | } |
1121 | 0 | if (asn1_read(data, blob->data, len - 1)) { |
1122 | 0 | blob->length--; |
1123 | 0 | blob->data[len] = 0; |
1124 | 0 | asn1_end_tag(data); |
1125 | 0 | } |
1126 | |
|
1127 | 0 | if (data->has_error) { |
1128 | 0 | data_blob_free(blob); |
1129 | 0 | *padding = 0; |
1130 | 0 | return false; |
1131 | 0 | } |
1132 | 0 | return true; |
1133 | 0 | } |
1134 | | |
1135 | | /* read a non-negative enumerated value */ |
1136 | | bool asn1_read_enumerated(struct asn1_data *data, int *v) |
1137 | 1.69k | { |
1138 | 1.69k | unsigned int val_will_wrap = (0xFFU << ((sizeof(int)*8)-8)); |
1139 | 1.69k | *v = 0; |
1140 | | |
1141 | 1.69k | if (!asn1_start_tag(data, ASN1_ENUMERATED)) return false; |
1142 | 1.45M | while (!data->has_error && asn1_tag_remaining(data)>0) { |
1143 | 1.45M | uint8_t b; |
1144 | 1.45M | if (!asn1_read_uint8(data, &b)) { |
1145 | 0 | return false; |
1146 | 0 | } |
1147 | 1.45M | if (*v & val_will_wrap) { |
1148 | | /* |
1149 | | * There is something already in |
1150 | | * the top byte of the int. If we |
1151 | | * shift left by 8 it's going to |
1152 | | * wrap. Prevent this. |
1153 | | */ |
1154 | 37 | data->has_error = true; |
1155 | 37 | return false; |
1156 | 37 | } |
1157 | | /* |
1158 | | * To please/fool the Undefined Behaviour Sanitizer we cast to |
1159 | | * unsigned for the left shift. |
1160 | | */ |
1161 | 1.45M | *v = ((unsigned int)*v << 8) + b; |
1162 | 1.45M | if (*v < 0) { |
1163 | | /* ASN1_ENUMERATED can't be -ve. */ |
1164 | 63 | data->has_error = true; |
1165 | 63 | return false; |
1166 | 63 | } |
1167 | 1.45M | } |
1168 | 1.49k | return asn1_end_tag(data); |
1169 | 1.59k | } |
1170 | | |
1171 | | /* write an enumerated value to the stream */ |
1172 | | bool asn1_write_enumerated(struct asn1_data *data, uint8_t v) |
1173 | 0 | { |
1174 | 0 | bool ok = !asn1_has_error(data); |
1175 | 0 | ok = ok && asn1_push_tag(data, ASN1_ENUMERATED); |
1176 | 0 | ok = ok && asn1_write_uint8(data, v); |
1177 | 0 | ok = ok && asn1_pop_tag(data); |
1178 | 0 | return ok; |
1179 | 0 | } |
1180 | | |
1181 | | /* |
1182 | | Get us the data just written without copying |
1183 | | */ |
1184 | | bool asn1_blob(const struct asn1_data *asn1, DATA_BLOB *blob) |
1185 | 0 | { |
1186 | 0 | if (asn1->has_error) { |
1187 | 0 | return false; |
1188 | 0 | } |
1189 | 0 | if (asn1->nesting != NULL) { |
1190 | 0 | return false; |
1191 | 0 | } |
1192 | 0 | blob->data = asn1->data; |
1193 | 0 | blob->length = asn1->length; |
1194 | 0 | return true; |
1195 | 0 | } |
1196 | | |
1197 | | bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx, |
1198 | | DATA_BLOB *pblob) |
1199 | 0 | { |
1200 | 0 | DATA_BLOB blob; |
1201 | |
|
1202 | 0 | if (!asn1_blob(asn1, &blob)) { |
1203 | 0 | return false; |
1204 | 0 | } |
1205 | | |
1206 | 0 | *pblob = (DATA_BLOB){ |
1207 | 0 | .length = blob.length, |
1208 | 0 | .data = talloc_move(mem_ctx, &blob.data), |
1209 | 0 | }; |
1210 | | |
1211 | | /* |
1212 | | * Stop access from here on |
1213 | | */ |
1214 | 0 | asn1->has_error = true; |
1215 | |
|
1216 | 0 | return true; |
1217 | 0 | } |
1218 | | |
1219 | | /* |
1220 | | Fill in an asn1 struct without making a copy |
1221 | | */ |
1222 | | void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len) |
1223 | 2.97k | { |
1224 | | /* |
1225 | | * Save max_depth |
1226 | | */ |
1227 | 2.97k | unsigned max_depth = data->max_depth; |
1228 | | |
1229 | 2.97k | *data = (struct asn1_data) { |
1230 | 2.97k | .data = buf, |
1231 | 2.97k | .length = len, |
1232 | 2.97k | .max_depth = max_depth, |
1233 | 2.97k | }; |
1234 | 2.97k | } |
1235 | | |
1236 | | int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size) |
1237 | 0 | { |
1238 | 0 | struct asn1_data asn1 = {}; |
1239 | 0 | size_t size; |
1240 | 0 | bool ok; |
1241 | |
|
1242 | 0 | asn1_load_nocopy(&asn1, blob.data, blob.length); |
1243 | |
|
1244 | 0 | ok = asn1_peek_tag_needed_size(&asn1, tag, &size); |
1245 | 0 | if (!ok) { |
1246 | 0 | return EMSGSIZE; |
1247 | 0 | } |
1248 | | |
1249 | 0 | if (size > blob.length) { |
1250 | 0 | *packet_size = size; |
1251 | 0 | return EAGAIN; |
1252 | 0 | } |
1253 | | |
1254 | 0 | *packet_size = size; |
1255 | 0 | return 0; |
1256 | 0 | } |
1257 | | |
1258 | | /* |
1259 | | * Get the length of the ASN.1 data |
1260 | | */ |
1261 | 694 | size_t asn1_get_length(const struct asn1_data *asn1) { |
1262 | 694 | return asn1->length; |
1263 | 694 | } |