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