]>
Commit | Line | Data |
---|---|---|
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 | ||
15 | Permission to use, copy, modify, and distribute this software and its | |
16 | documentation for any purpose and without fee is hereby granted, | |
17 | provided that the above copyright notice appear in all copies and that | |
18 | both that copyright notice and this permission notice appear in | |
19 | supporting documentation, and that the name of CMU not be | |
20 | used in advertising or publicity pertaining to distribution of the | |
21 | software without specific, written prior permission. | |
22 | ||
23 | CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
24 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
25 | CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
26 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
27 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
28 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
29 | SOFTWARE. | |
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 | */ | |
72 | u_char * | |
73 | asn_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 | */ | |
125 | u_char * | |
126 | asn_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 | */ | |
179 | u_char * | |
180 | asn_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 | */ | |
238 | u_char * | |
239 | asn_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 | */ | |
309 | u_char * | |
310 | asn_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 | */ | |
354 | u_char * | |
355 | asn_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 | */ | |
388 | u_char * | |
389 | asn_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 | */ | |
433 | u_char * | |
434 | asn_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 | */ | |
461 | u_char * | |
462 | asn_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 | */ | |
488 | u_char * | |
489 | asn_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 | ||
517 | u_char * | |
518 | asn_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 | */ | |
565 | u_char * | |
566 | asn_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 | */ | |
644 | u_char * | |
645 | asn_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 | */ | |
720 | u_char * | |
721 | asn_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 | */ | |
755 | u_char * | |
756 | asn_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 | */ | |
779 | u_char * | |
780 | asn_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 | */ | |
831 | u_char * | |
832 | asn_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 | */ | |
868 | u_char * | |
869 | asn_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 | */ | |
928 | u_char * | |
929 | asn_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 |