]> git.ipfire.org Git - thirdparty/squid.git/blame - snmplib/asn1.c
this does not compile on linux
[thirdparty/squid.git] / snmplib / asn1.c
CommitLineData
627f6d02 1/*
2 * Abstract Syntax Notation One, ASN.1
3 * As defined in ISO/IS 8824 and ISO/IS 8825
4 * This implements a subset of the above International Standards that
5 * is sufficient to implement SNMP.
6 *
7 * Encodes abstract data types into a machine independent stream of bytes.
8 *
9 */
10/**********************************************************************
11 Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
12
13 All Rights Reserved
14
15Permission to use, copy, modify, and distribute this software and its
16documentation for any purpose and without fee is hereby granted,
17provided that the above copyright notice appear in all copies and that
18both that copyright notice and this permission notice appear in
19supporting documentation, and that the name of CMU not be
20used in advertising or publicity pertaining to distribution of the
21software without specific, written prior permission.
22
23CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29SOFTWARE.
30******************************************************************/
627f6d02 31
db5edad5 32#include "config.h"
33
34#if HAVE_STDIO_H
627f6d02 35#include <stdio.h>
db5edad5 36#endif
37#if HAVE_STDLIB_H
627f6d02 38#include <stdlib.h>
db5edad5 39#endif
40#if HAVE_STRING_H
627f6d02 41#include <string.h>
42#endif
db5edad5 43#if HAVE_SYS_TYPES_H
627f6d02 44#include <sys/types.h>
db5edad5 45#endif
46#if HAVE_NETINET_IN_H
627f6d02 47#include <netinet/in.h>
627f6d02 48#endif
db5edad5 49#if HAVE_ASSERT_H
3265e68d 50#include <assert.h>
627f6d02 51#endif
52
db5edad5 53#include "asn1.h"
54
627f6d02 55#ifdef DEBUG
56#define ERROR(string) printf("%s(%d): %s",__FILE__, __LINE__, string);
57#else
58#define ERROR(string)
59#endif
60
61
62/*
63 * asn_parse_int - pulls a long out of an ASN int type.
64 * On entry, datalength is input as the number of valid bytes following
65 * "data". On exit, it is returned as the number of valid bytes
66 * following the end of this object.
67 *
68 * Returns a pointer to the first byte past the end
69 * of this object (i.e. the start of the next object).
70 * Returns NULL on any error.
71 */
72u_char *
29cd62b7 73asn_parse_int(
74 u_char * data, /* IN - pointer to start of object */
75 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
76 u_char * type, /* OUT - asn type of object */
77 long *intp, /* IN/OUT - pointer to start of output buffer */
78 int intsize)
79{ /* IN - size of output buffer */
627f6d02 80/*
81 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
82 */
83 u_char *bufp = data;
da2d50d1 84 u_long asn_length;
85 long value = 0;
627f6d02 86
da2d50d1 87 if (intsize != sizeof(long)) {
627f6d02 88 ERROR("not long");
89 return NULL;
90 }
91 *type = *bufp++;
92 bufp = asn_parse_length(bufp, &asn_length);
da2d50d1 93 if (bufp == NULL) {
627f6d02 94 ERROR("bad length");
95 return NULL;
96 }
da2d50d1 97 if (asn_length + (bufp - data) > *datalength) {
627f6d02 98 ERROR("overflow of message");
99 return NULL;
100 }
da2d50d1 101 if (asn_length > intsize) {
627f6d02 102 ERROR("I don't support such large integers");
103 return NULL;
104 }
da2d50d1 105 *datalength -= (int) asn_length + (bufp - data);
627f6d02 106 if (*bufp & 0x80)
da2d50d1 107 value = -1; /* integer is negative */
108 while (asn_length--)
627f6d02 109 value = (value << 8) | *bufp++;
110 *intp = value;
111 return bufp;
112}
113
114
115/*
116 * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
117 * On entry, datalength is input as the number of valid bytes following
118 * "data". On exit, it is returned as the number of valid bytes
119 * following the end of this object.
120 *
121 * Returns a pointer to the first byte past the end
122 * of this object (i.e. the start of the next object).
123 * Returns NULL on any error.
124 */
125u_char *
29cd62b7 126asn_parse_unsigned_int(
127 u_char * data, /* IN - pointer to start of object */
128 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
129 u_char * type, /* OUT - asn type of object */
130 u_long * intp, /* IN/OUT - pointer to start of output buffer */
131 int intsize)
132{ /* IN - size of output buffer */
627f6d02 133/*
134 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
135 */
136 u_char *bufp = data;
da2d50d1 137 u_long asn_length;
627f6d02 138 u_long value = 0;
139
da2d50d1 140 if (intsize != sizeof(long)) {
627f6d02 141 ERROR("not long");
142 return NULL;
143 }
144 *type = *bufp++;
145 bufp = asn_parse_length(bufp, &asn_length);
da2d50d1 146 if (bufp == NULL) {
627f6d02 147 ERROR("bad length");
148 return NULL;
149 }
da2d50d1 150 if (asn_length + (bufp - data) > *datalength) {
627f6d02 151 ERROR("overflow of message");
152 return NULL;
153 }
154 if ((asn_length > (intsize + 1)) ||
da2d50d1 155 ((asn_length == intsize + 1) && *bufp != 0x00)) {
627f6d02 156 ERROR("I don't support such large integers");
157 return NULL;
158 }
da2d50d1 159 *datalength -= (int) asn_length + (bufp - data);
627f6d02 160 if (*bufp & 0x80)
da2d50d1 161 value = -1; /* integer is negative */
162 while (asn_length--)
627f6d02 163 value = (value << 8) | *bufp++;
164 *intp = value;
165 return bufp;
166}
167
168
169/*
170 * asn_build_int - builds an ASN object containing an integer.
171 * On entry, datalength is input as the number of valid bytes following
172 * "data". On exit, it is returned as the number of valid bytes
173 * following the end of this object.
174 *
175 * Returns a pointer to the first byte past the end
176 * of this object (i.e. the start of the next object).
177 * Returns NULL on any error.
178 */
179u_char *
29cd62b7 180asn_build_int(
181 u_char * data, /* IN - pointer to start of output buffer */
182 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
183 u_char type, /* IN - asn type of object */
184 long *intp, /* IN - pointer to start of long integer */
185 int intsize)
186{ /* IN - size of *intp */
627f6d02 187/*
188 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
189 */
190
191 long integer;
192 u_long mask;
193
da2d50d1 194 if (intsize != sizeof(long)) {
627f6d02 195 ERROR("not long");
196 return NULL;
197 }
198 integer = *intp;
199 /*
200 * Truncate "unnecessary" bytes off of the most significant end of this
201 * 2's complement integer. There should be no sequence of 9
202 * consecutive 1's or 0's at the most significant end of the
203 * integer.
204 */
264ca1b0 205 mask = 0x1FF << ((8 * (NUM32LEN - 1)) - 1);
627f6d02 206 /* mask is 0xFF800000 on a big-endian machine */
da2d50d1 207 while ((((integer & mask) == 0) || ((integer & mask) == mask))
208 && intsize > 1) {
627f6d02 209 intsize--;
210 integer <<= 8;
211 }
212 data = asn_build_header(data, datalength, type, intsize);
213 if (data == NULL)
214 return NULL;
215 if (*datalength < intsize)
216 return NULL;
217 *datalength -= intsize;
264ca1b0 218 mask = 0xFF << (8 * (NUM32LEN - 1));
627f6d02 219 /* mask is 0xFF000000 on a big-endian machine */
da2d50d1 220 while (intsize--) {
264ca1b0 221 *data++ = (u_char) ((integer & mask) >> (8 * (NUM32LEN - 1)));
627f6d02 222 integer <<= 8;
223 }
224 return data;
225}
226
227
228/*
229 * asn_build_unsigned_int - builds an ASN object containing an integer.
230 * On entry, datalength is input as the number of valid bytes following
231 * "data". On exit, it is returned as the number of valid bytes
232 * following the end of this object.
233 *
234 * Returns a pointer to the first byte past the end
235 * of this object (i.e. the start of the next object).
236 * Returns NULL on any error.
237 */
238u_char *
29cd62b7 239asn_build_unsigned_int(
240 u_char * data, /* IN - pointer to start of output buffer */
241 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
242 u_char type, /* IN - asn type of object */
243 u_long * intp, /* IN - pointer to start of long integer */
244 int intsize)
245{ /* IN - size of *intp */
627f6d02 246/*
247 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
248 */
249
250 u_long integer;
251 u_long mask;
252 int add_null_byte = 0;
253
da2d50d1 254 if (intsize != sizeof(long)) {
627f6d02 255 ERROR("not long");
256 return NULL;
257 }
258 integer = *intp;
264ca1b0 259 mask = 0xFF << (8 * (NUM32LEN - 1));
627f6d02 260 /* mask is 0xFF000000 on a big-endian machine */
264ca1b0 261 if ((u_char) ((integer & mask) >> (8 * (NUM32LEN - 1))) & 0x80) {
627f6d02 262 /* if MSB is set */
263 add_null_byte = 1;
264 intsize++;
265 }
266 /*
267 * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
268 * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
269 * integer.
270 */
264ca1b0 271 mask = 0x1FF << ((8 * (NUM32LEN - 1)) - 1);
627f6d02 272 /* mask is 0xFF800000 on a big-endian machine */
da2d50d1 273 while ((((integer & mask) == 0) || ((integer & mask) == mask)) && intsize > 1) {
627f6d02 274 intsize--;
275 integer <<= 8;
276 }
277 data = asn_build_header(data, datalength, type, intsize);
278 if (data == NULL)
279 return NULL;
280 if (*datalength < intsize)
281 return NULL;
282 *datalength -= intsize;
da2d50d1 283 if (add_null_byte == 1) {
627f6d02 284 *data++ = '\0';
285 intsize--;
286 }
264ca1b0 287 mask = 0xFF << (8 * (NUM32LEN - 1));
627f6d02 288 /* mask is 0xFF000000 on a big-endian machine */
da2d50d1 289 while (intsize--) {
264ca1b0 290 *data++ = (u_char) ((integer & mask) >> (8 * (NUM32LEN - 1)));
627f6d02 291 integer <<= 8;
292 }
293 return data;
294}
295
296
297/*
298 * asn_parse_string - pulls an octet string out of an ASN octet string type.
299 * On entry, datalength is input as the number of valid bytes following
300 * "data". On exit, it is returned as the number of valid bytes
301 * following the beginning of the next object.
302 *
303 * "string" is filled with the octet string.
304 *
305 * Returns a pointer to the first byte past the end
306 * of this object (i.e. the start of the next object).
307 * Returns NULL on any error.
308 */
309u_char *
29cd62b7 310asn_parse_string(
311 u_char * data, /* IN - pointer to start of object */
312 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
313 u_char * type, /* OUT - asn type of object */
314 u_char * string, /* IN/OUT - pointer to start of output buffer */
315 int *strlength)
316{ /* IN/OUT - size of output buffer */
627f6d02 317/*
318 * ASN.1 octet string ::= primstring | cmpdstring
319 * primstring ::= 0x04 asnlength byte {byte}*
320 * cmpdstring ::= 0x24 asnlength string {string}*
321 */
322 u_char *bufp = data;
da2d50d1 323 u_long asn_length;
627f6d02 324
325 *type = *bufp++;
326 bufp = asn_parse_length(bufp, &asn_length);
327 if (bufp == NULL)
328 return NULL;
da2d50d1 329 if (asn_length + (bufp - data) > *datalength) {
627f6d02 330 ERROR("overflow of message");
331 return NULL;
332 }
da2d50d1 333 if (asn_length > *strlength) {
627f6d02 334 ERROR("I don't support such long strings");
335 return NULL;
336 }
29cd62b7 337 xmemcpy(string, bufp, (int) asn_length);
da2d50d1 338 *strlength = (int) asn_length;
339 *datalength -= (int) asn_length + (bufp - data);
627f6d02 340 return bufp + asn_length;
341}
342
343
344/*
345 * asn_build_string - Builds an ASN octet string object containing the input string.
346 * On entry, datalength is input as the number of valid bytes following
347 * "data". On exit, it is returned as the number of valid bytes
348 * following the beginning of the next object.
349 *
350 * Returns a pointer to the first byte past the end
351 * of this object (i.e. the start of the next object).
352 * Returns NULL on any error.
353 */
354u_char *
29cd62b7 355asn_build_string(
356 u_char * data, /* IN - pointer to start of object */
357 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
358 u_char type, /* IN - ASN type of string */
359 u_char * string, /* IN - pointer to start of input buffer */
360 int strlength)
361{ /* IN - size of input buffer */
627f6d02 362/*
363 * ASN.1 octet string ::= primstring | cmpdstring
364 * primstring ::= 0x04 asnlength byte {byte}*
365 * cmpdstring ::= 0x24 asnlength string {string}*
366 * This code will never send a compound string.
367 */
368 data = asn_build_header(data, datalength, type, strlength);
369 if (data == NULL)
370 return NULL;
371 if (*datalength < strlength)
372 return NULL;
29cd62b7 373 xmemcpy(data, string, strlength);
627f6d02 374 *datalength -= strlength;
375 return data + strlength;
376}
377
378
379/*
380 * asn_parse_header - interprets the ID and length of the current object.
381 * On entry, datalength is input as the number of valid bytes following
382 * "data". On exit, it is returned as the number of valid bytes
383 * in this object following the id and length.
384 *
385 * Returns a pointer to the first byte of the contents of this object.
386 * Returns NULL on any error.
387 */
388u_char *
29cd62b7 389asn_parse_header(
390 u_char * data, /* IN - pointer to start of object */
391 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
392 u_char * type)
393{ /* OUT - ASN type of object */
627f6d02 394 u_char *bufp = data;
395 int header_len;
396 u_long asn_length;
397
398 if (*datalength <= 0) {
399 return NULL;
400 }
627f6d02 401 /* this only works on data types < 30, i.e. no extension octets */
da2d50d1 402 if (IS_EXTENSION_ID(*bufp)) {
627f6d02 403 ERROR("can't process ID >= 30");
404 return NULL;
405 }
406 *type = *bufp;
407 bufp = asn_parse_length(bufp + 1, &asn_length);
408 if (bufp == NULL)
409 return NULL;
410 header_len = bufp - data;
da2d50d1 411 if (header_len + asn_length > *datalength) {
627f6d02 412 ERROR("asn length too long");
413 return NULL;
414 }
da2d50d1 415 *datalength = (int) asn_length;
627f6d02 416 return bufp;
417}
418
419/*
420 * asn_build_header - builds an ASN header for an object with the ID and
421 * length specified.
422 * On entry, datalength is input as the number of valid bytes following
423 * "data". On exit, it is returned as the number of valid bytes
424 * in this object following the id and length.
425 *
426 * This only works on data types < 30, i.e. no extension octets.
427 * The maximum length is 0xFFFF;
428 *
429 * Returns a pointer to the first byte of the contents of this object.
430 * Returns NULL on any error.
431 */
432u_char *
29cd62b7 433asn_build_header(
434 u_char * data, /* IN - pointer to start of object */
435 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
436 u_char type, /* IN - ASN type of object */
437 int length)
438{ /* IN - length of object */
627f6d02 439 if (*datalength < 1)
440 return NULL;
441 *data++ = type;
442 (*datalength)--;
443 return asn_build_length(data, datalength, length);
da2d50d1 444
627f6d02 445}
446
447/*
448 * asn_build_sequence - builds an ASN header for a sequence with the ID and
449 * length specified.
450 * On entry, datalength is input as the number of valid bytes following
451 * "data". On exit, it is returned as the number of valid bytes
452 * in this object following the id and length.
453 *
454 * This only works on data types < 30, i.e. no extension octets.
455 * The maximum length is 0xFFFF;
456 *
457 * Returns a pointer to the first byte of the contents of this object.
458 * Returns NULL on any error.
459 */
460u_char *
29cd62b7 461asn_build_sequence(
462 u_char * data, /* IN - pointer to start of object */
463 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
464 u_char type, /* IN - ASN type of object */
465 int length)
466{ /* IN - length of object */
be335c22 467 assert(*datalength >= 0);
627f6d02 468 *datalength -= 4;
da2d50d1 469 if (*datalength < 0) {
627f6d02 470 *datalength += 4; /* fix up before punting */
471 return NULL;
472 }
473 *data++ = type;
da2d50d1 474 *data++ = (u_char) (0x02 | ASN_LONG_LEN);
475 *data++ = (u_char) ((length >> 8) & 0xFF);
476 *data++ = (u_char) (length & 0xFF);
627f6d02 477 return data;
478}
479
480/*
481 * asn_parse_length - interprets the length of the current object.
482 * On exit, length contains the value of this length field.
483 *
484 * Returns a pointer to the first byte after this length
485 * field (aka: the start of the data field).
486 * Returns NULL on any error.
487 */
488u_char *
29cd62b7 489asn_parse_length(
490 u_char * data, /* IN - pointer to start of length field */
491 u_long * length)
492{ /* OUT - value of length field */
627f6d02 493 u_char lengthbyte = *data;
494
495 *length = 0;
da2d50d1 496 if (lengthbyte & ASN_LONG_LEN) {
627f6d02 497 lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
da2d50d1 498 if (lengthbyte == 0) {
627f6d02 499 ERROR("We don't support indefinite lengths");
500 return NULL;
501 }
da2d50d1 502 if (lengthbyte > sizeof(long)) {
627f6d02 503 ERROR("we can't support data lengths that long");
504 return NULL;
505 }
29cd62b7 506 xmemcpy(length, data + 1, (int) lengthbyte);
627f6d02 507 /* XXX: is this useable on a 64bit platform ? */
508 *length = ntohl(*length);
da2d50d1 509 *length >>= (8 * ((sizeof(*length)) - lengthbyte));
627f6d02 510 return data + lengthbyte + 1;
da2d50d1 511 } else { /* short asnlength */
512 *length = (long) lengthbyte;
627f6d02 513 return data + 1;
514 }
515}
516
517u_char *
29cd62b7 518asn_build_length(
519 u_char * data, /* IN - pointer to start of object */
520 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
521 int length)
522{ /* IN - length of object */
da2d50d1 523 u_char *start_data = data;
627f6d02 524
525 /* no indefinite lengths sent */
da2d50d1 526 if (length < 0x80) {
527 if (*datalength < 1) {
627f6d02 528 ERROR("build_length");
529 return NULL;
da2d50d1 530 }
531 *data++ = (u_char) length;
532 } else if (length <= 0xFF) {
533 if (*datalength < 2) {
627f6d02 534 ERROR("build_length");
535 return NULL;
da2d50d1 536 }
537 *data++ = (u_char) (0x01 | ASN_LONG_LEN);
538 *data++ = (u_char) length;
539 } else { /* 0xFF < length <= 0xFFFF */
540 if (*datalength < 3) {
627f6d02 541 ERROR("build_length");
542 return NULL;
da2d50d1 543 }
544 *data++ = (u_char) (0x02 | ASN_LONG_LEN);
545 *data++ = (u_char) ((length >> 8) & 0xFF);
546 *data++ = (u_char) (length & 0xFF);
627f6d02 547 }
548 *datalength -= (data - start_data);
549 return data;
550
551}
552
553/*
554 * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
555 * On entry, datalength is input as the number of valid bytes following
556 * "data". On exit, it is returned as the number of valid bytes
557 * following the beginning of the next object.
558 *
559 * "objid" is filled with the object identifier.
560 *
561 * Returns a pointer to the first byte past the end
562 * of this object (i.e. the start of the next object).
563 * Returns NULL on any error.
564 */
565u_char *
29cd62b7 566asn_parse_objid(
567 u_char * data, /* IN - pointer to start of object */
568 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
569 u_char * type, /* OUT - ASN type of object */
570 oid * objid, /* IN/OUT - pointer to start of output buffer */
571 int *objidlength)
572{ /* IN/OUT - number of sub-id's in objid */
627f6d02 573/*
574 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
575 * subidentifier ::= {leadingbyte}* lastbyte
576 * leadingbyte ::= 1 7bitvalue
577 * lastbyte ::= 0 7bitvalue
578 */
579 u_char *bufp = data;
580 oid *oidp = objid + 1;
581 u_long subidentifier;
da2d50d1 582 long length;
583 u_long asn_length;
627f6d02 584
585 *type = *bufp++;
586 bufp = asn_parse_length(bufp, &asn_length);
587 if (bufp == NULL)
588 return NULL;
da2d50d1 589 if (asn_length + (bufp - data) > *datalength) {
627f6d02 590 ERROR("overflow of message");
591 return NULL;
592 }
da2d50d1 593 *datalength -= (int) asn_length + (bufp - data);
627f6d02 594
595 /* Handle invalid object identifier encodings of the form 06 00 robustly */
596 if (asn_length == 0)
597 objid[0] = objid[1] = 0;
598
599 length = asn_length;
da2d50d1 600 (*objidlength)--; /* account for expansion of first byte */
601 while (length > 0 && (*objidlength)-- > 0) {
627f6d02 602 subidentifier = 0;
da2d50d1 603 do { /* shift and add in low order 7 bits */
604 subidentifier = (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
627f6d02 605 length--;
da2d50d1 606 } while (*(u_char *) bufp++ & ASN_BIT8); /* last byte has high bit clear */
607 if (subidentifier > (u_long) MAX_SUBID) {
627f6d02 608 ERROR("subidentifier too long");
609 return NULL;
610 }
da2d50d1 611 *oidp++ = (oid) subidentifier;
627f6d02 612 }
613
614 /*
615 * The first two subidentifiers are encoded into the first component
616 * with the value (X * 40) + Y, where:
da2d50d1 617 * X is the value of the first subidentifier.
627f6d02 618 * Y is the value of the second subidentifier.
619 */
da2d50d1 620 subidentifier = (u_long) objid[1];
621 if (subidentifier == 0x2B) {
627f6d02 622 objid[0] = 1;
623 objid[1] = 3;
624 } else {
da2d50d1 625 objid[1] = (u_char) (subidentifier % 40);
626 objid[0] = (u_char) ((subidentifier - objid[1]) / 40);
627f6d02 627 }
628
da2d50d1 629 *objidlength = (int) (oidp - objid);
627f6d02 630 return bufp;
631}
632
633/*
634 * asn_build_objid - Builds an ASN object identifier object containing the
635 * input string.
636 * On entry, datalength is input as the number of valid bytes following
637 * "data". On exit, it is returned as the number of valid bytes
638 * following the beginning of the next object.
639 *
640 * Returns a pointer to the first byte past the end
641 * of this object (i.e. the start of the next object).
642 * Returns NULL on any error.
643 */
644u_char *
29cd62b7 645asn_build_objid(
646 u_char * data, /* IN - pointer to start of object */
647 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
648 u_char type, /* IN - ASN type of object */
649 oid * objid, /* IN - pointer to start of input buffer */
650 int objidlength)
651{ /* IN - number of sub-id's in objid */
627f6d02 652/*
653 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
654 * subidentifier ::= {leadingbyte}* lastbyte
655 * leadingbyte ::= 1 7bitvalue
656 * lastbyte ::= 0 7bitvalue
657 */
658 u_char buf[MAX_OID_LEN];
659 u_char *bp = buf;
660 oid *op = objid;
da2d50d1 661 int asnlength;
627f6d02 662 u_long subid, mask, testmask;
663 int bits, testbits;
664
da2d50d1 665 if (objidlength < 2) {
627f6d02 666 *bp++ = 0;
667 objidlength = 0;
668 } else {
669 *bp++ = op[1] + (op[0] * 40);
670 objidlength -= 2;
671 op += 2;
672 }
673
da2d50d1 674 while (objidlength-- > 0) {
627f6d02 675 subid = *op++;
da2d50d1 676 if (subid < 127) { /* off by one? */
627f6d02 677 *bp++ = subid;
678 } else {
da2d50d1 679 mask = 0x7F; /* handle subid == 0 case */
627f6d02 680 bits = 0;
681 /* testmask *MUST* !!!! be of an unsigned type */
da2d50d1 682 for (testmask = 0x7F, testbits = 0; testmask != 0;
683 testmask <<= 7, testbits += 7) {
684 if (subid & testmask) { /* if any bits set */
627f6d02 685 mask = testmask;
686 bits = testbits;
687 }
688 }
689 /* mask can't be zero here */
da2d50d1 690 for (; mask != 0x7F; mask >>= 7, bits -= 7) {
627f6d02 691 /* fix a mask that got truncated above */
da2d50d1 692 if (mask == 0x1E00000)
627f6d02 693 mask = 0xFE00000;
da2d50d1 694 *bp++ = (u_char) (((subid & mask) >> bits) | ASN_BIT8);
627f6d02 695 }
da2d50d1 696 *bp++ = (u_char) (subid & mask);
627f6d02 697 }
698 }
699 asnlength = bp - buf;
700 data = asn_build_header(data, datalength, type, asnlength);
701 if (data == NULL)
702 return NULL;
703 if (*datalength < asnlength)
704 return NULL;
29cd62b7 705 xmemcpy(data, buf, asnlength);
627f6d02 706 *datalength -= asnlength;
707 return data + asnlength;
708}
709
710/*
711 * asn_parse_null - Interprets an ASN null type.
712 * On entry, datalength is input as the number of valid bytes following
713 * "data". On exit, it is returned as the number of valid bytes
714 * following the beginning of the next object.
715 *
716 * Returns a pointer to the first byte past the end
717 * of this object (i.e. the start of the next object).
718 * Returns NULL on any error.
719 */
720u_char *
29cd62b7 721asn_parse_null(
722 u_char * data, /* IN - pointer to start of object */
723 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
724 u_char * type)
725{ /* OUT - ASN type of object */
627f6d02 726/*
727 * ASN.1 null ::= 0x05 0x00
728 */
da2d50d1 729 u_char *bufp = data;
730 u_long asn_length;
627f6d02 731
732 *type = *bufp++;
733 bufp = asn_parse_length(bufp, &asn_length);
734 if (bufp == NULL)
735 return NULL;
da2d50d1 736 if (asn_length != 0) {
627f6d02 737 ERROR("Malformed NULL");
738 return NULL;
739 }
740 *datalength -= (bufp - data);
741 return bufp + asn_length;
742}
743
744
745/*
746 * asn_build_null - Builds an ASN null object.
747 * On entry, datalength is input as the number of valid bytes following
748 * "data". On exit, it is returned as the number of valid bytes
749 * following the beginning of the next object.
750 *
751 * Returns a pointer to the first byte past the end
752 * of this object (i.e. the start of the next object).
753 * Returns NULL on any error.
754 */
755u_char *
29cd62b7 756asn_build_null(
757 u_char * data, /* IN - pointer to start of object */
758 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
759 u_char type)
760{ /* IN - ASN type of object */
627f6d02 761/*
762 * ASN.1 null ::= 0x05 0x00
763 */
764 return asn_build_header(data, datalength, type, 0);
765}
766
767/*
768 * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
769 * On entry, datalength is input as the number of valid bytes following
770 * "data". On exit, it is returned as the number of valid bytes
771 * following the beginning of the next object.
772 *
773 * "string" is filled with the bit string.
774 *
775 * Returns a pointer to the first byte past the end
776 * of this object (i.e. the start of the next object).
777 * Returns NULL on any error.
778 */
779u_char *
29cd62b7 780asn_parse_bitstring(
781 u_char * data, /* IN - pointer to start of object */
782 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
783 u_char * type, /* OUT - asn type of object */
784 u_char * string, /* IN/OUT - pointer to start of output buffer */
785 int *strlength)
786{ /* IN/OUT - size of output buffer */
627f6d02 787/*
788 * bitstring ::= 0x03 asnlength unused {byte}*
789 */
790 u_char *bufp = data;
da2d50d1 791 u_long asn_length;
627f6d02 792
793 *type = *bufp++;
794 bufp = asn_parse_length(bufp, &asn_length);
795 if (bufp == NULL)
796 return NULL;
da2d50d1 797 if (asn_length + (bufp - data) > *datalength) {
627f6d02 798 ERROR("overflow of message");
799 return NULL;
800 }
da2d50d1 801 if (asn_length > *strlength) {
627f6d02 802 ERROR("I don't support such long bitstrings");
803 return NULL;
804 }
da2d50d1 805 if (asn_length < 1) {
627f6d02 806 ERROR("Invalid bitstring");
807 return NULL;
808 }
da2d50d1 809 if ( /** *bufp < 0 || **/ *bufp > 7) {
627f6d02 810 ERROR("Invalid bitstring");
811 return NULL;
812 }
29cd62b7 813 xmemcpy(string, bufp, (int) asn_length);
da2d50d1 814 *strlength = (int) asn_length;
815 *datalength -= (int) asn_length + (bufp - data);
627f6d02 816 return bufp + asn_length;
817}
818
819
820/*
821 * asn_build_bitstring - Builds an ASN bit string object containing the
822 * input string.
823 * On entry, datalength is input as the number of valid bytes following
824 * "data". On exit, it is returned as the number of valid bytes
825 * following the beginning of the next object.
826 *
827 * Returns a pointer to the first byte past the end
828 * of this object (i.e. the start of the next object).
829 * Returns NULL on any error.
830 */
831u_char *
29cd62b7 832asn_build_bitstring(
833 u_char * data, /* IN - pointer to start of object */
834 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
835 u_char type, /* IN - ASN type of string */
836 u_char * string, /* IN - pointer to start of input buffer */
837 int strlength)
838{ /* IN - size of input buffer */
627f6d02 839/*
840 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
841 */
da2d50d1 842 if (strlength < 1 || /** *string < 0 || **/ *string > 7) {
627f6d02 843 ERROR("Building invalid bitstring");
844 return NULL;
845 }
846 data = asn_build_header(data, datalength, type, strlength);
847 if (data == NULL)
848 return NULL;
849 if (*datalength < strlength)
850 return NULL;
29cd62b7 851 xmemcpy(data, string, strlength);
627f6d02 852 *datalength -= strlength;
853 return data + strlength;
854}
855
856
857/*
858 * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
859 * type.
860 * On entry, datalength is input as the number of valid bytes following
861 * "data". On exit, it is returned as the number of valid bytes
862 * following the end of this object.
863 *
864 * Returns a pointer to the first byte past the end
865 * of this object (i.e. the start of the next object).
866 * Returns NULL on any error.
867 */
868u_char *
29cd62b7 869asn_parse_unsigned_int64(
870 u_char * data, /* IN - pointer to start of object */
871 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
872 u_char * type, /* OUT - asn type of object */
873 struct counter64 * cp, /* IN/OUT -pointer to counter struct */
874 int countersize)
875{ /* IN - size of output buffer */
627f6d02 876/*
877 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
878 */
879 u_char *bufp = data;
da2d50d1 880 u_long asn_length;
627f6d02 881 u_long low = 0, high = 0;
882 int intsize = 4;
da2d50d1 883
884 if (countersize != sizeof(struct counter64)) {
627f6d02 885 ERROR("not counter64 size");
886 return NULL;
887 }
888 *type = *bufp++;
889 bufp = asn_parse_length(bufp, &asn_length);
da2d50d1 890 if (bufp == NULL) {
627f6d02 891 ERROR("bad length");
892 return NULL;
893 }
da2d50d1 894 if (asn_length + (bufp - data) > *datalength) {
627f6d02 895 ERROR("overflow of message");
896 return NULL;
897 }
898 if ((asn_length > (intsize * 2 + 1)) ||
da2d50d1 899 ((asn_length == (intsize * 2) + 1) && *bufp != 0x00)) {
627f6d02 900 ERROR("I don't support such large integers");
901 return NULL;
902 }
da2d50d1 903 *datalength -= (int) asn_length + (bufp - data);
904 if (*bufp & 0x80) {
905 low = -1; /* integer is negative */
627f6d02 906 high = -1;
907 }
da2d50d1 908 while (asn_length--) {
627f6d02 909 high = (high << 8) | ((low & 0xFF000000) >> 24);
910 low = (low << 8) | *bufp++;
911 }
912 cp->low = low;
913 cp->high = high;
914 return bufp;
915}
916
917
918/*
919 * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
920 * On entry, datalength is input as the number of valid bytes following
921 * "data". On exit, it is returned as the number of valid bytes
922 * following the end of this object.
923 *
924 * Returns a pointer to the first byte past the end
925 * of this object (i.e. the start of the next object).
926 * Returns NULL on any error.
927 */
928u_char *
29cd62b7 929asn_build_unsigned_int64(
930 u_char * data, /* IN - pointer to start of output buffer */
931 int *datalength, /* IN/OUT - number of valid bytes left in buffer */
932 u_char type, /* IN - asn type of object */
933 struct counter64 * cp, /* IN - pointer to counter struct */
934 int countersize)
935{ /* IN - size of *intp */
627f6d02 936/*
937 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
938 */
939
264ca1b0 940 u_num32 low, high;
941 u_num32 mask, mask2;
627f6d02 942 int add_null_byte = 0;
943 int intsize;
944
da2d50d1 945 if (countersize != sizeof(struct counter64)) {
627f6d02 946 ERROR("not counter64 size");
947 return NULL;
948 }
949 intsize = 8;
950 low = cp->low;
951 high = cp->high;
264ca1b0 952 mask = 0xFF << (8 * (NUM32LEN - 1));
627f6d02 953 /* mask is 0xFF000000 on a big-endian machine */
264ca1b0 954 if ((u_char) ((high & mask) >> (8 * (NUM32LEN - 1))) & 0x80) {
627f6d02 955 /* if MSB is set */
956 add_null_byte = 1;
957 intsize++;
958 }
959 /*
960 * Truncate "unnecessary" bytes off of the most significant end of this 2's
961 * complement integer.
962 * There should be no sequence of 9 consecutive 1's or 0's at the most
963 * significant end of the integer.
964 */
264ca1b0 965 mask2 = 0x1FF << ((8 * (NUM32LEN - 1)) - 1);
627f6d02 966 /* mask2 is 0xFF800000 on a big-endian machine */
da2d50d1 967 while ((((high & mask2) == 0) || ((high & mask2) == mask2))
968 && intsize > 1) {
627f6d02 969 intsize--;
970 high = (high << 8)
264ca1b0 971 | ((low & mask) >> (8 * (NUM32LEN - 1)));
627f6d02 972 low <<= 8;
973 }
974 data = asn_build_header(data, datalength, type, intsize);
975 if (data == NULL)
976 return NULL;
977 if (*datalength < intsize)
978 return NULL;
979 *datalength -= intsize;
da2d50d1 980 if (add_null_byte == 1) {
627f6d02 981 *data++ = '\0';
982 intsize--;
983 }
da2d50d1 984 while (intsize--) {
264ca1b0 985 *data++ = (u_char) ((high & mask) >> (8 * (NUM32LEN - 1)));
627f6d02 986 high = (high << 8)
264ca1b0 987 | ((low & mask) >> (8 * (NUM32LEN - 1)));
627f6d02 988 low <<= 8;
da2d50d1 989
627f6d02 990 }
991 return data;
992}