blob: a156d0602ba3667d947ff171cadb52b46a791340 [file] [log] [blame]
vlmfa67ddc2004-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>
vlm2e3dd3b2004-06-14 07:24:36 +00006#include <limits.h> /* for CHAR_BIT */
vlmfa67ddc2004-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 */
vlmb42843a2004-06-05 08:17:50 +000028 0, /* Always in primitive form */
29 0 /* No specifics */
vlmfa67ddc2004-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
vlm3717fb32004-06-14 08:17:27 +000094
vlmfa67ddc2004-06-03 03:38:44 +000095int
vlm2e3dd3b2004-06-14 07:24:36 +000096OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbuf, unsigned int rvsize) {
97 unsigned LE = 1; /* Little endian (x86) */
98 uint8_t *arcend = arcbuf + arclen; /* End of arc */
99 void *rvstart = rvbuf; /* Original start of the value buffer */
100 unsigned int cache = 0; /* No more than 14 significant bits */
101 int inc; /* Return value growth direction */
vlmfa67ddc2004-06-03 03:38:44 +0000102
vlm2e3dd3b2004-06-14 07:24:36 +0000103 rvsize *= CHAR_BIT; /* bytes to bits */
104 arclen *= 7; /* bytes to bits */
105
106 /*
107 * The arc has the number of bits
108 * cannot be represented using supplied return value type.
109 */
110 if(arclen > rvsize) {
111 if(arclen > (rvsize + CHAR_BIT)) {
112 errno = ERANGE; /* Overflow */
113 return -1;
114 } else {
115 /*
116 * Even if the number of bits in the arc representation
117 * is higher than the width of supplied * return value
118 * type, there is still possible to fit it when there
119 * are few unused high bits in the arc value
120 * representaion.
121 */
122 uint8_t mask = (0xff << (7-(arclen - rvsize))) & 0x7f;
123 if((*arcbuf & mask)) {
vlmfa67ddc2004-06-03 03:38:44 +0000124 errno = ERANGE; /* Overflow */
125 return -1;
126 }
vlm2e3dd3b2004-06-14 07:24:36 +0000127 /* Fool the routine computing unused bits */
128 arclen -= 7;
129 cache = *arcbuf & 0x7f;
130 arcbuf++;
131 }
132 }
133
vlm3717fb32004-06-14 08:17:27 +0000134 /* Faster path for common size */
135 if(rvsize == (CHAR_BIT * sizeof(unsigned long))) {
136 unsigned long accum;
137 /* Gather all bits into the accumulator */
138 for(accum = cache; arcbuf < arcend; arcbuf++)
139 accum = (accum << 7) | (*arcbuf & ~0x80);
140 if(accum < (unsigned)-add) {
141 errno = ERANGE; /* Overflow */
142 return -1;
143 }
144 *(unsigned long *)rvbuf = accum + add;
145 return 0;
146 }
147
vlm2e3dd3b2004-06-14 07:24:36 +0000148#ifndef WORDS_BIGENDIAN
149 if(*(unsigned char *)&LE) { /* Little endian (x86) */
150 /* "Convert" to big endian */
vlm3717fb32004-06-14 08:17:27 +0000151 rvbuf += rvsize / CHAR_BIT - 1;
152 ((unsigned char *)rvstart)--;
vlm2e3dd3b2004-06-14 07:24:36 +0000153 inc = -1; /* Descending */
vlm3717fb32004-06-14 08:17:27 +0000154 } else
vlm2e3dd3b2004-06-14 07:24:36 +0000155#endif /* !WORDS_BIGENDIAN */
vlm3717fb32004-06-14 08:17:27 +0000156 inc = +1; /* Big endian is known [at compile time] */
vlm2e3dd3b2004-06-14 07:24:36 +0000157
vlm3717fb32004-06-14 08:17:27 +0000158 {
vlm2e3dd3b2004-06-14 07:24:36 +0000159 unsigned int bits; /* typically no more than 3-4 bits */
vlm3717fb32004-06-14 08:17:27 +0000160
vlm2e3dd3b2004-06-14 07:24:36 +0000161 /* Clear the high unused bits */
162 for(bits = rvsize - arclen;
163 bits > CHAR_BIT;
164 rvbuf += inc, bits -= CHAR_BIT)
165 *(unsigned char *)rvbuf = 0;
vlm3717fb32004-06-14 08:17:27 +0000166
vlm2e3dd3b2004-06-14 07:24:36 +0000167 /* Fill the body of a value */
168 for(; arcbuf < arcend; arcbuf++) {
169 cache = (cache << 7) | (*arcbuf & 0x7f);
170 bits += 7;
171 if(bits >= CHAR_BIT) {
172 bits -= CHAR_BIT;
173 *(unsigned char *)rvbuf = (cache >> bits);
174 rvbuf += inc;
175 }
176 }
177 if(bits) {
178 *(unsigned char *)rvbuf = cache;
179 rvbuf += inc;
180 }
181 }
182
183 if(add) {
184 for(rvbuf -= inc; rvbuf != rvstart; rvbuf -= inc) {
185 int v = add + *(unsigned char *)rvbuf;
186 if(v & (-1 << CHAR_BIT)) {
187 *(unsigned char *)rvbuf
188 = v + (1 << CHAR_BIT);
189 add = -1;
190 } else {
191 *(unsigned char *)rvbuf = v;
192 break;
193 }
194 }
195 if(rvbuf == rvstart) {
196 /* No space to carry over */
vlmfa67ddc2004-06-03 03:38:44 +0000197 errno = ERANGE; /* Overflow */
198 return -1;
199 }
200 }
201
vlmfa67ddc2004-06-03 03:38:44 +0000202 return 0;
203}
204
vlm2e3dd3b2004-06-14 07:24:36 +0000205
vlmfa67ddc2004-06-03 03:38:44 +0000206int
207OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add,
208 asn_app_consume_bytes_f *cb, void *app_key) {
209 char scratch[64]; /* Conservative estimate */
210 unsigned long accum; /* Bits accumulator */
211 char *p; /* Position in the scratch buffer */
212
vlm2e3dd3b2004-06-14 07:24:36 +0000213 if(OBJECT_IDENTIFIER_get_single_arc(arcbuf, arclen, add,
214 &accum, sizeof(accum)))
vlmfa67ddc2004-06-03 03:38:44 +0000215 return -1;
216
217 /* Fill the scratch buffer in reverse. */
218 p = scratch + sizeof(scratch);
219 for(; accum; accum /= 10)
220 *(--p) = (accum % 10) + 0x30;
221
222 return cb(p, sizeof(scratch) - (p - scratch), app_key);
223}
224
225int
226OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr,
227 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
228 const OBJECT_IDENTIFIER_t *st = sptr;
229 int startn;
230 int add = 0;
231 int i;
232
vlmb42843a2004-06-05 08:17:50 +0000233 (void)td; /* Unused argument */
234 (void)ilevel; /* Unused argument */
235
vlmfa67ddc2004-06-03 03:38:44 +0000236 if(!st || !st->buf)
237 return cb("<absent>", 8, app_key);
238
239 /* Dump preamble */
240 if(cb("{ ", 2, app_key))
241 return -1;
242
243 for(i = 0, startn = 0; i < st->size; i++) {
244 uint8_t b = st->buf[i];
245 if((b & 0x80)) /* Continuation expected */
246 continue;
247
248 if(startn == 0) {
249 /*
250 * First two arcs are encoded through the backdoor.
251 */
252 if(i) {
253 add = -80;
254 if(cb("2", 1, app_key)) return -1;
255 } else if(b <= 39) {
256 add = 0;
257 if(cb("0", 1, app_key)) return -1;
258 } else if(b < 79) {
259 add = -40;
260 if(cb("1", 1, app_key)) return -1;
261 } else {
262 add = -80;
263 if(cb("2", 1, app_key)) return -1;
264 }
265 }
266
267 if(cb(" ", 1, app_key)) /* Separate arcs */
268 return -1;
269
270 if(OBJECT_IDENTIFIER_print_arc(&st->buf[startn],
271 i - startn + 1, add,
272 cb, app_key))
273 return -1;
274 startn = i + 1;
275 add = 0;
276 }
277
278 return cb(" }", 2, app_key);
279}
280
281int
vlm2e3dd3b2004-06-14 07:24:36 +0000282OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *oid, void *arcs,
283 unsigned int arc_type_size, unsigned int arc_slots) {
284 void *arcs_end = arcs + (arc_type_size * arc_slots);
285 int num_arcs = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000286 int startn = 0;
287 int add = 0;
288 int i;
289
290 if(!oid || !oid->buf) {
291 errno = EINVAL;
292 return -1;
293 }
294
295 for(i = 0; i < oid->size; i++) {
296 uint8_t b = oid->buf[i];
297 if((b & 0x80)) /* Continuation expected */
298 continue;
299
vlm2e3dd3b2004-06-14 07:24:36 +0000300 if(num_arcs == 0) {
vlmfa67ddc2004-06-03 03:38:44 +0000301 /*
302 * First two arcs are encoded through the backdoor.
303 */
vlm2e3dd3b2004-06-14 07:24:36 +0000304 unsigned LE = 1; /* Little endian */
305 int first_arc;
306 num_arcs++;
307 if(!arc_slots) { num_arcs++; continue; }
308
309 if(i) first_arc = 2;
310 else if(b <= 39) first_arc = 0;
311 else if(b < 79) first_arc = 1;
312 else first_arc = 2;
313
314 add = -40 * first_arc;
315 memset(arcs, 0, arc_type_size);
316 *(unsigned char *)(arcs
317 + ((*(char *)&LE)?0:(arc_type_size - 1)))
318 = first_arc;
319 arcs += arc_type_size;
vlmfa67ddc2004-06-03 03:38:44 +0000320 }
321
vlm2e3dd3b2004-06-14 07:24:36 +0000322 /* Decode, if has space */
323 if(arcs < arcs_end) {
324 if(OBJECT_IDENTIFIER_get_single_arc(&oid->buf[startn],
325 i - startn + 1, add,
326 arcs, arc_type_size))
327 return -1;
vlmfa67ddc2004-06-03 03:38:44 +0000328 startn = i + 1;
vlm2e3dd3b2004-06-14 07:24:36 +0000329 arcs += arc_type_size;
330 add = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000331 }
vlm2e3dd3b2004-06-14 07:24:36 +0000332 num_arcs++;
vlmfa67ddc2004-06-03 03:38:44 +0000333 }
334
vlm2e3dd3b2004-06-14 07:24:36 +0000335 return num_arcs;
vlmfa67ddc2004-06-03 03:38:44 +0000336}
337
338int
vlm2e3dd3b2004-06-14 07:24:36 +0000339OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, unsigned int arc_slots) {
vlmfa67ddc2004-06-03 03:38:44 +0000340 uint8_t *buf;
341 uint8_t *bp;
342 unsigned long long first_value;
vlm3717fb32004-06-14 08:17:27 +0000343 unsigned i;
vlmfa67ddc2004-06-03 03:38:44 +0000344 int size;
vlmfa67ddc2004-06-03 03:38:44 +0000345
vlm2e3dd3b2004-06-14 07:24:36 +0000346 if(oid == NULL || arcs == NULL || arc_slots < 2) {
vlmfa67ddc2004-06-03 03:38:44 +0000347 errno = EINVAL;
348 return -1;
349 }
350
351 if(arcs[0] <= 1) {
352 if(arcs[1] >= 39) {
353 /* 8.19.4: At most 39 subsequent values (including 0) */
354 errno = ERANGE;
355 return -1;
356 }
357 } else if(arcs[0] > 2) {
358 /* 8.19.4: Only three values are allocated from the root node */
359 errno = ERANGE;
360 return -1;
361 }
362
363 first_value = arcs[0] * 40 + arcs[1];
364
365 /*
366 * Roughly estimate the maximum size necessary to encode these arcs.
367 */
vlm2e3dd3b2004-06-14 07:24:36 +0000368 size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arc_slots;
vlmfa67ddc2004-06-03 03:38:44 +0000369 bp = buf = MALLOC(size + 1);
370 if(!buf) {
371 /* ENOMEM */
372 return -1;
373 }
374
375 /*
376 * Encode the arcs and refine the encoding size.
377 */
378 size = 0;
379
380 {
381 uint8_t tbuf[sizeof(first_value) * 2];
382 uint8_t *tp = tbuf;
383 int arc_len = 0;
384 int add = 0;
385
386 for(; first_value; first_value >>= 7) {
387 unsigned int b7 = first_value & 0x7f;
388 *tp++ = 0x80 | b7;
389 add++;
390 if(b7) { arc_len += add; add = 0; }
391 }
392
393 if(arc_len) {
394 tp = &tbuf[arc_len - 1];
395 /* The last octet does not have bit 8 set. */
396 *tbuf &= 0x7f;
397 for(; tp >= tbuf; tp--)
398 *bp++ = *tp;
399 size += arc_len;
400 } else {
401 *bp++ = 0;
402 size++;
403 }
404 }
405
vlm2e3dd3b2004-06-14 07:24:36 +0000406 for(i = 2; i < arc_slots; i++) {
vlmfa67ddc2004-06-03 03:38:44 +0000407 unsigned long value = arcs[i];
408 uint8_t tbuf[sizeof(value) * 2]; /* Conservatively sized */
409 uint8_t *tp = tbuf;
410 int arc_len = 0;
411 int add = 0;
412
413 for(; value; value >>= 7) {
414 unsigned int b7 = value & 0x7F;
415 *tp++ = 0x80 | b7;
416 add++;
417 if(b7) { arc_len += add; add = 0; }
418 }
419
420 if(arc_len) {
421 tp = &tbuf[arc_len - 1];
422 /* The last octet does not have bit 8 set. */
423 *tbuf &= 0x7f;
424 for(; tp >= tbuf; tp--)
425 *bp++ = *tp;
426 size += arc_len;
427 } else {
428 *bp++ = 0;
429 size++;
430 }
431 }
432
433 /*
434 * Replace buffer.
435 */
436 oid->size = size;
437 bp = oid->buf;
438 oid->buf = buf;
439 if(bp) FREEMEM(bp);
440
441 return 0;
442}
vlm3717fb32004-06-14 08:17:27 +0000443