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