blob: c4176160baf6f23ffba9500171d64f41dd1c6272 [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>
Lev Walkin29a044b2004-06-14 07:24:36 +00006#include <limits.h> /* for CHAR_BIT */
Lev Walkinf15320b2004-06-03 03:38:44 +00007#include <assert.h>
8#include <errno.h>
9
10/*
11 * OBJECT IDENTIFIER basic type description.
12 */
13static ber_tlv_tag_t asn1_DEF_OBJECT_IDENTIFIER_tags[] = {
14 (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
15};
16asn1_TYPE_descriptor_t asn1_DEF_OBJECT_IDENTIFIER = {
17 "OBJECT IDENTIFIER",
18 OBJECT_IDENTIFIER_constraint,
19 INTEGER_decode_ber, /* Implemented in terms of INTEGER type */
20 OBJECT_IDENTIFIER_encode_der,
21 OBJECT_IDENTIFIER_print,
22 INTEGER_free,
23 0, /* Use generic outmost tag fetcher */
24 asn1_DEF_OBJECT_IDENTIFIER_tags,
25 sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags)
26 / sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags[0]),
27 1, /* Single UNIVERSAL tag may be implicitly overriden */
Lev Walkind9bd7752004-06-05 08:17:50 +000028 0, /* Always in primitive form */
29 0 /* No specifics */
Lev Walkinf15320b2004-06-03 03:38:44 +000030};
31
32
33/*
34 * Encode OBJECT IDENTIFIER type using DER.
35 */
36der_enc_rval_t
37OBJECT_IDENTIFIER_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
38 int tag_mode, ber_tlv_tag_t tag,
39 asn_app_consume_bytes_f *cb, void *app_key) {
40 der_enc_rval_t erval;
41 OBJECT_IDENTIFIER_t *st = ptr;
42
43 ASN_DEBUG("%s %s as OBJECT IDENTIFIER (tm=%d)",
44 cb?"Encoding":"Estimating", sd->name, tag_mode);
45
46 erval.encoded = der_write_tags(sd, st->size, tag_mode, tag,
47 cb, app_key);
48 ASN_DEBUG("OBJECT IDENTIFIER %s wrote tags %d",
49 sd->name, (int)erval.encoded);
50 if(erval.encoded == -1) {
51 erval.failed_type = sd;
52 erval.structure_ptr = ptr;
53 return erval;
54 }
55
56 if(cb && st->buf) {
57 ssize_t ret;
58
59 ret = cb(st->buf, st->size, app_key);
60 if(ret == -1) {
61 erval.encoded = -1;
62 erval.failed_type = sd;
63 erval.structure_ptr = ptr;
64 return erval;
65 }
66 } else {
67 assert(st->buf || st->size == 0);
68 }
69
70 erval.encoded += st->size;
71
72 return erval;
73}
74
75int
76OBJECT_IDENTIFIER_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
77 asn_app_consume_bytes_f *app_errlog, void *app_key) {
78 const OBJECT_IDENTIFIER_t *st = sptr;
79
80 if(st && st->buf) {
81 if(st->size < 1) {
82 _ASN_ERRLOG("%s: at least one numerical value expected",
83 td->name);
84 return -1;
85 }
86 } else {
87 _ASN_ERRLOG("%s: value not given", td->name);
88 return -1;
89 }
90
91 return 0;
92}
93
94int
Lev Walkin29a044b2004-06-14 07:24:36 +000095OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbuf, unsigned int rvsize) {
96 unsigned LE = 1; /* Little endian (x86) */
97 uint8_t *arcend = arcbuf + arclen; /* End of arc */
98 void *rvstart = rvbuf; /* Original start of the value buffer */
99 unsigned int cache = 0; /* No more than 14 significant bits */
100 int inc; /* Return value growth direction */
Lev Walkinf15320b2004-06-03 03:38:44 +0000101
Lev Walkin29a044b2004-06-14 07:24:36 +0000102 rvsize *= CHAR_BIT; /* bytes to bits */
103 arclen *= 7; /* bytes to bits */
104
105 /*
106 * The arc has the number of bits
107 * cannot be represented using supplied return value type.
108 */
109 if(arclen > rvsize) {
110 if(arclen > (rvsize + CHAR_BIT)) {
111 errno = ERANGE; /* Overflow */
112 return -1;
113 } else {
114 /*
115 * Even if the number of bits in the arc representation
116 * is higher than the width of supplied * return value
117 * type, there is still possible to fit it when there
118 * are few unused high bits in the arc value
119 * representaion.
120 */
121 uint8_t mask = (0xff << (7-(arclen - rvsize))) & 0x7f;
122 if((*arcbuf & mask)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000123 errno = ERANGE; /* Overflow */
124 return -1;
125 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000126 /* Fool the routine computing unused bits */
127 arclen -= 7;
128 cache = *arcbuf & 0x7f;
129 arcbuf++;
130 }
131 }
132
133#ifndef WORDS_BIGENDIAN
134 if(*(unsigned char *)&LE) { /* Little endian (x86) */
135 /* "Convert" to big endian */
136 rvbuf += rvsize / CHAR_BIT;
137 inc = -1; /* Descending */
138 } else {
139 inc = +1; /* Ascending */
140 }
141#endif /* !WORDS_BIGENDIAN */
142
143 { /* Native big endian (Sparc, PPC) */
144 unsigned int bits; /* typically no more than 3-4 bits */
145 /* Clear the high unused bits */
146 for(bits = rvsize - arclen;
147 bits > CHAR_BIT;
148 rvbuf += inc, bits -= CHAR_BIT)
149 *(unsigned char *)rvbuf = 0;
150 /* Fill the body of a value */
151 for(; arcbuf < arcend; arcbuf++) {
152 cache = (cache << 7) | (*arcbuf & 0x7f);
153 bits += 7;
154 if(bits >= CHAR_BIT) {
155 bits -= CHAR_BIT;
156 *(unsigned char *)rvbuf = (cache >> bits);
157 rvbuf += inc;
158 }
159 }
160 if(bits) {
161 *(unsigned char *)rvbuf = cache;
162 rvbuf += inc;
163 }
164 }
165
166 if(add) {
167 for(rvbuf -= inc; rvbuf != rvstart; rvbuf -= inc) {
168 int v = add + *(unsigned char *)rvbuf;
169 if(v & (-1 << CHAR_BIT)) {
170 *(unsigned char *)rvbuf
171 = v + (1 << CHAR_BIT);
172 add = -1;
173 } else {
174 *(unsigned char *)rvbuf = v;
175 break;
176 }
177 }
178 if(rvbuf == rvstart) {
179 /* No space to carry over */
Lev Walkinf15320b2004-06-03 03:38:44 +0000180 errno = ERANGE; /* Overflow */
181 return -1;
182 }
183 }
184
Lev Walkinf15320b2004-06-03 03:38:44 +0000185 return 0;
186}
187
Lev Walkin29a044b2004-06-14 07:24:36 +0000188
Lev Walkinf15320b2004-06-03 03:38:44 +0000189int
190OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
191 asn_app_consume_bytes_f *cb, void *app_key) {
192 char scratch[64]; /* Conservative estimate */
193 unsigned long accum; /* Bits accumulator */
194 char *p; /* Position in the scratch buffer */
195
Lev Walkin29a044b2004-06-14 07:24:36 +0000196 if(OBJECT_IDENTIFIER_get_single_arc(arcbuf, arclen, add,
197 &accum, sizeof(accum)))
Lev Walkinf15320b2004-06-03 03:38:44 +0000198 return -1;
199
200 /* Fill the scratch buffer in reverse. */
201 p = scratch + sizeof(scratch);
202 for(; accum; accum /= 10)
203 *(--p) = (accum % 10) + 0x30;
204
205 return cb(p, sizeof(scratch) - (p - scratch), app_key);
206}
207
208int
209OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr,
210 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
211 const OBJECT_IDENTIFIER_t *st = sptr;
212 int startn;
213 int add = 0;
214 int i;
215
Lev Walkind9bd7752004-06-05 08:17:50 +0000216 (void)td; /* Unused argument */
217 (void)ilevel; /* Unused argument */
218
Lev Walkinf15320b2004-06-03 03:38:44 +0000219 if(!st || !st->buf)
220 return cb("<absent>", 8, app_key);
221
222 /* Dump preamble */
223 if(cb("{ ", 2, app_key))
224 return -1;
225
226 for(i = 0, startn = 0; i < st->size; i++) {
227 uint8_t b = st->buf[i];
228 if((b & 0x80)) /* Continuation expected */
229 continue;
230
231 if(startn == 0) {
232 /*
233 * First two arcs are encoded through the backdoor.
234 */
235 if(i) {
236 add = -80;
237 if(cb("2", 1, app_key)) return -1;
238 } else if(b <= 39) {
239 add = 0;
240 if(cb("0", 1, app_key)) return -1;
241 } else if(b < 79) {
242 add = -40;
243 if(cb("1", 1, app_key)) return -1;
244 } else {
245 add = -80;
246 if(cb("2", 1, app_key)) return -1;
247 }
248 }
249
250 if(cb(" ", 1, app_key)) /* Separate arcs */
251 return -1;
252
253 if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
254 i - startn + 1, add,
255 cb, app_key))
256 return -1;
257 startn = i + 1;
258 add = 0;
259 }
260
261 return cb(" }", 2, app_key);
262}
263
264int
Lev Walkin29a044b2004-06-14 07:24:36 +0000265OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *oid, void *arcs,
266 unsigned int arc_type_size, unsigned int arc_slots) {
267 void *arcs_end = arcs + (arc_type_size * arc_slots);
268 int num_arcs = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000269 int startn = 0;
270 int add = 0;
271 int i;
272
273 if(!oid || !oid->buf) {
274 errno = EINVAL;
275 return -1;
276 }
277
278 for(i = 0; i < oid->size; i++) {
279 uint8_t b = oid->buf[i];
280 if((b & 0x80)) /* Continuation expected */
281 continue;
282
Lev Walkin29a044b2004-06-14 07:24:36 +0000283 if(num_arcs == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000284 /*
285 * First two arcs are encoded through the backdoor.
286 */
Lev Walkin29a044b2004-06-14 07:24:36 +0000287 unsigned LE = 1; /* Little endian */
288 int first_arc;
289 num_arcs++;
290 if(!arc_slots) { num_arcs++; continue; }
291
292 if(i) first_arc = 2;
293 else if(b <= 39) first_arc = 0;
294 else if(b < 79) first_arc = 1;
295 else first_arc = 2;
296
297 add = -40 * first_arc;
298 memset(arcs, 0, arc_type_size);
299 *(unsigned char *)(arcs
300 + ((*(char *)&LE)?0:(arc_type_size - 1)))
301 = first_arc;
302 arcs += arc_type_size;
Lev Walkinf15320b2004-06-03 03:38:44 +0000303 }
304
Lev Walkin29a044b2004-06-14 07:24:36 +0000305 /* Decode, if has space */
306 if(arcs < arcs_end) {
307 if(OBJECT_IDENTIFIER_get_single_arc(&oid->buf[startn],
308 i - startn + 1, add,
309 arcs, arc_type_size))
310 return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000311 startn = i + 1;
Lev Walkin29a044b2004-06-14 07:24:36 +0000312 arcs += arc_type_size;
313 add = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000314 }
Lev Walkin29a044b2004-06-14 07:24:36 +0000315 num_arcs++;
Lev Walkinf15320b2004-06-03 03:38:44 +0000316 }
317
Lev Walkin29a044b2004-06-14 07:24:36 +0000318 return num_arcs;
Lev Walkinf15320b2004-06-03 03:38:44 +0000319}
320
321int
Lev Walkin29a044b2004-06-14 07:24:36 +0000322OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, unsigned int arc_slots) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000323 uint8_t *buf;
324 uint8_t *bp;
325 unsigned long long first_value;
326 int size;
327 int i;
328
Lev Walkin29a044b2004-06-14 07:24:36 +0000329 if(oid == NULL || arcs == NULL || arc_slots < 2) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000330 errno = EINVAL;
331 return -1;
332 }
333
334 if(arcs[0] <= 1) {
335 if(arcs[1] >= 39) {
336 /* 8.19.4: At most 39 subsequent values (including 0) */
337 errno = ERANGE;
338 return -1;
339 }
340 } else if(arcs[0] > 2) {
341 /* 8.19.4: Only three values are allocated from the root node */
342 errno = ERANGE;
343 return -1;
344 }
345
346 first_value = arcs[0] * 40 + arcs[1];
347
348 /*
349 * Roughly estimate the maximum size necessary to encode these arcs.
350 */
Lev Walkin29a044b2004-06-14 07:24:36 +0000351 size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arc_slots;
Lev Walkinf15320b2004-06-03 03:38:44 +0000352 bp = buf = MALLOC(size + 1);
353 if(!buf) {
354 /* ENOMEM */
355 return -1;
356 }
357
358 /*
359 * Encode the arcs and refine the encoding size.
360 */
361 size = 0;
362
363 {
364 uint8_t tbuf[sizeof(first_value) * 2];
365 uint8_t *tp = tbuf;
366 int arc_len = 0;
367 int add = 0;
368
369 for(; first_value; first_value >>= 7) {
370 unsigned int b7 = first_value & 0x7f;
371 *tp++ = 0x80 | b7;
372 add++;
373 if(b7) { arc_len += add; add = 0; }
374 }
375
376 if(arc_len) {
377 tp = &tbuf[arc_len - 1];
378 /* The last octet does not have bit 8 set. */
379 *tbuf &= 0x7f;
380 for(; tp >= tbuf; tp--)
381 *bp++ = *tp;
382 size += arc_len;
383 } else {
384 *bp++ = 0;
385 size++;
386 }
387 }
388
Lev Walkin29a044b2004-06-14 07:24:36 +0000389 for(i = 2; i < arc_slots; i++) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000390 unsigned long value = arcs[i];
391 uint8_t tbuf[sizeof(value) * 2]; /* Conservatively sized */
392 uint8_t *tp = tbuf;
393 int arc_len = 0;
394 int add = 0;
395
396 for(; value; value >>= 7) {
397 unsigned int b7 = value & 0x7F;
398 *tp++ = 0x80 | b7;
399 add++;
400 if(b7) { arc_len += add; add = 0; }
401 }
402
403 if(arc_len) {
404 tp = &tbuf[arc_len - 1];
405 /* The last octet does not have bit 8 set. */
406 *tbuf &= 0x7f;
407 for(; tp >= tbuf; tp--)
408 *bp++ = *tp;
409 size += arc_len;
410 } else {
411 *bp++ = 0;
412 size++;
413 }
414 }
415
416 /*
417 * Replace buffer.
418 */
419 oid->size = size;
420 bp = oid->buf;
421 oid->buf = buf;
422 if(bp) FREEMEM(bp);
423
424 return 0;
425}