Update contrib.
1 /* crypto/evp/bio_ok.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
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.
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).
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.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
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)"
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
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.]
60 © Portions copyright (c) 2006 Nokia Corporation. All rights reserved.
63 From: Arne Ansper <arne@cyber.ee>
67 I wrote function which took BIO* as argument, read data from it
68 and processed it. Then I wanted to store the input file in
69 encrypted form. OK I pushed BIO_f_cipher to the BIO stack
70 and everything was OK. BUT if user types wrong password
71 BIO_f_cipher outputs only garbage and my function crashes. Yes
72 I can and I should fix my function, but BIO_f_cipher is
73 easy way to add encryption support to many existing applications
74 and it's hard to debug and fix them all.
76 So I wanted another BIO which would catch the incorrect passwords and
77 file damages which cause garbage on BIO_f_cipher's output.
79 The easy way is to push the BIO_f_md and save the checksum at
80 the end of the file. However there are several problems with this
83 1) you must somehow separate checksum from actual data.
84 2) you need lot's of memory when reading the file, because you
85 must read to the end of the file and verify the checksum before
86 letting the application to read the data.
88 BIO_f_reliable tries to solve both problems, so that you can
89 read and write arbitrary long streams using only fixed amount
92 BIO_f_reliable splits data stream into blocks. Each block is prefixed
93 with it's length and suffixed with it's digest. So you need only
94 several Kbytes of memory to buffer single block before verifying
97 BIO_f_reliable goes further and adds several important capabilities:
99 1) the digest of the block is computed over the whole stream
100 -- so nobody can rearrange the blocks or remove or replace them.
102 2) to detect invalid passwords right at the start BIO_f_reliable
103 adds special prefix to the stream. In order to avoid known plain-text
104 attacks this prefix is generated as follows:
106 *) digest is initialized with random seed instead of
108 *) same seed is written to output
109 *) well-known text is then hashed and the output
110 of the digest is also written to output.
112 reader can now read the seed from stream, hash the same string
113 and then compare the digest output.
115 Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I
116 initially wrote and tested this code on x86 machine and wrote the
117 digests out in machine-dependent order :( There are people using
118 this code and I cannot change this easily without making existing
119 data files unreadable.
126 #include "cryptlib.h"
127 #include <openssl/buffer.h>
128 #include <openssl/bio.h>
129 #include <openssl/evp.h>
130 #include <openssl/rand.h>
131 #if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__)))
132 #include "libcrypto_wsd_macros.h"
133 #include "libcrypto_wsd.h"
137 static int ok_write(BIO *h, const char *buf, int num);
138 static int ok_read(BIO *h, char *buf, int size);
139 static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
140 static int ok_new(BIO *h);
141 static int ok_free(BIO *data);
142 static long ok_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
144 static void sig_out(BIO* b);
145 static void sig_in(BIO* b);
146 static void block_out(BIO* b);
147 static void block_in(BIO* b);
148 #define OK_BLOCK_SIZE (1024*4)
149 #define OK_BLOCK_BLOCK 4
150 #define IOBS (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE)
151 #define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
153 typedef struct ok_struct
159 int cont; /* <= 0 when finished */
162 int blockout; /* output block is ready */
163 int sigio; /* must process signature */
164 unsigned char buf[IOBS];
168 static BIO_METHOD methods_ok=
170 BIO_TYPE_CIPHER,"reliable",
181 GET_STATIC_VAR_FROM_TLS(methods_ok,bio_ok,BIO_METHOD)
182 #define methods_ok (*GET_WSD_VAR_NAME(methods_ok,bio_ok, s)())
183 const BIO_METHOD temp_s_methods_ok=
185 BIO_TYPE_CIPHER,"reliable",
198 EXPORT_C BIO_METHOD *BIO_f_reliable(void)
203 static int ok_new(BIO *bi)
207 ctx=(BIO_OK_CTX *)OPENSSL_malloc(sizeof(BIO_OK_CTX));
208 if (ctx == NULL) return(0);
219 EVP_MD_CTX_init(&ctx->md);
227 static int ok_free(BIO *a)
229 if (a == NULL) return(0);
230 EVP_MD_CTX_cleanup(&((BIO_OK_CTX *)a->ptr)->md);
231 OPENSSL_cleanse(a->ptr,sizeof(BIO_OK_CTX));
232 OPENSSL_free(a->ptr);
239 static int ok_read(BIO *b, char *out, int outl)
244 if (out == NULL) return(0);
245 ctx=(BIO_OK_CTX *)b->ptr;
247 if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) return(0);
252 /* copy clean bytes to output buffer */
255 i=ctx->buf_len-ctx->buf_off;
256 if (i > outl) i=outl;
257 memcpy(out,&(ctx->buf[ctx->buf_off]),i);
263 /* all clean bytes are out */
264 if (ctx->buf_len == ctx->buf_off)
268 /* copy start of the next block into proper place */
269 if(ctx->buf_len_save- ctx->buf_off_save > 0)
271 ctx->buf_len= ctx->buf_len_save- ctx->buf_off_save;
272 memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
283 /* output buffer full -- cancel */
284 if (outl == 0) break;
286 /* no clean bytes in buffer -- fill it */
287 n=IOBS- ctx->buf_len;
288 i=BIO_read(b->next_bio,&(ctx->buf[ctx->buf_len]),n);
290 if (i <= 0) break; /* nothing new */
294 /* no signature yet -- check if we got one */
295 if (ctx->sigio == 1) sig_in(b);
297 /* signature ok -- check if we got block */
298 if (ctx->sigio == 0) block_in(b);
300 /* invalid block -- cancel */
301 if (ctx->cont <= 0) break;
305 BIO_clear_retry_flags(b);
306 BIO_copy_next_retry(b);
310 static int ok_write(BIO *b, const char *in, int inl)
315 if (inl <= 0) return inl;
317 ctx=(BIO_OK_CTX *)b->ptr;
320 if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) return(0);
322 if(ctx->sigio) sig_out(b);
325 BIO_clear_retry_flags(b);
326 n=ctx->buf_len-ctx->buf_off;
327 while (ctx->blockout && n > 0)
329 i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
332 BIO_copy_next_retry(b);
333 if(!BIO_should_retry(b))
341 /* at this point all pending data has been written */
343 if (ctx->buf_len == ctx->buf_off)
345 ctx->buf_len=OK_BLOCK_BLOCK;
349 if ((in == NULL) || (inl <= 0)) return(0);
351 n= (inl+ ctx->buf_len > OK_BLOCK_SIZE+ OK_BLOCK_BLOCK) ?
352 (int)(OK_BLOCK_SIZE+OK_BLOCK_BLOCK-ctx->buf_len) : inl;
354 memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])),(unsigned char *)in,n);
359 if(ctx->buf_len >= OK_BLOCK_SIZE+ OK_BLOCK_BLOCK)
365 BIO_clear_retry_flags(b);
366 BIO_copy_next_retry(b);
370 static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
391 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
393 case BIO_CTRL_EOF: /* More to read */
397 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
399 case BIO_CTRL_PENDING: /* More to read in buffer */
400 case BIO_CTRL_WPENDING: /* More to read in buffer */
401 ret=ctx->blockout ? ctx->buf_len-ctx->buf_off : 0;
403 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
406 /* do a final write */
407 if(ctx->blockout == 0)
410 while (ctx->blockout)
412 i=ok_write(b,NULL,0);
421 ctx->buf_off=ctx->buf_len=0;
424 /* Finally flush the underlying BIO */
425 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
427 case BIO_C_DO_STATE_MACHINE:
428 BIO_clear_retry_flags(b);
429 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
430 BIO_copy_next_retry(b);
437 EVP_DigestInit_ex(&ctx->md, md, NULL);
444 *ppmd=ctx->md.digest;
450 ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
456 static long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
460 if (b->next_bio == NULL) return(0);
464 ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
470 static void longswap(void *_ptr, size_t len)
471 { const union { long one; char little; } is_endian = {1};
473 if (is_endian.little) {
475 unsigned char *p=_ptr,c;
477 for(i= 0;i < len;i+= 4) {
478 c=p[0],p[0]=p[3],p[3]=c;
479 c=p[1],p[1]=p[2],p[2]=c;
484 static void sig_out(BIO* b)
492 if(ctx->buf_len+ 2* md->digest->md_size > OK_BLOCK_SIZE) return;
494 EVP_DigestInit_ex(md, md->digest, NULL);
495 /* FIXME: there's absolutely no guarantee this makes any sense at all,
496 * particularly now EVP_MD_CTX has been restructured.
498 RAND_pseudo_bytes(md->md_data, md->digest->md_size);
499 memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size);
500 longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size);
501 ctx->buf_len+= md->digest->md_size;
503 EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN));
504 EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL);
505 ctx->buf_len+= md->digest->md_size;
510 static void sig_in(BIO* b)
514 unsigned char tmp[EVP_MAX_MD_SIZE];
520 if((int)(ctx->buf_len-ctx->buf_off) < 2*md->digest->md_size) return;
522 EVP_DigestInit_ex(md, md->digest, NULL);
523 memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size);
524 longswap(md->md_data, md->digest->md_size);
525 ctx->buf_off+= md->digest->md_size;
527 EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN));
528 EVP_DigestFinal_ex(md, tmp, NULL);
529 ret= memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0;
530 ctx->buf_off+= md->digest->md_size;
534 if(ctx->buf_len != ctx->buf_off)
536 memmove(ctx->buf, &(ctx->buf[ctx->buf_off]), ctx->buf_len- ctx->buf_off);
538 ctx->buf_len-= ctx->buf_off;
547 static void block_out(BIO* b)
556 tl= ctx->buf_len- OK_BLOCK_BLOCK;
557 ctx->buf[0]=(unsigned char)(tl>>24);
558 ctx->buf[1]=(unsigned char)(tl>>16);
559 ctx->buf[2]=(unsigned char)(tl>>8);
560 ctx->buf[3]=(unsigned char)(tl);
561 EVP_DigestUpdate(md, (unsigned char*) &(ctx->buf[OK_BLOCK_BLOCK]), tl);
562 EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL);
563 ctx->buf_len+= md->digest->md_size;
567 static void block_in(BIO* b)
572 unsigned char tmp[EVP_MAX_MD_SIZE];
577 assert(sizeof(tl)>=OK_BLOCK_BLOCK); /* always true */
578 tl =ctx->buf[0]; tl<<=8;
579 tl|=ctx->buf[1]; tl<<=8;
580 tl|=ctx->buf[2]; tl<<=8;
583 if (ctx->buf_len < tl+ OK_BLOCK_BLOCK+ md->digest->md_size) return;
585 EVP_DigestUpdate(md, (unsigned char*) &(ctx->buf[OK_BLOCK_BLOCK]), tl);
586 EVP_DigestFinal_ex(md, tmp, NULL);
587 if(memcmp(&(ctx->buf[tl+ OK_BLOCK_BLOCK]), tmp, md->digest->md_size) == 0)
589 /* there might be parts from next block lurking around ! */
590 ctx->buf_off_save= tl+ OK_BLOCK_BLOCK+ md->digest->md_size;
591 ctx->buf_len_save= ctx->buf_len;
592 ctx->buf_off= OK_BLOCK_BLOCK;
593 ctx->buf_len= tl+ OK_BLOCK_BLOCK;