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 /*
23*3089Swyllys  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
24*3089Swyllys  *
25*3089Swyllys  * The contents of this file are subject to the Netscape Public License
26*3089Swyllys  * Version 1.0 (the "NPL"); you may not use this file except in
27*3089Swyllys  * compliance with the NPL.  You may obtain a copy of the NPL at
28*3089Swyllys  * http://www.mozilla.org/NPL/
29*3089Swyllys  *
30*3089Swyllys  * Software distributed under the NPL is distributed on an "AS IS" basis,
31*3089Swyllys  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
32*3089Swyllys  * for the specific language governing rights and limitations under the
33*3089Swyllys  * NPL.
34*3089Swyllys  *
35*3089Swyllys  * The Initial Developer of this code under the NPL is Netscape
36*3089Swyllys  * Communications Corporation.  Portions created by Netscape are
37*3089Swyllys  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
38*3089Swyllys  * Reserved.
39*3089Swyllys  */
40*3089Swyllys 
41*3089Swyllys /*
42*3089Swyllys  * Copyright (c) 1990 Regents of the University of Michigan.
43*3089Swyllys  * All rights reserved.
44*3089Swyllys  *
45*3089Swyllys  * Redistribution and use in source and binary forms are permitted
46*3089Swyllys  * provided that this notice is preserved and that due credit is given
47*3089Swyllys  * to the University of Michigan at Ann Arbor. The name of the University
48*3089Swyllys  * may not be used to endorse or promote products derived from this
49*3089Swyllys  * software without specific prior written permission. This software
50*3089Swyllys  * is provided ``as is'' without express or implied warranty.
51*3089Swyllys  */
52*3089Swyllys 
53*3089Swyllys /*
54*3089Swyllys  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
55*3089Swyllys  * Use is subject to license terms.
56*3089Swyllys  */
57*3089Swyllys 
58*3089Swyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
59*3089Swyllys 
60*3089Swyllys #include <sys/types.h>
61*3089Swyllys #include <netinet/in.h>
62*3089Swyllys #include <inttypes.h>
63*3089Swyllys 
64*3089Swyllys #include <ber_der.h>
65*3089Swyllys #include "kmfber_int.h"
66*3089Swyllys 
67*3089Swyllys /* the following constants are used in kmfber_calc_lenlen */
68*3089Swyllys 
69*3089Swyllys #define	LENMASK1	0xFF
70*3089Swyllys #define	LENMASK2 	0xFFFF
71*3089Swyllys #define	LENMASK3	0xFFFFFF
72*3089Swyllys #define	LENMASK4	0xFFFFFFFF
73*3089Swyllys #define	_MASK		0x80
74*3089Swyllys 
75*3089Swyllys int
76*3089Swyllys kmfber_calc_taglen(ber_tag_t tag)
77*3089Swyllys {
78*3089Swyllys 	int		i;
79*3089Swyllys 	ber_int_t	mask;
80*3089Swyllys 
81*3089Swyllys 	/* find the first non-all-zero byte in the tag */
82*3089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
83*3089Swyllys 		mask = (LENMASK3 << (i * 8));
84*3089Swyllys 		/* not all zero */
85*3089Swyllys 		if (tag & mask)
86*3089Swyllys 			break;
87*3089Swyllys 	}
88*3089Swyllys 
89*3089Swyllys 	return (i + 1);
90*3089Swyllys }
91*3089Swyllys 
92*3089Swyllys static int
93*3089Swyllys ber_put_tag(BerElement	*ber, ber_tag_t tag, int nosos)
94*3089Swyllys {
95*3089Swyllys 	ber_int_t	taglen;
96*3089Swyllys 	ber_tag_t	ntag;
97*3089Swyllys 
98*3089Swyllys 	taglen = kmfber_calc_taglen(tag);
99*3089Swyllys 
100*3089Swyllys 	ntag = htonl(tag);
101*3089Swyllys 
102*3089Swyllys 	return (kmfber_write(ber,
103*3089Swyllys 		((char *) &ntag) + sizeof (ber_int_t) - taglen,
104*3089Swyllys 		taglen, nosos));
105*3089Swyllys }
106*3089Swyllys 
107*3089Swyllys int
108*3089Swyllys kmfber_calc_lenlen(ber_int_t len)
109*3089Swyllys {
110*3089Swyllys 	/*
111*3089Swyllys 	 * short len if it's less than 128 - one byte giving the len,
112*3089Swyllys 	 * with bit 8 0.
113*3089Swyllys 	 */
114*3089Swyllys 
115*3089Swyllys 	if (len <= 0x7F)
116*3089Swyllys 		return (1);
117*3089Swyllys 
118*3089Swyllys 	/*
119*3089Swyllys 	 * long len otherwise - one byte with bit 8 set, giving the
120*3089Swyllys 	 * length of the length, followed by the length itself.
121*3089Swyllys 	 */
122*3089Swyllys 
123*3089Swyllys 	if (len <= LENMASK1)
124*3089Swyllys 		return (2);
125*3089Swyllys 	if (len <= LENMASK2)
126*3089Swyllys 		return (3);
127*3089Swyllys 	if (len <= LENMASK3)
128*3089Swyllys 		return (4);
129*3089Swyllys 
130*3089Swyllys 	return (5);
131*3089Swyllys }
132*3089Swyllys 
133*3089Swyllys int
134*3089Swyllys kmfber_put_len(BerElement *ber, ber_int_t len, int nosos)
135*3089Swyllys {
136*3089Swyllys 	int		i;
137*3089Swyllys 	char		lenlen;
138*3089Swyllys 	ber_int_t	mask, netlen;
139*3089Swyllys 
140*3089Swyllys 	/*
141*3089Swyllys 	 * short len if it's less than 128 - one byte giving the len,
142*3089Swyllys 	 * with bit 8 0.
143*3089Swyllys 	 */
144*3089Swyllys 	if (len <= 127) {
145*3089Swyllys 		netlen = htonl(len);
146*3089Swyllys 		return (kmfber_write(ber,
147*3089Swyllys 			(char *)&netlen + sizeof (ber_int_t) - 1,
148*3089Swyllys 			1, nosos));
149*3089Swyllys 	}
150*3089Swyllys 
151*3089Swyllys 	/*
152*3089Swyllys 	 * long len otherwise - one byte with bit 8 set, giving the
153*3089Swyllys 	 * length of the length, followed by the length itself.
154*3089Swyllys 	 */
155*3089Swyllys 
156*3089Swyllys 	/* find the first non-all-zero byte */
157*3089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
158*3089Swyllys 		mask = (LENMASK1 << (i * 8));
159*3089Swyllys 		/* not all zero */
160*3089Swyllys 		if (len & mask)
161*3089Swyllys 			break;
162*3089Swyllys 	}
163*3089Swyllys 	lenlen = ++i;
164*3089Swyllys 	if (lenlen > 4)
165*3089Swyllys 		return (-1);
166*3089Swyllys 	lenlen |= 0x80;
167*3089Swyllys 
168*3089Swyllys 	/* write the length of the length */
169*3089Swyllys 	if (kmfber_write(ber, &lenlen, 1, nosos) != 1)
170*3089Swyllys 		return (-1);
171*3089Swyllys 
172*3089Swyllys 	/* write the length itself */
173*3089Swyllys 	netlen = htonl(len);
174*3089Swyllys 	if (kmfber_write(ber,
175*3089Swyllys 		(char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i)
176*3089Swyllys 		return (-1);
177*3089Swyllys 
178*3089Swyllys 	return (i + 1);
179*3089Swyllys }
180*3089Swyllys 
181*3089Swyllys static int
182*3089Swyllys ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag)
183*3089Swyllys {
184*3089Swyllys 	int		i, sign;
185*3089Swyllys 	ber_int_t	len, lenlen, taglen, netnum, mask;
186*3089Swyllys 
187*3089Swyllys 	sign = (num < 0);
188*3089Swyllys 
189*3089Swyllys 	/*
190*3089Swyllys 	 * high bit is set - look for first non-all-one byte
191*3089Swyllys 	 * high bit is clear - look for first non-all-zero byte
192*3089Swyllys 	 */
193*3089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
194*3089Swyllys 		mask = (LENMASK1 << (i * 8));
195*3089Swyllys 
196*3089Swyllys 		if (sign) {
197*3089Swyllys 			/* not all ones */
198*3089Swyllys 			if ((num & mask) != mask)
199*3089Swyllys 				break;
200*3089Swyllys 		} else {
201*3089Swyllys 			/* not all zero */
202*3089Swyllys 			if (num & mask)
203*3089Swyllys 				break;
204*3089Swyllys 		}
205*3089Swyllys 	}
206*3089Swyllys 
207*3089Swyllys 	/*
208*3089Swyllys 	 * we now have the "leading byte".  if the high bit on this
209*3089Swyllys 	 * byte matches the sign bit, we need to "back up" a byte.
210*3089Swyllys 	 */
211*3089Swyllys 	mask = (num & (_MASK << (i * 8)));
212*3089Swyllys 	if ((mask && !sign) || (sign && !mask))
213*3089Swyllys 		i++;
214*3089Swyllys 
215*3089Swyllys 	len = i + 1;
216*3089Swyllys 
217*3089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
218*3089Swyllys 		return (-1);
219*3089Swyllys 
220*3089Swyllys 	if ((lenlen = kmfber_put_len(ber, len, 0)) == -1)
221*3089Swyllys 		return (-1);
222*3089Swyllys 	i++;
223*3089Swyllys 	netnum = htonl(num);
224*3089Swyllys 	if (kmfber_write(ber,
225*3089Swyllys 		(char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i)
226*3089Swyllys 		/* length of tag + length + contents */
227*3089Swyllys 		return (taglen + lenlen + i);
228*3089Swyllys 
229*3089Swyllys 	return (-1);
230*3089Swyllys }
231*3089Swyllys 
232*3089Swyllys static int
233*3089Swyllys kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag)
234*3089Swyllys {
235*3089Swyllys 	if (tag == KMFBER_DEFAULT)
236*3089Swyllys 		tag = BER_ENUMERATED;
237*3089Swyllys 
238*3089Swyllys 	return (ber_put_int_or_enum(ber, num, tag));
239*3089Swyllys }
240*3089Swyllys 
241*3089Swyllys int
242*3089Swyllys ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag)
243*3089Swyllys {
244*3089Swyllys 	if (tag == KMFBER_DEFAULT)
245*3089Swyllys 		tag = BER_INTEGER;
246*3089Swyllys 
247*3089Swyllys 	return (ber_put_int_or_enum(ber, num, tag));
248*3089Swyllys }
249*3089Swyllys 
250*3089Swyllys int
251*3089Swyllys ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag)
252*3089Swyllys {
253*3089Swyllys 	ber_int_t taglen, lenlen, rc, len;
254*3089Swyllys 
255*3089Swyllys 	if (tag == KMFBER_DEFAULT)
256*3089Swyllys 		tag = 0x06; 	/* TODO: Add new OID constant to header */
257*3089Swyllys 
258*3089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
259*3089Swyllys 		return (-1);
260*3089Swyllys 
261*3089Swyllys 	len = (ber_int_t)oid->bv_len;
262*3089Swyllys 	if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 ||
263*3089Swyllys 		kmfber_write(ber, oid->bv_val, oid->bv_len, 0) !=
264*3089Swyllys 		(ber_int_t)oid->bv_len) {
265*3089Swyllys 		rc = -1;
266*3089Swyllys 	} else {
267*3089Swyllys 		/* return length of tag + length + contents */
268*3089Swyllys 		rc = taglen + lenlen + oid->bv_len;
269*3089Swyllys 	}
270*3089Swyllys 	return (rc);
271*3089Swyllys }
272*3089Swyllys 
273*3089Swyllys int
274*3089Swyllys ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data,
275*3089Swyllys 	ber_len_t len)
276*3089Swyllys {
277*3089Swyllys 	ber_int_t taglen, lenlen, ilen, rc;
278*3089Swyllys 
279*3089Swyllys 	if (tag == KMFBER_DEFAULT)
280*3089Swyllys 		tag = BER_INTEGER;
281*3089Swyllys 
282*3089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
283*3089Swyllys 		return (-1);
284*3089Swyllys 
285*3089Swyllys 	ilen = (ber_int_t)len;
286*3089Swyllys 	if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 ||
287*3089Swyllys 		kmfber_write(ber, data, len, 0) != (ber_int_t)len) {
288*3089Swyllys 		rc = -1;
289*3089Swyllys 	} else {
290*3089Swyllys 		/* return length of tag + length + contents */
291*3089Swyllys 		rc = taglen + lenlen + len;
292*3089Swyllys 	}
293*3089Swyllys 	return (rc);
294*3089Swyllys }
295*3089Swyllys 
296*3089Swyllys static int
297*3089Swyllys kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len,
298*3089Swyllys 	ber_tag_t tag)
299*3089Swyllys {
300*3089Swyllys 	ber_int_t	taglen, lenlen, ilen, rc;
301*3089Swyllys #ifdef STR_TRANSLATION
302*3089Swyllys 	int	free_str;
303*3089Swyllys #endif /* STR_TRANSLATION */
304*3089Swyllys 
305*3089Swyllys 	if (tag == KMFBER_DEFAULT)
306*3089Swyllys 		tag = BER_OCTET_STRING;
307*3089Swyllys 
308*3089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
309*3089Swyllys 		return (-1);
310*3089Swyllys 
311*3089Swyllys #ifdef STR_TRANSLATION
312*3089Swyllys 	if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 &&
313*3089Swyllys 	    ber->ber_encode_translate_proc != NULL) {
314*3089Swyllys 		if ((*(ber->ber_encode_translate_proc))(&str, &len, 0)
315*3089Swyllys 		    != 0) {
316*3089Swyllys 			return (-1);
317*3089Swyllys 		}
318*3089Swyllys 		free_str = 1;
319*3089Swyllys 	} else {
320*3089Swyllys 		free_str = 0;
321*3089Swyllys 	}
322*3089Swyllys #endif /* STR_TRANSLATION */
323*3089Swyllys 
324*3089Swyllys 	/*
325*3089Swyllys 	 *  Note:  below is a spot where we limit ber_write
326*3089Swyllys 	 *	to signed long (instead of unsigned long)
327*3089Swyllys 	 */
328*3089Swyllys 	ilen = (ber_int_t)len;
329*3089Swyllys 	if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 ||
330*3089Swyllys 		kmfber_write(ber, str, len, 0) != (ber_int_t)len) {
331*3089Swyllys 		rc = -1;
332*3089Swyllys 	} else {
333*3089Swyllys 		/* return length of tag + length + contents */
334*3089Swyllys 		rc = taglen + lenlen + len;
335*3089Swyllys 	}
336*3089Swyllys 
337*3089Swyllys #ifdef STR_TRANSLATION
338*3089Swyllys 	if (free_str) {
339*3089Swyllys 		free(str);
340*3089Swyllys 	}
341*3089Swyllys #endif /* STR_TRANSLATION */
342*3089Swyllys 
343*3089Swyllys 	return (rc);
344*3089Swyllys }
345*3089Swyllys 
346*3089Swyllys static int
347*3089Swyllys kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag)
348*3089Swyllys {
349*3089Swyllys 	return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag));
350*3089Swyllys }
351*3089Swyllys 
352*3089Swyllys static int
353*3089Swyllys kmfber_put_bitstring(BerElement *ber, char *str,
354*3089Swyllys 	ber_len_t blen /* in bits */, ber_tag_t tag)
355*3089Swyllys {
356*3089Swyllys 	ber_int_t	taglen, lenlen, len;
357*3089Swyllys 	unsigned char	unusedbits;
358*3089Swyllys 
359*3089Swyllys 	if (tag == KMFBER_DEFAULT)
360*3089Swyllys 		tag = BER_BIT_STRING;
361*3089Swyllys 
362*3089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
363*3089Swyllys 		return (-1);
364*3089Swyllys 
365*3089Swyllys 	len = (blen + 7) / 8;
366*3089Swyllys 	unusedbits = (unsigned char) (len * 8 - blen);
367*3089Swyllys 	if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1)
368*3089Swyllys 		return (-1);
369*3089Swyllys 
370*3089Swyllys 	if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1)
371*3089Swyllys 		return (-1);
372*3089Swyllys 
373*3089Swyllys 	if (kmfber_write(ber, str, len, 0) != len)
374*3089Swyllys 		return (-1);
375*3089Swyllys 
376*3089Swyllys 	/* return length of tag + length + unused bit count + contents */
377*3089Swyllys 	return (taglen + 1 + lenlen + len);
378*3089Swyllys }
379*3089Swyllys 
380*3089Swyllys static int
381*3089Swyllys kmfber_put_null(BerElement *ber, ber_tag_t tag)
382*3089Swyllys {
383*3089Swyllys 	int	taglen;
384*3089Swyllys 
385*3089Swyllys 	if (tag == KMFBER_DEFAULT)
386*3089Swyllys 		tag = BER_NULL;
387*3089Swyllys 
388*3089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
389*3089Swyllys 		return (-1);
390*3089Swyllys 
391*3089Swyllys 	if (kmfber_put_len(ber, 0, 0) != 1)
392*3089Swyllys 		return (-1);
393*3089Swyllys 
394*3089Swyllys 	return (taglen + 1);
395*3089Swyllys }
396*3089Swyllys 
397*3089Swyllys static int
398*3089Swyllys kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag)
399*3089Swyllys {
400*3089Swyllys 	int		taglen;
401*3089Swyllys 	unsigned char	trueval = 0xff;
402*3089Swyllys 	unsigned char	falseval = 0x00;
403*3089Swyllys 
404*3089Swyllys 	if (tag == KMFBER_DEFAULT)
405*3089Swyllys 		tag = BER_BOOLEAN;
406*3089Swyllys 
407*3089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
408*3089Swyllys 		return (-1);
409*3089Swyllys 
410*3089Swyllys 	if (kmfber_put_len(ber, 1, 0) != 1)
411*3089Swyllys 		return (-1);
412*3089Swyllys 
413*3089Swyllys 	if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0)
414*3089Swyllys 	    != 1)
415*3089Swyllys 		return (-1);
416*3089Swyllys 
417*3089Swyllys 	return (taglen + 2);
418*3089Swyllys }
419*3089Swyllys 
420*3089Swyllys #define	FOUR_BYTE_LEN	5
421*3089Swyllys 
422*3089Swyllys 
423*3089Swyllys /*
424*3089Swyllys  * The idea here is roughly this: we maintain a stack of these Seqorset
425*3089Swyllys  * structures. This is pushed when we see the beginning of a new set or
426*3089Swyllys  * sequence. It is popped when we see the end of a set or sequence.
427*3089Swyllys  * Since we don't want to malloc and free these structures all the time,
428*3089Swyllys  * we pre-allocate a small set of them within the ber element structure.
429*3089Swyllys  * thus we need to spot when we've overflowed this stack and fall back to
430*3089Swyllys  * malloc'ing instead.
431*3089Swyllys  */
432*3089Swyllys static int
433*3089Swyllys ber_start_seqorset(BerElement *ber, ber_tag_t tag)
434*3089Swyllys {
435*3089Swyllys 	Seqorset	*new_sos;
436*3089Swyllys 
437*3089Swyllys 	/* can we fit into the local stack ? */
438*3089Swyllys 	if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
439*3089Swyllys 		/* yes */
440*3089Swyllys 		new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
441*3089Swyllys 	} else {
442*3089Swyllys 		/* no */
443*3089Swyllys 		if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset)))
444*3089Swyllys 		    == NULLSEQORSET) {
445*3089Swyllys 			return (-1);
446*3089Swyllys 		}
447*3089Swyllys 	}
448*3089Swyllys 	ber->ber_sos_stack_posn++;
449*3089Swyllys 
450*3089Swyllys 	if (ber->ber_sos == NULLSEQORSET)
451*3089Swyllys 		new_sos->sos_first = ber->ber_ptr;
452*3089Swyllys 	else
453*3089Swyllys 		new_sos->sos_first = ber->ber_sos->sos_ptr;
454*3089Swyllys 
455*3089Swyllys 	/* Set aside room for a 4 byte length field */
456*3089Swyllys 	new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) +
457*3089Swyllys 		FOUR_BYTE_LEN;
458*3089Swyllys 	new_sos->sos_tag = tag;
459*3089Swyllys 
460*3089Swyllys 	new_sos->sos_next = ber->ber_sos;
461*3089Swyllys 	new_sos->sos_clen = 0;
462*3089Swyllys 
463*3089Swyllys 	ber->ber_sos = new_sos;
464*3089Swyllys 	if (ber->ber_sos->sos_ptr > ber->ber_end) {
465*3089Swyllys 		(void) realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
466*3089Swyllys 	}
467*3089Swyllys 	return (0);
468*3089Swyllys }
469*3089Swyllys 
470*3089Swyllys static int
471*3089Swyllys kmfber_start_seq(BerElement *ber, ber_tag_t tag)
472*3089Swyllys {
473*3089Swyllys 	if (tag == KMFBER_DEFAULT)
474*3089Swyllys 		tag = BER_CONSTRUCTED_SEQUENCE;
475*3089Swyllys 
476*3089Swyllys 	return (ber_start_seqorset(ber, tag));
477*3089Swyllys }
478*3089Swyllys 
479*3089Swyllys static int
480*3089Swyllys kmfber_start_set(BerElement *ber, ber_tag_t tag)
481*3089Swyllys {
482*3089Swyllys 	if (tag == KMFBER_DEFAULT)
483*3089Swyllys 		tag = BER_CONSTRUCTED_SET;
484*3089Swyllys 
485*3089Swyllys 	return (ber_start_seqorset(ber, tag));
486*3089Swyllys }
487*3089Swyllys 
488*3089Swyllys static int
489*3089Swyllys ber_put_seqorset(BerElement *ber)
490*3089Swyllys {
491*3089Swyllys 	ber_int_t	netlen, len, taglen, lenlen;
492*3089Swyllys 	unsigned char	ltag = 0x80 + FOUR_BYTE_LEN - 1;
493*3089Swyllys 	Seqorset	*next;
494*3089Swyllys 	Seqorset	**sos = &ber->ber_sos;
495*3089Swyllys 
496*3089Swyllys 	/*
497*3089Swyllys 	 * If this is the toplevel sequence or set, we need to actually
498*3089Swyllys 	 * write the stuff out.  Otherwise, it's already been put in
499*3089Swyllys 	 * the appropriate buffer and will be written when the toplevel
500*3089Swyllys 	 * one is written.  In this case all we need to do is update the
501*3089Swyllys 	 * length and tag.
502*3089Swyllys 	 */
503*3089Swyllys 
504*3089Swyllys 	len = (*sos)->sos_clen;
505*3089Swyllys 	netlen = (ber_len_t)htonl(len);
506*3089Swyllys 
507*3089Swyllys 	if (ber->ber_options & KMFBER_OPT_USE_DER) {
508*3089Swyllys 		lenlen = kmfber_calc_lenlen(len);
509*3089Swyllys 	} else {
510*3089Swyllys 		lenlen = FOUR_BYTE_LEN;
511*3089Swyllys 	}
512*3089Swyllys 
513*3089Swyllys 	if ((next = (*sos)->sos_next) == NULLSEQORSET) {
514*3089Swyllys 		/* write the tag */
515*3089Swyllys 		if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1)
516*3089Swyllys 			return (-1);
517*3089Swyllys 
518*3089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
519*3089Swyllys 			/* Write the length in the minimum # of octets */
520*3089Swyllys 			if (kmfber_put_len(ber, len, 1) == -1)
521*3089Swyllys 				return (-1);
522*3089Swyllys 
523*3089Swyllys 			if (lenlen != FOUR_BYTE_LEN) {
524*3089Swyllys 				/*
525*3089Swyllys 				 * We set aside FOUR_BYTE_LEN bytes for
526*3089Swyllys 				 * the length field.  Move the data if
527*3089Swyllys 				 * we don't actually need that much
528*3089Swyllys 				 */
529*3089Swyllys 				(void) memmove((*sos)->sos_first + taglen +
530*3089Swyllys 				    lenlen, (*sos)->sos_first + taglen +
531*3089Swyllys 				    FOUR_BYTE_LEN, len);
532*3089Swyllys 			}
533*3089Swyllys 		} else {
534*3089Swyllys 			/* Fill FOUR_BYTE_LEN bytes for length field */
535*3089Swyllys 			/* one byte of length length */
536*3089Swyllys 			if (kmfber_write(ber, (char *)&ltag, 1, 1) != 1)
537*3089Swyllys 				return (-1);
538*3089Swyllys 
539*3089Swyllys 			/* the length itself */
540*3089Swyllys 			if (kmfber_write(ber,
541*3089Swyllys 				(char *)&netlen + sizeof (ber_int_t)
542*3089Swyllys 				- (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) !=
543*3089Swyllys 				FOUR_BYTE_LEN - 1)
544*3089Swyllys 				return (-1);
545*3089Swyllys 		}
546*3089Swyllys 		/* The ber_ptr is at the set/seq start - move it to the end */
547*3089Swyllys 		ber->ber_ptr += len;
548*3089Swyllys 	} else {
549*3089Swyllys 		ber_tag_t	ntag;
550*3089Swyllys 
551*3089Swyllys 		/* the tag */
552*3089Swyllys 		taglen = kmfber_calc_taglen((*sos)->sos_tag);
553*3089Swyllys 		ntag = htonl((*sos)->sos_tag);
554*3089Swyllys 		(void) memmove((*sos)->sos_first, (char *)&ntag +
555*3089Swyllys 		    sizeof (ber_int_t) - taglen, taglen);
556*3089Swyllys 
557*3089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
558*3089Swyllys 			ltag = (lenlen == 1) ? (unsigned char)len :
559*3089Swyllys 				(unsigned char) (0x80 + (lenlen - 1));
560*3089Swyllys 		}
561*3089Swyllys 
562*3089Swyllys 		/* one byte of length length */
563*3089Swyllys 		(void) memmove((*sos)->sos_first + 1, &ltag, 1);
564*3089Swyllys 
565*3089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
566*3089Swyllys 			if (lenlen > 1) {
567*3089Swyllys 				/* Write the length itself */
568*3089Swyllys 				(void) memmove((*sos)->sos_first + 2,
569*3089Swyllys 				    (char *)&netlen + sizeof (ber_uint_t) -
570*3089Swyllys 				    (lenlen - 1),
571*3089Swyllys 				    lenlen - 1);
572*3089Swyllys 			}
573*3089Swyllys 			if (lenlen != FOUR_BYTE_LEN) {
574*3089Swyllys 				/*
575*3089Swyllys 				 * We set aside FOUR_BYTE_LEN bytes for
576*3089Swyllys 				 * the length field.  Move the data if
577*3089Swyllys 				 * we don't actually need that much
578*3089Swyllys 				 */
579*3089Swyllys 				(void) memmove((*sos)->sos_first + taglen +
580*3089Swyllys 				    lenlen, (*sos)->sos_first + taglen +
581*3089Swyllys 				    FOUR_BYTE_LEN, len);
582*3089Swyllys 			}
583*3089Swyllys 		} else {
584*3089Swyllys 			/* the length itself */
585*3089Swyllys 			(void) memmove((*sos)->sos_first + taglen + 1,
586*3089Swyllys 			    (char *) &netlen + sizeof (ber_int_t) -
587*3089Swyllys 			    (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1);
588*3089Swyllys 		}
589*3089Swyllys 
590*3089Swyllys 		next->sos_clen += (taglen + lenlen + len);
591*3089Swyllys 		next->sos_ptr += (taglen + lenlen + len);
592*3089Swyllys 	}
593*3089Swyllys 
594*3089Swyllys 	/* we're done with this seqorset, so free it up */
595*3089Swyllys 	/* was this one from the local stack ? */
596*3089Swyllys 	if (ber->ber_sos_stack_posn > SOS_STACK_SIZE) {
597*3089Swyllys 		free((char *)(*sos));
598*3089Swyllys 	}
599*3089Swyllys 	ber->ber_sos_stack_posn--;
600*3089Swyllys 	*sos = next;
601*3089Swyllys 
602*3089Swyllys 	return (taglen + lenlen + len);
603*3089Swyllys }
604*3089Swyllys 
605*3089Swyllys /* VARARGS */
606*3089Swyllys int
607*3089Swyllys kmfber_printf(BerElement *ber, const char *fmt, ...)
608*3089Swyllys {
609*3089Swyllys 	va_list		ap;
610*3089Swyllys 	char		*s, **ss;
611*3089Swyllys 	struct berval	**bv, *oid;
612*3089Swyllys 	int		rc, i, t;
613*3089Swyllys 	ber_int_t	len;
614*3089Swyllys 
615*3089Swyllys 	va_start(ap, fmt);
616*3089Swyllys 
617*3089Swyllys #ifdef KMFBER_DEBUG
618*3089Swyllys 	if (lber_debug & 64) {
619*3089Swyllys 		char msg[80];
620*3089Swyllys 		sprintf(msg, "kmfber_printf fmt (%s)\n", fmt);
621*3089Swyllys 		ber_err_print(msg);
622*3089Swyllys 	}
623*3089Swyllys #endif
624*3089Swyllys 
625*3089Swyllys 	for (rc = 0; *fmt && rc != -1; fmt++) {
626*3089Swyllys 		switch (*fmt) {
627*3089Swyllys 		case 'b':	/* boolean */
628*3089Swyllys 			i = va_arg(ap, int);
629*3089Swyllys 			rc = kmfber_put_boolean(ber, i, ber->ber_tag);
630*3089Swyllys 			break;
631*3089Swyllys 
632*3089Swyllys 		case 'i':	/* int */
633*3089Swyllys 			i = va_arg(ap, int);
634*3089Swyllys 			rc = ber_put_int(ber, (ber_int_t)i, ber->ber_tag);
635*3089Swyllys 			break;
636*3089Swyllys 
637*3089Swyllys 		case 'D':	/* Object ID */
638*3089Swyllys 			if ((oid = va_arg(ap, struct berval *)) == NULL)
639*3089Swyllys 				break;
640*3089Swyllys 			rc = ber_put_oid(ber, oid, ber->ber_tag);
641*3089Swyllys 			break;
642*3089Swyllys 		case 'I':	/* int */
643*3089Swyllys 			s = va_arg(ap, char *);
644*3089Swyllys 			len = va_arg(ap, ber_int_t);
645*3089Swyllys 			rc = ber_put_big_int(ber, ber->ber_tag, s, len);
646*3089Swyllys 			break;
647*3089Swyllys 
648*3089Swyllys 		case 'e':	/* enumeration */
649*3089Swyllys 			i = va_arg(ap, int);
650*3089Swyllys 			rc = kmfber_put_enum(ber, (ber_int_t)i, ber->ber_tag);
651*3089Swyllys 			break;
652*3089Swyllys 
653*3089Swyllys 		case 'l':
654*3089Swyllys 			t = va_arg(ap, int);
655*3089Swyllys 			rc = kmfber_put_len(ber, t, 0);
656*3089Swyllys 			break;
657*3089Swyllys 		case 'n':	/* null */
658*3089Swyllys 			rc = kmfber_put_null(ber, ber->ber_tag);
659*3089Swyllys 			break;
660*3089Swyllys 
661*3089Swyllys 		case 'o':	/* octet string (non-null terminated) */
662*3089Swyllys 			s = va_arg(ap, char *);
663*3089Swyllys 			len = va_arg(ap, int);
664*3089Swyllys 			rc = kmfber_put_ostring(ber, s, len, ber->ber_tag);
665*3089Swyllys 			break;
666*3089Swyllys 
667*3089Swyllys 		case 's':	/* string */
668*3089Swyllys 			s = va_arg(ap, char *);
669*3089Swyllys 			rc = kmfber_put_string(ber, s, ber->ber_tag);
670*3089Swyllys 			break;
671*3089Swyllys 
672*3089Swyllys 		case 'B':	/* bit string */
673*3089Swyllys 			s = va_arg(ap, char *);
674*3089Swyllys 			len = va_arg(ap, int);	/* in bits */
675*3089Swyllys 			rc = kmfber_put_bitstring(ber, s, len, ber->ber_tag);
676*3089Swyllys 			break;
677*3089Swyllys 
678*3089Swyllys 		case 't':	/* tag for the next element */
679*3089Swyllys 			ber->ber_tag = va_arg(ap, ber_tag_t);
680*3089Swyllys 			ber->ber_usertag = 1;
681*3089Swyllys 			break;
682*3089Swyllys 
683*3089Swyllys 		case 'T': /* Write an explicit tag, but don't change current */
684*3089Swyllys 			t = va_arg(ap, int);
685*3089Swyllys 			rc = ber_put_tag(ber, t, 0);
686*3089Swyllys 			break;
687*3089Swyllys 
688*3089Swyllys 		case 'v':	/* vector of strings */
689*3089Swyllys 			if ((ss = va_arg(ap, char **)) == NULL)
690*3089Swyllys 				break;
691*3089Swyllys 			for (i = 0; ss[i] != NULL; i++) {
692*3089Swyllys 				if ((rc = kmfber_put_string(ber, ss[i],
693*3089Swyllys 				    ber->ber_tag)) == -1)
694*3089Swyllys 					break;
695*3089Swyllys 			}
696*3089Swyllys 			break;
697*3089Swyllys 
698*3089Swyllys 		case 'V':	/* sequences of strings + lengths */
699*3089Swyllys 			if ((bv = va_arg(ap, struct berval **)) == NULL)
700*3089Swyllys 				break;
701*3089Swyllys 			for (i = 0; bv[i] != NULL; i++) {
702*3089Swyllys 				if ((rc = kmfber_put_ostring(ber, bv[i]->bv_val,
703*3089Swyllys 				    bv[i]->bv_len, ber->ber_tag)) == -1)
704*3089Swyllys 					break;
705*3089Swyllys 			}
706*3089Swyllys 			break;
707*3089Swyllys 
708*3089Swyllys 		case '{':	/* begin sequence */
709*3089Swyllys 			rc = kmfber_start_seq(ber, ber->ber_tag);
710*3089Swyllys 			break;
711*3089Swyllys 
712*3089Swyllys 		case '}':	/* end sequence */
713*3089Swyllys 			rc = ber_put_seqorset(ber);
714*3089Swyllys 			break;
715*3089Swyllys 
716*3089Swyllys 		case '[':	/* begin set */
717*3089Swyllys 			rc = kmfber_start_set(ber, ber->ber_tag);
718*3089Swyllys 			break;
719*3089Swyllys 
720*3089Swyllys 		case ']':	/* end set */
721*3089Swyllys 			rc = ber_put_seqorset(ber);
722*3089Swyllys 			break;
723*3089Swyllys 
724*3089Swyllys 		default: {
725*3089Swyllys #ifdef KMFBER_DEBUG
726*3089Swyllys 				char msg[80];
727*3089Swyllys 				sprintf(msg, "unknown fmt %c\n", *fmt);
728*3089Swyllys 				ber_err_print(msg);
729*3089Swyllys #endif
730*3089Swyllys 				rc = -1;
731*3089Swyllys 				break;
732*3089Swyllys 			}
733*3089Swyllys 		}
734*3089Swyllys 
735*3089Swyllys 		if (ber->ber_usertag == 0)
736*3089Swyllys 			ber->ber_tag = KMFBER_DEFAULT;
737*3089Swyllys 		else
738*3089Swyllys 			ber->ber_usertag = 0;
739*3089Swyllys 	}
740*3089Swyllys 
741*3089Swyllys 	va_end(ap);
742*3089Swyllys 
743*3089Swyllys 	return (rc);
744*3089Swyllys }
745