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