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