xref: /titanic_50/usr/src/lib/libkmf/ber_der/common/io.c (revision adecd3c68045d04dc367d30faf2eb5cac1f45d5a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
24  *
25  * The contents of this file are subject to the Netscape Public License
26  * Version 1.0 (the "NPL"); you may not use this file except in
27  * compliance with the NPL.  You may obtain a copy of the NPL at
28  * http://www.mozilla.org/NPL/
29  *
30  * Software distributed under the NPL is distributed on an "AS IS" basis,
31  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
32  * for the specific language governing rights and limitations under the
33  * NPL.
34  *
35  * The Initial Developer of this code under the NPL is Netscape
36  * Communications Corporation.  Portions created by Netscape are
37  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
38  * Reserved.
39  */
40 
41 /*
42  * Copyright (c) 1990 Regents of the University of Michigan.
43  * All rights reserved.
44  *
45  * Redistribution and use in source and binary forms are permitted
46  * provided that this notice is preserved and that due credit is given
47  * to the University of Michigan at Ann Arbor. The name of the University
48  * may not be used to endorse or promote products derived from this
49  * software without specific prior written permission. This software
50  * is provided ``as is'' without express or implied warranty.
51  */
52 /*
53  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
54  * Use is subject to license terms.
55  */
56 
57 #pragma ident	"%Z%%M%	%I%	%E% SMI"
58 
59 
60 #include <stdlib.h>
61 #include <ber_der.h>
62 #include "kmfber_int.h"
63 
64 #define	EXBUFSIZ	1024
65 
66 /*
67  * Note: kmfber_read() only uses the ber_end and ber_ptr elements of ber.
68  * Functions like kmfber_get_tag(), kmfber_skip_tag, and kmfber_peek_tag()
69  * rely on that fact, so if this code is changed to use any additional
70  * elements of the ber structure, those functions will need to be changed
71  * as well.
72  */
73 ber_int_t
74 kmfber_read(BerElement *ber, char *buf, ber_len_t len)
75 {
76 	size_t	actuallen;
77 	size_t	nleft;
78 
79 	nleft = ber->ber_end - ber->ber_ptr;
80 	actuallen = nleft < len ? nleft : len;
81 
82 	(void) memmove(buf, ber->ber_ptr, (size_t)actuallen);
83 
84 	ber->ber_ptr += actuallen;
85 
86 	return ((ber_int_t)actuallen);
87 }
88 
89 /*
90  * enlarge the ber buffer.
91  * return 0 on success, -1 on error.
92  */
93 static int
94 kmfber_realloc(BerElement *ber, ber_len_t len)
95 {
96 	ber_uint_t	need, have, total;
97 	size_t		have_bytes;
98 	Seqorset	*s;
99 	size_t		off;
100 	char		*oldbuf;
101 
102 	have_bytes = ber->ber_end - ber->ber_buf;
103 	have = have_bytes / EXBUFSIZ;
104 	need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
105 	total = have * EXBUFSIZ + need * EXBUFSIZ;
106 
107 	oldbuf = ber->ber_buf;
108 
109 	if (ber->ber_buf == NULL) {
110 		if ((ber->ber_buf = (char *)malloc((size_t)total))
111 		    == NULL) {
112 			return (-1);
113 		}
114 		ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
115 	} else {
116 		if (ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER) {
117 			/* transition to malloc'd buffer */
118 			if ((ber->ber_buf = (char *)malloc(
119 			    (size_t)total)) == NULL) {
120 				return (-1);
121 			}
122 			ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
123 			/* copy existing data into new malloc'd buffer */
124 			(void) memmove(ber->ber_buf, oldbuf, have_bytes);
125 		} else {
126 			if ((ber->ber_buf = (char *)realloc(
127 			    ber->ber_buf, (size_t)total)) == NULL) {
128 				return (-1);
129 			}
130 		}
131 	}
132 
133 	ber->ber_end = ber->ber_buf + total;
134 
135 	/*
136 	 * If the stinking thing was moved, we need to go through and
137 	 * reset all the sos and ber pointers.  Offsets would've been
138 	 * a better idea... oh well.
139 	 */
140 
141 	if (ber->ber_buf != oldbuf) {
142 		ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
143 
144 		for (s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next) {
145 			off = s->sos_first - oldbuf;
146 			s->sos_first = ber->ber_buf + off;
147 
148 			off = s->sos_ptr - oldbuf;
149 			s->sos_ptr = ber->ber_buf + off;
150 		}
151 	}
152 
153 	return (0);
154 }
155 
156 /*
157  * returns "len" on success and -1 on failure.
158  */
159 ber_int_t
160 kmfber_write(BerElement *ber, char *buf, ber_len_t len, int nosos)
161 {
162 	if (nosos || ber->ber_sos == NULL) {
163 		if (ber->ber_ptr + len > ber->ber_end) {
164 			if (kmfber_realloc(ber, len) != 0)
165 				return (-1);
166 		}
167 		(void) memmove(ber->ber_ptr, buf, (size_t)len);
168 		ber->ber_ptr += len;
169 		return (len);
170 	} else {
171 		if (ber->ber_sos->sos_ptr + len > ber->ber_end) {
172 			if (kmfber_realloc(ber, len) != 0)
173 				return (-1);
174 		}
175 		(void) memmove(ber->ber_sos->sos_ptr, buf, (size_t)len);
176 		ber->ber_sos->sos_ptr += len;
177 		ber->ber_sos->sos_clen += len;
178 		return (len);
179 	}
180 }
181 
182 void
183 kmfber_free(BerElement *ber, int freebuf)
184 {
185 	if (ber != NULL) {
186 		    if (freebuf &&
187 			!(ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER)) {
188 			    free(ber->ber_buf);
189 		    }
190 		    free((char *)ber);
191 	}
192 }
193 
194 /* we pre-allocate a buffer to save the extra malloc later */
195 BerElement *
196 kmfber_alloc_t(int options)
197 {
198 	BerElement	*ber;
199 
200 	if ((ber = (BerElement*)calloc(1,
201 	    sizeof (struct berelement) + EXBUFSIZ)) == NULL) {
202 		return (NULL);
203 	}
204 
205 	ber->ber_tag = KMFBER_DEFAULT;
206 	ber->ber_options = options;
207 	ber->ber_buf = (char *)ber + sizeof (struct berelement);
208 	ber->ber_ptr = ber->ber_buf;
209 	ber->ber_end = ber->ber_buf + EXBUFSIZ;
210 	ber->ber_flags = KMFBER_FLAG_NO_FREE_BUFFER;
211 
212 	return (ber);
213 }
214 
215 
216 BerElement *
217 kmfber_alloc()
218 {
219 	return (kmfber_alloc_t(0));
220 }
221 
222 BerElement *
223 kmfder_alloc()
224 {
225 	return (kmfber_alloc_t(KMFBER_OPT_USE_DER));
226 }
227 
228 BerElement *
229 kmfber_dup(BerElement *ber)
230 {
231 	BerElement	*new;
232 
233 	if ((new = kmfber_alloc()) == NULL)
234 		return (NULL);
235 
236 	*new = *ber;
237 
238 	return (new);
239 }
240 
241 
242 void
243 ber_init_w_nullchar(BerElement *ber, int options)
244 {
245 	(void) memset((char *)ber, '\0', sizeof (struct berelement));
246 	ber->ber_tag = KMFBER_DEFAULT;
247 
248 	ber->ber_options = options;
249 }
250 
251 
252 void
253 kmfber_reset(BerElement *ber, int was_writing)
254 {
255 	if (was_writing) {
256 		ber->ber_end = ber->ber_ptr;
257 		ber->ber_ptr = ber->ber_buf;
258 	} else {
259 		ber->ber_ptr = ber->ber_end;
260 	}
261 
262 	ber->ber_rwptr = NULL;
263 }
264 
265 
266 #ifdef KMFBER_DEBUG
267 
268 void
269 ber_dump(BerElement *ber, int inout)
270 {
271 	char msg[128];
272 	sprintf(msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
273 	    ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end);
274 	ber_err_print(msg);
275 	if (inout == 1) {
276 		sprintf(msg, "          current len %ld, contents:\n",
277 		    ber->ber_end - ber->ber_ptr);
278 		ber_err_print(msg);
279 		lber_bprint(ber->ber_ptr, ber->ber_end - ber->ber_ptr);
280 	} else {
281 		sprintf(msg, "          current len %ld, contents:\n",
282 		    ber->ber_ptr - ber->ber_buf);
283 		ber_err_print(msg);
284 		lber_bprint(ber->ber_buf, ber->ber_ptr - ber->ber_buf);
285 	}
286 }
287 
288 void
289 ber_sos_dump(Seqorset *sos)
290 {
291 	char msg[80];
292 	ber_err_print("*** sos dump ***\n");
293 	while (sos != NULLSEQORSET) {
294 		sprintf(msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
295 		    sos->sos_clen, sos->sos_first, sos->sos_ptr);
296 		ber_err_print(msg);
297 		sprintf(msg, "              current len %ld contents:\n",
298 		    sos->sos_ptr - sos->sos_first);
299 		ber_err_print(msg);
300 		lber_bprint(sos->sos_first, sos->sos_ptr - sos->sos_first);
301 
302 		sos = sos->sos_next;
303 	}
304 	ber_err_print("*** end dump ***\n");
305 }
306 
307 #endif
308 
309 /* new dboreham code below: */
310 struct byte_buffer  {
311 	unsigned char *p;
312 	int offset;
313 	int length;
314 };
315 typedef struct byte_buffer byte_buffer;
316 
317 /*
318  * The kmfber_flatten routine allocates a struct berval whose contents
319  * are a BER encoding taken from the ber argument. The bvPtr pointer
320  * points to the returned berval, which must be freed using
321  * kmfber_bvfree().  This routine returns 0 on success and -1 on error.
322  * The use of kmfber_flatten on a BerElement in which all '{' and '}'
323  * format modifiers have not been properly matched can result in a
324  * berval whose contents are not a valid BER encoding.
325  * Note that the ber_ptr is not modified.
326  */
327 int
328 kmfber_flatten(BerElement *ber, struct berval **bvPtr)
329 {
330 	struct berval *new;
331 	ber_len_t len;
332 
333 	/* allocate a struct berval */
334 	new = (struct berval *)malloc((size_t)(sizeof (struct berval)));
335 	if (new == NULL) {
336 		return (-1);
337 	}
338 	(void) memset(new, 0, sizeof (struct berval));
339 
340 	/*
341 	 * Copy everything from the BerElement's ber_buf to ber_ptr
342 	 * into the berval structure.
343 	 */
344 	if (ber == NULL) {
345 		new->bv_val = NULL;
346 		new->bv_len = 0;
347 	} else {
348 		len = ber->ber_ptr - ber->ber_buf;
349 		new->bv_val = (char *)malloc((size_t)(len + 1));
350 		if (new->bv_val == NULL) {
351 			kmfber_bvfree(new);
352 			return (-1);
353 		}
354 		(void) memmove(new->bv_val, ber->ber_buf, (size_t)len);
355 		new->bv_val[len] = '\0';
356 		new->bv_len = len;
357 	}
358 
359 	/* set bvPtr pointer to point to the returned berval */
360 	*bvPtr = new;
361 
362 	return (0);
363 }
364 
365 BerElement *
366 kmfder_init(const struct berval *bv)
367 {
368 	BerElement *ber;
369 
370 	/* construct BerElement */
371 	if ((ber = kmfber_alloc_t(KMFBER_OPT_USE_DER)) != NULL) {
372 		/* copy data from the bv argument into BerElement */
373 		/* XXXmcs: had to cast unsigned long bv_len to long */
374 		if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
375 			(ber_slen_t)bv->bv_len) {
376 			kmfber_free(ber, 1);
377 			return (NULL);
378 		}
379 	}
380 	/*
381 	 * reset ber_ptr back to the beginning of buffer so that this new
382 	 * and initialized ber element can be READ
383 	 */
384 	kmfber_reset(ber, 1);
385 
386 	/*
387 	 * return a ptr to a new BerElement containing a copy of the data
388 	 * in the bv argument or a null pointer on error
389 	 */
390 	return (ber);
391 }
392 
393 BerElement *
394 kmfber_init(const struct berval *bv)
395 {
396 	BerElement *ber;
397 
398 	/* construct BerElement */
399 	if ((ber = kmfber_alloc_t(0)) != NULL) {
400 		/* copy data from the bv argument into BerElement */
401 		/* XXXmcs: had to cast unsigned long bv_len to long */
402 		if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
403 			(ber_slen_t)bv->bv_len) {
404 			kmfber_free(ber, 1);
405 			return (NULL);
406 		}
407 	}
408 	/*
409 	 * reset ber_ptr back to the beginning of buffer so that this new
410 	 * and initialized ber element can be READ
411 	 */
412 	kmfber_reset(ber, 1);
413 
414 	/*
415 	 * return a ptr to a new BerElement containing a copy of the data
416 	 * in the bv argument or a null pointer on error
417 	 */
418 	return (ber);
419 }
420