]> git.ipfire.org Git - thirdparty/squid.git/blame - snmplib/asn1.c
SNMP, cmu derived, heavily modified
[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******************************************************************/
31#ifdef KINETICS
32#include "gw.h"
33#endif
34
35#ifdef linux
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#endif
40
41#include <sys/types.h>
42#include <netinet/in.h>
43
44#ifdef vms
45#include <in.h>
46#endif
47
48
49#include "asn1.h"
50
51#ifndef NULL
52#define NULL 0
53#endif
54
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 *
73asn_parse_int(data, datalength, type, intp, intsize)
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; /* IN - size of output buffer */
79{
80/*
81 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
82 */
83 u_char *bufp = data;
84 u_long asn_length;
85 long value = 0;
86
87 if (intsize != sizeof (long)){
88 ERROR("not long");
89 return NULL;
90 }
91 *type = *bufp++;
92 bufp = asn_parse_length(bufp, &asn_length);
93 if (bufp == NULL){
94 ERROR("bad length");
95 return NULL;
96 }
97 if (asn_length + (bufp - data) > *datalength){
98 ERROR("overflow of message");
99 return NULL;
100 }
101 if (asn_length > intsize){
102 ERROR("I don't support such large integers");
103 return NULL;
104 }
105 *datalength -= (int)asn_length + (bufp - data);
106 if (*bufp & 0x80)
107 value = -1; /* integer is negative */
108 while(asn_length--)
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 *
126asn_parse_unsigned_int(data, datalength, type, intp, intsize)
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; /* IN - size of output buffer */
132{
133/*
134 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
135 */
136 u_char *bufp = data;
137 u_long asn_length;
138 u_long value = 0;
139
140 if (intsize != sizeof (long)){
141 ERROR("not long");
142 return NULL;
143 }
144 *type = *bufp++;
145 bufp = asn_parse_length(bufp, &asn_length);
146 if (bufp == NULL){
147 ERROR("bad length");
148 return NULL;
149 }
150 if (asn_length + (bufp - data) > *datalength){
151 ERROR("overflow of message");
152 return NULL;
153 }
154 if ((asn_length > (intsize + 1)) ||
155 ((asn_length == intsize + 1) && *bufp != 0x00)){
156 ERROR("I don't support such large integers");
157 return NULL;
158 }
159 *datalength -= (int)asn_length + (bufp - data);
160 if (*bufp & 0x80)
161 value = -1; /* integer is negative */
162 while(asn_length--)
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 *
180asn_build_int(data, datalength, type, intp, intsize)
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; /* IN - size of *intp */
186{
187/*
188 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
189 */
190
191 long integer;
192 u_long mask;
193
194 if (intsize != sizeof (long)) {
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 */
205 mask = 0x1FF << ((8 * (sizeof(int32) - 1)) - 1);
206 /* mask is 0xFF800000 on a big-endian machine */
207 while((((integer & mask) == 0) || ((integer & mask) == mask))
208 && intsize > 1){
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;
218 mask = 0xFF << (8 * (sizeof(int32) - 1));
219 /* mask is 0xFF000000 on a big-endian machine */
220 while(intsize--){
221 *data++ = (u_char)((integer & mask) >> (8 * (sizeof(int32) - 1)));
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 *
239asn_build_unsigned_int(data, datalength, type, intp, intsize)
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; /* IN - size of *intp */
245{
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
254 if (intsize != sizeof (long)) {
255 ERROR("not long");
256 return NULL;
257 }
258 integer = *intp;
259 mask = 0xFF << (8 * (sizeof(int32) - 1));
260 /* mask is 0xFF000000 on a big-endian machine */
261 if ((u_char)((integer & mask) >> (8 * (sizeof(int32) - 1))) & 0x80){
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 */
271 mask = 0x1FF << ((8 * (sizeof(int32) - 1)) - 1);
272 /* mask is 0xFF800000 on a big-endian machine */
273 while((((integer & mask) == 0) || ((integer & mask) == mask)) && intsize > 1){
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;
283 if (add_null_byte == 1){
284 *data++ = '\0';
285 intsize--;
286 }
287 mask = 0xFF << (8 * (sizeof(int32) - 1));
288 /* mask is 0xFF000000 on a big-endian machine */
289 while(intsize--){
290 *data++ = (u_char)((integer & mask) >> (8 * (sizeof(int32) - 1)));
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 *
310asn_parse_string(data, datalength, type, string, strlength)
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; /* IN/OUT - size of output buffer */
316{
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;
323 u_long asn_length;
324
325 *type = *bufp++;
326 bufp = asn_parse_length(bufp, &asn_length);
327 if (bufp == NULL)
328 return NULL;
329 if (asn_length + (bufp - data) > *datalength){
330 ERROR("overflow of message");
331 return NULL;
332 }
333 if (asn_length > *strlength){
334 ERROR("I don't support such long strings");
335 return NULL;
336 }
337 bcopy((char *)bufp, (char *)string, (int)asn_length);
338 *strlength = (int)asn_length;
339 *datalength -= (int)asn_length + (bufp - data);
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 *
355asn_build_string(data, datalength, type, string, strlength)
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; /* IN - size of input buffer */
361{
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;
373 bcopy((char *)string, (char *)data, strlength);
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 *
389asn_parse_header(data, datalength, type)
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; /* OUT - ASN type of object */
393{
394 u_char *bufp = data;
395 int header_len;
396 u_long asn_length;
397
398 if (*datalength <= 0) {
399 return NULL;
400 }
401
402 /* this only works on data types < 30, i.e. no extension octets */
403 if (IS_EXTENSION_ID(*bufp)){
404 ERROR("can't process ID >= 30");
405 return NULL;
406 }
407 *type = *bufp;
408 bufp = asn_parse_length(bufp + 1, &asn_length);
409 if (bufp == NULL)
410 return NULL;
411 header_len = bufp - data;
412 if (header_len + asn_length > *datalength){
413 ERROR("asn length too long");
414 return NULL;
415 }
416 *datalength = (int)asn_length;
417 return bufp;
418}
419
420/*
421 * asn_build_header - builds an ASN header for an object with the ID and
422 * length specified.
423 * On entry, datalength is input as the number of valid bytes following
424 * "data". On exit, it is returned as the number of valid bytes
425 * in this object following the id and length.
426 *
427 * This only works on data types < 30, i.e. no extension octets.
428 * The maximum length is 0xFFFF;
429 *
430 * Returns a pointer to the first byte of the contents of this object.
431 * Returns NULL on any error.
432 */
433u_char *
434asn_build_header(data, datalength, type, length)
435 u_char *data; /* IN - pointer to start of object */
436 int *datalength;/* IN/OUT - number of valid bytes left in buffer */
437 u_char type; /* IN - ASN type of object */
438 int length; /* IN - length of object */
439{
440 if (*datalength < 1)
441 return NULL;
442 *data++ = type;
443 (*datalength)--;
444 return asn_build_length(data, datalength, length);
445
446}
447
448/*
449 * asn_build_sequence - builds an ASN header for a sequence with the ID and
450 * length specified.
451 * On entry, datalength is input as the number of valid bytes following
452 * "data". On exit, it is returned as the number of valid bytes
453 * in this object following the id and length.
454 *
455 * This only works on data types < 30, i.e. no extension octets.
456 * The maximum length is 0xFFFF;
457 *
458 * Returns a pointer to the first byte of the contents of this object.
459 * Returns NULL on any error.
460 */
461u_char *
462asn_build_sequence(data, datalength, type, length)
463 u_char *data; /* IN - pointer to start of object */
464 int *datalength;/* IN/OUT - number of valid bytes left in buffer */
465 u_char type; /* IN - ASN type of object */
466 int length; /* IN - length of object */
467{
468 *datalength -= 4;
469 if (*datalength < 0){
470 *datalength += 4; /* fix up before punting */
471 return NULL;
472 }
473 *data++ = type;
474 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
475 *data++ = (u_char)((length >> 8) & 0xFF);
476 *data++ = (u_char)(length & 0xFF);
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 *
489asn_parse_length(data, length)
490 u_char *data; /* IN - pointer to start of length field */
491 u_long *length; /* OUT - value of length field */
492{
493 u_char lengthbyte = *data;
494
495 *length = 0;
496 if (lengthbyte & ASN_LONG_LEN){
497 lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
498 if (lengthbyte == 0){
499 ERROR("We don't support indefinite lengths");
500 return NULL;
501 }
502 if (lengthbyte > sizeof(long)){
503 ERROR("we can't support data lengths that long");
504 return NULL;
505 }
506 bcopy((char *)data + 1, (char *)length, (int)lengthbyte);
507 /* XXX: is this useable on a 64bit platform ? */
508 *length = ntohl(*length);
509 *length >>= (8 * ((sizeof (*length)) - lengthbyte));
510 return data + lengthbyte + 1;
511 } else { /* short asnlength */
512 *length = (long)lengthbyte;
513 return data + 1;
514 }
515}
516
517u_char *
518asn_build_length(data, datalength, 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; /* IN - length of object */
522{
523 u_char *start_data = data;
524
525 /* no indefinite lengths sent */
526 if (length < 0x80){
527 if (*datalength < 1){
528 ERROR("build_length");
529 return NULL;
530 }
531 *data++ = (u_char)length;
532 } else if (length <= 0xFF){
533 if (*datalength < 2){
534 ERROR("build_length");
535 return NULL;
536 }
537 *data++ = (u_char)(0x01 | ASN_LONG_LEN);
538 *data++ = (u_char)length;
539 } else { /* 0xFF < length <= 0xFFFF */
540 if (*datalength < 3){
541 ERROR("build_length");
542 return NULL;
543 }
544 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
545 *data++ = (u_char)((length >> 8) & 0xFF);
546 *data++ = (u_char)(length & 0xFF);
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 *
566asn_parse_objid(data, datalength, type, objid, objidlength)
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; /* IN/OUT - number of sub-id's in objid */
572{
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;
582 long length;
583 u_long asn_length;
584
585 *type = *bufp++;
586 bufp = asn_parse_length(bufp, &asn_length);
587 if (bufp == NULL)
588 return NULL;
589 if (asn_length + (bufp - data) > *datalength){
590 ERROR("overflow of message");
591 return NULL;
592 }
593 *datalength -= (int)asn_length + (bufp - data);
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;
600 (*objidlength)--; /* account for expansion of first byte */
601 while (length > 0 && (*objidlength)-- > 0){
602 subidentifier = 0;
603 do { /* shift and add in low order 7 bits */
604 subidentifier = (subidentifier << 7) + (*(u_char *)bufp & ~ASN_BIT8);
605 length--;
606 } while (*(u_char *)bufp++ & ASN_BIT8); /* last byte has high bit clear */
607 if (subidentifier > (u_long)MAX_SUBID){
608 ERROR("subidentifier too long");
609 return NULL;
610 }
611 *oidp++ = (oid)subidentifier;
612 }
613
614 /*
615 * The first two subidentifiers are encoded into the first component
616 * with the value (X * 40) + Y, where:
617 * X is the value of the first subidentifier.
618 * Y is the value of the second subidentifier.
619 */
620 subidentifier = (u_long)objid[1];
621 if (subidentifier == 0x2B){
622 objid[0] = 1;
623 objid[1] = 3;
624 } else {
625 objid[1] = (u_char)(subidentifier % 40);
626 objid[0] = (u_char)((subidentifier - objid[1]) / 40);
627 }
628
629 *objidlength = (int)(oidp - objid);
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 *
645asn_build_objid(data, datalength, type, objid, objidlength)
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; /* IN - number of sub-id's in objid */
651{
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;
661 int asnlength;
662 u_long subid, mask, testmask;
663 int bits, testbits;
664
665 if (objidlength < 2){
666 *bp++ = 0;
667 objidlength = 0;
668 } else {
669 *bp++ = op[1] + (op[0] * 40);
670 objidlength -= 2;
671 op += 2;
672 }
673
674 while(objidlength-- > 0){
675 subid = *op++;
676 if (subid < 127){ /* off by one? */
677 *bp++ = subid;
678 } else {
679 mask = 0x7F; /* handle subid == 0 case */
680 bits = 0;
681 /* testmask *MUST* !!!! be of an unsigned type */
682 for(testmask = 0x7F, testbits = 0; testmask != 0;
683 testmask <<= 7, testbits += 7){
684 if (subid & testmask){ /* if any bits set */
685 mask = testmask;
686 bits = testbits;
687 }
688 }
689 /* mask can't be zero here */
690 for(;mask != 0x7F; mask >>= 7, bits -= 7){
691 /* fix a mask that got truncated above */
692 if (mask == 0x1E00000)
693 mask = 0xFE00000;
694 *bp++ = (u_char)(((subid & mask) >> bits) | ASN_BIT8);
695 }
696 *bp++ = (u_char)(subid & mask);
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;
705 bcopy((char *)buf, (char *)data, asnlength);
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 *
721asn_parse_null(data, datalength, type)
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; /* OUT - ASN type of object */
725{
726/*
727 * ASN.1 null ::= 0x05 0x00
728 */
729 u_char *bufp = data;
730 u_long asn_length;
731
732 *type = *bufp++;
733 bufp = asn_parse_length(bufp, &asn_length);
734 if (bufp == NULL)
735 return NULL;
736 if (asn_length != 0){
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 *
756asn_build_null(data, datalength, type)
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; /* IN - ASN type of object */
760{
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 *
780asn_parse_bitstring(data, datalength, type, string, strlength)
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; /* IN/OUT - size of output buffer */
786{
787/*
788 * bitstring ::= 0x03 asnlength unused {byte}*
789 */
790 u_char *bufp = data;
791 u_long asn_length;
792
793 *type = *bufp++;
794 bufp = asn_parse_length(bufp, &asn_length);
795 if (bufp == NULL)
796 return NULL;
797 if (asn_length + (bufp - data) > *datalength){
798 ERROR("overflow of message");
799 return NULL;
800 }
801 if (asn_length > *strlength){
802 ERROR("I don't support such long bitstrings");
803 return NULL;
804 }
805 if (asn_length < 1){
806 ERROR("Invalid bitstring");
807 return NULL;
808 }
809 if (/** *bufp < 0 || **/ *bufp > 7){
810 ERROR("Invalid bitstring");
811 return NULL;
812 }
813 bcopy((char *)bufp, (char *)string, (int)asn_length);
814 *strlength = (int)asn_length;
815 *datalength -= (int)asn_length + (bufp - data);
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 *
832asn_build_bitstring(data, datalength, type, string, strlength)
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; /* IN - size of input buffer */
838{
839/*
840 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
841 */
842 if (strlength < 1 || /** *string < 0 || **/ *string > 7){
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;
851 bcopy((char *)string, (char *)data, strlength);
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 *
869asn_parse_unsigned_int64(data, datalength, type, cp, countersize)
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;/* IN - size of output buffer */
875{
876/*
877 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
878 */
879 u_char *bufp = data;
880 u_long asn_length;
881 u_long low = 0, high = 0;
882 int intsize = 4;
883
884 if (countersize != sizeof(struct counter64)){
885 ERROR("not counter64 size");
886 return NULL;
887 }
888 *type = *bufp++;
889 bufp = asn_parse_length(bufp, &asn_length);
890 if (bufp == NULL){
891 ERROR("bad length");
892 return NULL;
893 }
894 if (asn_length + (bufp - data) > *datalength){
895 ERROR("overflow of message");
896 return NULL;
897 }
898 if ((asn_length > (intsize * 2 + 1)) ||
899 ((asn_length == (intsize * 2) + 1) && *bufp != 0x00)){
900 ERROR("I don't support such large integers");
901 return NULL;
902 }
903 *datalength -= (int)asn_length + (bufp - data);
904 if (*bufp & 0x80){
905 low = -1; /* integer is negative */
906 high = -1;
907 }
908 while(asn_length--){
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 *
929asn_build_unsigned_int64(data, datalength, type, cp, countersize)
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; /* IN - size of *intp */
935{
936/*
937 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
938 */
939
940 u_int32 low, high;
941 u_int32 mask, mask2;
942 int add_null_byte = 0;
943 int intsize;
944
945 if (countersize != sizeof (struct counter64)) {
946 ERROR("not counter64 size");
947 return NULL;
948 }
949 intsize = 8;
950 low = cp->low;
951 high = cp->high;
952 mask = 0xFF << (8 * (sizeof(int32) - 1));
953 /* mask is 0xFF000000 on a big-endian machine */
954 if ((u_char)((high & mask) >> (8 * (sizeof(int32) - 1))) & 0x80) {
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 */
965 mask2 = 0x1FF << ((8 * (sizeof(int32) - 1)) - 1);
966 /* mask2 is 0xFF800000 on a big-endian machine */
967 while((((high & mask2) == 0) || ((high & mask2) == mask2))
968 && intsize > 1){
969 intsize--;
970 high = (high << 8)
971 | ((low & mask) >> (8 * (sizeof(int32) - 1)));
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;
980 if (add_null_byte == 1){
981 *data++ = '\0';
982 intsize--;
983 }
984 while(intsize--){
985 *data++ = (u_char)((high & mask) >> (8 * (sizeof(int32) - 1)));
986 high = (high << 8)
987 | ((low & mask) >> (8 * (sizeof(int32) - 1)));
988 low <<= 8;
989
990 }
991 return data;
992}
993
994