13089Swyllys /*
23089Swyllys  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
33089Swyllys  *
43089Swyllys  * The contents of this file are subject to the Netscape Public License
53089Swyllys  * Version 1.0 (the "NPL"); you may not use this file except in
63089Swyllys  * compliance with the NPL.  You may obtain a copy of the NPL at
73089Swyllys  * http://www.mozilla.org/NPL/
83089Swyllys  *
93089Swyllys  * Software distributed under the NPL is distributed on an "AS IS" basis,
103089Swyllys  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
113089Swyllys  * for the specific language governing rights and limitations under the
123089Swyllys  * NPL.
133089Swyllys  *
143089Swyllys  * The Initial Developer of this code under the NPL is Netscape
153089Swyllys  * Communications Corporation.  Portions created by Netscape are
163089Swyllys  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
173089Swyllys  * Reserved.
183089Swyllys  */
193089Swyllys 
203089Swyllys /*
213089Swyllys  * Copyright (c) 1990 Regents of the University of Michigan.
223089Swyllys  * All rights reserved.
233089Swyllys  *
243089Swyllys  * Redistribution and use in source and binary forms are permitted
253089Swyllys  * provided that this notice is preserved and that due credit is given
263089Swyllys  * to the University of Michigan at Ann Arbor. The name of the University
273089Swyllys  * may not be used to endorse or promote products derived from this
283089Swyllys  * software without specific prior written permission. This software
293089Swyllys  * is provided ``as is'' without express or implied warranty.
303089Swyllys  */
313089Swyllys 
323089Swyllys /*
333433Shaimay  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
343089Swyllys  * Use is subject to license terms.
353089Swyllys  */
363089Swyllys 
373089Swyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
383089Swyllys 
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 /* the following constants are used in kmfber_calc_lenlen */
473089Swyllys 
483089Swyllys #define	LENMASK1	0xFF
493089Swyllys #define	LENMASK2 	0xFFFF
503089Swyllys #define	LENMASK3	0xFFFFFF
513089Swyllys #define	LENMASK4	0xFFFFFFFF
523089Swyllys #define	_MASK		0x80
533089Swyllys 
543089Swyllys int
553089Swyllys kmfber_calc_taglen(ber_tag_t tag)
563089Swyllys {
573089Swyllys 	int		i;
583089Swyllys 	ber_int_t	mask;
593089Swyllys 
603089Swyllys 	/* find the first non-all-zero byte in the tag */
613089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
623089Swyllys 		mask = (LENMASK3 << (i * 8));
633089Swyllys 		/* not all zero */
643089Swyllys 		if (tag & mask)
653089Swyllys 			break;
663089Swyllys 	}
673089Swyllys 
683089Swyllys 	return (i + 1);
693089Swyllys }
703089Swyllys 
713089Swyllys static int
723089Swyllys ber_put_tag(BerElement	*ber, ber_tag_t tag, int nosos)
733089Swyllys {
743089Swyllys 	ber_int_t	taglen;
753089Swyllys 	ber_tag_t	ntag;
763089Swyllys 
773089Swyllys 	taglen = kmfber_calc_taglen(tag);
783089Swyllys 
793089Swyllys 	ntag = htonl(tag);
803089Swyllys 
813089Swyllys 	return (kmfber_write(ber,
82*5221Swyllys 	    ((char *) &ntag) + sizeof (ber_int_t) - taglen,
83*5221Swyllys 	    taglen, nosos));
843089Swyllys }
853089Swyllys 
863089Swyllys int
873089Swyllys kmfber_calc_lenlen(ber_int_t len)
883089Swyllys {
893089Swyllys 	/*
903089Swyllys 	 * short len if it's less than 128 - one byte giving the len,
913089Swyllys 	 * with bit 8 0.
923089Swyllys 	 */
933089Swyllys 
943089Swyllys 	if (len <= 0x7F)
953089Swyllys 		return (1);
963089Swyllys 
973089Swyllys 	/*
983089Swyllys 	 * long len otherwise - one byte with bit 8 set, giving the
993089Swyllys 	 * length of the length, followed by the length itself.
1003089Swyllys 	 */
1013089Swyllys 
1023089Swyllys 	if (len <= LENMASK1)
1033089Swyllys 		return (2);
1043089Swyllys 	if (len <= LENMASK2)
1053089Swyllys 		return (3);
1063089Swyllys 	if (len <= LENMASK3)
1073089Swyllys 		return (4);
1083089Swyllys 
1093089Swyllys 	return (5);
1103089Swyllys }
1113089Swyllys 
1123089Swyllys int
1133089Swyllys kmfber_put_len(BerElement *ber, ber_int_t len, int nosos)
1143089Swyllys {
1153089Swyllys 	int		i;
1163089Swyllys 	char		lenlen;
1173089Swyllys 	ber_int_t	mask, netlen;
1183089Swyllys 
1193089Swyllys 	/*
1203089Swyllys 	 * short len if it's less than 128 - one byte giving the len,
1213089Swyllys 	 * with bit 8 0.
1223089Swyllys 	 */
1233089Swyllys 	if (len <= 127) {
1243089Swyllys 		netlen = htonl(len);
1253089Swyllys 		return (kmfber_write(ber,
126*5221Swyllys 		    (char *)&netlen + sizeof (ber_int_t) - 1,
127*5221Swyllys 		    1, nosos));
1283089Swyllys 	}
1293089Swyllys 
1303089Swyllys 	/*
1313089Swyllys 	 * long len otherwise - one byte with bit 8 set, giving the
1323089Swyllys 	 * length of the length, followed by the length itself.
1333089Swyllys 	 */
1343089Swyllys 
1353089Swyllys 	/* find the first non-all-zero byte */
1363089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
1373089Swyllys 		mask = (LENMASK1 << (i * 8));
1383089Swyllys 		/* not all zero */
1393089Swyllys 		if (len & mask)
1403089Swyllys 			break;
1413089Swyllys 	}
1423089Swyllys 	lenlen = ++i;
1433089Swyllys 	if (lenlen > 4)
1443089Swyllys 		return (-1);
1453089Swyllys 	lenlen |= 0x80;
1463089Swyllys 
1473089Swyllys 	/* write the length of the length */
1483089Swyllys 	if (kmfber_write(ber, &lenlen, 1, nosos) != 1)
1493089Swyllys 		return (-1);
1503089Swyllys 
1513089Swyllys 	/* write the length itself */
1523089Swyllys 	netlen = htonl(len);
1533089Swyllys 	if (kmfber_write(ber,
154*5221Swyllys 	    (char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i)
1553089Swyllys 		return (-1);
1563089Swyllys 
1573089Swyllys 	return (i + 1);
1583089Swyllys }
1593089Swyllys 
1603089Swyllys static int
1613089Swyllys ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag)
1623089Swyllys {
1633089Swyllys 	int		i, sign;
1643089Swyllys 	ber_int_t	len, lenlen, taglen, netnum, mask;
1653089Swyllys 
1663089Swyllys 	sign = (num < 0);
1673089Swyllys 
1683089Swyllys 	/*
1693089Swyllys 	 * high bit is set - look for first non-all-one byte
1703089Swyllys 	 * high bit is clear - look for first non-all-zero byte
1713089Swyllys 	 */
1723089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
1733089Swyllys 		mask = (LENMASK1 << (i * 8));
1743089Swyllys 
1753089Swyllys 		if (sign) {
1763089Swyllys 			/* not all ones */
1773089Swyllys 			if ((num & mask) != mask)
1783089Swyllys 				break;
1793089Swyllys 		} else {
1803089Swyllys 			/* not all zero */
1813089Swyllys 			if (num & mask)
1823089Swyllys 				break;
1833089Swyllys 		}
1843089Swyllys 	}
1853089Swyllys 
1863089Swyllys 	/*
1873089Swyllys 	 * we now have the "leading byte".  if the high bit on this
1883089Swyllys 	 * byte matches the sign bit, we need to "back up" a byte.
1893089Swyllys 	 */
1903089Swyllys 	mask = (num & (_MASK << (i * 8)));
1913089Swyllys 	if ((mask && !sign) || (sign && !mask))
1923089Swyllys 		i++;
1933089Swyllys 
1943089Swyllys 	len = i + 1;
1953089Swyllys 
1963089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
1973089Swyllys 		return (-1);
1983089Swyllys 
1993089Swyllys 	if ((lenlen = kmfber_put_len(ber, len, 0)) == -1)
2003089Swyllys 		return (-1);
2013089Swyllys 	i++;
2023089Swyllys 	netnum = htonl(num);
2033089Swyllys 	if (kmfber_write(ber,
204*5221Swyllys 	    (char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i)
2053089Swyllys 		/* length of tag + length + contents */
2063089Swyllys 		return (taglen + lenlen + i);
2073089Swyllys 
2083089Swyllys 	return (-1);
2093089Swyllys }
2103089Swyllys 
2113089Swyllys static int
2123089Swyllys kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag)
2133089Swyllys {
2143089Swyllys 	if (tag == KMFBER_DEFAULT)
2153089Swyllys 		tag = BER_ENUMERATED;
2163089Swyllys 
2173089Swyllys 	return (ber_put_int_or_enum(ber, num, tag));
2183089Swyllys }
2193089Swyllys 
2203089Swyllys int
2213089Swyllys ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag)
2223089Swyllys {
2233089Swyllys 	if (tag == KMFBER_DEFAULT)
2243089Swyllys 		tag = BER_INTEGER;
2253089Swyllys 
2263089Swyllys 	return (ber_put_int_or_enum(ber, num, tag));
2273089Swyllys }
2283089Swyllys 
2293089Swyllys int
2303089Swyllys ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag)
2313089Swyllys {
2323089Swyllys 	ber_int_t taglen, lenlen, rc, len;
2333089Swyllys 
2343089Swyllys 	if (tag == KMFBER_DEFAULT)
2353089Swyllys 		tag = 0x06; 	/* TODO: Add new OID constant to header */
2363089Swyllys 
2373089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
2383089Swyllys 		return (-1);
2393089Swyllys 
2403089Swyllys 	len = (ber_int_t)oid->bv_len;
2413089Swyllys 	if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 ||
242*5221Swyllys 	    kmfber_write(ber, oid->bv_val, oid->bv_len, 0) !=
243*5221Swyllys 	    (ber_int_t)oid->bv_len) {
2443089Swyllys 		rc = -1;
2453089Swyllys 	} else {
2463089Swyllys 		/* return length of tag + length + contents */
2473089Swyllys 		rc = taglen + lenlen + oid->bv_len;
2483089Swyllys 	}
2493089Swyllys 	return (rc);
2503089Swyllys }
2513089Swyllys 
2523089Swyllys int
2533089Swyllys ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data,
2543089Swyllys 	ber_len_t len)
2553089Swyllys {
2563089Swyllys 	ber_int_t taglen, lenlen, ilen, rc;
257*5221Swyllys 	char zero = 0x00;
2583089Swyllys 
2593089Swyllys 	if (tag == KMFBER_DEFAULT)
2603089Swyllys 		tag = BER_INTEGER;
2613089Swyllys 
2623089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
2633089Swyllys 		return (-1);
2643089Swyllys 
265*5221Swyllys 	/* Add a leading 0 if the high order bit is set */
266*5221Swyllys 	if (data[0] & 0x80)
267*5221Swyllys 		len++;
268*5221Swyllys 
2693089Swyllys 	ilen = (ber_int_t)len;
270*5221Swyllys 	if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1)
271*5221Swyllys 		return (-1);
272*5221Swyllys 
273*5221Swyllys 	/* add leading 0 if hi bit set */
274*5221Swyllys 	if ((data[0] & 0x80) && kmfber_write(ber, &zero, 1, 0) != 1)
275*5221Swyllys 		return (-1);
276*5221Swyllys 
277*5221Swyllys 	/* Adjust the length of the write if hi-order bit is set */
278*5221Swyllys 	if (data[0] & 0x80)
279*5221Swyllys 		ilen = len - 1;
280*5221Swyllys 	if (kmfber_write(ber, data, ilen, 0) != (ber_int_t)ilen) {
281*5221Swyllys 		return (-1);
2823089Swyllys 	} else {
2833089Swyllys 		/* return length of tag + length + contents */
2843089Swyllys 		rc = taglen + lenlen + len;
2853089Swyllys 	}
2863089Swyllys 	return (rc);
2873089Swyllys }
2883089Swyllys 
2893089Swyllys static int
2903089Swyllys kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len,
2913089Swyllys 	ber_tag_t tag)
2923089Swyllys {
2933089Swyllys 	ber_int_t	taglen, lenlen, ilen, rc;
2943089Swyllys #ifdef STR_TRANSLATION
2953089Swyllys 	int	free_str;
2963089Swyllys #endif /* STR_TRANSLATION */
2973089Swyllys 
2983089Swyllys 	if (tag == KMFBER_DEFAULT)
2993089Swyllys 		tag = BER_OCTET_STRING;
3003089Swyllys 
3013089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3023089Swyllys 		return (-1);
3033089Swyllys 
3043089Swyllys #ifdef STR_TRANSLATION
3053089Swyllys 	if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 &&
3063089Swyllys 	    ber->ber_encode_translate_proc != NULL) {
3073089Swyllys 		if ((*(ber->ber_encode_translate_proc))(&str, &len, 0)
3083089Swyllys 		    != 0) {
3093089Swyllys 			return (-1);
3103089Swyllys 		}
3113089Swyllys 		free_str = 1;
3123089Swyllys 	} else {
3133089Swyllys 		free_str = 0;
3143089Swyllys 	}
3153089Swyllys #endif /* STR_TRANSLATION */
3163089Swyllys 
3173089Swyllys 	/*
3183089Swyllys 	 *  Note:  below is a spot where we limit ber_write
3193089Swyllys 	 *	to signed long (instead of unsigned long)
3203089Swyllys 	 */
3213089Swyllys 	ilen = (ber_int_t)len;
3223089Swyllys 	if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 ||
323*5221Swyllys 	    kmfber_write(ber, str, len, 0) != (ber_int_t)len) {
3243089Swyllys 		rc = -1;
3253089Swyllys 	} else {
3263089Swyllys 		/* return length of tag + length + contents */
3273089Swyllys 		rc = taglen + lenlen + len;
3283089Swyllys 	}
3293089Swyllys 
3303089Swyllys #ifdef STR_TRANSLATION
3313089Swyllys 	if (free_str) {
3323089Swyllys 		free(str);
3333089Swyllys 	}
3343089Swyllys #endif /* STR_TRANSLATION */
3353089Swyllys 
3363089Swyllys 	return (rc);
3373089Swyllys }
3383089Swyllys 
3393089Swyllys static int
3403089Swyllys kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag)
3413089Swyllys {
3423089Swyllys 	return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag));
3433089Swyllys }
3443089Swyllys 
3453089Swyllys static int
3463089Swyllys kmfber_put_bitstring(BerElement *ber, char *str,
3473089Swyllys 	ber_len_t blen /* in bits */, ber_tag_t tag)
3483089Swyllys {
3493089Swyllys 	ber_int_t	taglen, lenlen, len;
3503089Swyllys 	unsigned char	unusedbits;
3513089Swyllys 
3523089Swyllys 	if (tag == KMFBER_DEFAULT)
3533089Swyllys 		tag = BER_BIT_STRING;
3543089Swyllys 
3553089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3563089Swyllys 		return (-1);
3573089Swyllys 
3583089Swyllys 	len = (blen + 7) / 8;
3593089Swyllys 	unusedbits = (unsigned char) (len * 8 - blen);
3603089Swyllys 	if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1)
3613089Swyllys 		return (-1);
3623089Swyllys 
3633089Swyllys 	if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1)
3643089Swyllys 		return (-1);
3653089Swyllys 
3663089Swyllys 	if (kmfber_write(ber, str, len, 0) != len)
3673089Swyllys 		return (-1);
3683089Swyllys 
3693089Swyllys 	/* return length of tag + length + unused bit count + contents */
3703089Swyllys 	return (taglen + 1 + lenlen + len);
3713089Swyllys }
3723089Swyllys 
3733089Swyllys static int
3743089Swyllys kmfber_put_null(BerElement *ber, ber_tag_t tag)
3753089Swyllys {
3763089Swyllys 	int	taglen;
3773089Swyllys 
3783089Swyllys 	if (tag == KMFBER_DEFAULT)
3793089Swyllys 		tag = BER_NULL;
3803089Swyllys 
3813089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3823089Swyllys 		return (-1);
3833089Swyllys 
3843089Swyllys 	if (kmfber_put_len(ber, 0, 0) != 1)
3853089Swyllys 		return (-1);
3863089Swyllys 
3873089Swyllys 	return (taglen + 1);
3883089Swyllys }
3893089Swyllys 
3903089Swyllys static int
3913089Swyllys kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag)
3923089Swyllys {
3933089Swyllys 	int		taglen;
3943089Swyllys 	unsigned char	trueval = 0xff;
3953089Swyllys 	unsigned char	falseval = 0x00;
3963089Swyllys 
3973089Swyllys 	if (tag == KMFBER_DEFAULT)
3983089Swyllys 		tag = BER_BOOLEAN;
3993089Swyllys 
4003089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
4013089Swyllys 		return (-1);
4023089Swyllys 
4033089Swyllys 	if (kmfber_put_len(ber, 1, 0) != 1)
4043089Swyllys 		return (-1);
4053089Swyllys 
4063089Swyllys 	if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0)
4073089Swyllys 	    != 1)
4083089Swyllys 		return (-1);
4093089Swyllys 
4103089Swyllys 	return (taglen + 2);
4113089Swyllys }
4123089Swyllys 
4133089Swyllys #define	FOUR_BYTE_LEN	5
4143089Swyllys 
4153089Swyllys 
4163089Swyllys /*
4173089Swyllys  * The idea here is roughly this: we maintain a stack of these Seqorset
4183089Swyllys  * structures. This is pushed when we see the beginning of a new set or
4193089Swyllys  * sequence. It is popped when we see the end of a set or sequence.
4203089Swyllys  * Since we don't want to malloc and free these structures all the time,
4213089Swyllys  * we pre-allocate a small set of them within the ber element structure.
4223089Swyllys  * thus we need to spot when we've overflowed this stack and fall back to
4233089Swyllys  * malloc'ing instead.
4243089Swyllys  */
4253089Swyllys static int
4263089Swyllys ber_start_seqorset(BerElement *ber, ber_tag_t tag)
4273089Swyllys {
4283089Swyllys 	Seqorset	*new_sos;
4293089Swyllys 
4303089Swyllys 	/* can we fit into the local stack ? */
4313089Swyllys 	if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
4323089Swyllys 		/* yes */
4333089Swyllys 		new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
4343089Swyllys 	} else {
4353089Swyllys 		/* no */
4363089Swyllys 		if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset)))
4373089Swyllys 		    == NULLSEQORSET) {
4383089Swyllys 			return (-1);
4393089Swyllys 		}
4403089Swyllys 	}
4413089Swyllys 	ber->ber_sos_stack_posn++;
4423089Swyllys 
4433089Swyllys 	if (ber->ber_sos == NULLSEQORSET)
4443089Swyllys 		new_sos->sos_first = ber->ber_ptr;
4453089Swyllys 	else
4463089Swyllys 		new_sos->sos_first = ber->ber_sos->sos_ptr;
4473089Swyllys 
4483089Swyllys 	/* Set aside room for a 4 byte length field */
4493089Swyllys 	new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) +
450*5221Swyllys 	    FOUR_BYTE_LEN;
4513089Swyllys 	new_sos->sos_tag = tag;
4523089Swyllys 
4533089Swyllys 	new_sos->sos_next = ber->ber_sos;
4543089Swyllys 	new_sos->sos_clen = 0;
4553089Swyllys 
4563089Swyllys 	ber->ber_sos = new_sos;
4573089Swyllys 	if (ber->ber_sos->sos_ptr > ber->ber_end) {
4583089Swyllys 		(void) realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
4593089Swyllys 	}
4603089Swyllys 	return (0);
4613089Swyllys }
4623089Swyllys 
4633089Swyllys static int
4643089Swyllys kmfber_start_seq(BerElement *ber, ber_tag_t tag)
4653089Swyllys {
4663089Swyllys 	if (tag == KMFBER_DEFAULT)
4673089Swyllys 		tag = BER_CONSTRUCTED_SEQUENCE;
4683089Swyllys 
4693089Swyllys 	return (ber_start_seqorset(ber, tag));
4703089Swyllys }
4713089Swyllys 
4723089Swyllys static int
4733089Swyllys kmfber_start_set(BerElement *ber, ber_tag_t tag)
4743089Swyllys {
4753089Swyllys 	if (tag == KMFBER_DEFAULT)
4763089Swyllys 		tag = BER_CONSTRUCTED_SET;
4773089Swyllys 
4783089Swyllys 	return (ber_start_seqorset(ber, tag));
4793089Swyllys }
4803089Swyllys 
4813089Swyllys static int
4823089Swyllys ber_put_seqorset(BerElement *ber)
4833089Swyllys {
4843089Swyllys 	ber_int_t	netlen, len, taglen, lenlen;
4853089Swyllys 	unsigned char	ltag = 0x80 + FOUR_BYTE_LEN - 1;
4863089Swyllys 	Seqorset	*next;
4873089Swyllys 	Seqorset	**sos = &ber->ber_sos;
4883089Swyllys 
4893089Swyllys 	/*
4903089Swyllys 	 * If this is the toplevel sequence or set, we need to actually
4913089Swyllys 	 * write the stuff out.  Otherwise, it's already been put in
4923089Swyllys 	 * the appropriate buffer and will be written when the toplevel
4933089Swyllys 	 * one is written.  In this case all we need to do is update the
4943089Swyllys 	 * length and tag.
4953089Swyllys 	 */
4963089Swyllys 
4973089Swyllys 	len = (*sos)->sos_clen;
4983089Swyllys 	netlen = (ber_len_t)htonl(len);
4993089Swyllys 
5003089Swyllys 	if (ber->ber_options & KMFBER_OPT_USE_DER) {
5013089Swyllys 		lenlen = kmfber_calc_lenlen(len);
5023089Swyllys 	} else {
5033089Swyllys 		lenlen = FOUR_BYTE_LEN;
5043089Swyllys 	}
5053089Swyllys 
5063089Swyllys 	if ((next = (*sos)->sos_next) == NULLSEQORSET) {
5073089Swyllys 		/* write the tag */
5083089Swyllys 		if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1)
5093089Swyllys 			return (-1);
5103089Swyllys 
5113089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
5123089Swyllys 			/* Write the length in the minimum # of octets */
5133089Swyllys 			if (kmfber_put_len(ber, len, 1) == -1)
5143089Swyllys 				return (-1);
5153089Swyllys 
5163089Swyllys 			if (lenlen != FOUR_BYTE_LEN) {
5173089Swyllys 				/*
5183089Swyllys 				 * We set aside FOUR_BYTE_LEN bytes for
5193089Swyllys 				 * the length field.  Move the data if
5203089Swyllys 				 * we don't actually need that much
5213089Swyllys 				 */
5223089Swyllys 				(void) memmove((*sos)->sos_first + taglen +
5233089Swyllys 				    lenlen, (*sos)->sos_first + taglen +
5243089Swyllys 				    FOUR_BYTE_LEN, len);
5253089Swyllys 			}
5263089Swyllys 		} else {
5273089Swyllys 			/* Fill FOUR_BYTE_LEN bytes for length field */
5283089Swyllys 			/* one byte of length length */
5293089Swyllys 			if (kmfber_write(ber, (char *)&ltag, 1, 1) != 1)
5303089Swyllys 				return (-1);
5313089Swyllys 
5323089Swyllys 			/* the length itself */
5333089Swyllys 			if (kmfber_write(ber,
534*5221Swyllys 			    (char *)&netlen + sizeof (ber_int_t)
535*5221Swyllys 			    - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) !=
536*5221Swyllys 			    FOUR_BYTE_LEN - 1)
5373089Swyllys 				return (-1);
5383089Swyllys 		}
5393089Swyllys 		/* The ber_ptr is at the set/seq start - move it to the end */
5403089Swyllys 		ber->ber_ptr += len;
5413089Swyllys 	} else {
5423089Swyllys 		ber_tag_t	ntag;
5433089Swyllys 
5443089Swyllys 		/* the tag */
5453089Swyllys 		taglen = kmfber_calc_taglen((*sos)->sos_tag);
5463089Swyllys 		ntag = htonl((*sos)->sos_tag);
5473089Swyllys 		(void) memmove((*sos)->sos_first, (char *)&ntag +
5483089Swyllys 		    sizeof (ber_int_t) - taglen, taglen);
5493089Swyllys 
5503089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
5513089Swyllys 			ltag = (lenlen == 1) ? (unsigned char)len :
552*5221Swyllys 			    (unsigned char) (0x80 + (lenlen - 1));
5533089Swyllys 		}
5543089Swyllys 
5553089Swyllys 		/* one byte of length length */
5563089Swyllys 		(void) memmove((*sos)->sos_first + 1, &ltag, 1);
5573089Swyllys 
5583089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
5593089Swyllys 			if (lenlen > 1) {
5603089Swyllys 				/* Write the length itself */
5613089Swyllys 				(void) memmove((*sos)->sos_first + 2,
5623089Swyllys 				    (char *)&netlen + sizeof (ber_uint_t) -
5633089Swyllys 				    (lenlen - 1),
5643089Swyllys 				    lenlen - 1);
5653089Swyllys 			}
5663089Swyllys 			if (lenlen != FOUR_BYTE_LEN) {
5673089Swyllys 				/*
5683089Swyllys 				 * We set aside FOUR_BYTE_LEN bytes for
5693089Swyllys 				 * the length field.  Move the data if
5703089Swyllys 				 * we don't actually need that much
5713089Swyllys 				 */
5723089Swyllys 				(void) memmove((*sos)->sos_first + taglen +
5733089Swyllys 				    lenlen, (*sos)->sos_first + taglen +
5743089Swyllys 				    FOUR_BYTE_LEN, len);
5753089Swyllys 			}
5763089Swyllys 		} else {
5773089Swyllys 			/* the length itself */
5783089Swyllys 			(void) memmove((*sos)->sos_first + taglen + 1,
5793089Swyllys 			    (char *) &netlen + sizeof (ber_int_t) -
5803089Swyllys 			    (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1);
5813089Swyllys 		}
5823089Swyllys 
5833089Swyllys 		next->sos_clen += (taglen + lenlen + len);
5843089Swyllys 		next->sos_ptr += (taglen + lenlen + len);
5853089Swyllys 	}
5863089Swyllys 
5873089Swyllys 	/* we're done with this seqorset, so free it up */
5883089Swyllys 	/* was this one from the local stack ? */
5893089Swyllys 	if (ber->ber_sos_stack_posn > SOS_STACK_SIZE) {
5903089Swyllys 		free((char *)(*sos));
5913089Swyllys 	}
5923089Swyllys 	ber->ber_sos_stack_posn--;
5933089Swyllys 	*sos = next;
5943089Swyllys 
5953089Swyllys 	return (taglen + lenlen + len);
5963089Swyllys }
5973089Swyllys 
5983089Swyllys /* VARARGS */
5993089Swyllys int
6003089Swyllys kmfber_printf(BerElement *ber, const char *fmt, ...)
6013089Swyllys {
6023089Swyllys 	va_list		ap;
6033089Swyllys 	char		*s, **ss;
6043089Swyllys 	struct berval	**bv, *oid;
6053089Swyllys 	int		rc, i, t;
6063089Swyllys 	ber_int_t	len;
6073089Swyllys 
6083089Swyllys 	va_start(ap, fmt);
6093089Swyllys 
6103089Swyllys #ifdef KMFBER_DEBUG
6113089Swyllys 	if (lber_debug & 64) {
6123089Swyllys 		char msg[80];
6133089Swyllys 		sprintf(msg, "kmfber_printf fmt (%s)\n", fmt);
6143089Swyllys 		ber_err_print(msg);
6153089Swyllys 	}
6163089Swyllys #endif
6173089Swyllys 
6183089Swyllys 	for (rc = 0; *fmt && rc != -1; fmt++) {
6193089Swyllys 		switch (*fmt) {
6203089Swyllys 		case 'b':	/* boolean */
6213089Swyllys 			i = va_arg(ap, int);
6223089Swyllys 			rc = kmfber_put_boolean(ber, i, ber->ber_tag);
6233089Swyllys 			break;
6243089Swyllys 
6253089Swyllys 		case 'i':	/* int */
6263089Swyllys 			i = va_arg(ap, int);
6273089Swyllys 			rc = ber_put_int(ber, (ber_int_t)i, ber->ber_tag);
6283089Swyllys 			break;
6293089Swyllys 
6303089Swyllys 		case 'D':	/* Object ID */
6313089Swyllys 			if ((oid = va_arg(ap, struct berval *)) == NULL)
6323089Swyllys 				break;
6333089Swyllys 			rc = ber_put_oid(ber, oid, ber->ber_tag);
6343089Swyllys 			break;
6353089Swyllys 		case 'I':	/* int */
6363089Swyllys 			s = va_arg(ap, char *);
6373089Swyllys 			len = va_arg(ap, ber_int_t);
6383089Swyllys 			rc = ber_put_big_int(ber, ber->ber_tag, s, len);
6393089Swyllys 			break;
6403089Swyllys 
6413089Swyllys 		case 'e':	/* enumeration */
6423089Swyllys 			i = va_arg(ap, int);
6433089Swyllys 			rc = kmfber_put_enum(ber, (ber_int_t)i, ber->ber_tag);
6443089Swyllys 			break;
6453089Swyllys 
6463089Swyllys 		case 'l':
6473089Swyllys 			t = va_arg(ap, int);
6483089Swyllys 			rc = kmfber_put_len(ber, t, 0);
6493089Swyllys 			break;
6503089Swyllys 		case 'n':	/* null */
6513089Swyllys 			rc = kmfber_put_null(ber, ber->ber_tag);
6523089Swyllys 			break;
6533089Swyllys 
6543089Swyllys 		case 'o':	/* octet string (non-null terminated) */
6553089Swyllys 			s = va_arg(ap, char *);
6563089Swyllys 			len = va_arg(ap, int);
6573089Swyllys 			rc = kmfber_put_ostring(ber, s, len, ber->ber_tag);
6583089Swyllys 			break;
6593089Swyllys 
6603089Swyllys 		case 's':	/* string */
6613089Swyllys 			s = va_arg(ap, char *);
6623089Swyllys 			rc = kmfber_put_string(ber, s, ber->ber_tag);
6633089Swyllys 			break;
6643089Swyllys 
6653089Swyllys 		case 'B':	/* bit string */
6663089Swyllys 			s = va_arg(ap, char *);
6673089Swyllys 			len = va_arg(ap, int);	/* in bits */
6683089Swyllys 			rc = kmfber_put_bitstring(ber, s, len, ber->ber_tag);
6693089Swyllys 			break;
6703089Swyllys 
6713089Swyllys 		case 't':	/* tag for the next element */
6723089Swyllys 			ber->ber_tag = va_arg(ap, ber_tag_t);
6733089Swyllys 			ber->ber_usertag = 1;
6743089Swyllys 			break;
6753089Swyllys 
6763089Swyllys 		case 'T': /* Write an explicit tag, but don't change current */
6773089Swyllys 			t = va_arg(ap, int);
6783089Swyllys 			rc = ber_put_tag(ber, t, 0);
6793089Swyllys 			break;
6803089Swyllys 
6813089Swyllys 		case 'v':	/* vector of strings */
6823089Swyllys 			if ((ss = va_arg(ap, char **)) == NULL)
6833089Swyllys 				break;
6843089Swyllys 			for (i = 0; ss[i] != NULL; i++) {
6853089Swyllys 				if ((rc = kmfber_put_string(ber, ss[i],
6863089Swyllys 				    ber->ber_tag)) == -1)
6873089Swyllys 					break;
6883089Swyllys 			}
6893089Swyllys 			break;
6903089Swyllys 
6913089Swyllys 		case 'V':	/* sequences of strings + lengths */
6923089Swyllys 			if ((bv = va_arg(ap, struct berval **)) == NULL)
6933089Swyllys 				break;
6943089Swyllys 			for (i = 0; bv[i] != NULL; i++) {
6953089Swyllys 				if ((rc = kmfber_put_ostring(ber, bv[i]->bv_val,
6963089Swyllys 				    bv[i]->bv_len, ber->ber_tag)) == -1)
6973089Swyllys 					break;
6983089Swyllys 			}
6993089Swyllys 			break;
7003089Swyllys 
7013089Swyllys 		case '{':	/* begin sequence */
7023089Swyllys 			rc = kmfber_start_seq(ber, ber->ber_tag);
7033089Swyllys 			break;
7043089Swyllys 
7053089Swyllys 		case '}':	/* end sequence */
7063089Swyllys 			rc = ber_put_seqorset(ber);
7073089Swyllys 			break;
7083089Swyllys 
7093089Swyllys 		case '[':	/* begin set */
7103089Swyllys 			rc = kmfber_start_set(ber, ber->ber_tag);
7113089Swyllys 			break;
7123089Swyllys 
7133089Swyllys 		case ']':	/* end set */
7143089Swyllys 			rc = ber_put_seqorset(ber);
7153089Swyllys 			break;
7163089Swyllys 
7173089Swyllys 		default: {
7183089Swyllys #ifdef KMFBER_DEBUG
7193089Swyllys 				char msg[80];
7203089Swyllys 				sprintf(msg, "unknown fmt %c\n", *fmt);
7213089Swyllys 				ber_err_print(msg);
7223089Swyllys #endif
7233089Swyllys 				rc = -1;
7243089Swyllys 				break;
7253089Swyllys 			}
7263089Swyllys 		}
7273089Swyllys 
7283089Swyllys 		if (ber->ber_usertag == 0)
7293089Swyllys 			ber->ber_tag = KMFBER_DEFAULT;
7303089Swyllys 		else
7313089Swyllys 			ber->ber_usertag = 0;
7323089Swyllys 	}
7333089Swyllys 
7343089Swyllys 	va_end(ap);
7353089Swyllys 
7363089Swyllys 	return (rc);
7373089Swyllys }
738