RT4320/GH705: Fix PEM parsing bug.
[openssl.git] / crypto / bio / bf_buff.c
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.]
56  */
57
58 #include <stdio.h>
59 #include <errno.h>
60 #include "internal/cryptlib.h"
61 #include <openssl/bio.h>
62
63 static int buffer_write(BIO *h, const char *buf, int num);
64 static int buffer_read(BIO *h, char *buf, int size);
65 static int buffer_puts(BIO *h, const char *str);
66 static int buffer_gets(BIO *h, char *str, int size);
67 static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
68 static int buffer_new(BIO *h);
69 static int buffer_free(BIO *data);
70 static long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
71 #define DEFAULT_BUFFER_SIZE     4096
72
73 static BIO_METHOD methods_buffer = {
74     BIO_TYPE_BUFFER,
75     "buffer",
76     buffer_write,
77     buffer_read,
78     buffer_puts,
79     buffer_gets,
80     buffer_ctrl,
81     buffer_new,
82     buffer_free,
83     buffer_callback_ctrl,
84 };
85
86 BIO_METHOD *BIO_f_buffer(void)
87 {
88     return (&methods_buffer);
89 }
90
91 static int buffer_new(BIO *bi)
92 {
93     BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
94
95     if (ctx == NULL)
96         return (0);
97     ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
98     ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
99     if (ctx->ibuf == NULL) {
100         OPENSSL_free(ctx);
101         return (0);
102     }
103     ctx->obuf_size = DEFAULT_BUFFER_SIZE;
104     ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE);
105     if (ctx->obuf == NULL) {
106         OPENSSL_free(ctx->ibuf);
107         OPENSSL_free(ctx);
108         return (0);
109     }
110
111     bi->init = 1;
112     bi->ptr = (char *)ctx;
113     bi->flags = 0;
114     return (1);
115 }
116
117 static int buffer_free(BIO *a)
118 {
119     BIO_F_BUFFER_CTX *b;
120
121     if (a == NULL)
122         return (0);
123     b = (BIO_F_BUFFER_CTX *)a->ptr;
124     OPENSSL_free(b->ibuf);
125     OPENSSL_free(b->obuf);
126     OPENSSL_free(a->ptr);
127     a->ptr = NULL;
128     a->init = 0;
129     a->flags = 0;
130     return (1);
131 }
132
133 static int buffer_read(BIO *b, char *out, int outl)
134 {
135     int i, num = 0;
136     BIO_F_BUFFER_CTX *ctx;
137
138     if (out == NULL)
139         return (0);
140     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
141
142     if ((ctx == NULL) || (b->next_bio == NULL))
143         return (0);
144     num = 0;
145     BIO_clear_retry_flags(b);
146
147  start:
148     i = ctx->ibuf_len;
149     /* If there is stuff left over, grab it */
150     if (i != 0) {
151         if (i > outl)
152             i = outl;
153         memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i);
154         ctx->ibuf_off += i;
155         ctx->ibuf_len -= i;
156         num += i;
157         if (outl == i)
158             return (num);
159         outl -= i;
160         out += i;
161     }
162
163     /*
164      * We may have done a partial read. try to do more. We have nothing in
165      * the buffer. If we get an error and have read some data, just return it
166      * and let them retry to get the error again. copy direct to parent
167      * address space
168      */
169     if (outl > ctx->ibuf_size) {
170         for (;;) {
171             i = BIO_read(b->next_bio, out, outl);
172             if (i <= 0) {
173                 BIO_copy_next_retry(b);
174                 if (i < 0)
175                     return ((num > 0) ? num : i);
176                 if (i == 0)
177                     return (num);
178             }
179             num += i;
180             if (outl == i)
181                 return (num);
182             out += i;
183             outl -= i;
184         }
185     }
186     /* else */
187
188     /* we are going to be doing some buffering */
189     i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
190     if (i <= 0) {
191         BIO_copy_next_retry(b);
192         if (i < 0)
193             return ((num > 0) ? num : i);
194         if (i == 0)
195             return (num);
196     }
197     ctx->ibuf_off = 0;
198     ctx->ibuf_len = i;
199
200     /* Lets re-read using ourselves :-) */
201     goto start;
202 }
203
204 static int buffer_write(BIO *b, const char *in, int inl)
205 {
206     int i, num = 0;
207     BIO_F_BUFFER_CTX *ctx;
208
209     if ((in == NULL) || (inl <= 0))
210         return (0);
211     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
212     if ((ctx == NULL) || (b->next_bio == NULL))
213         return (0);
214
215     BIO_clear_retry_flags(b);
216  start:
217     i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off);
218     /* add to buffer and return */
219     if (i >= inl) {
220         memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl);
221         ctx->obuf_len += inl;
222         return (num + inl);
223     }
224     /* else */
225     /* stuff already in buffer, so add to it first, then flush */
226     if (ctx->obuf_len != 0) {
227         if (i > 0) {            /* lets fill it up if we can */
228             memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i);
229             in += i;
230             inl -= i;
231             num += i;
232             ctx->obuf_len += i;
233         }
234         /* we now have a full buffer needing flushing */
235         for (;;) {
236             i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
237                           ctx->obuf_len);
238             if (i <= 0) {
239                 BIO_copy_next_retry(b);
240
241                 if (i < 0)
242                     return ((num > 0) ? num : i);
243                 if (i == 0)
244                     return (num);
245             }
246             ctx->obuf_off += i;
247             ctx->obuf_len -= i;
248             if (ctx->obuf_len == 0)
249                 break;
250         }
251     }
252     /*
253      * we only get here if the buffer has been flushed and we still have
254      * stuff to write
255      */
256     ctx->obuf_off = 0;
257
258     /* we now have inl bytes to write */
259     while (inl >= ctx->obuf_size) {
260         i = BIO_write(b->next_bio, in, inl);
261         if (i <= 0) {
262             BIO_copy_next_retry(b);
263             if (i < 0)
264                 return ((num > 0) ? num : i);
265             if (i == 0)
266                 return (num);
267         }
268         num += i;
269         in += i;
270         inl -= i;
271         if (inl == 0)
272             return (num);
273     }
274
275     /*
276      * copy the rest into the buffer since we have only a small amount left
277      */
278     goto start;
279 }
280
281 static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
282 {
283     BIO *dbio;
284     BIO_F_BUFFER_CTX *ctx;
285     long ret = 1;
286     char *p1, *p2;
287     int r, i, *ip;
288     int ibs, obs;
289
290     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
291
292     switch (cmd) {
293     case BIO_CTRL_RESET:
294         ctx->ibuf_off = 0;
295         ctx->ibuf_len = 0;
296         ctx->obuf_off = 0;
297         ctx->obuf_len = 0;
298         if (b->next_bio == NULL)
299             return (0);
300         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
301         break;
302     case BIO_CTRL_INFO:
303         ret = (long)ctx->obuf_len;
304         break;
305     case BIO_C_GET_BUFF_NUM_LINES:
306         ret = 0;
307         p1 = ctx->ibuf;
308         for (i = 0; i < ctx->ibuf_len; i++) {
309             if (p1[ctx->ibuf_off + i] == '\n')
310                 ret++;
311         }
312         break;
313     case BIO_CTRL_WPENDING:
314         ret = (long)ctx->obuf_len;
315         if (ret == 0) {
316             if (b->next_bio == NULL)
317                 return (0);
318             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
319         }
320         break;
321     case BIO_CTRL_PENDING:
322         ret = (long)ctx->ibuf_len;
323         if (ret == 0) {
324             if (b->next_bio == NULL)
325                 return (0);
326             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
327         }
328         break;
329     case BIO_C_SET_BUFF_READ_DATA:
330         if (num > ctx->ibuf_size) {
331             p1 = OPENSSL_malloc((int)num);
332             if (p1 == NULL)
333                 goto malloc_error;
334             OPENSSL_free(ctx->ibuf);
335             ctx->ibuf = p1;
336         }
337         ctx->ibuf_off = 0;
338         ctx->ibuf_len = (int)num;
339         memcpy(ctx->ibuf, ptr, (int)num);
340         ret = 1;
341         break;
342     case BIO_C_SET_BUFF_SIZE:
343         if (ptr != NULL) {
344             ip = (int *)ptr;
345             if (*ip == 0) {
346                 ibs = (int)num;
347                 obs = ctx->obuf_size;
348             } else {            /* if (*ip == 1) */
349
350                 ibs = ctx->ibuf_size;
351                 obs = (int)num;
352             }
353         } else {
354             ibs = (int)num;
355             obs = (int)num;
356         }
357         p1 = ctx->ibuf;
358         p2 = ctx->obuf;
359         if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) {
360             p1 = OPENSSL_malloc((int)num);
361             if (p1 == NULL)
362                 goto malloc_error;
363         }
364         if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) {
365             p2 = OPENSSL_malloc((int)num);
366             if (p2 == NULL) {
367                 if (p1 != ctx->ibuf)
368                     OPENSSL_free(p1);
369                 goto malloc_error;
370             }
371         }
372         if (ctx->ibuf != p1) {
373             OPENSSL_free(ctx->ibuf);
374             ctx->ibuf = p1;
375             ctx->ibuf_off = 0;
376             ctx->ibuf_len = 0;
377             ctx->ibuf_size = ibs;
378         }
379         if (ctx->obuf != p2) {
380             OPENSSL_free(ctx->obuf);
381             ctx->obuf = p2;
382             ctx->obuf_off = 0;
383             ctx->obuf_len = 0;
384             ctx->obuf_size = obs;
385         }
386         break;
387     case BIO_C_DO_STATE_MACHINE:
388         if (b->next_bio == NULL)
389             return (0);
390         BIO_clear_retry_flags(b);
391         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
392         BIO_copy_next_retry(b);
393         break;
394
395     case BIO_CTRL_FLUSH:
396         if (b->next_bio == NULL)
397             return (0);
398         if (ctx->obuf_len <= 0) {
399             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
400             break;
401         }
402
403         for (;;) {
404             BIO_clear_retry_flags(b);
405             if (ctx->obuf_len > 0) {
406                 r = BIO_write(b->next_bio,
407                               &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len);
408                 BIO_copy_next_retry(b);
409                 if (r <= 0)
410                     return ((long)r);
411                 ctx->obuf_off += r;
412                 ctx->obuf_len -= r;
413             } else {
414                 ctx->obuf_len = 0;
415                 ctx->obuf_off = 0;
416                 ret = 1;
417                 break;
418             }
419         }
420         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
421         break;
422     case BIO_CTRL_DUP:
423         dbio = (BIO *)ptr;
424         if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) ||
425             !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
426             ret = 0;
427         break;
428     default:
429         if (b->next_bio == NULL)
430             return (0);
431         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
432         break;
433     }
434     return (ret);
435  malloc_error:
436     BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE);
437     return (0);
438 }
439
440 static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
441 {
442     long ret = 1;
443
444     if (b->next_bio == NULL)
445         return (0);
446     switch (cmd) {
447     default:
448         ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
449         break;
450     }
451     return (ret);
452 }
453
454 static int buffer_gets(BIO *b, char *buf, int size)
455 {
456     BIO_F_BUFFER_CTX *ctx;
457     int num = 0, i, flag;
458     char *p;
459
460     ctx = (BIO_F_BUFFER_CTX *)b->ptr;
461     size--;                     /* reserve space for a '\0' */
462     BIO_clear_retry_flags(b);
463
464     for (;;) {
465         if (ctx->ibuf_len > 0) {
466             p = &(ctx->ibuf[ctx->ibuf_off]);
467             flag = 0;
468             for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
469                 *(buf++) = p[i];
470                 if (p[i] == '\n') {
471                     flag = 1;
472                     i++;
473                     break;
474                 }
475             }
476             num += i;
477             size -= i;
478             ctx->ibuf_len -= i;
479             ctx->ibuf_off += i;
480             if (flag || size == 0) {
481                 *buf = '\0';
482                 return (num);
483             }
484         } else {                /* read another chunk */
485
486             i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
487             if (i <= 0) {
488                 BIO_copy_next_retry(b);
489                 *buf = '\0';
490                 if (i < 0)
491                     return ((num > 0) ? num : i);
492                 if (i == 0)
493                     return (num);
494             }
495             ctx->ibuf_len = i;
496             ctx->ibuf_off = 0;
497         }
498     }
499 }
500
501 static int buffer_puts(BIO *b, const char *str)
502 {
503     return (buffer_write(b, str, strlen(str)));
504 }