13089Swyllys /* 23089Swyllys * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 33089Swyllys * 43089Swyllys * The contents of this file are subject to the Netscape Public License 53089Swyllys * Version 1.0 (the "NPL"); you may not use this file except in 63089Swyllys * compliance with the NPL. You may obtain a copy of the NPL at 73089Swyllys * http://www.mozilla.org/NPL/ 83089Swyllys * 93089Swyllys * Software distributed under the NPL is distributed on an "AS IS" basis, 103089Swyllys * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 113089Swyllys * for the specific language governing rights and limitations under the 123089Swyllys * NPL. 133089Swyllys * 143089Swyllys * The Initial Developer of this code under the NPL is Netscape 153089Swyllys * Communications Corporation. Portions created by Netscape are 163089Swyllys * Copyright (C) 1998 Netscape Communications Corporation. All Rights 173089Swyllys * Reserved. 183089Swyllys */ 193089Swyllys 203089Swyllys /* 213089Swyllys * Copyright (c) 1990 Regents of the University of Michigan. 223089Swyllys * All rights reserved. 233089Swyllys * 243089Swyllys * Redistribution and use in source and binary forms are permitted 253089Swyllys * provided that this notice is preserved and that due credit is given 263089Swyllys * to the University of Michigan at Ann Arbor. The name of the University 273089Swyllys * may not be used to endorse or promote products derived from this 283089Swyllys * software without specific prior written permission. This software 293089Swyllys * is provided ``as is'' without express or implied warranty. 303089Swyllys */ 313089Swyllys 323089Swyllys /* 333433Shaimay * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 343089Swyllys * Use is subject to license terms. 353089Swyllys */ 363089Swyllys 373089Swyllys #pragma ident "%Z%%M% %I% %E% SMI" 383089Swyllys 393089Swyllys #include <sys/types.h> 403089Swyllys #include <netinet/in.h> 413089Swyllys #include <inttypes.h> 423089Swyllys 433089Swyllys #include <ber_der.h> 443089Swyllys #include "kmfber_int.h" 453089Swyllys 463089Swyllys /* the following constants are used in kmfber_calc_lenlen */ 473089Swyllys 483089Swyllys #define LENMASK1 0xFF 493089Swyllys #define LENMASK2 0xFFFF 503089Swyllys #define LENMASK3 0xFFFFFF 513089Swyllys #define LENMASK4 0xFFFFFFFF 523089Swyllys #define _MASK 0x80 533089Swyllys 543089Swyllys int 553089Swyllys kmfber_calc_taglen(ber_tag_t tag) 563089Swyllys { 573089Swyllys int i; 583089Swyllys ber_int_t mask; 593089Swyllys 603089Swyllys /* find the first non-all-zero byte in the tag */ 613089Swyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 623089Swyllys mask = (LENMASK3 << (i * 8)); 633089Swyllys /* not all zero */ 643089Swyllys if (tag & mask) 653089Swyllys break; 663089Swyllys } 673089Swyllys 683089Swyllys return (i + 1); 693089Swyllys } 703089Swyllys 713089Swyllys static int 723089Swyllys ber_put_tag(BerElement *ber, ber_tag_t tag, int nosos) 733089Swyllys { 743089Swyllys ber_int_t taglen; 753089Swyllys ber_tag_t ntag; 763089Swyllys 773089Swyllys taglen = kmfber_calc_taglen(tag); 783089Swyllys 793089Swyllys ntag = htonl(tag); 803089Swyllys 813089Swyllys return (kmfber_write(ber, 82*5221Swyllys ((char *) &ntag) + sizeof (ber_int_t) - taglen, 83*5221Swyllys taglen, nosos)); 843089Swyllys } 853089Swyllys 863089Swyllys int 873089Swyllys kmfber_calc_lenlen(ber_int_t len) 883089Swyllys { 893089Swyllys /* 903089Swyllys * short len if it's less than 128 - one byte giving the len, 913089Swyllys * with bit 8 0. 923089Swyllys */ 933089Swyllys 943089Swyllys if (len <= 0x7F) 953089Swyllys return (1); 963089Swyllys 973089Swyllys /* 983089Swyllys * long len otherwise - one byte with bit 8 set, giving the 993089Swyllys * length of the length, followed by the length itself. 1003089Swyllys */ 1013089Swyllys 1023089Swyllys if (len <= LENMASK1) 1033089Swyllys return (2); 1043089Swyllys if (len <= LENMASK2) 1053089Swyllys return (3); 1063089Swyllys if (len <= LENMASK3) 1073089Swyllys return (4); 1083089Swyllys 1093089Swyllys return (5); 1103089Swyllys } 1113089Swyllys 1123089Swyllys int 1133089Swyllys kmfber_put_len(BerElement *ber, ber_int_t len, int nosos) 1143089Swyllys { 1153089Swyllys int i; 1163089Swyllys char lenlen; 1173089Swyllys ber_int_t mask, netlen; 1183089Swyllys 1193089Swyllys /* 1203089Swyllys * short len if it's less than 128 - one byte giving the len, 1213089Swyllys * with bit 8 0. 1223089Swyllys */ 1233089Swyllys if (len <= 127) { 1243089Swyllys netlen = htonl(len); 1253089Swyllys return (kmfber_write(ber, 126*5221Swyllys (char *)&netlen + sizeof (ber_int_t) - 1, 127*5221Swyllys 1, nosos)); 1283089Swyllys } 1293089Swyllys 1303089Swyllys /* 1313089Swyllys * long len otherwise - one byte with bit 8 set, giving the 1323089Swyllys * length of the length, followed by the length itself. 1333089Swyllys */ 1343089Swyllys 1353089Swyllys /* find the first non-all-zero byte */ 1363089Swyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 1373089Swyllys mask = (LENMASK1 << (i * 8)); 1383089Swyllys /* not all zero */ 1393089Swyllys if (len & mask) 1403089Swyllys break; 1413089Swyllys } 1423089Swyllys lenlen = ++i; 1433089Swyllys if (lenlen > 4) 1443089Swyllys return (-1); 1453089Swyllys lenlen |= 0x80; 1463089Swyllys 1473089Swyllys /* write the length of the length */ 1483089Swyllys if (kmfber_write(ber, &lenlen, 1, nosos) != 1) 1493089Swyllys return (-1); 1503089Swyllys 1513089Swyllys /* write the length itself */ 1523089Swyllys netlen = htonl(len); 1533089Swyllys if (kmfber_write(ber, 154*5221Swyllys (char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i) 1553089Swyllys return (-1); 1563089Swyllys 1573089Swyllys return (i + 1); 1583089Swyllys } 1593089Swyllys 1603089Swyllys static int 1613089Swyllys ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) 1623089Swyllys { 1633089Swyllys int i, sign; 1643089Swyllys ber_int_t len, lenlen, taglen, netnum, mask; 1653089Swyllys 1663089Swyllys sign = (num < 0); 1673089Swyllys 1683089Swyllys /* 1693089Swyllys * high bit is set - look for first non-all-one byte 1703089Swyllys * high bit is clear - look for first non-all-zero byte 1713089Swyllys */ 1723089Swyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 1733089Swyllys mask = (LENMASK1 << (i * 8)); 1743089Swyllys 1753089Swyllys if (sign) { 1763089Swyllys /* not all ones */ 1773089Swyllys if ((num & mask) != mask) 1783089Swyllys break; 1793089Swyllys } else { 1803089Swyllys /* not all zero */ 1813089Swyllys if (num & mask) 1823089Swyllys break; 1833089Swyllys } 1843089Swyllys } 1853089Swyllys 1863089Swyllys /* 1873089Swyllys * we now have the "leading byte". if the high bit on this 1883089Swyllys * byte matches the sign bit, we need to "back up" a byte. 1893089Swyllys */ 1903089Swyllys mask = (num & (_MASK << (i * 8))); 1913089Swyllys if ((mask && !sign) || (sign && !mask)) 1923089Swyllys i++; 1933089Swyllys 1943089Swyllys len = i + 1; 1953089Swyllys 1963089Swyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 1973089Swyllys return (-1); 1983089Swyllys 1993089Swyllys if ((lenlen = kmfber_put_len(ber, len, 0)) == -1) 2003089Swyllys return (-1); 2013089Swyllys i++; 2023089Swyllys netnum = htonl(num); 2033089Swyllys if (kmfber_write(ber, 204*5221Swyllys (char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i) 2053089Swyllys /* length of tag + length + contents */ 2063089Swyllys return (taglen + lenlen + i); 2073089Swyllys 2083089Swyllys return (-1); 2093089Swyllys } 2103089Swyllys 2113089Swyllys static int 2123089Swyllys kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) 2133089Swyllys { 2143089Swyllys if (tag == KMFBER_DEFAULT) 2153089Swyllys tag = BER_ENUMERATED; 2163089Swyllys 2173089Swyllys return (ber_put_int_or_enum(ber, num, tag)); 2183089Swyllys } 2193089Swyllys 2203089Swyllys int 2213089Swyllys ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag) 2223089Swyllys { 2233089Swyllys if (tag == KMFBER_DEFAULT) 2243089Swyllys tag = BER_INTEGER; 2253089Swyllys 2263089Swyllys return (ber_put_int_or_enum(ber, num, tag)); 2273089Swyllys } 2283089Swyllys 2293089Swyllys int 2303089Swyllys ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag) 2313089Swyllys { 2323089Swyllys ber_int_t taglen, lenlen, rc, len; 2333089Swyllys 2343089Swyllys if (tag == KMFBER_DEFAULT) 2353089Swyllys tag = 0x06; /* TODO: Add new OID constant to header */ 2363089Swyllys 2373089Swyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 2383089Swyllys return (-1); 2393089Swyllys 2403089Swyllys len = (ber_int_t)oid->bv_len; 2413089Swyllys if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 || 242*5221Swyllys kmfber_write(ber, oid->bv_val, oid->bv_len, 0) != 243*5221Swyllys (ber_int_t)oid->bv_len) { 2443089Swyllys rc = -1; 2453089Swyllys } else { 2463089Swyllys /* return length of tag + length + contents */ 2473089Swyllys rc = taglen + lenlen + oid->bv_len; 2483089Swyllys } 2493089Swyllys return (rc); 2503089Swyllys } 2513089Swyllys 2523089Swyllys int 2533089Swyllys ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data, 2543089Swyllys ber_len_t len) 2553089Swyllys { 2563089Swyllys ber_int_t taglen, lenlen, ilen, rc; 257*5221Swyllys char zero = 0x00; 2583089Swyllys 2593089Swyllys if (tag == KMFBER_DEFAULT) 2603089Swyllys tag = BER_INTEGER; 2613089Swyllys 2623089Swyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 2633089Swyllys return (-1); 2643089Swyllys 265*5221Swyllys /* Add a leading 0 if the high order bit is set */ 266*5221Swyllys if (data[0] & 0x80) 267*5221Swyllys len++; 268*5221Swyllys 2693089Swyllys ilen = (ber_int_t)len; 270*5221Swyllys if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1) 271*5221Swyllys return (-1); 272*5221Swyllys 273*5221Swyllys /* add leading 0 if hi bit set */ 274*5221Swyllys if ((data[0] & 0x80) && kmfber_write(ber, &zero, 1, 0) != 1) 275*5221Swyllys return (-1); 276*5221Swyllys 277*5221Swyllys /* Adjust the length of the write if hi-order bit is set */ 278*5221Swyllys if (data[0] & 0x80) 279*5221Swyllys ilen = len - 1; 280*5221Swyllys if (kmfber_write(ber, data, ilen, 0) != (ber_int_t)ilen) { 281*5221Swyllys return (-1); 2823089Swyllys } else { 2833089Swyllys /* return length of tag + length + contents */ 2843089Swyllys rc = taglen + lenlen + len; 2853089Swyllys } 2863089Swyllys return (rc); 2873089Swyllys } 2883089Swyllys 2893089Swyllys static int 2903089Swyllys kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len, 2913089Swyllys ber_tag_t tag) 2923089Swyllys { 2933089Swyllys ber_int_t taglen, lenlen, ilen, rc; 2943089Swyllys #ifdef STR_TRANSLATION 2953089Swyllys int free_str; 2963089Swyllys #endif /* STR_TRANSLATION */ 2973089Swyllys 2983089Swyllys if (tag == KMFBER_DEFAULT) 2993089Swyllys tag = BER_OCTET_STRING; 3003089Swyllys 3013089Swyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 3023089Swyllys return (-1); 3033089Swyllys 3043089Swyllys #ifdef STR_TRANSLATION 3053089Swyllys if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 && 3063089Swyllys ber->ber_encode_translate_proc != NULL) { 3073089Swyllys if ((*(ber->ber_encode_translate_proc))(&str, &len, 0) 3083089Swyllys != 0) { 3093089Swyllys return (-1); 3103089Swyllys } 3113089Swyllys free_str = 1; 3123089Swyllys } else { 3133089Swyllys free_str = 0; 3143089Swyllys } 3153089Swyllys #endif /* STR_TRANSLATION */ 3163089Swyllys 3173089Swyllys /* 3183089Swyllys * Note: below is a spot where we limit ber_write 3193089Swyllys * to signed long (instead of unsigned long) 3203089Swyllys */ 3213089Swyllys ilen = (ber_int_t)len; 3223089Swyllys if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 || 323*5221Swyllys kmfber_write(ber, str, len, 0) != (ber_int_t)len) { 3243089Swyllys rc = -1; 3253089Swyllys } else { 3263089Swyllys /* return length of tag + length + contents */ 3273089Swyllys rc = taglen + lenlen + len; 3283089Swyllys } 3293089Swyllys 3303089Swyllys #ifdef STR_TRANSLATION 3313089Swyllys if (free_str) { 3323089Swyllys free(str); 3333089Swyllys } 3343089Swyllys #endif /* STR_TRANSLATION */ 3353089Swyllys 3363089Swyllys return (rc); 3373089Swyllys } 3383089Swyllys 3393089Swyllys static int 3403089Swyllys kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag) 3413089Swyllys { 3423089Swyllys return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag)); 3433089Swyllys } 3443089Swyllys 3453089Swyllys static int 3463089Swyllys kmfber_put_bitstring(BerElement *ber, char *str, 3473089Swyllys ber_len_t blen /* in bits */, ber_tag_t tag) 3483089Swyllys { 3493089Swyllys ber_int_t taglen, lenlen, len; 3503089Swyllys unsigned char unusedbits; 3513089Swyllys 3523089Swyllys if (tag == KMFBER_DEFAULT) 3533089Swyllys tag = BER_BIT_STRING; 3543089Swyllys 3553089Swyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 3563089Swyllys return (-1); 3573089Swyllys 3583089Swyllys len = (blen + 7) / 8; 3593089Swyllys unusedbits = (unsigned char) (len * 8 - blen); 3603089Swyllys if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1) 3613089Swyllys return (-1); 3623089Swyllys 3633089Swyllys if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1) 3643089Swyllys return (-1); 3653089Swyllys 3663089Swyllys if (kmfber_write(ber, str, len, 0) != len) 3673089Swyllys return (-1); 3683089Swyllys 3693089Swyllys /* return length of tag + length + unused bit count + contents */ 3703089Swyllys return (taglen + 1 + lenlen + len); 3713089Swyllys } 3723089Swyllys 3733089Swyllys static int 3743089Swyllys kmfber_put_null(BerElement *ber, ber_tag_t tag) 3753089Swyllys { 3763089Swyllys int taglen; 3773089Swyllys 3783089Swyllys if (tag == KMFBER_DEFAULT) 3793089Swyllys tag = BER_NULL; 3803089Swyllys 3813089Swyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 3823089Swyllys return (-1); 3833089Swyllys 3843089Swyllys if (kmfber_put_len(ber, 0, 0) != 1) 3853089Swyllys return (-1); 3863089Swyllys 3873089Swyllys return (taglen + 1); 3883089Swyllys } 3893089Swyllys 3903089Swyllys static int 3913089Swyllys kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag) 3923089Swyllys { 3933089Swyllys int taglen; 3943089Swyllys unsigned char trueval = 0xff; 3953089Swyllys unsigned char falseval = 0x00; 3963089Swyllys 3973089Swyllys if (tag == KMFBER_DEFAULT) 3983089Swyllys tag = BER_BOOLEAN; 3993089Swyllys 4003089Swyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 4013089Swyllys return (-1); 4023089Swyllys 4033089Swyllys if (kmfber_put_len(ber, 1, 0) != 1) 4043089Swyllys return (-1); 4053089Swyllys 4063089Swyllys if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0) 4073089Swyllys != 1) 4083089Swyllys return (-1); 4093089Swyllys 4103089Swyllys return (taglen + 2); 4113089Swyllys } 4123089Swyllys 4133089Swyllys #define FOUR_BYTE_LEN 5 4143089Swyllys 4153089Swyllys 4163089Swyllys /* 4173089Swyllys * The idea here is roughly this: we maintain a stack of these Seqorset 4183089Swyllys * structures. This is pushed when we see the beginning of a new set or 4193089Swyllys * sequence. It is popped when we see the end of a set or sequence. 4203089Swyllys * Since we don't want to malloc and free these structures all the time, 4213089Swyllys * we pre-allocate a small set of them within the ber element structure. 4223089Swyllys * thus we need to spot when we've overflowed this stack and fall back to 4233089Swyllys * malloc'ing instead. 4243089Swyllys */ 4253089Swyllys static int 4263089Swyllys ber_start_seqorset(BerElement *ber, ber_tag_t tag) 4273089Swyllys { 4283089Swyllys Seqorset *new_sos; 4293089Swyllys 4303089Swyllys /* can we fit into the local stack ? */ 4313089Swyllys if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) { 4323089Swyllys /* yes */ 4333089Swyllys new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn]; 4343089Swyllys } else { 4353089Swyllys /* no */ 4363089Swyllys if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset))) 4373089Swyllys == NULLSEQORSET) { 4383089Swyllys return (-1); 4393089Swyllys } 4403089Swyllys } 4413089Swyllys ber->ber_sos_stack_posn++; 4423089Swyllys 4433089Swyllys if (ber->ber_sos == NULLSEQORSET) 4443089Swyllys new_sos->sos_first = ber->ber_ptr; 4453089Swyllys else 4463089Swyllys new_sos->sos_first = ber->ber_sos->sos_ptr; 4473089Swyllys 4483089Swyllys /* Set aside room for a 4 byte length field */ 4493089Swyllys new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) + 450*5221Swyllys FOUR_BYTE_LEN; 4513089Swyllys new_sos->sos_tag = tag; 4523089Swyllys 4533089Swyllys new_sos->sos_next = ber->ber_sos; 4543089Swyllys new_sos->sos_clen = 0; 4553089Swyllys 4563089Swyllys ber->ber_sos = new_sos; 4573089Swyllys if (ber->ber_sos->sos_ptr > ber->ber_end) { 4583089Swyllys (void) realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end); 4593089Swyllys } 4603089Swyllys return (0); 4613089Swyllys } 4623089Swyllys 4633089Swyllys static int 4643089Swyllys kmfber_start_seq(BerElement *ber, ber_tag_t tag) 4653089Swyllys { 4663089Swyllys if (tag == KMFBER_DEFAULT) 4673089Swyllys tag = BER_CONSTRUCTED_SEQUENCE; 4683089Swyllys 4693089Swyllys return (ber_start_seqorset(ber, tag)); 4703089Swyllys } 4713089Swyllys 4723089Swyllys static int 4733089Swyllys kmfber_start_set(BerElement *ber, ber_tag_t tag) 4743089Swyllys { 4753089Swyllys if (tag == KMFBER_DEFAULT) 4763089Swyllys tag = BER_CONSTRUCTED_SET; 4773089Swyllys 4783089Swyllys return (ber_start_seqorset(ber, tag)); 4793089Swyllys } 4803089Swyllys 4813089Swyllys static int 4823089Swyllys ber_put_seqorset(BerElement *ber) 4833089Swyllys { 4843089Swyllys ber_int_t netlen, len, taglen, lenlen; 4853089Swyllys unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; 4863089Swyllys Seqorset *next; 4873089Swyllys Seqorset **sos = &ber->ber_sos; 4883089Swyllys 4893089Swyllys /* 4903089Swyllys * If this is the toplevel sequence or set, we need to actually 4913089Swyllys * write the stuff out. Otherwise, it's already been put in 4923089Swyllys * the appropriate buffer and will be written when the toplevel 4933089Swyllys * one is written. In this case all we need to do is update the 4943089Swyllys * length and tag. 4953089Swyllys */ 4963089Swyllys 4973089Swyllys len = (*sos)->sos_clen; 4983089Swyllys netlen = (ber_len_t)htonl(len); 4993089Swyllys 5003089Swyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 5013089Swyllys lenlen = kmfber_calc_lenlen(len); 5023089Swyllys } else { 5033089Swyllys lenlen = FOUR_BYTE_LEN; 5043089Swyllys } 5053089Swyllys 5063089Swyllys if ((next = (*sos)->sos_next) == NULLSEQORSET) { 5073089Swyllys /* write the tag */ 5083089Swyllys if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1) 5093089Swyllys return (-1); 5103089Swyllys 5113089Swyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 5123089Swyllys /* Write the length in the minimum # of octets */ 5133089Swyllys if (kmfber_put_len(ber, len, 1) == -1) 5143089Swyllys return (-1); 5153089Swyllys 5163089Swyllys if (lenlen != FOUR_BYTE_LEN) { 5173089Swyllys /* 5183089Swyllys * We set aside FOUR_BYTE_LEN bytes for 5193089Swyllys * the length field. Move the data if 5203089Swyllys * we don't actually need that much 5213089Swyllys */ 5223089Swyllys (void) memmove((*sos)->sos_first + taglen + 5233089Swyllys lenlen, (*sos)->sos_first + taglen + 5243089Swyllys FOUR_BYTE_LEN, len); 5253089Swyllys } 5263089Swyllys } else { 5273089Swyllys /* Fill FOUR_BYTE_LEN bytes for length field */ 5283089Swyllys /* one byte of length length */ 5293089Swyllys if (kmfber_write(ber, (char *)<ag, 1, 1) != 1) 5303089Swyllys return (-1); 5313089Swyllys 5323089Swyllys /* the length itself */ 5333089Swyllys if (kmfber_write(ber, 534*5221Swyllys (char *)&netlen + sizeof (ber_int_t) 535*5221Swyllys - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) != 536*5221Swyllys FOUR_BYTE_LEN - 1) 5373089Swyllys return (-1); 5383089Swyllys } 5393089Swyllys /* The ber_ptr is at the set/seq start - move it to the end */ 5403089Swyllys ber->ber_ptr += len; 5413089Swyllys } else { 5423089Swyllys ber_tag_t ntag; 5433089Swyllys 5443089Swyllys /* the tag */ 5453089Swyllys taglen = kmfber_calc_taglen((*sos)->sos_tag); 5463089Swyllys ntag = htonl((*sos)->sos_tag); 5473089Swyllys (void) memmove((*sos)->sos_first, (char *)&ntag + 5483089Swyllys sizeof (ber_int_t) - taglen, taglen); 5493089Swyllys 5503089Swyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 5513089Swyllys ltag = (lenlen == 1) ? (unsigned char)len : 552*5221Swyllys (unsigned char) (0x80 + (lenlen - 1)); 5533089Swyllys } 5543089Swyllys 5553089Swyllys /* one byte of length length */ 5563089Swyllys (void) memmove((*sos)->sos_first + 1, <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 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