blob: 0a27c8cac1ac59feb10d1940346232f67ae8c4e0 [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 */
5#include <OBJECT_IDENTIFIER.h>
6#include <assert.h>
7#include <errno.h>
8
9/*
10 * OBJECT IDENTIFIER basic type description.
11 */
12static ber_tlv_tag_t asn1_DEF_OBJECT_IDENTIFIER_tags[] = {
13 (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
14};
15asn1_TYPE_descriptor_t asn1_DEF_OBJECT_IDENTIFIER = {
16 "OBJECT IDENTIFIER",
17 OBJECT_IDENTIFIER_constraint,
18 INTEGER_decode_ber, /* Implemented in terms of INTEGER type */
19 OBJECT_IDENTIFIER_encode_der,
20 OBJECT_IDENTIFIER_print,
21 INTEGER_free,
22 0, /* Use generic outmost tag fetcher */
23 asn1_DEF_OBJECT_IDENTIFIER_tags,
24 sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags)
25 / sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags[0]),
26 1, /* Single UNIVERSAL tag may be implicitly overriden */
Lev Walkind9bd7752004-06-05 08:17:50 +000027 0, /* Always in primitive form */
28 0 /* No specifics */
Lev Walkinf15320b2004-06-03 03:38:44 +000029};
30
31
32/*
33 * Encode OBJECT IDENTIFIER type using DER.
34 */
35der_enc_rval_t
36OBJECT_IDENTIFIER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
37 int tag_mode, ber_tlv_tag_t tag,
38 asn_app_consume_bytes_f *cb, void *app_key) {
39 der_enc_rval_t erval;
40 OBJECT_IDENTIFIER_t *st = ptr;
41
42 ASN_DEBUG("%s %s as OBJECT IDENTIFIER (tm=%d)",
43 cb?"Encoding":"Estimating", sd->name, tag_mode);
44
45 erval.encoded = der_write_tags(sd, st->size, tag_mode, tag,
46 cb, app_key);
47 ASN_DEBUG("OBJECT IDENTIFIER %s wrote tags %d",
48 sd->name, (int)erval.encoded);
49 if(erval.encoded == -1) {
50 erval.failed_type = sd;
51 erval.structure_ptr = ptr;
52 return erval;
53 }
54
55 if(cb && st->buf) {
56 ssize_t ret;
57
58 ret = cb(st->buf, st->size, app_key);
59 if(ret == -1) {
60 erval.encoded = -1;
61 erval.failed_type = sd;
62 erval.structure_ptr = ptr;
63 return erval;
64 }
65 } else {
66 assert(st->buf || st->size == 0);
67 }
68
69 erval.encoded += st->size;
70
71 return erval;
72}
73
74int
75OBJECT_IDENTIFIER_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
76 asn_app_consume_bytes_f *app_errlog, void *app_key) {
77 const OBJECT_IDENTIFIER_t *st = sptr;
78
79 if(st && st->buf) {
80 if(st->size < 1) {
81 _ASN_ERRLOG("%s: at least one numerical value expected",
82 td->name);
83 return -1;
84 }
85 } else {
86 _ASN_ERRLOG("%s: value not given", td->name);
87 return -1;
88 }
89
90 return 0;
91}
92
93int
94OBJECT_IDENTIFIER_get_arc_l(uint8_t *arcbuf, int arclen, int add, unsigned long *rvalue) {
95 unsigned long accum;
96 uint8_t *arcend = arcbuf + arclen;
97
Lev Walkind9bd7752004-06-05 08:17:50 +000098 if((size_t)arclen * 7 > 8 * sizeof(accum)) {
99 if((size_t)arclen * 7 <= 8 * (sizeof(accum) + 1)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000100 if((*arcbuf & ~0x8f)) {
101 errno = ERANGE; /* Overflow */
102 return -1;
103 }
104 } else {
105 errno = ERANGE; /* Overflow */
106 return -1;
107 }
108 }
109
110 /* Gather all bits into the accumulator */
111 for(accum = 0; arcbuf < arcend; arcbuf++)
112 accum = (accum << 7) | (*arcbuf & ~0x80);
113
Lev Walkind9bd7752004-06-05 08:17:50 +0000114 assert(accum >= (unsigned long)-add);
Lev Walkinf15320b2004-06-03 03:38:44 +0000115 accum += add; /* Actually, a negative value */
Lev Walkinf15320b2004-06-03 03:38:44 +0000116
117 *rvalue = accum;
118
119 return 0;
120}
121
122int
123OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
124 asn_app_consume_bytes_f *cb, void *app_key) {
125 char scratch[64]; /* Conservative estimate */
126 unsigned long accum; /* Bits accumulator */
127 char *p; /* Position in the scratch buffer */
128
129 if(OBJECT_IDENTIFIER_get_arc_l(arcbuf, arclen, add, &accum))
130 return -1;
131
132 /* Fill the scratch buffer in reverse. */
133 p = scratch + sizeof(scratch);
134 for(; accum; accum /= 10)
135 *(--p) = (accum % 10) + 0x30;
136
137 return cb(p, sizeof(scratch) - (p - scratch), app_key);
138}
139
140int
141OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr,
142 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
143 const OBJECT_IDENTIFIER_t *st = sptr;
144 int startn;
145 int add = 0;
146 int i;
147
Lev Walkind9bd7752004-06-05 08:17:50 +0000148 (void)td; /* Unused argument */
149 (void)ilevel; /* Unused argument */
150
Lev Walkinf15320b2004-06-03 03:38:44 +0000151 if(!st || !st->buf)
152 return cb("<absent>", 8, app_key);
153
154 /* Dump preamble */
155 if(cb("{ ", 2, app_key))
156 return -1;
157
158 for(i = 0, startn = 0; i < st->size; i++) {
159 uint8_t b = st->buf[i];
160 if((b & 0x80)) /* Continuation expected */
161 continue;
162
163 if(startn == 0) {
164 /*
165 * First two arcs are encoded through the backdoor.
166 */
167 if(i) {
168 add = -80;
169 if(cb("2", 1, app_key)) return -1;
170 } else if(b <= 39) {
171 add = 0;
172 if(cb("0", 1, app_key)) return -1;
173 } else if(b < 79) {
174 add = -40;
175 if(cb("1", 1, app_key)) return -1;
176 } else {
177 add = -80;
178 if(cb("2", 1, app_key)) return -1;
179 }
180 }
181
182 if(cb(" ", 1, app_key)) /* Separate arcs */
183 return -1;
184
185 if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
186 i - startn + 1, add,
187 cb, app_key))
188 return -1;
189 startn = i + 1;
190 add = 0;
191 }
192
193 return cb(" }", 2, app_key);
194}
195
196int
197OBJECT_IDENTIFIER_get_arcs_l(OBJECT_IDENTIFIER_t *oid,
198 unsigned long *arcs, int arcs_slots) {
199 unsigned long arc_value;
200 int cur_arc = 0;
201 int startn = 0;
202 int add = 0;
203 int i;
204
205 if(!oid || !oid->buf) {
206 errno = EINVAL;
207 return -1;
208 }
209
210 for(i = 0; i < oid->size; i++) {
211 uint8_t b = oid->buf[i];
212 if((b & 0x80)) /* Continuation expected */
213 continue;
214
215 if(startn == 0) {
216 /*
217 * First two arcs are encoded through the backdoor.
218 */
219 if(i) {
220 add = -80;
221 if(cur_arc < arcs_slots) arcs[cur_arc] = 2;
222 cur_arc++;
223 } else if(b <= 39) {
224 add = 0;
225 if(cur_arc < arcs_slots) arcs[cur_arc] = 0;
226 cur_arc++;
227 } else if(b < 79) {
228 add = -40;
229 if(cur_arc < arcs_slots) arcs[cur_arc] = 1;
230 cur_arc++;
231 } else {
232 add = -80;
233 if(cur_arc < arcs_slots) arcs[cur_arc] = 2;
234 cur_arc++;
235 }
236 }
237
238 /* Do not fill */
239 if(cur_arc >= arcs_slots) {
240 startn = i + 1;
241 continue;
242 }
243
244 if(OBJECT_IDENTIFIER_get_arc_l(&oid->buf[startn],
245 i - startn + 1,
246 add, &arc_value))
247 return -1;
248 arcs[cur_arc++] = arc_value;
249 startn = i + 1;
250 add = 0;
251 }
252
253 return cur_arc;
254}
255
256int
257OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, int arcs_slots) {
258 uint8_t *buf;
259 uint8_t *bp;
260 unsigned long long first_value;
261 int size;
262 int i;
263
264 if(oid == NULL || arcs == NULL || arcs_slots < 2) {
265 errno = EINVAL;
266 return -1;
267 }
268
269 if(arcs[0] <= 1) {
270 if(arcs[1] >= 39) {
271 /* 8.19.4: At most 39 subsequent values (including 0) */
272 errno = ERANGE;
273 return -1;
274 }
275 } else if(arcs[0] > 2) {
276 /* 8.19.4: Only three values are allocated from the root node */
277 errno = ERANGE;
278 return -1;
279 }
280
281 first_value = arcs[0] * 40 + arcs[1];
282
283 /*
284 * Roughly estimate the maximum size necessary to encode these arcs.
285 */
286 size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arcs_slots;
287 bp = buf = MALLOC(size + 1);
288 if(!buf) {
289 /* ENOMEM */
290 return -1;
291 }
292
293 /*
294 * Encode the arcs and refine the encoding size.
295 */
296 size = 0;
297
298 {
299 uint8_t tbuf[sizeof(first_value) * 2];
300 uint8_t *tp = tbuf;
301 int arc_len = 0;
302 int add = 0;
303
304 for(; first_value; first_value >>= 7) {
305 unsigned int b7 = first_value & 0x7f;
306 *tp++ = 0x80 | b7;
307 add++;
308 if(b7) { arc_len += add; add = 0; }
309 }
310
311 if(arc_len) {
312 tp = &tbuf[arc_len - 1];
313 /* The last octet does not have bit 8 set. */
314 *tbuf &= 0x7f;
315 for(; tp >= tbuf; tp--)
316 *bp++ = *tp;
317 size += arc_len;
318 } else {
319 *bp++ = 0;
320 size++;
321 }
322 }
323
324 for(i = 2; i < arcs_slots; i++) {
325 unsigned long value = arcs[i];
326 uint8_t tbuf[sizeof(value) * 2]; /* Conservatively sized */
327 uint8_t *tp = tbuf;
328 int arc_len = 0;
329 int add = 0;
330
331 for(; value; value >>= 7) {
332 unsigned int b7 = value & 0x7F;
333 *tp++ = 0x80 | b7;
334 add++;
335 if(b7) { arc_len += add; add = 0; }
336 }
337
338 if(arc_len) {
339 tp = &tbuf[arc_len - 1];
340 /* The last octet does not have bit 8 set. */
341 *tbuf &= 0x7f;
342 for(; tp >= tbuf; tp--)
343 *bp++ = *tp;
344 size += arc_len;
345 } else {
346 *bp++ = 0;
347 size++;
348 }
349 }
350
351 /*
352 * Replace buffer.
353 */
354 oid->size = size;
355 bp = oid->buf;
356 oid->buf = buf;
357 if(bp) FREEMEM(bp);
358
359 return 0;
360}