]>
Commit | Line | Data |
---|---|---|
c04fda28 | 1 | /* |
f6e9a3ee | 2 | * Copyright (C) 1996-2019 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 | 92 | u_char * |
f53969cc SM |
93 | asn_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 | 113 | u_char * |
114 | asn_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 | 178 | u_char * |
179 | asn_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 | 244 | u_char * |
245 | asn_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 | 310 | u_char * |
311 | asn_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 | 386 | u_char * |
387 | asn_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 | 432 | u_char * |
433 | asn_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 | 469 | u_char * |
470 | asn_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 | 512 | u_char * |
513 | asn_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 | 544 | u_char * |
545 | asn_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 | 574 | u_char * |
575 | asn_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 | 605 | u_char * |
606 | asn_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 | 673 | u_char * |
674 | asn_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 | 758 | u_char * |
759 | asn_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 | 839 | u_char * |
840 | asn_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 | 875 | u_char * |
876 | asn_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 | 901 | u_char * |
902 | asn_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 | 954 | u_char * |
955 | asn_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 | 1007 | u_char * |
1008 | asn_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 |