1/* crypto/evp/bio_ok.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	From: Arne Ansper <arne@cyber.ee>
61
62	Why BIO_f_reliable?
63
64	I wrote function which took BIO* as argument, read data from it
65	and processed it. Then I wanted to store the input file in
66	encrypted form. OK I pushed BIO_f_cipher to the BIO stack
67	and everything was OK. BUT if user types wrong password
68	BIO_f_cipher outputs only garbage and my function crashes. Yes
69	I can and I should fix my function, but BIO_f_cipher is
70	easy way to add encryption support to many existing applications
71	and it's hard to debug and fix them all.
72
73	So I wanted another BIO which would catch the incorrect passwords and
74	file damages which cause garbage on BIO_f_cipher's output.
75
76	The easy way is to push the BIO_f_md and save the checksum at
77	the end of the file. However there are several problems with this
78	approach:
79
80	1) you must somehow separate checksum from actual data.
81	2) you need lot's of memory when reading the file, because you
82	must read to the end of the file and verify the checksum before
83	letting the application to read the data.
84
85	BIO_f_reliable tries to solve both problems, so that you can
86	read and write arbitrary long streams using only fixed amount
87	of memory.
88
89	BIO_f_reliable splits data stream into blocks. Each block is prefixed
90	with it's length and suffixed with it's digest. So you need only
91	several Kbytes of memory to buffer single block before verifying
92	it's digest.
93
94	BIO_f_reliable goes further and adds several important capabilities:
95
96	1) the digest of the block is computed over the whole stream
97	-- so nobody can rearrange the blocks or remove or replace them.
98
99	2) to detect invalid passwords right at the start BIO_f_reliable
100	adds special prefix to the stream. In order to avoid known plain-text
101	attacks this prefix is generated as follows:
102
103		*) digest is initialized with random seed instead of
104		standardized one.
105		*) same seed is written to output
106		*) well-known text is then hashed and the output
107		of the digest is also written to output.
108
109	reader can now read the seed from stream, hash the same string
110	and then compare the digest output.
111
112	Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I
113	initially wrote and tested this code on x86 machine and wrote the
114	digests out in machine-dependent order :( There are people using
115	this code and I cannot change this easily without making existing
116	data files unreadable.
117
118*/
119
120#include <stdio.h>
121#include <errno.h>
122#include <assert.h>
123#include "cryptlib.h"
124#include <openssl/buffer.h>
125#include <openssl/bio.h>
126#include <openssl/evp.h>
127#include <openssl/rand.h>
128
129static int ok_write(BIO *h, const char *buf, int num);
130static int ok_read(BIO *h, char *buf, int size);
131static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
132static int ok_new(BIO *h);
133static int ok_free(BIO *data);
134static long ok_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
135
136static void sig_out(BIO* b);
137static void sig_in(BIO* b);
138static void block_out(BIO* b);
139static void block_in(BIO* b);
140#define OK_BLOCK_SIZE	(1024*4)
141#define OK_BLOCK_BLOCK	4
142#define IOBS		(OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE)
143#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
144
145typedef struct ok_struct
146	{
147	size_t buf_len;
148	size_t buf_off;
149	size_t buf_len_save;
150	size_t buf_off_save;
151	int cont;		/* <= 0 when finished */
152	int finished;
153	EVP_MD_CTX md;
154	int blockout;		/* output block is ready */
155	int sigio;		/* must process signature */
156	unsigned char buf[IOBS];
157	} BIO_OK_CTX;
158
159static BIO_METHOD methods_ok=
160	{
161	BIO_TYPE_CIPHER,"reliable",
162	ok_write,
163	ok_read,
164	NULL, /* ok_puts, */
165	NULL, /* ok_gets, */
166	ok_ctrl,
167	ok_new,
168	ok_free,
169	ok_callback_ctrl,
170	};
171
172BIO_METHOD *BIO_f_reliable(void)
173	{
174	return(&methods_ok);
175	}
176
177static int ok_new(BIO *bi)
178	{
179	BIO_OK_CTX *ctx;
180
181	ctx=(BIO_OK_CTX *)OPENSSL_malloc(sizeof(BIO_OK_CTX));
182	if (ctx == NULL) return(0);
183
184	ctx->buf_len=0;
185	ctx->buf_off=0;
186	ctx->buf_len_save=0;
187	ctx->buf_off_save=0;
188	ctx->cont=1;
189	ctx->finished=0;
190	ctx->blockout= 0;
191	ctx->sigio=1;
192
193	EVP_MD_CTX_init(&ctx->md);
194
195	bi->init=0;
196	bi->ptr=(char *)ctx;
197	bi->flags=0;
198	return(1);
199	}
200
201static int ok_free(BIO *a)
202	{
203	if (a == NULL) return(0);
204	EVP_MD_CTX_cleanup(&((BIO_OK_CTX *)a->ptr)->md);
205	OPENSSL_cleanse(a->ptr,sizeof(BIO_OK_CTX));
206	OPENSSL_free(a->ptr);
207	a->ptr=NULL;
208	a->init=0;
209	a->flags=0;
210	return(1);
211	}
212
213static int ok_read(BIO *b, char *out, int outl)
214	{
215	int ret=0,i,n;
216	BIO_OK_CTX *ctx;
217
218	if (out == NULL) return(0);
219	ctx=(BIO_OK_CTX *)b->ptr;
220
221	if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) return(0);
222
223	while(outl > 0)
224		{
225
226		/* copy clean bytes to output buffer */
227		if (ctx->blockout)
228			{
229			i=ctx->buf_len-ctx->buf_off;
230			if (i > outl) i=outl;
231			memcpy(out,&(ctx->buf[ctx->buf_off]),i);
232			ret+=i;
233			out+=i;
234			outl-=i;
235			ctx->buf_off+=i;
236
237			/* all clean bytes are out */
238			if (ctx->buf_len == ctx->buf_off)
239				{
240				ctx->buf_off=0;
241
242				/* copy start of the next block into proper place */
243				if(ctx->buf_len_save- ctx->buf_off_save > 0)
244					{
245					ctx->buf_len= ctx->buf_len_save- ctx->buf_off_save;
246					memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
247							ctx->buf_len);
248					}
249				else
250					{
251					ctx->buf_len=0;
252					}
253				ctx->blockout= 0;
254				}
255			}
256
257		/* output buffer full -- cancel */
258		if (outl == 0) break;
259
260		/* no clean bytes in buffer -- fill it */
261		n=IOBS- ctx->buf_len;
262		i=BIO_read(b->next_bio,&(ctx->buf[ctx->buf_len]),n);
263
264		if (i <= 0) break;	/* nothing new */
265
266		ctx->buf_len+= i;
267
268		/* no signature yet -- check if we got one */
269		if (ctx->sigio == 1) sig_in(b);
270
271		/* signature ok -- check if we got block */
272		if (ctx->sigio == 0) block_in(b);
273
274		/* invalid block -- cancel */
275		if (ctx->cont <= 0) break;
276
277		}
278
279	BIO_clear_retry_flags(b);
280	BIO_copy_next_retry(b);
281	return(ret);
282	}
283
284static int ok_write(BIO *b, const char *in, int inl)
285	{
286	int ret=0,n,i;
287	BIO_OK_CTX *ctx;
288
289	if (inl <= 0) return inl;
290
291	ctx=(BIO_OK_CTX *)b->ptr;
292	ret=inl;
293
294	if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) return(0);
295
296	if(ctx->sigio) sig_out(b);
297
298	do{
299		BIO_clear_retry_flags(b);
300		n=ctx->buf_len-ctx->buf_off;
301		while (ctx->blockout && n > 0)
302			{
303			i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
304			if (i <= 0)
305				{
306				BIO_copy_next_retry(b);
307				if(!BIO_should_retry(b))
308					ctx->cont= 0;
309				return(i);
310				}
311			ctx->buf_off+=i;
312			n-=i;
313			}
314
315		/* at this point all pending data has been written */
316		ctx->blockout= 0;
317		if (ctx->buf_len == ctx->buf_off)
318			{
319			ctx->buf_len=OK_BLOCK_BLOCK;
320			ctx->buf_off=0;
321			}
322
323		if ((in == NULL) || (inl <= 0)) return(0);
324
325		n= (inl+ ctx->buf_len > OK_BLOCK_SIZE+ OK_BLOCK_BLOCK) ?
326			(int)(OK_BLOCK_SIZE+OK_BLOCK_BLOCK-ctx->buf_len) : inl;
327
328		memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])),(unsigned char *)in,n);
329		ctx->buf_len+= n;
330		inl-=n;
331		in+=n;
332
333		if(ctx->buf_len >= OK_BLOCK_SIZE+ OK_BLOCK_BLOCK)
334			{
335			block_out(b);
336			}
337	}while(inl > 0);
338
339	BIO_clear_retry_flags(b);
340	BIO_copy_next_retry(b);
341	return(ret);
342	}
343
344static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
345	{
346	BIO_OK_CTX *ctx;
347	EVP_MD *md;
348	const EVP_MD **ppmd;
349	long ret=1;
350	int i;
351
352	ctx=b->ptr;
353
354	switch (cmd)
355		{
356	case BIO_CTRL_RESET:
357		ctx->buf_len=0;
358		ctx->buf_off=0;
359		ctx->buf_len_save=0;
360		ctx->buf_off_save=0;
361		ctx->cont=1;
362		ctx->finished=0;
363		ctx->blockout= 0;
364		ctx->sigio=1;
365		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
366		break;
367	case BIO_CTRL_EOF:	/* More to read */
368		if (ctx->cont <= 0)
369			ret=1;
370		else
371			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
372		break;
373	case BIO_CTRL_PENDING: /* More to read in buffer */
374	case BIO_CTRL_WPENDING: /* More to read in buffer */
375		ret=ctx->blockout ? ctx->buf_len-ctx->buf_off : 0;
376		if (ret <= 0)
377			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
378		break;
379	case BIO_CTRL_FLUSH:
380		/* do a final write */
381		if(ctx->blockout == 0)
382			block_out(b);
383
384		while (ctx->blockout)
385			{
386			i=ok_write(b,NULL,0);
387			if (i < 0)
388				{
389				ret=i;
390				break;
391				}
392			}
393
394		ctx->finished=1;
395		ctx->buf_off=ctx->buf_len=0;
396		ctx->cont=(int)ret;
397
398		/* Finally flush the underlying BIO */
399		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
400		break;
401	case BIO_C_DO_STATE_MACHINE:
402		BIO_clear_retry_flags(b);
403		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
404		BIO_copy_next_retry(b);
405		break;
406	case BIO_CTRL_INFO:
407		ret=(long)ctx->cont;
408		break;
409	case BIO_C_SET_MD:
410		md=ptr;
411		EVP_DigestInit_ex(&ctx->md, md, NULL);
412		b->init=1;
413		break;
414	case BIO_C_GET_MD:
415		if (b->init)
416			{
417			ppmd=ptr;
418			*ppmd=ctx->md.digest;
419			}
420		else
421			ret=0;
422		break;
423	default:
424		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
425		break;
426		}
427	return(ret);
428	}
429
430static long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
431	{
432	long ret=1;
433
434	if (b->next_bio == NULL) return(0);
435	switch (cmd)
436		{
437	default:
438		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
439		break;
440		}
441	return(ret);
442	}
443
444static void longswap(void *_ptr, size_t len)
445{	const union { long one; char little; } is_endian = {1};
446
447	if (is_endian.little) {
448		size_t i;
449		unsigned char *p=_ptr,c;
450
451		for(i= 0;i < len;i+= 4) {
452			c=p[0],p[0]=p[3],p[3]=c;
453			c=p[1],p[1]=p[2],p[2]=c;
454		}
455	}
456}
457
458static void sig_out(BIO* b)
459	{
460	BIO_OK_CTX *ctx;
461	EVP_MD_CTX *md;
462
463	ctx=b->ptr;
464	md=&ctx->md;
465
466	if(ctx->buf_len+ 2* md->digest->md_size > OK_BLOCK_SIZE) return;
467
468	EVP_DigestInit_ex(md, md->digest, NULL);
469	/* FIXME: there's absolutely no guarantee this makes any sense at all,
470	 * particularly now EVP_MD_CTX has been restructured.
471	 */
472	RAND_pseudo_bytes(md->md_data, md->digest->md_size);
473	memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size);
474	longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size);
475	ctx->buf_len+= md->digest->md_size;
476
477	EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN));
478	EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL);
479	ctx->buf_len+= md->digest->md_size;
480	ctx->blockout= 1;
481	ctx->sigio= 0;
482	}
483
484static void sig_in(BIO* b)
485	{
486	BIO_OK_CTX *ctx;
487	EVP_MD_CTX *md;
488	unsigned char tmp[EVP_MAX_MD_SIZE];
489	int ret= 0;
490
491	ctx=b->ptr;
492	md=&ctx->md;
493
494	if((int)(ctx->buf_len-ctx->buf_off) < 2*md->digest->md_size) return;
495
496	EVP_DigestInit_ex(md, md->digest, NULL);
497	memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size);
498	longswap(md->md_data, md->digest->md_size);
499	ctx->buf_off+= md->digest->md_size;
500
501	EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN));
502	EVP_DigestFinal_ex(md, tmp, NULL);
503	ret= memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0;
504	ctx->buf_off+= md->digest->md_size;
505	if(ret == 1)
506		{
507		ctx->sigio= 0;
508		if(ctx->buf_len != ctx->buf_off)
509			{
510			memmove(ctx->buf, &(ctx->buf[ctx->buf_off]), ctx->buf_len- ctx->buf_off);
511			}
512		ctx->buf_len-= ctx->buf_off;
513		ctx->buf_off= 0;
514		}
515	else
516		{
517		ctx->cont= 0;
518		}
519	}
520
521static void block_out(BIO* b)
522	{
523	BIO_OK_CTX *ctx;
524	EVP_MD_CTX *md;
525	unsigned long tl;
526
527	ctx=b->ptr;
528	md=&ctx->md;
529
530	tl= ctx->buf_len- OK_BLOCK_BLOCK;
531	ctx->buf[0]=(unsigned char)(tl>>24);
532	ctx->buf[1]=(unsigned char)(tl>>16);
533	ctx->buf[2]=(unsigned char)(tl>>8);
534	ctx->buf[3]=(unsigned char)(tl);
535	EVP_DigestUpdate(md, (unsigned char*) &(ctx->buf[OK_BLOCK_BLOCK]), tl);
536	EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL);
537	ctx->buf_len+= md->digest->md_size;
538	ctx->blockout= 1;
539	}
540
541static void block_in(BIO* b)
542	{
543	BIO_OK_CTX *ctx;
544	EVP_MD_CTX *md;
545	unsigned long tl= 0;
546	unsigned char tmp[EVP_MAX_MD_SIZE];
547
548	ctx=b->ptr;
549	md=&ctx->md;
550
551	assert(sizeof(tl)>=OK_BLOCK_BLOCK);	/* always true */
552	tl =ctx->buf[0]; tl<<=8;
553	tl|=ctx->buf[1]; tl<<=8;
554	tl|=ctx->buf[2]; tl<<=8;
555	tl|=ctx->buf[3];
556
557	if (ctx->buf_len < tl+ OK_BLOCK_BLOCK+ md->digest->md_size) return;
558
559	EVP_DigestUpdate(md, (unsigned char*) &(ctx->buf[OK_BLOCK_BLOCK]), tl);
560	EVP_DigestFinal_ex(md, tmp, NULL);
561	if(memcmp(&(ctx->buf[tl+ OK_BLOCK_BLOCK]), tmp, md->digest->md_size) == 0)
562		{
563		/* there might be parts from next block lurking around ! */
564		ctx->buf_off_save= tl+ OK_BLOCK_BLOCK+ md->digest->md_size;
565		ctx->buf_len_save= ctx->buf_len;
566		ctx->buf_off= OK_BLOCK_BLOCK;
567		ctx->buf_len= tl+ OK_BLOCK_BLOCK;
568		ctx->blockout= 1;
569		}
570	else
571		{
572		ctx->cont= 0;
573		}
574	}
575
576