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
kmfber_calc_taglen(ber_tag_t tag)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
ber_put_tag(BerElement * ber,ber_tag_t tag,int nosos)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
kmfber_calc_lenlen(ber_int_t len)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
kmfber_put_len(BerElement * ber,ber_int_t len,int nosos)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
ber_put_int_or_enum(BerElement * ber,ber_int_t num,ber_tag_t tag)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
kmfber_put_enum(BerElement * ber,ber_int_t num,ber_tag_t tag)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
ber_put_int(BerElement * ber,ber_int_t num,ber_tag_t tag)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
ber_put_oid(BerElement * ber,struct berval * oid,ber_tag_t tag)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
ber_put_big_int(BerElement * ber,ber_tag_t tag,char * data,ber_len_t len)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
kmfber_put_ostring(BerElement * ber,char * str,ber_len_t len,ber_tag_t tag)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
kmfber_put_string(BerElement * ber,char * str,ber_tag_t tag)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
kmfber_put_bitstring(BerElement * ber,char * str,ber_len_t blen,ber_tag_t tag)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
kmfber_put_null(BerElement * ber,ber_tag_t tag)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
kmfber_put_boolean(BerElement * ber,int boolval,ber_tag_t tag)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
ber_start_seqorset(BerElement * ber,ber_tag_t tag)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
kmfber_start_seq(BerElement * ber,ber_tag_t tag)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
kmfber_start_set(BerElement * ber,ber_tag_t tag)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
ber_put_seqorset(BerElement * ber)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
kmfber_printf(BerElement * ber,const char * fmt,...)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