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