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 *)<ag, 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, <ag, 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