Mercurial > illumos > onarm
comparison usr/src/cmd/agents/snmp/snmplib/asn1.c @ 0:c9caec207d52 b86
Initial porting based on b86
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Tue, 02 Jun 2009 18:56:50 +0900 |
parents | |
children | 1a15d5aaf794 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c9caec207d52 |
---|---|
1 /* | |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
5 * Common Development and Distribution License, Version 1.0 only | |
6 * (the "License"). You may not use this file except in compliance | |
7 * with the License. | |
8 * | |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
10 * or http://www.opensolaris.org/os/licensing. | |
11 * See the License for the specific language governing permissions | |
12 * and limitations under the License. | |
13 * | |
14 * When distributing Covered Code, include this CDDL HEADER in each | |
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
16 * If applicable, add the following below this CDDL HEADER, with the | |
17 * fields enclosed by brackets "[]" replaced with your own identifying | |
18 * information: Portions Copyright [yyyy] [name of copyright owner] | |
19 * | |
20 * CDDL HEADER END | |
21 */ | |
22 /* | |
23 * Copyright 2001,2002 Sun Microsystems, Inc. All rights reserved. | |
24 * Use is subject to license terms. | |
25 */ | |
26 | |
27 #pragma ident "@(#)asn1.c 1.10 05/06/12 SMI" | |
28 | |
29 #include <string.h> | |
30 #include <stdio.h> | |
31 #include <sys/types.h> | |
32 #include <netinet/in.h> | |
33 #include "snmp_msg.h" | |
34 #include "asn1.h" | |
35 | |
36 | |
37 /* | |
38 * asn_parse_int - pulls a int32_t out of an ASN int type. | |
39 * On entry, datalength is input as the number of valid bytes following | |
40 * "data". On exit, it is returned as the number of valid bytes | |
41 * following the end of this object. | |
42 * | |
43 * Returns a pointer to the first byte past the end | |
44 * of this object (i.e. the start of the next object). | |
45 * Returns NULL on any error. | |
46 */ | |
47 u_char * | |
48 asn_parse_int( | |
49 u_char *data, /* IN - pointer to start of object */ | |
50 uint32_t *datalength,/* IN/OUT - number of valid bytes left in buffer */ | |
51 u_char *type, /* OUT - asn type of object */ | |
52 int32_t *intp, /* IN/OUT - pointer to start of output buffer */ | |
53 uint32_t intsize, /* IN - size of output buffer */ | |
54 char *error_label) | |
55 { | |
56 /* | |
57 * ASN.1 integer ::= 0x02 asnlength byte {byte}* | |
58 */ | |
59 u_char *bufp = data; | |
60 uint32_t asn_length = 0; | |
61 int32_t value = 0; | |
62 | |
63 | |
64 error_label[0] = '\0'; | |
65 | |
66 if (intsize != sizeof (int32_t)){ | |
67 (void)sprintf(error_label, ERR_MSG_NOT_LONG); | |
68 return NULL; | |
69 } | |
70 *type = *bufp++; | |
71 bufp = asn_parse_length(bufp, &asn_length, error_label); | |
72 if (bufp == NULL){ | |
73 (void)sprintf(error_label, ERR_MSG_BAD_LENGTH); | |
74 return NULL; | |
75 } | |
76 /* LINTED */ | |
77 if (asn_length + (uint32_t)(bufp - data) > *datalength){ | |
78 (void)sprintf(error_label, ERR_MSG_OVERFLOW); | |
79 return NULL; | |
80 } | |
81 if (asn_length > intsize){ | |
82 (void)sprintf(error_label, ERR_MSG_DONT_SUPPORT_LARGE_INT); | |
83 return NULL; | |
84 } | |
85 /* LINTED */ | |
86 *datalength -= asn_length + (uint32_t)(bufp - data); | |
87 if (*bufp & 0x80) | |
88 value = -1; /* integer is negative */ | |
89 while(asn_length--) | |
90 value = (value << 8) | *bufp++; | |
91 *intp = value; | |
92 return bufp; | |
93 } | |
94 | |
95 /* | |
96 * asn_parse_unsigned_int - pulls an unsigned int32_t out of an ASN int type. | |
97 * On entry, datalength is input as the number of valid bytes following | |
98 * "data". On exit, it is returned as the number of valid bytes | |
99 * following the end of this object. | |
100 * | |
101 * Returns a pointer to the first byte past the end | |
102 * of this object (i.e. the start of the next object). | |
103 * Returns NULL on any error. | |
104 */ | |
105 u_char * | |
106 asn_parse_unsigned_int( | |
107 u_char *data, /* IN - pointer to start of object */ | |
108 uint32_t * datalength,/* IN/OUT - number of valid bytes left in buffer */ | |
109 u_char *type, /* OUT - asn type of object */ | |
110 int32_t *intp, /* IN/OUT - pointer to start of output buffer */ | |
111 uint32_t intsize, /* IN - size of output buffer */ | |
112 char *error_label) | |
113 { | |
114 /* | |
115 * ASN.1 integer ::= 0x02 asnlength byte {byte}* | |
116 */ | |
117 u_char *bufp = data; | |
118 uint32_t asn_length; | |
119 uint32_t value = 0; | |
120 | |
121 error_label[0] = '\0'; | |
122 | |
123 if (intsize != sizeof (int32_t)){ | |
124 (void)sprintf(error_label, ERR_MSG_NOT_LONG); | |
125 return NULL; | |
126 } | |
127 *type = *bufp++; | |
128 bufp = asn_parse_length(bufp, &asn_length, error_label); | |
129 if (bufp == NULL){ | |
130 (void)sprintf(error_label, ERR_MSG_BAD_LENGTH); | |
131 return NULL; | |
132 } | |
133 /* LINTED */ | |
134 if (asn_length + (uint32_t)(bufp - data) > *datalength){ | |
135 (void)sprintf(error_label, ERR_MSG_OVERFLOW); | |
136 return NULL; | |
137 } | |
138 if ((asn_length > (intsize + 1)) || | |
139 ((asn_length == intsize + 1) && *bufp != 0x00)){ | |
140 (void)sprintf(error_label, ERR_MSG_DONT_SUPPORT_LARGE_INT); | |
141 return NULL; | |
142 } | |
143 /* LINTED */ | |
144 *datalength -= asn_length + (uint32_t)(bufp - data); | |
145 if (*bufp & 0x80) | |
146 value = -1U; /* integer is negative */ | |
147 while(asn_length--) | |
148 value = (value << 8) | *bufp++; | |
149 *intp = value; | |
150 return bufp; | |
151 } | |
152 | |
153 | |
154 /* | |
155 * asn_build_int - builds an ASN object containing an integer. | |
156 * On entry, datalength is input as the number of valid bytes following | |
157 * "data". On exit, it is returned as the number of valid bytes | |
158 * following the end of this object. | |
159 * | |
160 * Returns a pointer to the first byte past the end | |
161 * of this object (i.e. the start of the next object). | |
162 * Returns NULL on any error. | |
163 */ | |
164 u_char * | |
165 asn_build_int( | |
166 u_char *data, /* IN - pointer to start of output buffer */ | |
167 uint32_t * datalength,/* IN/OUT - number of valid bytes left in buffer */ | |
168 u_char type, /* IN - asn type of object */ | |
169 int32_t *intp, /* IN - pointer to start of integer */ | |
170 uint32_t intsize, /* IN - size of *intp */ | |
171 char *error_label) | |
172 { | |
173 /* | |
174 * ASN.1 integer ::= 0x02 asnlength byte {byte}* | |
175 */ | |
176 | |
177 int32_t integer; | |
178 uint32_t mask; | |
179 | |
180 error_label[0] = '\0'; | |
181 | |
182 if (intsize != sizeof (int32_t)) | |
183 return NULL; | |
184 integer = *intp; | |
185 /* | |
186 * Truncate "unnecessary" bytes off of the most significant end of this 2's | |
187 * complement integer. There should be no sequence of 9 consecutive 1's or | |
188 * 0's at the most significant end of the integer. | |
189 */ | |
190 mask = ((uint32_t) 0x1FF) << ((8 * (sizeof(int32_t) - 1)) - 1); | |
191 | |
192 /* mask is 0xFF800000 on a big-endian machine */ | |
193 while((((integer & mask) == 0) || ((integer & mask) == mask)) && intsize > 1){ | |
194 intsize--; | |
195 integer <<= 8; | |
196 } | |
197 data = asn_build_header(data, datalength, type, intsize, error_label); | |
198 if (data == NULL) | |
199 return NULL; | |
200 if (*datalength < intsize) | |
201 return NULL; | |
202 *datalength -= intsize; | |
203 | |
204 mask = ((uint32_t) 0xFF) << (8 * (sizeof(int32_t) - 1)); | |
205 | |
206 /* mask is 0xFF000000 on a big-endian machine */ | |
207 while(intsize--){ | |
208 /* LINTED */ | |
209 *data++ = (u_char)((integer & mask) >> (8 * (sizeof(int32_t) - 1))); | |
210 integer <<= 8; | |
211 } | |
212 return data; | |
213 } | |
214 | |
215 /* | |
216 * asn_build_unsigned_int - builds an ASN object containing an integer. | |
217 * On entry, datalength is input as the number of valid bytes following | |
218 * "data". On exit, it is returned as the number of valid bytes | |
219 * following the end of this object. | |
220 * | |
221 * Returns a pointer to the first byte past the end | |
222 * of this object (i.e. the start of the next object). | |
223 * Returns NULL on any error. | |
224 */ | |
225 u_char * | |
226 asn_build_unsigned_int( | |
227 u_char *data, /* IN - pointer to start of output buffer */ | |
228 uint32_t *datalength,/* IN/OUT - number of valid bytes left in buffer */ | |
229 u_char type, /* IN - asn type of object */ | |
230 int32_t *intp, /* IN - pointer to start of int32_t integer */ | |
231 uint32_t intsize, /* IN - size of *intp */ | |
232 char *error_label) | |
233 { | |
234 /* | |
235 * ASN.1 integer ::= 0x02 asnlength byte {byte}* | |
236 */ | |
237 | |
238 uint32_t integer; | |
239 uint32_t mask; | |
240 int add_null_byte = 0; | |
241 | |
242 error_label[0] = '\0'; | |
243 | |
244 if (intsize != sizeof (int32_t)) | |
245 return NULL; | |
246 integer = *intp; | |
247 mask = ((uint32_t) 0xFF) << (8 * (sizeof(int32_t) - 1)); | |
248 /* mask is 0xFF000000 on a big-endian machine */ | |
249 /* LINTED */ | |
250 if ((u_char)((integer & mask) >> (8 * (sizeof(int32_t) - 1))) & 0x80){ | |
251 /* if MSB is set */ | |
252 add_null_byte = 1; | |
253 intsize++; | |
254 } else { | |
255 /* | |
256 * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer. | |
257 * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the | |
258 * integer. | |
259 */ | |
260 mask = ((uint32_t) 0x1FF) << ((8 * (sizeof(int32_t) - 1)) - 1); | |
261 /* mask is 0xFF800000 on a big-endian machine */ | |
262 while(((integer & mask) == 0) && intsize > 1){ | |
263 intsize--; | |
264 integer <<= 8; | |
265 } | |
266 } | |
267 data = asn_build_header(data, datalength, type, intsize, error_label); | |
268 if (data == NULL) | |
269 return NULL; | |
270 if (*datalength < intsize) | |
271 return NULL; | |
272 *datalength -= intsize; | |
273 if (add_null_byte == 1){ | |
274 *data++ = '\0'; | |
275 intsize--; | |
276 } | |
277 mask = ((uint32_t) 0xFF) << (8 * (sizeof(int32_t) - 1)); | |
278 /* mask is 0xFF000000 on a big-endian machine */ | |
279 while(intsize--){ | |
280 /* LINTED */ | |
281 *data++ = (u_char)((integer & mask) >> (8 * (sizeof(int32_t) - 1))); | |
282 integer <<= 8; | |
283 } | |
284 return data; | |
285 } | |
286 | |
287 | |
288 /* | |
289 * asn_parse_string - pulls an octet string out of an ASN octet string type. | |
290 * On entry, datalength is input as the number of valid bytes following | |
291 * "data". On exit, it is returned as the number of valid bytes | |
292 * following the beginning of the next object. | |
293 * | |
294 * "string" is filled with the octet string. | |
295 * | |
296 * Returns a pointer to the first byte past the end | |
297 * of this object (i.e. the start of the next object). | |
298 * Returns NULL on any error. | |
299 */ | |
300 u_char * | |
301 asn_parse_string( | |
302 u_char *data, /* IN - pointer to start of object */ | |
303 uint32_t *datalength, /* IN/OUT - number of valid bytes left in buffer */ | |
304 u_char *type, /* OUT - asn type of object */ | |
305 u_char *string, /* IN/OUT - pointer to start of output buffer */ | |
306 uint32_t *strlength, /* IN/OUT - size of output buffer */ | |
307 char *error_label) | |
308 { | |
309 /* | |
310 * ASN.1 octet string ::= primstring | cmpdstring | |
311 * primstring ::= 0x04 asnlength byte {byte}* | |
312 * cmpdstring ::= 0x24 asnlength string {string}* | |
313 * This doesn't yet support the compound string. | |
314 */ | |
315 u_char *bufp = data; | |
316 uint32_t asn_length = 0; | |
317 | |
318 | |
319 error_label[0] = '\0'; | |
320 | |
321 *type = *bufp++; | |
322 bufp = asn_parse_length(bufp, &asn_length, error_label); | |
323 if (bufp == NULL) | |
324 return NULL; | |
325 /* LINTED */ | |
326 if (asn_length + (uint32_t)(bufp - data) > *datalength){ | |
327 (void)sprintf(error_label, ERR_MSG_OVERFLOW); | |
328 return NULL; | |
329 } | |
330 if (asn_length > *strlength){ | |
331 (void)sprintf(error_label, ERR_MSG_DONT_SUPPORT_LARGE_STR); | |
332 return NULL; | |
333 } | |
334 memcpy(string, bufp, asn_length); | |
335 *strlength = asn_length; | |
336 /* LINTED */ | |
337 *datalength -= asn_length + (uint32_t)(bufp - data); | |
338 return bufp + asn_length; | |
339 } | |
340 | |
341 | |
342 /* | |
343 * asn_build_string - Builds an ASN octet string object containing the input string. | |
344 * On entry, datalength is input as the number of valid bytes following | |
345 * "data". On exit, it is returned as the number of valid bytes | |
346 * following the beginning of the next object. | |
347 * | |
348 * Returns a pointer to the first byte past the end | |
349 * of this object (i.e. the start of the next object). | |
350 * Returns NULL on any error. | |
351 */ | |
352 u_char * | |
353 asn_build_string( | |
354 u_char *data, /* IN - pointer to start of object */ | |
355 uint32_t *datalength, /* IN/OUT - number of valid bytes left in buffer */ | |
356 u_char type, /* IN - ASN type of string */ | |
357 u_char *string, /* IN - pointer to start of input buffer */ | |
358 uint32_t strlength, /* IN - size of input buffer */ | |
359 char *error_label) | |
360 { | |
361 /* | |
362 * ASN.1 octet string ::= primstring | cmpdstring | |
363 * primstring ::= 0x04 asnlength byte {byte}* | |
364 * cmpdstring ::= 0x24 asnlength string {string}* | |
365 * This code will never send a compound string. | |
366 */ | |
367 | |
368 error_label[0] = '\0'; | |
369 | |
370 data = asn_build_header(data, datalength, type, strlength, error_label); | |
371 if (data == NULL) | |
372 return NULL; | |
373 if (*datalength < strlength) | |
374 return NULL; | |
375 memcpy(data, string, strlength); | |
376 *datalength -= strlength; | |
377 return data + (intptr_t)strlength; | |
378 } | |
379 | |
380 | |
381 /* | |
382 * asn_parse_header - interprets the ID and length of the current object. | |
383 * On entry, datalength is input as the number of valid bytes following | |
384 * "data". On exit, it is returned as the number of valid bytes | |
385 * in this object following the id and length. | |
386 * | |
387 * Returns a pointer to the first byte of the contents of this object. | |
388 * Returns NULL on any error. | |
389 */ | |
390 u_char * | |
391 asn_parse_header( | |
392 u_char *data, /* IN - pointer to start of object */ | |
393 uint32_t * datalength,/* IN/OUT - number of valid bytes left in buffer */ | |
394 u_char *type, /* OUT - ASN type of object */ | |
395 char *error_label) | |
396 { | |
397 u_char *bufp = data; | |
398 uint32_t header_len; | |
399 uint32_t asn_length = 0; | |
400 | |
401 error_label[0] = '\0'; | |
402 | |
403 /* this only works on data types < 30, i.e. no extension octets */ | |
404 if (IS_EXTENSION_ID(*bufp)){ | |
405 (void)sprintf(error_label, ERR_MSG_CANT_PROCESS_LONG_ID); | |
406 return NULL; | |
407 } | |
408 *type = *bufp; | |
409 bufp = asn_parse_length(bufp + 1, &asn_length, error_label); | |
410 if (bufp == NULL) | |
411 return NULL; | |
412 | |
413 /* LINTED */ | |
414 header_len = (uint32_t)(bufp - data); | |
415 if (header_len + asn_length > *datalength){ | |
416 (void)sprintf(error_label, ERR_MSG_ASN_LEN_TOO_LONG); | |
417 return NULL; | |
418 } | |
419 *datalength = asn_length; | |
420 return bufp; | |
421 } | |
422 | |
423 /* | |
424 * asn_build_header - builds an ASN header for an object with the ID and | |
425 * length specified. | |
426 * On entry, datalength is input as the number of valid bytes following | |
427 * "data". On exit, it is returned as the number of valid bytes | |
428 * in this object following the id and length. | |
429 * | |
430 * This only works on data types < 30, i.e. no extension octets. | |
431 * The maximum length is 0xFFFF; | |
432 * | |
433 * Returns a pointer to the first byte of the contents of this object. | |
434 * Returns NULL on any error. | |
435 */ | |
436 u_char * | |
437 asn_build_header( | |
438 u_char *data, /* IN - pointer to start of object */ | |
439 uint32_t *datalength,/* IN/OUT - number of valid bytes left in buffer */ | |
440 u_char type, /* IN - ASN type of object */ | |
441 uint32_t length, /* IN - length of object */ | |
442 char *error_label) | |
443 { | |
444 error_label[0] = '\0'; | |
445 | |
446 if (*datalength == 0) | |
447 return NULL; | |
448 *data++ = type; | |
449 (*datalength)--; | |
450 return asn_build_length(data, datalength, length, error_label); | |
451 | |
452 } | |
453 | |
454 /* | |
455 * asn_parse_length - interprets the length of the current object. | |
456 * On exit, length contains the value of this length field. | |
457 * | |
458 * Returns a pointer to the first byte after this length | |
459 * field (aka: the start of the data field). | |
460 * Returns NULL on any error. | |
461 */ | |
462 u_char * | |
463 asn_parse_length( | |
464 u_char *data, /* IN - pointer to start of length field */ | |
465 uint32_t *length, /* OUT - value of length field */ | |
466 char *error_label) | |
467 { | |
468 u_char lengthbyte = *data; | |
469 | |
470 error_label[0] = '\0'; | |
471 | |
472 if (lengthbyte & ASN_LONG_LEN){ | |
473 lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */ | |
474 if (lengthbyte == 0){ | |
475 (void)sprintf(error_label, ERR_MSG_DONT_SUPPORT_INDEF_LEN); | |
476 return NULL; | |
477 } | |
478 if (lengthbyte > sizeof(int32_t)){ | |
479 (void)sprintf(error_label, ERR_MSG_DONT_SUPPORT_SUCH_LEN); | |
480 return NULL; | |
481 } | |
482 memcpy(length, data + 1, (int)lengthbyte); | |
483 *length = ntohl(*length); | |
484 *length >>= (8 * ((sizeof *length) - lengthbyte)); | |
485 return data + lengthbyte + 1; | |
486 } else { /* short asnlength */ | |
487 *length = (int32_t)lengthbyte; | |
488 return data + 1; | |
489 } | |
490 } | |
491 | |
492 u_char * | |
493 asn_build_length( | |
494 u_char *data, /* IN - pointer to start of object */ | |
495 uint32_t *datalength, /* IN/OUT - number of valid bytes left in buffer */ | |
496 uint32_t length, /* IN - length of object */ | |
497 char *error_label) | |
498 { | |
499 u_char *start_data = data; | |
500 | |
501 error_label[0] = '\0'; | |
502 | |
503 /* no indefinite lengths sent */ | |
504 if (length < 0x80){ | |
505 if (*datalength < 1) | |
506 goto errout; | |
507 /* LINTED */ | |
508 *data++ = (u_char)length; | |
509 } else if (length <= 0xFF){ | |
510 if (*datalength < 2) | |
511 goto errout; | |
512 /* LINTED */ | |
513 *data++ = (u_char)(0x01 | ASN_LONG_LEN); | |
514 /* LINTED */ | |
515 *data++ = (u_char)length; | |
516 } else { /* 0xFF < length <= 0xFFFF */ | |
517 if (*datalength < 3) | |
518 goto errout; | |
519 /* LINTED */ | |
520 *data++ = (u_char)(0x02 | ASN_LONG_LEN); | |
521 /* LINTED */ | |
522 *data++ = (u_char)((length >> 8) & 0xFF); | |
523 /* LINTED */ | |
524 *data++ = (u_char)(length & 0xFF); | |
525 } | |
526 /* LINTED */ | |
527 *datalength -= (uint32_t)(data - start_data); | |
528 return data; | |
529 | |
530 errout: | |
531 (void)sprintf(error_label, ERR_MSG_BUILD_LENGTH); | |
532 return NULL; | |
533 } | |
534 | |
535 /* | |
536 * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type. | |
537 * On entry, datalength is input as the number of valid bytes following | |
538 * "data". On exit, it is returned as the number of valid bytes | |
539 * following the beginning of the next object. | |
540 * | |
541 * "objid" is filled with the object identifier. | |
542 * | |
543 * Returns a pointer to the first byte past the end | |
544 * of this object (i.e. the start of the next object). | |
545 * Returns NULL on any error. | |
546 */ | |
547 u_char * | |
548 asn_parse_objid( | |
549 u_char *data, /* IN - pointer to start of object */ | |
550 uint32_t *datalength, /* IN/OUT - number of valid bytes left in buffer */ | |
551 u_char *type, /* OUT - ASN type of object */ | |
552 Subid *objid, /* IN/OUT - pointer to start of output buffer */ | |
553 int32_t *objidlength, /* IN/OUT - number of sub-id's in objid */ | |
554 char *error_label) | |
555 { | |
556 /* | |
557 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}* | |
558 * subidentifier ::= {leadingbyte}* lastbyte | |
559 * leadingbyte ::= 1 7bitvalue | |
560 * lastbyte ::= 0 7bitvalue | |
561 */ | |
562 u_char *bufp = data; | |
563 Subid *oidp = objid + 1; | |
564 uint32_t subidentifier; | |
565 int32_t length; | |
566 uint32_t asn_length = 0; | |
567 | |
568 | |
569 error_label[0] = '\0'; | |
570 | |
571 *type = *bufp++; | |
572 bufp = asn_parse_length(bufp, &asn_length, error_label); | |
573 if (bufp == NULL) | |
574 return NULL; | |
575 /* LINTED */ | |
576 if (asn_length + (uint32_t)(bufp - data) > *datalength){ | |
577 (void)sprintf(error_label, ERR_MSG_OVERFLOW); | |
578 return NULL; | |
579 } | |
580 /* LINTED */ | |
581 *datalength -= asn_length + (uint32_t)(bufp - data); | |
582 | |
583 length = asn_length; | |
584 (*objidlength)--; /* account for expansion of first byte */ | |
585 while (length > 0 && (*objidlength)-- > 0){ | |
586 subidentifier = 0; | |
587 do { /* shift and add in low order 7 bits */ | |
588 subidentifier = (subidentifier << 7) + (*(u_char *)bufp & ~ASN_BIT8); | |
589 length--; | |
590 } while (*(u_char *)bufp++ & ASN_BIT8); /* last byte has high bit clear */ | |
591 if (subidentifier > (uint32_t)MAX_SUBID){ | |
592 (void)sprintf(error_label, ERR_MSG_SUBIDENTIFIER_TOO_LONG); | |
593 return NULL; | |
594 } | |
595 *oidp++ = (Subid)subidentifier; | |
596 } | |
597 | |
598 /* | |
599 * The first two subidentifiers are encoded into the first component | |
600 * with the value (X * 40) + Y, where: | |
601 * X is the value of the first subidentifier. | |
602 * Y is the value of the second subidentifier. | |
603 */ | |
604 subidentifier = (uint32_t)objid[1]; | |
605 /* LINTED */ | |
606 objid[1] = (u_char)(subidentifier % 0x28); | |
607 /* LINTED */ | |
608 objid[0] = (u_char)((subidentifier - objid[1]) / 0x28); | |
609 | |
610 /* LINTED */ | |
611 *objidlength = (int32_t)(oidp - objid); | |
612 return bufp; | |
613 } | |
614 | |
615 /* | |
616 * asn_build_objid - Builds an ASN object identifier object containing the input string. | |
617 * On entry, datalength is input as the number of valid bytes following | |
618 * "data". On exit, it is returned as the number of valid bytes | |
619 * following the beginning of the next object. | |
620 * | |
621 * Returns a pointer to the first byte past the end | |
622 * of this object (i.e. the start of the next object). | |
623 * Returns NULL on any error. | |
624 */ | |
625 u_char * | |
626 asn_build_objid( | |
627 u_char *data, /* IN - pointer to start of object */ | |
628 uint32_t *datalength, /* IN/OUT - number of valid bytes left in buffer */ | |
629 u_char type, /* IN - ASN type of object */ | |
630 Subid *objid, /* IN - pointer to start of input buffer */ | |
631 int32_t objidlength, /* IN - number of sub-id's in objid */ | |
632 char *error_label) | |
633 { | |
634 /* | |
635 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}* | |
636 * subidentifier ::= {leadingbyte}* lastbyte | |
637 * leadingbyte ::= 1 7bitvalue | |
638 * lastbyte ::= 0 7bitvalue | |
639 */ | |
640 | |
641 uchar_t buf[MAX_OID_LEN * 5]; | |
642 uchar_t *bp = buf; | |
643 Subid objbuf[MAX_OID_LEN]; | |
644 Subid *op = objbuf; | |
645 uint32_t asnlength; | |
646 uint32_t subid, mask, testmask; | |
647 int bits, testbits; | |
648 | |
649 error_label[0] = '\0'; | |
650 | |
651 if (objidlength > MAX_OID_LEN) | |
652 return (NULL); | |
653 | |
654 memcpy(objbuf, objid, objidlength * (int32_t)sizeof (Subid)); | |
655 /* transform size in bytes to size in subid's */ | |
656 /* encode the first two components into the first subidentifier */ | |
657 op[1] = op[1] + (op[0] * 40); | |
658 op++; | |
659 objidlength--; | |
660 | |
661 while (objidlength-- > 0){ | |
662 subid = *op++; | |
663 mask = 0x7F; /* handle subid == 0 case */ | |
664 bits = 0; | |
665 /* testmask *MUST* !!!! be of an unsigned type */ | |
666 for (testmask = 0x7F, testbits = 0; testmask != 0; | |
667 testmask <<= 7, testbits += 7) { | |
668 if (subid & testmask) { /* if any bits set */ | |
669 mask = testmask; | |
670 bits = testbits; | |
671 } | |
672 } | |
673 /* mask can't be zero here */ | |
674 for (; mask != 0x7F; mask >>= 7, bits -= 7){ | |
675 if (mask == 0x1E00000) | |
676 /* fix a mask that got truncated above */ | |
677 mask = 0xFE00000; | |
678 /* LINTED */ | |
679 *bp++ = (uchar_t)(((subid & mask) >> bits) | ASN_BIT8); | |
680 } | |
681 /* LINTED */ | |
682 *bp++ = (uchar_t)(subid & mask); | |
683 } | |
684 /* LINTED */ | |
685 asnlength = (uint32_t)(bp - buf); | |
686 data = asn_build_header(data, datalength, type, asnlength, error_label); | |
687 if (data == NULL) | |
688 return (NULL); | |
689 if (*datalength < asnlength) | |
690 return (NULL); | |
691 memcpy(data, buf, asnlength); | |
692 *datalength -= asnlength; | |
693 return (data + (uintptr_t)asnlength); | |
694 } | |
695 | |
696 /* | |
697 * asn_parse_null - Interprets an ASN null type. | |
698 * On entry, datalength is input as the number of valid bytes following | |
699 * "data". On exit, it is returned as the number of valid bytes | |
700 * following the beginning of the next object. | |
701 * | |
702 * Returns a pointer to the first byte past the end | |
703 * of this object (i.e. the start of the next object). | |
704 * Returns NULL on any error. | |
705 */ | |
706 u_char * | |
707 asn_parse_null( | |
708 u_char *data, /* IN - pointer to start of object */ | |
709 uint32_t *datalength, /* IN/OUT - number of valid bytes left in buffer */ | |
710 u_char *type, /* OUT - ASN type of object */ | |
711 char *error_label) | |
712 { | |
713 /* | |
714 * ASN.1 null ::= 0x05 0x00 | |
715 */ | |
716 u_char *bufp = data; | |
717 uint32_t asn_length = 0; | |
718 | |
719 | |
720 error_label[0] = '\0'; | |
721 | |
722 *type = *bufp++; | |
723 bufp = asn_parse_length(bufp, &asn_length, error_label); | |
724 if (bufp == NULL) | |
725 return NULL; | |
726 if (asn_length != 0){ | |
727 (void)sprintf(error_label, ERR_MSG_MALFORMED_NULL); | |
728 return NULL; | |
729 } | |
730 /* LINTED */ | |
731 *datalength -= (uint32_t)(bufp - data); | |
732 return bufp + (uintptr_t)asn_length; | |
733 } | |
734 | |
735 /* | |
736 * asn_build_null - Builds an ASN null object. | |
737 * On entry, datalength is input as the number of valid bytes following | |
738 * "data". On exit, it is returned as the number of valid bytes | |
739 * following the beginning of the next object. | |
740 * | |
741 * Returns a pointer to the first byte past the end | |
742 * of this object (i.e. the start of the next object). | |
743 * Returns NULL on any error. | |
744 */ | |
745 u_char * | |
746 asn_build_null( | |
747 u_char *data, /* IN - pointer to start of object */ | |
748 uint32_t *datalength, /* IN/OUT - number of valid bytes left in buffer */ | |
749 u_char type, /* IN - ASN type of object */ | |
750 char *error_label) | |
751 { | |
752 /* | |
753 * ASN.1 null ::= 0x05 0x00 | |
754 */ | |
755 error_label[0] = '\0'; | |
756 | |
757 return asn_build_header(data, datalength, type, 0, error_label); | |
758 } |