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