blob: 3eb2276bf1cfadb0783e00194c267b30b095c587 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
Lev Walkina5972be2017-09-29 23:15:58 -07002 * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>.
Lev Walkin2c34aad2005-03-10 11:50:24 +00003 * All rights reserved.
Lev Walkinf15320b2004-06-03 03:38:44 +00004 * Redistribution and modifications are permitted subject to BSD license.
5 */
Lev Walkina9cc46e2004-09-22 16:06:28 +00006#include <asn_internal.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00007#include <RELATIVE-OID.h>
Lev Walkin725883b2006-10-09 12:07:58 +00008#include <OCTET_STRING.h>
Lev Walkin3256d6f2004-10-21 11:22:12 +00009#include <asn_codecs_prim.h> /* Encoder and decoder of a primitive type */
Lev Walkin0787ff02004-06-17 23:43:39 +000010#include <limits.h> /* for CHAR_BIT */
Lev Walkinf15320b2004-06-03 03:38:44 +000011#include <errno.h>
12
13/*
14 * RELATIVE-OID basic type description.
15 */
Wim Lewis18c2ec92014-07-29 11:30:10 -070016static const ber_tlv_tag_t asn_DEF_RELATIVE_OID_tags[] = {
Lev Walkinf15320b2004-06-03 03:38:44 +000017 (ASN_TAG_CLASS_UNIVERSAL | (13 << 2))
18};
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +080019asn_TYPE_operation_t asn_OP_RELATIVE_OID = {
Lev Walkin8e8078a2004-09-26 13:10:40 +000020 ASN__PRIMITIVE_TYPE_free,
Lev Walkina9cc46e2004-09-22 16:06:28 +000021 RELATIVE_OID_print,
Lev Walkincd2f48e2017-08-10 02:14:59 -070022 OCTET_STRING_compare, /* Implemented in terms of opaque comparison */
Lev Walkin8e8078a2004-09-26 13:10:40 +000023 ber_decode_primitive,
24 der_encode_primitive,
Lev Walkin92302252004-10-23 10:16:51 +000025 RELATIVE_OID_decode_xer,
Lev Walkina9cc46e2004-09-22 16:06:28 +000026 RELATIVE_OID_encode_xer,
Lev Walkincc159472017-07-06 08:26:36 -070027#ifdef ASN_DISABLE_OER_SUPPORT
28 0,
29 0,
30#else
Lev Walkinb5b524b2017-10-13 03:14:03 -070031 RELATIVE_OID_decode_oer,
32 RELATIVE_OID_encode_oer,
Lev Walkincc159472017-07-06 08:26:36 -070033#endif /* ASN_DISABLE_OER_SUPPORT */
Lev Walkinb33425f2017-07-14 14:59:52 +040034#ifdef ASN_DISABLE_PER_SUPPORT
35 0,
36 0,
37#else
38 OCTET_STRING_decode_uper,
39 OCTET_STRING_encode_uper,
40#endif /* ASN_DISABLE_PER_SUPPORT */
Lev Walkina5972be2017-09-29 23:15:58 -070041 RELATIVE_OID_random_fill,
Bi-Ruei, Chiu1f87ac02017-08-20 01:25:45 +080042 0 /* Use generic outmost tag fetcher */
43};
44asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = {
45 "RELATIVE-OID",
46 "RELATIVE_OID",
47 &asn_OP_RELATIVE_OID,
Lev Walkin5e033762004-09-29 13:26:15 +000048 asn_DEF_RELATIVE_OID_tags,
49 sizeof(asn_DEF_RELATIVE_OID_tags)
50 / sizeof(asn_DEF_RELATIVE_OID_tags[0]),
51 asn_DEF_RELATIVE_OID_tags, /* Same as above */
52 sizeof(asn_DEF_RELATIVE_OID_tags)
53 / sizeof(asn_DEF_RELATIVE_OID_tags[0]),
Lev Walkina5972be2017-09-29 23:15:58 -070054 { 0, 0, asn_generic_no_constraint },
Lev Walkin449f8322004-08-20 13:23:42 +000055 0, 0, /* No members */
Lev Walkind9bd7752004-06-05 08:17:50 +000056 0 /* No specifics */
Lev Walkinf15320b2004-06-03 03:38:44 +000057};
58
Lev Walkina9cc46e2004-09-22 16:06:28 +000059static ssize_t
60RELATIVE_OID__dump_body(const RELATIVE_OID_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin588bf0f2017-10-13 23:51:16 -070061 char scratch[32];
62 size_t produced = 0;
63 size_t off = 0;
Lev Walkina9cc46e2004-09-22 16:06:28 +000064
Lev Walkin588bf0f2017-10-13 23:51:16 -070065 for(;;) {
66 asn_oid_arc_t arc;
67 ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off,
68 st->size - off, &arc);
69 if(rd < 0) {
70 return -1;
71 } else if(rd == 0) {
72 /* No more arcs. */
73 break;
74 } else {
75 int ret = snprintf(scratch, sizeof(scratch), "%s%" PRIu32,
76 off ? "." : "", arc);
77 if(ret >= (ssize_t)sizeof(scratch)) {
78 return -1;
79 }
80 produced += ret;
81 off += rd;
82 assert(off <= st->size);
83 if(cb(scratch, ret, app_key) < 0) return -1;
84 }
85 }
Lev Walkina9cc46e2004-09-22 16:06:28 +000086
Lev Walkin588bf0f2017-10-13 23:51:16 -070087 if(off != st->size) {
88 ASN_DEBUG("Could not scan to the end of Object Identifier");
89 return -1;
90 }
Lev Walkina9cc46e2004-09-22 16:06:28 +000091
Lev Walkin588bf0f2017-10-13 23:51:16 -070092 return produced;
Lev Walkina9cc46e2004-09-22 16:06:28 +000093}
94
Lev Walkinf15320b2004-06-03 03:38:44 +000095int
Lev Walkin5e033762004-09-29 13:26:15 +000096RELATIVE_OID_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkinf15320b2004-06-03 03:38:44 +000097 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +000098 const RELATIVE_OID_t *st = (const RELATIVE_OID_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +000099
Lev Walkind9bd7752004-06-05 08:17:50 +0000100 (void)td; /* Unused argument */
101 (void)ilevel; /* Unused argument */
102
Lev Walkinf15320b2004-06-03 03:38:44 +0000103 if(!st || !st->buf)
Lev Walkin8e8078a2004-09-26 13:10:40 +0000104 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000105
106 /* Dump preamble */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000107 if(cb("{ ", 2, app_key) < 0)
Lev Walkinf15320b2004-06-03 03:38:44 +0000108 return -1;
109
Lev Walkina9cc46e2004-09-22 16:06:28 +0000110 if(RELATIVE_OID__dump_body(st, cb, app_key) < 0)
111 return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000112
Lev Walkin8e8078a2004-09-26 13:10:40 +0000113 return (cb(" }", 2, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000114}
115
Lev Walkin0fab1a62005-03-09 22:19:25 +0000116static enum xer_pbd_rval
117RELATIVE_OID__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 +0000118 RELATIVE_OID_t *st = (RELATIVE_OID_t *)sptr;
Lev Walkin2c34aad2005-03-10 11:50:24 +0000119 const char *chunk_end = (const char *)chunk_buf + chunk_size;
120 const char *endptr;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700121 asn_oid_arc_t s_arcs[6];
122 asn_oid_arc_t *arcs = s_arcs;
123 ssize_t num_arcs;
Lev Walkin92302252004-10-23 10:16:51 +0000124 int ret;
125
Lev Walkine0b56e02005-02-25 12:10:27 +0000126 (void)td;
127
Lev Walkin588bf0f2017-10-13 23:51:16 -0700128 num_arcs = OBJECT_IDENTIFIER_parse_arcs(
129 (const char *)chunk_buf, chunk_size, arcs,
130 sizeof(s_arcs) / sizeof(s_arcs[0]), &endptr);
131 if(num_arcs < 0) {
132 /* Expecting at least one arc arcs */
133 return XPBD_BROKEN_ENCODING;
134 } else if(num_arcs == 0) {
135 return XPBD_NOT_BODY_IGNORE;
136 }
137 assert(endptr == chunk_end);
Lev Walkin0fab1a62005-03-09 22:19:25 +0000138
Lev Walkin588bf0f2017-10-13 23:51:16 -0700139 if((size_t)num_arcs > sizeof(s_arcs) / sizeof(s_arcs[0])) {
140 arcs = (asn_oid_arc_t *)MALLOC(num_arcs * sizeof(arcs[0]));
141 if(!arcs) return XPBD_SYSTEM_FAILURE;
142 ret = OBJECT_IDENTIFIER_parse_arcs((const char *)chunk_buf, chunk_size,
143 arcs, num_arcs, &endptr);
144 if(ret != num_arcs) {
145 return XPBD_SYSTEM_FAILURE; /* assert?.. */
146 }
147 }
Lev Walkin92302252004-10-23 10:16:51 +0000148
Lev Walkin588bf0f2017-10-13 23:51:16 -0700149 /*
150 * Convert arcs into BER representation.
151 */
152 ret = RELATIVE_OID_set_arcs(st, arcs, num_arcs);
153 if(arcs != s_arcs) FREEMEM(arcs);
Lev Walkin92302252004-10-23 10:16:51 +0000154
Lev Walkin588bf0f2017-10-13 23:51:16 -0700155 return ret ? XPBD_SYSTEM_FAILURE : XPBD_BODY_CONSUMED;
Lev Walkin92302252004-10-23 10:16:51 +0000156}
157
158asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -0700159RELATIVE_OID_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin92302252004-10-23 10:16:51 +0000160 asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
Lev Walkin8c3b8542005-03-10 18:52:02 +0000161 const void *buf_ptr, size_t size) {
Lev Walkin92302252004-10-23 10:16:51 +0000162
163 return xer_decode_primitive(opt_codec_ctx, td,
164 sptr, sizeof(RELATIVE_OID_t), opt_mname,
165 buf_ptr, size, RELATIVE_OID__xer_body_decode);
166}
167
Lev Walkina9cc46e2004-09-22 16:06:28 +0000168asn_enc_rval_t
Lev Walkin5e033762004-09-29 13:26:15 +0000169RELATIVE_OID_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000170 int ilevel, enum xer_encoder_flags_e flags,
171 asn_app_consume_bytes_f *cb, void *app_key) {
172 RELATIVE_OID_t *st = (RELATIVE_OID_t *)sptr;
173 asn_enc_rval_t er;
174
175 (void)ilevel; /* Unused argument */
176 (void)flags; /* Unused argument */
177
178 if(!st || !st->buf)
Lev Walkin7c1dc052016-03-14 03:08:15 -0700179 ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000180
181 er.encoded = RELATIVE_OID__dump_body(st, cb, app_key);
Lev Walkin7c1dc052016-03-14 03:08:15 -0700182 if(er.encoded < 0) ASN__ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000183
Lev Walkin7c1dc052016-03-14 03:08:15 -0700184 ASN__ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000185}
Lev Walkinf15320b2004-06-03 03:38:44 +0000186
Lev Walkin588bf0f2017-10-13 23:51:16 -0700187ssize_t
188RELATIVE_OID_get_arcs(const RELATIVE_OID_t *st, asn_oid_arc_t *arcs,
189 size_t arcs_count) {
190 size_t num_arcs = 0;
191 size_t off;
Lev Walkinf15320b2004-06-03 03:38:44 +0000192
Lev Walkin588bf0f2017-10-13 23:51:16 -0700193 if(!st || !st->buf) {
194 errno = EINVAL;
195 return -1;
196 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000197
Lev Walkin588bf0f2017-10-13 23:51:16 -0700198 for(off = 0;;) {
199 asn_oid_arc_t arc;
200 ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off,
201 st->size - off, &arc);
202 if(rd < 0) {
203 return -1;
204 } else if(rd == 0) {
205 /* No more arcs. */
206 break;
207 } else {
208 off += rd;
209 if(num_arcs < arcs_count) {
210 arcs[num_arcs] = arc;
211 }
212 num_arcs++;
213 }
214 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000215
Lev Walkin588bf0f2017-10-13 23:51:16 -0700216 if(off != st->size) {
217 return -1;
218 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000219
Lev Walkin29a044b2004-06-14 07:24:36 +0000220 return num_arcs;
Lev Walkinf15320b2004-06-03 03:38:44 +0000221}
222
223int
Lev Walkin588bf0f2017-10-13 23:51:16 -0700224RELATIVE_OID_set_arcs(RELATIVE_OID_t *st, const asn_oid_arc_t *arcs,
225 size_t arcs_count) {
226 uint8_t *buf;
Lev Walkinf15320b2004-06-03 03:38:44 +0000227 uint8_t *bp;
Lev Walkin588bf0f2017-10-13 23:51:16 -0700228 size_t size;
229 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000230
Lev Walkin588bf0f2017-10-13 23:51:16 -0700231 if(!st || !arcs) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000232 errno = EINVAL;
233 return -1;
234 }
235
236 /*
237 * Roughly estimate the maximum size necessary to encode these arcs.
238 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700239 size = ((sizeof(asn_oid_arc_t) * CHAR_BIT + 6) / 7) * arcs_count;
240 bp = buf = (uint8_t *)MALLOC(size + 1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000241 if(!buf) {
242 /* ENOMEM */
243 return -1;
244 }
245
246 /*
Lev Walkin0787ff02004-06-17 23:43:39 +0000247 * Encode the arcs.
Lev Walkinf15320b2004-06-03 03:38:44 +0000248 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700249 for(i = 0; i < arcs_count; i++) {
250 ssize_t wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arcs[i]);
251 if(wrote <= 0) {
252 FREEMEM(buf);
253 return -1;
254 }
255 assert((size_t)wrote <= size);
256 bp += wrote;
257 size -= wrote;
258 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000259
Lev Walkin588bf0f2017-10-13 23:51:16 -0700260 assert(size >= 0);
Lev Walkin0787ff02004-06-17 23:43:39 +0000261
Lev Walkinf15320b2004-06-03 03:38:44 +0000262 /*
263 * Replace buffer.
264 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700265 st->size = bp - buf;
266 bp = st->buf;
267 st->buf = buf;
268 st->buf[st->size] = '\0';
Lev Walkinf15320b2004-06-03 03:38:44 +0000269 if(bp) FREEMEM(bp);
270
271 return 0;
272}
Lev Walkin0787ff02004-06-17 23:43:39 +0000273
Lev Walkina5972be2017-09-29 23:15:58 -0700274
275/*
276 * Generate values from the list of interesting values, or just a random value.
277 */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700278static asn_oid_arc_t
Lev Walkina5972be2017-09-29 23:15:58 -0700279RELATIVE_OID__biased_random_arc() {
280 static const uint16_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
281
Lev Walkinb5b524b2017-10-13 03:14:03 -0700282 switch(asn_random_between(0, 2)) {
283 case 0:
284 return values[asn_random_between(
285 0, sizeof(values) / sizeof(values[0]) - 1)];
286 case 1:
287 return asn_random_between(0, UINT_MAX);
288 case 2:
289 default:
290 return UINT_MAX;
Lev Walkina5972be2017-09-29 23:15:58 -0700291 }
Lev Walkina5972be2017-09-29 23:15:58 -0700292}
293
294asn_random_fill_result_t
295RELATIVE_OID_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkin588bf0f2017-10-13 23:51:16 -0700296 const asn_encoding_constraints_t *constraints,
297 size_t max_length) {
Lev Walkina5972be2017-09-29 23:15:58 -0700298 asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
299 asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
300 asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
301 RELATIVE_OID_t *st;
Lev Walkinb5b524b2017-10-13 03:14:03 -0700302 const int min_arcs = 1; /* A minimum of 1 arc is required */
Lev Walkin588bf0f2017-10-13 23:51:16 -0700303 asn_oid_arc_t arcs[3];
304 size_t arcs_len =
305 asn_random_between(min_arcs, sizeof(arcs) / sizeof(arcs[0]));
Lev Walkina5972be2017-09-29 23:15:58 -0700306 size_t i;
307
308 (void)constraints;
309
310 if(max_length < arcs_len) return result_skipped;
311
312 if(*sptr) {
313 st = *sptr;
314 } else {
315 st = CALLOC(1, sizeof(*st));
316 }
317
318 for(i = 0; i < arcs_len; i++) {
319 arcs[i] = RELATIVE_OID__biased_random_arc();
320 }
321
Lev Walkin588bf0f2017-10-13 23:51:16 -0700322 if(RELATIVE_OID_set_arcs(st, arcs, arcs_len)) {
Lev Walkina5972be2017-09-29 23:15:58 -0700323 if(st != *sptr) {
324 ASN_STRUCT_FREE(*td, st);
325 }
326 return result_failed;
327 }
328
329 *sptr = st;
330
Lev Walkin588bf0f2017-10-13 23:51:16 -0700331 result_ok.length = st->size;
Lev Walkina5972be2017-09-29 23:15:58 -0700332 return result_ok;
333}