blob: 3f26477bc3766aedf8de26ef917d4149e856fabe [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 Walkin5e033762004-09-29 13:26:15 +000059OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
Lev Walkin1eded352006-07-13 11:19:01 +000060 asn_app_constraint_failed_f *ctfailcb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +000061 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +000062
63 if(st && st->buf) {
64 if(st->size < 1) {
Lev Walkin7c1dc052016-03-14 03:08:15 -070065 ASN__CTFAIL(app_key, td, sptr,
Lev Walkin16835b62004-08-22 13:47:59 +000066 "%s: at least one numerical value "
67 "expected (%s:%d)",
68 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +000069 return -1;
70 }
71 } else {
Lev Walkin7c1dc052016-03-14 03:08:15 -070072 ASN__CTFAIL(app_key, td, sptr,
Lev Walkin16835b62004-08-22 13:47:59 +000073 "%s: value not given (%s:%d)",
74 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +000075 return -1;
76 }
77
78 return 0;
79}
80
Lev Walkin588bf0f2017-10-13 23:51:16 -070081static ssize_t
82OBJECT_IDENTIFIER_get_first_arcs(const uint8_t *arcbuf, size_t arcbuf_len,
83 asn_oid_arc_t *arc0, asn_oid_arc_t *arc1) {
84 asn_oid_arc_t value;
Lev Walkinf15320b2004-06-03 03:38:44 +000085
Lev Walkin588bf0f2017-10-13 23:51:16 -070086 ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(arcbuf, arcbuf_len, &value);
87 if(rd <= 0) return rd;
Lev Walkin29a044b2004-06-14 07:24:36 +000088
Lev Walkin588bf0f2017-10-13 23:51:16 -070089 if(value >= 80) {
90 *arc0 = 2;
91 *arc1 = value - 80;
92 } else if(value >= 40) {
93 *arc0 = 1;
94 *arc1 = value - 40;
95 } else {
96 *arc0 = 0;
97 *arc1 = value;
98 }
Lev Walkin0995f352017-09-17 23:16:38 -070099
Lev Walkin588bf0f2017-10-13 23:51:16 -0700100 return rd;
Lev Walkinf15320b2004-06-03 03:38:44 +0000101}
102
Lev Walkina9cc46e2004-09-22 16:06:28 +0000103ssize_t
Lev Walkin588bf0f2017-10-13 23:51:16 -0700104OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, size_t arcbuf_len,
105 asn_oid_arc_t *ret_value) {
106 const uint8_t *b = arcbuf;
107 const uint8_t *arcend = arcbuf + arcbuf_len; /* End of arc */
Lev Walkinf15320b2004-06-03 03:38:44 +0000108
Lev Walkin588bf0f2017-10-13 23:51:16 -0700109 if(arcbuf == arcend) {
110 return 0;
111 } else {
112 asn_oid_arc_t accum;
113 /* Gather all bits into the accumulator */
114 for(accum = 0; b < arcend; b++) {
115 accum = (accum << 7) | (*b & ~0x80);
116 if((*b & 0x80) == 0) {
117 if(accum <= ASN_OID_ARC_MAX) {
118 *ret_value = accum;
119 return 1 + (b - arcbuf);
120 } else {
121 errno = ERANGE; /* Overflow */
122 return -1;
123 }
124 }
125 }
126 errno = EINVAL;
127 return -1;
128 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000129
Lev Walkina9cc46e2004-09-22 16:06:28 +0000130}
131
132static ssize_t
Lev Walkin588bf0f2017-10-13 23:51:16 -0700133OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st,
134 asn_app_consume_bytes_f *cb, void *app_key) {
135 char scratch[32];
136 asn_oid_arc_t arc0, arc1;
137 size_t produced = 0;
138 size_t off = 0;
139 ssize_t rd;
140 int ret;
Lev Walkinf15320b2004-06-03 03:38:44 +0000141
Lev Walkin588bf0f2017-10-13 23:51:16 -0700142 rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
143 if(rd <= 0) {
144 return -1;
145 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000146
Lev Walkin588bf0f2017-10-13 23:51:16 -0700147 ret = snprintf(scratch, sizeof(scratch), "%"PRIu32".%"PRIu32, arc0, arc1);
148 if(ret >= (ssize_t)sizeof(scratch)) {
149 return -1;
150 }
151 produced += ret;
152 if(cb(scratch, ret, app_key) < 0)
153 return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000154
Lev Walkin588bf0f2017-10-13 23:51:16 -0700155 for(off = rd; ; ) {
156 asn_oid_arc_t arc;
157 rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
158 &arc);
159 if(rd < 0) {
160 return -1;
161 } else if(rd == 0) {
162 /* No more arcs. */
163 break;
164 } else {
165 off += rd;
166 assert(off <= st->size);
167 ret = snprintf(scratch, sizeof(scratch), ".%" PRIu32, arc);
168 if(ret >= (ssize_t)sizeof(scratch)) {
169 return -1;
170 }
171 produced += ret;
172 if(cb(scratch, ret, app_key) < 0) return -1;
173 }
174 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000175
Lev Walkin588bf0f2017-10-13 23:51:16 -0700176 if(off != st->size) {
177 ASN_DEBUG("Could not scan to the end of Object Identifier");
178 return -1;
179 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000180
Lev Walkin588bf0f2017-10-13 23:51:16 -0700181 return produced;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000182}
183
Lev Walkin0fab1a62005-03-09 22:19:25 +0000184static enum xer_pbd_rval
185OBJECT_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 +0000186 OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)sptr;
Lev Walkin2c34aad2005-03-10 11:50:24 +0000187 const char *chunk_end = (const char *)chunk_buf + chunk_size;
188 const char *endptr;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700189 asn_oid_arc_t s_arcs[10];
190 asn_oid_arc_t *arcs = s_arcs;
191 ssize_t num_arcs;
192 ssize_t ret;
Lev Walkin92302252004-10-23 10:16:51 +0000193
Lev Walkine0b56e02005-02-25 12:10:27 +0000194 (void)td;
195
Lev Walkin588bf0f2017-10-13 23:51:16 -0700196 num_arcs = OBJECT_IDENTIFIER_parse_arcs(
197 (const char *)chunk_buf, chunk_size, arcs,
198 sizeof(s_arcs) / sizeof(s_arcs[0]), &endptr);
199 if(num_arcs < 0) {
Lev Walkin0fab1a62005-03-09 22:19:25 +0000200 /* Expecting more than zero arcs */
201 return XPBD_BROKEN_ENCODING;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700202 } else if(num_arcs == 0) {
Lev Walkinaed43c82012-09-04 14:56:27 -0700203 return XPBD_NOT_BODY_IGNORE;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000204 }
Lev Walkinaed43c82012-09-04 14:56:27 -0700205 assert(endptr == chunk_end);
Lev Walkin0fab1a62005-03-09 22:19:25 +0000206
Lev Walkin588bf0f2017-10-13 23:51:16 -0700207 if((size_t)num_arcs > sizeof(s_arcs)/sizeof(s_arcs[0])) {
208 arcs = (asn_oid_arc_t *)MALLOC(num_arcs * sizeof(asn_oid_arc_t));
Lev Walkin0fab1a62005-03-09 22:19:25 +0000209 if(!arcs) return XPBD_SYSTEM_FAILURE;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700210 ret = OBJECT_IDENTIFIER_parse_arcs((const char *)chunk_buf, chunk_size,
211 arcs, num_arcs, &endptr);
212 if(ret != num_arcs)
Lev Walkin0fab1a62005-03-09 22:19:25 +0000213 return XPBD_SYSTEM_FAILURE; /* assert?.. */
Lev Walkin92302252004-10-23 10:16:51 +0000214 }
215
216 /*
217 * Convert arcs into BER representation.
218 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700219 ret = OBJECT_IDENTIFIER_set_arcs(st, arcs, num_arcs);
Lev Walkin92302252004-10-23 10:16:51 +0000220 if(arcs != s_arcs) FREEMEM(arcs);
221
Lev Walkin2c34aad2005-03-10 11:50:24 +0000222 return ret ? XPBD_SYSTEM_FAILURE : XPBD_BODY_CONSUMED;
Lev Walkin92302252004-10-23 10:16:51 +0000223}
224
225asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700226OBJECT_IDENTIFIER_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin92302252004-10-23 10:16:51 +0000227 asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
Lev Walkin8c3b8542005-03-10 18:52:02 +0000228 const void *buf_ptr, size_t size) {
Lev Walkin92302252004-10-23 10:16:51 +0000229
230 return xer_decode_primitive(opt_codec_ctx, td,
231 sptr, sizeof(OBJECT_IDENTIFIER_t), opt_mname,
232 buf_ptr, size, OBJECT_IDENTIFIER__xer_body_decode);
233}
234
Lev Walkina9cc46e2004-09-22 16:06:28 +0000235asn_enc_rval_t
Lev Walkin5e033762004-09-29 13:26:15 +0000236OBJECT_IDENTIFIER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000237 int ilevel, enum xer_encoder_flags_e flags,
238 asn_app_consume_bytes_f *cb, void *app_key) {
239 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
240 asn_enc_rval_t er;
241
Lev Walkin588bf0f2017-10-13 23:51:16 -0700242 (void)ilevel;
243 (void)flags;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000244
Lev Walkin588bf0f2017-10-13 23:51:16 -0700245 if(!st || !st->buf) {
246 ASN__ENCODE_FAILED;
247 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000248
Lev Walkin588bf0f2017-10-13 23:51:16 -0700249 er.encoded = OBJECT_IDENTIFIER__dump_body(st, cb, app_key);
250 if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000251
Lev Walkin588bf0f2017-10-13 23:51:16 -0700252 ASN__ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000253}
254
255int
Lev Walkin5e033762004-09-29 13:26:15 +0000256OBJECT_IDENTIFIER_print(asn_TYPE_descriptor_t *td, const void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000257 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
258 const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
259
260 (void)td; /* Unused argument */
261 (void)ilevel; /* Unused argument */
262
263 if(!st || !st->buf)
Lev Walkin8e8078a2004-09-26 13:10:40 +0000264 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000265
266 /* Dump preamble */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000267 if(cb("{ ", 2, app_key) < 0)
Lev Walkina9cc46e2004-09-22 16:06:28 +0000268 return -1;
269
Lev Walkin588bf0f2017-10-13 23:51:16 -0700270 if(OBJECT_IDENTIFIER__dump_body(st, cb, app_key) < 0) {
271 return -1;
272 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000273
Lev Walkin588bf0f2017-10-13 23:51:16 -0700274 return (cb(" }", 2, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000275}
276
Lev Walkin588bf0f2017-10-13 23:51:16 -0700277ssize_t
278OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *st, asn_oid_arc_t *arcs,
279 size_t arc_slots) {
280 asn_oid_arc_t arc0, arc1;
281 size_t num_arcs = 0;
282 size_t off;
283 ssize_t rd;
Lev Walkinf15320b2004-06-03 03:38:44 +0000284
Lev Walkin588bf0f2017-10-13 23:51:16 -0700285 if(!st || !st->buf) {
286 errno = EINVAL;
287 return -1;
288 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000289
Lev Walkin588bf0f2017-10-13 23:51:16 -0700290 rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
291 if(rd <= 0) {
292 return -1;
293 }
294 num_arcs = 2;
295 switch(arc_slots) {
296 default:
297 case 2:
298 arcs[1] = arc1;
299 /* Fall through */
300 case 1:
301 arcs[0] = arc0;
302 /* Fall through */
303 case 0:
304 break;
305 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000306
Lev Walkin588bf0f2017-10-13 23:51:16 -0700307 for(off = rd; ; ) {
308 asn_oid_arc_t arc;
309 rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
310 &arc);
311 if(rd < 0) {
312 return -1;
313 } else if(rd == 0) {
314 /* No more arcs. */
315 break;
316 } else {
317 off += rd;
318 if(num_arcs < arc_slots) {
319 arcs[num_arcs] = arc;
320 }
321 num_arcs++;
322 }
323 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000324
Lev Walkin588bf0f2017-10-13 23:51:16 -0700325 if(off != st->size) {
326 return -1;
327 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000328
Lev Walkin588bf0f2017-10-13 23:51:16 -0700329 return num_arcs;
Lev Walkinf15320b2004-06-03 03:38:44 +0000330}
331
Lev Walkin0787ff02004-06-17 23:43:39 +0000332
333/*
334 * Save the single value as an object identifier arc.
335 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700336ssize_t
337OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, size_t arcbuf_len,
338 asn_oid_arc_t value) {
339 /*
Lev Walkin0787ff02004-06-17 23:43:39 +0000340 * The following conditions must hold:
Lev Walkin0787ff02004-06-17 23:43:39 +0000341 * assert(arcbuf);
342 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700343 uint8_t scratch[((sizeof(value) * CHAR_BIT + 6) / 7)];
344 uint8_t *scratch_end = &scratch[sizeof(scratch)-1];
345 uint8_t *b;
346 size_t result_len;
347 uint8_t mask;
Lev Walkin0787ff02004-06-17 23:43:39 +0000348
Lev Walkin588bf0f2017-10-13 23:51:16 -0700349 for(b = scratch_end, mask = 0; ; mask = 0x80, b--) {
350 *b = mask | (value & 0x7f);
351 value >>= 7;
352 if(!value) {
353 break;
354 }
355 }
Lev Walkin0787ff02004-06-17 23:43:39 +0000356
Lev Walkin588bf0f2017-10-13 23:51:16 -0700357 result_len = (scratch_end - b) + 1;
Lev Walkin0787ff02004-06-17 23:43:39 +0000358
Lev Walkin588bf0f2017-10-13 23:51:16 -0700359 if(result_len > arcbuf_len) {
360 return -1;
361 }
362
363 memcpy(arcbuf, b, result_len);
364
365 return result_len;
Lev Walkin0787ff02004-06-17 23:43:39 +0000366}
367
Lev Walkinf15320b2004-06-03 03:38:44 +0000368int
Lev Walkin588bf0f2017-10-13 23:51:16 -0700369OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *st, const asn_oid_arc_t *arcs,
370 size_t arc_slots) {
371 uint8_t *buf;
372 uint8_t *bp;
Lev Walkin2d824a62017-10-14 02:58:46 -0700373 ssize_t wrote;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700374 asn_oid_arc_t arc0;
375 asn_oid_arc_t arc1;
376 size_t size;
377 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000378
Lev Walkin588bf0f2017-10-13 23:51:16 -0700379 if(!st || !arcs || arc_slots < 2) {
380 errno = EINVAL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000381 return -1;
382 }
383
Lev Walkin588bf0f2017-10-13 23:51:16 -0700384 arc0 = arcs[0];
385 arc1 = arcs[1];
Lev Walkin0787ff02004-06-17 23:43:39 +0000386
Lev Walkin0787ff02004-06-17 23:43:39 +0000387 if(arc0 <= 1) {
Lev Walkin588bf0f2017-10-13 23:51:16 -0700388 if(arc1 >= 40) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000389 /* 8.19.4: At most 39 subsequent values (including 0) */
390 errno = ERANGE;
391 return -1;
392 }
Lev Walkin588bf0f2017-10-13 23:51:16 -0700393 } else if(arc0 == 2) {
394 if(arc1 > ASN_OID_ARC_MAX - 80) {
395 errno = ERANGE;
396 return -1;
397 }
398 } else if(arc0 > 2) {
399 /* 8.19.4: Only three values are allocated from the root node */
400 errno = ERANGE;
401 return -1;
402 }
403
404 /*
Lev Walkin0787ff02004-06-17 23:43:39 +0000405 * After above tests it is known that the value of arc0 is completely
406 * trustworthy (0..2). However, the arc1's value is still meaningless.
407 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000408
Lev Walkin588bf0f2017-10-13 23:51:16 -0700409 /*
410 * Roughly estimate the maximum size necessary to encode these arcs.
411 * This estimation implicitly takes in account the following facts,
412 * that cancel each other:
413 * * the first two arcs are encoded in a single value.
414 * * the first value may require more space (+1 byte)
415 * * the value of the first arc which is in range (0..2)
416 */
417 size = ((sizeof(asn_oid_arc_t) * CHAR_BIT + 6) / 7) * arc_slots;
418 bp = buf = (uint8_t *)MALLOC(size + 1);
419 if(!buf) {
420 /* ENOMEM */
421 return -1;
422 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000423
Lev Walkin588bf0f2017-10-13 23:51:16 -0700424 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arc0 * 40 + arc1);
425 if(wrote <= 0) {
426 FREEMEM(buf);
427 return -1;
428 }
Lev Walkin2d824a62017-10-14 02:58:46 -0700429 assert((size_t)wrote <= size);
Lev Walkin588bf0f2017-10-13 23:51:16 -0700430 bp += wrote;
431 size -= wrote;
Lev Walkinf15320b2004-06-03 03:38:44 +0000432
Lev Walkin588bf0f2017-10-13 23:51:16 -0700433 for(i = 2; i < arc_slots; i++) {
434 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arcs[i]);
435 if(wrote <= 0) {
436 FREEMEM(buf);
437 return -1;
438 }
Lev Walkin2d824a62017-10-14 02:58:46 -0700439 assert((size_t)wrote <= size);
Lev Walkin588bf0f2017-10-13 23:51:16 -0700440 bp += wrote;
441 size -= wrote;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700442 }
Lev Walkin0787ff02004-06-17 23:43:39 +0000443
Lev Walkin588bf0f2017-10-13 23:51:16 -0700444 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000445 * Replace buffer.
446 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700447 st->size = bp - buf;
448 bp = st->buf;
449 st->buf = buf;
450 st->buf[st->size] = '\0';
Lev Walkinf15320b2004-06-03 03:38:44 +0000451 if(bp) FREEMEM(bp);
452
453 return 0;
454}
Lev Walkinc4c61962004-06-14 08:17:27 +0000455
Lev Walkin588bf0f2017-10-13 23:51:16 -0700456ssize_t
Lev Walkin92302252004-10-23 10:16:51 +0000457OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
Lev Walkin588bf0f2017-10-13 23:51:16 -0700458 asn_oid_arc_t *arcs, size_t arcs_count,
459 const char **opt_oid_text_end) {
460 size_t num_arcs = 0;
461 const char *oid_end;
Lev Walkin92302252004-10-23 10:16:51 +0000462 enum {
Lev Walkinf5927112012-09-03 00:48:45 -0700463 ST_LEADSPACE,
464 ST_TAILSPACE,
Lev Walkincad560a2013-03-16 07:00:58 -0700465 ST_AFTERVALUE, /* Next character ought to be '.' or a space */
Lev Walkin104af192016-01-24 22:13:27 -0800466 ST_WAITDIGITS /* Next character is expected to be a digit */
Lev Walkinf5927112012-09-03 00:48:45 -0700467 } state = ST_LEADSPACE;
Lev Walkin92302252004-10-23 10:16:51 +0000468
Lev Walkin588bf0f2017-10-13 23:51:16 -0700469 if(!oid_text || oid_txt_length < -1 || (arcs_count && !arcs)) {
Lev Walkin093ba2e2005-04-04 21:10:06 +0000470 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
Lev Walkin92302252004-10-23 10:16:51 +0000471 errno = EINVAL;
472 return -1;
473 }
474
475 if(oid_txt_length == -1)
476 oid_txt_length = strlen(oid_text);
477
Lev Walkin588bf0f2017-10-13 23:51:16 -0700478#define _OID_CAPTURE_ARC(oid_text, oid_end) \
479 do { \
480 const char *endp = oid_end; \
481 unsigned long value; \
482 switch(asn_strtoul_lim(oid_text, &endp, &value)) { \
483 case ASN_STRTOX_EXTRA_DATA: \
484 case ASN_STRTOX_OK: \
485 if(value <= ASN_OID_ARC_MAX) { \
486 if(num_arcs < arcs_count) arcs[num_arcs] = value; \
487 num_arcs++; \
488 oid_text = endp - 1; \
489 break; \
490 } \
491 /* Fall through */ \
492 case ASN_STRTOX_ERROR_RANGE: \
493 if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
494 errno = ERANGE; \
495 return -1; \
496 case ASN_STRTOX_ERROR_INVAL: \
497 case ASN_STRTOX_EXPECT_MORE: \
498 if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
499 errno = EINVAL; \
500 return -1; \
501 } \
502 } while(0)
Lev Walkinf5927112012-09-03 00:48:45 -0700503
Lev Walkin588bf0f2017-10-13 23:51:16 -0700504 for(oid_end = oid_text + oid_txt_length; oid_text<oid_end; oid_text++) {
Lev Walkin92302252004-10-23 10:16:51 +0000505 switch(*oid_text) {
506 case 0x09: case 0x0a: case 0x0d: case 0x20: /* whitespace */
Lev Walkinf5927112012-09-03 00:48:45 -0700507 switch(state) {
508 case ST_LEADSPACE:
509 case ST_TAILSPACE:
Lev Walkin92302252004-10-23 10:16:51 +0000510 continue;
Lev Walkincad560a2013-03-16 07:00:58 -0700511 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700512 state = ST_TAILSPACE;
513 continue;
514 case ST_WAITDIGITS:
Lev Walkincad560a2013-03-16 07:00:58 -0700515 break; /* Digits expected after ".", got whitespace */
Lev Walkin92302252004-10-23 10:16:51 +0000516 }
Lev Walkincad560a2013-03-16 07:00:58 -0700517 break;
Lev Walkinf5927112012-09-03 00:48:45 -0700518 case 0x2e: /* '.' */
519 switch(state) {
520 case ST_LEADSPACE:
Lev Walkinf5927112012-09-03 00:48:45 -0700521 case ST_TAILSPACE:
Lev Walkincad560a2013-03-16 07:00:58 -0700522 case ST_WAITDIGITS:
523 if(opt_oid_text_end)
524 *opt_oid_text_end = oid_text;
525 errno = EINVAL; /* Broken OID */
526 return -1;
Lev Walkinf5927112012-09-03 00:48:45 -0700527 break;
Lev Walkincad560a2013-03-16 07:00:58 -0700528 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700529 state = ST_WAITDIGITS;
Lev Walkin92302252004-10-23 10:16:51 +0000530 continue;
531 }
Lev Walkinf5927112012-09-03 00:48:45 -0700532 break;
533 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
534 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
535 switch(state) {
536 case ST_TAILSPACE:
Lev Walkincad560a2013-03-16 07:00:58 -0700537 case ST_AFTERVALUE:
538 if(opt_oid_text_end)
539 *opt_oid_text_end = oid_text;
540 errno = EINVAL; /* "1. 1" => broken OID */
541 return -1;
Lev Walkinf5927112012-09-03 00:48:45 -0700542 case ST_LEADSPACE:
543 case ST_WAITDIGITS:
Lev Walkincad560a2013-03-16 07:00:58 -0700544 _OID_CAPTURE_ARC(oid_text, oid_end);
545 state = ST_AFTERVALUE;
Lev Walkinf5927112012-09-03 00:48:45 -0700546 continue;
547 }
548 break;
Lev Walkin92302252004-10-23 10:16:51 +0000549 default:
550 /* Unexpected symbols */
551 state = ST_WAITDIGITS;
552 break;
553 } /* switch() */
554 break;
555 } /* for() */
556
557
Lev Walkin093ba2e2005-04-04 21:10:06 +0000558 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
Lev Walkin92302252004-10-23 10:16:51 +0000559
560 /* Finalize last arc */
561 switch(state) {
Lev Walkinf5927112012-09-03 00:48:45 -0700562 case ST_LEADSPACE:
Lev Walkinaed43c82012-09-04 14:56:27 -0700563 return 0; /* No OID found in input data */
Lev Walkinaed43c82012-09-04 14:56:27 -0700564 case ST_WAITDIGITS:
565 errno = EINVAL; /* Broken OID */
566 return -1;
Lev Walkincad560a2013-03-16 07:00:58 -0700567 case ST_AFTERVALUE:
Lev Walkinf5927112012-09-03 00:48:45 -0700568 case ST_TAILSPACE:
Lev Walkin588bf0f2017-10-13 23:51:16 -0700569 return num_arcs;
Lev Walkin92302252004-10-23 10:16:51 +0000570 }
Lev Walkinaed43c82012-09-04 14:56:27 -0700571
572 errno = EINVAL; /* Broken OID */
573 return -1;
Lev Walkin92302252004-10-23 10:16:51 +0000574}
575
Lev Walkina5972be2017-09-29 23:15:58 -0700576/*
577 * Generate values from the list of interesting values, or just a random
578 * value up to the upper limit.
579 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700580static asn_oid_arc_t
581OBJECT_IDENTIFIER__biased_random_arc(asn_oid_arc_t upper_bound) {
582 const asn_oid_arc_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
Lev Walkinb5b524b2017-10-13 03:14:03 -0700583 size_t idx;
Lev Walkin92302252004-10-23 10:16:51 +0000584
Lev Walkinb5b524b2017-10-13 03:14:03 -0700585 switch(asn_random_between(0, 2)) {
586 case 0:
587 idx = asn_random_between(0, sizeof(values) / sizeof(values[0]) - 1);
Lev Walkina5972be2017-09-29 23:15:58 -0700588 if(values[idx] < upper_bound) {
589 return values[idx];
590 }
Lev Walkinb5b524b2017-10-13 03:14:03 -0700591 /* Fall through */
592 case 1:
593 return asn_random_between(0, upper_bound);
594 case 2:
595 default:
596 return upper_bound;
Lev Walkina5972be2017-09-29 23:15:58 -0700597 }
Lev Walkina5972be2017-09-29 23:15:58 -0700598}
599
600asn_random_fill_result_t
601OBJECT_IDENTIFIER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
602 const asn_encoding_constraints_t *constraints,
603 size_t max_length) {
604 asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
605 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
606 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
607 OBJECT_IDENTIFIER_t *st;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700608 asn_oid_arc_t arcs[5];
Lev Walkina5972be2017-09-29 23:15:58 -0700609 size_t arcs_len = asn_random_between(2, 5);
610 size_t i;
611
612 (void)constraints;
613
614 if(max_length < arcs_len) return result_skipped;
615
616 if(*sptr) {
617 st = *sptr;
618 } else {
619 st = CALLOC(1, sizeof(*st));
620 }
621
622 arcs[0] = asn_random_between(0, 2);
Lev Walkin588bf0f2017-10-13 23:51:16 -0700623 arcs[1] = OBJECT_IDENTIFIER__biased_random_arc(
624 arcs[0] <= 1 ? 39 : (ASN_OID_ARC_MAX - 80));
Lev Walkina5972be2017-09-29 23:15:58 -0700625 for(i = 2; i < arcs_len; i++) {
Lev Walkin588bf0f2017-10-13 23:51:16 -0700626 arcs[i] = OBJECT_IDENTIFIER__biased_random_arc(ASN_OID_ARC_MAX);
Lev Walkina5972be2017-09-29 23:15:58 -0700627 }
628
Lev Walkin588bf0f2017-10-13 23:51:16 -0700629 if(OBJECT_IDENTIFIER_set_arcs(st, arcs, arcs_len)) {
Lev Walkina5972be2017-09-29 23:15:58 -0700630 if(st != *sptr) {
631 ASN_STRUCT_FREE(*td, st);
632 }
633 return result_failed;
634 }
635
636 *sptr = st;
637
Lev Walkin588bf0f2017-10-13 23:51:16 -0700638 result_ok.length = st->size;
Lev Walkina5972be2017-09-29 23:15:58 -0700639 return result_ok;
640}