xref: /onnv-gate/usr/src/lib/libkmf/ber_der/common/io.c (revision 11221:b211d0a04b63)
13089Swyllys /*
23089Swyllys  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
33089Swyllys  *
43089Swyllys  * The contents of this file are subject to the Netscape Public License
53089Swyllys  * Version 1.0 (the "NPL"); you may not use this file except in
63089Swyllys  * compliance with the NPL.  You may obtain a copy of the NPL at
73089Swyllys  * http://www.mozilla.org/NPL/
83089Swyllys  *
93089Swyllys  * Software distributed under the NPL is distributed on an "AS IS" basis,
103089Swyllys  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
113089Swyllys  * for the specific language governing rights and limitations under the
123089Swyllys  * NPL.
133089Swyllys  *
143089Swyllys  * The Initial Developer of this code under the NPL is Netscape
153089Swyllys  * Communications Corporation.  Portions created by Netscape are
163089Swyllys  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
173089Swyllys  * Reserved.
183089Swyllys  */
193089Swyllys 
203089Swyllys /*
213089Swyllys  * Copyright (c) 1990 Regents of the University of Michigan.
223089Swyllys  * All rights reserved.
233089Swyllys  *
243089Swyllys  * Redistribution and use in source and binary forms are permitted
253089Swyllys  * provided that this notice is preserved and that due credit is given
263089Swyllys  * to the University of Michigan at Ann Arbor. The name of the University
273089Swyllys  * may not be used to endorse or promote products derived from this
283089Swyllys  * software without specific prior written permission. This software
293089Swyllys  * is provided ``as is'' without express or implied warranty.
303089Swyllys  */
313089Swyllys /*
3210818Swyllys.ingersoll@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
333089Swyllys  * Use is subject to license terms.
343089Swyllys  */
353089Swyllys 
363089Swyllys #include <stdlib.h>
373089Swyllys #include <ber_der.h>
383089Swyllys #include "kmfber_int.h"
393089Swyllys 
403089Swyllys #define	EXBUFSIZ	1024
413089Swyllys 
423089Swyllys /*
433089Swyllys  * Note: kmfber_read() only uses the ber_end and ber_ptr elements of ber.
443089Swyllys  * Functions like kmfber_get_tag(), kmfber_skip_tag, and kmfber_peek_tag()
453089Swyllys  * rely on that fact, so if this code is changed to use any additional
463089Swyllys  * elements of the ber structure, those functions will need to be changed
473089Swyllys  * as well.
483089Swyllys  */
493089Swyllys ber_int_t
kmfber_read(BerElement * ber,char * buf,ber_len_t len)503089Swyllys kmfber_read(BerElement *ber, char *buf, ber_len_t len)
513089Swyllys {
523089Swyllys 	size_t	actuallen;
533089Swyllys 	size_t	nleft;
543089Swyllys 
553089Swyllys 	nleft = ber->ber_end - ber->ber_ptr;
563089Swyllys 	actuallen = nleft < len ? nleft : len;
573089Swyllys 
583089Swyllys 	(void) memmove(buf, ber->ber_ptr, (size_t)actuallen);
593089Swyllys 
603089Swyllys 	ber->ber_ptr += actuallen;
613089Swyllys 
623089Swyllys 	return ((ber_int_t)actuallen);
633089Swyllys }
643089Swyllys 
653089Swyllys /*
663089Swyllys  * enlarge the ber buffer.
673089Swyllys  * return 0 on success, -1 on error.
683089Swyllys  */
6910818Swyllys.ingersoll@sun.com int
kmfber_realloc(BerElement * ber,ber_len_t len)703089Swyllys kmfber_realloc(BerElement *ber, ber_len_t len)
713089Swyllys {
723089Swyllys 	ber_uint_t	need, have, total;
733089Swyllys 	size_t		have_bytes;
743089Swyllys 	Seqorset	*s;
753089Swyllys 	size_t		off;
763089Swyllys 	char		*oldbuf;
773089Swyllys 
783089Swyllys 	have_bytes = ber->ber_end - ber->ber_buf;
793089Swyllys 	have = have_bytes / EXBUFSIZ;
803089Swyllys 	need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
813089Swyllys 	total = have * EXBUFSIZ + need * EXBUFSIZ;
823089Swyllys 
833089Swyllys 	oldbuf = ber->ber_buf;
843089Swyllys 
853089Swyllys 	if (ber->ber_buf == NULL) {
863089Swyllys 		if ((ber->ber_buf = (char *)malloc((size_t)total))
873089Swyllys 		    == NULL) {
883089Swyllys 			return (-1);
893089Swyllys 		}
903089Swyllys 		ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
913089Swyllys 	} else {
923089Swyllys 		if (ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER) {
933089Swyllys 			/* transition to malloc'd buffer */
943089Swyllys 			if ((ber->ber_buf = (char *)malloc(
953089Swyllys 			    (size_t)total)) == NULL) {
963089Swyllys 				return (-1);
973089Swyllys 			}
983089Swyllys 			ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
99*11221Swyllys.ingersoll@sun.com 
1003089Swyllys 			/* copy existing data into new malloc'd buffer */
1013089Swyllys 			(void) memmove(ber->ber_buf, oldbuf, have_bytes);
1023089Swyllys 		} else {
1033089Swyllys 			if ((ber->ber_buf = (char *)realloc(
104*11221Swyllys.ingersoll@sun.com 			    oldbuf, (size_t)total)) == NULL) {
105*11221Swyllys.ingersoll@sun.com 				free(oldbuf);
1063089Swyllys 				return (-1);
1073089Swyllys 			}
1083089Swyllys 		}
1093089Swyllys 	}
1103089Swyllys 
1113089Swyllys 	ber->ber_end = ber->ber_buf + total;
1123089Swyllys 
1133089Swyllys 	/*
1143089Swyllys 	 * If the stinking thing was moved, we need to go through and
1153089Swyllys 	 * reset all the sos and ber pointers.  Offsets would've been
1163089Swyllys 	 * a better idea... oh well.
1173089Swyllys 	 */
1183089Swyllys 	if (ber->ber_buf != oldbuf) {
1193089Swyllys 		ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
1203089Swyllys 
1213089Swyllys 		for (s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next) {
1223089Swyllys 			off = s->sos_first - oldbuf;
1233089Swyllys 			s->sos_first = ber->ber_buf + off;
1243089Swyllys 
1253089Swyllys 			off = s->sos_ptr - oldbuf;
1263089Swyllys 			s->sos_ptr = ber->ber_buf + off;
1273089Swyllys 		}
1283089Swyllys 	}
1293089Swyllys 
1303089Swyllys 	return (0);
1313089Swyllys }
1323089Swyllys 
1333089Swyllys /*
1343089Swyllys  * returns "len" on success and -1 on failure.
1353089Swyllys  */
1363089Swyllys ber_int_t
kmfber_write(BerElement * ber,char * buf,ber_len_t len,int nosos)1373089Swyllys kmfber_write(BerElement *ber, char *buf, ber_len_t len, int nosos)
1383089Swyllys {
1393089Swyllys 	if (nosos || ber->ber_sos == NULL) {
1403089Swyllys 		if (ber->ber_ptr + len > ber->ber_end) {
1413089Swyllys 			if (kmfber_realloc(ber, len) != 0)
1423089Swyllys 				return (-1);
1433089Swyllys 		}
1443089Swyllys 		(void) memmove(ber->ber_ptr, buf, (size_t)len);
1453089Swyllys 		ber->ber_ptr += len;
1463089Swyllys 		return (len);
1473089Swyllys 	} else {
1483089Swyllys 		if (ber->ber_sos->sos_ptr + len > ber->ber_end) {
1493089Swyllys 			if (kmfber_realloc(ber, len) != 0)
1503089Swyllys 				return (-1);
1513089Swyllys 		}
1523089Swyllys 		(void) memmove(ber->ber_sos->sos_ptr, buf, (size_t)len);
1533089Swyllys 		ber->ber_sos->sos_ptr += len;
1543089Swyllys 		ber->ber_sos->sos_clen += len;
1553089Swyllys 		return (len);
1563089Swyllys 	}
1573089Swyllys }
1583089Swyllys 
1593089Swyllys void
kmfber_free(BerElement * ber,int freebuf)1603089Swyllys kmfber_free(BerElement *ber, int freebuf)
1613089Swyllys {
1623089Swyllys 	if (ber != NULL) {
16310818Swyllys.ingersoll@sun.com 		if (freebuf &&
16410818Swyllys.ingersoll@sun.com 		    !(ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER))
16510818Swyllys.ingersoll@sun.com 			free(ber->ber_buf);
16610818Swyllys.ingersoll@sun.com 		free((char *)ber);
1673089Swyllys 	}
1683089Swyllys }
1693089Swyllys 
1703089Swyllys /* we pre-allocate a buffer to save the extra malloc later */
1713089Swyllys BerElement *
kmfber_alloc_t(int options)1723089Swyllys kmfber_alloc_t(int options)
1733089Swyllys {
1743089Swyllys 	BerElement	*ber;
1753089Swyllys 
1763089Swyllys 	if ((ber = (BerElement*)calloc(1,
1773089Swyllys 	    sizeof (struct berelement) + EXBUFSIZ)) == NULL) {
1783089Swyllys 		return (NULL);
1793089Swyllys 	}
1803089Swyllys 
1813089Swyllys 	ber->ber_tag = KMFBER_DEFAULT;
1823089Swyllys 	ber->ber_options = options;
1833089Swyllys 	ber->ber_buf = (char *)ber + sizeof (struct berelement);
1843089Swyllys 	ber->ber_ptr = ber->ber_buf;
1853089Swyllys 	ber->ber_end = ber->ber_buf + EXBUFSIZ;
1863089Swyllys 	ber->ber_flags = KMFBER_FLAG_NO_FREE_BUFFER;
1873089Swyllys 
1883089Swyllys 	return (ber);
1893089Swyllys }
1903089Swyllys 
1913089Swyllys 
1923089Swyllys BerElement *
kmfber_alloc()1933089Swyllys kmfber_alloc()
1943089Swyllys {
1953089Swyllys 	return (kmfber_alloc_t(0));
1963089Swyllys }
1973089Swyllys 
1983089Swyllys BerElement *
kmfder_alloc()1993089Swyllys kmfder_alloc()
2003089Swyllys {
2013089Swyllys 	return (kmfber_alloc_t(KMFBER_OPT_USE_DER));
2023089Swyllys }
2033089Swyllys 
2043089Swyllys BerElement *
kmfber_dup(BerElement * ber)2053089Swyllys kmfber_dup(BerElement *ber)
2063089Swyllys {
2073089Swyllys 	BerElement	*new;
2083089Swyllys 
2093089Swyllys 	if ((new = kmfber_alloc()) == NULL)
2103089Swyllys 		return (NULL);
2113089Swyllys 
2123089Swyllys 	*new = *ber;
2133089Swyllys 
2143089Swyllys 	return (new);
2153089Swyllys }
2163089Swyllys 
2173089Swyllys 
2183089Swyllys void
ber_init_w_nullchar(BerElement * ber,int options)2193089Swyllys ber_init_w_nullchar(BerElement *ber, int options)
2203089Swyllys {
2213089Swyllys 	(void) memset((char *)ber, '\0', sizeof (struct berelement));
2223089Swyllys 	ber->ber_tag = KMFBER_DEFAULT;
2233089Swyllys 
2243089Swyllys 	ber->ber_options = options;
2253089Swyllys }
2263089Swyllys 
2273089Swyllys 
2283089Swyllys void
kmfber_reset(BerElement * ber,int was_writing)2293089Swyllys kmfber_reset(BerElement *ber, int was_writing)
2303089Swyllys {
2313089Swyllys 	if (was_writing) {
2323089Swyllys 		ber->ber_end = ber->ber_ptr;
2333089Swyllys 		ber->ber_ptr = ber->ber_buf;
2343089Swyllys 	} else {
2353089Swyllys 		ber->ber_ptr = ber->ber_end;
2363089Swyllys 	}
2373089Swyllys 
2383089Swyllys 	ber->ber_rwptr = NULL;
2393089Swyllys }
2403089Swyllys 
2413089Swyllys 
2423089Swyllys #ifdef KMFBER_DEBUG
2433089Swyllys 
2443089Swyllys void
ber_dump(BerElement * ber,int inout)2453089Swyllys ber_dump(BerElement *ber, int inout)
2463089Swyllys {
2473089Swyllys 	char msg[128];
2483089Swyllys 	sprintf(msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
2493089Swyllys 	    ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end);
2503089Swyllys 	ber_err_print(msg);
2513089Swyllys 	if (inout == 1) {
2523089Swyllys 		sprintf(msg, "          current len %ld, contents:\n",
2533089Swyllys 		    ber->ber_end - ber->ber_ptr);
2543089Swyllys 		ber_err_print(msg);
2553089Swyllys 		lber_bprint(ber->ber_ptr, ber->ber_end - ber->ber_ptr);
2563089Swyllys 	} else {
2573089Swyllys 		sprintf(msg, "          current len %ld, contents:\n",
2583089Swyllys 		    ber->ber_ptr - ber->ber_buf);
2593089Swyllys 		ber_err_print(msg);
2603089Swyllys 		lber_bprint(ber->ber_buf, ber->ber_ptr - ber->ber_buf);
2613089Swyllys 	}
2623089Swyllys }
2633089Swyllys 
2643089Swyllys void
ber_sos_dump(Seqorset * sos)2653089Swyllys ber_sos_dump(Seqorset *sos)
2663089Swyllys {
2673089Swyllys 	char msg[80];
2683089Swyllys 	ber_err_print("*** sos dump ***\n");
2693089Swyllys 	while (sos != NULLSEQORSET) {
2703089Swyllys 		sprintf(msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
2713089Swyllys 		    sos->sos_clen, sos->sos_first, sos->sos_ptr);
2723089Swyllys 		ber_err_print(msg);
2733089Swyllys 		sprintf(msg, "              current len %ld contents:\n",
2743089Swyllys 		    sos->sos_ptr - sos->sos_first);
2753089Swyllys 		ber_err_print(msg);
2763089Swyllys 		lber_bprint(sos->sos_first, sos->sos_ptr - sos->sos_first);
2773089Swyllys 
2783089Swyllys 		sos = sos->sos_next;
2793089Swyllys 	}
2803089Swyllys 	ber_err_print("*** end dump ***\n");
2813089Swyllys }
2823089Swyllys 
2833089Swyllys #endif
2843089Swyllys 
2853089Swyllys /* new dboreham code below: */
2863089Swyllys struct byte_buffer  {
2873089Swyllys 	unsigned char *p;
2883089Swyllys 	int offset;
2893089Swyllys 	int length;
2903089Swyllys };
2913089Swyllys typedef struct byte_buffer byte_buffer;
2923089Swyllys 
2933089Swyllys /*
2943089Swyllys  * The kmfber_flatten routine allocates a struct berval whose contents
2953089Swyllys  * are a BER encoding taken from the ber argument. The bvPtr pointer
2963089Swyllys  * points to the returned berval, which must be freed using
2973089Swyllys  * kmfber_bvfree().  This routine returns 0 on success and -1 on error.
2983089Swyllys  * The use of kmfber_flatten on a BerElement in which all '{' and '}'
2993089Swyllys  * format modifiers have not been properly matched can result in a
3003089Swyllys  * berval whose contents are not a valid BER encoding.
3013089Swyllys  * Note that the ber_ptr is not modified.
3023089Swyllys  */
3033089Swyllys int
kmfber_flatten(BerElement * ber,struct berval ** bvPtr)3043089Swyllys kmfber_flatten(BerElement *ber, struct berval **bvPtr)
3053089Swyllys {
3063089Swyllys 	struct berval *new;
3073089Swyllys 	ber_len_t len;
3083089Swyllys 
3093089Swyllys 	/* allocate a struct berval */
3103089Swyllys 	new = (struct berval *)malloc((size_t)(sizeof (struct berval)));
3113089Swyllys 	if (new == NULL) {
3123089Swyllys 		return (-1);
3133089Swyllys 	}
3143089Swyllys 	(void) memset(new, 0, sizeof (struct berval));
3153089Swyllys 
3163089Swyllys 	/*
3173089Swyllys 	 * Copy everything from the BerElement's ber_buf to ber_ptr
3183089Swyllys 	 * into the berval structure.
3193089Swyllys 	 */
3203089Swyllys 	if (ber == NULL) {
3213089Swyllys 		new->bv_val = NULL;
3223089Swyllys 		new->bv_len = 0;
3233089Swyllys 	} else {
3243089Swyllys 		len = ber->ber_ptr - ber->ber_buf;
3253089Swyllys 		new->bv_val = (char *)malloc((size_t)(len + 1));
3263089Swyllys 		if (new->bv_val == NULL) {
3273089Swyllys 			kmfber_bvfree(new);
3283089Swyllys 			return (-1);
3293089Swyllys 		}
3303089Swyllys 		(void) memmove(new->bv_val, ber->ber_buf, (size_t)len);
3313089Swyllys 		new->bv_val[len] = '\0';
3323089Swyllys 		new->bv_len = len;
3333089Swyllys 	}
3343089Swyllys 
3353089Swyllys 	/* set bvPtr pointer to point to the returned berval */
3363089Swyllys 	*bvPtr = new;
3373089Swyllys 
3383089Swyllys 	return (0);
3393089Swyllys }
3403089Swyllys 
3413089Swyllys BerElement *
kmfder_init(const struct berval * bv)3423089Swyllys kmfder_init(const struct berval *bv)
3433089Swyllys {
3443089Swyllys 	BerElement *ber;
3453089Swyllys 
3463089Swyllys 	/* construct BerElement */
3473089Swyllys 	if ((ber = kmfber_alloc_t(KMFBER_OPT_USE_DER)) != NULL) {
3483089Swyllys 		/* copy data from the bv argument into BerElement */
3493089Swyllys 		/* XXXmcs: had to cast unsigned long bv_len to long */
3503089Swyllys 		if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
35110818Swyllys.ingersoll@sun.com 		    (ber_slen_t)bv->bv_len) {
3523089Swyllys 			kmfber_free(ber, 1);
3533089Swyllys 			return (NULL);
3543089Swyllys 		}
3553089Swyllys 	}
3563089Swyllys 	/*
3573089Swyllys 	 * reset ber_ptr back to the beginning of buffer so that this new
3583089Swyllys 	 * and initialized ber element can be READ
3593089Swyllys 	 */
3603089Swyllys 	kmfber_reset(ber, 1);
3613089Swyllys 
3623089Swyllys 	/*
3633089Swyllys 	 * return a ptr to a new BerElement containing a copy of the data
3643089Swyllys 	 * in the bv argument or a null pointer on error
3653089Swyllys 	 */
3663089Swyllys 	return (ber);
3673089Swyllys }
3683089Swyllys 
3693089Swyllys BerElement *
kmfber_init(const struct berval * bv)3703089Swyllys kmfber_init(const struct berval *bv)
3713089Swyllys {
3723089Swyllys 	BerElement *ber;
3733089Swyllys 
3743089Swyllys 	/* construct BerElement */
3753089Swyllys 	if ((ber = kmfber_alloc_t(0)) != NULL) {
3763089Swyllys 		/* copy data from the bv argument into BerElement */
3773089Swyllys 		/* XXXmcs: had to cast unsigned long bv_len to long */
3783089Swyllys 		if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
37910818Swyllys.ingersoll@sun.com 		    (ber_slen_t)bv->bv_len) {
3803089Swyllys 			kmfber_free(ber, 1);
3813089Swyllys 			return (NULL);
3823089Swyllys 		}
3833089Swyllys 	}
3843089Swyllys 	/*
3853089Swyllys 	 * reset ber_ptr back to the beginning of buffer so that this new
3863089Swyllys 	 * and initialized ber element can be READ
3873089Swyllys 	 */
3883089Swyllys 	kmfber_reset(ber, 1);
3893089Swyllys 
3903089Swyllys 	/*
3913089Swyllys 	 * return a ptr to a new BerElement containing a copy of the data
3923089Swyllys 	 * in the bv argument or a null pointer on error
3933089Swyllys 	 */
3943089Swyllys 	return (ber);
3953089Swyllys }
396