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