xref: /onnv-gate/usr/src/lib/libkmf/ber_der/common/decode.c (revision 11973:480f5412d630)
13089Swyllys /*
2*11973Swyllys.ingersoll@sun.com  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
33089Swyllys  * Use is subject to license terms.
43089Swyllys  */
53089Swyllys /*
63089Swyllys  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
73089Swyllys  *
83089Swyllys  * The contents of this file are subject to the Netscape Public License
93089Swyllys  * Version 1.0 (the "NPL"); you may not use this file except in
103089Swyllys  * compliance with the NPL.  You may obtain a copy of the NPL at
113089Swyllys  * http://www.mozilla.org/NPL/
123089Swyllys  *
133089Swyllys  * Software distributed under the NPL is distributed on an "AS IS" basis,
143089Swyllys  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
153089Swyllys  * for the specific language governing rights and limitations under the
163089Swyllys  * NPL.
173089Swyllys  *
183089Swyllys  * The Initial Developer of this code under the NPL is Netscape
193089Swyllys  * Communications Corporation.  Portions created by Netscape are
203089Swyllys  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
213089Swyllys  * Reserved.
223089Swyllys  */
233089Swyllys 
243089Swyllys /*
253089Swyllys  * Copyright (c) 1990 Regents of the University of Michigan.
263089Swyllys  * All rights reserved.
273089Swyllys  *
283089Swyllys  * Redistribution and use in source and binary forms are permitted
293089Swyllys  * provided that this notice is preserved and that due credit is given
303089Swyllys  * to the University of Michigan at Ann Arbor. The name of the University
313089Swyllys  * may not be used to endorse or promote products derived from this
323089Swyllys  * software without specific prior written permission. This software
333089Swyllys  * is provided ``as is'' without express or implied warranty.
343089Swyllys  */
353089Swyllys 
363089Swyllys /* decode.c - ber input decoding routines */
373089Swyllys 
383089Swyllys #include <strings.h>
393089Swyllys #include <sys/types.h>
403089Swyllys #include <netinet/in.h>
413089Swyllys #include <inttypes.h>
423089Swyllys 
433089Swyllys #include <ber_der.h>
443089Swyllys #include "kmfber_int.h"
453089Swyllys 
463089Swyllys static void
ber_svecfree(char ** vals)473089Swyllys ber_svecfree(char **vals)
483089Swyllys {
493089Swyllys 	int	i;
503089Swyllys 
513089Swyllys 	if (vals == NULL)
523089Swyllys 		return;
533089Swyllys 	for (i = 0; vals[i] != NULL; i++)
543089Swyllys 		free(vals[i]);
553089Swyllys 	free((char *)vals);
563089Swyllys }
573089Swyllys 
583089Swyllys /*
593089Swyllys  * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
603089Swyllys  * If that changes, the kmfber_peek_tag() and/or
613089Swyllys  * kmfkmfber_skip_tag() implementations will need to be changed.
623089Swyllys  */
633089Swyllys /* return the tag - KMFBER_DEFAULT returned means trouble */
643089Swyllys static ber_tag_t
kmfber_get_tag(BerElement * ber)653089Swyllys kmfber_get_tag(BerElement *ber)
663089Swyllys {
673089Swyllys 	unsigned char	xbyte;
683089Swyllys 	ber_tag_t	tag;
693089Swyllys 	char		*tagp;
703089Swyllys 	int		i;
713089Swyllys 
723089Swyllys 	if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
733089Swyllys 		return (KMFBER_DEFAULT);
743089Swyllys 
753089Swyllys 	if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
763089Swyllys 		return ((ber_uint_t)xbyte);
773089Swyllys 
783089Swyllys 	tagp = (char *)&tag;
793089Swyllys 	tagp[0] = xbyte;
803089Swyllys 	for (i = 1; i < sizeof (ber_int_t); i++) {
813089Swyllys 		if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
823089Swyllys 			return (KMFBER_DEFAULT);
833089Swyllys 
843089Swyllys 		tagp[i] = xbyte;
853089Swyllys 
863089Swyllys 		if (! (xbyte & KMFBER_MORE_TAG_MASK))
873089Swyllys 			break;
883089Swyllys 	}
893089Swyllys 
903089Swyllys 	/* tag too big! */
913089Swyllys 	if (i == sizeof (ber_int_t))
923089Swyllys 		return (KMFBER_DEFAULT);
933089Swyllys 
943089Swyllys 	/* want leading, not trailing 0's */
953089Swyllys 	return (tag >> (sizeof (ber_int_t)- i - 1));
963089Swyllys }
973089Swyllys 
983089Swyllys /*
993089Swyllys  * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
1003089Swyllys  * If that changes, the implementation of kmfber_peek_tag() will need to
1013089Swyllys  * be changed.
1023089Swyllys  */
1033089Swyllys ber_tag_t
kmfber_skip_tag(BerElement * ber,ber_len_t * len)1043089Swyllys kmfber_skip_tag(BerElement *ber, ber_len_t *len)
1053089Swyllys {
1063089Swyllys 	ber_tag_t	tag;
1073089Swyllys 	unsigned char	lc;
1083089Swyllys 	int		noctets, diff;
1093089Swyllys 	uint32_t	netlen;
1103089Swyllys 
1113089Swyllys 	/*
1123089Swyllys 	 * Any ber element looks like this: tag length contents.
1133089Swyllys 	 * Assuming everything's ok, we return the tag byte (we
1143089Swyllys 	 * can assume a single byte), and return the length in len.
1153089Swyllys 	 *
1163089Swyllys 	 * Assumptions:
1173089Swyllys 	 *	1) definite lengths
1183089Swyllys 	 *	2) primitive encodings used whenever possible
1193089Swyllys 	 */
1203089Swyllys 
1213089Swyllys 	/*
1223089Swyllys 	 * First, we read the tag.
1233089Swyllys 	 */
1243089Swyllys 
1253089Swyllys 	if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
1263089Swyllys 		return (KMFBER_DEFAULT);
1273089Swyllys 
1283089Swyllys 	/*
1293089Swyllys 	 * Next, read the length.  The first byte contains the length of
1303089Swyllys 	 * the length.  If bit 8 is set, the length is the long form,
1313089Swyllys 	 * otherwise it's the short form.  We don't allow a length that's
1323089Swyllys 	 * greater than what we can hold in an unsigned long.
1333089Swyllys 	 */
1343089Swyllys 
1353089Swyllys 	*len = 0;
1363089Swyllys 	netlen = 0;
1373089Swyllys 	if (kmfber_read(ber, (char *)&lc, 1) != 1)
1383089Swyllys 		return (KMFBER_DEFAULT);
1393089Swyllys 	if (lc & 0x80) {
1403089Swyllys 		noctets = (lc & 0x7f);
1413089Swyllys 		if (noctets > sizeof (ber_uint_t))
1423089Swyllys 			return (KMFBER_DEFAULT);
1433089Swyllys 		diff = sizeof (ber_int_t) - noctets;
1443089Swyllys 		if (kmfber_read(ber, (char *)&netlen + diff, noctets)
1456051Swyllys 		    != noctets)
1463089Swyllys 			return (KMFBER_DEFAULT);
1473089Swyllys 		*len = ntohl(netlen);
1483089Swyllys 	} else {
1493089Swyllys 		*len = lc;
1503089Swyllys 	}
1513089Swyllys 
1523089Swyllys 	return (tag);
1533089Swyllys }
1543089Swyllys 
1553089Swyllys 
1563089Swyllys /*
1573089Swyllys  * Note: Previously, we passed the "ber" parameter directly to
1583089Swyllys  * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
1593089Swyllys  * We now take advantage of the fact that the only ber structure
1603089Swyllys  * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
1613089Swyllys  * If that changes, this code must change too.
1623089Swyllys  */
1633089Swyllys static ber_tag_t
kmfber_peek_tag(BerElement * ber,ber_len_t * len)1643089Swyllys kmfber_peek_tag(BerElement *ber, ber_len_t *len)
1653089Swyllys {
1663089Swyllys 	BerElement	bercopy;
1673089Swyllys 
1683089Swyllys 	bercopy.ber_end = ber->ber_end;
1693089Swyllys 	bercopy.ber_ptr = ber->ber_ptr;
1703089Swyllys 	return (kmfber_skip_tag(&bercopy, len));
1713089Swyllys }
1723089Swyllys 
1733089Swyllys static int
ber_getnint(BerElement * ber,ber_int_t * num,ber_slen_t len)1743089Swyllys ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
1753089Swyllys {
1763089Swyllys 	int i;
1773089Swyllys 	ber_int_t value;
1783089Swyllys 	unsigned char buffer[sizeof (ber_int_t)];
1793089Swyllys 	/*
1803089Swyllys 	 * The tag and length have already been stripped off.  We should
1813089Swyllys 	 * be sitting right before len bytes of 2's complement integer,
1823089Swyllys 	 * ready to be read straight into an int.  We may have to sign
1833089Swyllys 	 * extend after we read it in.
1843089Swyllys 	 */
1853089Swyllys 
18610442Swyllys.ingersoll@sun.com 	if (len > sizeof (buffer))
1873089Swyllys 		return (-1);
1883089Swyllys 
1893089Swyllys 	/* read into the low-order bytes of netnum */
1903089Swyllys 	if (kmfber_read(ber, (char *)buffer, len) != len)
1913089Swyllys 		return (-1);
1923089Swyllys 
1933089Swyllys 	/* This sets the required sign extension */
1943089Swyllys 	if (len != 0) {
1953089Swyllys 		value = 0x80 & buffer[0] ? (-1) : 0;
1963089Swyllys 	} else {
1973089Swyllys 		value = 0;
1983089Swyllys 	}
1993089Swyllys 
2003089Swyllys 	for (i = 0; i < len; i++)
2013089Swyllys 		value = (value << 8) | buffer[i];
2023089Swyllys 
2033089Swyllys 	*num = value;
2043089Swyllys 
2053089Swyllys 	return (len);
2063089Swyllys }
2073089Swyllys 
2083089Swyllys static ber_tag_t
kmfber_get_int(BerElement * ber,ber_int_t * num)2093089Swyllys kmfber_get_int(BerElement *ber, ber_int_t *num)
2103089Swyllys {
2113089Swyllys 	ber_tag_t	tag;
2123089Swyllys 	ber_len_t	len;
2133089Swyllys 
2143089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
2153089Swyllys 		return (KMFBER_DEFAULT);
2163089Swyllys 
2173089Swyllys 	/*
2183089Swyllys 	 * len is being demoted to a long here --  possible conversion error
2193089Swyllys 	 */
2203089Swyllys 
2213089Swyllys 	if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
2223089Swyllys 		return (KMFBER_DEFAULT);
2233089Swyllys 	else
2243089Swyllys 		return (tag);
2253089Swyllys }
2263089Swyllys 
2273089Swyllys static ber_tag_t
kmfber_get_stringb(BerElement * ber,char * buf,ber_len_t * len)2283089Swyllys kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
2293089Swyllys {
2303089Swyllys 	ber_len_t	datalen;
2313089Swyllys 	ber_tag_t	tag;
2323089Swyllys #ifdef STR_TRANSLATION
2333089Swyllys 	char		*transbuf;
2343089Swyllys #endif /* STR_TRANSLATION */
2353089Swyllys 
2363089Swyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
2373089Swyllys 		return (KMFBER_DEFAULT);
2383089Swyllys 	if (datalen > (*len - 1))
2393089Swyllys 		return (KMFBER_DEFAULT);
2403089Swyllys 
2413089Swyllys 	/*
2423089Swyllys 	 * datalen is being demoted to a long here --  possible conversion error
2433089Swyllys 	 */
2443089Swyllys 
2453089Swyllys 	if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
2463089Swyllys 		return (KMFBER_DEFAULT);
2473089Swyllys 
2483089Swyllys 	buf[datalen] = '\0';
2493089Swyllys 
2503089Swyllys #ifdef STR_TRANSLATION
2513089Swyllys 	if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
2526051Swyllys 	    != 0 && ber->ber_decode_translate_proc != NULL) {
2533089Swyllys 
2543089Swyllys 		transbuf = buf;
2553089Swyllys 		++datalen;
2563089Swyllys 		if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
2576051Swyllys 		    0) != 0) {
2583089Swyllys 			return (KMFBER_DEFAULT);
2593089Swyllys 		}
2603089Swyllys 		if (datalen > *len) {
2613089Swyllys 			free(transbuf);
2623089Swyllys 			return (KMFBER_DEFAULT);
2633089Swyllys 		}
2643089Swyllys 		(void) memmove(buf, transbuf, datalen);
2653089Swyllys 		free(transbuf);
2663089Swyllys 		--datalen;
2673089Swyllys 	}
2683089Swyllys #endif /* STR_TRANSLATION */
2693089Swyllys 
2703089Swyllys 	*len = datalen;
2713089Swyllys 	return (tag);
2723089Swyllys }
2733089Swyllys 
2743089Swyllys static ber_tag_t
kmfber_get_stringa(BerElement * ber,char ** buf)2753089Swyllys kmfber_get_stringa(BerElement *ber, char **buf)
2763089Swyllys {
2773089Swyllys 	ber_len_t	datalen;
2783089Swyllys 	ber_tag_t	tag;
2793089Swyllys 
2803089Swyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
2813089Swyllys 		return (KMFBER_DEFAULT);
2823089Swyllys 
2833089Swyllys 	if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
2843089Swyllys 		return (KMFBER_DEFAULT);
2853089Swyllys 
2863089Swyllys 	/*
2873089Swyllys 	 * datalen is being demoted to a long here --  possible conversion error
2883089Swyllys 	 */
2893089Swyllys 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
2903089Swyllys 		return (KMFBER_DEFAULT);
2913089Swyllys 	(*buf)[datalen] = '\0';
2923089Swyllys 
2933089Swyllys 	return (tag);
2943089Swyllys }
2953089Swyllys 
2963089Swyllys ber_tag_t
ber_get_oid(BerElement * ber,struct berval * oid)2973089Swyllys ber_get_oid(BerElement *ber, struct berval *oid)
2983089Swyllys {
2993089Swyllys 	ber_len_t	len;
3003089Swyllys 	ber_tag_t	tag;
3013089Swyllys 
3023089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
3033089Swyllys 		return (KMFBER_DEFAULT);
3043089Swyllys 	}
3053089Swyllys 
3063089Swyllys 	if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
3073089Swyllys 		return (KMFBER_DEFAULT);
3083089Swyllys 	}
3093089Swyllys 	oid->bv_len = len;
3103089Swyllys 
3113089Swyllys 	if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
3126051Swyllys 	    (ber_slen_t)oid->bv_len)
3133089Swyllys 		return (KMFBER_DEFAULT);
3143089Swyllys 
3153089Swyllys 	return (tag);
3163089Swyllys }
3173089Swyllys 
3183089Swyllys ber_tag_t
ber_get_bigint(BerElement * ber,struct berval ** bv)3193089Swyllys ber_get_bigint(BerElement *ber, struct berval **bv)
3203089Swyllys {
3213089Swyllys 	ber_len_t	len;
3223089Swyllys 	ber_tag_t	tag;
3233089Swyllys 
3243089Swyllys 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
3256051Swyllys 	    == NULL) {
3263089Swyllys 		return (KMFBER_DEFAULT);
3273089Swyllys 	}
3286051Swyllys 	(*bv)->bv_len = 0;
3296051Swyllys 	(*bv)->bv_val = NULL;
3303089Swyllys 
3313089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
3323089Swyllys 		return (KMFBER_DEFAULT);
3333089Swyllys 	}
3343089Swyllys 
3353089Swyllys 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
3366051Swyllys 	    == NULL) {
3373089Swyllys 		return (KMFBER_DEFAULT);
3383089Swyllys 	}
3393089Swyllys 
3403089Swyllys 	/*
3413089Swyllys 	 * len is being demoted to a long here --  possible conversion error
3423089Swyllys 	 */
3433089Swyllys 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
3443089Swyllys 		return (KMFBER_DEFAULT);
3453089Swyllys 
3463089Swyllys 	(*bv)->bv_len = len;
3473089Swyllys 
348*11973Swyllys.ingersoll@sun.com 	/* If DER encoding, strip leading 0's if high-order bit is set */
3493089Swyllys 	if (ber->ber_options & KMFBER_OPT_USE_DER) {
3503089Swyllys 		char *p = (*bv)->bv_val;
351*11973Swyllys.ingersoll@sun.com 		while ((*p == 0x00) && ((*bv)->bv_len > 0) && (p[1] & 0x80)) {
3523089Swyllys 			p++;
3533089Swyllys 			(*bv)->bv_len--;
3543089Swyllys 		}
3553089Swyllys 		/*
3563089Swyllys 		 * Shift the buffer to the beginning of the allocated space
3573089Swyllys 		 * so it can be properly freed later.
3583089Swyllys 		 */
3593089Swyllys 		if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
3603089Swyllys 			(void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
3613089Swyllys 	}
3623089Swyllys 
3633089Swyllys 	return (tag);
3643089Swyllys }
3653089Swyllys 
3663089Swyllys static ber_tag_t
kmfber_get_stringal(BerElement * ber,struct berval ** bv)3673089Swyllys kmfber_get_stringal(BerElement *ber, struct berval **bv)
3683089Swyllys {
3693089Swyllys 	ber_len_t	len;
3703089Swyllys 	ber_tag_t	tag;
3713089Swyllys 
3723089Swyllys 	if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
3736051Swyllys 	    == NULL) {
3743089Swyllys 		return (KMFBER_DEFAULT);
3753089Swyllys 	}
3763089Swyllys 
3773089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
3783089Swyllys 		return (KMFBER_DEFAULT);
3793089Swyllys 	}
3803089Swyllys 
3813089Swyllys 	if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
3826051Swyllys 	    == NULL) {
3833089Swyllys 		return (KMFBER_DEFAULT);
3843089Swyllys 	}
3853089Swyllys 
3863089Swyllys 	/*
3873089Swyllys 	 * len is being demoted to a long here --  possible conversion error
3883089Swyllys 	 */
3893089Swyllys 	if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
3903089Swyllys 		return (KMFBER_DEFAULT);
3913089Swyllys 	((*bv)->bv_val)[len] = '\0';
3923089Swyllys 	(*bv)->bv_len = len;
3933089Swyllys 
3943089Swyllys 	return (tag);
3953089Swyllys }
3963089Swyllys 
3973089Swyllys static ber_tag_t
kmfber_get_bitstringa(BerElement * ber,char ** buf,ber_len_t * blen)3983089Swyllys kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
3993089Swyllys {
4003089Swyllys 	ber_len_t	datalen;
4013089Swyllys 	ber_tag_t	tag;
4023089Swyllys 	unsigned char	unusedbits;
4033089Swyllys 
4043089Swyllys 	if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
4053089Swyllys 		return (KMFBER_DEFAULT);
4063089Swyllys 
4073089Swyllys 	if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
4083089Swyllys 		return (KMFBER_DEFAULT);
4093089Swyllys 
4103089Swyllys 	if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
4113089Swyllys 		return (KMFBER_DEFAULT);
4123089Swyllys 
4133089Swyllys 	/* Subtract 1 for the unused bits */
4143089Swyllys 	datalen--;
4153089Swyllys 
4163089Swyllys 	/*
4173089Swyllys 	 * datalen is being demoted to a long here --  possible conversion error
4183089Swyllys 	 */
4193089Swyllys 	if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
4203089Swyllys 		return (KMFBER_DEFAULT);
4213089Swyllys 
4223089Swyllys 	*blen = datalen * 8 - unusedbits;
4233089Swyllys 	return (tag);
4243089Swyllys }
4253089Swyllys 
4263089Swyllys static ber_tag_t
kmfber_get_null(BerElement * ber)4273089Swyllys kmfber_get_null(BerElement *ber)
4283089Swyllys {
4293089Swyllys 	ber_len_t	len;
4303089Swyllys 	ber_tag_t tag;
4313089Swyllys 
4323089Swyllys 	if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
4333089Swyllys 		return (KMFBER_DEFAULT);
4343089Swyllys 
4353089Swyllys 	if (len != 0)
4363089Swyllys 		return (KMFBER_DEFAULT);
4373089Swyllys 
4383089Swyllys 	return (tag);
4393089Swyllys }
4403089Swyllys 
4413089Swyllys static ber_tag_t
kmfber_get_boolean(BerElement * ber,int * boolval)4423089Swyllys kmfber_get_boolean(BerElement *ber, int *boolval)
4433089Swyllys {
4443089Swyllys 	ber_int_t	longbool;
4453089Swyllys 	int		rc;
4463089Swyllys 
4473089Swyllys 	rc = kmfber_get_int(ber, &longbool);
4483089Swyllys 	*boolval = longbool;
4493089Swyllys 
4503089Swyllys 	return (rc);
4513089Swyllys }
4523089Swyllys 
4533089Swyllys ber_tag_t
kmfber_first_element(BerElement * ber,ber_len_t * len,char ** last)4543089Swyllys kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
4553089Swyllys {
4563089Swyllys 	/* skip the sequence header, use the len to mark where to stop */
4573089Swyllys 	if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
4583089Swyllys 		return (KMFBER_ERROR);
4593089Swyllys 	}
4603089Swyllys 
4613089Swyllys 	*last = ber->ber_ptr + *len;
4623089Swyllys 
4633089Swyllys 	if (*last == ber->ber_ptr) {
4643089Swyllys 		return (KMFBER_END_OF_SEQORSET);
4653089Swyllys 	}
4663089Swyllys 
4673089Swyllys 	return (kmfber_peek_tag(ber, len));
4683089Swyllys }
4693089Swyllys 
4703089Swyllys ber_tag_t
kmfber_next_element(BerElement * ber,ber_len_t * len,char * last)4713089Swyllys kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
4723089Swyllys {
4733089Swyllys 	if (ber->ber_ptr == last) {
4743089Swyllys 		return (KMFBER_END_OF_SEQORSET);
4753089Swyllys 	}
4763089Swyllys 
4773089Swyllys 	return (kmfber_peek_tag(ber, len));
4783089Swyllys }
4793089Swyllys 
4803089Swyllys void
kmfber_bvfree(struct berval * bv)4813089Swyllys kmfber_bvfree(struct berval *bv)
4823089Swyllys {
4833089Swyllys 	if (bv != NULL) {
4843089Swyllys 		if (bv->bv_val != NULL) {
4853089Swyllys 			free(bv->bv_val);
4863089Swyllys 		}
4873089Swyllys 		free((char *)bv);
4883089Swyllys 	}
4893089Swyllys }
4903089Swyllys 
4913089Swyllys void
kmfber_bvecfree(struct berval ** bv)4923089Swyllys kmfber_bvecfree(struct berval **bv)
4933089Swyllys {
4943089Swyllys 	int	i;
4953089Swyllys 
4963089Swyllys 	if (bv != NULL) {
4973089Swyllys 		for (i = 0; bv[i] != NULL; i++) {
4983089Swyllys 			kmfber_bvfree(bv[i]);
4993089Swyllys 		}
5003089Swyllys 		free((char *)bv);
5013089Swyllys 	}
5023089Swyllys }
5033089Swyllys 
5043089Swyllys /* VARARGS */
5053089Swyllys ber_tag_t
kmfber_scanf(BerElement * ber,const char * fmt,...)5063089Swyllys kmfber_scanf(BerElement *ber, const char *fmt, ...)
5073089Swyllys {
5083089Swyllys 	va_list		ap;
5093089Swyllys 	char		*last, *p;
5103089Swyllys 	char		*s, **ss, ***sss;
5113089Swyllys 	struct berval 	***bv, **bvp, *bval;
5123089Swyllys 	int		*i, j;
5133089Swyllys 	ber_slen_t	*l;
5143089Swyllys 	ber_int_t	rc, tag, *b_int;
5153089Swyllys 	ber_tag_t	*t;
5163089Swyllys 	ber_len_t	len;
5173089Swyllys 	size_t		array_size;
5183089Swyllys 
5193089Swyllys 	va_start(ap, fmt);
5203089Swyllys 
5213089Swyllys 	for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
5223089Swyllys 	switch (*p) {
5236051Swyllys 		case 'a':	/* octet string - allocate storage as needed */
5243089Swyllys 		ss = va_arg(ap, char **);
5253089Swyllys 		rc = kmfber_get_stringa(ber, ss);
5263089Swyllys 		break;
5273089Swyllys 
5286051Swyllys 		case 'b':	/* boolean */
5293089Swyllys 		i = va_arg(ap, int *);
5303089Swyllys 		rc = kmfber_get_boolean(ber, i);
5313089Swyllys 		break;
5323089Swyllys 
5336051Swyllys 		case 'D':	/* Object ID */
5343089Swyllys 		bval = va_arg(ap, struct berval *);
5353089Swyllys 		rc = ber_get_oid(ber, bval);
5363089Swyllys 		break;
5376051Swyllys 		case 'e':	/* enumerated */
5386051Swyllys 		case 'i':	/* int */
5393089Swyllys 		b_int = va_arg(ap, ber_int_t *);
5403089Swyllys 		rc = kmfber_get_int(ber, b_int);
5413089Swyllys 		break;
5423089Swyllys 
5436051Swyllys 		case 'l':	/* length of next item */
5443089Swyllys 		l = va_arg(ap, ber_slen_t *);
5453089Swyllys 		rc = kmfber_peek_tag(ber, (ber_len_t *)l);
5463089Swyllys 		break;
5473089Swyllys 
5486051Swyllys 		case 'n':	/* null */
5493089Swyllys 		rc = kmfber_get_null(ber);
5503089Swyllys 		break;
5513089Swyllys 
5526051Swyllys 		case 's':	/* octet string - in a buffer */
5533089Swyllys 		s = va_arg(ap, char *);
5543089Swyllys 		l = va_arg(ap, ber_slen_t *);
5553089Swyllys 		rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
5563089Swyllys 		break;
5573089Swyllys 
5586051Swyllys 		case 'o':	/* octet string in a supplied berval */
5593089Swyllys 		bval = va_arg(ap, struct berval *);
5603089Swyllys 		(void) kmfber_peek_tag(ber, &bval->bv_len);
5613089Swyllys 		rc = kmfber_get_stringa(ber, &bval->bv_val);
5623089Swyllys 		break;
5633089Swyllys 
5646051Swyllys 		case 'I': /* variable length Integer */
5653089Swyllys 		/* Treat INTEGER same as an OCTET string, but ignore the tag */
5663089Swyllys 		bvp = va_arg(ap, struct berval **);
5673089Swyllys 		rc = ber_get_bigint(ber, bvp);
5683089Swyllys 		break;
5696051Swyllys 		case 'O': /* octet string - allocate & include length */
5703089Swyllys 		bvp = va_arg(ap, struct berval **);
5713089Swyllys 		rc = kmfber_get_stringal(ber, bvp);
5723089Swyllys 		break;
5733089Swyllys 
5746051Swyllys 		case 'B':	/* bit string - allocate storage as needed */
5753089Swyllys 		ss = va_arg(ap, char **);
5763089Swyllys 		l = va_arg(ap, ber_slen_t *); /* for length, in bits */
5773089Swyllys 		rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
5783089Swyllys 		break;
5793089Swyllys 
5806051Swyllys 		case 't':	/* tag of next item */
5813089Swyllys 		t = va_arg(ap, ber_tag_t *);
5823089Swyllys 		*t = kmfber_peek_tag(ber, &len);
5833089Swyllys 		rc = (ber_int_t)(*t);
5843089Swyllys 		break;
5853089Swyllys 
5866051Swyllys 		case 'T':	/* skip tag of next item */
5873089Swyllys 		t = va_arg(ap, ber_tag_t *);
5883089Swyllys 		*t = kmfber_skip_tag(ber, &len);
5893089Swyllys 		rc = (ber_int_t)(*t);
5903089Swyllys 		break;
5913089Swyllys 
5926051Swyllys 		case 'v':	/* sequence of strings */
5933089Swyllys 		sss = va_arg(ap, char ***);
5946051Swyllys 		if (sss == NULL)
5956051Swyllys 			break;
5963089Swyllys 		*sss = NULL;
5973089Swyllys 		j = 0;
5983089Swyllys 		array_size = 0;
5993089Swyllys 		for (tag = kmfber_first_element(ber, &len, &last);
6006051Swyllys 		    (tag != KMFBER_DEFAULT &&
6016051Swyllys 		    tag != KMFBER_END_OF_SEQORSET &&
6026051Swyllys 		    rc != KMFBER_DEFAULT);
6036051Swyllys 		    tag = kmfber_next_element(ber, &len, last)) {
6046051Swyllys 			if (*sss == NULL) {
6056051Swyllys 				/* Make room for at least 15 strings */
6066051Swyllys 				*sss = (char **)malloc(16 * sizeof (char *));
6076051Swyllys 				array_size = 16;
6086051Swyllys 			} else {
6096051Swyllys 				if ((size_t)(j+2) > array_size) {
6106051Swyllys 					/* We'v overflowed our buffer */
6116051Swyllys 					*sss = (char **)realloc(*sss,
6126051Swyllys 					    (array_size * 2) * sizeof (char *));
6136051Swyllys 					array_size = array_size * 2;
6146051Swyllys 				}
6153089Swyllys 			}
6166051Swyllys 			rc = kmfber_get_stringa(ber, &((*sss)[j]));
6176051Swyllys 			j++;
6183089Swyllys 		}
6196051Swyllys 		if (rc != KMFBER_DEFAULT && tag != KMFBER_END_OF_SEQORSET) {
6206051Swyllys 			rc = KMFBER_DEFAULT;
6213089Swyllys 		}
6223089Swyllys 		if (j > 0)
6236051Swyllys 			(*sss)[j] = NULL;
6243089Swyllys 		break;
6253089Swyllys 
6266051Swyllys 		case 'V':	/* sequence of strings + lengths */
6273089Swyllys 		bv = va_arg(ap, struct berval ***);
6283089Swyllys 		*bv = NULL;
6293089Swyllys 		j = 0;
6303089Swyllys 		for (tag = kmfber_first_element(ber, &len, &last);
6316051Swyllys 		    (tag != KMFBER_DEFAULT &&
6326051Swyllys 		    tag != KMFBER_END_OF_SEQORSET &&
6336051Swyllys 		    rc != KMFBER_DEFAULT);
6346051Swyllys 		    tag = kmfber_next_element(ber, &len, last)) {
6356051Swyllys 			if (*bv == NULL) {
6366051Swyllys 				*bv = (struct berval **)malloc(
6376051Swyllys 				    2 * sizeof (struct berval *));
6386051Swyllys 			} else {
6396051Swyllys 				*bv = (struct berval **)realloc(*bv,
6406051Swyllys 				    (j + 2) * sizeof (struct berval *));
6416051Swyllys 			}
6426051Swyllys 			rc = kmfber_get_stringal(ber, &((*bv)[j]));
6436051Swyllys 			j++;
6443089Swyllys 		}
6453089Swyllys 		if (rc != KMFBER_DEFAULT &&
6466051Swyllys 		    tag != KMFBER_END_OF_SEQORSET) {
6476051Swyllys 			rc = KMFBER_DEFAULT;
6483089Swyllys 		}
6493089Swyllys 		if (j > 0)
6506051Swyllys 			(*bv)[j] = NULL;
6513089Swyllys 		break;
6523089Swyllys 
6536051Swyllys 		case 'x':	/* skip the next element - whatever it is */
6543089Swyllys 		if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
6556051Swyllys 			break;
6563089Swyllys 		ber->ber_ptr += len;
6573089Swyllys 		break;
6583089Swyllys 
6596051Swyllys 		case '{':	/* begin sequence */
6606051Swyllys 		case '[':	/* begin set */
6613089Swyllys 		if (*(p + 1) != 'v' && *(p + 1) != 'V')
6626051Swyllys 			rc = kmfber_skip_tag(ber, &len);
6633089Swyllys 		break;
6643089Swyllys 
6656051Swyllys 		case '}':	/* end sequence */
6666051Swyllys 		case ']':	/* end set */
6676051Swyllys 		break;
6686051Swyllys 
6696051Swyllys 		default:
6703089Swyllys 		rc = KMFBER_DEFAULT;
6713089Swyllys 		break;
6726051Swyllys 		}
6733089Swyllys 	}
6743089Swyllys 
6753089Swyllys 
6763089Swyllys 	va_end(ap);
6773089Swyllys 	if (rc == KMFBER_DEFAULT) {
6783089Swyllys 	va_start(ap, fmt);
6793089Swyllys 	for (p--; fmt < p && *fmt; fmt++) {
6806051Swyllys 		switch (*fmt) {
6813089Swyllys 		case 'a':	/* octet string - allocate storage as needed */
6826051Swyllys 			ss = va_arg(ap, char **);
6836051Swyllys 			if (ss != NULL && *ss != NULL) {
6846051Swyllys 				free(*ss);
6856051Swyllys 				*ss = NULL;
6866051Swyllys 			}
6876051Swyllys 			break;
6883089Swyllys 
6893089Swyllys 		case 'b':	/* boolean */
6906051Swyllys 			i = va_arg(ap, int *);
6916051Swyllys 			break;
6923089Swyllys 
6933089Swyllys 		case 'e':	/* enumerated */
6943089Swyllys 		case 'i':	/* int */
6956051Swyllys 			l = va_arg(ap, ber_slen_t *);
6966051Swyllys 			break;
6973089Swyllys 
6983089Swyllys 		case 'l':	/* length of next item */
6996051Swyllys 			l = va_arg(ap, ber_slen_t *);
7006051Swyllys 			break;
7013089Swyllys 
7023089Swyllys 		case 'n':	/* null */
7036051Swyllys 			break;
7043089Swyllys 
7053089Swyllys 		case 's':	/* octet string - in a buffer */
7066051Swyllys 			s = va_arg(ap, char *);
7076051Swyllys 			l = va_arg(ap, ber_slen_t *);
7086051Swyllys 			break;
7093089Swyllys 
7103089Swyllys 		case 'o':	/* octet string in a supplied berval */
7116051Swyllys 			bval = va_arg(ap, struct berval *);
7126051Swyllys 			if (bval->bv_val) free(bval->bv_val);
7136051Swyllys 			(void) memset(bval, 0, sizeof (struct berval));
7146051Swyllys 			break;
7153089Swyllys 
7163089Swyllys 		case 'O':	/* octet string - allocate & include length */
7176051Swyllys 			bvp = va_arg(ap, struct berval **);
7186051Swyllys 			kmfber_bvfree(*bvp);
7196051Swyllys 			bvp = NULL;
7206051Swyllys 			break;
7213089Swyllys 
7223089Swyllys 		case 'B':	/* bit string - allocate storage as needed */
7236051Swyllys 			ss = va_arg(ap, char **);
7246051Swyllys 			l = va_arg(ap, ber_slen_t *); /* for length, in bits */
7256051Swyllys 			if (ss != NULL && *ss != NULL) {
7266051Swyllys 				free(*ss);
7276051Swyllys 				*ss = NULL;
7286051Swyllys 			}
7296051Swyllys 			break;
7303089Swyllys 
7313089Swyllys 		case 't':	/* tag of next item */
7326051Swyllys 			t = va_arg(ap, ber_tag_t *);
7336051Swyllys 			break;
7343089Swyllys 		case 'T':	/* skip tag of next item */
7356051Swyllys 			t = va_arg(ap, ber_tag_t *);
7366051Swyllys 			break;
7373089Swyllys 
7383089Swyllys 		case 'v':	/* sequence of strings */
7396051Swyllys 			sss = va_arg(ap, char ***);
7406051Swyllys 			if (sss != NULL && *sss != NULL) {
7416051Swyllys 				ber_svecfree(*sss);
7426051Swyllys 				*sss = NULL;
7436051Swyllys 			}
7446051Swyllys 			break;
7453089Swyllys 
7463089Swyllys 		case 'V':	/* sequence of strings + lengths */
7476051Swyllys 			bv = va_arg(ap, struct berval ***);
7486051Swyllys 			kmfber_bvecfree(*bv);
7496051Swyllys 			*bv = NULL;
7506051Swyllys 			break;
7513089Swyllys 
7523089Swyllys 		case 'x':	/* skip the next element - whatever it is */
7536051Swyllys 			break;
7543089Swyllys 
7553089Swyllys 		case '{':	/* begin sequence */
7563089Swyllys 		case '[':	/* begin set */
7576051Swyllys 			break;
7583089Swyllys 
7593089Swyllys 		case '}':	/* end sequence */
7603089Swyllys 		case ']':	/* end set */
7616051Swyllys 			break;
7623089Swyllys 
7633089Swyllys 		default:
7646051Swyllys 			break;
7656051Swyllys 		}
7663089Swyllys 	} /* for */
7673089Swyllys 	va_end(ap);
7683089Swyllys 	} /* if */
7693089Swyllys 
7703089Swyllys 	return (rc);
7713089Swyllys }
7723089Swyllys 
7733089Swyllys struct berval *
kmfber_bvdup(const struct berval * bv)7743089Swyllys kmfber_bvdup(const struct berval *bv)
7753089Swyllys {
7763089Swyllys 	struct berval	*new;
7773089Swyllys 
7783089Swyllys 	if ((new = (struct berval *)malloc(sizeof (struct berval)))
7796051Swyllys 	    == NULL) {
7803089Swyllys 		return (NULL);
7813089Swyllys 	}
7823089Swyllys 	if (bv->bv_val == NULL) {
7833089Swyllys 		new->bv_val = NULL;
7843089Swyllys 		new->bv_len = 0;
7853089Swyllys 	} else {
7863089Swyllys 		if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
7876051Swyllys 		    == NULL) {
7886051Swyllys 			return (NULL);
7893089Swyllys 		}
7903089Swyllys 		(void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
7913089Swyllys 		new->bv_val[bv->bv_len] = '\0';
7923089Swyllys 		new->bv_len = bv->bv_len;
7933089Swyllys 	}
7943089Swyllys 
7953089Swyllys 	return (new);
7963089Swyllys }
797