xref: /onnv-gate/usr/src/cmd/agents/snmp/snmplib/asn1.c (revision 0:68f95e015346)
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	"%Z%%M%	%I%	%E% 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 *
asn_parse_int(u_char * data,uint32_t * datalength,u_char * type,int32_t * intp,uint32_t intsize,char * error_label)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 *
asn_parse_unsigned_int(u_char * data,uint32_t * datalength,u_char * type,int32_t * intp,uint32_t intsize,char * error_label)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 *
asn_build_int(u_char * data,uint32_t * datalength,u_char type,int32_t * intp,uint32_t intsize,char * error_label)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 *
asn_build_unsigned_int(u_char * data,uint32_t * datalength,u_char type,int32_t * intp,uint32_t intsize,char * error_label)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 *
asn_parse_string(u_char * data,uint32_t * datalength,u_char * type,u_char * string,uint32_t * strlength,char * error_label)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 *
asn_build_string(u_char * data,uint32_t * datalength,u_char type,u_char * string,uint32_t strlength,char * error_label)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 *
asn_parse_header(u_char * data,uint32_t * datalength,u_char * type,char * error_label)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 *
asn_build_header(u_char * data,uint32_t * datalength,u_char type,uint32_t length,char * error_label)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 *
asn_parse_length(u_char * data,uint32_t * length,char * error_label)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 *
asn_build_length(u_char * data,uint32_t * datalength,uint32_t length,char * error_label)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 *
asn_parse_objid(u_char * data,uint32_t * datalength,u_char * type,Subid * objid,int32_t * objidlength,char * error_label)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 *
asn_build_objid(u_char * data,uint32_t * datalength,u_char type,Subid * objid,int32_t objidlength,char * error_label)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 *
asn_parse_null(u_char * data,uint32_t * datalength,u_char * type,char * error_label)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 *
asn_build_null(u_char * data,uint32_t * datalength,u_char type,char * error_label)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 }
759