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
kmfber_read(BerElement * ber,char * buf,ber_len_t len)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
kmfber_realloc(BerElement * ber,ber_len_t len)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
kmfber_write(BerElement * ber,char * buf,ber_len_t len,int nosos)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
kmfber_free(BerElement * ber,int freebuf)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 *
kmfber_alloc_t(int options)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 *
kmfber_alloc()193 kmfber_alloc()
194 {
195 return (kmfber_alloc_t(0));
196 }
197
198 BerElement *
kmfder_alloc()199 kmfder_alloc()
200 {
201 return (kmfber_alloc_t(KMFBER_OPT_USE_DER));
202 }
203
204 BerElement *
kmfber_dup(BerElement * ber)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
ber_init_w_nullchar(BerElement * ber,int options)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
kmfber_reset(BerElement * ber,int was_writing)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
ber_dump(BerElement * ber,int inout)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
ber_sos_dump(Seqorset * sos)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
kmfber_flatten(BerElement * ber,struct berval ** bvPtr)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 *
kmfder_init(const struct berval * bv)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 *
kmfber_init(const struct berval * bv)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