blob: 44a3b1755d2f628c9207d14574f357d58039dc34 [file] [log] [blame]
Harry Tran1f1098a2020-03-10 10:40:10 -04001/*****************************************************************************
2# *
3# Copyright 2019 AT&T Intellectual Property *
4# *
5# Licensed under the Apache License, Version 2.0 (the "License"); *
6# you may not use this file except in compliance with the License. *
7# You may obtain a copy of the License at *
8# *
9# http://www.apache.org/licenses/LICENSE-2.0 *
10# *
11# Unless required by applicable law or agreed to in writing, software *
12# distributed under the License is distributed on an "AS IS" BASIS, *
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
14# See the License for the specific language governing permissions and *
15# limitations under the License. *
16# *
17******************************************************************************/
18
19/*-
20 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
21 * Redistribution and modifications are permitted subject to BSD license.
22 */
23#include <asn_internal.h>
24#include <INTEGER.h>
25#include <OBJECT_IDENTIFIER.h>
26#include <OCTET_STRING.h>
27#include <limits.h> /* for CHAR_BIT */
28#include <errno.h>
29
30/*
31 * OBJECT IDENTIFIER basic type description.
32 */
33static const ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = {
34 (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
35};
36asn_TYPE_operation_t asn_OP_OBJECT_IDENTIFIER = {
37 ASN__PRIMITIVE_TYPE_free,
38 OBJECT_IDENTIFIER_print,
39 OCTET_STRING_compare, /* Implemented in terms of a string comparison */
40 ber_decode_primitive,
41 der_encode_primitive,
42 OBJECT_IDENTIFIER_decode_xer,
43 OBJECT_IDENTIFIER_encode_xer,
44#ifdef ASN_DISABLE_OER_SUPPORT
45 0,
46 0,
47#else
48 OBJECT_IDENTIFIER_decode_oer,
49 OBJECT_IDENTIFIER_encode_oer,
50#endif /* ASN_DISABLE_OER_SUPPORT */
51#ifdef ASN_DISABLE_PER_SUPPORT
52 0,
53 0,
54 0,
55 0,
56#else
57 OCTET_STRING_decode_uper,
58 OCTET_STRING_encode_uper,
59 OCTET_STRING_decode_aper,
60 OCTET_STRING_encode_aper,
61#endif /* ASN_DISABLE_PER_SUPPORT */
62 OBJECT_IDENTIFIER_random_fill,
63 0 /* Use generic outmost tag fetcher */
64};
65asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
66 "OBJECT IDENTIFIER",
67 "OBJECT_IDENTIFIER",
68 &asn_OP_OBJECT_IDENTIFIER,
69 asn_DEF_OBJECT_IDENTIFIER_tags,
70 sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
71 / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags[0]),
72 asn_DEF_OBJECT_IDENTIFIER_tags, /* Same as above */
73 sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
74 / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags[0]),
75 { 0, 0, OBJECT_IDENTIFIER_constraint },
76 0, 0, /* No members */
77 0 /* No specifics */
78};
79
80int
81OBJECT_IDENTIFIER_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
82 asn_app_constraint_failed_f *ctfailcb,
83 void *app_key) {
84 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
85
86 if(st && st->buf) {
87 if(st->size < 1) {
88 ASN__CTFAIL(app_key, td, sptr,
89 "%s: at least one numerical value "
90 "expected (%s:%d)",
91 td->name, __FILE__, __LINE__);
92 return -1;
93 }
94 } else {
95 ASN__CTFAIL(app_key, td, sptr,
96 "%s: value not given (%s:%d)",
97 td->name, __FILE__, __LINE__);
98 return -1;
99 }
100
101 return 0;
102}
103
104static ssize_t
105OBJECT_IDENTIFIER_get_first_arcs(const uint8_t *arcbuf, size_t arcbuf_len,
106 asn_oid_arc_t *arc0, asn_oid_arc_t *arc1) {
107 asn_oid_arc_t value;
108
109 ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(arcbuf, arcbuf_len, &value);
110 if(rd <= 0) return rd;
111
112 if(value >= 80) {
113 *arc0 = 2;
114 *arc1 = value - 80;
115 } else if(value >= 40) {
116 *arc0 = 1;
117 *arc1 = value - 40;
118 } else {
119 *arc0 = 0;
120 *arc1 = value;
121 }
122
123 return rd;
124}
125
126ssize_t
127OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, size_t arcbuf_len,
128 asn_oid_arc_t *ret_value) {
129 const uint8_t *b = arcbuf;
130 const uint8_t *arcend = arcbuf + arcbuf_len; /* End of arc */
131
132 if(arcbuf == arcend) {
133 return 0;
134 } else {
135 asn_oid_arc_t accum;
136 asn_oid_arc_t upper_limit = (ASN_OID_ARC_MAX >> 7);
137 /* When the value reaches "upper_limit", it can take */
138 /* at most one more digit. If it exceeds "upper_limit" */
139 /* but there are more digits - it's an Overflow condition */
140 /* Gather all bits into the accumulator */
141 for(accum = 0; b < arcend; b++) {
142 accum = (accum << 7) | (*b & ~0x80);
143 if((*b & 0x80) == 0) { // no more digits
144 if(accum <= ASN_OID_ARC_MAX) {
145 *ret_value = accum;
146 return 1 + (b - arcbuf);
147 } else {
148 errno = ERANGE; /* Overflow */
149 return -1;
150 }
151 } else { // to make sure we aren't wrapping around
152 if(accum > upper_limit) {
153 errno = ERANGE; /* Overflow */
154 return -1;
155 }
156 }
157 }
158 errno = EINVAL;
159 return -1;
160 }
161
162}
163
164static ssize_t
165OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st,
166 asn_app_consume_bytes_f *cb, void *app_key) {
167 char scratch[32];
168 asn_oid_arc_t arc0, arc1;
169 size_t produced = 0;
170 size_t off = 0;
171 ssize_t rd;
172 int ret;
173
174 rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
175 if(rd <= 0) {
176 return -1;
177 }
178
179 ret = snprintf(scratch, sizeof(scratch), "%"PRIu32".%"PRIu32, arc0, arc1);
180 if(ret >= (ssize_t)sizeof(scratch)) {
181 return -1;
182 }
183 produced += ret;
184 if(cb(scratch, ret, app_key) < 0)
185 return -1;
186
187 for(off = rd; ; ) {
188 asn_oid_arc_t arc;
189 rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
190 &arc);
191 if(rd < 0) {
192 return -1;
193 } else if(rd == 0) {
194 /* No more arcs. */
195 break;
196 } else {
197 off += rd;
198 assert(off <= st->size);
199 ret = snprintf(scratch, sizeof(scratch), ".%" PRIu32, arc);
200 if(ret >= (ssize_t)sizeof(scratch)) {
201 return -1;
202 }
203 produced += ret;
204 if(cb(scratch, ret, app_key) < 0) return -1;
205 }
206 }
207
208 if(off != st->size) {
209 ASN_DEBUG("Could not scan to the end of Object Identifier");
210 return -1;
211 }
212
213 return produced;
214}
215
216static enum xer_pbd_rval
217OBJECT_IDENTIFIER__xer_body_decode(const asn_TYPE_descriptor_t *td, void *sptr,
218 const void *chunk_buf, size_t chunk_size) {
219 OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)sptr;
220 const char *chunk_end = (const char *)chunk_buf + chunk_size;
221 const char *endptr;
222 asn_oid_arc_t s_arcs[10];
223 asn_oid_arc_t *arcs = s_arcs;
224 ssize_t num_arcs;
225 ssize_t ret;
226
227 (void)td;
228
229 num_arcs = OBJECT_IDENTIFIER_parse_arcs(
230 (const char *)chunk_buf, chunk_size, arcs,
231 sizeof(s_arcs) / sizeof(s_arcs[0]), &endptr);
232 if(num_arcs < 0) {
233 /* Expecting more than zero arcs */
234 return XPBD_BROKEN_ENCODING;
235 } else if(num_arcs == 0) {
236 return XPBD_NOT_BODY_IGNORE;
237 }
238 assert(endptr == chunk_end);
239
240 if((size_t)num_arcs > sizeof(s_arcs)/sizeof(s_arcs[0])) {
241 arcs = (asn_oid_arc_t *)MALLOC(num_arcs * sizeof(asn_oid_arc_t));
242 if(!arcs) return XPBD_SYSTEM_FAILURE;
243 ret = OBJECT_IDENTIFIER_parse_arcs((const char *)chunk_buf, chunk_size,
244 arcs, num_arcs, &endptr);
245 if(ret != num_arcs)
246 return XPBD_SYSTEM_FAILURE; /* assert?.. */
247 }
248
249 /*
250 * Convert arcs into BER representation.
251 */
252 ret = OBJECT_IDENTIFIER_set_arcs(st, arcs, num_arcs);
253 if(arcs != s_arcs) FREEMEM(arcs);
254
255 return ret ? XPBD_SYSTEM_FAILURE : XPBD_BODY_CONSUMED;
256}
257
258asn_dec_rval_t
259OBJECT_IDENTIFIER_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
260 const asn_TYPE_descriptor_t *td, void **sptr,
261 const char *opt_mname, const void *buf_ptr,
262 size_t size) {
263 return xer_decode_primitive(opt_codec_ctx, td,
264 sptr, sizeof(OBJECT_IDENTIFIER_t), opt_mname,
265 buf_ptr, size, OBJECT_IDENTIFIER__xer_body_decode);
266}
267
268asn_enc_rval_t
269OBJECT_IDENTIFIER_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
270 int ilevel, enum xer_encoder_flags_e flags,
271 asn_app_consume_bytes_f *cb, void *app_key) {
272 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
273 asn_enc_rval_t er = {0,0,0};
274
275 (void)ilevel;
276 (void)flags;
277
278 if(!st || !st->buf) {
279 ASN__ENCODE_FAILED;
280 }
281
282 er.encoded = OBJECT_IDENTIFIER__dump_body(st, cb, app_key);
283 if(er.encoded < 0) ASN__ENCODE_FAILED;
284
285 ASN__ENCODED_OK(er);
286}
287
288int
289OBJECT_IDENTIFIER_print(const asn_TYPE_descriptor_t *td, const void *sptr,
290 int ilevel, asn_app_consume_bytes_f *cb,
291 void *app_key) {
292 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
293
294 (void)td; /* Unused argument */
295 (void)ilevel; /* Unused argument */
296
297 if(!st || !st->buf)
298 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
299
300 /* Dump preamble */
301 if(cb("{ ", 2, app_key) < 0)
302 return -1;
303
304 if(OBJECT_IDENTIFIER__dump_body(st, cb, app_key) < 0) {
305 return -1;
306 }
307
308 return (cb(" }", 2, app_key) < 0) ? -1 : 0;
309}
310
311ssize_t
312OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *st, asn_oid_arc_t *arcs,
313 size_t arc_slots) {
314 asn_oid_arc_t arc0, arc1;
315 size_t num_arcs = 0;
316 size_t off;
317 ssize_t rd;
318
319 if(!st || !st->buf) {
320 errno = EINVAL;
321 return -1;
322 }
323
324 rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
325 if(rd <= 0) {
326 return -1;
327 }
328 num_arcs = 2;
329 switch(arc_slots) {
330 default:
331 case 2:
332 arcs[1] = arc1;
333 /* Fall through */
334 case 1:
335 arcs[0] = arc0;
336 /* Fall through */
337 case 0:
338 break;
339 }
340
341 for(off = rd; ; ) {
342 asn_oid_arc_t arc;
343 rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
344 &arc);
345 if(rd < 0) {
346 return -1;
347 } else if(rd == 0) {
348 /* No more arcs. */
349 break;
350 } else {
351 off += rd;
352 if(num_arcs < arc_slots) {
353 arcs[num_arcs] = arc;
354 }
355 num_arcs++;
356 }
357 }
358
359 if(off != st->size) {
360 return -1;
361 }
362
363 return num_arcs;
364}
365
366
367/*
368 * Save the single value as an object identifier arc.
369 */
370ssize_t
371OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, size_t arcbuf_len,
372 asn_oid_arc_t value) {
373 /*
374 * The following conditions must hold:
375 * assert(arcbuf);
376 */
377 uint8_t scratch[((sizeof(value) * CHAR_BIT + 6) / 7)];
378 uint8_t *scratch_end = &scratch[sizeof(scratch)-1];
379 uint8_t *b;
380 size_t result_len;
381 uint8_t mask;
382
383 for(b = scratch_end, mask = 0; ; mask = 0x80, b--) {
384 *b = mask | (value & 0x7f);
385 value >>= 7;
386 if(!value) {
387 break;
388 }
389 }
390
391 result_len = (scratch_end - b) + 1;
392
393 if(result_len > arcbuf_len) {
394 return -1;
395 }
396
397 memcpy(arcbuf, b, result_len);
398
399 return result_len;
400}
401
402int
403OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *st, const asn_oid_arc_t *arcs,
404 size_t arc_slots) {
405 uint8_t *buf;
406 uint8_t *bp;
407 ssize_t wrote;
408 asn_oid_arc_t arc0;
409 asn_oid_arc_t arc1;
410 size_t size;
411 size_t i;
412
413 if(!st || !arcs || arc_slots < 2) {
414 errno = EINVAL;
415 return -1;
416 }
417
418 arc0 = arcs[0];
419 arc1 = arcs[1];
420
421 if(arc0 <= 1) {
422 if(arc1 >= 40) {
423 /* 8.19.4: At most 39 subsequent values (including 0) */
424 errno = ERANGE;
425 return -1;
426 }
427 } else if(arc0 == 2) {
428 if(arc1 > ASN_OID_ARC_MAX - 80) {
429 errno = ERANGE;
430 return -1;
431 }
432 } else if(arc0 > 2) {
433 /* 8.19.4: Only three values are allocated from the root node */
434 errno = ERANGE;
435 return -1;
436 }
437
438 /*
439 * After above tests it is known that the value of arc0 is completely
440 * trustworthy (0..2). However, the arc1's value is still meaningless.
441 */
442
443 /*
444 * Roughly estimate the maximum size necessary to encode these arcs.
445 * This estimation implicitly takes in account the following facts,
446 * that cancel each other:
447 * * the first two arcs are encoded in a single value.
448 * * the first value may require more space (+1 byte)
449 * * the value of the first arc which is in range (0..2)
450 */
451 size = ((sizeof(asn_oid_arc_t) * CHAR_BIT + 6) / 7) * arc_slots;
452 bp = buf = (uint8_t *)MALLOC(size + 1);
453 if(!buf) {
454 /* ENOMEM */
455 return -1;
456 }
457
458 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arc0 * 40 + arc1);
459 if(wrote <= 0) {
460 FREEMEM(buf);
461 return -1;
462 }
463 assert((size_t)wrote <= size);
464 bp += wrote;
465 size -= wrote;
466
467 for(i = 2; i < arc_slots; i++) {
468 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arcs[i]);
469 if(wrote <= 0) {
470 FREEMEM(buf);
471 return -1;
472 }
473 assert((size_t)wrote <= size);
474 bp += wrote;
475 size -= wrote;
476 }
477
478 /*
479 * Replace buffer.
480 */
481 st->size = bp - buf;
482 bp = st->buf;
483 st->buf = buf;
484 st->buf[st->size] = '\0';
485 if(bp) FREEMEM(bp);
486
487 return 0;
488}
489
490ssize_t
491OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
492 asn_oid_arc_t *arcs, size_t arcs_count,
493 const char **opt_oid_text_end) {
494 size_t num_arcs = 0;
495 const char *oid_end;
496 enum {
497 ST_LEADSPACE,
498 ST_TAILSPACE,
499 ST_AFTERVALUE, /* Next character ought to be '.' or a space */
500 ST_WAITDIGITS /* Next character is expected to be a digit */
501 } state = ST_LEADSPACE;
502
503 if(!oid_text || oid_txt_length < -1 || (arcs_count && !arcs)) {
504 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
505 errno = EINVAL;
506 return -1;
507 }
508
509 if(oid_txt_length == -1)
510 oid_txt_length = strlen(oid_text);
511
512#define _OID_CAPTURE_ARC(oid_text, oid_end) \
513 do { \
514 const char *endp = oid_end; \
515 unsigned long value; \
516 switch(asn_strtoul_lim(oid_text, &endp, &value)) { \
517 case ASN_STRTOX_EXTRA_DATA: \
518 case ASN_STRTOX_OK: \
519 if(value <= ASN_OID_ARC_MAX) { \
520 if(num_arcs < arcs_count) arcs[num_arcs] = value; \
521 num_arcs++; \
522 oid_text = endp - 1; \
523 break; \
524 } \
525 /* Fall through */ \
526 case ASN_STRTOX_ERROR_RANGE: \
527 if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
528 errno = ERANGE; \
529 return -1; \
530 case ASN_STRTOX_ERROR_INVAL: \
531 case ASN_STRTOX_EXPECT_MORE: \
532 if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
533 errno = EINVAL; \
534 return -1; \
535 } \
536 } while(0)
537
538 for(oid_end = oid_text + oid_txt_length; oid_text<oid_end; oid_text++) {
539 switch(*oid_text) {
540 case 0x09: case 0x0a: case 0x0d: case 0x20: /* whitespace */
541 switch(state) {
542 case ST_LEADSPACE:
543 case ST_TAILSPACE:
544 continue;
545 case ST_AFTERVALUE:
546 state = ST_TAILSPACE;
547 continue;
548 case ST_WAITDIGITS:
549 break; /* Digits expected after ".", got whitespace */
550 }
551 break;
552 case 0x2e: /* '.' */
553 switch(state) {
554 case ST_LEADSPACE:
555 case ST_TAILSPACE:
556 case ST_WAITDIGITS:
557 if(opt_oid_text_end)
558 *opt_oid_text_end = oid_text;
559 errno = EINVAL; /* Broken OID */
560 return -1;
561 break;
562 case ST_AFTERVALUE:
563 state = ST_WAITDIGITS;
564 continue;
565 }
566 break;
567 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
568 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
569 switch(state) {
570 case ST_TAILSPACE:
571 case ST_AFTERVALUE:
572 if(opt_oid_text_end)
573 *opt_oid_text_end = oid_text;
574 errno = EINVAL; /* "1. 1" => broken OID */
575 return -1;
576 case ST_LEADSPACE:
577 case ST_WAITDIGITS:
578 _OID_CAPTURE_ARC(oid_text, oid_end);
579 state = ST_AFTERVALUE;
580 continue;
581 }
582 break;
583 default:
584 /* Unexpected symbols */
585 state = ST_WAITDIGITS;
586 break;
587 } /* switch() */
588 break;
589 } /* for() */
590
591
592 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
593
594 /* Finalize last arc */
595 switch(state) {
596 case ST_LEADSPACE:
597 return 0; /* No OID found in input data */
598 case ST_WAITDIGITS:
599 errno = EINVAL; /* Broken OID */
600 return -1;
601 case ST_AFTERVALUE:
602 case ST_TAILSPACE:
603 return num_arcs;
604 }
605
606 errno = EINVAL; /* Broken OID */
607 return -1;
608}
609
610/*
611 * Generate values from the list of interesting values, or just a random
612 * value up to the upper limit.
613 */
614static asn_oid_arc_t
615OBJECT_IDENTIFIER__biased_random_arc(asn_oid_arc_t upper_bound) {
616 const asn_oid_arc_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
617 size_t idx;
618
619 switch(asn_random_between(0, 2)) {
620 case 0:
621 idx = asn_random_between(0, sizeof(values) / sizeof(values[0]) - 1);
622 if(values[idx] < upper_bound) {
623 return values[idx];
624 }
625 /* Fall through */
626 case 1:
627 return asn_random_between(0, upper_bound);
628 case 2:
629 default:
630 return upper_bound;
631 }
632}
633
634asn_random_fill_result_t
635OBJECT_IDENTIFIER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
636 const asn_encoding_constraints_t *constraints,
637 size_t max_length) {
638 asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
639 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
640 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
641 OBJECT_IDENTIFIER_t *st;
642 asn_oid_arc_t arcs[5];
643 size_t arcs_len = asn_random_between(2, 5);
644 size_t i;
645
646 (void)constraints;
647
648 if(max_length < arcs_len) return result_skipped;
649
650 if(*sptr) {
651 st = *sptr;
652 } else {
653 st = CALLOC(1, sizeof(*st));
654 }
655
656 arcs[0] = asn_random_between(0, 2);
657 arcs[1] = OBJECT_IDENTIFIER__biased_random_arc(
658 arcs[0] <= 1 ? 39 : (ASN_OID_ARC_MAX - 80));
659 for(i = 2; i < arcs_len; i++) {
660 arcs[i] = OBJECT_IDENTIFIER__biased_random_arc(ASN_OID_ARC_MAX);
661 }
662
663 if(OBJECT_IDENTIFIER_set_arcs(st, arcs, arcs_len)) {
664 if(st != *sptr) {
665 ASN_STRUCT_FREE(*td, st);
666 }
667 return result_failed;
668 }
669
670 *sptr = st;
671
672 result_ok.length = st->size;
673 return result_ok;
674}