xref: /illumos-gate/usr/src/lib/libkmf/ber_der/common/decode.c (revision fbb63b428340370268557fdc3b3f35e789a0445e)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /*
26  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
27  *
28  * The contents of this file are subject to the Netscape Public License
29  * Version 1.0 (the "NPL"); you may not use this file except in
30  * compliance with the NPL.  You may obtain a copy of the NPL at
31  * http://www.mozilla.org/NPL/
32  *
33  * Software distributed under the NPL is distributed on an "AS IS" basis,
34  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
35  * for the specific language governing rights and limitations under the
36  * NPL.
37  *
38  * The Initial Developer of this code under the NPL is Netscape
39  * Communications Corporation.  Portions created by Netscape are
40  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
41  * Reserved.
42  */
43 
44 /*
45  * Copyright (c) 1990 Regents of the University of Michigan.
46  * All rights reserved.
47  *
48  * Redistribution and use in source and binary forms are permitted
49  * provided that this notice is preserved and that due credit is given
50  * to the University of Michigan at Ann Arbor. The name of the University
51  * may not be used to endorse or promote products derived from this
52  * software without specific prior written permission. This software
53  * is provided ``as is'' without express or implied warranty.
54  */
55 
56 /* decode.c - ber input decoding routines */
57 
58 #pragma ident	"%Z%%M%	%I%	%E% SMI"
59 
60 #include <strings.h>
61 #include <sys/types.h>
62 #include <netinet/in.h>
63 #include <inttypes.h>
64 
65 #include <ber_der.h>
66 #include "kmfber_int.h"
67 
68 static void
69 ber_svecfree(char **vals)
70 {
71 	int	i;
72 
73 	if (vals == NULL)
74 		return;
75 	for (i = 0; vals[i] != NULL; i++)
76 		free(vals[i]);
77 	free((char *)vals);
78 }
79 
80 /*
81  * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
82  * If that changes, the kmfber_peek_tag() and/or
83  * kmfkmfber_skip_tag() implementations will need to be changed.
84  */
85 /* return the tag - KMFBER_DEFAULT returned means trouble */
86 static ber_tag_t
87 kmfber_get_tag(BerElement *ber)
88 {
89 	unsigned char	xbyte;
90 	ber_tag_t	tag;
91 	char		*tagp;
92 	int		i;
93 
94 	if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
95 		return (KMFBER_DEFAULT);
96 
97 	if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
98 		return ((ber_uint_t)xbyte);
99 
100 	tagp = (char *)&tag;
101 	tagp[0] = xbyte;
102 	for (i = 1; i < sizeof (ber_int_t); i++) {
103 		if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
104 			return (KMFBER_DEFAULT);
105 
106 		tagp[i] = xbyte;
107 
108 		if (! (xbyte & KMFBER_MORE_TAG_MASK))
109 			break;
110 	}
111 
112 	/* tag too big! */
113 	if (i == sizeof (ber_int_t))
114 		return (KMFBER_DEFAULT);
115 
116 	/* want leading, not trailing 0's */
117 	return (tag >> (sizeof (ber_int_t)- i - 1));
118 }
119 
120 /*
121  * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
122  * If that changes, the implementation of kmfber_peek_tag() will need to
123  * be changed.
124  */
125 ber_tag_t
126 kmfber_skip_tag(BerElement *ber, ber_len_t *len)
127 {
128 	ber_tag_t	tag;
129 	unsigned char	lc;
130 	int		noctets, diff;
131 	uint32_t	netlen;
132 
133 	/*
134 	 * Any ber element looks like this: tag length contents.
135 	 * Assuming everything's ok, we return the tag byte (we
136 	 * can assume a single byte), and return the length in len.
137 	 *
138 	 * Assumptions:
139 	 *	1) definite lengths
140 	 *	2) primitive encodings used whenever possible
141 	 */
142 
143 	/*
144 	 * First, we read the tag.
145 	 */
146 
147 	if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
148 		return (KMFBER_DEFAULT);
149 
150 	/*
151 	 * Next, read the length.  The first byte contains the length of
152 	 * the length.  If bit 8 is set, the length is the long form,
153 	 * otherwise it's the short form.  We don't allow a length that's
154 	 * greater than what we can hold in an unsigned long.
155 	 */
156 
157 	*len = 0;
158 	netlen = 0;
159 	if (kmfber_read(ber, (char *)&lc, 1) != 1)
160 		return (KMFBER_DEFAULT);
161 	if (lc & 0x80) {
162 		noctets = (lc & 0x7f);
163 		if (noctets > sizeof (ber_uint_t))
164 			return (KMFBER_DEFAULT);
165 		diff = sizeof (ber_int_t) - noctets;
166 		if (kmfber_read(ber, (char *)&netlen + diff, noctets)
167 			!= noctets)
168 			return (KMFBER_DEFAULT);
169 		*len = ntohl(netlen);
170 	} else {
171 		*len = lc;
172 	}
173 
174 	return (tag);
175 }
176 
177 
178 /*
179  * Note: Previously, we passed the "ber" parameter directly to
180  * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
181  * We now take advantage of the fact that the only ber structure
182  * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
183  * If that changes, this code must change too.
184  */
185 static ber_tag_t
186 kmfber_peek_tag(BerElement *ber, ber_len_t *len)
187 {
188 	BerElement	bercopy;
189 
190 	bercopy.ber_end = ber->ber_end;
191 	bercopy.ber_ptr = ber->ber_ptr;
192 	return (kmfber_skip_tag(&bercopy, len));
193 }
194 
195 static int
196 ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
197 {
198 	int i;
199 	ber_int_t value;
200 	unsigned char buffer[sizeof (ber_int_t)];
201 	/*
202 	 * The tag and length have already been stripped off.  We should
203 	 * be sitting right before len bytes of 2's complement integer,
204 	 * ready to be read straight into an int.  We may have to sign
205 	 * extend after we read it in.
206 	 */
207 
208 	if (len > sizeof (ber_slen_t))
209 		return (-1);
210 
211 	/* read into the low-order bytes of netnum */
212 	if (kmfber_read(ber, (char *)buffer, len) != len)
213 		return (-1);
214 
215 	/* This sets the required sign extension */
216 	if (len != 0) {
217 		value = 0x80 & buffer[0] ? (-1) : 0;
218 	} else {
219 		value = 0;
220 	}
221 
222 	for (i = 0; i < len; i++)
223 		value = (value << 8) | buffer[i];
224 
225 	*num = value;
226 
227 	return (len);
228 }
229 
230 static ber_tag_t
231 kmfber_get_int(BerElement *ber, ber_int_t *num)
232 {
233 	ber_tag_t	tag;
234 	ber_len_t	len;
235 
236 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
237 		return (KMFBER_DEFAULT);
238 
239 	/*
240 	 * len is being demoted to a long here --  possible conversion error
241 	 */
242 
243 	if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
244 		return (KMFBER_DEFAULT);
245 	else
246 		return (tag);
247 }
248 
249 static ber_tag_t
250 kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
251 {
252 	ber_len_t	datalen;
253 	ber_tag_t	tag;
254 #ifdef STR_TRANSLATION
255 	char		*transbuf;
256 #endif /* STR_TRANSLATION */
257 
258 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
259 		return (KMFBER_DEFAULT);
260 	if (datalen > (*len - 1))
261 		return (KMFBER_DEFAULT);
262 
263 	/*
264 	 * datalen is being demoted to a long here --  possible conversion error
265 	 */
266 
267 	if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
268 		return (KMFBER_DEFAULT);
269 
270 	buf[datalen] = '\0';
271 
272 #ifdef STR_TRANSLATION
273 	if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
274 		!= 0 && ber->ber_decode_translate_proc != NULL) {
275 
276 		transbuf = buf;
277 		++datalen;
278 		if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
279 			0) != 0) {
280 			return (KMFBER_DEFAULT);
281 		}
282 		if (datalen > *len) {
283 			free(transbuf);
284 			return (KMFBER_DEFAULT);
285 		}
286 		(void) memmove(buf, transbuf, datalen);
287 		free(transbuf);
288 		--datalen;
289 	}
290 #endif /* STR_TRANSLATION */
291 
292 	*len = datalen;
293 	return (tag);
294 }
295 
296 static ber_tag_t
297 kmfber_get_stringa(BerElement *ber, char **buf)
298 {
299 	ber_len_t	datalen;
300 	ber_tag_t	tag;
301 
302 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
303 		return (KMFBER_DEFAULT);
304 
305 	if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
306 		return (KMFBER_DEFAULT);
307 
308 	/*
309 	 * datalen is being demoted to a long here --  possible conversion error
310 	 */
311 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
312 		return (KMFBER_DEFAULT);
313 	(*buf)[datalen] = '\0';
314 
315 	return (tag);
316 }
317 
318 ber_tag_t
319 ber_get_oid(BerElement *ber, struct berval *oid)
320 {
321 	ber_len_t	len;
322 	ber_tag_t	tag;
323 
324 	if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
325 		return (KMFBER_DEFAULT);
326 	}
327 
328 	if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
329 		return (KMFBER_DEFAULT);
330 	}
331 	oid->bv_len = len;
332 
333 	if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
334 		(ber_slen_t)oid->bv_len)
335 		return (KMFBER_DEFAULT);
336 
337 	return (tag);
338 }
339 
340 ber_tag_t
341 ber_get_bigint(BerElement *ber, struct berval **bv)
342 {
343 	ber_len_t	len;
344 	ber_tag_t	tag;
345 
346 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
347 		== NULL) {
348 		return (KMFBER_DEFAULT);
349 	}
350 
351 	if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
352 		return (KMFBER_DEFAULT);
353 	}
354 
355 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
356 		== NULL) {
357 		return (KMFBER_DEFAULT);
358 	}
359 
360 	/*
361 	 * len is being demoted to a long here --  possible conversion error
362 	 */
363 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
364 		return (KMFBER_DEFAULT);
365 
366 	(*bv)->bv_len = len;
367 
368 	/* If DER encoding, strip leading 0's */
369 	if (ber->ber_options & KMFBER_OPT_USE_DER) {
370 		char *p = (*bv)->bv_val;
371 		while ((*p == 0x00) && ((*bv)->bv_len > 0)) {
372 			p++;
373 			(*bv)->bv_len--;
374 		}
375 		/*
376 		 * Shift the buffer to the beginning of the allocated space
377 		 * so it can be properly freed later.
378 		 */
379 		if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
380 			(void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
381 	}
382 
383 	return (tag);
384 }
385 
386 static ber_tag_t
387 kmfber_get_stringal(BerElement *ber, struct berval **bv)
388 {
389 	ber_len_t	len;
390 	ber_tag_t	tag;
391 
392 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
393 		== NULL) {
394 		return (KMFBER_DEFAULT);
395 	}
396 
397 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
398 		return (KMFBER_DEFAULT);
399 	}
400 
401 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
402 		== NULL) {
403 		return (KMFBER_DEFAULT);
404 	}
405 
406 	/*
407 	 * len is being demoted to a long here --  possible conversion error
408 	 */
409 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
410 		return (KMFBER_DEFAULT);
411 	((*bv)->bv_val)[len] = '\0';
412 	(*bv)->bv_len = len;
413 
414 	return (tag);
415 }
416 
417 static ber_tag_t
418 kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
419 {
420 	ber_len_t	datalen;
421 	ber_tag_t	tag;
422 	unsigned char	unusedbits;
423 
424 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
425 		return (KMFBER_DEFAULT);
426 
427 	if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
428 		return (KMFBER_DEFAULT);
429 
430 	if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
431 		return (KMFBER_DEFAULT);
432 
433 	/* Subtract 1 for the unused bits */
434 	datalen--;
435 
436 	/*
437 	 * datalen is being demoted to a long here --  possible conversion error
438 	 */
439 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
440 		return (KMFBER_DEFAULT);
441 
442 	*blen = datalen * 8 - unusedbits;
443 	return (tag);
444 }
445 
446 static ber_tag_t
447 kmfber_get_null(BerElement *ber)
448 {
449 	ber_len_t	len;
450 	ber_tag_t tag;
451 
452 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
453 		return (KMFBER_DEFAULT);
454 
455 	if (len != 0)
456 		return (KMFBER_DEFAULT);
457 
458 	return (tag);
459 }
460 
461 static ber_tag_t
462 kmfber_get_boolean(BerElement *ber, int *boolval)
463 {
464 	ber_int_t	longbool;
465 	int		rc;
466 
467 	rc = kmfber_get_int(ber, &longbool);
468 	*boolval = longbool;
469 
470 	return (rc);
471 }
472 
473 ber_tag_t
474 kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
475 {
476 	/* skip the sequence header, use the len to mark where to stop */
477 	if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
478 		return (KMFBER_ERROR);
479 	}
480 
481 	*last = ber->ber_ptr + *len;
482 
483 	if (*last == ber->ber_ptr) {
484 		return (KMFBER_END_OF_SEQORSET);
485 	}
486 
487 	return (kmfber_peek_tag(ber, len));
488 }
489 
490 ber_tag_t
491 kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
492 {
493 	if (ber->ber_ptr == last) {
494 		return (KMFBER_END_OF_SEQORSET);
495 	}
496 
497 	return (kmfber_peek_tag(ber, len));
498 }
499 
500 void
501 kmfber_bvfree(struct berval *bv)
502 {
503 	if (bv != NULL) {
504 		if (bv->bv_val != NULL) {
505 			free(bv->bv_val);
506 		}
507 		free((char *)bv);
508 	}
509 }
510 
511 void
512 kmfber_bvecfree(struct berval **bv)
513 {
514 	int	i;
515 
516 	if (bv != NULL) {
517 		for (i = 0; bv[i] != NULL; i++) {
518 			kmfber_bvfree(bv[i]);
519 		}
520 		free((char *)bv);
521 	}
522 }
523 
524 /* VARARGS */
525 ber_tag_t
526 kmfber_scanf(BerElement *ber, const char *fmt, ...)
527 {
528 	va_list		ap;
529 	char		*last, *p;
530 	char		*s, **ss, ***sss;
531 	struct berval 	***bv, **bvp, *bval;
532 	int		*i, j;
533 	ber_slen_t	*l;
534 	ber_int_t	rc, tag, *b_int;
535 	ber_tag_t	*t;
536 	ber_len_t	len;
537 	size_t		array_size;
538 
539 	va_start(ap, fmt);
540 
541 	for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
542 	switch (*p) {
543 	    case 'a':	/* octet string - allocate storage as needed */
544 		ss = va_arg(ap, char **);
545 		rc = kmfber_get_stringa(ber, ss);
546 		break;
547 
548 	    case 'b':	/* boolean */
549 		i = va_arg(ap, int *);
550 		rc = kmfber_get_boolean(ber, i);
551 		break;
552 
553 	    case 'D':	/* Object ID */
554 		bval = va_arg(ap, struct berval *);
555 		rc = ber_get_oid(ber, bval);
556 		break;
557 	    case 'e':	/* enumerated */
558 	    case 'i':	/* int */
559 		b_int = va_arg(ap, ber_int_t *);
560 		rc = kmfber_get_int(ber, b_int);
561 		break;
562 
563 	    case 'l':	/* length of next item */
564 		l = va_arg(ap, ber_slen_t *);
565 		rc = kmfber_peek_tag(ber, (ber_len_t *)l);
566 		break;
567 
568 	    case 'n':	/* null */
569 		rc = kmfber_get_null(ber);
570 		break;
571 
572 	    case 's':	/* octet string - in a buffer */
573 		s = va_arg(ap, char *);
574 		l = va_arg(ap, ber_slen_t *);
575 		rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
576 		break;
577 
578 	    case 'o':	/* octet string in a supplied berval */
579 		bval = va_arg(ap, struct berval *);
580 		(void) kmfber_peek_tag(ber, &bval->bv_len);
581 		rc = kmfber_get_stringa(ber, &bval->bv_val);
582 		break;
583 
584 	    case 'I': /* variable length Integer */
585 		/* Treat INTEGER same as an OCTET string, but ignore the tag */
586 		bvp = va_arg(ap, struct berval **);
587 		rc = ber_get_bigint(ber, bvp);
588 		break;
589 	    case 'O': /* octet string - allocate & include length */
590 		bvp = va_arg(ap, struct berval **);
591 		rc = kmfber_get_stringal(ber, bvp);
592 		break;
593 
594 	    case 'B':	/* bit string - allocate storage as needed */
595 		ss = va_arg(ap, char **);
596 		l = va_arg(ap, ber_slen_t *); /* for length, in bits */
597 		rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
598 		break;
599 
600 	    case 't':	/* tag of next item */
601 		t = va_arg(ap, ber_tag_t *);
602 		*t = kmfber_peek_tag(ber, &len);
603 		rc = (ber_int_t)(*t);
604 		break;
605 
606 	    case 'T':	/* skip tag of next item */
607 		t = va_arg(ap, ber_tag_t *);
608 		*t = kmfber_skip_tag(ber, &len);
609 		rc = (ber_int_t)(*t);
610 		break;
611 
612 	    case 'v':	/* sequence of strings */
613 		sss = va_arg(ap, char ***);
614 		*sss = NULL;
615 		j = 0;
616 		array_size = 0;
617 		for (tag = kmfber_first_element(ber, &len, &last);
618 			(tag != KMFBER_DEFAULT &&
619 			tag != KMFBER_END_OF_SEQORSET &&
620 			rc != KMFBER_DEFAULT);
621 			tag = kmfber_next_element(ber, &len, last)) {
622 		    if (*sss == NULL) {
623 			/* Make room for at least 15 strings */
624 			*sss = (char **)malloc(16 * sizeof (char *));
625 			array_size = 16;
626 		    } else {
627 			if ((size_t)(j+2) > array_size) {
628 			    /* We'v overflowed our buffer */
629 			    *sss = (char **)realloc(*sss,
630 				(array_size * 2) * sizeof (char *));
631 			    array_size = array_size * 2;
632 			}
633 		    }
634 		    rc = kmfber_get_stringa(ber, &((*sss)[j]));
635 		    j++;
636 		}
637 		if (rc != KMFBER_DEFAULT &&
638 			tag != KMFBER_END_OF_SEQORSET) {
639 		    rc = KMFBER_DEFAULT;
640 		}
641 		if (j > 0)
642 		    (*sss)[j] = NULL;
643 		break;
644 
645 	    case 'V':	/* sequence of strings + lengths */
646 		bv = va_arg(ap, struct berval ***);
647 		*bv = NULL;
648 		j = 0;
649 		for (tag = kmfber_first_element(ber, &len, &last);
650 			(tag != KMFBER_DEFAULT &&
651 			tag != KMFBER_END_OF_SEQORSET &&
652 			rc != KMFBER_DEFAULT);
653 			tag = kmfber_next_element(ber, &len, last)) {
654 		    if (*bv == NULL) {
655 			*bv = (struct berval **)malloc(
656 				2 * sizeof (struct berval *));
657 		    } else {
658 			*bv = (struct berval **)realloc(*bv,
659 				(j + 2) * sizeof (struct berval *));
660 		    }
661 		    rc = kmfber_get_stringal(ber, &((*bv)[j]));
662 		    j++;
663 		}
664 		if (rc != KMFBER_DEFAULT &&
665 			tag != KMFBER_END_OF_SEQORSET) {
666 		    rc = KMFBER_DEFAULT;
667 		}
668 		if (j > 0)
669 		    (*bv)[j] = NULL;
670 		break;
671 
672 	    case 'x':	/* skip the next element - whatever it is */
673 		if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
674 		    break;
675 		ber->ber_ptr += len;
676 		break;
677 
678 	    case '{':	/* begin sequence */
679 	    case '[':	/* begin set */
680 		if (*(p + 1) != 'v' && *(p + 1) != 'V')
681 		    rc = kmfber_skip_tag(ber, &len);
682 		break;
683 
684 	    case '}':	/* end sequence */
685 	    case ']':	/* end set */
686 		break;
687 
688 	    default:
689 #ifdef KMFBER_DEBUG
690 		{
691 		    char msg[80];
692 		    sprintf(msg, "unknown fmt %c\n", *p);
693 		    ber_err_print(msg);
694 		}
695 #endif
696 		rc = KMFBER_DEFAULT;
697 		break;
698 	}
699 	}
700 
701 
702 	va_end(ap);
703 	if (rc == KMFBER_DEFAULT) {
704 	va_start(ap, fmt);
705 	for (p--; fmt < p && *fmt; fmt++) {
706 	    switch (*fmt) {
707 		case 'a':	/* octet string - allocate storage as needed */
708 		    ss = va_arg(ap, char **);
709 		    free(*ss);
710 		    *ss = NULL;
711 		    break;
712 
713 		case 'b':	/* boolean */
714 		    i = va_arg(ap, int *);
715 		    break;
716 
717 		case 'e':	/* enumerated */
718 		case 'i':	/* int */
719 		    l = va_arg(ap, ber_slen_t *);
720 		    break;
721 
722 		case 'l':	/* length of next item */
723 		    l = va_arg(ap, ber_slen_t *);
724 		    break;
725 
726 		case 'n':	/* null */
727 		    break;
728 
729 		case 's':	/* octet string - in a buffer */
730 		    s = va_arg(ap, char *);
731 		    l = va_arg(ap, ber_slen_t *);
732 		    break;
733 
734 		case 'o':	/* octet string in a supplied berval */
735 		    bval = va_arg(ap, struct berval *);
736 		    if (bval->bv_val) free(bval->bv_val);
737 		    (void) memset(bval, 0, sizeof (struct berval));
738 		    break;
739 
740 		case 'O':	/* octet string - allocate & include length */
741 		    bvp = va_arg(ap, struct berval **);
742 		    kmfber_bvfree(*bvp);
743 		    bvp = NULL;
744 		    break;
745 
746 		case 'B':	/* bit string - allocate storage as needed */
747 		    ss = va_arg(ap, char **);
748 		    l = va_arg(ap, ber_slen_t *); /* for length, in bits */
749 		    if (*ss) free(*ss);
750 		    *ss = NULL;
751 		    break;
752 
753 		case 't':	/* tag of next item */
754 		    t = va_arg(ap, ber_tag_t *);
755 		    break;
756 		case 'T':	/* skip tag of next item */
757 		    t = va_arg(ap, ber_tag_t *);
758 		    break;
759 
760 		case 'v':	/* sequence of strings */
761 		    sss = va_arg(ap, char ***);
762 		    ber_svecfree(*sss);
763 		    *sss = NULL;
764 		    break;
765 
766 		case 'V':	/* sequence of strings + lengths */
767 		    bv = va_arg(ap, struct berval ***);
768 		    kmfber_bvecfree(*bv);
769 		    *bv = NULL;
770 		    break;
771 
772 		case 'x':	/* skip the next element - whatever it is */
773 		    break;
774 
775 		case '{':	/* begin sequence */
776 		case '[':	/* begin set */
777 		    break;
778 
779 		case '}':	/* end sequence */
780 		case ']':	/* end set */
781 		    break;
782 
783 		default:
784 		    break;
785 	    }
786 	} /* for */
787 	va_end(ap);
788 	} /* if */
789 
790 
791 	return (rc);
792 }
793 
794 struct berval *
795 kmfber_bvdup(const struct berval *bv)
796 {
797 	struct berval	*new;
798 
799 	if ((new = (struct berval *)malloc(sizeof (struct berval)))
800 		== NULL) {
801 		return (NULL);
802 	}
803 	if (bv->bv_val == NULL) {
804 		new->bv_val = NULL;
805 		new->bv_len = 0;
806 	} else {
807 		if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
808 			== NULL) {
809 		    return (NULL);
810 		}
811 		(void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
812 		new->bv_val[bv->bv_len] = '\0';
813 		new->bv_len = bv->bv_len;
814 	}
815 
816 	return (new);
817 }
818