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