199ebb4caSwyllys /* 299ebb4caSwyllys * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 399ebb4caSwyllys * 499ebb4caSwyllys * The contents of this file are subject to the Netscape Public License 599ebb4caSwyllys * Version 1.0 (the "NPL"); you may not use this file except in 699ebb4caSwyllys * compliance with the NPL. You may obtain a copy of the NPL at 799ebb4caSwyllys * http://www.mozilla.org/NPL/ 899ebb4caSwyllys * 999ebb4caSwyllys * Software distributed under the NPL is distributed on an "AS IS" basis, 1099ebb4caSwyllys * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 1199ebb4caSwyllys * for the specific language governing rights and limitations under the 1299ebb4caSwyllys * NPL. 1399ebb4caSwyllys * 1499ebb4caSwyllys * The Initial Developer of this code under the NPL is Netscape 1599ebb4caSwyllys * Communications Corporation. Portions created by Netscape are 1699ebb4caSwyllys * Copyright (C) 1998 Netscape Communications Corporation. All Rights 1799ebb4caSwyllys * Reserved. 1899ebb4caSwyllys */ 1999ebb4caSwyllys 2099ebb4caSwyllys /* 2199ebb4caSwyllys * Copyright (c) 1990 Regents of the University of Michigan. 2299ebb4caSwyllys * All rights reserved. 2399ebb4caSwyllys * 2499ebb4caSwyllys * Redistribution and use in source and binary forms are permitted 2599ebb4caSwyllys * provided that this notice is preserved and that due credit is given 2699ebb4caSwyllys * to the University of Michigan at Ann Arbor. The name of the University 2799ebb4caSwyllys * may not be used to endorse or promote products derived from this 2899ebb4caSwyllys * software without specific prior written permission. This software 2999ebb4caSwyllys * is provided ``as is'' without express or implied warranty. 3099ebb4caSwyllys */ 3199ebb4caSwyllys 3299ebb4caSwyllys /* 33*56664548SWyllys Ingersoll * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3499ebb4caSwyllys * Use is subject to license terms. 3599ebb4caSwyllys */ 3699ebb4caSwyllys 3799ebb4caSwyllys #include <sys/types.h> 3899ebb4caSwyllys #include <netinet/in.h> 3999ebb4caSwyllys #include <inttypes.h> 4099ebb4caSwyllys 4199ebb4caSwyllys #include <ber_der.h> 4299ebb4caSwyllys #include "kmfber_int.h" 4399ebb4caSwyllys 4499ebb4caSwyllys /* the following constants are used in kmfber_calc_lenlen */ 4599ebb4caSwyllys 4699ebb4caSwyllys #define LENMASK1 0xFF 4799ebb4caSwyllys #define LENMASK2 0xFFFF 4899ebb4caSwyllys #define LENMASK3 0xFFFFFF 4999ebb4caSwyllys #define LENMASK4 0xFFFFFFFF 5099ebb4caSwyllys #define _MASK 0x80 5199ebb4caSwyllys 5299ebb4caSwyllys int 5399ebb4caSwyllys kmfber_calc_taglen(ber_tag_t tag) 5499ebb4caSwyllys { 5599ebb4caSwyllys int i; 5699ebb4caSwyllys ber_int_t mask; 5799ebb4caSwyllys 5899ebb4caSwyllys /* find the first non-all-zero byte in the tag */ 5999ebb4caSwyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 6099ebb4caSwyllys mask = (LENMASK3 << (i * 8)); 6199ebb4caSwyllys /* not all zero */ 6299ebb4caSwyllys if (tag & mask) 6399ebb4caSwyllys break; 6499ebb4caSwyllys } 6599ebb4caSwyllys 6699ebb4caSwyllys return (i + 1); 6799ebb4caSwyllys } 6899ebb4caSwyllys 6999ebb4caSwyllys static int 7099ebb4caSwyllys ber_put_tag(BerElement *ber, ber_tag_t tag, int nosos) 7199ebb4caSwyllys { 7299ebb4caSwyllys ber_int_t taglen; 7399ebb4caSwyllys ber_tag_t ntag; 7499ebb4caSwyllys 7599ebb4caSwyllys taglen = kmfber_calc_taglen(tag); 7699ebb4caSwyllys 7799ebb4caSwyllys ntag = htonl(tag); 7899ebb4caSwyllys 7999ebb4caSwyllys return (kmfber_write(ber, 8099ebb4caSwyllys ((char *) &ntag) + sizeof (ber_int_t) - taglen, 8199ebb4caSwyllys taglen, nosos)); 8299ebb4caSwyllys } 8399ebb4caSwyllys 8499ebb4caSwyllys int 8599ebb4caSwyllys kmfber_calc_lenlen(ber_int_t len) 8699ebb4caSwyllys { 8799ebb4caSwyllys /* 8899ebb4caSwyllys * short len if it's less than 128 - one byte giving the len, 8999ebb4caSwyllys * with bit 8 0. 9099ebb4caSwyllys */ 9199ebb4caSwyllys 9299ebb4caSwyllys if (len <= 0x7F) 9399ebb4caSwyllys return (1); 9499ebb4caSwyllys 9599ebb4caSwyllys /* 9699ebb4caSwyllys * long len otherwise - one byte with bit 8 set, giving the 9799ebb4caSwyllys * length of the length, followed by the length itself. 9899ebb4caSwyllys */ 9999ebb4caSwyllys 10099ebb4caSwyllys if (len <= LENMASK1) 10199ebb4caSwyllys return (2); 10299ebb4caSwyllys if (len <= LENMASK2) 10399ebb4caSwyllys return (3); 10499ebb4caSwyllys if (len <= LENMASK3) 10599ebb4caSwyllys return (4); 10699ebb4caSwyllys 10799ebb4caSwyllys return (5); 10899ebb4caSwyllys } 10999ebb4caSwyllys 11099ebb4caSwyllys int 11199ebb4caSwyllys kmfber_put_len(BerElement *ber, ber_int_t len, int nosos) 11299ebb4caSwyllys { 11399ebb4caSwyllys int i; 11499ebb4caSwyllys char lenlen; 11599ebb4caSwyllys ber_int_t mask, netlen; 11699ebb4caSwyllys 11799ebb4caSwyllys /* 11899ebb4caSwyllys * short len if it's less than 128 - one byte giving the len, 11999ebb4caSwyllys * with bit 8 0. 12099ebb4caSwyllys */ 12199ebb4caSwyllys if (len <= 127) { 12299ebb4caSwyllys netlen = htonl(len); 12399ebb4caSwyllys return (kmfber_write(ber, 12499ebb4caSwyllys (char *)&netlen + sizeof (ber_int_t) - 1, 12599ebb4caSwyllys 1, nosos)); 12699ebb4caSwyllys } 12799ebb4caSwyllys 12899ebb4caSwyllys /* 12999ebb4caSwyllys * long len otherwise - one byte with bit 8 set, giving the 13099ebb4caSwyllys * length of the length, followed by the length itself. 13199ebb4caSwyllys */ 13299ebb4caSwyllys 13399ebb4caSwyllys /* find the first non-all-zero byte */ 13499ebb4caSwyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 13599ebb4caSwyllys mask = (LENMASK1 << (i * 8)); 13699ebb4caSwyllys /* not all zero */ 13799ebb4caSwyllys if (len & mask) 13899ebb4caSwyllys break; 13999ebb4caSwyllys } 14099ebb4caSwyllys lenlen = ++i; 14199ebb4caSwyllys if (lenlen > 4) 14299ebb4caSwyllys return (-1); 14399ebb4caSwyllys lenlen |= 0x80; 14499ebb4caSwyllys 14599ebb4caSwyllys /* write the length of the length */ 14699ebb4caSwyllys if (kmfber_write(ber, &lenlen, 1, nosos) != 1) 14799ebb4caSwyllys return (-1); 14899ebb4caSwyllys 14999ebb4caSwyllys /* write the length itself */ 15099ebb4caSwyllys netlen = htonl(len); 15199ebb4caSwyllys if (kmfber_write(ber, 15299ebb4caSwyllys (char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i) 15399ebb4caSwyllys return (-1); 15499ebb4caSwyllys 15599ebb4caSwyllys return (i + 1); 15699ebb4caSwyllys } 15799ebb4caSwyllys 15899ebb4caSwyllys static int 15999ebb4caSwyllys ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) 16099ebb4caSwyllys { 16199ebb4caSwyllys int i, sign; 16299ebb4caSwyllys ber_int_t len, lenlen, taglen, netnum, mask; 16399ebb4caSwyllys 16499ebb4caSwyllys sign = (num < 0); 16599ebb4caSwyllys 16699ebb4caSwyllys /* 16799ebb4caSwyllys * high bit is set - look for first non-all-one byte 16899ebb4caSwyllys * high bit is clear - look for first non-all-zero byte 16999ebb4caSwyllys */ 17099ebb4caSwyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 17199ebb4caSwyllys mask = (LENMASK1 << (i * 8)); 17299ebb4caSwyllys 17399ebb4caSwyllys if (sign) { 17499ebb4caSwyllys /* not all ones */ 17599ebb4caSwyllys if ((num & mask) != mask) 17699ebb4caSwyllys break; 17799ebb4caSwyllys } else { 17899ebb4caSwyllys /* not all zero */ 17999ebb4caSwyllys if (num & mask) 18099ebb4caSwyllys break; 18199ebb4caSwyllys } 18299ebb4caSwyllys } 18399ebb4caSwyllys 18499ebb4caSwyllys /* 18599ebb4caSwyllys * we now have the "leading byte". if the high bit on this 18699ebb4caSwyllys * byte matches the sign bit, we need to "back up" a byte. 18799ebb4caSwyllys */ 18899ebb4caSwyllys mask = (num & (_MASK << (i * 8))); 18999ebb4caSwyllys if ((mask && !sign) || (sign && !mask)) 19099ebb4caSwyllys i++; 19199ebb4caSwyllys 19299ebb4caSwyllys len = i + 1; 19399ebb4caSwyllys 19499ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 19599ebb4caSwyllys return (-1); 19699ebb4caSwyllys 19799ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, len, 0)) == -1) 19899ebb4caSwyllys return (-1); 19999ebb4caSwyllys i++; 20099ebb4caSwyllys netnum = htonl(num); 20199ebb4caSwyllys if (kmfber_write(ber, 20299ebb4caSwyllys (char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i) 20399ebb4caSwyllys /* length of tag + length + contents */ 20499ebb4caSwyllys return (taglen + lenlen + i); 20599ebb4caSwyllys 20699ebb4caSwyllys return (-1); 20799ebb4caSwyllys } 20899ebb4caSwyllys 20999ebb4caSwyllys static int 21099ebb4caSwyllys kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) 21199ebb4caSwyllys { 21299ebb4caSwyllys if (tag == KMFBER_DEFAULT) 21399ebb4caSwyllys tag = BER_ENUMERATED; 21499ebb4caSwyllys 21599ebb4caSwyllys return (ber_put_int_or_enum(ber, num, tag)); 21699ebb4caSwyllys } 21799ebb4caSwyllys 21899ebb4caSwyllys int 21999ebb4caSwyllys ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag) 22099ebb4caSwyllys { 22199ebb4caSwyllys if (tag == KMFBER_DEFAULT) 22299ebb4caSwyllys tag = BER_INTEGER; 22399ebb4caSwyllys 22499ebb4caSwyllys return (ber_put_int_or_enum(ber, num, tag)); 22599ebb4caSwyllys } 22699ebb4caSwyllys 22799ebb4caSwyllys int 22899ebb4caSwyllys ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag) 22999ebb4caSwyllys { 23099ebb4caSwyllys ber_int_t taglen, lenlen, rc, len; 23199ebb4caSwyllys 23299ebb4caSwyllys if (tag == KMFBER_DEFAULT) 23399ebb4caSwyllys tag = 0x06; /* TODO: Add new OID constant to header */ 23499ebb4caSwyllys 23599ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 23699ebb4caSwyllys return (-1); 23799ebb4caSwyllys 23899ebb4caSwyllys len = (ber_int_t)oid->bv_len; 23999ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 || 24099ebb4caSwyllys kmfber_write(ber, oid->bv_val, oid->bv_len, 0) != 24199ebb4caSwyllys (ber_int_t)oid->bv_len) { 24299ebb4caSwyllys rc = -1; 24399ebb4caSwyllys } else { 24499ebb4caSwyllys /* return length of tag + length + contents */ 24599ebb4caSwyllys rc = taglen + lenlen + oid->bv_len; 24699ebb4caSwyllys } 24799ebb4caSwyllys return (rc); 24899ebb4caSwyllys } 24999ebb4caSwyllys 25099ebb4caSwyllys int 25199ebb4caSwyllys ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data, 25299ebb4caSwyllys ber_len_t len) 25399ebb4caSwyllys { 25499ebb4caSwyllys ber_int_t taglen, lenlen, ilen, rc; 2552cbed729Swyllys char zero = 0x00; 25699ebb4caSwyllys 25799ebb4caSwyllys if (tag == KMFBER_DEFAULT) 25899ebb4caSwyllys tag = BER_INTEGER; 25999ebb4caSwyllys 26099ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 26199ebb4caSwyllys return (-1); 26299ebb4caSwyllys 2632cbed729Swyllys /* Add a leading 0 if the high order bit is set */ 2642cbed729Swyllys if (data[0] & 0x80) 2652cbed729Swyllys len++; 2662cbed729Swyllys 26799ebb4caSwyllys ilen = (ber_int_t)len; 2682cbed729Swyllys if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1) 2692cbed729Swyllys return (-1); 2702cbed729Swyllys 2712cbed729Swyllys /* add leading 0 if hi bit set */ 2722cbed729Swyllys if ((data[0] & 0x80) && kmfber_write(ber, &zero, 1, 0) != 1) 2732cbed729Swyllys return (-1); 2742cbed729Swyllys 2752cbed729Swyllys /* Adjust the length of the write if hi-order bit is set */ 2762cbed729Swyllys if (data[0] & 0x80) 2772cbed729Swyllys ilen = len - 1; 2782cbed729Swyllys if (kmfber_write(ber, data, ilen, 0) != (ber_int_t)ilen) { 2792cbed729Swyllys return (-1); 28099ebb4caSwyllys } else { 28199ebb4caSwyllys /* return length of tag + length + contents */ 28299ebb4caSwyllys rc = taglen + lenlen + len; 28399ebb4caSwyllys } 28499ebb4caSwyllys return (rc); 28599ebb4caSwyllys } 28699ebb4caSwyllys 28799ebb4caSwyllys static int 28899ebb4caSwyllys kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len, 28999ebb4caSwyllys ber_tag_t tag) 29099ebb4caSwyllys { 29199ebb4caSwyllys ber_int_t taglen, lenlen, ilen, rc; 29299ebb4caSwyllys #ifdef STR_TRANSLATION 29399ebb4caSwyllys int free_str; 29499ebb4caSwyllys #endif /* STR_TRANSLATION */ 29599ebb4caSwyllys 29699ebb4caSwyllys if (tag == KMFBER_DEFAULT) 29799ebb4caSwyllys tag = BER_OCTET_STRING; 29899ebb4caSwyllys 29999ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 30099ebb4caSwyllys return (-1); 30199ebb4caSwyllys 30299ebb4caSwyllys #ifdef STR_TRANSLATION 30399ebb4caSwyllys if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 && 30499ebb4caSwyllys ber->ber_encode_translate_proc != NULL) { 30599ebb4caSwyllys if ((*(ber->ber_encode_translate_proc))(&str, &len, 0) 30699ebb4caSwyllys != 0) { 30799ebb4caSwyllys return (-1); 30899ebb4caSwyllys } 30999ebb4caSwyllys free_str = 1; 31099ebb4caSwyllys } else { 31199ebb4caSwyllys free_str = 0; 31299ebb4caSwyllys } 31399ebb4caSwyllys #endif /* STR_TRANSLATION */ 31499ebb4caSwyllys 31599ebb4caSwyllys /* 31699ebb4caSwyllys * Note: below is a spot where we limit ber_write 31799ebb4caSwyllys * to signed long (instead of unsigned long) 31899ebb4caSwyllys */ 31999ebb4caSwyllys ilen = (ber_int_t)len; 32099ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 || 32199ebb4caSwyllys kmfber_write(ber, str, len, 0) != (ber_int_t)len) { 32299ebb4caSwyllys rc = -1; 32399ebb4caSwyllys } else { 32499ebb4caSwyllys /* return length of tag + length + contents */ 32599ebb4caSwyllys rc = taglen + lenlen + len; 32699ebb4caSwyllys } 32799ebb4caSwyllys 32899ebb4caSwyllys #ifdef STR_TRANSLATION 32999ebb4caSwyllys if (free_str) { 33099ebb4caSwyllys free(str); 33199ebb4caSwyllys } 33299ebb4caSwyllys #endif /* STR_TRANSLATION */ 33399ebb4caSwyllys 33499ebb4caSwyllys return (rc); 33599ebb4caSwyllys } 33699ebb4caSwyllys 33799ebb4caSwyllys static int 33899ebb4caSwyllys kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag) 33999ebb4caSwyllys { 34099ebb4caSwyllys return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag)); 34199ebb4caSwyllys } 34299ebb4caSwyllys 34399ebb4caSwyllys static int 34499ebb4caSwyllys kmfber_put_bitstring(BerElement *ber, char *str, 34599ebb4caSwyllys ber_len_t blen /* in bits */, ber_tag_t tag) 34699ebb4caSwyllys { 34799ebb4caSwyllys ber_int_t taglen, lenlen, len; 34899ebb4caSwyllys unsigned char unusedbits; 34999ebb4caSwyllys 35099ebb4caSwyllys if (tag == KMFBER_DEFAULT) 35199ebb4caSwyllys tag = BER_BIT_STRING; 35299ebb4caSwyllys 35399ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 35499ebb4caSwyllys return (-1); 35599ebb4caSwyllys 35699ebb4caSwyllys len = (blen + 7) / 8; 35799ebb4caSwyllys unusedbits = (unsigned char) (len * 8 - blen); 35899ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1) 35999ebb4caSwyllys return (-1); 36099ebb4caSwyllys 36199ebb4caSwyllys if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1) 36299ebb4caSwyllys return (-1); 36399ebb4caSwyllys 36499ebb4caSwyllys if (kmfber_write(ber, str, len, 0) != len) 36599ebb4caSwyllys return (-1); 36699ebb4caSwyllys 36799ebb4caSwyllys /* return length of tag + length + unused bit count + contents */ 36899ebb4caSwyllys return (taglen + 1 + lenlen + len); 36999ebb4caSwyllys } 37099ebb4caSwyllys 37199ebb4caSwyllys static int 37299ebb4caSwyllys kmfber_put_null(BerElement *ber, ber_tag_t tag) 37399ebb4caSwyllys { 37499ebb4caSwyllys int taglen; 37599ebb4caSwyllys 37699ebb4caSwyllys if (tag == KMFBER_DEFAULT) 37799ebb4caSwyllys tag = BER_NULL; 37899ebb4caSwyllys 37999ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 38099ebb4caSwyllys return (-1); 38199ebb4caSwyllys 38299ebb4caSwyllys if (kmfber_put_len(ber, 0, 0) != 1) 38399ebb4caSwyllys return (-1); 38499ebb4caSwyllys 38599ebb4caSwyllys return (taglen + 1); 38699ebb4caSwyllys } 38799ebb4caSwyllys 38899ebb4caSwyllys static int 38999ebb4caSwyllys kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag) 39099ebb4caSwyllys { 39199ebb4caSwyllys int taglen; 39299ebb4caSwyllys unsigned char trueval = 0xff; 39399ebb4caSwyllys unsigned char falseval = 0x00; 39499ebb4caSwyllys 39599ebb4caSwyllys if (tag == KMFBER_DEFAULT) 39699ebb4caSwyllys tag = BER_BOOLEAN; 39799ebb4caSwyllys 39899ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 39999ebb4caSwyllys return (-1); 40099ebb4caSwyllys 40199ebb4caSwyllys if (kmfber_put_len(ber, 1, 0) != 1) 40299ebb4caSwyllys return (-1); 40399ebb4caSwyllys 40499ebb4caSwyllys if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0) 40599ebb4caSwyllys != 1) 40699ebb4caSwyllys return (-1); 40799ebb4caSwyllys 40899ebb4caSwyllys return (taglen + 2); 40999ebb4caSwyllys } 41099ebb4caSwyllys 41199ebb4caSwyllys #define FOUR_BYTE_LEN 5 41299ebb4caSwyllys 41399ebb4caSwyllys 41499ebb4caSwyllys /* 41599ebb4caSwyllys * The idea here is roughly this: we maintain a stack of these Seqorset 41699ebb4caSwyllys * structures. This is pushed when we see the beginning of a new set or 41799ebb4caSwyllys * sequence. It is popped when we see the end of a set or sequence. 41899ebb4caSwyllys * Since we don't want to malloc and free these structures all the time, 41999ebb4caSwyllys * we pre-allocate a small set of them within the ber element structure. 42099ebb4caSwyllys * thus we need to spot when we've overflowed this stack and fall back to 42199ebb4caSwyllys * malloc'ing instead. 42299ebb4caSwyllys */ 42399ebb4caSwyllys static int 42499ebb4caSwyllys ber_start_seqorset(BerElement *ber, ber_tag_t tag) 42599ebb4caSwyllys { 42699ebb4caSwyllys Seqorset *new_sos; 42799ebb4caSwyllys 42899ebb4caSwyllys /* can we fit into the local stack ? */ 42999ebb4caSwyllys if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) { 43099ebb4caSwyllys /* yes */ 43199ebb4caSwyllys new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn]; 43299ebb4caSwyllys } else { 43399ebb4caSwyllys /* no */ 43499ebb4caSwyllys if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset))) 43599ebb4caSwyllys == NULLSEQORSET) { 43699ebb4caSwyllys return (-1); 43799ebb4caSwyllys } 43899ebb4caSwyllys } 43999ebb4caSwyllys ber->ber_sos_stack_posn++; 44099ebb4caSwyllys 44199ebb4caSwyllys if (ber->ber_sos == NULLSEQORSET) 44299ebb4caSwyllys new_sos->sos_first = ber->ber_ptr; 44399ebb4caSwyllys else 44499ebb4caSwyllys new_sos->sos_first = ber->ber_sos->sos_ptr; 44599ebb4caSwyllys 44699ebb4caSwyllys /* Set aside room for a 4 byte length field */ 44799ebb4caSwyllys new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) + 44899ebb4caSwyllys FOUR_BYTE_LEN; 44999ebb4caSwyllys new_sos->sos_tag = tag; 45099ebb4caSwyllys 45199ebb4caSwyllys new_sos->sos_next = ber->ber_sos; 45299ebb4caSwyllys new_sos->sos_clen = 0; 45399ebb4caSwyllys 45499ebb4caSwyllys ber->ber_sos = new_sos; 45599ebb4caSwyllys if (ber->ber_sos->sos_ptr > ber->ber_end) { 456*56664548SWyllys Ingersoll if (kmfber_realloc(ber, ber->ber_sos->sos_ptr - 457*56664548SWyllys Ingersoll ber->ber_end) != 0) 458*56664548SWyllys Ingersoll return (-1); 45999ebb4caSwyllys } 46099ebb4caSwyllys return (0); 46199ebb4caSwyllys } 46299ebb4caSwyllys 46399ebb4caSwyllys static int 46499ebb4caSwyllys kmfber_start_seq(BerElement *ber, ber_tag_t tag) 46599ebb4caSwyllys { 46699ebb4caSwyllys if (tag == KMFBER_DEFAULT) 46799ebb4caSwyllys tag = BER_CONSTRUCTED_SEQUENCE; 46899ebb4caSwyllys 46999ebb4caSwyllys return (ber_start_seqorset(ber, tag)); 47099ebb4caSwyllys } 47199ebb4caSwyllys 47299ebb4caSwyllys static int 47399ebb4caSwyllys kmfber_start_set(BerElement *ber, ber_tag_t tag) 47499ebb4caSwyllys { 47599ebb4caSwyllys if (tag == KMFBER_DEFAULT) 47699ebb4caSwyllys tag = BER_CONSTRUCTED_SET; 47799ebb4caSwyllys 47899ebb4caSwyllys return (ber_start_seqorset(ber, tag)); 47999ebb4caSwyllys } 48099ebb4caSwyllys 48199ebb4caSwyllys static int 48299ebb4caSwyllys ber_put_seqorset(BerElement *ber) 48399ebb4caSwyllys { 48499ebb4caSwyllys ber_int_t netlen, len, taglen, lenlen; 48599ebb4caSwyllys unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; 48699ebb4caSwyllys Seqorset *next; 48799ebb4caSwyllys Seqorset **sos = &ber->ber_sos; 48899ebb4caSwyllys 48999ebb4caSwyllys /* 49099ebb4caSwyllys * If this is the toplevel sequence or set, we need to actually 49199ebb4caSwyllys * write the stuff out. Otherwise, it's already been put in 49299ebb4caSwyllys * the appropriate buffer and will be written when the toplevel 49399ebb4caSwyllys * one is written. In this case all we need to do is update the 49499ebb4caSwyllys * length and tag. 49599ebb4caSwyllys */ 49699ebb4caSwyllys 49799ebb4caSwyllys len = (*sos)->sos_clen; 49899ebb4caSwyllys netlen = (ber_len_t)htonl(len); 49999ebb4caSwyllys 50099ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 50199ebb4caSwyllys lenlen = kmfber_calc_lenlen(len); 50299ebb4caSwyllys } else { 50399ebb4caSwyllys lenlen = FOUR_BYTE_LEN; 50499ebb4caSwyllys } 50599ebb4caSwyllys 50699ebb4caSwyllys if ((next = (*sos)->sos_next) == NULLSEQORSET) { 50799ebb4caSwyllys /* write the tag */ 50899ebb4caSwyllys if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1) 50999ebb4caSwyllys return (-1); 51099ebb4caSwyllys 51199ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 51299ebb4caSwyllys /* Write the length in the minimum # of octets */ 51399ebb4caSwyllys if (kmfber_put_len(ber, len, 1) == -1) 51499ebb4caSwyllys return (-1); 51599ebb4caSwyllys 51699ebb4caSwyllys if (lenlen != FOUR_BYTE_LEN) { 51799ebb4caSwyllys /* 51899ebb4caSwyllys * We set aside FOUR_BYTE_LEN bytes for 51999ebb4caSwyllys * the length field. Move the data if 52099ebb4caSwyllys * we don't actually need that much 52199ebb4caSwyllys */ 52299ebb4caSwyllys (void) memmove((*sos)->sos_first + taglen + 52399ebb4caSwyllys lenlen, (*sos)->sos_first + taglen + 52499ebb4caSwyllys FOUR_BYTE_LEN, len); 52599ebb4caSwyllys } 52699ebb4caSwyllys } else { 52799ebb4caSwyllys /* Fill FOUR_BYTE_LEN bytes for length field */ 52899ebb4caSwyllys /* one byte of length length */ 52999ebb4caSwyllys if (kmfber_write(ber, (char *)<ag, 1, 1) != 1) 53099ebb4caSwyllys return (-1); 53199ebb4caSwyllys 53299ebb4caSwyllys /* the length itself */ 53399ebb4caSwyllys if (kmfber_write(ber, 53499ebb4caSwyllys (char *)&netlen + sizeof (ber_int_t) 53599ebb4caSwyllys - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) != 53699ebb4caSwyllys FOUR_BYTE_LEN - 1) 53799ebb4caSwyllys return (-1); 53899ebb4caSwyllys } 53999ebb4caSwyllys /* The ber_ptr is at the set/seq start - move it to the end */ 54099ebb4caSwyllys ber->ber_ptr += len; 54199ebb4caSwyllys } else { 54299ebb4caSwyllys ber_tag_t ntag; 54399ebb4caSwyllys 54499ebb4caSwyllys /* the tag */ 54599ebb4caSwyllys taglen = kmfber_calc_taglen((*sos)->sos_tag); 54699ebb4caSwyllys ntag = htonl((*sos)->sos_tag); 54799ebb4caSwyllys (void) memmove((*sos)->sos_first, (char *)&ntag + 54899ebb4caSwyllys sizeof (ber_int_t) - taglen, taglen); 54999ebb4caSwyllys 55099ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 55199ebb4caSwyllys ltag = (lenlen == 1) ? (unsigned char)len : 55299ebb4caSwyllys (unsigned char) (0x80 + (lenlen - 1)); 55399ebb4caSwyllys } 55499ebb4caSwyllys 55599ebb4caSwyllys /* one byte of length length */ 55699ebb4caSwyllys (void) memmove((*sos)->sos_first + 1, <ag, 1); 55799ebb4caSwyllys 55899ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 55999ebb4caSwyllys if (lenlen > 1) { 56099ebb4caSwyllys /* Write the length itself */ 56199ebb4caSwyllys (void) memmove((*sos)->sos_first + 2, 56299ebb4caSwyllys (char *)&netlen + sizeof (ber_uint_t) - 56399ebb4caSwyllys (lenlen - 1), 56499ebb4caSwyllys lenlen - 1); 56599ebb4caSwyllys } 56699ebb4caSwyllys if (lenlen != FOUR_BYTE_LEN) { 56799ebb4caSwyllys /* 56899ebb4caSwyllys * We set aside FOUR_BYTE_LEN bytes for 56999ebb4caSwyllys * the length field. Move the data if 57099ebb4caSwyllys * we don't actually need that much 57199ebb4caSwyllys */ 57299ebb4caSwyllys (void) memmove((*sos)->sos_first + taglen + 57399ebb4caSwyllys lenlen, (*sos)->sos_first + taglen + 57499ebb4caSwyllys FOUR_BYTE_LEN, len); 57599ebb4caSwyllys } 57699ebb4caSwyllys } else { 57799ebb4caSwyllys /* the length itself */ 57899ebb4caSwyllys (void) memmove((*sos)->sos_first + taglen + 1, 57999ebb4caSwyllys (char *) &netlen + sizeof (ber_int_t) - 58099ebb4caSwyllys (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1); 58199ebb4caSwyllys } 58299ebb4caSwyllys 58399ebb4caSwyllys next->sos_clen += (taglen + lenlen + len); 58499ebb4caSwyllys next->sos_ptr += (taglen + lenlen + len); 58599ebb4caSwyllys } 58699ebb4caSwyllys 58799ebb4caSwyllys /* we're done with this seqorset, so free it up */ 58899ebb4caSwyllys /* was this one from the local stack ? */ 58999ebb4caSwyllys if (ber->ber_sos_stack_posn > SOS_STACK_SIZE) { 59099ebb4caSwyllys free((char *)(*sos)); 59199ebb4caSwyllys } 59299ebb4caSwyllys ber->ber_sos_stack_posn--; 59399ebb4caSwyllys *sos = next; 59499ebb4caSwyllys 59599ebb4caSwyllys return (taglen + lenlen + len); 59699ebb4caSwyllys } 59799ebb4caSwyllys 59899ebb4caSwyllys /* VARARGS */ 59999ebb4caSwyllys int 60099ebb4caSwyllys kmfber_printf(BerElement *ber, const char *fmt, ...) 60199ebb4caSwyllys { 60299ebb4caSwyllys va_list ap; 60399ebb4caSwyllys char *s, **ss; 60499ebb4caSwyllys struct berval **bv, *oid; 60599ebb4caSwyllys int rc, i, t; 60699ebb4caSwyllys ber_int_t len; 60799ebb4caSwyllys 60899ebb4caSwyllys va_start(ap, fmt); 60999ebb4caSwyllys 61099ebb4caSwyllys #ifdef KMFBER_DEBUG 61199ebb4caSwyllys if (lber_debug & 64) { 61299ebb4caSwyllys char msg[80]; 61399ebb4caSwyllys sprintf(msg, "kmfber_printf fmt (%s)\n", fmt); 61499ebb4caSwyllys ber_err_print(msg); 61599ebb4caSwyllys } 61699ebb4caSwyllys #endif 61799ebb4caSwyllys 61899ebb4caSwyllys for (rc = 0; *fmt && rc != -1; fmt++) { 61999ebb4caSwyllys switch (*fmt) { 62099ebb4caSwyllys case 'b': /* boolean */ 62199ebb4caSwyllys i = va_arg(ap, int); 62299ebb4caSwyllys rc = kmfber_put_boolean(ber, i, ber->ber_tag); 62399ebb4caSwyllys break; 62499ebb4caSwyllys 62599ebb4caSwyllys case 'i': /* int */ 62699ebb4caSwyllys i = va_arg(ap, int); 62799ebb4caSwyllys rc = ber_put_int(ber, (ber_int_t)i, ber->ber_tag); 62899ebb4caSwyllys break; 62999ebb4caSwyllys 63099ebb4caSwyllys case 'D': /* Object ID */ 63199ebb4caSwyllys if ((oid = va_arg(ap, struct berval *)) == NULL) 63299ebb4caSwyllys break; 63399ebb4caSwyllys rc = ber_put_oid(ber, oid, ber->ber_tag); 63499ebb4caSwyllys break; 63599ebb4caSwyllys case 'I': /* int */ 63699ebb4caSwyllys s = va_arg(ap, char *); 63799ebb4caSwyllys len = va_arg(ap, ber_int_t); 63899ebb4caSwyllys rc = ber_put_big_int(ber, ber->ber_tag, s, len); 63999ebb4caSwyllys break; 64099ebb4caSwyllys 64199ebb4caSwyllys case 'e': /* enumeration */ 64299ebb4caSwyllys i = va_arg(ap, int); 64399ebb4caSwyllys rc = kmfber_put_enum(ber, (ber_int_t)i, ber->ber_tag); 64499ebb4caSwyllys break; 64599ebb4caSwyllys 64699ebb4caSwyllys case 'l': 64799ebb4caSwyllys t = va_arg(ap, int); 64899ebb4caSwyllys rc = kmfber_put_len(ber, t, 0); 64999ebb4caSwyllys break; 65099ebb4caSwyllys case 'n': /* null */ 65199ebb4caSwyllys rc = kmfber_put_null(ber, ber->ber_tag); 65299ebb4caSwyllys break; 65399ebb4caSwyllys 65499ebb4caSwyllys case 'o': /* octet string (non-null terminated) */ 65599ebb4caSwyllys s = va_arg(ap, char *); 65699ebb4caSwyllys len = va_arg(ap, int); 65799ebb4caSwyllys rc = kmfber_put_ostring(ber, s, len, ber->ber_tag); 65899ebb4caSwyllys break; 65999ebb4caSwyllys 66099ebb4caSwyllys case 's': /* string */ 66199ebb4caSwyllys s = va_arg(ap, char *); 66299ebb4caSwyllys rc = kmfber_put_string(ber, s, ber->ber_tag); 66399ebb4caSwyllys break; 66499ebb4caSwyllys 66599ebb4caSwyllys case 'B': /* bit string */ 66699ebb4caSwyllys s = va_arg(ap, char *); 66799ebb4caSwyllys len = va_arg(ap, int); /* in bits */ 66899ebb4caSwyllys rc = kmfber_put_bitstring(ber, s, len, ber->ber_tag); 66999ebb4caSwyllys break; 67099ebb4caSwyllys 67199ebb4caSwyllys case 't': /* tag for the next element */ 67299ebb4caSwyllys ber->ber_tag = va_arg(ap, ber_tag_t); 67399ebb4caSwyllys ber->ber_usertag = 1; 67499ebb4caSwyllys break; 67599ebb4caSwyllys 67699ebb4caSwyllys case 'T': /* Write an explicit tag, but don't change current */ 67799ebb4caSwyllys t = va_arg(ap, int); 67899ebb4caSwyllys rc = ber_put_tag(ber, t, 0); 67999ebb4caSwyllys break; 68099ebb4caSwyllys 68199ebb4caSwyllys case 'v': /* vector of strings */ 68299ebb4caSwyllys if ((ss = va_arg(ap, char **)) == NULL) 68399ebb4caSwyllys break; 68499ebb4caSwyllys for (i = 0; ss[i] != NULL; i++) { 68599ebb4caSwyllys if ((rc = kmfber_put_string(ber, ss[i], 68699ebb4caSwyllys ber->ber_tag)) == -1) 68799ebb4caSwyllys break; 68899ebb4caSwyllys } 68999ebb4caSwyllys break; 69099ebb4caSwyllys 69199ebb4caSwyllys case 'V': /* sequences of strings + lengths */ 69299ebb4caSwyllys if ((bv = va_arg(ap, struct berval **)) == NULL) 69399ebb4caSwyllys break; 69499ebb4caSwyllys for (i = 0; bv[i] != NULL; i++) { 69599ebb4caSwyllys if ((rc = kmfber_put_ostring(ber, bv[i]->bv_val, 69699ebb4caSwyllys bv[i]->bv_len, ber->ber_tag)) == -1) 69799ebb4caSwyllys break; 69899ebb4caSwyllys } 69999ebb4caSwyllys break; 70099ebb4caSwyllys 70199ebb4caSwyllys case '{': /* begin sequence */ 70299ebb4caSwyllys rc = kmfber_start_seq(ber, ber->ber_tag); 70399ebb4caSwyllys break; 70499ebb4caSwyllys 70599ebb4caSwyllys case '}': /* end sequence */ 70699ebb4caSwyllys rc = ber_put_seqorset(ber); 70799ebb4caSwyllys break; 70899ebb4caSwyllys 70999ebb4caSwyllys case '[': /* begin set */ 71099ebb4caSwyllys rc = kmfber_start_set(ber, ber->ber_tag); 71199ebb4caSwyllys break; 71299ebb4caSwyllys 71399ebb4caSwyllys case ']': /* end set */ 71499ebb4caSwyllys rc = ber_put_seqorset(ber); 71599ebb4caSwyllys break; 71699ebb4caSwyllys 71799ebb4caSwyllys default: { 71899ebb4caSwyllys #ifdef KMFBER_DEBUG 71999ebb4caSwyllys char msg[80]; 72099ebb4caSwyllys sprintf(msg, "unknown fmt %c\n", *fmt); 72199ebb4caSwyllys ber_err_print(msg); 72299ebb4caSwyllys #endif 72399ebb4caSwyllys rc = -1; 72499ebb4caSwyllys break; 72599ebb4caSwyllys } 72699ebb4caSwyllys } 72799ebb4caSwyllys 72899ebb4caSwyllys if (ber->ber_usertag == 0) 72999ebb4caSwyllys ber->ber_tag = KMFBER_DEFAULT; 73099ebb4caSwyllys else 73199ebb4caSwyllys ber->ber_usertag = 0; 73299ebb4caSwyllys } 73399ebb4caSwyllys 73499ebb4caSwyllys va_end(ap); 73599ebb4caSwyllys 73699ebb4caSwyllys return (rc); 73799ebb4caSwyllys } 738