199ebb4caSwyllys /*
2*e65e5c2dSWyllys Ingersoll * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
399ebb4caSwyllys * Use is subject to license terms.
499ebb4caSwyllys */
599ebb4caSwyllys /*
699ebb4caSwyllys * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
799ebb4caSwyllys *
899ebb4caSwyllys * The contents of this file are subject to the Netscape Public License
999ebb4caSwyllys * Version 1.0 (the "NPL"); you may not use this file except in
1099ebb4caSwyllys * compliance with the NPL. You may obtain a copy of the NPL at
1199ebb4caSwyllys * http://www.mozilla.org/NPL/
1299ebb4caSwyllys *
1399ebb4caSwyllys * Software distributed under the NPL is distributed on an "AS IS" basis,
1499ebb4caSwyllys * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
1599ebb4caSwyllys * for the specific language governing rights and limitations under the
1699ebb4caSwyllys * NPL.
1799ebb4caSwyllys *
1899ebb4caSwyllys * The Initial Developer of this code under the NPL is Netscape
1999ebb4caSwyllys * Communications Corporation. Portions created by Netscape are
2099ebb4caSwyllys * Copyright (C) 1998 Netscape Communications Corporation. All Rights
2199ebb4caSwyllys * Reserved.
2299ebb4caSwyllys */
2399ebb4caSwyllys
2499ebb4caSwyllys /*
2599ebb4caSwyllys * Copyright (c) 1990 Regents of the University of Michigan.
2699ebb4caSwyllys * All rights reserved.
2799ebb4caSwyllys *
2899ebb4caSwyllys * Redistribution and use in source and binary forms are permitted
2999ebb4caSwyllys * provided that this notice is preserved and that due credit is given
3099ebb4caSwyllys * to the University of Michigan at Ann Arbor. The name of the University
3199ebb4caSwyllys * may not be used to endorse or promote products derived from this
3299ebb4caSwyllys * software without specific prior written permission. This software
3399ebb4caSwyllys * is provided ``as is'' without express or implied warranty.
3499ebb4caSwyllys */
3599ebb4caSwyllys
3699ebb4caSwyllys /* decode.c - ber input decoding routines */
3799ebb4caSwyllys
3899ebb4caSwyllys #include <strings.h>
3999ebb4caSwyllys #include <sys/types.h>
4099ebb4caSwyllys #include <netinet/in.h>
4199ebb4caSwyllys #include <inttypes.h>
4299ebb4caSwyllys
4399ebb4caSwyllys #include <ber_der.h>
4499ebb4caSwyllys #include "kmfber_int.h"
4599ebb4caSwyllys
4699ebb4caSwyllys static void
ber_svecfree(char ** vals)4799ebb4caSwyllys ber_svecfree(char **vals)
4899ebb4caSwyllys {
4999ebb4caSwyllys int i;
5099ebb4caSwyllys
5199ebb4caSwyllys if (vals == NULL)
5299ebb4caSwyllys return;
5399ebb4caSwyllys for (i = 0; vals[i] != NULL; i++)
5499ebb4caSwyllys free(vals[i]);
5599ebb4caSwyllys free((char *)vals);
5699ebb4caSwyllys }
5799ebb4caSwyllys
5899ebb4caSwyllys /*
5999ebb4caSwyllys * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
6099ebb4caSwyllys * If that changes, the kmfber_peek_tag() and/or
6199ebb4caSwyllys * kmfkmfber_skip_tag() implementations will need to be changed.
6299ebb4caSwyllys */
6399ebb4caSwyllys /* return the tag - KMFBER_DEFAULT returned means trouble */
6499ebb4caSwyllys static ber_tag_t
kmfber_get_tag(BerElement * ber)6599ebb4caSwyllys kmfber_get_tag(BerElement *ber)
6699ebb4caSwyllys {
6799ebb4caSwyllys unsigned char xbyte;
6899ebb4caSwyllys ber_tag_t tag;
6999ebb4caSwyllys char *tagp;
7099ebb4caSwyllys int i;
7199ebb4caSwyllys
7299ebb4caSwyllys if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
7399ebb4caSwyllys return (KMFBER_DEFAULT);
7499ebb4caSwyllys
7599ebb4caSwyllys if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
7699ebb4caSwyllys return ((ber_uint_t)xbyte);
7799ebb4caSwyllys
7899ebb4caSwyllys tagp = (char *)&tag;
7999ebb4caSwyllys tagp[0] = xbyte;
8099ebb4caSwyllys for (i = 1; i < sizeof (ber_int_t); i++) {
8199ebb4caSwyllys if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
8299ebb4caSwyllys return (KMFBER_DEFAULT);
8399ebb4caSwyllys
8499ebb4caSwyllys tagp[i] = xbyte;
8599ebb4caSwyllys
8699ebb4caSwyllys if (! (xbyte & KMFBER_MORE_TAG_MASK))
8799ebb4caSwyllys break;
8899ebb4caSwyllys }
8999ebb4caSwyllys
9099ebb4caSwyllys /* tag too big! */
9199ebb4caSwyllys if (i == sizeof (ber_int_t))
9299ebb4caSwyllys return (KMFBER_DEFAULT);
9399ebb4caSwyllys
9499ebb4caSwyllys /* want leading, not trailing 0's */
9599ebb4caSwyllys return (tag >> (sizeof (ber_int_t)- i - 1));
9699ebb4caSwyllys }
9799ebb4caSwyllys
9899ebb4caSwyllys /*
9999ebb4caSwyllys * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
10099ebb4caSwyllys * If that changes, the implementation of kmfber_peek_tag() will need to
10199ebb4caSwyllys * be changed.
10299ebb4caSwyllys */
10399ebb4caSwyllys ber_tag_t
kmfber_skip_tag(BerElement * ber,ber_len_t * len)10499ebb4caSwyllys kmfber_skip_tag(BerElement *ber, ber_len_t *len)
10599ebb4caSwyllys {
10699ebb4caSwyllys ber_tag_t tag;
10799ebb4caSwyllys unsigned char lc;
10899ebb4caSwyllys int noctets, diff;
10999ebb4caSwyllys uint32_t netlen;
11099ebb4caSwyllys
11199ebb4caSwyllys /*
11299ebb4caSwyllys * Any ber element looks like this: tag length contents.
11399ebb4caSwyllys * Assuming everything's ok, we return the tag byte (we
11499ebb4caSwyllys * can assume a single byte), and return the length in len.
11599ebb4caSwyllys *
11699ebb4caSwyllys * Assumptions:
11799ebb4caSwyllys * 1) definite lengths
11899ebb4caSwyllys * 2) primitive encodings used whenever possible
11999ebb4caSwyllys */
12099ebb4caSwyllys
12199ebb4caSwyllys /*
12299ebb4caSwyllys * First, we read the tag.
12399ebb4caSwyllys */
12499ebb4caSwyllys
12599ebb4caSwyllys if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
12699ebb4caSwyllys return (KMFBER_DEFAULT);
12799ebb4caSwyllys
12899ebb4caSwyllys /*
12999ebb4caSwyllys * Next, read the length. The first byte contains the length of
13099ebb4caSwyllys * the length. If bit 8 is set, the length is the long form,
13199ebb4caSwyllys * otherwise it's the short form. We don't allow a length that's
13299ebb4caSwyllys * greater than what we can hold in an unsigned long.
13399ebb4caSwyllys */
13499ebb4caSwyllys
13599ebb4caSwyllys *len = 0;
13699ebb4caSwyllys netlen = 0;
13799ebb4caSwyllys if (kmfber_read(ber, (char *)&lc, 1) != 1)
13899ebb4caSwyllys return (KMFBER_DEFAULT);
13999ebb4caSwyllys if (lc & 0x80) {
14099ebb4caSwyllys noctets = (lc & 0x7f);
14199ebb4caSwyllys if (noctets > sizeof (ber_uint_t))
14299ebb4caSwyllys return (KMFBER_DEFAULT);
14399ebb4caSwyllys diff = sizeof (ber_int_t) - noctets;
14499ebb4caSwyllys if (kmfber_read(ber, (char *)&netlen + diff, noctets)
14599ebb4caSwyllys != noctets)
14699ebb4caSwyllys return (KMFBER_DEFAULT);
14799ebb4caSwyllys *len = ntohl(netlen);
14899ebb4caSwyllys } else {
14999ebb4caSwyllys *len = lc;
15099ebb4caSwyllys }
15199ebb4caSwyllys
15299ebb4caSwyllys return (tag);
15399ebb4caSwyllys }
15499ebb4caSwyllys
15599ebb4caSwyllys
15699ebb4caSwyllys /*
15799ebb4caSwyllys * Note: Previously, we passed the "ber" parameter directly to
15899ebb4caSwyllys * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
15999ebb4caSwyllys * We now take advantage of the fact that the only ber structure
16099ebb4caSwyllys * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
16199ebb4caSwyllys * If that changes, this code must change too.
16299ebb4caSwyllys */
16399ebb4caSwyllys static ber_tag_t
kmfber_peek_tag(BerElement * ber,ber_len_t * len)16499ebb4caSwyllys kmfber_peek_tag(BerElement *ber, ber_len_t *len)
16599ebb4caSwyllys {
16699ebb4caSwyllys BerElement bercopy;
16799ebb4caSwyllys
16899ebb4caSwyllys bercopy.ber_end = ber->ber_end;
16999ebb4caSwyllys bercopy.ber_ptr = ber->ber_ptr;
17099ebb4caSwyllys return (kmfber_skip_tag(&bercopy, len));
17199ebb4caSwyllys }
17299ebb4caSwyllys
17399ebb4caSwyllys static int
ber_getnint(BerElement * ber,ber_int_t * num,ber_slen_t len)17499ebb4caSwyllys ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
17599ebb4caSwyllys {
17699ebb4caSwyllys int i;
17799ebb4caSwyllys ber_int_t value;
17899ebb4caSwyllys unsigned char buffer[sizeof (ber_int_t)];
17999ebb4caSwyllys /*
18099ebb4caSwyllys * The tag and length have already been stripped off. We should
18199ebb4caSwyllys * be sitting right before len bytes of 2's complement integer,
18299ebb4caSwyllys * ready to be read straight into an int. We may have to sign
18399ebb4caSwyllys * extend after we read it in.
18499ebb4caSwyllys */
18599ebb4caSwyllys
186ab8b4e5cSWyllys Ingersoll if (len > sizeof (buffer))
18799ebb4caSwyllys return (-1);
18899ebb4caSwyllys
18999ebb4caSwyllys /* read into the low-order bytes of netnum */
19099ebb4caSwyllys if (kmfber_read(ber, (char *)buffer, len) != len)
19199ebb4caSwyllys return (-1);
19299ebb4caSwyllys
19399ebb4caSwyllys /* This sets the required sign extension */
19499ebb4caSwyllys if (len != 0) {
19599ebb4caSwyllys value = 0x80 & buffer[0] ? (-1) : 0;
19699ebb4caSwyllys } else {
19799ebb4caSwyllys value = 0;
19899ebb4caSwyllys }
19999ebb4caSwyllys
20099ebb4caSwyllys for (i = 0; i < len; i++)
20199ebb4caSwyllys value = (value << 8) | buffer[i];
20299ebb4caSwyllys
20399ebb4caSwyllys *num = value;
20499ebb4caSwyllys
20599ebb4caSwyllys return (len);
20699ebb4caSwyllys }
20799ebb4caSwyllys
20899ebb4caSwyllys static ber_tag_t
kmfber_get_int(BerElement * ber,ber_int_t * num)20999ebb4caSwyllys kmfber_get_int(BerElement *ber, ber_int_t *num)
21099ebb4caSwyllys {
21199ebb4caSwyllys ber_tag_t tag;
21299ebb4caSwyllys ber_len_t len;
21399ebb4caSwyllys
21499ebb4caSwyllys if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
21599ebb4caSwyllys return (KMFBER_DEFAULT);
21699ebb4caSwyllys
21799ebb4caSwyllys /*
21899ebb4caSwyllys * len is being demoted to a long here -- possible conversion error
21999ebb4caSwyllys */
22099ebb4caSwyllys
22199ebb4caSwyllys if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
22299ebb4caSwyllys return (KMFBER_DEFAULT);
22399ebb4caSwyllys else
22499ebb4caSwyllys return (tag);
22599ebb4caSwyllys }
22699ebb4caSwyllys
22799ebb4caSwyllys static ber_tag_t
kmfber_get_stringb(BerElement * ber,char * buf,ber_len_t * len)22899ebb4caSwyllys kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
22999ebb4caSwyllys {
23099ebb4caSwyllys ber_len_t datalen;
23199ebb4caSwyllys ber_tag_t tag;
23299ebb4caSwyllys #ifdef STR_TRANSLATION
23399ebb4caSwyllys char *transbuf;
23499ebb4caSwyllys #endif /* STR_TRANSLATION */
23599ebb4caSwyllys
23699ebb4caSwyllys if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
23799ebb4caSwyllys return (KMFBER_DEFAULT);
23899ebb4caSwyllys if (datalen > (*len - 1))
23999ebb4caSwyllys return (KMFBER_DEFAULT);
24099ebb4caSwyllys
24199ebb4caSwyllys /*
24299ebb4caSwyllys * datalen is being demoted to a long here -- possible conversion error
24399ebb4caSwyllys */
24499ebb4caSwyllys
24599ebb4caSwyllys if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
24699ebb4caSwyllys return (KMFBER_DEFAULT);
24799ebb4caSwyllys
24899ebb4caSwyllys buf[datalen] = '\0';
24999ebb4caSwyllys
25099ebb4caSwyllys #ifdef STR_TRANSLATION
25199ebb4caSwyllys if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
25299ebb4caSwyllys != 0 && ber->ber_decode_translate_proc != NULL) {
25399ebb4caSwyllys
25499ebb4caSwyllys transbuf = buf;
25599ebb4caSwyllys ++datalen;
25699ebb4caSwyllys if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
25799ebb4caSwyllys 0) != 0) {
25899ebb4caSwyllys return (KMFBER_DEFAULT);
25999ebb4caSwyllys }
26099ebb4caSwyllys if (datalen > *len) {
26199ebb4caSwyllys free(transbuf);
26299ebb4caSwyllys return (KMFBER_DEFAULT);
26399ebb4caSwyllys }
26499ebb4caSwyllys (void) memmove(buf, transbuf, datalen);
26599ebb4caSwyllys free(transbuf);
26699ebb4caSwyllys --datalen;
26799ebb4caSwyllys }
26899ebb4caSwyllys #endif /* STR_TRANSLATION */
26999ebb4caSwyllys
27099ebb4caSwyllys *len = datalen;
27199ebb4caSwyllys return (tag);
27299ebb4caSwyllys }
27399ebb4caSwyllys
27499ebb4caSwyllys static ber_tag_t
kmfber_get_stringa(BerElement * ber,char ** buf)27599ebb4caSwyllys kmfber_get_stringa(BerElement *ber, char **buf)
27699ebb4caSwyllys {
27799ebb4caSwyllys ber_len_t datalen;
27899ebb4caSwyllys ber_tag_t tag;
27999ebb4caSwyllys
28099ebb4caSwyllys if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
28199ebb4caSwyllys return (KMFBER_DEFAULT);
28299ebb4caSwyllys
28399ebb4caSwyllys if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
28499ebb4caSwyllys return (KMFBER_DEFAULT);
28599ebb4caSwyllys
28699ebb4caSwyllys /*
28799ebb4caSwyllys * datalen is being demoted to a long here -- possible conversion error
28899ebb4caSwyllys */
28999ebb4caSwyllys if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
29099ebb4caSwyllys return (KMFBER_DEFAULT);
29199ebb4caSwyllys (*buf)[datalen] = '\0';
29299ebb4caSwyllys
29399ebb4caSwyllys return (tag);
29499ebb4caSwyllys }
29599ebb4caSwyllys
29699ebb4caSwyllys ber_tag_t
ber_get_oid(BerElement * ber,struct berval * oid)29799ebb4caSwyllys ber_get_oid(BerElement *ber, struct berval *oid)
29899ebb4caSwyllys {
29999ebb4caSwyllys ber_len_t len;
30099ebb4caSwyllys ber_tag_t tag;
30199ebb4caSwyllys
30299ebb4caSwyllys if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
30399ebb4caSwyllys return (KMFBER_DEFAULT);
30499ebb4caSwyllys }
30599ebb4caSwyllys
30699ebb4caSwyllys if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
30799ebb4caSwyllys return (KMFBER_DEFAULT);
30899ebb4caSwyllys }
30999ebb4caSwyllys oid->bv_len = len;
31099ebb4caSwyllys
31199ebb4caSwyllys if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
31299ebb4caSwyllys (ber_slen_t)oid->bv_len)
31399ebb4caSwyllys return (KMFBER_DEFAULT);
31499ebb4caSwyllys
31599ebb4caSwyllys return (tag);
31699ebb4caSwyllys }
31799ebb4caSwyllys
31899ebb4caSwyllys ber_tag_t
ber_get_bigint(BerElement * ber,struct berval ** bv)31999ebb4caSwyllys ber_get_bigint(BerElement *ber, struct berval **bv)
32099ebb4caSwyllys {
32199ebb4caSwyllys ber_len_t len;
32299ebb4caSwyllys ber_tag_t tag;
32399ebb4caSwyllys
32499ebb4caSwyllys if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
32599ebb4caSwyllys == NULL) {
32699ebb4caSwyllys return (KMFBER_DEFAULT);
32799ebb4caSwyllys }
328d00756ccSwyllys (*bv)->bv_len = 0;
329d00756ccSwyllys (*bv)->bv_val = NULL;
33099ebb4caSwyllys
33199ebb4caSwyllys if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
33299ebb4caSwyllys return (KMFBER_DEFAULT);
33399ebb4caSwyllys }
33499ebb4caSwyllys
33599ebb4caSwyllys if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
33699ebb4caSwyllys == NULL) {
33799ebb4caSwyllys return (KMFBER_DEFAULT);
33899ebb4caSwyllys }
33999ebb4caSwyllys
34099ebb4caSwyllys /*
34199ebb4caSwyllys * len is being demoted to a long here -- possible conversion error
34299ebb4caSwyllys */
34399ebb4caSwyllys if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
34499ebb4caSwyllys return (KMFBER_DEFAULT);
34599ebb4caSwyllys
34699ebb4caSwyllys (*bv)->bv_len = len;
34799ebb4caSwyllys
348*e65e5c2dSWyllys Ingersoll /* If DER encoding, strip leading 0's if high-order bit is set */
34999ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) {
35099ebb4caSwyllys char *p = (*bv)->bv_val;
351*e65e5c2dSWyllys Ingersoll while ((*p == 0x00) && ((*bv)->bv_len > 0) && (p[1] & 0x80)) {
35299ebb4caSwyllys p++;
35399ebb4caSwyllys (*bv)->bv_len--;
35499ebb4caSwyllys }
35599ebb4caSwyllys /*
35699ebb4caSwyllys * Shift the buffer to the beginning of the allocated space
35799ebb4caSwyllys * so it can be properly freed later.
35899ebb4caSwyllys */
35999ebb4caSwyllys if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
36099ebb4caSwyllys (void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
36199ebb4caSwyllys }
36299ebb4caSwyllys
36399ebb4caSwyllys return (tag);
36499ebb4caSwyllys }
36599ebb4caSwyllys
36699ebb4caSwyllys static ber_tag_t
kmfber_get_stringal(BerElement * ber,struct berval ** bv)36799ebb4caSwyllys kmfber_get_stringal(BerElement *ber, struct berval **bv)
36899ebb4caSwyllys {
36999ebb4caSwyllys ber_len_t len;
37099ebb4caSwyllys ber_tag_t tag;
37199ebb4caSwyllys
37299ebb4caSwyllys if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
37399ebb4caSwyllys == NULL) {
37499ebb4caSwyllys return (KMFBER_DEFAULT);
37599ebb4caSwyllys }
37699ebb4caSwyllys
37799ebb4caSwyllys if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
37899ebb4caSwyllys return (KMFBER_DEFAULT);
37999ebb4caSwyllys }
38099ebb4caSwyllys
38199ebb4caSwyllys if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
38299ebb4caSwyllys == NULL) {
38399ebb4caSwyllys return (KMFBER_DEFAULT);
38499ebb4caSwyllys }
38599ebb4caSwyllys
38699ebb4caSwyllys /*
38799ebb4caSwyllys * len is being demoted to a long here -- possible conversion error
38899ebb4caSwyllys */
38999ebb4caSwyllys if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
39099ebb4caSwyllys return (KMFBER_DEFAULT);
39199ebb4caSwyllys ((*bv)->bv_val)[len] = '\0';
39299ebb4caSwyllys (*bv)->bv_len = len;
39399ebb4caSwyllys
39499ebb4caSwyllys return (tag);
39599ebb4caSwyllys }
39699ebb4caSwyllys
39799ebb4caSwyllys static ber_tag_t
kmfber_get_bitstringa(BerElement * ber,char ** buf,ber_len_t * blen)39899ebb4caSwyllys kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
39999ebb4caSwyllys {
40099ebb4caSwyllys ber_len_t datalen;
40199ebb4caSwyllys ber_tag_t tag;
40299ebb4caSwyllys unsigned char unusedbits;
40399ebb4caSwyllys
40499ebb4caSwyllys if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
40599ebb4caSwyllys return (KMFBER_DEFAULT);
40699ebb4caSwyllys
40799ebb4caSwyllys if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
40899ebb4caSwyllys return (KMFBER_DEFAULT);
40999ebb4caSwyllys
41099ebb4caSwyllys if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
41199ebb4caSwyllys return (KMFBER_DEFAULT);
41299ebb4caSwyllys
41399ebb4caSwyllys /* Subtract 1 for the unused bits */
41499ebb4caSwyllys datalen--;
41599ebb4caSwyllys
41699ebb4caSwyllys /*
41799ebb4caSwyllys * datalen is being demoted to a long here -- possible conversion error
41899ebb4caSwyllys */
41999ebb4caSwyllys if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
42099ebb4caSwyllys return (KMFBER_DEFAULT);
42199ebb4caSwyllys
42299ebb4caSwyllys *blen = datalen * 8 - unusedbits;
42399ebb4caSwyllys return (tag);
42499ebb4caSwyllys }
42599ebb4caSwyllys
42699ebb4caSwyllys static ber_tag_t
kmfber_get_null(BerElement * ber)42799ebb4caSwyllys kmfber_get_null(BerElement *ber)
42899ebb4caSwyllys {
42999ebb4caSwyllys ber_len_t len;
43099ebb4caSwyllys ber_tag_t tag;
43199ebb4caSwyllys
43299ebb4caSwyllys if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
43399ebb4caSwyllys return (KMFBER_DEFAULT);
43499ebb4caSwyllys
43599ebb4caSwyllys if (len != 0)
43699ebb4caSwyllys return (KMFBER_DEFAULT);
43799ebb4caSwyllys
43899ebb4caSwyllys return (tag);
43999ebb4caSwyllys }
44099ebb4caSwyllys
44199ebb4caSwyllys static ber_tag_t
kmfber_get_boolean(BerElement * ber,int * boolval)44299ebb4caSwyllys kmfber_get_boolean(BerElement *ber, int *boolval)
44399ebb4caSwyllys {
44499ebb4caSwyllys ber_int_t longbool;
44599ebb4caSwyllys int rc;
44699ebb4caSwyllys
44799ebb4caSwyllys rc = kmfber_get_int(ber, &longbool);
44899ebb4caSwyllys *boolval = longbool;
44999ebb4caSwyllys
45099ebb4caSwyllys return (rc);
45199ebb4caSwyllys }
45299ebb4caSwyllys
45399ebb4caSwyllys ber_tag_t
kmfber_first_element(BerElement * ber,ber_len_t * len,char ** last)45499ebb4caSwyllys kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
45599ebb4caSwyllys {
45699ebb4caSwyllys /* skip the sequence header, use the len to mark where to stop */
45799ebb4caSwyllys if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
45899ebb4caSwyllys return (KMFBER_ERROR);
45999ebb4caSwyllys }
46099ebb4caSwyllys
46199ebb4caSwyllys *last = ber->ber_ptr + *len;
46299ebb4caSwyllys
46399ebb4caSwyllys if (*last == ber->ber_ptr) {
46499ebb4caSwyllys return (KMFBER_END_OF_SEQORSET);
46599ebb4caSwyllys }
46699ebb4caSwyllys
46799ebb4caSwyllys return (kmfber_peek_tag(ber, len));
46899ebb4caSwyllys }
46999ebb4caSwyllys
47099ebb4caSwyllys ber_tag_t
kmfber_next_element(BerElement * ber,ber_len_t * len,char * last)47199ebb4caSwyllys kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
47299ebb4caSwyllys {
47399ebb4caSwyllys if (ber->ber_ptr == last) {
47499ebb4caSwyllys return (KMFBER_END_OF_SEQORSET);
47599ebb4caSwyllys }
47699ebb4caSwyllys
47799ebb4caSwyllys return (kmfber_peek_tag(ber, len));
47899ebb4caSwyllys }
47999ebb4caSwyllys
48099ebb4caSwyllys void
kmfber_bvfree(struct berval * bv)48199ebb4caSwyllys kmfber_bvfree(struct berval *bv)
48299ebb4caSwyllys {
48399ebb4caSwyllys if (bv != NULL) {
48499ebb4caSwyllys if (bv->bv_val != NULL) {
48599ebb4caSwyllys free(bv->bv_val);
48699ebb4caSwyllys }
48799ebb4caSwyllys free((char *)bv);
48899ebb4caSwyllys }
48999ebb4caSwyllys }
49099ebb4caSwyllys
49199ebb4caSwyllys void
kmfber_bvecfree(struct berval ** bv)49299ebb4caSwyllys kmfber_bvecfree(struct berval **bv)
49399ebb4caSwyllys {
49499ebb4caSwyllys int i;
49599ebb4caSwyllys
49699ebb4caSwyllys if (bv != NULL) {
49799ebb4caSwyllys for (i = 0; bv[i] != NULL; i++) {
49899ebb4caSwyllys kmfber_bvfree(bv[i]);
49999ebb4caSwyllys }
50099ebb4caSwyllys free((char *)bv);
50199ebb4caSwyllys }
50299ebb4caSwyllys }
50399ebb4caSwyllys
50499ebb4caSwyllys /* VARARGS */
50599ebb4caSwyllys ber_tag_t
kmfber_scanf(BerElement * ber,const char * fmt,...)50699ebb4caSwyllys kmfber_scanf(BerElement *ber, const char *fmt, ...)
50799ebb4caSwyllys {
50899ebb4caSwyllys va_list ap;
50999ebb4caSwyllys char *last, *p;
51099ebb4caSwyllys char *s, **ss, ***sss;
51199ebb4caSwyllys struct berval ***bv, **bvp, *bval;
51299ebb4caSwyllys int *i, j;
51399ebb4caSwyllys ber_slen_t *l;
51499ebb4caSwyllys ber_int_t rc, tag, *b_int;
51599ebb4caSwyllys ber_tag_t *t;
51699ebb4caSwyllys ber_len_t len;
51799ebb4caSwyllys size_t array_size;
51899ebb4caSwyllys
51999ebb4caSwyllys va_start(ap, fmt);
52099ebb4caSwyllys
52199ebb4caSwyllys for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
52299ebb4caSwyllys switch (*p) {
52399ebb4caSwyllys case 'a': /* octet string - allocate storage as needed */
52499ebb4caSwyllys ss = va_arg(ap, char **);
52599ebb4caSwyllys rc = kmfber_get_stringa(ber, ss);
52699ebb4caSwyllys break;
52799ebb4caSwyllys
52899ebb4caSwyllys case 'b': /* boolean */
52999ebb4caSwyllys i = va_arg(ap, int *);
53099ebb4caSwyllys rc = kmfber_get_boolean(ber, i);
53199ebb4caSwyllys break;
53299ebb4caSwyllys
53399ebb4caSwyllys case 'D': /* Object ID */
53499ebb4caSwyllys bval = va_arg(ap, struct berval *);
53599ebb4caSwyllys rc = ber_get_oid(ber, bval);
53699ebb4caSwyllys break;
53799ebb4caSwyllys case 'e': /* enumerated */
53899ebb4caSwyllys case 'i': /* int */
53999ebb4caSwyllys b_int = va_arg(ap, ber_int_t *);
54099ebb4caSwyllys rc = kmfber_get_int(ber, b_int);
54199ebb4caSwyllys break;
54299ebb4caSwyllys
54399ebb4caSwyllys case 'l': /* length of next item */
54499ebb4caSwyllys l = va_arg(ap, ber_slen_t *);
54599ebb4caSwyllys rc = kmfber_peek_tag(ber, (ber_len_t *)l);
54699ebb4caSwyllys break;
54799ebb4caSwyllys
54899ebb4caSwyllys case 'n': /* null */
54999ebb4caSwyllys rc = kmfber_get_null(ber);
55099ebb4caSwyllys break;
55199ebb4caSwyllys
55299ebb4caSwyllys case 's': /* octet string - in a buffer */
55399ebb4caSwyllys s = va_arg(ap, char *);
55499ebb4caSwyllys l = va_arg(ap, ber_slen_t *);
55599ebb4caSwyllys rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
55699ebb4caSwyllys break;
55799ebb4caSwyllys
55899ebb4caSwyllys case 'o': /* octet string in a supplied berval */
55999ebb4caSwyllys bval = va_arg(ap, struct berval *);
56099ebb4caSwyllys (void) kmfber_peek_tag(ber, &bval->bv_len);
56199ebb4caSwyllys rc = kmfber_get_stringa(ber, &bval->bv_val);
56299ebb4caSwyllys break;
56399ebb4caSwyllys
56499ebb4caSwyllys case 'I': /* variable length Integer */
56599ebb4caSwyllys /* Treat INTEGER same as an OCTET string, but ignore the tag */
56699ebb4caSwyllys bvp = va_arg(ap, struct berval **);
56799ebb4caSwyllys rc = ber_get_bigint(ber, bvp);
56899ebb4caSwyllys break;
56999ebb4caSwyllys case 'O': /* octet string - allocate & include length */
57099ebb4caSwyllys bvp = va_arg(ap, struct berval **);
57199ebb4caSwyllys rc = kmfber_get_stringal(ber, bvp);
57299ebb4caSwyllys break;
57399ebb4caSwyllys
57499ebb4caSwyllys case 'B': /* bit string - allocate storage as needed */
57599ebb4caSwyllys ss = va_arg(ap, char **);
57699ebb4caSwyllys l = va_arg(ap, ber_slen_t *); /* for length, in bits */
57799ebb4caSwyllys rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
57899ebb4caSwyllys break;
57999ebb4caSwyllys
58099ebb4caSwyllys case 't': /* tag of next item */
58199ebb4caSwyllys t = va_arg(ap, ber_tag_t *);
58299ebb4caSwyllys *t = kmfber_peek_tag(ber, &len);
58399ebb4caSwyllys rc = (ber_int_t)(*t);
58499ebb4caSwyllys break;
58599ebb4caSwyllys
58699ebb4caSwyllys case 'T': /* skip tag of next item */
58799ebb4caSwyllys t = va_arg(ap, ber_tag_t *);
58899ebb4caSwyllys *t = kmfber_skip_tag(ber, &len);
58999ebb4caSwyllys rc = (ber_int_t)(*t);
59099ebb4caSwyllys break;
59199ebb4caSwyllys
59299ebb4caSwyllys case 'v': /* sequence of strings */
59399ebb4caSwyllys sss = va_arg(ap, char ***);
594d00756ccSwyllys if (sss == NULL)
595d00756ccSwyllys break;
59699ebb4caSwyllys *sss = NULL;
59799ebb4caSwyllys j = 0;
59899ebb4caSwyllys array_size = 0;
59999ebb4caSwyllys for (tag = kmfber_first_element(ber, &len, &last);
60099ebb4caSwyllys (tag != KMFBER_DEFAULT &&
60199ebb4caSwyllys tag != KMFBER_END_OF_SEQORSET &&
60299ebb4caSwyllys rc != KMFBER_DEFAULT);
60399ebb4caSwyllys tag = kmfber_next_element(ber, &len, last)) {
60499ebb4caSwyllys if (*sss == NULL) {
60599ebb4caSwyllys /* Make room for at least 15 strings */
60699ebb4caSwyllys *sss = (char **)malloc(16 * sizeof (char *));
60799ebb4caSwyllys array_size = 16;
60899ebb4caSwyllys } else {
60999ebb4caSwyllys if ((size_t)(j+2) > array_size) {
61099ebb4caSwyllys /* We'v overflowed our buffer */
61199ebb4caSwyllys *sss = (char **)realloc(*sss,
61299ebb4caSwyllys (array_size * 2) * sizeof (char *));
61399ebb4caSwyllys array_size = array_size * 2;
61499ebb4caSwyllys }
61599ebb4caSwyllys }
61699ebb4caSwyllys rc = kmfber_get_stringa(ber, &((*sss)[j]));
61799ebb4caSwyllys j++;
61899ebb4caSwyllys }
619d00756ccSwyllys if (rc != KMFBER_DEFAULT && tag != KMFBER_END_OF_SEQORSET) {
62099ebb4caSwyllys rc = KMFBER_DEFAULT;
62199ebb4caSwyllys }
62299ebb4caSwyllys if (j > 0)
62399ebb4caSwyllys (*sss)[j] = NULL;
62499ebb4caSwyllys break;
62599ebb4caSwyllys
62699ebb4caSwyllys case 'V': /* sequence of strings + lengths */
62799ebb4caSwyllys bv = va_arg(ap, struct berval ***);
62899ebb4caSwyllys *bv = NULL;
62999ebb4caSwyllys j = 0;
63099ebb4caSwyllys for (tag = kmfber_first_element(ber, &len, &last);
63199ebb4caSwyllys (tag != KMFBER_DEFAULT &&
63299ebb4caSwyllys tag != KMFBER_END_OF_SEQORSET &&
63399ebb4caSwyllys rc != KMFBER_DEFAULT);
63499ebb4caSwyllys tag = kmfber_next_element(ber, &len, last)) {
63599ebb4caSwyllys if (*bv == NULL) {
63699ebb4caSwyllys *bv = (struct berval **)malloc(
63799ebb4caSwyllys 2 * sizeof (struct berval *));
63899ebb4caSwyllys } else {
63999ebb4caSwyllys *bv = (struct berval **)realloc(*bv,
64099ebb4caSwyllys (j + 2) * sizeof (struct berval *));
64199ebb4caSwyllys }
64299ebb4caSwyllys rc = kmfber_get_stringal(ber, &((*bv)[j]));
64399ebb4caSwyllys j++;
64499ebb4caSwyllys }
64599ebb4caSwyllys if (rc != KMFBER_DEFAULT &&
64699ebb4caSwyllys tag != KMFBER_END_OF_SEQORSET) {
64799ebb4caSwyllys rc = KMFBER_DEFAULT;
64899ebb4caSwyllys }
64999ebb4caSwyllys if (j > 0)
65099ebb4caSwyllys (*bv)[j] = NULL;
65199ebb4caSwyllys break;
65299ebb4caSwyllys
65399ebb4caSwyllys case 'x': /* skip the next element - whatever it is */
65499ebb4caSwyllys if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
65599ebb4caSwyllys break;
65699ebb4caSwyllys ber->ber_ptr += len;
65799ebb4caSwyllys break;
65899ebb4caSwyllys
65999ebb4caSwyllys case '{': /* begin sequence */
66099ebb4caSwyllys case '[': /* begin set */
66199ebb4caSwyllys if (*(p + 1) != 'v' && *(p + 1) != 'V')
66299ebb4caSwyllys rc = kmfber_skip_tag(ber, &len);
66399ebb4caSwyllys break;
66499ebb4caSwyllys
66599ebb4caSwyllys case '}': /* end sequence */
66699ebb4caSwyllys case ']': /* end set */
66799ebb4caSwyllys break;
66899ebb4caSwyllys
66999ebb4caSwyllys default:
67099ebb4caSwyllys rc = KMFBER_DEFAULT;
67199ebb4caSwyllys break;
67299ebb4caSwyllys }
67399ebb4caSwyllys }
67499ebb4caSwyllys
67599ebb4caSwyllys
67699ebb4caSwyllys va_end(ap);
67799ebb4caSwyllys if (rc == KMFBER_DEFAULT) {
67899ebb4caSwyllys va_start(ap, fmt);
67999ebb4caSwyllys for (p--; fmt < p && *fmt; fmt++) {
68099ebb4caSwyllys switch (*fmt) {
68199ebb4caSwyllys case 'a': /* octet string - allocate storage as needed */
68299ebb4caSwyllys ss = va_arg(ap, char **);
683d00756ccSwyllys if (ss != NULL && *ss != NULL) {
68499ebb4caSwyllys free(*ss);
68599ebb4caSwyllys *ss = NULL;
686d00756ccSwyllys }
68799ebb4caSwyllys break;
68899ebb4caSwyllys
68999ebb4caSwyllys case 'b': /* boolean */
69099ebb4caSwyllys i = va_arg(ap, int *);
69199ebb4caSwyllys break;
69299ebb4caSwyllys
69399ebb4caSwyllys case 'e': /* enumerated */
69499ebb4caSwyllys case 'i': /* int */
69599ebb4caSwyllys l = va_arg(ap, ber_slen_t *);
69699ebb4caSwyllys break;
69799ebb4caSwyllys
69899ebb4caSwyllys case 'l': /* length of next item */
69999ebb4caSwyllys l = va_arg(ap, ber_slen_t *);
70099ebb4caSwyllys break;
70199ebb4caSwyllys
70299ebb4caSwyllys case 'n': /* null */
70399ebb4caSwyllys break;
70499ebb4caSwyllys
70599ebb4caSwyllys case 's': /* octet string - in a buffer */
70699ebb4caSwyllys s = va_arg(ap, char *);
70799ebb4caSwyllys l = va_arg(ap, ber_slen_t *);
70899ebb4caSwyllys break;
70999ebb4caSwyllys
71099ebb4caSwyllys case 'o': /* octet string in a supplied berval */
71199ebb4caSwyllys bval = va_arg(ap, struct berval *);
71299ebb4caSwyllys if (bval->bv_val) free(bval->bv_val);
71399ebb4caSwyllys (void) memset(bval, 0, sizeof (struct berval));
71499ebb4caSwyllys break;
71599ebb4caSwyllys
71699ebb4caSwyllys case 'O': /* octet string - allocate & include length */
71799ebb4caSwyllys bvp = va_arg(ap, struct berval **);
71899ebb4caSwyllys kmfber_bvfree(*bvp);
71999ebb4caSwyllys bvp = NULL;
72099ebb4caSwyllys break;
72199ebb4caSwyllys
72299ebb4caSwyllys case 'B': /* bit string - allocate storage as needed */
72399ebb4caSwyllys ss = va_arg(ap, char **);
72499ebb4caSwyllys l = va_arg(ap, ber_slen_t *); /* for length, in bits */
725d00756ccSwyllys if (ss != NULL && *ss != NULL) {
726d00756ccSwyllys free(*ss);
72799ebb4caSwyllys *ss = NULL;
728d00756ccSwyllys }
72999ebb4caSwyllys break;
73099ebb4caSwyllys
73199ebb4caSwyllys case 't': /* tag of next item */
73299ebb4caSwyllys t = va_arg(ap, ber_tag_t *);
73399ebb4caSwyllys break;
73499ebb4caSwyllys case 'T': /* skip tag of next item */
73599ebb4caSwyllys t = va_arg(ap, ber_tag_t *);
73699ebb4caSwyllys break;
73799ebb4caSwyllys
73899ebb4caSwyllys case 'v': /* sequence of strings */
73999ebb4caSwyllys sss = va_arg(ap, char ***);
740d00756ccSwyllys if (sss != NULL && *sss != NULL) {
74199ebb4caSwyllys ber_svecfree(*sss);
74299ebb4caSwyllys *sss = NULL;
743d00756ccSwyllys }
74499ebb4caSwyllys break;
74599ebb4caSwyllys
74699ebb4caSwyllys case 'V': /* sequence of strings + lengths */
74799ebb4caSwyllys bv = va_arg(ap, struct berval ***);
74899ebb4caSwyllys kmfber_bvecfree(*bv);
74999ebb4caSwyllys *bv = NULL;
75099ebb4caSwyllys break;
75199ebb4caSwyllys
75299ebb4caSwyllys case 'x': /* skip the next element - whatever it is */
75399ebb4caSwyllys break;
75499ebb4caSwyllys
75599ebb4caSwyllys case '{': /* begin sequence */
75699ebb4caSwyllys case '[': /* begin set */
75799ebb4caSwyllys break;
75899ebb4caSwyllys
75999ebb4caSwyllys case '}': /* end sequence */
76099ebb4caSwyllys case ']': /* end set */
76199ebb4caSwyllys break;
76299ebb4caSwyllys
76399ebb4caSwyllys default:
76499ebb4caSwyllys break;
76599ebb4caSwyllys }
76699ebb4caSwyllys } /* for */
76799ebb4caSwyllys va_end(ap);
76899ebb4caSwyllys } /* if */
76999ebb4caSwyllys
77099ebb4caSwyllys return (rc);
77199ebb4caSwyllys }
77299ebb4caSwyllys
77399ebb4caSwyllys struct berval *
kmfber_bvdup(const struct berval * bv)77499ebb4caSwyllys kmfber_bvdup(const struct berval *bv)
77599ebb4caSwyllys {
77699ebb4caSwyllys struct berval *new;
77799ebb4caSwyllys
77899ebb4caSwyllys if ((new = (struct berval *)malloc(sizeof (struct berval)))
77999ebb4caSwyllys == NULL) {
78099ebb4caSwyllys return (NULL);
78199ebb4caSwyllys }
78299ebb4caSwyllys if (bv->bv_val == NULL) {
78399ebb4caSwyllys new->bv_val = NULL;
78499ebb4caSwyllys new->bv_len = 0;
78599ebb4caSwyllys } else {
78699ebb4caSwyllys if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
78799ebb4caSwyllys == NULL) {
78899ebb4caSwyllys return (NULL);
78999ebb4caSwyllys }
79099ebb4caSwyllys (void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
79199ebb4caSwyllys new->bv_val[bv->bv_len] = '\0';
79299ebb4caSwyllys new->bv_len = bv->bv_len;
79399ebb4caSwyllys }
79499ebb4caSwyllys
79599ebb4caSwyllys return (new);
79699ebb4caSwyllys }
797