blob: 86fee4679eb8ff1923e6da09a492874faa138d7b [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
Lev Walkina9cc46e2004-09-22 16:06:28 +00005#include <asn_internal.h>
Lev Walkinf5927112012-09-03 00:48:45 -07006#include <INTEGER.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00007#include <OBJECT_IDENTIFIER.h>
Lev Walkin725883b2006-10-09 12:07:58 +00008#include <OCTET_STRING.h>
Lev Walkin29a044b2004-06-14 07:24:36 +00009#include <limits.h> /* for CHAR_BIT */
Lev Walkinf15320b2004-06-03 03:38:44 +000010#include <errno.h>
11
12/*
13 * OBJECT IDENTIFIER basic type description.
14 */
Wim Lewis18c2ec92014-07-29 11:30:10 -070015static const ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = {
Lev Walkinf15320b2004-06-03 03:38:44 +000016 (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
17};
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +080018asn_TYPE_operation_t asn_OP_OBJECT_IDENTIFIER = {
Lev Walkin8e8078a2004-09-26 13:10:40 +000019 ASN__PRIMITIVE_TYPE_free,
Lev Walkina9cc46e2004-09-22 16:06:28 +000020 OBJECT_IDENTIFIER_print,
Lev Walkincd2f48e2017-08-10 02:14:59 -070021 OCTET_STRING_compare, /* Implemented in terms of a string comparison */
Lev Walkin8e8078a2004-09-26 13:10:40 +000022 ber_decode_primitive,
23 der_encode_primitive,
Lev Walkin92302252004-10-23 10:16:51 +000024 OBJECT_IDENTIFIER_decode_xer,
Lev Walkina9cc46e2004-09-22 16:06:28 +000025 OBJECT_IDENTIFIER_encode_xer,
Lev Walkincc159472017-07-06 08:26:36 -070026#ifdef ASN_DISABLE_OER_SUPPORT
27 0,
28 0,
29#else
Lev Walkinb5b524b2017-10-13 03:14:03 -070030 OBJECT_IDENTIFIER_decode_oer,
31 OBJECT_IDENTIFIER_encode_oer,
Lev Walkincc159472017-07-06 08:26:36 -070032#endif /* ASN_DISABLE_OER_SUPPORT */
Lev Walkinb33425f2017-07-14 14:59:52 +040033#ifdef ASN_DISABLE_PER_SUPPORT
34 0,
35 0,
36#else
37 OCTET_STRING_decode_uper,
38 OCTET_STRING_encode_uper,
39#endif /* ASN_DISABLE_PER_SUPPORT */
Lev Walkina5972be2017-09-29 23:15:58 -070040 OBJECT_IDENTIFIER_random_fill,
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +080041 0 /* Use generic outmost tag fetcher */
42};
43asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
44 "OBJECT IDENTIFIER",
45 "OBJECT_IDENTIFIER",
46 &asn_OP_OBJECT_IDENTIFIER,
Lev Walkin5e033762004-09-29 13:26:15 +000047 asn_DEF_OBJECT_IDENTIFIER_tags,
48 sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
49 / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags[0]),
50 asn_DEF_OBJECT_IDENTIFIER_tags, /* Same as above */
51 sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
52 / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags[0]),
Lev Walkina5972be2017-09-29 23:15:58 -070053 { 0, 0, OBJECT_IDENTIFIER_constraint },
Lev Walkin449f8322004-08-20 13:23:42 +000054 0, 0, /* No members */
Lev Walkind9bd7752004-06-05 08:17:50 +000055 0 /* No specifics */
Lev Walkinf15320b2004-06-03 03:38:44 +000056};
57
58
Lev Walkinfa9a3262017-10-07 16:22:47 -070059/*
60 * Endianness check. Will be optimized out by the compiler.
61 */
62static int
63little_endian() {
64 int le_check = 1;
65 return *(char *)&le_check;
66}
67
Lev Walkinf15320b2004-06-03 03:38:44 +000068int
Lev Walkin5e033762004-09-29 13:26:15 +000069OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
Lev Walkin1eded352006-07-13 11:19:01 +000070 asn_app_constraint_failed_f *ctfailcb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +000071 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +000072
73 if(st && st->buf) {
74 if(st->size < 1) {
Lev Walkin7c1dc052016-03-14 03:08:15 -070075 ASN__CTFAIL(app_key, td, sptr,
Lev Walkin16835b62004-08-22 13:47:59 +000076 "%s: at least one numerical value "
77 "expected (%s:%d)",
78 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +000079 return -1;
80 }
81 } else {
Lev Walkin7c1dc052016-03-14 03:08:15 -070082 ASN__CTFAIL(app_key, td, sptr,
Lev Walkin16835b62004-08-22 13:47:59 +000083 "%s: value not given (%s:%d)",
84 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +000085 return -1;
86 }
87
88 return 0;
89}
90
91int
Wim Lewis14e6b162014-07-23 16:06:01 -070092OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbufp, unsigned int rvsize) {
Wim Lewis14e6b162014-07-23 16:06:01 -070093 const uint8_t *arcend = arcbuf + arclen; /* End of arc */
Lev Walkin29a044b2004-06-14 07:24:36 +000094 unsigned int cache = 0; /* No more than 14 significant bits */
Lev Walkin8e8078a2004-09-26 13:10:40 +000095 unsigned char *rvbuf = (unsigned char *)rvbufp;
96 unsigned char *rvstart = rvbuf; /* Original start of the value buffer */
Lev Walkin29a044b2004-06-14 07:24:36 +000097 int inc; /* Return value growth direction */
Lev Walkinf15320b2004-06-03 03:38:44 +000098
Lev Walkin29a044b2004-06-14 07:24:36 +000099 rvsize *= CHAR_BIT; /* bytes to bits */
100 arclen *= 7; /* bytes to bits */
101
Lev Walkin0995f352017-09-17 23:16:38 -0700102 assert(add <= 0);
103
Lev Walkin29a044b2004-06-14 07:24:36 +0000104 /*
105 * The arc has the number of bits
106 * cannot be represented using supplied return value type.
107 */
108 if(arclen > rvsize) {
109 if(arclen > (rvsize + CHAR_BIT)) {
110 errno = ERANGE; /* Overflow */
111 return -1;
112 } else {
113 /*
114 * Even if the number of bits in the arc representation
115 * is higher than the width of supplied * return value
116 * type, there is still possible to fit it when there
117 * are few unused high bits in the arc value
118 * representaion.
Lev Walkin0787ff02004-06-17 23:43:39 +0000119 *
120 * Moreover, there is a possibility that the
121 * number could actually fit the arc space, given
122 * that add is negative, but we don't handle
123 * such "temporary lack of precision" situation here.
124 * May be considered as a bug.
Lev Walkin29a044b2004-06-14 07:24:36 +0000125 */
126 uint8_t mask = (0xff << (7-(arclen - rvsize))) & 0x7f;
127 if((*arcbuf & mask)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000128 errno = ERANGE; /* Overflow */
129 return -1;
130 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000131 /* Fool the routine computing unused bits */
132 arclen -= 7;
133 cache = *arcbuf & 0x7f;
134 arcbuf++;
135 }
136 }
Lev Walkinc4c61962004-06-14 08:17:27 +0000137 /* Faster path for common size */
Lev Walkinfa9a3262017-10-07 16:22:47 -0700138 if(rvsize == (CHAR_BIT * sizeof(unsigned long))
139 && (arcend-arcbuf) <= (ssize_t)sizeof(unsigned long)) {
Lev Walkinc4c61962004-06-14 08:17:27 +0000140 unsigned long accum;
141 /* Gather all bits into the accumulator */
142 for(accum = cache; arcbuf < arcend; arcbuf++)
143 accum = (accum << 7) | (*arcbuf & ~0x80);
Lev Walkin0995f352017-09-17 23:16:38 -0700144 if(accum < (unsigned)-add
Lev Walkinfa9a3262017-10-07 16:22:47 -0700145 || accum > ULONG_MAX-(unsigned long)(-add)) {
Lev Walkinc4c61962004-06-14 08:17:27 +0000146 errno = ERANGE; /* Overflow */
147 return -1;
148 }
Lev Walkin0995f352017-09-17 23:16:38 -0700149 *(unsigned long *)(void *)rvbuf =
150 accum - (unsigned long)(-add); /* alignment OK! */
Lev Walkinc4c61962004-06-14 08:17:27 +0000151 return 0;
152 }
153
Lev Walkinfa9a3262017-10-07 16:22:47 -0700154 if(little_endian()) { /* Little endian (x86) */
Lev Walkin29a044b2004-06-14 07:24:36 +0000155 /* "Convert" to big endian */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000156 rvbuf += rvsize / CHAR_BIT - 1;
157 rvstart--;
Lev Walkin29a044b2004-06-14 07:24:36 +0000158 inc = -1; /* Descending */
Lev Walkinfa9a3262017-10-07 16:22:47 -0700159 } else {
160 inc = +1; /* Big endian */
161 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000162
Lev Walkinc4c61962004-06-14 08:17:27 +0000163 {
Lev Walkin0787ff02004-06-17 23:43:39 +0000164 int bits; /* typically no more than 3-4 bits */
Lev Walkinc4c61962004-06-14 08:17:27 +0000165
Lev Walkin29a044b2004-06-14 07:24:36 +0000166 /* Clear the high unused bits */
167 for(bits = rvsize - arclen;
168 bits > CHAR_BIT;
Lev Walkin8e8078a2004-09-26 13:10:40 +0000169 rvbuf += inc, bits -= CHAR_BIT)
170 *rvbuf = 0;
Lev Walkinc4c61962004-06-14 08:17:27 +0000171
Lev Walkin29a044b2004-06-14 07:24:36 +0000172 /* Fill the body of a value */
173 for(; arcbuf < arcend; arcbuf++) {
174 cache = (cache << 7) | (*arcbuf & 0x7f);
175 bits += 7;
176 if(bits >= CHAR_BIT) {
177 bits -= CHAR_BIT;
Lev Walkin8e8078a2004-09-26 13:10:40 +0000178 *rvbuf = (cache >> bits);
179 rvbuf += inc;
Lev Walkin29a044b2004-06-14 07:24:36 +0000180 }
181 }
182 if(bits) {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000183 *rvbuf = cache;
184 rvbuf += inc;
Lev Walkin29a044b2004-06-14 07:24:36 +0000185 }
186 }
187
188 if(add) {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000189 for(rvbuf -= inc; rvbuf != rvstart; rvbuf -= inc) {
190 int v = add + *rvbuf;
Lev Walkin74757c82016-07-02 23:02:59 -0700191 if(v & ((unsigned)~0 << CHAR_BIT)) {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000192 *rvbuf = (unsigned char)(v + (1 << CHAR_BIT));
Lev Walkin29a044b2004-06-14 07:24:36 +0000193 add = -1;
194 } else {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000195 *rvbuf = v;
Lev Walkin29a044b2004-06-14 07:24:36 +0000196 break;
197 }
198 }
199 if(rvbuf == rvstart) {
200 /* No space to carry over */
Lev Walkinf15320b2004-06-03 03:38:44 +0000201 errno = ERANGE; /* Overflow */
202 return -1;
203 }
204 }
205
Lev Walkinf15320b2004-06-03 03:38:44 +0000206 return 0;
207}
208
Lev Walkina9cc46e2004-09-22 16:06:28 +0000209ssize_t
Wim Lewis14e6b162014-07-23 16:06:01 -0700210OBJECT_IDENTIFIER__dump_arc(const uint8_t *arcbuf, int arclen, int add,
Lev Walkinf15320b2004-06-03 03:38:44 +0000211 asn_app_consume_bytes_f *cb, void *app_key) {
212 char scratch[64]; /* Conservative estimate */
213 unsigned long accum; /* Bits accumulator */
214 char *p; /* Position in the scratch buffer */
215
Lev Walkin29a044b2004-06-14 07:24:36 +0000216 if(OBJECT_IDENTIFIER_get_single_arc(arcbuf, arclen, add,
217 &accum, sizeof(accum)))
Lev Walkinf15320b2004-06-03 03:38:44 +0000218 return -1;
219
Lev Walkin3251b8e2004-08-23 09:23:02 +0000220 if(accum) {
Lev Walkina9cc46e2004-09-22 16:06:28 +0000221 ssize_t len;
222
Lev Walkin3251b8e2004-08-23 09:23:02 +0000223 /* Fill the scratch buffer in reverse. */
224 p = scratch + sizeof(scratch);
225 for(; accum; accum /= 10)
Lev Walkina9cc46e2004-09-22 16:06:28 +0000226 *(--p) = (char)(accum % 10) + 0x30; /* Put a digit */
Lev Walkinf15320b2004-06-03 03:38:44 +0000227
Lev Walkina9cc46e2004-09-22 16:06:28 +0000228 len = sizeof(scratch) - (p - scratch);
229 if(cb(p, len, app_key) < 0)
230 return -1;
231 return len;
Lev Walkin3251b8e2004-08-23 09:23:02 +0000232 } else {
233 *scratch = 0x30;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000234 if(cb(scratch, 1, app_key) < 0)
235 return -1;
236 return 1;
Lev Walkin3251b8e2004-08-23 09:23:02 +0000237 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000238}
239
240int
Wim Lewis14e6b162014-07-23 16:06:01 -0700241OBJECT_IDENTIFIER_print_arc(const uint8_t *arcbuf, int arclen, int add,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000242 asn_app_consume_bytes_f *cb, void *app_key) {
243
244 if(OBJECT_IDENTIFIER__dump_arc(arcbuf, arclen, add, cb, app_key) < 0)
245 return -1;
246
247 return 0;
248}
249
250static ssize_t
251OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
252 ssize_t wrote_len = 0;
Lev Walkin494fb702017-08-07 20:07:00 -0700253 size_t startn;
Lev Walkinf15320b2004-06-03 03:38:44 +0000254 int add = 0;
Lev Walkin494fb702017-08-07 20:07:00 -0700255 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000256
Lev Walkinf15320b2004-06-03 03:38:44 +0000257 for(i = 0, startn = 0; i < st->size; i++) {
258 uint8_t b = st->buf[i];
259 if((b & 0x80)) /* Continuation expected */
260 continue;
261
262 if(startn == 0) {
263 /*
264 * First two arcs are encoded through the backdoor.
265 */
266 if(i) {
267 add = -80;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000268 if(cb("2", 1, app_key) < 0) return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000269 } else if(b <= 39) {
270 add = 0;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000271 if(cb("0", 1, app_key) < 0) return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000272 } else if(b < 79) {
273 add = -40;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000274 if(cb("1", 1, app_key) < 0) return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000275 } else {
276 add = -80;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000277 if(cb("2", 1, app_key) < 0) return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000278 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000279 wrote_len += 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000280 }
281
Lev Walkina9cc46e2004-09-22 16:06:28 +0000282 if(cb(".", 1, app_key) < 0) /* Separate arcs */
Lev Walkinf15320b2004-06-03 03:38:44 +0000283 return -1;
284
Lev Walkina9cc46e2004-09-22 16:06:28 +0000285 add = OBJECT_IDENTIFIER__dump_arc(&st->buf[startn],
286 i - startn + 1, add, cb, app_key);
287 if(add < 0) return -1;
288 wrote_len += 1 + add;
Lev Walkinf15320b2004-06-03 03:38:44 +0000289 startn = i + 1;
290 add = 0;
291 }
292
Lev Walkina9cc46e2004-09-22 16:06:28 +0000293 return wrote_len;
294}
295
Lev Walkin0fab1a62005-03-09 22:19:25 +0000296static enum xer_pbd_rval
297OBJECT_IDENTIFIER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
Lev Walkin92302252004-10-23 10:16:51 +0000298 OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)sptr;
Lev Walkin2c34aad2005-03-10 11:50:24 +0000299 const char *chunk_end = (const char *)chunk_buf + chunk_size;
300 const char *endptr;
Lev Walkin92302252004-10-23 10:16:51 +0000301 long s_arcs[10];
302 long *arcs = s_arcs;
303 int arcs_count;
304 int ret;
305
Lev Walkine0b56e02005-02-25 12:10:27 +0000306 (void)td;
307
Lev Walkin92302252004-10-23 10:16:51 +0000308 arcs_count = OBJECT_IDENTIFIER_parse_arcs(
Lev Walkin0fab1a62005-03-09 22:19:25 +0000309 (const char *)chunk_buf, chunk_size, arcs,
310 sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr);
Lev Walkinaed43c82012-09-04 14:56:27 -0700311 if(arcs_count < 0) {
Lev Walkin0fab1a62005-03-09 22:19:25 +0000312 /* Expecting more than zero arcs */
313 return XPBD_BROKEN_ENCODING;
Lev Walkinaed43c82012-09-04 14:56:27 -0700314 } else if(arcs_count == 0) {
315 return XPBD_NOT_BODY_IGNORE;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000316 }
Lev Walkinaed43c82012-09-04 14:56:27 -0700317 assert(endptr == chunk_end);
Lev Walkin0fab1a62005-03-09 22:19:25 +0000318
319 if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) {
Lev Walkin92302252004-10-23 10:16:51 +0000320 arcs = (long *)MALLOC(arcs_count * sizeof(long));
Lev Walkin0fab1a62005-03-09 22:19:25 +0000321 if(!arcs) return XPBD_SYSTEM_FAILURE;
Lev Walkin92302252004-10-23 10:16:51 +0000322 ret = OBJECT_IDENTIFIER_parse_arcs(
323 (const char *)chunk_buf, chunk_size,
324 arcs, arcs_count, &endptr);
325 if(ret != arcs_count)
Lev Walkin0fab1a62005-03-09 22:19:25 +0000326 return XPBD_SYSTEM_FAILURE; /* assert?.. */
Lev Walkin92302252004-10-23 10:16:51 +0000327 }
328
329 /*
330 * Convert arcs into BER representation.
331 */
332 ret = OBJECT_IDENTIFIER_set_arcs(st, arcs, sizeof(*arcs), arcs_count);
Lev Walkin92302252004-10-23 10:16:51 +0000333 if(arcs != s_arcs) FREEMEM(arcs);
334
Lev Walkin2c34aad2005-03-10 11:50:24 +0000335 return ret ? XPBD_SYSTEM_FAILURE : XPBD_BODY_CONSUMED;
Lev Walkin92302252004-10-23 10:16:51 +0000336}
337
338asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700339OBJECT_IDENTIFIER_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin92302252004-10-23 10:16:51 +0000340 asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
Lev Walkin8c3b8542005-03-10 18:52:02 +0000341 const void *buf_ptr, size_t size) {
Lev Walkin92302252004-10-23 10:16:51 +0000342
343 return xer_decode_primitive(opt_codec_ctx, td,
344 sptr, sizeof(OBJECT_IDENTIFIER_t), opt_mname,
345 buf_ptr, size, OBJECT_IDENTIFIER__xer_body_decode);
346}
347
Lev Walkina9cc46e2004-09-22 16:06:28 +0000348asn_enc_rval_t
Lev Walkin5e033762004-09-29 13:26:15 +0000349OBJECT_IDENTIFIER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000350 int ilevel, enum xer_encoder_flags_e flags,
351 asn_app_consume_bytes_f *cb, void *app_key) {
352 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
353 asn_enc_rval_t er;
354
355 (void)ilevel;
356 (void)flags;
357
358 if(!st || !st->buf)
Lev Walkin7c1dc052016-03-14 03:08:15 -0700359 ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000360
361 er.encoded = OBJECT_IDENTIFIER__dump_body(st, cb, app_key);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700362 if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000363
Lev Walkin7c1dc052016-03-14 03:08:15 -0700364 ASN__ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000365}
366
367int
Lev Walkin5e033762004-09-29 13:26:15 +0000368OBJECT_IDENTIFIER_print(asn_TYPE_descriptor_t *td, const void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000369 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
370 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
371
372 (void)td; /* Unused argument */
373 (void)ilevel; /* Unused argument */
374
375 if(!st || !st->buf)
Lev Walkin8e8078a2004-09-26 13:10:40 +0000376 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000377
378 /* Dump preamble */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000379 if(cb("{ ", 2, app_key) < 0)
Lev Walkina9cc46e2004-09-22 16:06:28 +0000380 return -1;
381
382 if(OBJECT_IDENTIFIER__dump_body(st, cb, app_key) < 0)
383 return -1;
384
Lev Walkin8e8078a2004-09-26 13:10:40 +0000385 return (cb(" }", 2, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000386}
387
388int
Wim Lewis14e6b162014-07-23 16:06:01 -0700389OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *oid, void *arcs,
Lev Walkin29a044b2004-06-14 07:24:36 +0000390 unsigned int arc_type_size, unsigned int arc_slots) {
Lev Walkin4d9528c2004-08-11 08:10:13 +0000391 void *arcs_end = (char *)arcs + (arc_type_size * arc_slots);
Lev Walkin29a044b2004-06-14 07:24:36 +0000392 int num_arcs = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000393 int startn = 0;
394 int add = 0;
Lev Walkin494fb702017-08-07 20:07:00 -0700395 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000396
Lev Walkin0787ff02004-06-17 23:43:39 +0000397 if(!oid || !oid->buf || (arc_slots && arc_type_size <= 1)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000398 errno = EINVAL;
399 return -1;
400 }
401
402 for(i = 0; i < oid->size; i++) {
403 uint8_t b = oid->buf[i];
404 if((b & 0x80)) /* Continuation expected */
405 continue;
406
Lev Walkin29a044b2004-06-14 07:24:36 +0000407 if(num_arcs == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000408 /*
409 * First two arcs are encoded through the backdoor.
410 */
Lev Walkin29a044b2004-06-14 07:24:36 +0000411 int first_arc;
412 num_arcs++;
413 if(!arc_slots) { num_arcs++; continue; }
414
415 if(i) first_arc = 2;
416 else if(b <= 39) first_arc = 0;
417 else if(b < 79) first_arc = 1;
418 else first_arc = 2;
419
420 add = -40 * first_arc;
421 memset(arcs, 0, arc_type_size);
Lev Walkin4d9528c2004-08-11 08:10:13 +0000422 *(unsigned char *)((char *)arcs
Lev Walkinfa9a3262017-10-07 16:22:47 -0700423 + (little_endian()?0:(arc_type_size - 1)))
Lev Walkin29a044b2004-06-14 07:24:36 +0000424 = first_arc;
Lev Walkin4ce78ca2004-08-25 01:34:11 +0000425 arcs = ((char *)arcs) + arc_type_size;
Lev Walkinf15320b2004-06-03 03:38:44 +0000426 }
427
Lev Walkin29a044b2004-06-14 07:24:36 +0000428 /* Decode, if has space */
429 if(arcs < arcs_end) {
430 if(OBJECT_IDENTIFIER_get_single_arc(&oid->buf[startn],
431 i - startn + 1, add,
Lev Walkinfa9a3262017-10-07 16:22:47 -0700432 arcs, arc_type_size)) {
Lev Walkin29a044b2004-06-14 07:24:36 +0000433 return -1;
Lev Walkinfa9a3262017-10-07 16:22:47 -0700434 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000435 startn = i + 1;
Lev Walkin4ce78ca2004-08-25 01:34:11 +0000436 arcs = ((char *)arcs) + arc_type_size;
Lev Walkin29a044b2004-06-14 07:24:36 +0000437 add = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000438 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000439 num_arcs++;
Lev Walkinf15320b2004-06-03 03:38:44 +0000440 }
441
Lev Walkin29a044b2004-06-14 07:24:36 +0000442 return num_arcs;
Lev Walkinf15320b2004-06-03 03:38:44 +0000443}
444
Lev Walkin0787ff02004-06-17 23:43:39 +0000445
446/*
447 * Save the single value as an object identifier arc.
448 */
Lev Walkin91f5cd02004-08-11 09:10:59 +0000449int
Lev Walkinb1a15552005-12-22 21:39:44 +0000450OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, const void *arcval, unsigned int arcval_size, int prepared_order) {
Lev Walkin0787ff02004-06-17 23:43:39 +0000451 /*
452 * The following conditions must hold:
453 * assert(arcval);
454 * assert(arcval_size > 0);
Lev Walkin523de9e2006-08-18 01:34:18 +0000455 * assert(arcval_size <= 16);
Lev Walkin0787ff02004-06-17 23:43:39 +0000456 * assert(arcbuf);
457 */
Lev Walkinb1a15552005-12-22 21:39:44 +0000458 const uint8_t *tend, *tp;
Lev Walkin0787ff02004-06-17 23:43:39 +0000459 unsigned int cache;
460 uint8_t *bp = arcbuf;
461 int bits;
Lev Walkin523de9e2006-08-18 01:34:18 +0000462 uint8_t buffer[16];
Lev Walkin0787ff02004-06-17 23:43:39 +0000463
Lev Walkinfa9a3262017-10-07 16:22:47 -0700464 if(little_endian() && !prepared_order) {
Lev Walkinb1a15552005-12-22 21:39:44 +0000465 const uint8_t *a = (const unsigned char *)arcval + arcval_size - 1;
466 const uint8_t *aend = (const uint8_t *)arcval;
Lev Walkin0787ff02004-06-17 23:43:39 +0000467 uint8_t *msb = buffer + arcval_size - 1;
Lev Walkinb1a15552005-12-22 21:39:44 +0000468 uint8_t *tb;
469 for(tb = buffer; a >= aend; tb++, a--)
470 if((*tb = *a) && (tb < msb))
471 msb = tb;
Lev Walkin0787ff02004-06-17 23:43:39 +0000472 tend = &buffer[arcval_size];
473 tp = msb; /* Most significant non-zero byte */
474 } else {
475 /* Look for most significant non-zero byte */
Lev Walkinb1a15552005-12-22 21:39:44 +0000476 tend = (const unsigned char *)arcval + arcval_size;
477 for(tp = (const uint8_t *)arcval; tp < tend - 1; tp++)
Lev Walkin0787ff02004-06-17 23:43:39 +0000478 if(*tp) break;
479 }
480
481 /*
482 * Split the value in 7-bits chunks.
483 */
484 bits = ((tend - tp) * CHAR_BIT) % 7;
485 if(bits) {
486 cache = *tp >> (CHAR_BIT - bits);
487 if(cache) {
488 *bp++ = cache | 0x80;
489 cache = *tp++;
490 bits = CHAR_BIT - bits;
491 } else {
492 bits = -bits;
493 }
494 } else {
495 cache = 0;
496 }
497 for(; tp < tend; tp++) {
498 cache = (cache << CHAR_BIT) + *tp;
499 bits += CHAR_BIT;
500 while(bits >= 7) {
501 bits -= 7;
502 *bp++ = 0x80 | (cache >> bits);
503 }
504 }
505 if(bits) *bp++ = cache;
506 bp[-1] &= 0x7f; /* Clear the last bit */
507
508 return bp - arcbuf;
509}
510
Lev Walkinf15320b2004-06-03 03:38:44 +0000511int
Lev Walkinb1a15552005-12-22 21:39:44 +0000512OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *oid, const void *arcs, unsigned int arc_type_size, unsigned int arc_slots) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000513 uint8_t *buf;
514 uint8_t *bp;
Lev Walkin0787ff02004-06-17 23:43:39 +0000515 unsigned int arc0;
516 unsigned int arc1;
517 unsigned size;
Lev Walkinc4c61962004-06-14 08:17:27 +0000518 unsigned i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000519
Lev Walkin523de9e2006-08-18 01:34:18 +0000520 if(!oid || !arcs || arc_type_size < 1
521 || arc_type_size > 16
522 || arc_slots < 2) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000523 errno = EINVAL;
524 return -1;
525 }
526
Lev Walkin0787ff02004-06-17 23:43:39 +0000527 switch(arc_type_size) {
528 case sizeof(char):
Lev Walkinb1a15552005-12-22 21:39:44 +0000529 arc0 = ((const unsigned char *)arcs)[0];
530 arc1 = ((const unsigned char *)arcs)[1];
Lev Walkin0787ff02004-06-17 23:43:39 +0000531 break;
532 case sizeof(short):
Lev Walkinb1a15552005-12-22 21:39:44 +0000533 arc0 = ((const unsigned short *)arcs)[0];
534 arc1 = ((const unsigned short *)arcs)[1];
Lev Walkin0787ff02004-06-17 23:43:39 +0000535 break;
536 case sizeof(int):
Lev Walkinb1a15552005-12-22 21:39:44 +0000537 arc0 = ((const unsigned int *)arcs)[0];
538 arc1 = ((const unsigned int *)arcs)[1];
Lev Walkin0787ff02004-06-17 23:43:39 +0000539 break;
540 default:
541 arc1 = arc0 = 0;
Lev Walkinfa9a3262017-10-07 16:22:47 -0700542 if(little_endian()) { /* Little endian (x86) */
Lev Walkinb1a15552005-12-22 21:39:44 +0000543 const unsigned char *ps, *pe;
Lev Walkin0787ff02004-06-17 23:43:39 +0000544 /* If more significant bytes are present,
545 * make them > 255 quick */
Lev Walkinb1a15552005-12-22 21:39:44 +0000546 for(ps = (const unsigned char *)arcs + 1, pe = ps+arc_type_size;
Lev Walkin4d9528c2004-08-11 08:10:13 +0000547 ps < pe; ps++)
Lev Walkin0787ff02004-06-17 23:43:39 +0000548 arc0 |= *ps, arc1 |= *(ps + arc_type_size);
549 arc0 <<= CHAR_BIT, arc1 <<= CHAR_BIT;
Lev Walkinb1a15552005-12-22 21:39:44 +0000550 arc0 = *((const unsigned char *)arcs + 0);
551 arc1 = *((const unsigned char *)arcs + arc_type_size);
Lev Walkin0787ff02004-06-17 23:43:39 +0000552 } else {
Lev Walkinb1a15552005-12-22 21:39:44 +0000553 const unsigned char *ps, *pe;
Lev Walkin0787ff02004-06-17 23:43:39 +0000554 /* If more significant bytes are present,
555 * make them > 255 quick */
Lev Walkinb1a15552005-12-22 21:39:44 +0000556 for(ps = (const unsigned char *)arcs, pe = ps+arc_type_size - 1; ps < pe; ps++)
Lev Walkin0787ff02004-06-17 23:43:39 +0000557 arc0 |= *ps, arc1 |= *(ps + arc_type_size);
Lev Walkinb1a15552005-12-22 21:39:44 +0000558 arc0 = *((const unsigned char *)arcs + arc_type_size - 1);
559 arc1 = *((const unsigned char *)arcs +(arc_type_size<< 1)-1);
Lev Walkin0787ff02004-06-17 23:43:39 +0000560 }
561 }
562
563 /*
564 * The previous chapter left us with the first and the second arcs.
565 * The values are not precise (that is, they are valid only if
566 * they're less than 255), but OK for the purposes of making
567 * the sanity test below.
568 */
569 if(arc0 <= 1) {
570 if(arc1 >= 39) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000571 /* 8.19.4: At most 39 subsequent values (including 0) */
572 errno = ERANGE;
573 return -1;
574 }
Lev Walkin0787ff02004-06-17 23:43:39 +0000575 } else if(arc0 > 2) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000576 /* 8.19.4: Only three values are allocated from the root node */
577 errno = ERANGE;
578 return -1;
579 }
Lev Walkin0787ff02004-06-17 23:43:39 +0000580 /*
581 * After above tests it is known that the value of arc0 is completely
582 * trustworthy (0..2). However, the arc1's value is still meaningless.
583 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000584
585 /*
586 * Roughly estimate the maximum size necessary to encode these arcs.
Lev Walkin0787ff02004-06-17 23:43:39 +0000587 * This estimation implicitly takes in account the following facts,
588 * that cancel each other:
589 * * the first two arcs are encoded in a single value.
590 * * the first value may require more space (+1 byte)
591 * * the value of the first arc which is in range (0..2)
Lev Walkinf15320b2004-06-03 03:38:44 +0000592 */
Lev Walkin0787ff02004-06-17 23:43:39 +0000593 size = ((arc_type_size * CHAR_BIT + 6) / 7) * arc_slots;
Lev Walkinc2346572004-08-11 09:07:36 +0000594 bp = buf = (uint8_t *)MALLOC(size + 1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000595 if(!buf) {
596 /* ENOMEM */
597 return -1;
598 }
599
600 /*
Lev Walkin0787ff02004-06-17 23:43:39 +0000601 * Encode the first two arcs.
602 * These require special treatment.
Lev Walkinf15320b2004-06-03 03:38:44 +0000603 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000604 {
Lev Walkin0787ff02004-06-17 23:43:39 +0000605 uint8_t *tp;
Lev Walkin523de9e2006-08-18 01:34:18 +0000606 uint8_t first_value[1 + 16]; /* of two arcs */
Lev Walkin4d9528c2004-08-11 08:10:13 +0000607 uint8_t *fv = first_value;
Lev Walkinf15320b2004-06-03 03:38:44 +0000608
Lev Walkin0787ff02004-06-17 23:43:39 +0000609 /*
610 * Simulate first_value = arc0 * 40 + arc1;
611 */
612 /* Copy the second (1'st) arcs[1] into the first_value */
613 *fv++ = 0;
Lev Walkinb1a15552005-12-22 21:39:44 +0000614 arcs = ((const char *)arcs) + arc_type_size;
Lev Walkinfa9a3262017-10-07 16:22:47 -0700615 if(little_endian()) {
Lev Walkinb1a15552005-12-22 21:39:44 +0000616 const uint8_t *aend = (const unsigned char *)arcs - 1;
617 const uint8_t *a1 = (const unsigned char *)arcs + arc_type_size - 1;
Lev Walkin0787ff02004-06-17 23:43:39 +0000618 for(; a1 > aend; fv++, a1--) *fv = *a1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000619 } else {
Lev Walkinb1a15552005-12-22 21:39:44 +0000620 const uint8_t *a1 = (const uint8_t *)arcs;
621 const uint8_t *aend = a1 + arc_type_size;
Lev Walkin0787ff02004-06-17 23:43:39 +0000622 for(; a1 < aend; fv++, a1++) *fv = *a1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000623 }
Lev Walkin0787ff02004-06-17 23:43:39 +0000624 /* Increase the first_value by arc0 */
625 arc0 *= 40; /* (0..80) */
626 for(tp = first_value + arc_type_size; tp >= first_value; tp--) {
627 unsigned int v = *tp;
628 v += arc0;
629 *tp = v;
630 if(v >= (1 << CHAR_BIT)) arc0 = v >> CHAR_BIT;
631 else break;
632 }
633
634 assert(tp >= first_value);
635
636 bp += OBJECT_IDENTIFIER_set_single_arc(bp, first_value,
637 fv - first_value, 1);
638 }
639
640 /*
641 * Save the rest of arcs.
642 */
Lev Walkinb1a15552005-12-22 21:39:44 +0000643 for(arcs = ((const char *)arcs) + arc_type_size, i = 2;
Lev Walkin4ce78ca2004-08-25 01:34:11 +0000644 i < arc_slots;
Lev Walkinb1a15552005-12-22 21:39:44 +0000645 i++, arcs = ((const char *)arcs) + arc_type_size) {
Lev Walkin0787ff02004-06-17 23:43:39 +0000646 bp += OBJECT_IDENTIFIER_set_single_arc(bp,
647 arcs, arc_type_size, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000648 }
649
Lev Walkin34b2a932004-06-17 23:46:45 +0000650 assert((unsigned)(bp - buf) <= size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000651
652 /*
653 * Replace buffer.
654 */
Lev Walkin0787ff02004-06-17 23:43:39 +0000655 oid->size = bp - buf;
Lev Walkinf15320b2004-06-03 03:38:44 +0000656 bp = oid->buf;
657 oid->buf = buf;
658 if(bp) FREEMEM(bp);
659
660 return 0;
661}
Lev Walkinc4c61962004-06-14 08:17:27 +0000662
Lev Walkin92302252004-10-23 10:16:51 +0000663
664int
665OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
Lev Walkin093ba2e2005-04-04 21:10:06 +0000666 long *arcs, unsigned int arcs_slots, const char **opt_oid_text_end) {
Lev Walkin92302252004-10-23 10:16:51 +0000667 unsigned int arcs_count = 0;
668 const char *oid_end;
Lev Walkin92302252004-10-23 10:16:51 +0000669 enum {
Lev Walkinf5927112012-09-03 00:48:45 -0700670 ST_LEADSPACE,
671 ST_TAILSPACE,
Lev Walkincad560a2013-03-16 07:00:58 -0700672 ST_AFTERVALUE, /* Next character ought to be '.' or a space */
Lev Walkin104af192016-01-24 22:13:27 -0800673 ST_WAITDIGITS /* Next character is expected to be a digit */
Lev Walkinf5927112012-09-03 00:48:45 -0700674 } state = ST_LEADSPACE;
Lev Walkin92302252004-10-23 10:16:51 +0000675
676 if(!oid_text || oid_txt_length < -1 || (arcs_slots && !arcs)) {
Lev Walkin093ba2e2005-04-04 21:10:06 +0000677 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
Lev Walkin92302252004-10-23 10:16:51 +0000678 errno = EINVAL;
679 return -1;
680 }
681
682 if(oid_txt_length == -1)
683 oid_txt_length = strlen(oid_text);
684
Lev Walkincad560a2013-03-16 07:00:58 -0700685#define _OID_CAPTURE_ARC(oid_text, oid_end) do { \
686 const char *endp = oid_end; \
Lev Walkinf5927112012-09-03 00:48:45 -0700687 long value; \
Lev Walkincad560a2013-03-16 07:00:58 -0700688 switch(asn_strtol_lim(oid_text, &endp, &value)) { \
Lev Walkin72ec9092017-07-05 05:49:12 -0700689 case ASN_STRTOX_EXTRA_DATA: \
690 case ASN_STRTOX_OK: \
Lev Walkinf5927112012-09-03 00:48:45 -0700691 if(arcs_count < arcs_slots) \
692 arcs[arcs_count] = value; \
693 arcs_count++; \
Lev Walkincad560a2013-03-16 07:00:58 -0700694 oid_text = endp - 1; \
Lev Walkinf5927112012-09-03 00:48:45 -0700695 break; \
Lev Walkin72ec9092017-07-05 05:49:12 -0700696 case ASN_STRTOX_ERROR_RANGE: \
Lev Walkinf5927112012-09-03 00:48:45 -0700697 if(opt_oid_text_end) \
698 *opt_oid_text_end = oid_text; \
699 errno = ERANGE; \
700 return -1; \
Lev Walkin72ec9092017-07-05 05:49:12 -0700701 case ASN_STRTOX_ERROR_INVAL: \
702 case ASN_STRTOX_EXPECT_MORE: \
Lev Walkinf5927112012-09-03 00:48:45 -0700703 if(opt_oid_text_end) \
704 *opt_oid_text_end = oid_text; \
705 errno = EINVAL; \
706 return -1; \
707 } \
708 } while(0)
709
Lev Walkin92302252004-10-23 10:16:51 +0000710 for(oid_end = oid_text + oid_txt_length; oid_text<oid_end; oid_text++) {
711 switch(*oid_text) {
712 case 0x09: case 0x0a: case 0x0d: case 0x20: /* whitespace */
Lev Walkinf5927112012-09-03 00:48:45 -0700713 switch(state) {
714 case ST_LEADSPACE:
715 case ST_TAILSPACE:
Lev Walkin92302252004-10-23 10:16:51 +0000716 continue;
Lev Walkincad560a2013-03-16 07:00:58 -0700717 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700718 state = ST_TAILSPACE;
719 continue;
720 case ST_WAITDIGITS:
Lev Walkincad560a2013-03-16 07:00:58 -0700721 break; /* Digits expected after ".", got whitespace */
Lev Walkin92302252004-10-23 10:16:51 +0000722 }
Lev Walkincad560a2013-03-16 07:00:58 -0700723 break;
Lev Walkinf5927112012-09-03 00:48:45 -0700724 case 0x2e: /* '.' */
725 switch(state) {
726 case ST_LEADSPACE:
Lev Walkinf5927112012-09-03 00:48:45 -0700727 case ST_TAILSPACE:
Lev Walkincad560a2013-03-16 07:00:58 -0700728 case ST_WAITDIGITS:
729 if(opt_oid_text_end)
730 *opt_oid_text_end = oid_text;
731 errno = EINVAL; /* Broken OID */
732 return -1;
Lev Walkinf5927112012-09-03 00:48:45 -0700733 break;
Lev Walkincad560a2013-03-16 07:00:58 -0700734 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700735 state = ST_WAITDIGITS;
Lev Walkin92302252004-10-23 10:16:51 +0000736 continue;
737 }
Lev Walkinf5927112012-09-03 00:48:45 -0700738 break;
739 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
740 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
741 switch(state) {
742 case ST_TAILSPACE:
Lev Walkincad560a2013-03-16 07:00:58 -0700743 case ST_AFTERVALUE:
744 if(opt_oid_text_end)
745 *opt_oid_text_end = oid_text;
746 errno = EINVAL; /* "1. 1" => broken OID */
747 return -1;
Lev Walkinf5927112012-09-03 00:48:45 -0700748 case ST_LEADSPACE:
749 case ST_WAITDIGITS:
Lev Walkincad560a2013-03-16 07:00:58 -0700750 _OID_CAPTURE_ARC(oid_text, oid_end);
751 state = ST_AFTERVALUE;
Lev Walkinf5927112012-09-03 00:48:45 -0700752 continue;
753 }
754 break;
Lev Walkin92302252004-10-23 10:16:51 +0000755 default:
756 /* Unexpected symbols */
757 state = ST_WAITDIGITS;
758 break;
759 } /* switch() */
760 break;
761 } /* for() */
762
763
Lev Walkin093ba2e2005-04-04 21:10:06 +0000764 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
Lev Walkin92302252004-10-23 10:16:51 +0000765
766 /* Finalize last arc */
767 switch(state) {
Lev Walkinf5927112012-09-03 00:48:45 -0700768 case ST_LEADSPACE:
Lev Walkinaed43c82012-09-04 14:56:27 -0700769 return 0; /* No OID found in input data */
Lev Walkinaed43c82012-09-04 14:56:27 -0700770 case ST_WAITDIGITS:
771 errno = EINVAL; /* Broken OID */
772 return -1;
Lev Walkincad560a2013-03-16 07:00:58 -0700773 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700774 case ST_TAILSPACE:
Lev Walkin92302252004-10-23 10:16:51 +0000775 return arcs_count;
776 }
Lev Walkinaed43c82012-09-04 14:56:27 -0700777
778 errno = EINVAL; /* Broken OID */
779 return -1;
Lev Walkin92302252004-10-23 10:16:51 +0000780}
781
Lev Walkina5972be2017-09-29 23:15:58 -0700782/*
783 * Generate values from the list of interesting values, or just a random
784 * value up to the upper limit.
785 */
786static uint32_t
Lev Walkinb5b524b2017-10-13 03:14:03 -0700787OBJECT_IDENTIFIER__biased_random_arc(uint32_t upper_bound) {
Lev Walkina5972be2017-09-29 23:15:58 -0700788 static const uint16_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
Lev Walkinb5b524b2017-10-13 03:14:03 -0700789 size_t idx;
Lev Walkin92302252004-10-23 10:16:51 +0000790
Lev Walkinb5b524b2017-10-13 03:14:03 -0700791 switch(asn_random_between(0, 2)) {
792 case 0:
793 idx = asn_random_between(0, sizeof(values) / sizeof(values[0]) - 1);
Lev Walkina5972be2017-09-29 23:15:58 -0700794 if(values[idx] < upper_bound) {
795 return values[idx];
796 }
Lev Walkinb5b524b2017-10-13 03:14:03 -0700797 /* Fall through */
798 case 1:
799 return asn_random_between(0, upper_bound);
800 case 2:
801 default:
802 return upper_bound;
Lev Walkina5972be2017-09-29 23:15:58 -0700803 }
Lev Walkina5972be2017-09-29 23:15:58 -0700804}
805
806asn_random_fill_result_t
807OBJECT_IDENTIFIER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
808 const asn_encoding_constraints_t *constraints,
809 size_t max_length) {
810 asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
811 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
812 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
813 OBJECT_IDENTIFIER_t *st;
814 uint32_t arcs[5];
815 size_t arcs_len = asn_random_between(2, 5);
816 size_t i;
817
818 (void)constraints;
819
820 if(max_length < arcs_len) return result_skipped;
821
822 if(*sptr) {
823 st = *sptr;
824 } else {
825 st = CALLOC(1, sizeof(*st));
826 }
827
828 arcs[0] = asn_random_between(0, 2);
829 arcs[1] =
Lev Walkinb5b524b2017-10-13 03:14:03 -0700830 OBJECT_IDENTIFIER__biased_random_arc(arcs[0] <= 1 ? 39 : UINT_MAX);
Lev Walkina5972be2017-09-29 23:15:58 -0700831 for(i = 2; i < arcs_len; i++) {
Lev Walkinb5b524b2017-10-13 03:14:03 -0700832 arcs[i] = OBJECT_IDENTIFIER__biased_random_arc(UINT_MAX);
Lev Walkina5972be2017-09-29 23:15:58 -0700833 }
834
835 if(OBJECT_IDENTIFIER_set_arcs(st, arcs, sizeof(arcs[0]), arcs_len)) {
836 if(st != *sptr) {
837 ASN_STRUCT_FREE(*td, st);
838 }
839 return result_failed;
840 }
841
842 *sptr = st;
843
844 return result_ok;
845}