xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4v/lib/snmp/asn1.c (revision 3941:328be6a20f20)
1*3941Svenki /*
2*3941Svenki  * CDDL HEADER START
3*3941Svenki  *
4*3941Svenki  * The contents of this file are subject to the terms of the
5*3941Svenki  * Common Development and Distribution License (the "License").
6*3941Svenki  * You may not use this file except in compliance with the License.
7*3941Svenki  *
8*3941Svenki  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3941Svenki  * or http://www.opensolaris.org/os/licensing.
10*3941Svenki  * See the License for the specific language governing permissions
11*3941Svenki  * and limitations under the License.
12*3941Svenki  *
13*3941Svenki  * When distributing Covered Code, include this CDDL HEADER in each
14*3941Svenki  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3941Svenki  * If applicable, add the following below this CDDL HEADER, with the
16*3941Svenki  * fields enclosed by brackets "[]" replaced with your own identifying
17*3941Svenki  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3941Svenki  *
19*3941Svenki  * CDDL HEADER END
20*3941Svenki  */
21*3941Svenki 
22*3941Svenki /*
23*3941Svenki  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*3941Svenki  * Use is subject to license terms.
25*3941Svenki  */
26*3941Svenki 
27*3941Svenki #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*3941Svenki 
29*3941Svenki /*
30*3941Svenki  * ASN.1 encoding related routines
31*3941Svenki  */
32*3941Svenki 
33*3941Svenki #include <stdio.h>
34*3941Svenki #include <stdlib.h>
35*3941Svenki #include <string.h>
36*3941Svenki #include <sys/types.h>
37*3941Svenki #include "asn1.h"
38*3941Svenki #include "pdu.h"
39*3941Svenki #include "debug.h"
40*3941Svenki 
41*3941Svenki /*
42*3941Svenki  * This routine builds a 'SEQUENCE OF' ASN.1 object in the buffer
43*3941Svenki  * using the 'id' and 'length' supplied. This is probably the place
44*3941Svenki  * where using "reverse" asn encoding will help.
45*3941Svenki  */
46*3941Svenki uchar_t *
asn_build_sequence(uchar_t * buf,size_t * bufsz_p,uchar_t id,size_t length)47*3941Svenki asn_build_sequence(uchar_t *buf, size_t *bufsz_p, uchar_t id, size_t length)
48*3941Svenki {
49*3941Svenki 	/*
50*3941Svenki 	 * When rebuilding sequence (which we do many times), we'll
51*3941Svenki 	 * simply pass NULL to bufsz_p to skip the error check.
52*3941Svenki 	 */
53*3941Svenki 	if ((bufsz_p) && (*bufsz_p < 4))
54*3941Svenki 		return (NULL);
55*3941Svenki 
56*3941Svenki 	buf[0] = id;
57*3941Svenki 	buf[1] = (uchar_t)(ASN_LONG_LEN | 0x02);	/* following 2 octets */
58*3941Svenki 	buf[2] = (uchar_t)((length >> 8) & 0xff);
59*3941Svenki 	buf[3] = (uchar_t)(length & 0xff);
60*3941Svenki 
61*3941Svenki 	if (bufsz_p)
62*3941Svenki 		*bufsz_p -= 4;
63*3941Svenki 
64*3941Svenki 	LOGASNSEQ(buf, 4);
65*3941Svenki 
66*3941Svenki 	return (buf + 4);
67*3941Svenki }
68*3941Svenki 
69*3941Svenki /*
70*3941Svenki  * The next two routines, asn_build_header() and asn_build_length(), build
71*3941Svenki  * the header and length for an arbitrary object type into the buffer. The
72*3941Svenki  * length of the object is encoded using as few length octets as possible.
73*3941Svenki  */
74*3941Svenki uchar_t *
asn_build_header(uchar_t * buf,size_t * bufsz_p,uchar_t id,size_t length)75*3941Svenki asn_build_header(uchar_t *buf, size_t *bufsz_p, uchar_t id, size_t length)
76*3941Svenki {
77*3941Svenki 	if (*bufsz_p < 1)
78*3941Svenki 		return (NULL);
79*3941Svenki 
80*3941Svenki 	buf[0] = id;
81*3941Svenki 	(*bufsz_p)--;
82*3941Svenki 
83*3941Svenki 	return (asn_build_length(buf + 1, bufsz_p, length));
84*3941Svenki }
85*3941Svenki uchar_t *
asn_build_length(uchar_t * buf,size_t * bufsz_p,size_t length)86*3941Svenki asn_build_length(uchar_t *buf, size_t *bufsz_p, size_t length)
87*3941Svenki {
88*3941Svenki 	if (length < 0x80) {
89*3941Svenki 		if (*bufsz_p < 1)
90*3941Svenki 			return (NULL);
91*3941Svenki 		buf[0] = (uchar_t)length;
92*3941Svenki 		(*bufsz_p)--;
93*3941Svenki 
94*3941Svenki 		LOGASNLENGTH(buf, 1);
95*3941Svenki 
96*3941Svenki 		return (buf + 1);
97*3941Svenki 
98*3941Svenki 	} else if (length <= 0xFF) {
99*3941Svenki 		if (*bufsz_p < 2)
100*3941Svenki 			return (NULL);
101*3941Svenki 		buf[0] = (uchar_t)(ASN_LONG_LEN | 0x01);
102*3941Svenki 		buf[1] = (uchar_t)length;
103*3941Svenki 		*bufsz_p -= 2;
104*3941Svenki 
105*3941Svenki 		LOGASNLENGTH(buf, 2);
106*3941Svenki 
107*3941Svenki 		return (buf + 2);
108*3941Svenki 
109*3941Svenki 	} else {
110*3941Svenki 		if (*bufsz_p < 3)
111*3941Svenki 			return (NULL);
112*3941Svenki 
113*3941Svenki 		buf[0] = (uchar_t)(ASN_LONG_LEN | 0x02);
114*3941Svenki 		buf[1] = (uchar_t)((length >> 8) & 0xff);
115*3941Svenki 		buf[2] = (uchar_t)(length & 0xff);
116*3941Svenki 		*bufsz_p -= 3;
117*3941Svenki 
118*3941Svenki 		LOGASNLENGTH(buf, 3);
119*3941Svenki 
120*3941Svenki 		return (buf + 3);
121*3941Svenki 	}
122*3941Svenki }
123*3941Svenki /*
124*3941Svenki  * Builds an ASN.1 encoded integer in the buffer using as few octets
125*3941Svenki  * as possible.
126*3941Svenki  */
127*3941Svenki uchar_t *
asn_build_int(uchar_t * buf,size_t * bufsz_p,uchar_t id,int val)128*3941Svenki asn_build_int(uchar_t *buf, size_t *bufsz_p, uchar_t id, int val)
129*3941Svenki {
130*3941Svenki 	uint_t	uival;
131*3941Svenki 	int	ival, i;
132*3941Svenki 	short	sval;
133*3941Svenki 	char	cval;
134*3941Svenki 
135*3941Svenki 	size_t	valsz;
136*3941Svenki 	uchar_t	*p, *valp;
137*3941Svenki 
138*3941Svenki 	/*
139*3941Svenki 	 * We need to "pack" the integer before sending it, so determine
140*3941Svenki 	 * the minimum number of bytes in which we can pack the integer
141*3941Svenki 	 */
142*3941Svenki 	uival = ((uint_t)val >> BUILD_INT_SHIFT) & BUILD_INT_MASK;
143*3941Svenki 	ival = val;
144*3941Svenki 	sval = (short)val;	/* yes, loss of data intended */
145*3941Svenki 	cval = (char)val;	/* yes, loss of data intended */
146*3941Svenki 
147*3941Svenki 	if (val == (int)cval)
148*3941Svenki 		valsz = 1;
149*3941Svenki 	else if (val == (int)sval)
150*3941Svenki 		valsz = 2;
151*3941Svenki 	else if (uival == BUILD_INT_MASK || uival == 0)
152*3941Svenki 		valsz = 3;
153*3941Svenki 	else
154*3941Svenki 		valsz = 4;
155*3941Svenki 
156*3941Svenki 	/*
157*3941Svenki 	 * Prepare the ASN.1 header for the integer
158*3941Svenki 	 */
159*3941Svenki 	if ((p = asn_build_header(buf, bufsz_p, id, valsz)) == NULL)
160*3941Svenki 		return (NULL);
161*3941Svenki 
162*3941Svenki 	/*
163*3941Svenki 	 * If we have enough space left, encode the integer
164*3941Svenki 	 */
165*3941Svenki 	if (*bufsz_p < valsz)
166*3941Svenki 		return (NULL);
167*3941Svenki 	else {
168*3941Svenki 		valp = (uchar_t *)&ival;
169*3941Svenki 		for (i = 0; i < valsz; i++)
170*3941Svenki 			p[i] = valp[sizeof (int) - valsz + i];
171*3941Svenki 
172*3941Svenki 		*bufsz_p -= valsz;
173*3941Svenki 
174*3941Svenki 		LOGASNINT(buf, p + valsz - buf);
175*3941Svenki 
176*3941Svenki 		return (p + valsz);
177*3941Svenki 	}
178*3941Svenki }
179*3941Svenki /*
180*3941Svenki  * Builds an ASN.1 encoded octet string in the buffer. The source string
181*3941Svenki  * need not be null-terminated.
182*3941Svenki  */
183*3941Svenki uchar_t *
asn_build_string(uchar_t * buf,size_t * bufsz_p,uchar_t id,uchar_t * str,size_t slen)184*3941Svenki asn_build_string(uchar_t *buf, size_t *bufsz_p, uchar_t id, uchar_t *str,
185*3941Svenki     size_t slen)
186*3941Svenki {
187*3941Svenki 	uchar_t	*p;
188*3941Svenki 
189*3941Svenki 	if ((p = asn_build_header(buf, bufsz_p, id, slen)) == NULL)
190*3941Svenki 		return (NULL);
191*3941Svenki 
192*3941Svenki 	if (*bufsz_p < slen)
193*3941Svenki 		return (NULL);
194*3941Svenki 	else {
195*3941Svenki 	    if (str) {
196*3941Svenki 		    (void) memcpy(p, str, slen);
197*3941Svenki 	    } else {
198*3941Svenki 		    (void) memset(p, 0, slen);
199*3941Svenki 	    }
200*3941Svenki 
201*3941Svenki 	    *bufsz_p -= slen;
202*3941Svenki 
203*3941Svenki 	    LOGASNOCTSTR(buf, p + slen - buf);
204*3941Svenki 
205*3941Svenki 	    return (p + slen);
206*3941Svenki 	}
207*3941Svenki }
208*3941Svenki 
209*3941Svenki /*
210*3941Svenki  * Builds an Object Identifier into the buffer according to the OID
211*3941Svenki  * packing and encoding rules.
212*3941Svenki  */
213*3941Svenki uchar_t *
asn_build_objid(uchar_t * buf,size_t * bufsz_p,uchar_t id,void * oidp,size_t n_subids)214*3941Svenki asn_build_objid(uchar_t *buf, size_t *bufsz_p, uchar_t id, void *oidp,
215*3941Svenki     size_t n_subids)
216*3941Svenki {
217*3941Svenki 	oid	*objid = oidp;
218*3941Svenki 	size_t	oid_asnlen;
219*3941Svenki 	oid	subid, first_subid;
220*3941Svenki 	uchar_t	subid_len[MAX_SUBIDS_IN_OID];
221*3941Svenki 	uchar_t	*p;
222*3941Svenki 	int	i, ndx;
223*3941Svenki 
224*3941Svenki 	/*
225*3941Svenki 	 * Eliminate invalid cases
226*3941Svenki 	 */
227*3941Svenki 	if (n_subids < MIN_SUBIDS_IN_OID || n_subids > MAX_SUBIDS_IN_OID)
228*3941Svenki 		return (NULL);
229*3941Svenki 	if ((objid[0] > 2) || (objid[0] < 2 && objid[1] >= 40))
230*3941Svenki 		return (NULL);
231*3941Svenki 
232*3941Svenki 	/*
233*3941Svenki 	 * The BER encoding rule for the ASN.1 Object Identifier states
234*3941Svenki 	 * that after packing the first two subids into one, each subsequent
235*3941Svenki 	 * component is considered as the next subid. Each subidentifier is
236*3941Svenki 	 * then encoded as a non-negative integer using as few 7-bit blocks
237*3941Svenki 	 * as possible. The blocks are packed in octets with the first bit of
238*3941Svenki 	 * each octet equal to 1, except for the last octet of each subid.
239*3941Svenki 	 */
240*3941Svenki 	oid_asnlen = 0;
241*3941Svenki 	for (i = 0, ndx = 0; i < n_subids; i++, ndx++) {
242*3941Svenki 		if (i == 0) {
243*3941Svenki 			/*
244*3941Svenki 			 * The packing formula for the first two subids
245*3941Svenki 			 * of an OID is given by Z = (X * 40) + Y
246*3941Svenki 			 */
247*3941Svenki 			subid = objid[0] * 40 + objid[1];
248*3941Svenki 			first_subid = subid;
249*3941Svenki 			i++;	/* done with both subids 0 and 1 */
250*3941Svenki 		} else {
251*3941Svenki 			subid = objid[i];
252*3941Svenki 		}
253*3941Svenki 
254*3941Svenki 		if (subid < (oid) 0x80)
255*3941Svenki 			subid_len[ndx] = 1;
256*3941Svenki 		else if (subid < (oid) 0x4000)
257*3941Svenki 			subid_len[ndx] = 2;
258*3941Svenki 		else if (subid < (oid) 0x200000)
259*3941Svenki 			subid_len[ndx] = 3;
260*3941Svenki 		else if (subid < (oid) 0x10000000)
261*3941Svenki 			subid_len[ndx] = 4;
262*3941Svenki 		else {
263*3941Svenki 			subid_len[ndx] = 5;
264*3941Svenki 		}
265*3941Svenki 
266*3941Svenki 		oid_asnlen += subid_len[ndx];
267*3941Svenki 	}
268*3941Svenki 
269*3941Svenki 	if ((p = asn_build_header(buf, bufsz_p, id, oid_asnlen)) == NULL)
270*3941Svenki 		return (NULL);
271*3941Svenki 
272*3941Svenki 	if (*bufsz_p < oid_asnlen)
273*3941Svenki 		return (NULL);
274*3941Svenki 
275*3941Svenki 	/*
276*3941Svenki 	 * Store the encoded OID
277*3941Svenki 	 */
278*3941Svenki 	for (i = 0, ndx = 0; i < n_subids; i++, ndx++) {
279*3941Svenki 		if (i == 0) {
280*3941Svenki 			subid = first_subid;
281*3941Svenki 			i++;
282*3941Svenki 		} else {
283*3941Svenki 			subid = objid[i];
284*3941Svenki 		}
285*3941Svenki 
286*3941Svenki 		switch (subid_len[ndx]) {
287*3941Svenki 		case 1:
288*3941Svenki 			*p++ = (uchar_t)subid;
289*3941Svenki 			break;
290*3941Svenki 
291*3941Svenki 		case 2:
292*3941Svenki 			*p++ = (uchar_t)((subid >> 7) | 0x80);
293*3941Svenki 			*p++ = (uchar_t)(subid & 0x7f);
294*3941Svenki 			break;
295*3941Svenki 
296*3941Svenki 		case 3:
297*3941Svenki 			*p++ = (uchar_t)((subid >> 14) | 0x80);
298*3941Svenki 			*p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80);
299*3941Svenki 			*p++ = (uchar_t)(subid & 0x7f);
300*3941Svenki 			break;
301*3941Svenki 
302*3941Svenki 		case 4:
303*3941Svenki 			*p++ = (uchar_t)((subid >> 21) | 0x80);
304*3941Svenki 			*p++ = (uchar_t)(((subid >> 14) & 0x7f) | 0x80);
305*3941Svenki 			*p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80);
306*3941Svenki 			*p++ = (uchar_t)(subid & 0x7f);
307*3941Svenki 			break;
308*3941Svenki 
309*3941Svenki 		case 5:
310*3941Svenki 			*p++ = (uchar_t)((subid >> 28) | 0x80);
311*3941Svenki 			*p++ = (uchar_t)(((subid >> 21) & 0x7f) | 0x80);
312*3941Svenki 			*p++ = (uchar_t)(((subid >> 14) & 0x7f) | 0x80);
313*3941Svenki 			*p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80);
314*3941Svenki 			*p++ = (uchar_t)(subid & 0x7f);
315*3941Svenki 			break;
316*3941Svenki 		}
317*3941Svenki 	}
318*3941Svenki 
319*3941Svenki 	*bufsz_p -= oid_asnlen;
320*3941Svenki 
321*3941Svenki 	LOGASNOID(buf, p - buf);
322*3941Svenki 
323*3941Svenki 	return (p);
324*3941Svenki }
325*3941Svenki /*
326*3941Svenki  * Build an ASN_NULL object val into the request packet
327*3941Svenki  */
328*3941Svenki uchar_t *
asn_build_null(uchar_t * buf,size_t * bufsz_p,uchar_t id)329*3941Svenki asn_build_null(uchar_t *buf, size_t *bufsz_p, uchar_t id)
330*3941Svenki {
331*3941Svenki 	uchar_t	*p;
332*3941Svenki 
333*3941Svenki 	p = asn_build_header(buf, bufsz_p, id, 0);
334*3941Svenki 
335*3941Svenki 	LOGASNNULL(buf, p - buf);
336*3941Svenki 
337*3941Svenki 	return (p);
338*3941Svenki }
339*3941Svenki 
340*3941Svenki 
341*3941Svenki 
342*3941Svenki /*
343*3941Svenki  * This routine parses a 'SEQUENCE OF' object header from the input
344*3941Svenki  * buffer stream. If the identifier tag (made up of class, constructed
345*3941Svenki  * type and data type tag) does not match the expected identifier tag,
346*3941Svenki  * returns failure.
347*3941Svenki  */
348*3941Svenki uchar_t *
asn_parse_sequence(uchar_t * buf,size_t * bufsz_p,uchar_t exp_id)349*3941Svenki asn_parse_sequence(uchar_t *buf, size_t *bufsz_p, uchar_t exp_id)
350*3941Svenki {
351*3941Svenki 	uchar_t	*p;
352*3941Svenki 	uchar_t	id;
353*3941Svenki 
354*3941Svenki 	if ((p = asn_parse_header(buf, bufsz_p, &id)) == NULL)
355*3941Svenki 		return (NULL);
356*3941Svenki 
357*3941Svenki 	if (id != exp_id)
358*3941Svenki 		return (NULL);
359*3941Svenki 
360*3941Svenki 	return (p);
361*3941Svenki }
362*3941Svenki /*
363*3941Svenki  * Return the type identifier of the ASN object via 'id'
364*3941Svenki  */
365*3941Svenki uchar_t *
asn_parse_header(uchar_t * buf,size_t * bufsz_p,uchar_t * id)366*3941Svenki asn_parse_header(uchar_t *buf, size_t *bufsz_p, uchar_t *id)
367*3941Svenki {
368*3941Svenki 	uchar_t	*p;
369*3941Svenki 	size_t	asnobj_len, hdrlen;
370*3941Svenki 
371*3941Svenki 	/*
372*3941Svenki 	 * Objects with extension tag type are not supported
373*3941Svenki 	 */
374*3941Svenki 	if ((buf[0] & ASN_EXT_TAG) == ASN_EXT_TAG)
375*3941Svenki 		return (NULL);
376*3941Svenki 
377*3941Svenki 	/*
378*3941Svenki 	 * Parse the length field of the ASN object in the header
379*3941Svenki 	 */
380*3941Svenki 	if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL)
381*3941Svenki 		return (NULL);
382*3941Svenki 
383*3941Svenki 	/*
384*3941Svenki 	 * Check if the rest of the msg packet is big enough for the
385*3941Svenki 	 * full length of the object
386*3941Svenki 	 */
387*3941Svenki 	hdrlen = p - buf;
388*3941Svenki 	if (*bufsz_p < (asnobj_len + hdrlen))
389*3941Svenki 		return (NULL);
390*3941Svenki 
391*3941Svenki 	*id = buf[0];
392*3941Svenki 	*bufsz_p -= hdrlen;
393*3941Svenki 
394*3941Svenki 	return (p);
395*3941Svenki }
396*3941Svenki /*
397*3941Svenki  * This routine parses the length of the object as specified in its
398*3941Svenki  * header. The 'Indefinite' form of representing length is not supported.
399*3941Svenki  */
400*3941Svenki uchar_t *
asn_parse_length(uchar_t * buf,size_t * asnobj_len_p)401*3941Svenki asn_parse_length(uchar_t *buf, size_t *asnobj_len_p)
402*3941Svenki {
403*3941Svenki 	uchar_t	*p;
404*3941Svenki 	int	n_length_octets;
405*3941Svenki 
406*3941Svenki 	/*
407*3941Svenki 	 * First, check for the short-definite form. Length of
408*3941Svenki 	 * the object is simply the least significant 7-bits of
409*3941Svenki 	 * the first byte.
410*3941Svenki 	 */
411*3941Svenki 	if ((buf[0] & ASN_LONG_LEN) == 0) {
412*3941Svenki 		*asnobj_len_p = (size_t)buf[0];
413*3941Svenki 		return (buf + 1);
414*3941Svenki 	}
415*3941Svenki 
416*3941Svenki 	/*
417*3941Svenki 	 * Then, eliminate the indefinite form. The ASN_LONG_LEN
418*3941Svenki 	 * bit of the first byte will be set and the least significant
419*3941Svenki 	 * 7-bites of that byte will be zeros.
420*3941Svenki 	 */
421*3941Svenki 	if (buf[0] == (uchar_t)ASN_LONG_LEN)
422*3941Svenki 		return (NULL);
423*3941Svenki 
424*3941Svenki 	/*
425*3941Svenki 	 * Then, eliminate the long-definite case when the number of
426*3941Svenki 	 * follow-up octets is more than what the size var can hold.
427*3941Svenki 	 */
428*3941Svenki 	n_length_octets = buf[0] & ~ASN_LONG_LEN;
429*3941Svenki 	if (n_length_octets > sizeof (*asnobj_len_p))
430*3941Svenki 		return (NULL);
431*3941Svenki 
432*3941Svenki 	/*
433*3941Svenki 	 * Finally gather the length
434*3941Svenki 	 */
435*3941Svenki 	p = buf + 1;
436*3941Svenki 	*asnobj_len_p = 0;
437*3941Svenki 	while (n_length_octets--) {
438*3941Svenki 		*asnobj_len_p <<= 8;
439*3941Svenki 		*asnobj_len_p |= *p++;
440*3941Svenki 	}
441*3941Svenki 
442*3941Svenki 	return (p);
443*3941Svenki }
444*3941Svenki /*
445*3941Svenki  * Parses an integer out of the input buffer
446*3941Svenki  */
447*3941Svenki uchar_t *
asn_parse_int(uchar_t * buf,size_t * bufsz_p,int * ival)448*3941Svenki asn_parse_int(uchar_t *buf, size_t *bufsz_p, int *ival)
449*3941Svenki {
450*3941Svenki 	size_t	asnobj_len, hdrlen;
451*3941Svenki 	uchar_t	int_id;
452*3941Svenki 	uchar_t	*p;
453*3941Svenki 
454*3941Svenki 	int_id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER;
455*3941Svenki 	if (buf[0] != int_id)
456*3941Svenki 		return (NULL);
457*3941Svenki 
458*3941Svenki 	/*
459*3941Svenki 	 * Read in the length of the object; Note that integers are
460*3941Svenki 	 * "packed" when sent from agent to manager and vice-versa,
461*3941Svenki 	 * so the size of the object could be less than sizeof (int).
462*3941Svenki 	 */
463*3941Svenki 	if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL)
464*3941Svenki 		return (NULL);
465*3941Svenki 
466*3941Svenki 	/*
467*3941Svenki 	 * Is there sufficient space left in the packet to read the integer ?
468*3941Svenki 	 */
469*3941Svenki 	hdrlen = p - buf;
470*3941Svenki 	if (*bufsz_p < (hdrlen + asnobj_len))
471*3941Svenki 		return (NULL);
472*3941Svenki 
473*3941Svenki 	/*
474*3941Svenki 	 * Update space left in the buffer after the integer is read
475*3941Svenki 	 */
476*3941Svenki 	*bufsz_p -= (hdrlen + asnobj_len);
477*3941Svenki 
478*3941Svenki 	/*
479*3941Svenki 	 * Read in the integer value
480*3941Svenki 	 */
481*3941Svenki 	*ival = (*p & ASN_BIT8) ? -1 : 0;
482*3941Svenki 	while (asnobj_len--) {
483*3941Svenki 		*ival <<= 8;
484*3941Svenki 		*ival |= *p++;
485*3941Svenki 	}
486*3941Svenki 
487*3941Svenki 	return (p);
488*3941Svenki }
489*3941Svenki /*
490*3941Svenki  * Parses an unsigned integer out of the input buffer
491*3941Svenki  */
492*3941Svenki uchar_t *
asn_parse_uint(uchar_t * buf,size_t * bufsz_p,uint_t * uival)493*3941Svenki asn_parse_uint(uchar_t *buf, size_t *bufsz_p, uint_t *uival)
494*3941Svenki {
495*3941Svenki 	size_t	asnobj_len, hdrlen;
496*3941Svenki 	uchar_t	*p;
497*3941Svenki 
498*3941Svenki 	if ((buf[0] != ASN_COUNTER) && (buf[0] != ASN_TIMETICKS))
499*3941Svenki 		return (NULL);
500*3941Svenki 
501*3941Svenki 	/*
502*3941Svenki 	 * Read in the length of the object. Integers are sent the same
503*3941Svenki 	 * way unsigned integers are sent.  Except that, if the MSB was 1
504*3941Svenki 	 * in the unsigned int value, a null-byte is attached to the front.
505*3941Svenki 	 * Otherwise, packing rules are the same as for integer values.
506*3941Svenki 	 */
507*3941Svenki 	if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL)
508*3941Svenki 		return (NULL);
509*3941Svenki 
510*3941Svenki 	/*
511*3941Svenki 	 * Is there sufficient space left in the packet to read in the value ?
512*3941Svenki 	 */
513*3941Svenki 	hdrlen = p - buf;
514*3941Svenki 	if (*bufsz_p < (hdrlen + asnobj_len))
515*3941Svenki 		return (NULL);
516*3941Svenki 
517*3941Svenki 	/*
518*3941Svenki 	 * Update space left in the buffer after the uint is read
519*3941Svenki 	 */
520*3941Svenki 	*bufsz_p -= (hdrlen + asnobj_len);
521*3941Svenki 
522*3941Svenki 	/*
523*3941Svenki 	 * Read in the unsigned integer (this should never get
524*3941Svenki 	 * initialized to ~0 if it was sent right)
525*3941Svenki 	 */
526*3941Svenki 	*uival = (*p & ASN_BIT8) ? ~0 : 0;
527*3941Svenki 	while (asnobj_len--) {
528*3941Svenki 		*uival <<= 8;
529*3941Svenki 		*uival |= *p++;
530*3941Svenki 	}
531*3941Svenki 
532*3941Svenki 	return (p);
533*3941Svenki }
534*3941Svenki /*
535*3941Svenki  * Parses a string (ASN_OCTET_STR or ASN_BIT_STR) out of the input buffer.
536*3941Svenki  * The memory for the string is allocated inside the routine and must be
537*3941Svenki  * freed by the caller when it is no longer needed. If the string type is
538*3941Svenki  * ASN_OCTET_STR, the returned string is null-terminated, and the returned
539*3941Svenki  * length indicates the strlen value. If the string type is ASN_BIT_STR,
540*3941Svenki  * the returned string is not null-terminated, and the returned length
541*3941Svenki  * indicates the number of bytes.
542*3941Svenki  */
543*3941Svenki uchar_t *
asn_parse_string(uchar_t * buf,size_t * bufsz_p,uchar_t ** str_p,size_t * slen)544*3941Svenki asn_parse_string(uchar_t *buf, size_t *bufsz_p, uchar_t **str_p, size_t *slen)
545*3941Svenki {
546*3941Svenki 	uchar_t	*p;
547*3941Svenki 	uchar_t	id1, id2;
548*3941Svenki 	size_t	asnobj_len, hdrlen;
549*3941Svenki 
550*3941Svenki 	/*
551*3941Svenki 	 * Octet and bit strings are supported
552*3941Svenki 	 */
553*3941Svenki 	id1 = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR;
554*3941Svenki 	id2 = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_BIT_STR;
555*3941Svenki 	if ((buf[0] != id1) && (buf[0] != id2))
556*3941Svenki 		return (NULL);
557*3941Svenki 
558*3941Svenki 	/*
559*3941Svenki 	 * Parse out the length of the object and verify source buf sz
560*3941Svenki 	 */
561*3941Svenki 	if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL)
562*3941Svenki 		return (NULL);
563*3941Svenki 
564*3941Svenki 	hdrlen = p - buf;
565*3941Svenki 	if (*bufsz_p < (hdrlen + asnobj_len))
566*3941Svenki 		return (NULL);
567*3941Svenki 
568*3941Svenki 	/*
569*3941Svenki 	 * Allocate for and copy out the string
570*3941Svenki 	 */
571*3941Svenki 	if ((*str_p = (uchar_t *)calloc(1, asnobj_len + 1)) == NULL)
572*3941Svenki 		return (NULL);
573*3941Svenki 
574*3941Svenki 	(void) memcpy(*str_p, p, asnobj_len);
575*3941Svenki 
576*3941Svenki 	/*
577*3941Svenki 	 * Terminate the octet string with a null
578*3941Svenki 	 */
579*3941Svenki 	if (buf[0] == id1) {
580*3941Svenki 		(*str_p)[asnobj_len] = 0;
581*3941Svenki 	}
582*3941Svenki 
583*3941Svenki 	/*
584*3941Svenki 	 * Update pointers and return
585*3941Svenki 	 */
586*3941Svenki 	*slen = asnobj_len;
587*3941Svenki 	*bufsz_p -= (hdrlen + asnobj_len);
588*3941Svenki 
589*3941Svenki 	return (p + asnobj_len);
590*3941Svenki }
591*3941Svenki /*
592*3941Svenki  * Parses an object identifier out of the input packet buffer. Space for
593*3941Svenki  * the oid object is allocated within this routine and must be freed by the
594*3941Svenki  * caller when no longer needed.
595*3941Svenki  */
596*3941Svenki uchar_t *
asn_parse_objid(uchar_t * msg,size_t * varsz_p,void * oidp,size_t * n_subids)597*3941Svenki asn_parse_objid(uchar_t *msg, size_t *varsz_p, void *oidp, size_t *n_subids)
598*3941Svenki {
599*3941Svenki 	oid	**objid_p = oidp;
600*3941Svenki 	oid	*objid;
601*3941Svenki 	uchar_t	*p;
602*3941Svenki 	size_t	hdrlen, asnobj_len;
603*3941Svenki 	oid	subid;
604*3941Svenki 	int	i, ndx;
605*3941Svenki 	uchar_t	exp_id;
606*3941Svenki 
607*3941Svenki 	/*
608*3941Svenki 	 * Check id
609*3941Svenki 	 */
610*3941Svenki 	exp_id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID;
611*3941Svenki 	if (msg[0] != exp_id)
612*3941Svenki 		return (NULL);
613*3941Svenki 
614*3941Svenki 	/*
615*3941Svenki 	 * Read object length
616*3941Svenki 	 */
617*3941Svenki 	if ((p = asn_parse_length(msg + 1, &asnobj_len)) == NULL)
618*3941Svenki 		return (NULL);
619*3941Svenki 
620*3941Svenki 	/*
621*3941Svenki 	 * Check space in input message
622*3941Svenki 	 */
623*3941Svenki 	hdrlen = p - msg;
624*3941Svenki 	if (*varsz_p < (hdrlen + asnobj_len))
625*3941Svenki 		return (NULL);
626*3941Svenki 
627*3941Svenki 	/*
628*3941Svenki 	 * Since the OID subidentifiers are packed in 7-bit blocks with
629*3941Svenki 	 * MSB set to 1 for all but the last octet, the number of subids
630*3941Svenki 	 * is simply the number of octets with MSB equal to 0, plus 1
631*3941Svenki 	 * (since the first two subids were packed into one subid and have
632*3941Svenki 	 * to be expanded back to two).
633*3941Svenki 	 */
634*3941Svenki 	*n_subids = 1;
635*3941Svenki 	for (i = 0; i < asnobj_len; i++) {
636*3941Svenki 		if ((p[i] & ASN_BIT8) == 0)
637*3941Svenki 			(*n_subids)++;
638*3941Svenki 	}
639*3941Svenki 
640*3941Svenki 	/*
641*3941Svenki 	 * Now allocate for the oid and parse the OID into it
642*3941Svenki 	 */
643*3941Svenki 	if ((objid = (oid *) calloc(1, (*n_subids) * sizeof (oid))) == NULL)
644*3941Svenki 		return (NULL);
645*3941Svenki 
646*3941Svenki 	ndx = 1;	/* start from 1 to allow for unpacking later */
647*3941Svenki 	subid = 0;
648*3941Svenki 	for (i = 0; i < asnobj_len; i++) {
649*3941Svenki 		subid = subid << 7;
650*3941Svenki 		subid |= (p[i] & ~ASN_BIT8);
651*3941Svenki 
652*3941Svenki 		if ((p[i] & ASN_BIT8) == 0) {
653*3941Svenki 			objid[ndx] = subid;
654*3941Svenki 			ndx++;
655*3941Svenki 			subid = 0;
656*3941Svenki 		}
657*3941Svenki 	}
658*3941Svenki 
659*3941Svenki 	/*
660*3941Svenki 	 * Now unpack the first two subids from the subid at index 1.
661*3941Svenki 	 */
662*3941Svenki 	if (objid[1] < 40) {
663*3941Svenki 		objid[0] = 0;
664*3941Svenki 	} else if (objid[1] < 80) {
665*3941Svenki 		objid[0] = 1;
666*3941Svenki 		objid[1] -= 40;
667*3941Svenki 	} else {
668*3941Svenki 		objid[0] = 2;
669*3941Svenki 		objid[1] -= 80;
670*3941Svenki 	}
671*3941Svenki 
672*3941Svenki 	*objid_p = objid;
673*3941Svenki 	*varsz_p -= (hdrlen + asnobj_len);
674*3941Svenki 
675*3941Svenki 	return (msg + hdrlen + asnobj_len);
676*3941Svenki }
677*3941Svenki /*
678*3941Svenki  * Parses the value of an OID object out of the input message buffer.
679*3941Svenki  * Only type tags less than ASN_EXT_TAG (0x1f) are supported.
680*3941Svenki  */
681*3941Svenki uchar_t *
asn_parse_objval(uchar_t * msg,size_t * varsz_p,void * varlistp)682*3941Svenki asn_parse_objval(uchar_t *msg, size_t *varsz_p, void *varlistp)
683*3941Svenki {
684*3941Svenki 	pdu_varlist_t	*vp = varlistp;
685*3941Svenki 	uchar_t	*p;
686*3941Svenki 	size_t	n_subids;
687*3941Svenki 	size_t	hdrlen, asnobj_len;
688*3941Svenki 
689*3941Svenki 	vp->type = msg[0] & ASN_EXT_TAG;
690*3941Svenki 	if (vp->type == ASN_EXT_TAG)
691*3941Svenki 		return (NULL);
692*3941Svenki 
693*3941Svenki 	/*
694*3941Svenki 	 * Currently we handle ASN_INTEGER, ASN_OCTET_STR, ASN_BIT_STR
695*3941Svenki 	 * and ASN_TIMETICKS types.
696*3941Svenki 	 */
697*3941Svenki 	switch (msg[0]) {
698*3941Svenki 	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER:
699*3941Svenki 		vp->val.iptr = (int *)calloc(1, sizeof (int));
700*3941Svenki 		if (vp->val.iptr == NULL)
701*3941Svenki 			return (NULL);
702*3941Svenki 
703*3941Svenki 		if ((p = asn_parse_int(msg, varsz_p, vp->val.iptr)) == NULL) {
704*3941Svenki 			free(vp->val.iptr);
705*3941Svenki 			return (NULL);
706*3941Svenki 		}
707*3941Svenki 		vp->val_len = sizeof (int);
708*3941Svenki 		break;
709*3941Svenki 
710*3941Svenki 	case ASN_COUNTER:
711*3941Svenki 	case ASN_TIMETICKS:
712*3941Svenki 		vp->val.uiptr = (uint_t *)calloc(1, sizeof (uint_t));
713*3941Svenki 		if (vp->val.uiptr == NULL)
714*3941Svenki 			return (NULL);
715*3941Svenki 
716*3941Svenki 		if ((p = asn_parse_uint(msg, varsz_p, vp->val.uiptr)) == NULL) {
717*3941Svenki 			free(vp->val.uiptr);
718*3941Svenki 			return (NULL);
719*3941Svenki 		}
720*3941Svenki 		vp->val_len = sizeof (uint_t);
721*3941Svenki 		vp->type = msg[0];
722*3941Svenki 		break;
723*3941Svenki 
724*3941Svenki 	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR:
725*3941Svenki 	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_BIT_STR:
726*3941Svenki 		p = asn_parse_string(msg, varsz_p, &vp->val.str, &vp->val_len);
727*3941Svenki 		if (p == NULL)
728*3941Svenki 			return (NULL);
729*3941Svenki 		break;
730*3941Svenki 
731*3941Svenki 	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID:
732*3941Svenki 		p = asn_parse_objid(msg, varsz_p, &vp->val.objid, &n_subids);
733*3941Svenki 		if (p == NULL)
734*3941Svenki 			return (NULL);
735*3941Svenki 		vp->val_len = n_subids * sizeof (oid);
736*3941Svenki 		break;
737*3941Svenki 
738*3941Svenki 	case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_NULL:
739*3941Svenki 	case SNMP_NOSUCHOBJECT:
740*3941Svenki 	case SNMP_NOSUCHINSTANCE:
741*3941Svenki 	case SNMP_ENDOFMIBVIEW:
742*3941Svenki 	default:
743*3941Svenki 		p = asn_parse_length(msg + 1, &asnobj_len);
744*3941Svenki 		if (p == NULL)
745*3941Svenki 			return (NULL);
746*3941Svenki 
747*3941Svenki 		hdrlen = p - msg;
748*3941Svenki 		if (*varsz_p < (hdrlen + asnobj_len))
749*3941Svenki 			return (NULL);
750*3941Svenki 
751*3941Svenki 		vp->type = msg[0];
752*3941Svenki 		vp->val_len = asnobj_len;
753*3941Svenki 
754*3941Svenki 		*varsz_p -= (hdrlen + asnobj_len);
755*3941Svenki 		p += asnobj_len;
756*3941Svenki 		break;
757*3941Svenki 	}
758*3941Svenki 
759*3941Svenki 	return (p);
760*3941Svenki }
761