2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
5 #include <asn_internal.h>
7 #include <OBJECT_IDENTIFIER.h>
8 #include <asn_codecs_prim.h>
9 #include <limits.h> /* for CHAR_BIT */
14 * OBJECT IDENTIFIER basic type description.
16 static const ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = {
17 (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
19 asn_TYPE_operation_t asn_OP_OBJECT_IDENTIFIER = {
20 ASN__PRIMITIVE_TYPE_free,
21 #if !defined(ASN_DISABLE_PRINT_SUPPORT)
22 OBJECT_IDENTIFIER_print,
25 #endif /* !defined(ASN_DISABLE_PRINT_SUPPORT) */
26 OCTET_STRING_compare, /* Implemented in terms of a string comparison */
27 #if !defined(ASN_DISABLE_BER_SUPPORT)
33 #endif /* !defined(ASN_DISABLE_BER_SUPPORT) */
34 #if !defined(ASN_DISABLE_XER_SUPPORT)
35 OBJECT_IDENTIFIER_decode_xer,
36 OBJECT_IDENTIFIER_encode_xer,
40 #endif /* !defined(ASN_DISABLE_XER_SUPPORT) */
41 #if !defined(ASN_DISABLE_JER_SUPPORT)
42 OBJECT_IDENTIFIER_encode_jer,
45 #endif /* !defined(ASN_DISABLE_JER_SUPPORT) */
46 #if !defined(ASN_DISABLE_OER_SUPPORT)
47 OBJECT_IDENTIFIER_decode_oer,
48 OBJECT_IDENTIFIER_encode_oer,
52 #endif /* !defined(ASN_DISABLE_OER_SUPPORT) */
53 #if !defined(ASN_DISABLE_UPER_SUPPORT)
54 OCTET_STRING_decode_uper,
55 OCTET_STRING_encode_uper,
59 #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) */
60 #if !defined(ASN_DISABLE_APER_SUPPORT)
61 OCTET_STRING_decode_aper,
62 OCTET_STRING_encode_aper,
66 #endif /* !defined(ASN_DISABLE_APER_SUPPORT) */
67 #if !defined(ASN_DISABLE_RFILL_SUPPORT)
68 OBJECT_IDENTIFIER_random_fill,
71 #endif /* !defined(ASN_DISABLE_RFILL_SUPPORT) */
72 0 /* Use generic outmost tag fetcher */
74 asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
77 &asn_OP_OBJECT_IDENTIFIER,
78 asn_DEF_OBJECT_IDENTIFIER_tags,
79 sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
80 / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags[0]),
81 asn_DEF_OBJECT_IDENTIFIER_tags, /* Same as above */
82 sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
83 / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags[0]),
85 #if !defined(ASN_DISABLE_OER_SUPPORT)
87 #endif /* !defined(ASN_DISABLE_OER_SUPPORT) */
88 #if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT)
90 #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */
91 OBJECT_IDENTIFIER_constraint
93 0, 0, /* No members */
98 OBJECT_IDENTIFIER_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
99 asn_app_constraint_failed_f *ctfailcb,
101 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
105 ASN__CTFAIL(app_key, td, sptr,
106 "%s: at least one numerical value "
108 td->name, __FILE__, __LINE__);
112 ASN__CTFAIL(app_key, td, sptr,
113 "%s: value not given (%s:%d)",
114 td->name, __FILE__, __LINE__);
122 OBJECT_IDENTIFIER_get_first_arcs(const uint8_t *arcbuf, size_t arcbuf_len,
123 asn_oid_arc_t *arc0, asn_oid_arc_t *arc1) {
126 ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(arcbuf, arcbuf_len, &value);
127 if(rd <= 0) return rd;
132 } else if(value >= 40) {
144 OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, size_t arcbuf_len,
145 asn_oid_arc_t *ret_value) {
146 const uint8_t *b = arcbuf;
147 const uint8_t *arcend = arcbuf + arcbuf_len; /* End of arc */
149 if(arcbuf == arcend) {
153 asn_oid_arc_t upper_limit = (ASN_OID_ARC_MAX >> 7);
154 /* When the value reaches "upper_limit", it can take */
155 /* at most one more digit. If it exceeds "upper_limit" */
156 /* but there are more digits - it's an Overflow condition */
157 /* Gather all bits into the accumulator */
158 for(accum = 0; b < arcend; b++) {
159 accum = (accum << 7) | (*b & ~0x80);
160 if((*b & 0x80) == 0) { // no more digits
161 if(accum <= ASN_OID_ARC_MAX) {
163 return 1 + (b - arcbuf);
165 errno = ERANGE; /* Overflow */
168 } else { // to make sure we aren't wrapping around
169 if(accum > upper_limit) {
170 errno = ERANGE; /* Overflow */
182 OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st,
183 asn_app_consume_bytes_f *cb, void *app_key) {
185 asn_oid_arc_t arc0 = 0;
186 asn_oid_arc_t arc1 = 0;
192 rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
197 ret = snprintf(scratch, sizeof(scratch), "%"PRIu32".%"PRIu32, arc0, arc1);
198 if(ret >= (ssize_t)sizeof(scratch)) {
202 if(cb(scratch, ret, app_key) < 0)
207 rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
216 assert(off <= st->size);
217 ret = snprintf(scratch, sizeof(scratch), ".%" PRIu32, arc);
218 if(ret >= (ssize_t)sizeof(scratch)) {
222 if(cb(scratch, ret, app_key) < 0) return -1;
226 if(off != st->size) {
227 ASN_DEBUG("Could not scan to the end of Object Identifier");
235 OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *st, asn_oid_arc_t *arcs,
237 asn_oid_arc_t arc0 = 0;
238 asn_oid_arc_t arc1 = 0;
243 if(!st || !st->buf) {
248 rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
267 rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
276 if(num_arcs < arc_slots) {
277 arcs[num_arcs] = arc;
283 if(off != st->size) {
292 * Save the single value as an object identifier arc.
295 OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, size_t arcbuf_len,
296 asn_oid_arc_t value) {
298 * The following conditions must hold:
301 uint8_t scratch[((sizeof(value) * CHAR_BIT + 6) / 7)];
302 uint8_t *scratch_end = &scratch[sizeof(scratch)-1];
307 for(b = scratch_end, mask = 0; ; mask = 0x80, b--) {
308 *b = mask | (value & 0x7f);
315 result_len = (scratch_end - b) + 1;
317 if(result_len > arcbuf_len) {
321 memcpy(arcbuf, b, result_len);
327 OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *st, const asn_oid_arc_t *arcs,
337 if(!st || !arcs || arc_slots < 2) {
347 /* 8.19.4: At most 39 subsequent values (including 0) */
351 } else if(arc0 == 2) {
352 if(arc1 > ASN_OID_ARC_MAX - 80) {
356 } else if(arc0 > 2) {
357 /* 8.19.4: Only three values are allocated from the root node */
363 * After above tests it is known that the value of arc0 is completely
364 * trustworthy (0..2). However, the arc1's value is still meaningless.
368 * Roughly estimate the maximum size necessary to encode these arcs.
369 * This estimation implicitly takes in account the following facts,
370 * that cancel each other:
371 * * the first two arcs are encoded in a single value.
372 * * the first value may require more space (+1 byte)
373 * * the value of the first arc which is in range (0..2)
375 size = ((sizeof(asn_oid_arc_t) * CHAR_BIT + 6) / 7) * arc_slots;
376 bp = buf = (uint8_t *)MALLOC(size + 1);
382 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arc0 * 40 + arc1);
387 assert((size_t)wrote <= size);
391 for(i = 2; i < arc_slots; i++) {
392 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arcs[i]);
397 assert((size_t)wrote <= size);
408 st->buf[st->size] = '\0';
415 OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
416 asn_oid_arc_t *arcs, size_t arcs_count,
417 const char **opt_oid_text_end) {
423 ST_AFTERVALUE, /* Next character ought to be '.' or a space */
424 ST_WAITDIGITS /* Next character is expected to be a digit */
425 } state = ST_LEADSPACE;
427 if(!oid_text || oid_txt_length < -1 || (arcs_count && !arcs)) {
428 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
433 if(oid_txt_length == -1)
434 oid_txt_length = strlen(oid_text);
436 #define _OID_CAPTURE_ARC(oid_text, oid_end) \
438 const char *endp = oid_end; \
439 unsigned long value; \
440 switch(asn_strtoul_lim(oid_text, &endp, &value)) { \
441 case ASN_STRTOX_EXTRA_DATA: \
442 case ASN_STRTOX_OK: \
443 if(value <= ASN_OID_ARC_MAX) { \
444 if(num_arcs < arcs_count) arcs[num_arcs] = value; \
446 oid_text = endp - 1; \
450 case ASN_STRTOX_ERROR_RANGE: \
451 if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
454 case ASN_STRTOX_ERROR_INVAL: \
455 case ASN_STRTOX_EXPECT_MORE: \
456 if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
462 for(oid_end = oid_text + oid_txt_length; oid_text<oid_end; oid_text++) {
464 case 0x09: case 0x0a: case 0x0d: case 0x20: /* whitespace */
470 state = ST_TAILSPACE;
473 break; /* Digits expected after ".", got whitespace */
482 *opt_oid_text_end = oid_text;
483 errno = EINVAL; /* Broken OID */
487 state = ST_WAITDIGITS;
491 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
492 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
497 *opt_oid_text_end = oid_text;
498 errno = EINVAL; /* "1. 1" => broken OID */
502 _OID_CAPTURE_ARC(oid_text, oid_end);
503 state = ST_AFTERVALUE;
508 /* Unexpected symbols */
509 state = ST_WAITDIGITS;
516 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
518 /* Finalize last arc */
521 return 0; /* No OID found in input data */
523 errno = EINVAL; /* Broken OID */
530 errno = EINVAL; /* Broken OID */