blob: 290545d1c2e76c60ce7b879095508909671eb6bd [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
Lev Walkinf15320b2004-06-03 03:38:44 +000058int
Lev Walkin20696a42017-10-17 21:27:33 -070059OBJECT_IDENTIFIER_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
60 asn_app_constraint_failed_f *ctfailcb,
61 void *app_key) {
62 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +000063
64 if(st && st->buf) {
65 if(st->size < 1) {
Lev Walkin7c1dc052016-03-14 03:08:15 -070066 ASN__CTFAIL(app_key, td, sptr,
Lev Walkin16835b62004-08-22 13:47:59 +000067 "%s: at least one numerical value "
68 "expected (%s:%d)",
69 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +000070 return -1;
71 }
72 } else {
Lev Walkin7c1dc052016-03-14 03:08:15 -070073 ASN__CTFAIL(app_key, td, sptr,
Lev Walkin16835b62004-08-22 13:47:59 +000074 "%s: value not given (%s:%d)",
75 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +000076 return -1;
77 }
78
79 return 0;
80}
81
Lev Walkin588bf0f2017-10-13 23:51:16 -070082static ssize_t
83OBJECT_IDENTIFIER_get_first_arcs(const uint8_t *arcbuf, size_t arcbuf_len,
84 asn_oid_arc_t *arc0, asn_oid_arc_t *arc1) {
85 asn_oid_arc_t value;
Lev Walkinf15320b2004-06-03 03:38:44 +000086
Lev Walkin588bf0f2017-10-13 23:51:16 -070087 ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(arcbuf, arcbuf_len, &value);
88 if(rd <= 0) return rd;
Lev Walkin29a044b2004-06-14 07:24:36 +000089
Lev Walkin588bf0f2017-10-13 23:51:16 -070090 if(value >= 80) {
91 *arc0 = 2;
92 *arc1 = value - 80;
93 } else if(value >= 40) {
94 *arc0 = 1;
95 *arc1 = value - 40;
96 } else {
97 *arc0 = 0;
98 *arc1 = value;
99 }
Lev Walkin0995f352017-09-17 23:16:38 -0700100
Lev Walkin588bf0f2017-10-13 23:51:16 -0700101 return rd;
Lev Walkinf15320b2004-06-03 03:38:44 +0000102}
103
Lev Walkina9cc46e2004-09-22 16:06:28 +0000104ssize_t
Lev Walkin588bf0f2017-10-13 23:51:16 -0700105OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, size_t arcbuf_len,
106 asn_oid_arc_t *ret_value) {
107 const uint8_t *b = arcbuf;
108 const uint8_t *arcend = arcbuf + arcbuf_len; /* End of arc */
Lev Walkinf15320b2004-06-03 03:38:44 +0000109
Lev Walkin588bf0f2017-10-13 23:51:16 -0700110 if(arcbuf == arcend) {
111 return 0;
112 } else {
113 asn_oid_arc_t accum;
114 /* Gather all bits into the accumulator */
115 for(accum = 0; b < arcend; b++) {
116 accum = (accum << 7) | (*b & ~0x80);
117 if((*b & 0x80) == 0) {
118 if(accum <= ASN_OID_ARC_MAX) {
119 *ret_value = accum;
120 return 1 + (b - arcbuf);
121 } else {
122 errno = ERANGE; /* Overflow */
123 return -1;
124 }
125 }
126 }
127 errno = EINVAL;
128 return -1;
129 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000130
Lev Walkina9cc46e2004-09-22 16:06:28 +0000131}
132
133static ssize_t
Lev Walkin588bf0f2017-10-13 23:51:16 -0700134OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st,
135 asn_app_consume_bytes_f *cb, void *app_key) {
136 char scratch[32];
137 asn_oid_arc_t arc0, arc1;
138 size_t produced = 0;
139 size_t off = 0;
140 ssize_t rd;
141 int ret;
Lev Walkinf15320b2004-06-03 03:38:44 +0000142
Lev Walkin588bf0f2017-10-13 23:51:16 -0700143 rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
144 if(rd <= 0) {
145 return -1;
146 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000147
Lev Walkin588bf0f2017-10-13 23:51:16 -0700148 ret = snprintf(scratch, sizeof(scratch), "%"PRIu32".%"PRIu32, arc0, arc1);
149 if(ret >= (ssize_t)sizeof(scratch)) {
150 return -1;
151 }
152 produced += ret;
153 if(cb(scratch, ret, app_key) < 0)
154 return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000155
Lev Walkin588bf0f2017-10-13 23:51:16 -0700156 for(off = rd; ; ) {
157 asn_oid_arc_t arc;
158 rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
159 &arc);
160 if(rd < 0) {
161 return -1;
162 } else if(rd == 0) {
163 /* No more arcs. */
164 break;
165 } else {
166 off += rd;
167 assert(off <= st->size);
168 ret = snprintf(scratch, sizeof(scratch), ".%" PRIu32, arc);
169 if(ret >= (ssize_t)sizeof(scratch)) {
170 return -1;
171 }
172 produced += ret;
173 if(cb(scratch, ret, app_key) < 0) return -1;
174 }
175 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000176
Lev Walkin588bf0f2017-10-13 23:51:16 -0700177 if(off != st->size) {
178 ASN_DEBUG("Could not scan to the end of Object Identifier");
179 return -1;
180 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000181
Lev Walkin588bf0f2017-10-13 23:51:16 -0700182 return produced;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000183}
184
Lev Walkin0fab1a62005-03-09 22:19:25 +0000185static enum xer_pbd_rval
Lev Walkin20696a42017-10-17 21:27:33 -0700186OBJECT_IDENTIFIER__xer_body_decode(const asn_TYPE_descriptor_t *td, void *sptr,
187 const void *chunk_buf, size_t chunk_size) {
188 OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)sptr;
Lev Walkin2c34aad2005-03-10 11:50:24 +0000189 const char *chunk_end = (const char *)chunk_buf + chunk_size;
190 const char *endptr;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700191 asn_oid_arc_t s_arcs[10];
192 asn_oid_arc_t *arcs = s_arcs;
193 ssize_t num_arcs;
194 ssize_t ret;
Lev Walkin92302252004-10-23 10:16:51 +0000195
Lev Walkine0b56e02005-02-25 12:10:27 +0000196 (void)td;
197
Lev Walkin588bf0f2017-10-13 23:51:16 -0700198 num_arcs = OBJECT_IDENTIFIER_parse_arcs(
199 (const char *)chunk_buf, chunk_size, arcs,
200 sizeof(s_arcs) / sizeof(s_arcs[0]), &endptr);
201 if(num_arcs < 0) {
Lev Walkin0fab1a62005-03-09 22:19:25 +0000202 /* Expecting more than zero arcs */
203 return XPBD_BROKEN_ENCODING;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700204 } else if(num_arcs == 0) {
Lev Walkinaed43c82012-09-04 14:56:27 -0700205 return XPBD_NOT_BODY_IGNORE;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000206 }
Lev Walkinaed43c82012-09-04 14:56:27 -0700207 assert(endptr == chunk_end);
Lev Walkin0fab1a62005-03-09 22:19:25 +0000208
Lev Walkin588bf0f2017-10-13 23:51:16 -0700209 if((size_t)num_arcs > sizeof(s_arcs)/sizeof(s_arcs[0])) {
210 arcs = (asn_oid_arc_t *)MALLOC(num_arcs * sizeof(asn_oid_arc_t));
Lev Walkin0fab1a62005-03-09 22:19:25 +0000211 if(!arcs) return XPBD_SYSTEM_FAILURE;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700212 ret = OBJECT_IDENTIFIER_parse_arcs((const char *)chunk_buf, chunk_size,
213 arcs, num_arcs, &endptr);
214 if(ret != num_arcs)
Lev Walkin0fab1a62005-03-09 22:19:25 +0000215 return XPBD_SYSTEM_FAILURE; /* assert?.. */
Lev Walkin92302252004-10-23 10:16:51 +0000216 }
217
218 /*
219 * Convert arcs into BER representation.
220 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700221 ret = OBJECT_IDENTIFIER_set_arcs(st, arcs, num_arcs);
Lev Walkin92302252004-10-23 10:16:51 +0000222 if(arcs != s_arcs) FREEMEM(arcs);
223
Lev Walkin2c34aad2005-03-10 11:50:24 +0000224 return ret ? XPBD_SYSTEM_FAILURE : XPBD_BODY_CONSUMED;
Lev Walkin92302252004-10-23 10:16:51 +0000225}
226
227asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700228OBJECT_IDENTIFIER_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin20696a42017-10-17 21:27:33 -0700229 const asn_TYPE_descriptor_t *td, void **sptr,
230 const char *opt_mname, const void *buf_ptr,
231 size_t size) {
232 return xer_decode_primitive(opt_codec_ctx, td,
Lev Walkin92302252004-10-23 10:16:51 +0000233 sptr, sizeof(OBJECT_IDENTIFIER_t), opt_mname,
234 buf_ptr, size, OBJECT_IDENTIFIER__xer_body_decode);
235}
236
Lev Walkina9cc46e2004-09-22 16:06:28 +0000237asn_enc_rval_t
Lev Walkin20696a42017-10-17 21:27:33 -0700238OBJECT_IDENTIFIER_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
239 int ilevel, enum xer_encoder_flags_e flags,
240 asn_app_consume_bytes_f *cb, void *app_key) {
241 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000242 asn_enc_rval_t er;
243
Lev Walkin588bf0f2017-10-13 23:51:16 -0700244 (void)ilevel;
245 (void)flags;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000246
Lev Walkin588bf0f2017-10-13 23:51:16 -0700247 if(!st || !st->buf) {
248 ASN__ENCODE_FAILED;
249 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000250
Lev Walkin588bf0f2017-10-13 23:51:16 -0700251 er.encoded = OBJECT_IDENTIFIER__dump_body(st, cb, app_key);
252 if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000253
Lev Walkin588bf0f2017-10-13 23:51:16 -0700254 ASN__ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000255}
256
257int
Lev Walkin20696a42017-10-17 21:27:33 -0700258OBJECT_IDENTIFIER_print(const asn_TYPE_descriptor_t *td, const void *sptr,
259 int ilevel, asn_app_consume_bytes_f *cb,
260 void *app_key) {
261 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000262
263 (void)td; /* Unused argument */
264 (void)ilevel; /* Unused argument */
265
266 if(!st || !st->buf)
Lev Walkin8e8078a2004-09-26 13:10:40 +0000267 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000268
269 /* Dump preamble */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000270 if(cb("{ ", 2, app_key) < 0)
Lev Walkina9cc46e2004-09-22 16:06:28 +0000271 return -1;
272
Lev Walkin588bf0f2017-10-13 23:51:16 -0700273 if(OBJECT_IDENTIFIER__dump_body(st, cb, app_key) < 0) {
274 return -1;
275 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000276
Lev Walkin588bf0f2017-10-13 23:51:16 -0700277 return (cb(" }", 2, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000278}
279
Lev Walkin588bf0f2017-10-13 23:51:16 -0700280ssize_t
281OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *st, asn_oid_arc_t *arcs,
282 size_t arc_slots) {
283 asn_oid_arc_t arc0, arc1;
284 size_t num_arcs = 0;
285 size_t off;
286 ssize_t rd;
Lev Walkinf15320b2004-06-03 03:38:44 +0000287
Lev Walkin588bf0f2017-10-13 23:51:16 -0700288 if(!st || !st->buf) {
289 errno = EINVAL;
290 return -1;
291 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000292
Lev Walkin588bf0f2017-10-13 23:51:16 -0700293 rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
294 if(rd <= 0) {
295 return -1;
296 }
297 num_arcs = 2;
298 switch(arc_slots) {
299 default:
300 case 2:
301 arcs[1] = arc1;
302 /* Fall through */
303 case 1:
304 arcs[0] = arc0;
305 /* Fall through */
306 case 0:
307 break;
308 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000309
Lev Walkin588bf0f2017-10-13 23:51:16 -0700310 for(off = rd; ; ) {
311 asn_oid_arc_t arc;
312 rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
313 &arc);
314 if(rd < 0) {
315 return -1;
316 } else if(rd == 0) {
317 /* No more arcs. */
318 break;
319 } else {
320 off += rd;
321 if(num_arcs < arc_slots) {
322 arcs[num_arcs] = arc;
323 }
324 num_arcs++;
325 }
326 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000327
Lev Walkin588bf0f2017-10-13 23:51:16 -0700328 if(off != st->size) {
329 return -1;
330 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000331
Lev Walkin588bf0f2017-10-13 23:51:16 -0700332 return num_arcs;
Lev Walkinf15320b2004-06-03 03:38:44 +0000333}
334
Lev Walkin0787ff02004-06-17 23:43:39 +0000335
336/*
337 * Save the single value as an object identifier arc.
338 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700339ssize_t
340OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, size_t arcbuf_len,
341 asn_oid_arc_t value) {
342 /*
Lev Walkin0787ff02004-06-17 23:43:39 +0000343 * The following conditions must hold:
Lev Walkin0787ff02004-06-17 23:43:39 +0000344 * assert(arcbuf);
345 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700346 uint8_t scratch[((sizeof(value) * CHAR_BIT + 6) / 7)];
347 uint8_t *scratch_end = &scratch[sizeof(scratch)-1];
348 uint8_t *b;
349 size_t result_len;
350 uint8_t mask;
Lev Walkin0787ff02004-06-17 23:43:39 +0000351
Lev Walkin588bf0f2017-10-13 23:51:16 -0700352 for(b = scratch_end, mask = 0; ; mask = 0x80, b--) {
353 *b = mask | (value & 0x7f);
354 value >>= 7;
355 if(!value) {
356 break;
357 }
358 }
Lev Walkin0787ff02004-06-17 23:43:39 +0000359
Lev Walkin588bf0f2017-10-13 23:51:16 -0700360 result_len = (scratch_end - b) + 1;
Lev Walkin0787ff02004-06-17 23:43:39 +0000361
Lev Walkin588bf0f2017-10-13 23:51:16 -0700362 if(result_len > arcbuf_len) {
363 return -1;
364 }
365
366 memcpy(arcbuf, b, result_len);
367
368 return result_len;
Lev Walkin0787ff02004-06-17 23:43:39 +0000369}
370
Lev Walkinf15320b2004-06-03 03:38:44 +0000371int
Lev Walkin588bf0f2017-10-13 23:51:16 -0700372OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *st, const asn_oid_arc_t *arcs,
373 size_t arc_slots) {
374 uint8_t *buf;
375 uint8_t *bp;
Lev Walkin2d824a62017-10-14 02:58:46 -0700376 ssize_t wrote;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700377 asn_oid_arc_t arc0;
378 asn_oid_arc_t arc1;
379 size_t size;
380 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000381
Lev Walkin588bf0f2017-10-13 23:51:16 -0700382 if(!st || !arcs || arc_slots < 2) {
383 errno = EINVAL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000384 return -1;
385 }
386
Lev Walkin588bf0f2017-10-13 23:51:16 -0700387 arc0 = arcs[0];
388 arc1 = arcs[1];
Lev Walkin0787ff02004-06-17 23:43:39 +0000389
Lev Walkin0787ff02004-06-17 23:43:39 +0000390 if(arc0 <= 1) {
Lev Walkin588bf0f2017-10-13 23:51:16 -0700391 if(arc1 >= 40) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000392 /* 8.19.4: At most 39 subsequent values (including 0) */
393 errno = ERANGE;
394 return -1;
395 }
Lev Walkin588bf0f2017-10-13 23:51:16 -0700396 } else if(arc0 == 2) {
397 if(arc1 > ASN_OID_ARC_MAX - 80) {
398 errno = ERANGE;
399 return -1;
400 }
401 } else if(arc0 > 2) {
402 /* 8.19.4: Only three values are allocated from the root node */
403 errno = ERANGE;
404 return -1;
405 }
406
407 /*
Lev Walkin0787ff02004-06-17 23:43:39 +0000408 * After above tests it is known that the value of arc0 is completely
409 * trustworthy (0..2). However, the arc1's value is still meaningless.
410 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000411
Lev Walkin588bf0f2017-10-13 23:51:16 -0700412 /*
413 * Roughly estimate the maximum size necessary to encode these arcs.
414 * This estimation implicitly takes in account the following facts,
415 * that cancel each other:
416 * * the first two arcs are encoded in a single value.
417 * * the first value may require more space (+1 byte)
418 * * the value of the first arc which is in range (0..2)
419 */
420 size = ((sizeof(asn_oid_arc_t) * CHAR_BIT + 6) / 7) * arc_slots;
421 bp = buf = (uint8_t *)MALLOC(size + 1);
422 if(!buf) {
423 /* ENOMEM */
424 return -1;
425 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000426
Lev Walkin588bf0f2017-10-13 23:51:16 -0700427 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arc0 * 40 + arc1);
428 if(wrote <= 0) {
429 FREEMEM(buf);
430 return -1;
431 }
Lev Walkin2d824a62017-10-14 02:58:46 -0700432 assert((size_t)wrote <= size);
Lev Walkin588bf0f2017-10-13 23:51:16 -0700433 bp += wrote;
434 size -= wrote;
Lev Walkinf15320b2004-06-03 03:38:44 +0000435
Lev Walkin588bf0f2017-10-13 23:51:16 -0700436 for(i = 2; i < arc_slots; i++) {
437 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arcs[i]);
438 if(wrote <= 0) {
439 FREEMEM(buf);
440 return -1;
441 }
Lev Walkin2d824a62017-10-14 02:58:46 -0700442 assert((size_t)wrote <= size);
Lev Walkin588bf0f2017-10-13 23:51:16 -0700443 bp += wrote;
444 size -= wrote;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700445 }
Lev Walkin0787ff02004-06-17 23:43:39 +0000446
Lev Walkin588bf0f2017-10-13 23:51:16 -0700447 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000448 * Replace buffer.
449 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700450 st->size = bp - buf;
451 bp = st->buf;
452 st->buf = buf;
453 st->buf[st->size] = '\0';
Lev Walkinf15320b2004-06-03 03:38:44 +0000454 if(bp) FREEMEM(bp);
455
456 return 0;
457}
Lev Walkinc4c61962004-06-14 08:17:27 +0000458
Lev Walkin588bf0f2017-10-13 23:51:16 -0700459ssize_t
Lev Walkin92302252004-10-23 10:16:51 +0000460OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
Lev Walkin588bf0f2017-10-13 23:51:16 -0700461 asn_oid_arc_t *arcs, size_t arcs_count,
462 const char **opt_oid_text_end) {
463 size_t num_arcs = 0;
464 const char *oid_end;
Lev Walkin92302252004-10-23 10:16:51 +0000465 enum {
Lev Walkinf5927112012-09-03 00:48:45 -0700466 ST_LEADSPACE,
467 ST_TAILSPACE,
Lev Walkincad560a2013-03-16 07:00:58 -0700468 ST_AFTERVALUE, /* Next character ought to be '.' or a space */
Lev Walkin104af192016-01-24 22:13:27 -0800469 ST_WAITDIGITS /* Next character is expected to be a digit */
Lev Walkinf5927112012-09-03 00:48:45 -0700470 } state = ST_LEADSPACE;
Lev Walkin92302252004-10-23 10:16:51 +0000471
Lev Walkin588bf0f2017-10-13 23:51:16 -0700472 if(!oid_text || oid_txt_length < -1 || (arcs_count && !arcs)) {
Lev Walkin093ba2e2005-04-04 21:10:06 +0000473 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
Lev Walkin92302252004-10-23 10:16:51 +0000474 errno = EINVAL;
475 return -1;
476 }
477
478 if(oid_txt_length == -1)
479 oid_txt_length = strlen(oid_text);
480
Lev Walkin588bf0f2017-10-13 23:51:16 -0700481#define _OID_CAPTURE_ARC(oid_text, oid_end) \
482 do { \
483 const char *endp = oid_end; \
484 unsigned long value; \
485 switch(asn_strtoul_lim(oid_text, &endp, &value)) { \
486 case ASN_STRTOX_EXTRA_DATA: \
487 case ASN_STRTOX_OK: \
488 if(value <= ASN_OID_ARC_MAX) { \
489 if(num_arcs < arcs_count) arcs[num_arcs] = value; \
490 num_arcs++; \
491 oid_text = endp - 1; \
492 break; \
493 } \
494 /* Fall through */ \
495 case ASN_STRTOX_ERROR_RANGE: \
496 if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
497 errno = ERANGE; \
498 return -1; \
499 case ASN_STRTOX_ERROR_INVAL: \
500 case ASN_STRTOX_EXPECT_MORE: \
501 if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
502 errno = EINVAL; \
503 return -1; \
504 } \
505 } while(0)
Lev Walkinf5927112012-09-03 00:48:45 -0700506
Lev Walkin588bf0f2017-10-13 23:51:16 -0700507 for(oid_end = oid_text + oid_txt_length; oid_text<oid_end; oid_text++) {
Lev Walkin92302252004-10-23 10:16:51 +0000508 switch(*oid_text) {
509 case 0x09: case 0x0a: case 0x0d: case 0x20: /* whitespace */
Lev Walkinf5927112012-09-03 00:48:45 -0700510 switch(state) {
511 case ST_LEADSPACE:
512 case ST_TAILSPACE:
Lev Walkin92302252004-10-23 10:16:51 +0000513 continue;
Lev Walkincad560a2013-03-16 07:00:58 -0700514 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700515 state = ST_TAILSPACE;
516 continue;
517 case ST_WAITDIGITS:
Lev Walkincad560a2013-03-16 07:00:58 -0700518 break; /* Digits expected after ".", got whitespace */
Lev Walkin92302252004-10-23 10:16:51 +0000519 }
Lev Walkincad560a2013-03-16 07:00:58 -0700520 break;
Lev Walkinf5927112012-09-03 00:48:45 -0700521 case 0x2e: /* '.' */
522 switch(state) {
523 case ST_LEADSPACE:
Lev Walkinf5927112012-09-03 00:48:45 -0700524 case ST_TAILSPACE:
Lev Walkincad560a2013-03-16 07:00:58 -0700525 case ST_WAITDIGITS:
526 if(opt_oid_text_end)
527 *opt_oid_text_end = oid_text;
528 errno = EINVAL; /* Broken OID */
529 return -1;
Lev Walkinf5927112012-09-03 00:48:45 -0700530 break;
Lev Walkincad560a2013-03-16 07:00:58 -0700531 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700532 state = ST_WAITDIGITS;
Lev Walkin92302252004-10-23 10:16:51 +0000533 continue;
534 }
Lev Walkinf5927112012-09-03 00:48:45 -0700535 break;
536 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
537 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
538 switch(state) {
539 case ST_TAILSPACE:
Lev Walkincad560a2013-03-16 07:00:58 -0700540 case ST_AFTERVALUE:
541 if(opt_oid_text_end)
542 *opt_oid_text_end = oid_text;
543 errno = EINVAL; /* "1. 1" => broken OID */
544 return -1;
Lev Walkinf5927112012-09-03 00:48:45 -0700545 case ST_LEADSPACE:
546 case ST_WAITDIGITS:
Lev Walkincad560a2013-03-16 07:00:58 -0700547 _OID_CAPTURE_ARC(oid_text, oid_end);
548 state = ST_AFTERVALUE;
Lev Walkinf5927112012-09-03 00:48:45 -0700549 continue;
550 }
551 break;
Lev Walkin92302252004-10-23 10:16:51 +0000552 default:
553 /* Unexpected symbols */
554 state = ST_WAITDIGITS;
555 break;
556 } /* switch() */
557 break;
558 } /* for() */
559
560
Lev Walkin093ba2e2005-04-04 21:10:06 +0000561 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
Lev Walkin92302252004-10-23 10:16:51 +0000562
563 /* Finalize last arc */
564 switch(state) {
Lev Walkinf5927112012-09-03 00:48:45 -0700565 case ST_LEADSPACE:
Lev Walkinaed43c82012-09-04 14:56:27 -0700566 return 0; /* No OID found in input data */
Lev Walkinaed43c82012-09-04 14:56:27 -0700567 case ST_WAITDIGITS:
568 errno = EINVAL; /* Broken OID */
569 return -1;
Lev Walkincad560a2013-03-16 07:00:58 -0700570 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700571 case ST_TAILSPACE:
Lev Walkin588bf0f2017-10-13 23:51:16 -0700572 return num_arcs;
Lev Walkin92302252004-10-23 10:16:51 +0000573 }
Lev Walkinaed43c82012-09-04 14:56:27 -0700574
575 errno = EINVAL; /* Broken OID */
576 return -1;
Lev Walkin92302252004-10-23 10:16:51 +0000577}
578
Lev Walkina5972be2017-09-29 23:15:58 -0700579/*
580 * Generate values from the list of interesting values, or just a random
581 * value up to the upper limit.
582 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700583static asn_oid_arc_t
584OBJECT_IDENTIFIER__biased_random_arc(asn_oid_arc_t upper_bound) {
585 const asn_oid_arc_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
Lev Walkinb5b524b2017-10-13 03:14:03 -0700586 size_t idx;
Lev Walkin92302252004-10-23 10:16:51 +0000587
Lev Walkinb5b524b2017-10-13 03:14:03 -0700588 switch(asn_random_between(0, 2)) {
589 case 0:
590 idx = asn_random_between(0, sizeof(values) / sizeof(values[0]) - 1);
Lev Walkina5972be2017-09-29 23:15:58 -0700591 if(values[idx] < upper_bound) {
592 return values[idx];
593 }
Lev Walkinb5b524b2017-10-13 03:14:03 -0700594 /* Fall through */
595 case 1:
596 return asn_random_between(0, upper_bound);
597 case 2:
598 default:
599 return upper_bound;
Lev Walkina5972be2017-09-29 23:15:58 -0700600 }
Lev Walkina5972be2017-09-29 23:15:58 -0700601}
602
603asn_random_fill_result_t
604OBJECT_IDENTIFIER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
605 const asn_encoding_constraints_t *constraints,
606 size_t max_length) {
607 asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
608 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
609 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
610 OBJECT_IDENTIFIER_t *st;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700611 asn_oid_arc_t arcs[5];
Lev Walkina5972be2017-09-29 23:15:58 -0700612 size_t arcs_len = asn_random_between(2, 5);
613 size_t i;
614
615 (void)constraints;
616
617 if(max_length < arcs_len) return result_skipped;
618
619 if(*sptr) {
620 st = *sptr;
621 } else {
622 st = CALLOC(1, sizeof(*st));
623 }
624
625 arcs[0] = asn_random_between(0, 2);
Lev Walkin588bf0f2017-10-13 23:51:16 -0700626 arcs[1] = OBJECT_IDENTIFIER__biased_random_arc(
627 arcs[0] <= 1 ? 39 : (ASN_OID_ARC_MAX - 80));
Lev Walkina5972be2017-09-29 23:15:58 -0700628 for(i = 2; i < arcs_len; i++) {
Lev Walkin588bf0f2017-10-13 23:51:16 -0700629 arcs[i] = OBJECT_IDENTIFIER__biased_random_arc(ASN_OID_ARC_MAX);
Lev Walkina5972be2017-09-29 23:15:58 -0700630 }
631
Lev Walkin588bf0f2017-10-13 23:51:16 -0700632 if(OBJECT_IDENTIFIER_set_arcs(st, arcs, arcs_len)) {
Lev Walkina5972be2017-09-29 23:15:58 -0700633 if(st != *sptr) {
634 ASN_STRUCT_FREE(*td, st);
635 }
636 return result_failed;
637 }
638
639 *sptr = st;
640
Lev Walkin588bf0f2017-10-13 23:51:16 -0700641 result_ok.length = st->size;
Lev Walkina5972be2017-09-29 23:15:58 -0700642 return result_ok;
643}