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