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