0
|
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 }
|