xref: /onnv-gate/usr/src/lib/libkmf/ber_der/common/io.c (revision 10818:89e8703947be)
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 /*
32*10818Swyllys.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
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  */
69*10818Swyllys.ingersoll@sun.com int
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;
77*10818Swyllys.ingersoll@sun.com 	boolean_t	freeold = B_FALSE;
783089Swyllys 
793089Swyllys 	have_bytes = ber->ber_end - ber->ber_buf;
803089Swyllys 	have = have_bytes / EXBUFSIZ;
813089Swyllys 	need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
823089Swyllys 	total = have * EXBUFSIZ + need * EXBUFSIZ;
833089Swyllys 
843089Swyllys 	oldbuf = ber->ber_buf;
853089Swyllys 
863089Swyllys 	if (ber->ber_buf == NULL) {
873089Swyllys 		if ((ber->ber_buf = (char *)malloc((size_t)total))
883089Swyllys 		    == NULL) {
893089Swyllys 			return (-1);
903089Swyllys 		}
913089Swyllys 		ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
923089Swyllys 	} else {
933089Swyllys 		if (ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER) {
943089Swyllys 			/* transition to malloc'd buffer */
953089Swyllys 			if ((ber->ber_buf = (char *)malloc(
963089Swyllys 			    (size_t)total)) == NULL) {
97*10818Swyllys.ingersoll@sun.com 				free(oldbuf);
983089Swyllys 				return (-1);
993089Swyllys 			}
1003089Swyllys 			ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
1013089Swyllys 			/* copy existing data into new malloc'd buffer */
1023089Swyllys 			(void) memmove(ber->ber_buf, oldbuf, have_bytes);
103*10818Swyllys.ingersoll@sun.com 			freeold = B_TRUE;
1043089Swyllys 		} else {
1053089Swyllys 			if ((ber->ber_buf = (char *)realloc(
1063089Swyllys 			    ber->ber_buf, (size_t)total)) == NULL) {
1073089Swyllys 				return (-1);
1083089Swyllys 			}
109*10818Swyllys.ingersoll@sun.com 			freeold = B_FALSE; /* it was just realloced */
1103089Swyllys 		}
1113089Swyllys 	}
1123089Swyllys 
1133089Swyllys 	ber->ber_end = ber->ber_buf + total;
1143089Swyllys 
1153089Swyllys 	/*
1163089Swyllys 	 * If the stinking thing was moved, we need to go through and
1173089Swyllys 	 * reset all the sos and ber pointers.  Offsets would've been
1183089Swyllys 	 * a better idea... oh well.
1193089Swyllys 	 */
1203089Swyllys 	if (ber->ber_buf != oldbuf) {
1213089Swyllys 		ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
1223089Swyllys 
1233089Swyllys 		for (s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next) {
1243089Swyllys 			off = s->sos_first - oldbuf;
1253089Swyllys 			s->sos_first = ber->ber_buf + off;
1263089Swyllys 
1273089Swyllys 			off = s->sos_ptr - oldbuf;
1283089Swyllys 			s->sos_ptr = ber->ber_buf + off;
1293089Swyllys 		}
1303089Swyllys 	}
131*10818Swyllys.ingersoll@sun.com 	if (freeold && oldbuf != NULL)
132*10818Swyllys.ingersoll@sun.com 		free(oldbuf);
1333089Swyllys 
1343089Swyllys 	return (0);
1353089Swyllys }
1363089Swyllys 
1373089Swyllys /*
1383089Swyllys  * returns "len" on success and -1 on failure.
1393089Swyllys  */
1403089Swyllys ber_int_t
1413089Swyllys kmfber_write(BerElement *ber, char *buf, ber_len_t len, int nosos)
1423089Swyllys {
1433089Swyllys 	if (nosos || ber->ber_sos == NULL) {
1443089Swyllys 		if (ber->ber_ptr + len > ber->ber_end) {
1453089Swyllys 			if (kmfber_realloc(ber, len) != 0)
1463089Swyllys 				return (-1);
1473089Swyllys 		}
1483089Swyllys 		(void) memmove(ber->ber_ptr, buf, (size_t)len);
1493089Swyllys 		ber->ber_ptr += len;
1503089Swyllys 		return (len);
1513089Swyllys 	} else {
1523089Swyllys 		if (ber->ber_sos->sos_ptr + len > ber->ber_end) {
1533089Swyllys 			if (kmfber_realloc(ber, len) != 0)
1543089Swyllys 				return (-1);
1553089Swyllys 		}
1563089Swyllys 		(void) memmove(ber->ber_sos->sos_ptr, buf, (size_t)len);
1573089Swyllys 		ber->ber_sos->sos_ptr += len;
1583089Swyllys 		ber->ber_sos->sos_clen += len;
1593089Swyllys 		return (len);
1603089Swyllys 	}
1613089Swyllys }
1623089Swyllys 
1633089Swyllys void
1643089Swyllys kmfber_free(BerElement *ber, int freebuf)
1653089Swyllys {
1663089Swyllys 	if (ber != NULL) {
167*10818Swyllys.ingersoll@sun.com 		if (freebuf &&
168*10818Swyllys.ingersoll@sun.com 		    !(ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER))
169*10818Swyllys.ingersoll@sun.com 			free(ber->ber_buf);
170*10818Swyllys.ingersoll@sun.com 		free((char *)ber);
1713089Swyllys 	}
1723089Swyllys }
1733089Swyllys 
1743089Swyllys /* we pre-allocate a buffer to save the extra malloc later */
1753089Swyllys BerElement *
1763089Swyllys kmfber_alloc_t(int options)
1773089Swyllys {
1783089Swyllys 	BerElement	*ber;
1793089Swyllys 
1803089Swyllys 	if ((ber = (BerElement*)calloc(1,
1813089Swyllys 	    sizeof (struct berelement) + EXBUFSIZ)) == NULL) {
1823089Swyllys 		return (NULL);
1833089Swyllys 	}
1843089Swyllys 
1853089Swyllys 	ber->ber_tag = KMFBER_DEFAULT;
1863089Swyllys 	ber->ber_options = options;
1873089Swyllys 	ber->ber_buf = (char *)ber + sizeof (struct berelement);
1883089Swyllys 	ber->ber_ptr = ber->ber_buf;
1893089Swyllys 	ber->ber_end = ber->ber_buf + EXBUFSIZ;
1903089Swyllys 	ber->ber_flags = KMFBER_FLAG_NO_FREE_BUFFER;
1913089Swyllys 
1923089Swyllys 	return (ber);
1933089Swyllys }
1943089Swyllys 
1953089Swyllys 
1963089Swyllys BerElement *
1973089Swyllys kmfber_alloc()
1983089Swyllys {
1993089Swyllys 	return (kmfber_alloc_t(0));
2003089Swyllys }
2013089Swyllys 
2023089Swyllys BerElement *
2033089Swyllys kmfder_alloc()
2043089Swyllys {
2053089Swyllys 	return (kmfber_alloc_t(KMFBER_OPT_USE_DER));
2063089Swyllys }
2073089Swyllys 
2083089Swyllys BerElement *
2093089Swyllys kmfber_dup(BerElement *ber)
2103089Swyllys {
2113089Swyllys 	BerElement	*new;
2123089Swyllys 
2133089Swyllys 	if ((new = kmfber_alloc()) == NULL)
2143089Swyllys 		return (NULL);
2153089Swyllys 
2163089Swyllys 	*new = *ber;
2173089Swyllys 
2183089Swyllys 	return (new);
2193089Swyllys }
2203089Swyllys 
2213089Swyllys 
2223089Swyllys void
2233089Swyllys ber_init_w_nullchar(BerElement *ber, int options)
2243089Swyllys {
2253089Swyllys 	(void) memset((char *)ber, '\0', sizeof (struct berelement));
2263089Swyllys 	ber->ber_tag = KMFBER_DEFAULT;
2273089Swyllys 
2283089Swyllys 	ber->ber_options = options;
2293089Swyllys }
2303089Swyllys 
2313089Swyllys 
2323089Swyllys void
2333089Swyllys kmfber_reset(BerElement *ber, int was_writing)
2343089Swyllys {
2353089Swyllys 	if (was_writing) {
2363089Swyllys 		ber->ber_end = ber->ber_ptr;
2373089Swyllys 		ber->ber_ptr = ber->ber_buf;
2383089Swyllys 	} else {
2393089Swyllys 		ber->ber_ptr = ber->ber_end;
2403089Swyllys 	}
2413089Swyllys 
2423089Swyllys 	ber->ber_rwptr = NULL;
2433089Swyllys }
2443089Swyllys 
2453089Swyllys 
2463089Swyllys #ifdef KMFBER_DEBUG
2473089Swyllys 
2483089Swyllys void
2493089Swyllys ber_dump(BerElement *ber, int inout)
2503089Swyllys {
2513089Swyllys 	char msg[128];
2523089Swyllys 	sprintf(msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
2533089Swyllys 	    ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end);
2543089Swyllys 	ber_err_print(msg);
2553089Swyllys 	if (inout == 1) {
2563089Swyllys 		sprintf(msg, "          current len %ld, contents:\n",
2573089Swyllys 		    ber->ber_end - ber->ber_ptr);
2583089Swyllys 		ber_err_print(msg);
2593089Swyllys 		lber_bprint(ber->ber_ptr, ber->ber_end - ber->ber_ptr);
2603089Swyllys 	} else {
2613089Swyllys 		sprintf(msg, "          current len %ld, contents:\n",
2623089Swyllys 		    ber->ber_ptr - ber->ber_buf);
2633089Swyllys 		ber_err_print(msg);
2643089Swyllys 		lber_bprint(ber->ber_buf, ber->ber_ptr - ber->ber_buf);
2653089Swyllys 	}
2663089Swyllys }
2673089Swyllys 
2683089Swyllys void
2693089Swyllys ber_sos_dump(Seqorset *sos)
2703089Swyllys {
2713089Swyllys 	char msg[80];
2723089Swyllys 	ber_err_print("*** sos dump ***\n");
2733089Swyllys 	while (sos != NULLSEQORSET) {
2743089Swyllys 		sprintf(msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
2753089Swyllys 		    sos->sos_clen, sos->sos_first, sos->sos_ptr);
2763089Swyllys 		ber_err_print(msg);
2773089Swyllys 		sprintf(msg, "              current len %ld contents:\n",
2783089Swyllys 		    sos->sos_ptr - sos->sos_first);
2793089Swyllys 		ber_err_print(msg);
2803089Swyllys 		lber_bprint(sos->sos_first, sos->sos_ptr - sos->sos_first);
2813089Swyllys 
2823089Swyllys 		sos = sos->sos_next;
2833089Swyllys 	}
2843089Swyllys 	ber_err_print("*** end dump ***\n");
2853089Swyllys }
2863089Swyllys 
2873089Swyllys #endif
2883089Swyllys 
2893089Swyllys /* new dboreham code below: */
2903089Swyllys struct byte_buffer  {
2913089Swyllys 	unsigned char *p;
2923089Swyllys 	int offset;
2933089Swyllys 	int length;
2943089Swyllys };
2953089Swyllys typedef struct byte_buffer byte_buffer;
2963089Swyllys 
2973089Swyllys /*
2983089Swyllys  * The kmfber_flatten routine allocates a struct berval whose contents
2993089Swyllys  * are a BER encoding taken from the ber argument. The bvPtr pointer
3003089Swyllys  * points to the returned berval, which must be freed using
3013089Swyllys  * kmfber_bvfree().  This routine returns 0 on success and -1 on error.
3023089Swyllys  * The use of kmfber_flatten on a BerElement in which all '{' and '}'
3033089Swyllys  * format modifiers have not been properly matched can result in a
3043089Swyllys  * berval whose contents are not a valid BER encoding.
3053089Swyllys  * Note that the ber_ptr is not modified.
3063089Swyllys  */
3073089Swyllys int
3083089Swyllys kmfber_flatten(BerElement *ber, struct berval **bvPtr)
3093089Swyllys {
3103089Swyllys 	struct berval *new;
3113089Swyllys 	ber_len_t len;
3123089Swyllys 
3133089Swyllys 	/* allocate a struct berval */
3143089Swyllys 	new = (struct berval *)malloc((size_t)(sizeof (struct berval)));
3153089Swyllys 	if (new == NULL) {
3163089Swyllys 		return (-1);
3173089Swyllys 	}
3183089Swyllys 	(void) memset(new, 0, sizeof (struct berval));
3193089Swyllys 
3203089Swyllys 	/*
3213089Swyllys 	 * Copy everything from the BerElement's ber_buf to ber_ptr
3223089Swyllys 	 * into the berval structure.
3233089Swyllys 	 */
3243089Swyllys 	if (ber == NULL) {
3253089Swyllys 		new->bv_val = NULL;
3263089Swyllys 		new->bv_len = 0;
3273089Swyllys 	} else {
3283089Swyllys 		len = ber->ber_ptr - ber->ber_buf;
3293089Swyllys 		new->bv_val = (char *)malloc((size_t)(len + 1));
3303089Swyllys 		if (new->bv_val == NULL) {
3313089Swyllys 			kmfber_bvfree(new);
3323089Swyllys 			return (-1);
3333089Swyllys 		}
3343089Swyllys 		(void) memmove(new->bv_val, ber->ber_buf, (size_t)len);
3353089Swyllys 		new->bv_val[len] = '\0';
3363089Swyllys 		new->bv_len = len;
3373089Swyllys 	}
3383089Swyllys 
3393089Swyllys 	/* set bvPtr pointer to point to the returned berval */
3403089Swyllys 	*bvPtr = new;
3413089Swyllys 
3423089Swyllys 	return (0);
3433089Swyllys }
3443089Swyllys 
3453089Swyllys BerElement *
3463089Swyllys kmfder_init(const struct berval *bv)
3473089Swyllys {
3483089Swyllys 	BerElement *ber;
3493089Swyllys 
3503089Swyllys 	/* construct BerElement */
3513089Swyllys 	if ((ber = kmfber_alloc_t(KMFBER_OPT_USE_DER)) != NULL) {
3523089Swyllys 		/* copy data from the bv argument into BerElement */
3533089Swyllys 		/* XXXmcs: had to cast unsigned long bv_len to long */
3543089Swyllys 		if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
355*10818Swyllys.ingersoll@sun.com 		    (ber_slen_t)bv->bv_len) {
3563089Swyllys 			kmfber_free(ber, 1);
3573089Swyllys 			return (NULL);
3583089Swyllys 		}
3593089Swyllys 	}
3603089Swyllys 	/*
3613089Swyllys 	 * reset ber_ptr back to the beginning of buffer so that this new
3623089Swyllys 	 * and initialized ber element can be READ
3633089Swyllys 	 */
3643089Swyllys 	kmfber_reset(ber, 1);
3653089Swyllys 
3663089Swyllys 	/*
3673089Swyllys 	 * return a ptr to a new BerElement containing a copy of the data
3683089Swyllys 	 * in the bv argument or a null pointer on error
3693089Swyllys 	 */
3703089Swyllys 	return (ber);
3713089Swyllys }
3723089Swyllys 
3733089Swyllys BerElement *
3743089Swyllys kmfber_init(const struct berval *bv)
3753089Swyllys {
3763089Swyllys 	BerElement *ber;
3773089Swyllys 
3783089Swyllys 	/* construct BerElement */
3793089Swyllys 	if ((ber = kmfber_alloc_t(0)) != NULL) {
3803089Swyllys 		/* copy data from the bv argument into BerElement */
3813089Swyllys 		/* XXXmcs: had to cast unsigned long bv_len to long */
3823089Swyllys 		if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
383*10818Swyllys.ingersoll@sun.com 		    (ber_slen_t)bv->bv_len) {
3843089Swyllys 			kmfber_free(ber, 1);
3853089Swyllys 			return (NULL);
3863089Swyllys 		}
3873089Swyllys 	}
3883089Swyllys 	/*
3893089Swyllys 	 * reset ber_ptr back to the beginning of buffer so that this new
3903089Swyllys 	 * and initialized ber element can be READ
3913089Swyllys 	 */
3923089Swyllys 	kmfber_reset(ber, 1);
3933089Swyllys 
3943089Swyllys 	/*
3953089Swyllys 	 * return a ptr to a new BerElement containing a copy of the data
3963089Swyllys 	 * in the bv argument or a null pointer on error
3973089Swyllys 	 */
3983089Swyllys 	return (ber);
3993089Swyllys }
400