|
1 /* crypto/evp/bio_b64.c */ |
|
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
|
3 * All rights reserved. |
|
4 * |
|
5 * This package is an SSL implementation written |
|
6 * by Eric Young (eay@cryptsoft.com). |
|
7 * The implementation was written so as to conform with Netscapes SSL. |
|
8 * |
|
9 * This library is free for commercial and non-commercial use as long as |
|
10 * the following conditions are aheared to. The following conditions |
|
11 * apply to all code found in this distribution, be it the RC4, RSA, |
|
12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation |
|
13 * included with this distribution is covered by the same copyright terms |
|
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). |
|
15 * |
|
16 * Copyright remains Eric Young's, and as such any Copyright notices in |
|
17 * the code are not to be removed. |
|
18 * If this package is used in a product, Eric Young should be given attribution |
|
19 * as the author of the parts of the library used. |
|
20 * This can be in the form of a textual message at program startup or |
|
21 * in documentation (online or textual) provided with the package. |
|
22 * |
|
23 * Redistribution and use in source and binary forms, with or without |
|
24 * modification, are permitted provided that the following conditions |
|
25 * are met: |
|
26 * 1. Redistributions of source code must retain the copyright |
|
27 * notice, this list of conditions and the following disclaimer. |
|
28 * 2. Redistributions in binary form must reproduce the above copyright |
|
29 * notice, this list of conditions and the following disclaimer in the |
|
30 * documentation and/or other materials provided with the distribution. |
|
31 * 3. All advertising materials mentioning features or use of this software |
|
32 * must display the following acknowledgement: |
|
33 * "This product includes cryptographic software written by |
|
34 * Eric Young (eay@cryptsoft.com)" |
|
35 * The word 'cryptographic' can be left out if the rouines from the library |
|
36 * being used are not cryptographic related :-). |
|
37 * 4. If you include any Windows specific code (or a derivative thereof) from |
|
38 * the apps directory (application code) you must include an acknowledgement: |
|
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
|
40 * |
|
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
|
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
|
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
51 * SUCH DAMAGE. |
|
52 * |
|
53 * The licence and distribution terms for any publically available version or |
|
54 * derivative of this code cannot be changed. i.e. this code cannot simply be |
|
55 * copied and put under another distribution licence |
|
56 * [including the GNU Public Licence.] |
|
57 */ |
|
58 |
|
59 /* |
|
60 © Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
61 */ |
|
62 |
|
63 |
|
64 #include <stdio.h> |
|
65 #include <errno.h> |
|
66 #include "cryptlib.h" |
|
67 #include <openssl/buffer.h> |
|
68 #include <openssl/evp.h> |
|
69 #if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__))) |
|
70 #include "libcrypto_wsd_macros.h" |
|
71 #include "libcrypto_wsd.h" |
|
72 #endif |
|
73 |
|
74 static int b64_write(BIO *h, const char *buf, int num); |
|
75 static int b64_read(BIO *h, char *buf, int size); |
|
76 /*static int b64_puts(BIO *h, const char *str); */ |
|
77 /*static int b64_gets(BIO *h, char *str, int size); */ |
|
78 static long b64_ctrl(BIO *h, int cmd, long arg1, void *arg2); |
|
79 static int b64_new(BIO *h); |
|
80 static int b64_free(BIO *data); |
|
81 static long b64_callback_ctrl(BIO *h,int cmd,bio_info_cb *fp); |
|
82 #define B64_BLOCK_SIZE 1024 |
|
83 #define B64_BLOCK_SIZE2 768 |
|
84 #define B64_NONE 0 |
|
85 #define B64_ENCODE 1 |
|
86 #define B64_DECODE 2 |
|
87 |
|
88 typedef struct b64_struct |
|
89 { |
|
90 /*BIO *bio; moved to the BIO structure */ |
|
91 int buf_len; |
|
92 int buf_off; |
|
93 int tmp_len; /* used to find the start when decoding */ |
|
94 int tmp_nl; /* If true, scan until '\n' */ |
|
95 int encode; |
|
96 int start; /* have we started decoding yet? */ |
|
97 int cont; /* <= 0 when finished */ |
|
98 EVP_ENCODE_CTX base64; |
|
99 char buf[EVP_ENCODE_LENGTH(B64_BLOCK_SIZE)+10]; |
|
100 char tmp[B64_BLOCK_SIZE]; |
|
101 } BIO_B64_CTX; |
|
102 |
|
103 #ifndef EMULATOR |
|
104 static BIO_METHOD methods_b64= |
|
105 { |
|
106 BIO_TYPE_BASE64,"base64 encoding", |
|
107 b64_write, |
|
108 b64_read, |
|
109 NULL, /* b64_puts, */ |
|
110 NULL, /* b64_gets, */ |
|
111 b64_ctrl, |
|
112 b64_new, |
|
113 b64_free, |
|
114 b64_callback_ctrl, |
|
115 }; |
|
116 #else |
|
117 GET_STATIC_VAR_FROM_TLS(methods_b64,bio_b64,BIO_METHOD) |
|
118 #define methods_b64 (*GET_WSD_VAR_NAME(methods_b64,bio_b64, s)()) |
|
119 const BIO_METHOD temp_s_methods_b64= |
|
120 { |
|
121 BIO_TYPE_BASE64,"base64 encoding", |
|
122 b64_write, |
|
123 b64_read, |
|
124 NULL, /* b64_puts, */ |
|
125 NULL, /* b64_gets, */ |
|
126 b64_ctrl, |
|
127 b64_new, |
|
128 b64_free, |
|
129 b64_callback_ctrl, |
|
130 }; |
|
131 #endif |
|
132 EXPORT_C BIO_METHOD *BIO_f_base64(void) |
|
133 { |
|
134 return(&methods_b64); |
|
135 } |
|
136 |
|
137 static int b64_new(BIO *bi) |
|
138 { |
|
139 BIO_B64_CTX *ctx; |
|
140 |
|
141 ctx=(BIO_B64_CTX *)OPENSSL_malloc(sizeof(BIO_B64_CTX)); |
|
142 if (ctx == NULL) return(0); |
|
143 |
|
144 ctx->buf_len=0; |
|
145 ctx->tmp_len=0; |
|
146 ctx->tmp_nl=0; |
|
147 ctx->buf_off=0; |
|
148 ctx->cont=1; |
|
149 ctx->start=1; |
|
150 ctx->encode=0; |
|
151 |
|
152 bi->init=1; |
|
153 bi->ptr=(char *)ctx; |
|
154 bi->flags=0; |
|
155 return(1); |
|
156 } |
|
157 |
|
158 static int b64_free(BIO *a) |
|
159 { |
|
160 if (a == NULL) return(0); |
|
161 OPENSSL_free(a->ptr); |
|
162 a->ptr=NULL; |
|
163 a->init=0; |
|
164 a->flags=0; |
|
165 return(1); |
|
166 } |
|
167 |
|
168 static int b64_read(BIO *b, char *out, int outl) |
|
169 { |
|
170 int ret=0,i,ii,j,k,x,n,num,ret_code=0; |
|
171 BIO_B64_CTX *ctx; |
|
172 unsigned char *p,*q; |
|
173 |
|
174 if (out == NULL) return(0); |
|
175 ctx=(BIO_B64_CTX *)b->ptr; |
|
176 |
|
177 if ((ctx == NULL) || (b->next_bio == NULL)) return(0); |
|
178 |
|
179 if (ctx->encode != B64_DECODE) |
|
180 { |
|
181 ctx->encode=B64_DECODE; |
|
182 ctx->buf_len=0; |
|
183 ctx->buf_off=0; |
|
184 ctx->tmp_len=0; |
|
185 EVP_DecodeInit(&(ctx->base64)); |
|
186 } |
|
187 |
|
188 /* First check if there are bytes decoded/encoded */ |
|
189 if (ctx->buf_len > 0) |
|
190 { |
|
191 i=ctx->buf_len-ctx->buf_off; |
|
192 if (i > outl) i=outl; |
|
193 OPENSSL_assert(ctx->buf_off+i < (int)sizeof(ctx->buf)); |
|
194 memcpy(out,&(ctx->buf[ctx->buf_off]),i); |
|
195 ret=i; |
|
196 out+=i; |
|
197 outl-=i; |
|
198 ctx->buf_off+=i; |
|
199 if (ctx->buf_len == ctx->buf_off) |
|
200 { |
|
201 ctx->buf_len=0; |
|
202 ctx->buf_off=0; |
|
203 } |
|
204 } |
|
205 |
|
206 /* At this point, we have room of outl bytes and an empty |
|
207 * buffer, so we should read in some more. */ |
|
208 |
|
209 ret_code=0; |
|
210 while (outl > 0) |
|
211 { |
|
212 |
|
213 if (ctx->cont <= 0) |
|
214 break; |
|
215 |
|
216 i=BIO_read(b->next_bio,&(ctx->tmp[ctx->tmp_len]), |
|
217 B64_BLOCK_SIZE-ctx->tmp_len); |
|
218 |
|
219 if (i <= 0) |
|
220 { |
|
221 ret_code=i; |
|
222 |
|
223 /* Should be continue next time we are called? */ |
|
224 if (!BIO_should_retry(b->next_bio)) |
|
225 { |
|
226 ctx->cont=i; |
|
227 /* If buffer empty break */ |
|
228 if(ctx->tmp_len == 0) |
|
229 break; |
|
230 /* Fall through and process what we have */ |
|
231 else |
|
232 i = 0; |
|
233 } |
|
234 /* else we retry and add more data to buffer */ |
|
235 else |
|
236 break; |
|
237 } |
|
238 i+=ctx->tmp_len; |
|
239 ctx->tmp_len = i; |
|
240 |
|
241 /* We need to scan, a line at a time until we |
|
242 * have a valid line if we are starting. */ |
|
243 if (ctx->start && (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL)) |
|
244 { |
|
245 /* ctx->start=1; */ |
|
246 ctx->tmp_len=0; |
|
247 } |
|
248 else if (ctx->start) |
|
249 { |
|
250 q=p=(unsigned char *)ctx->tmp; |
|
251 for (j=0; j<i; j++) |
|
252 { |
|
253 if (*(q++) != '\n') continue; |
|
254 |
|
255 /* due to a previous very long line, |
|
256 * we need to keep on scanning for a '\n' |
|
257 * before we even start looking for |
|
258 * base64 encoded stuff. */ |
|
259 if (ctx->tmp_nl) |
|
260 { |
|
261 p=q; |
|
262 ctx->tmp_nl=0; |
|
263 continue; |
|
264 } |
|
265 |
|
266 k=EVP_DecodeUpdate(&(ctx->base64), |
|
267 (unsigned char *)ctx->buf, |
|
268 &num,p,q-p); |
|
269 if ((k <= 0) && (num == 0) && (ctx->start)) |
|
270 EVP_DecodeInit(&ctx->base64); |
|
271 else |
|
272 { |
|
273 if (p != (unsigned char *) |
|
274 &(ctx->tmp[0])) |
|
275 { |
|
276 i-=(p- (unsigned char *) |
|
277 &(ctx->tmp[0])); |
|
278 for (x=0; x < i; x++) |
|
279 ctx->tmp[x]=p[x]; |
|
280 } |
|
281 EVP_DecodeInit(&ctx->base64); |
|
282 ctx->start=0; |
|
283 break; |
|
284 } |
|
285 p=q; |
|
286 } |
|
287 |
|
288 /* we fell off the end without starting */ |
|
289 if (j == i) |
|
290 { |
|
291 /* Is this is one long chunk?, if so, keep on |
|
292 * reading until a new line. */ |
|
293 if (p == (unsigned char *)&(ctx->tmp[0])) |
|
294 { |
|
295 /* Check buffer full */ |
|
296 if (i == B64_BLOCK_SIZE) |
|
297 { |
|
298 ctx->tmp_nl=1; |
|
299 ctx->tmp_len=0; |
|
300 } |
|
301 } |
|
302 else if (p != q) /* finished on a '\n' */ |
|
303 { |
|
304 n=q-p; |
|
305 for (ii=0; ii<n; ii++) |
|
306 ctx->tmp[ii]=p[ii]; |
|
307 ctx->tmp_len=n; |
|
308 } |
|
309 /* else finished on a '\n' */ |
|
310 continue; |
|
311 } |
|
312 else |
|
313 ctx->tmp_len=0; |
|
314 } |
|
315 /* If buffer isn't full and we can retry then |
|
316 * restart to read in more data. |
|
317 */ |
|
318 else if ((i < B64_BLOCK_SIZE) && (ctx->cont > 0)) |
|
319 continue; |
|
320 |
|
321 if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) |
|
322 { |
|
323 int z,jj; |
|
324 |
|
325 jj=(i>>2)<<2; |
|
326 z=EVP_DecodeBlock((unsigned char *)ctx->buf, |
|
327 (unsigned char *)ctx->tmp,jj); |
|
328 if (jj > 2) |
|
329 { |
|
330 if (ctx->tmp[jj-1] == '=') |
|
331 { |
|
332 z--; |
|
333 if (ctx->tmp[jj-2] == '=') |
|
334 z--; |
|
335 } |
|
336 } |
|
337 /* z is now number of output bytes and jj is the |
|
338 * number consumed */ |
|
339 if (jj != i) |
|
340 { |
|
341 memcpy((unsigned char *)ctx->tmp, |
|
342 (unsigned char *)&(ctx->tmp[jj]),i-jj); |
|
343 ctx->tmp_len=i-jj; |
|
344 } |
|
345 ctx->buf_len=0; |
|
346 if (z > 0) |
|
347 { |
|
348 ctx->buf_len=z; |
|
349 i=1; |
|
350 } |
|
351 else |
|
352 i=z; |
|
353 } |
|
354 else |
|
355 { |
|
356 i=EVP_DecodeUpdate(&(ctx->base64), |
|
357 (unsigned char *)ctx->buf,&ctx->buf_len, |
|
358 (unsigned char *)ctx->tmp,i); |
|
359 ctx->tmp_len = 0; |
|
360 } |
|
361 ctx->buf_off=0; |
|
362 if (i < 0) |
|
363 { |
|
364 ret_code=0; |
|
365 ctx->buf_len=0; |
|
366 break; |
|
367 } |
|
368 |
|
369 if (ctx->buf_len <= outl) |
|
370 i=ctx->buf_len; |
|
371 else |
|
372 i=outl; |
|
373 |
|
374 memcpy(out,ctx->buf,i); |
|
375 ret+=i; |
|
376 ctx->buf_off=i; |
|
377 if (ctx->buf_off == ctx->buf_len) |
|
378 { |
|
379 ctx->buf_len=0; |
|
380 ctx->buf_off=0; |
|
381 } |
|
382 outl-=i; |
|
383 out+=i; |
|
384 } |
|
385 BIO_clear_retry_flags(b); |
|
386 BIO_copy_next_retry(b); |
|
387 return((ret == 0)?ret_code:ret); |
|
388 } |
|
389 |
|
390 static int b64_write(BIO *b, const char *in, int inl) |
|
391 { |
|
392 int ret=inl,n,i; |
|
393 BIO_B64_CTX *ctx; |
|
394 |
|
395 ctx=(BIO_B64_CTX *)b->ptr; |
|
396 BIO_clear_retry_flags(b); |
|
397 |
|
398 if (ctx->encode != B64_ENCODE) |
|
399 { |
|
400 ctx->encode=B64_ENCODE; |
|
401 ctx->buf_len=0; |
|
402 ctx->buf_off=0; |
|
403 ctx->tmp_len=0; |
|
404 EVP_EncodeInit(&(ctx->base64)); |
|
405 } |
|
406 |
|
407 n=ctx->buf_len-ctx->buf_off; |
|
408 while (n > 0) |
|
409 { |
|
410 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); |
|
411 if (i <= 0) |
|
412 { |
|
413 BIO_copy_next_retry(b); |
|
414 return(i); |
|
415 } |
|
416 ctx->buf_off+=i; |
|
417 n-=i; |
|
418 } |
|
419 /* at this point all pending data has been written */ |
|
420 ctx->buf_off=0; |
|
421 ctx->buf_len=0; |
|
422 |
|
423 if ((in == NULL) || (inl <= 0)) return(0); |
|
424 |
|
425 while (inl > 0) |
|
426 { |
|
427 n=(inl > B64_BLOCK_SIZE)?B64_BLOCK_SIZE:inl; |
|
428 |
|
429 if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) |
|
430 { |
|
431 if (ctx->tmp_len > 0) |
|
432 { |
|
433 n=3-ctx->tmp_len; |
|
434 /* There's a teoretical possibility for this */ |
|
435 if (n > inl) |
|
436 n=inl; |
|
437 memcpy(&(ctx->tmp[ctx->tmp_len]),in,n); |
|
438 ctx->tmp_len+=n; |
|
439 if (ctx->tmp_len < 3) |
|
440 break; |
|
441 ctx->buf_len=EVP_EncodeBlock( |
|
442 (unsigned char *)ctx->buf, |
|
443 (unsigned char *)ctx->tmp, |
|
444 ctx->tmp_len); |
|
445 /* Since we're now done using the temporary |
|
446 buffer, the length should be 0'd */ |
|
447 ctx->tmp_len=0; |
|
448 } |
|
449 else |
|
450 { |
|
451 if (n < 3) |
|
452 { |
|
453 memcpy(&(ctx->tmp[0]),in,n); |
|
454 ctx->tmp_len=n; |
|
455 break; |
|
456 } |
|
457 n-=n%3; |
|
458 ctx->buf_len=EVP_EncodeBlock( |
|
459 (unsigned char *)ctx->buf, |
|
460 (unsigned char *)in,n); |
|
461 } |
|
462 } |
|
463 else |
|
464 { |
|
465 EVP_EncodeUpdate(&(ctx->base64), |
|
466 (unsigned char *)ctx->buf,&ctx->buf_len, |
|
467 (unsigned char *)in,n); |
|
468 } |
|
469 inl-=n; |
|
470 in+=n; |
|
471 |
|
472 ctx->buf_off=0; |
|
473 n=ctx->buf_len; |
|
474 while (n > 0) |
|
475 { |
|
476 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n); |
|
477 if (i <= 0) |
|
478 { |
|
479 BIO_copy_next_retry(b); |
|
480 return((ret == 0)?i:ret); |
|
481 } |
|
482 n-=i; |
|
483 ctx->buf_off+=i; |
|
484 } |
|
485 ctx->buf_len=0; |
|
486 ctx->buf_off=0; |
|
487 } |
|
488 return(ret); |
|
489 } |
|
490 |
|
491 static long b64_ctrl(BIO *b, int cmd, long num, void *ptr) |
|
492 { |
|
493 BIO_B64_CTX *ctx; |
|
494 long ret=1; |
|
495 int i; |
|
496 |
|
497 ctx=(BIO_B64_CTX *)b->ptr; |
|
498 |
|
499 switch (cmd) |
|
500 { |
|
501 case BIO_CTRL_RESET: |
|
502 ctx->cont=1; |
|
503 ctx->start=1; |
|
504 ctx->encode=B64_NONE; |
|
505 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); |
|
506 break; |
|
507 case BIO_CTRL_EOF: /* More to read */ |
|
508 if (ctx->cont <= 0) |
|
509 ret=1; |
|
510 else |
|
511 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); |
|
512 break; |
|
513 case BIO_CTRL_WPENDING: /* More to write in buffer */ |
|
514 ret=ctx->buf_len-ctx->buf_off; |
|
515 if ((ret == 0) && (ctx->encode != B64_NONE) |
|
516 && (ctx->base64.num != 0)) |
|
517 ret=1; |
|
518 else if (ret <= 0) |
|
519 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); |
|
520 break; |
|
521 case BIO_CTRL_PENDING: /* More to read in buffer */ |
|
522 ret=ctx->buf_len-ctx->buf_off; |
|
523 if (ret <= 0) |
|
524 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); |
|
525 break; |
|
526 case BIO_CTRL_FLUSH: |
|
527 /* do a final write */ |
|
528 again: |
|
529 while (ctx->buf_len != ctx->buf_off) |
|
530 { |
|
531 i=b64_write(b,NULL,0); |
|
532 if (i < 0) |
|
533 return i; |
|
534 } |
|
535 if (BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) |
|
536 { |
|
537 if (ctx->tmp_len != 0) |
|
538 { |
|
539 ctx->buf_len=EVP_EncodeBlock( |
|
540 (unsigned char *)ctx->buf, |
|
541 (unsigned char *)ctx->tmp, |
|
542 ctx->tmp_len); |
|
543 ctx->buf_off=0; |
|
544 ctx->tmp_len=0; |
|
545 goto again; |
|
546 } |
|
547 } |
|
548 else if (ctx->encode != B64_NONE && ctx->base64.num != 0) |
|
549 { |
|
550 ctx->buf_off=0; |
|
551 EVP_EncodeFinal(&(ctx->base64), |
|
552 (unsigned char *)ctx->buf, |
|
553 &(ctx->buf_len)); |
|
554 /* push out the bytes */ |
|
555 goto again; |
|
556 } |
|
557 /* Finally flush the underlying BIO */ |
|
558 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); |
|
559 break; |
|
560 |
|
561 case BIO_C_DO_STATE_MACHINE: |
|
562 BIO_clear_retry_flags(b); |
|
563 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); |
|
564 BIO_copy_next_retry(b); |
|
565 break; |
|
566 |
|
567 case BIO_CTRL_DUP: |
|
568 break; |
|
569 case BIO_CTRL_INFO: |
|
570 case BIO_CTRL_GET: |
|
571 case BIO_CTRL_SET: |
|
572 default: |
|
573 ret=BIO_ctrl(b->next_bio,cmd,num,ptr); |
|
574 break; |
|
575 } |
|
576 return(ret); |
|
577 } |
|
578 |
|
579 static long b64_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) |
|
580 { |
|
581 long ret=1; |
|
582 |
|
583 if (b->next_bio == NULL) return(0); |
|
584 switch (cmd) |
|
585 { |
|
586 default: |
|
587 ret=BIO_callback_ctrl(b->next_bio,cmd,fp); |
|
588 break; |
|
589 } |
|
590 return(ret); |
|
591 } |
|
592 |