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