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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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