xref: /onnv-gate/usr/src/lib/libkmf/ber_der/common/encode.c (revision 3433:2971a4d3cf72)
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 /*
33*3433Shaimay  * 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,
823089Swyllys 		((char *) &ntag) + sizeof (ber_int_t) - taglen,
833089Swyllys 		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,
1263089Swyllys 			(char *)&netlen + sizeof (ber_int_t) - 1,
1273089Swyllys 			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,
1543089Swyllys 		(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,
2043089Swyllys 		(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 ||
2423089Swyllys 		kmfber_write(ber, oid->bv_val, oid->bv_len, 0) !=
2433089Swyllys 		(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;
2573089Swyllys 
2583089Swyllys 	if (tag == KMFBER_DEFAULT)
2593089Swyllys 		tag = BER_INTEGER;
2603089Swyllys 
2613089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
2623089Swyllys 		return (-1);
2633089Swyllys 
2643089Swyllys 	ilen = (ber_int_t)len;
2653089Swyllys 	if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 ||
2663089Swyllys 		kmfber_write(ber, data, len, 0) != (ber_int_t)len) {
2673089Swyllys 		rc = -1;
2683089Swyllys 	} else {
2693089Swyllys 		/* return length of tag + length + contents */
2703089Swyllys 		rc = taglen + lenlen + len;
2713089Swyllys 	}
2723089Swyllys 	return (rc);
2733089Swyllys }
2743089Swyllys 
2753089Swyllys static int
2763089Swyllys kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len,
2773089Swyllys 	ber_tag_t tag)
2783089Swyllys {
2793089Swyllys 	ber_int_t	taglen, lenlen, ilen, rc;
2803089Swyllys #ifdef STR_TRANSLATION
2813089Swyllys 	int	free_str;
2823089Swyllys #endif /* STR_TRANSLATION */
2833089Swyllys 
2843089Swyllys 	if (tag == KMFBER_DEFAULT)
2853089Swyllys 		tag = BER_OCTET_STRING;
2863089Swyllys 
2873089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
2883089Swyllys 		return (-1);
2893089Swyllys 
2903089Swyllys #ifdef STR_TRANSLATION
2913089Swyllys 	if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 &&
2923089Swyllys 	    ber->ber_encode_translate_proc != NULL) {
2933089Swyllys 		if ((*(ber->ber_encode_translate_proc))(&str, &len, 0)
2943089Swyllys 		    != 0) {
2953089Swyllys 			return (-1);
2963089Swyllys 		}
2973089Swyllys 		free_str = 1;
2983089Swyllys 	} else {
2993089Swyllys 		free_str = 0;
3003089Swyllys 	}
3013089Swyllys #endif /* STR_TRANSLATION */
3023089Swyllys 
3033089Swyllys 	/*
3043089Swyllys 	 *  Note:  below is a spot where we limit ber_write
3053089Swyllys 	 *	to signed long (instead of unsigned long)
3063089Swyllys 	 */
3073089Swyllys 	ilen = (ber_int_t)len;
3083089Swyllys 	if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 ||
3093089Swyllys 		kmfber_write(ber, str, len, 0) != (ber_int_t)len) {
3103089Swyllys 		rc = -1;
3113089Swyllys 	} else {
3123089Swyllys 		/* return length of tag + length + contents */
3133089Swyllys 		rc = taglen + lenlen + len;
3143089Swyllys 	}
3153089Swyllys 
3163089Swyllys #ifdef STR_TRANSLATION
3173089Swyllys 	if (free_str) {
3183089Swyllys 		free(str);
3193089Swyllys 	}
3203089Swyllys #endif /* STR_TRANSLATION */
3213089Swyllys 
3223089Swyllys 	return (rc);
3233089Swyllys }
3243089Swyllys 
3253089Swyllys static int
3263089Swyllys kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag)
3273089Swyllys {
3283089Swyllys 	return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag));
3293089Swyllys }
3303089Swyllys 
3313089Swyllys static int
3323089Swyllys kmfber_put_bitstring(BerElement *ber, char *str,
3333089Swyllys 	ber_len_t blen /* in bits */, ber_tag_t tag)
3343089Swyllys {
3353089Swyllys 	ber_int_t	taglen, lenlen, len;
3363089Swyllys 	unsigned char	unusedbits;
3373089Swyllys 
3383089Swyllys 	if (tag == KMFBER_DEFAULT)
3393089Swyllys 		tag = BER_BIT_STRING;
3403089Swyllys 
3413089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3423089Swyllys 		return (-1);
3433089Swyllys 
3443089Swyllys 	len = (blen + 7) / 8;
3453089Swyllys 	unusedbits = (unsigned char) (len * 8 - blen);
3463089Swyllys 	if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1)
3473089Swyllys 		return (-1);
3483089Swyllys 
3493089Swyllys 	if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1)
3503089Swyllys 		return (-1);
3513089Swyllys 
3523089Swyllys 	if (kmfber_write(ber, str, len, 0) != len)
3533089Swyllys 		return (-1);
3543089Swyllys 
3553089Swyllys 	/* return length of tag + length + unused bit count + contents */
3563089Swyllys 	return (taglen + 1 + lenlen + len);
3573089Swyllys }
3583089Swyllys 
3593089Swyllys static int
3603089Swyllys kmfber_put_null(BerElement *ber, ber_tag_t tag)
3613089Swyllys {
3623089Swyllys 	int	taglen;
3633089Swyllys 
3643089Swyllys 	if (tag == KMFBER_DEFAULT)
3653089Swyllys 		tag = BER_NULL;
3663089Swyllys 
3673089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3683089Swyllys 		return (-1);
3693089Swyllys 
3703089Swyllys 	if (kmfber_put_len(ber, 0, 0) != 1)
3713089Swyllys 		return (-1);
3723089Swyllys 
3733089Swyllys 	return (taglen + 1);
3743089Swyllys }
3753089Swyllys 
3763089Swyllys static int
3773089Swyllys kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag)
3783089Swyllys {
3793089Swyllys 	int		taglen;
3803089Swyllys 	unsigned char	trueval = 0xff;
3813089Swyllys 	unsigned char	falseval = 0x00;
3823089Swyllys 
3833089Swyllys 	if (tag == KMFBER_DEFAULT)
3843089Swyllys 		tag = BER_BOOLEAN;
3853089Swyllys 
3863089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3873089Swyllys 		return (-1);
3883089Swyllys 
3893089Swyllys 	if (kmfber_put_len(ber, 1, 0) != 1)
3903089Swyllys 		return (-1);
3913089Swyllys 
3923089Swyllys 	if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0)
3933089Swyllys 	    != 1)
3943089Swyllys 		return (-1);
3953089Swyllys 
3963089Swyllys 	return (taglen + 2);
3973089Swyllys }
3983089Swyllys 
3993089Swyllys #define	FOUR_BYTE_LEN	5
4003089Swyllys 
4013089Swyllys 
4023089Swyllys /*
4033089Swyllys  * The idea here is roughly this: we maintain a stack of these Seqorset
4043089Swyllys  * structures. This is pushed when we see the beginning of a new set or
4053089Swyllys  * sequence. It is popped when we see the end of a set or sequence.
4063089Swyllys  * Since we don't want to malloc and free these structures all the time,
4073089Swyllys  * we pre-allocate a small set of them within the ber element structure.
4083089Swyllys  * thus we need to spot when we've overflowed this stack and fall back to
4093089Swyllys  * malloc'ing instead.
4103089Swyllys  */
4113089Swyllys static int
4123089Swyllys ber_start_seqorset(BerElement *ber, ber_tag_t tag)
4133089Swyllys {
4143089Swyllys 	Seqorset	*new_sos;
4153089Swyllys 
4163089Swyllys 	/* can we fit into the local stack ? */
4173089Swyllys 	if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
4183089Swyllys 		/* yes */
4193089Swyllys 		new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
4203089Swyllys 	} else {
4213089Swyllys 		/* no */
4223089Swyllys 		if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset)))
4233089Swyllys 		    == NULLSEQORSET) {
4243089Swyllys 			return (-1);
4253089Swyllys 		}
4263089Swyllys 	}
4273089Swyllys 	ber->ber_sos_stack_posn++;
4283089Swyllys 
4293089Swyllys 	if (ber->ber_sos == NULLSEQORSET)
4303089Swyllys 		new_sos->sos_first = ber->ber_ptr;
4313089Swyllys 	else
4323089Swyllys 		new_sos->sos_first = ber->ber_sos->sos_ptr;
4333089Swyllys 
4343089Swyllys 	/* Set aside room for a 4 byte length field */
4353089Swyllys 	new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) +
4363089Swyllys 		FOUR_BYTE_LEN;
4373089Swyllys 	new_sos->sos_tag = tag;
4383089Swyllys 
4393089Swyllys 	new_sos->sos_next = ber->ber_sos;
4403089Swyllys 	new_sos->sos_clen = 0;
4413089Swyllys 
4423089Swyllys 	ber->ber_sos = new_sos;
4433089Swyllys 	if (ber->ber_sos->sos_ptr > ber->ber_end) {
4443089Swyllys 		(void) realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
4453089Swyllys 	}
4463089Swyllys 	return (0);
4473089Swyllys }
4483089Swyllys 
4493089Swyllys static int
4503089Swyllys kmfber_start_seq(BerElement *ber, ber_tag_t tag)
4513089Swyllys {
4523089Swyllys 	if (tag == KMFBER_DEFAULT)
4533089Swyllys 		tag = BER_CONSTRUCTED_SEQUENCE;
4543089Swyllys 
4553089Swyllys 	return (ber_start_seqorset(ber, tag));
4563089Swyllys }
4573089Swyllys 
4583089Swyllys static int
4593089Swyllys kmfber_start_set(BerElement *ber, ber_tag_t tag)
4603089Swyllys {
4613089Swyllys 	if (tag == KMFBER_DEFAULT)
4623089Swyllys 		tag = BER_CONSTRUCTED_SET;
4633089Swyllys 
4643089Swyllys 	return (ber_start_seqorset(ber, tag));
4653089Swyllys }
4663089Swyllys 
4673089Swyllys static int
4683089Swyllys ber_put_seqorset(BerElement *ber)
4693089Swyllys {
4703089Swyllys 	ber_int_t	netlen, len, taglen, lenlen;
4713089Swyllys 	unsigned char	ltag = 0x80 + FOUR_BYTE_LEN - 1;
4723089Swyllys 	Seqorset	*next;
4733089Swyllys 	Seqorset	**sos = &ber->ber_sos;
4743089Swyllys 
4753089Swyllys 	/*
4763089Swyllys 	 * If this is the toplevel sequence or set, we need to actually
4773089Swyllys 	 * write the stuff out.  Otherwise, it's already been put in
4783089Swyllys 	 * the appropriate buffer and will be written when the toplevel
4793089Swyllys 	 * one is written.  In this case all we need to do is update the
4803089Swyllys 	 * length and tag.
4813089Swyllys 	 */
4823089Swyllys 
4833089Swyllys 	len = (*sos)->sos_clen;
4843089Swyllys 	netlen = (ber_len_t)htonl(len);
4853089Swyllys 
4863089Swyllys 	if (ber->ber_options & KMFBER_OPT_USE_DER) {
4873089Swyllys 		lenlen = kmfber_calc_lenlen(len);
4883089Swyllys 	} else {
4893089Swyllys 		lenlen = FOUR_BYTE_LEN;
4903089Swyllys 	}
4913089Swyllys 
4923089Swyllys 	if ((next = (*sos)->sos_next) == NULLSEQORSET) {
4933089Swyllys 		/* write the tag */
4943089Swyllys 		if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1)
4953089Swyllys 			return (-1);
4963089Swyllys 
4973089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
4983089Swyllys 			/* Write the length in the minimum # of octets */
4993089Swyllys 			if (kmfber_put_len(ber, len, 1) == -1)
5003089Swyllys 				return (-1);
5013089Swyllys 
5023089Swyllys 			if (lenlen != FOUR_BYTE_LEN) {
5033089Swyllys 				/*
5043089Swyllys 				 * We set aside FOUR_BYTE_LEN bytes for
5053089Swyllys 				 * the length field.  Move the data if
5063089Swyllys 				 * we don't actually need that much
5073089Swyllys 				 */
5083089Swyllys 				(void) memmove((*sos)->sos_first + taglen +
5093089Swyllys 				    lenlen, (*sos)->sos_first + taglen +
5103089Swyllys 				    FOUR_BYTE_LEN, len);
5113089Swyllys 			}
5123089Swyllys 		} else {
5133089Swyllys 			/* Fill FOUR_BYTE_LEN bytes for length field */
5143089Swyllys 			/* one byte of length length */
5153089Swyllys 			if (kmfber_write(ber, (char *)&ltag, 1, 1) != 1)
5163089Swyllys 				return (-1);
5173089Swyllys 
5183089Swyllys 			/* the length itself */
5193089Swyllys 			if (kmfber_write(ber,
5203089Swyllys 				(char *)&netlen + sizeof (ber_int_t)
5213089Swyllys 				- (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) !=
5223089Swyllys 				FOUR_BYTE_LEN - 1)
5233089Swyllys 				return (-1);
5243089Swyllys 		}
5253089Swyllys 		/* The ber_ptr is at the set/seq start - move it to the end */
5263089Swyllys 		ber->ber_ptr += len;
5273089Swyllys 	} else {
5283089Swyllys 		ber_tag_t	ntag;
5293089Swyllys 
5303089Swyllys 		/* the tag */
5313089Swyllys 		taglen = kmfber_calc_taglen((*sos)->sos_tag);
5323089Swyllys 		ntag = htonl((*sos)->sos_tag);
5333089Swyllys 		(void) memmove((*sos)->sos_first, (char *)&ntag +
5343089Swyllys 		    sizeof (ber_int_t) - taglen, taglen);
5353089Swyllys 
5363089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
5373089Swyllys 			ltag = (lenlen == 1) ? (unsigned char)len :
5383089Swyllys 				(unsigned char) (0x80 + (lenlen - 1));
5393089Swyllys 		}
5403089Swyllys 
5413089Swyllys 		/* one byte of length length */
5423089Swyllys 		(void) memmove((*sos)->sos_first + 1, &ltag, 1);
5433089Swyllys 
5443089Swyllys 		if (ber->ber_options & KMFBER_OPT_USE_DER) {
5453089Swyllys 			if (lenlen > 1) {
5463089Swyllys 				/* Write the length itself */
5473089Swyllys 				(void) memmove((*sos)->sos_first + 2,
5483089Swyllys 				    (char *)&netlen + sizeof (ber_uint_t) -
5493089Swyllys 				    (lenlen - 1),
5503089Swyllys 				    lenlen - 1);
5513089Swyllys 			}
5523089Swyllys 			if (lenlen != FOUR_BYTE_LEN) {
5533089Swyllys 				/*
5543089Swyllys 				 * We set aside FOUR_BYTE_LEN bytes for
5553089Swyllys 				 * the length field.  Move the data if
5563089Swyllys 				 * we don't actually need that much
5573089Swyllys 				 */
5583089Swyllys 				(void) memmove((*sos)->sos_first + taglen +
5593089Swyllys 				    lenlen, (*sos)->sos_first + taglen +
5603089Swyllys 				    FOUR_BYTE_LEN, len);
5613089Swyllys 			}
5623089Swyllys 		} else {
5633089Swyllys 			/* the length itself */
5643089Swyllys 			(void) memmove((*sos)->sos_first + taglen + 1,
5653089Swyllys 			    (char *) &netlen + sizeof (ber_int_t) -
5663089Swyllys 			    (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1);
5673089Swyllys 		}
5683089Swyllys 
5693089Swyllys 		next->sos_clen += (taglen + lenlen + len);
5703089Swyllys 		next->sos_ptr += (taglen + lenlen + len);
5713089Swyllys 	}
5723089Swyllys 
5733089Swyllys 	/* we're done with this seqorset, so free it up */
5743089Swyllys 	/* was this one from the local stack ? */
5753089Swyllys 	if (ber->ber_sos_stack_posn > SOS_STACK_SIZE) {
5763089Swyllys 		free((char *)(*sos));
5773089Swyllys 	}
5783089Swyllys 	ber->ber_sos_stack_posn--;
5793089Swyllys 	*sos = next;
5803089Swyllys 
5813089Swyllys 	return (taglen + lenlen + len);
5823089Swyllys }
5833089Swyllys 
5843089Swyllys /* VARARGS */
5853089Swyllys int
5863089Swyllys kmfber_printf(BerElement *ber, const char *fmt, ...)
5873089Swyllys {
5883089Swyllys 	va_list		ap;
5893089Swyllys 	char		*s, **ss;
5903089Swyllys 	struct berval	**bv, *oid;
5913089Swyllys 	int		rc, i, t;
5923089Swyllys 	ber_int_t	len;
5933089Swyllys 
5943089Swyllys 	va_start(ap, fmt);
5953089Swyllys 
5963089Swyllys #ifdef KMFBER_DEBUG
5973089Swyllys 	if (lber_debug & 64) {
5983089Swyllys 		char msg[80];
5993089Swyllys 		sprintf(msg, "kmfber_printf fmt (%s)\n", fmt);
6003089Swyllys 		ber_err_print(msg);
6013089Swyllys 	}
6023089Swyllys #endif
6033089Swyllys 
6043089Swyllys 	for (rc = 0; *fmt && rc != -1; fmt++) {
6053089Swyllys 		switch (*fmt) {
6063089Swyllys 		case 'b':	/* boolean */
6073089Swyllys 			i = va_arg(ap, int);
6083089Swyllys 			rc = kmfber_put_boolean(ber, i, ber->ber_tag);
6093089Swyllys 			break;
6103089Swyllys 
6113089Swyllys 		case 'i':	/* int */
6123089Swyllys 			i = va_arg(ap, int);
6133089Swyllys 			rc = ber_put_int(ber, (ber_int_t)i, ber->ber_tag);
6143089Swyllys 			break;
6153089Swyllys 
6163089Swyllys 		case 'D':	/* Object ID */
6173089Swyllys 			if ((oid = va_arg(ap, struct berval *)) == NULL)
6183089Swyllys 				break;
6193089Swyllys 			rc = ber_put_oid(ber, oid, ber->ber_tag);
6203089Swyllys 			break;
6213089Swyllys 		case 'I':	/* int */
6223089Swyllys 			s = va_arg(ap, char *);
6233089Swyllys 			len = va_arg(ap, ber_int_t);
6243089Swyllys 			rc = ber_put_big_int(ber, ber->ber_tag, s, len);
6253089Swyllys 			break;
6263089Swyllys 
6273089Swyllys 		case 'e':	/* enumeration */
6283089Swyllys 			i = va_arg(ap, int);
6293089Swyllys 			rc = kmfber_put_enum(ber, (ber_int_t)i, ber->ber_tag);
6303089Swyllys 			break;
6313089Swyllys 
6323089Swyllys 		case 'l':
6333089Swyllys 			t = va_arg(ap, int);
6343089Swyllys 			rc = kmfber_put_len(ber, t, 0);
6353089Swyllys 			break;
6363089Swyllys 		case 'n':	/* null */
6373089Swyllys 			rc = kmfber_put_null(ber, ber->ber_tag);
6383089Swyllys 			break;
6393089Swyllys 
6403089Swyllys 		case 'o':	/* octet string (non-null terminated) */
6413089Swyllys 			s = va_arg(ap, char *);
6423089Swyllys 			len = va_arg(ap, int);
6433089Swyllys 			rc = kmfber_put_ostring(ber, s, len, ber->ber_tag);
6443089Swyllys 			break;
6453089Swyllys 
6463089Swyllys 		case 's':	/* string */
6473089Swyllys 			s = va_arg(ap, char *);
6483089Swyllys 			rc = kmfber_put_string(ber, s, ber->ber_tag);
6493089Swyllys 			break;
6503089Swyllys 
6513089Swyllys 		case 'B':	/* bit string */
6523089Swyllys 			s = va_arg(ap, char *);
6533089Swyllys 			len = va_arg(ap, int);	/* in bits */
6543089Swyllys 			rc = kmfber_put_bitstring(ber, s, len, ber->ber_tag);
6553089Swyllys 			break;
6563089Swyllys 
6573089Swyllys 		case 't':	/* tag for the next element */
6583089Swyllys 			ber->ber_tag = va_arg(ap, ber_tag_t);
6593089Swyllys 			ber->ber_usertag = 1;
6603089Swyllys 			break;
6613089Swyllys 
6623089Swyllys 		case 'T': /* Write an explicit tag, but don't change current */
6633089Swyllys 			t = va_arg(ap, int);
6643089Swyllys 			rc = ber_put_tag(ber, t, 0);
6653089Swyllys 			break;
6663089Swyllys 
6673089Swyllys 		case 'v':	/* vector of strings */
6683089Swyllys 			if ((ss = va_arg(ap, char **)) == NULL)
6693089Swyllys 				break;
6703089Swyllys 			for (i = 0; ss[i] != NULL; i++) {
6713089Swyllys 				if ((rc = kmfber_put_string(ber, ss[i],
6723089Swyllys 				    ber->ber_tag)) == -1)
6733089Swyllys 					break;
6743089Swyllys 			}
6753089Swyllys 			break;
6763089Swyllys 
6773089Swyllys 		case 'V':	/* sequences of strings + lengths */
6783089Swyllys 			if ((bv = va_arg(ap, struct berval **)) == NULL)
6793089Swyllys 				break;
6803089Swyllys 			for (i = 0; bv[i] != NULL; i++) {
6813089Swyllys 				if ((rc = kmfber_put_ostring(ber, bv[i]->bv_val,
6823089Swyllys 				    bv[i]->bv_len, ber->ber_tag)) == -1)
6833089Swyllys 					break;
6843089Swyllys 			}
6853089Swyllys 			break;
6863089Swyllys 
6873089Swyllys 		case '{':	/* begin sequence */
6883089Swyllys 			rc = kmfber_start_seq(ber, ber->ber_tag);
6893089Swyllys 			break;
6903089Swyllys 
6913089Swyllys 		case '}':	/* end sequence */
6923089Swyllys 			rc = ber_put_seqorset(ber);
6933089Swyllys 			break;
6943089Swyllys 
6953089Swyllys 		case '[':	/* begin set */
6963089Swyllys 			rc = kmfber_start_set(ber, ber->ber_tag);
6973089Swyllys 			break;
6983089Swyllys 
6993089Swyllys 		case ']':	/* end set */
7003089Swyllys 			rc = ber_put_seqorset(ber);
7013089Swyllys 			break;
7023089Swyllys 
7033089Swyllys 		default: {
7043089Swyllys #ifdef KMFBER_DEBUG
7053089Swyllys 				char msg[80];
7063089Swyllys 				sprintf(msg, "unknown fmt %c\n", *fmt);
7073089Swyllys 				ber_err_print(msg);
7083089Swyllys #endif
7093089Swyllys 				rc = -1;
7103089Swyllys 				break;
7113089Swyllys 			}
7123089Swyllys 		}
7133089Swyllys 
7143089Swyllys 		if (ber->ber_usertag == 0)
7153089Swyllys 			ber->ber_tag = KMFBER_DEFAULT;
7163089Swyllys 		else
7173089Swyllys 			ber->ber_usertag = 0;
7183089Swyllys 	}
7193089Swyllys 
7203089Swyllys 	va_end(ap);
7213089Swyllys 
7223089Swyllys 	return (rc);
7233089Swyllys }
724