xref: /onnv-gate/usr/src/lib/libkmf/ber_der/common/encode.c (revision 10818:89e8703947be)
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*10818Swyllys.ingersoll@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
343089Swyllys  * Use is subject to license terms.
353089Swyllys  */
363089Swyllys 
373089Swyllys #include <sys/types.h>
383089Swyllys #include <netinet/in.h>
393089Swyllys #include <inttypes.h>
403089Swyllys 
413089Swyllys #include <ber_der.h>
423089Swyllys #include "kmfber_int.h"
433089Swyllys 
443089Swyllys /* the following constants are used in kmfber_calc_lenlen */
453089Swyllys 
463089Swyllys #define	LENMASK1	0xFF
473089Swyllys #define	LENMASK2 	0xFFFF
483089Swyllys #define	LENMASK3	0xFFFFFF
493089Swyllys #define	LENMASK4	0xFFFFFFFF
503089Swyllys #define	_MASK		0x80
513089Swyllys 
523089Swyllys int
kmfber_calc_taglen(ber_tag_t tag)533089Swyllys kmfber_calc_taglen(ber_tag_t tag)
543089Swyllys {
553089Swyllys 	int		i;
563089Swyllys 	ber_int_t	mask;
573089Swyllys 
583089Swyllys 	/* find the first non-all-zero byte in the tag */
593089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
603089Swyllys 		mask = (LENMASK3 << (i * 8));
613089Swyllys 		/* not all zero */
623089Swyllys 		if (tag & mask)
633089Swyllys 			break;
643089Swyllys 	}
653089Swyllys 
663089Swyllys 	return (i + 1);
673089Swyllys }
683089Swyllys 
693089Swyllys static int
ber_put_tag(BerElement * ber,ber_tag_t tag,int nosos)703089Swyllys ber_put_tag(BerElement	*ber, ber_tag_t tag, int nosos)
713089Swyllys {
723089Swyllys 	ber_int_t	taglen;
733089Swyllys 	ber_tag_t	ntag;
743089Swyllys 
753089Swyllys 	taglen = kmfber_calc_taglen(tag);
763089Swyllys 
773089Swyllys 	ntag = htonl(tag);
783089Swyllys 
793089Swyllys 	return (kmfber_write(ber,
805221Swyllys 	    ((char *) &ntag) + sizeof (ber_int_t) - taglen,
815221Swyllys 	    taglen, nosos));
823089Swyllys }
833089Swyllys 
843089Swyllys int
kmfber_calc_lenlen(ber_int_t len)853089Swyllys kmfber_calc_lenlen(ber_int_t len)
863089Swyllys {
873089Swyllys 	/*
883089Swyllys 	 * short len if it's less than 128 - one byte giving the len,
893089Swyllys 	 * with bit 8 0.
903089Swyllys 	 */
913089Swyllys 
923089Swyllys 	if (len <= 0x7F)
933089Swyllys 		return (1);
943089Swyllys 
953089Swyllys 	/*
963089Swyllys 	 * long len otherwise - one byte with bit 8 set, giving the
973089Swyllys 	 * length of the length, followed by the length itself.
983089Swyllys 	 */
993089Swyllys 
1003089Swyllys 	if (len <= LENMASK1)
1013089Swyllys 		return (2);
1023089Swyllys 	if (len <= LENMASK2)
1033089Swyllys 		return (3);
1043089Swyllys 	if (len <= LENMASK3)
1053089Swyllys 		return (4);
1063089Swyllys 
1073089Swyllys 	return (5);
1083089Swyllys }
1093089Swyllys 
1103089Swyllys int
kmfber_put_len(BerElement * ber,ber_int_t len,int nosos)1113089Swyllys kmfber_put_len(BerElement *ber, ber_int_t len, int nosos)
1123089Swyllys {
1133089Swyllys 	int		i;
1143089Swyllys 	char		lenlen;
1153089Swyllys 	ber_int_t	mask, netlen;
1163089Swyllys 
1173089Swyllys 	/*
1183089Swyllys 	 * short len if it's less than 128 - one byte giving the len,
1193089Swyllys 	 * with bit 8 0.
1203089Swyllys 	 */
1213089Swyllys 	if (len <= 127) {
1223089Swyllys 		netlen = htonl(len);
1233089Swyllys 		return (kmfber_write(ber,
1245221Swyllys 		    (char *)&netlen + sizeof (ber_int_t) - 1,
1255221Swyllys 		    1, nosos));
1263089Swyllys 	}
1273089Swyllys 
1283089Swyllys 	/*
1293089Swyllys 	 * long len otherwise - one byte with bit 8 set, giving the
1303089Swyllys 	 * length of the length, followed by the length itself.
1313089Swyllys 	 */
1323089Swyllys 
1333089Swyllys 	/* find the first non-all-zero byte */
1343089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
1353089Swyllys 		mask = (LENMASK1 << (i * 8));
1363089Swyllys 		/* not all zero */
1373089Swyllys 		if (len & mask)
1383089Swyllys 			break;
1393089Swyllys 	}
1403089Swyllys 	lenlen = ++i;
1413089Swyllys 	if (lenlen > 4)
1423089Swyllys 		return (-1);
1433089Swyllys 	lenlen |= 0x80;
1443089Swyllys 
1453089Swyllys 	/* write the length of the length */
1463089Swyllys 	if (kmfber_write(ber, &lenlen, 1, nosos) != 1)
1473089Swyllys 		return (-1);
1483089Swyllys 
1493089Swyllys 	/* write the length itself */
1503089Swyllys 	netlen = htonl(len);
1513089Swyllys 	if (kmfber_write(ber,
1525221Swyllys 	    (char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i)
1533089Swyllys 		return (-1);
1543089Swyllys 
1553089Swyllys 	return (i + 1);
1563089Swyllys }
1573089Swyllys 
1583089Swyllys static int
ber_put_int_or_enum(BerElement * ber,ber_int_t num,ber_tag_t tag)1593089Swyllys ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag)
1603089Swyllys {
1613089Swyllys 	int		i, sign;
1623089Swyllys 	ber_int_t	len, lenlen, taglen, netnum, mask;
1633089Swyllys 
1643089Swyllys 	sign = (num < 0);
1653089Swyllys 
1663089Swyllys 	/*
1673089Swyllys 	 * high bit is set - look for first non-all-one byte
1683089Swyllys 	 * high bit is clear - look for first non-all-zero byte
1693089Swyllys 	 */
1703089Swyllys 	for (i = sizeof (ber_int_t) - 1; i > 0; i--) {
1713089Swyllys 		mask = (LENMASK1 << (i * 8));
1723089Swyllys 
1733089Swyllys 		if (sign) {
1743089Swyllys 			/* not all ones */
1753089Swyllys 			if ((num & mask) != mask)
1763089Swyllys 				break;
1773089Swyllys 		} else {
1783089Swyllys 			/* not all zero */
1793089Swyllys 			if (num & mask)
1803089Swyllys 				break;
1813089Swyllys 		}
1823089Swyllys 	}
1833089Swyllys 
1843089Swyllys 	/*
1853089Swyllys 	 * we now have the "leading byte".  if the high bit on this
1863089Swyllys 	 * byte matches the sign bit, we need to "back up" a byte.
1873089Swyllys 	 */
1883089Swyllys 	mask = (num & (_MASK << (i * 8)));
1893089Swyllys 	if ((mask && !sign) || (sign && !mask))
1903089Swyllys 		i++;
1913089Swyllys 
1923089Swyllys 	len = i + 1;
1933089Swyllys 
1943089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
1953089Swyllys 		return (-1);
1963089Swyllys 
1973089Swyllys 	if ((lenlen = kmfber_put_len(ber, len, 0)) == -1)
1983089Swyllys 		return (-1);
1993089Swyllys 	i++;
2003089Swyllys 	netnum = htonl(num);
2013089Swyllys 	if (kmfber_write(ber,
2025221Swyllys 	    (char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i)
2033089Swyllys 		/* length of tag + length + contents */
2043089Swyllys 		return (taglen + lenlen + i);
2053089Swyllys 
2063089Swyllys 	return (-1);
2073089Swyllys }
2083089Swyllys 
2093089Swyllys static int
kmfber_put_enum(BerElement * ber,ber_int_t num,ber_tag_t tag)2103089Swyllys kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag)
2113089Swyllys {
2123089Swyllys 	if (tag == KMFBER_DEFAULT)
2133089Swyllys 		tag = BER_ENUMERATED;
2143089Swyllys 
2153089Swyllys 	return (ber_put_int_or_enum(ber, num, tag));
2163089Swyllys }
2173089Swyllys 
2183089Swyllys int
ber_put_int(BerElement * ber,ber_int_t num,ber_tag_t tag)2193089Swyllys ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag)
2203089Swyllys {
2213089Swyllys 	if (tag == KMFBER_DEFAULT)
2223089Swyllys 		tag = BER_INTEGER;
2233089Swyllys 
2243089Swyllys 	return (ber_put_int_or_enum(ber, num, tag));
2253089Swyllys }
2263089Swyllys 
2273089Swyllys int
ber_put_oid(BerElement * ber,struct berval * oid,ber_tag_t tag)2283089Swyllys ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag)
2293089Swyllys {
2303089Swyllys 	ber_int_t taglen, lenlen, rc, len;
2313089Swyllys 
2323089Swyllys 	if (tag == KMFBER_DEFAULT)
2333089Swyllys 		tag = 0x06; 	/* TODO: Add new OID constant to header */
2343089Swyllys 
2353089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
2363089Swyllys 		return (-1);
2373089Swyllys 
2383089Swyllys 	len = (ber_int_t)oid->bv_len;
2393089Swyllys 	if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 ||
2405221Swyllys 	    kmfber_write(ber, oid->bv_val, oid->bv_len, 0) !=
2415221Swyllys 	    (ber_int_t)oid->bv_len) {
2423089Swyllys 		rc = -1;
2433089Swyllys 	} else {
2443089Swyllys 		/* return length of tag + length + contents */
2453089Swyllys 		rc = taglen + lenlen + oid->bv_len;
2463089Swyllys 	}
2473089Swyllys 	return (rc);
2483089Swyllys }
2493089Swyllys 
2503089Swyllys int
ber_put_big_int(BerElement * ber,ber_tag_t tag,char * data,ber_len_t len)2513089Swyllys ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data,
2523089Swyllys 	ber_len_t len)
2533089Swyllys {
2543089Swyllys 	ber_int_t taglen, lenlen, ilen, rc;
2555221Swyllys 	char zero = 0x00;
2563089Swyllys 
2573089Swyllys 	if (tag == KMFBER_DEFAULT)
2583089Swyllys 		tag = BER_INTEGER;
2593089Swyllys 
2603089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
2613089Swyllys 		return (-1);
2623089Swyllys 
2635221Swyllys 	/* Add a leading 0 if the high order bit is set */
2645221Swyllys 	if (data[0] & 0x80)
2655221Swyllys 		len++;
2665221Swyllys 
2673089Swyllys 	ilen = (ber_int_t)len;
2685221Swyllys 	if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1)
2695221Swyllys 		return (-1);
2705221Swyllys 
2715221Swyllys 	/* add leading 0 if hi bit set */
2725221Swyllys 	if ((data[0] & 0x80) && kmfber_write(ber, &zero, 1, 0) != 1)
2735221Swyllys 		return (-1);
2745221Swyllys 
2755221Swyllys 	/* Adjust the length of the write if hi-order bit is set */
2765221Swyllys 	if (data[0] & 0x80)
2775221Swyllys 		ilen = len - 1;
2785221Swyllys 	if (kmfber_write(ber, data, ilen, 0) != (ber_int_t)ilen) {
2795221Swyllys 		return (-1);
2803089Swyllys 	} else {
2813089Swyllys 		/* return length of tag + length + contents */
2823089Swyllys 		rc = taglen + lenlen + len;
2833089Swyllys 	}
2843089Swyllys 	return (rc);
2853089Swyllys }
2863089Swyllys 
2873089Swyllys static int
kmfber_put_ostring(BerElement * ber,char * str,ber_len_t len,ber_tag_t tag)2883089Swyllys kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len,
2893089Swyllys 	ber_tag_t tag)
2903089Swyllys {
2913089Swyllys 	ber_int_t	taglen, lenlen, ilen, rc;
2923089Swyllys #ifdef STR_TRANSLATION
2933089Swyllys 	int	free_str;
2943089Swyllys #endif /* STR_TRANSLATION */
2953089Swyllys 
2963089Swyllys 	if (tag == KMFBER_DEFAULT)
2973089Swyllys 		tag = BER_OCTET_STRING;
2983089Swyllys 
2993089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3003089Swyllys 		return (-1);
3013089Swyllys 
3023089Swyllys #ifdef STR_TRANSLATION
3033089Swyllys 	if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 &&
3043089Swyllys 	    ber->ber_encode_translate_proc != NULL) {
3053089Swyllys 		if ((*(ber->ber_encode_translate_proc))(&str, &len, 0)
3063089Swyllys 		    != 0) {
3073089Swyllys 			return (-1);
3083089Swyllys 		}
3093089Swyllys 		free_str = 1;
3103089Swyllys 	} else {
3113089Swyllys 		free_str = 0;
3123089Swyllys 	}
3133089Swyllys #endif /* STR_TRANSLATION */
3143089Swyllys 
3153089Swyllys 	/*
3163089Swyllys 	 *  Note:  below is a spot where we limit ber_write
3173089Swyllys 	 *	to signed long (instead of unsigned long)
3183089Swyllys 	 */
3193089Swyllys 	ilen = (ber_int_t)len;
3203089Swyllys 	if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 ||
3215221Swyllys 	    kmfber_write(ber, str, len, 0) != (ber_int_t)len) {
3223089Swyllys 		rc = -1;
3233089Swyllys 	} else {
3243089Swyllys 		/* return length of tag + length + contents */
3253089Swyllys 		rc = taglen + lenlen + len;
3263089Swyllys 	}
3273089Swyllys 
3283089Swyllys #ifdef STR_TRANSLATION
3293089Swyllys 	if (free_str) {
3303089Swyllys 		free(str);
3313089Swyllys 	}
3323089Swyllys #endif /* STR_TRANSLATION */
3333089Swyllys 
3343089Swyllys 	return (rc);
3353089Swyllys }
3363089Swyllys 
3373089Swyllys static int
kmfber_put_string(BerElement * ber,char * str,ber_tag_t tag)3383089Swyllys kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag)
3393089Swyllys {
3403089Swyllys 	return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag));
3413089Swyllys }
3423089Swyllys 
3433089Swyllys static int
kmfber_put_bitstring(BerElement * ber,char * str,ber_len_t blen,ber_tag_t tag)3443089Swyllys kmfber_put_bitstring(BerElement *ber, char *str,
3453089Swyllys 	ber_len_t blen /* in bits */, ber_tag_t tag)
3463089Swyllys {
3473089Swyllys 	ber_int_t	taglen, lenlen, len;
3483089Swyllys 	unsigned char	unusedbits;
3493089Swyllys 
3503089Swyllys 	if (tag == KMFBER_DEFAULT)
3513089Swyllys 		tag = BER_BIT_STRING;
3523089Swyllys 
3533089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3543089Swyllys 		return (-1);
3553089Swyllys 
3563089Swyllys 	len = (blen + 7) / 8;
3573089Swyllys 	unusedbits = (unsigned char) (len * 8 - blen);
3583089Swyllys 	if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1)
3593089Swyllys 		return (-1);
3603089Swyllys 
3613089Swyllys 	if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1)
3623089Swyllys 		return (-1);
3633089Swyllys 
3643089Swyllys 	if (kmfber_write(ber, str, len, 0) != len)
3653089Swyllys 		return (-1);
3663089Swyllys 
3673089Swyllys 	/* return length of tag + length + unused bit count + contents */
3683089Swyllys 	return (taglen + 1 + lenlen + len);
3693089Swyllys }
3703089Swyllys 
3713089Swyllys static int
kmfber_put_null(BerElement * ber,ber_tag_t tag)3723089Swyllys kmfber_put_null(BerElement *ber, ber_tag_t tag)
3733089Swyllys {
3743089Swyllys 	int	taglen;
3753089Swyllys 
3763089Swyllys 	if (tag == KMFBER_DEFAULT)
3773089Swyllys 		tag = BER_NULL;
3783089Swyllys 
3793089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3803089Swyllys 		return (-1);
3813089Swyllys 
3823089Swyllys 	if (kmfber_put_len(ber, 0, 0) != 1)
3833089Swyllys 		return (-1);
3843089Swyllys 
3853089Swyllys 	return (taglen + 1);
3863089Swyllys }
3873089Swyllys 
3883089Swyllys static int
kmfber_put_boolean(BerElement * ber,int boolval,ber_tag_t tag)3893089Swyllys kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag)
3903089Swyllys {
3913089Swyllys 	int		taglen;
3923089Swyllys 	unsigned char	trueval = 0xff;
3933089Swyllys 	unsigned char	falseval = 0x00;
3943089Swyllys 
3953089Swyllys 	if (tag == KMFBER_DEFAULT)
3963089Swyllys 		tag = BER_BOOLEAN;
3973089Swyllys 
3983089Swyllys 	if ((taglen = ber_put_tag(ber, tag, 0)) == -1)
3993089Swyllys 		return (-1);
4003089Swyllys 
4013089Swyllys 	if (kmfber_put_len(ber, 1, 0) != 1)
4023089Swyllys 		return (-1);
4033089Swyllys 
4043089Swyllys 	if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0)
4053089Swyllys 	    != 1)
4063089Swyllys 		return (-1);
4073089Swyllys 
4083089Swyllys 	return (taglen + 2);
4093089Swyllys }
4103089Swyllys 
4113089Swyllys #define	FOUR_BYTE_LEN	5
4123089Swyllys 
4133089Swyllys 
4143089Swyllys /*
4153089Swyllys  * The idea here is roughly this: we maintain a stack of these Seqorset
4163089Swyllys  * structures. This is pushed when we see the beginning of a new set or
4173089Swyllys  * sequence. It is popped when we see the end of a set or sequence.
4183089Swyllys  * Since we don't want to malloc and free these structures all the time,
4193089Swyllys  * we pre-allocate a small set of them within the ber element structure.
4203089Swyllys  * thus we need to spot when we've overflowed this stack and fall back to
4213089Swyllys  * malloc'ing instead.
4223089Swyllys  */
4233089Swyllys static int
ber_start_seqorset(BerElement * ber,ber_tag_t tag)4243089Swyllys ber_start_seqorset(BerElement *ber, ber_tag_t tag)
4253089Swyllys {
4263089Swyllys 	Seqorset	*new_sos;
4273089Swyllys 
4283089Swyllys 	/* can we fit into the local stack ? */
4293089Swyllys 	if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) {
4303089Swyllys 		/* yes */
4313089Swyllys 		new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn];
4323089Swyllys 	} else {
4333089Swyllys 		/* no */
4343089Swyllys 		if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset)))
4353089Swyllys 		    == NULLSEQORSET) {
4363089Swyllys 			return (-1);
4373089Swyllys 		}
4383089Swyllys 	}
4393089Swyllys 	ber->ber_sos_stack_posn++;
4403089Swyllys 
4413089Swyllys 	if (ber->ber_sos == NULLSEQORSET)
4423089Swyllys 		new_sos->sos_first = ber->ber_ptr;
4433089Swyllys 	else
4443089Swyllys 		new_sos->sos_first = ber->ber_sos->sos_ptr;
4453089Swyllys 
4463089Swyllys 	/* Set aside room for a 4 byte length field */
4473089Swyllys 	new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) +
4485221Swyllys 	    FOUR_BYTE_LEN;
4493089Swyllys 	new_sos->sos_tag = tag;
4503089Swyllys 
4513089Swyllys 	new_sos->sos_next = ber->ber_sos;
4523089Swyllys 	new_sos->sos_clen = 0;
4533089Swyllys 
4543089Swyllys 	ber->ber_sos = new_sos;
4553089Swyllys 	if (ber->ber_sos->sos_ptr > ber->ber_end) {
456*10818Swyllys.ingersoll@sun.com 		if (kmfber_realloc(ber, ber->ber_sos->sos_ptr -
457*10818Swyllys.ingersoll@sun.com 		    ber->ber_end) != 0)
458*10818Swyllys.ingersoll@sun.com 			return (-1);
4593089Swyllys 	}
4603089Swyllys 	return (0);
4613089Swyllys }
4623089Swyllys 
4633089Swyllys static int
kmfber_start_seq(BerElement * ber,ber_tag_t tag)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
kmfber_start_set(BerElement * ber,ber_tag_t tag)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
ber_put_seqorset(BerElement * ber)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,
5345221Swyllys 			    (char *)&netlen + sizeof (ber_int_t)
5355221Swyllys 			    - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) !=
5365221Swyllys 			    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 :
5525221Swyllys 			    (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
kmfber_printf(BerElement * ber,const char * fmt,...)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