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 
129 static int ok_write(BIO *h, const char *buf, int num);
130 static int ok_read(BIO *h, char *buf, int size);
131 static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
132 static int ok_new(BIO *h);
133 static int ok_free(BIO *data);
134 static long ok_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
135 
136 static __owur int sig_out(BIO* b);
137 static __owur int sig_in(BIO* b);
138 static __owur int block_out(BIO* b);
139 static __owur int 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 
145 typedef 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 
159 static 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 
172 BIO_METHOD *BIO_f_reliable(void)
173 	{
174 	return(&methods_ok);
175 	}
176 
177 static 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 
201 static 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 
213 static 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)
270 			{
271 			if (!sig_in(b))
272 				{
273 				BIO_clear_retry_flags(b);
274 				return 0;
275 				}
276 			}
277 
278 		/* signature ok -- check if we got block */
279 		if (ctx->sigio == 0)
280 			{
281 			if (!block_in(b))
282 				{
283 				BIO_clear_retry_flags(b);
284 				return 0;
285 				}
286 			}
287 
288 		/* invalid block -- cancel */
289 		if (ctx->cont <= 0) break;
290 
291 		}
292 
293 	BIO_clear_retry_flags(b);
294 	BIO_copy_next_retry(b);
295 	return(ret);
296 	}
297 
298 static int ok_write(BIO *b, const char *in, int inl)
299 	{
300 	int ret=0,n,i;
301 	BIO_OK_CTX *ctx;
302 
303 	if (inl <= 0) return inl;
304 
305 	ctx=(BIO_OK_CTX *)b->ptr;
306 	ret=inl;
307 
308 	if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) return(0);
309 
310 	if(ctx->sigio && !sig_out(b))
311 		return 0;
312 
313 	do{
314 		BIO_clear_retry_flags(b);
315 		n=ctx->buf_len-ctx->buf_off;
316 		while (ctx->blockout && n > 0)
317 			{
318 			i=BIO_write(b->next_bio,&(ctx->buf[ctx->buf_off]),n);
319 			if (i <= 0)
320 				{
321 				BIO_copy_next_retry(b);
322 				if(!BIO_should_retry(b))
323 					ctx->cont= 0;
324 				return(i);
325 				}
326 			ctx->buf_off+=i;
327 			n-=i;
328 			}
329 
330 		/* at this point all pending data has been written */
331 		ctx->blockout= 0;
332 		if (ctx->buf_len == ctx->buf_off)
333 			{
334 			ctx->buf_len=OK_BLOCK_BLOCK;
335 			ctx->buf_off=0;
336 			}
337 
338 		if ((in == NULL) || (inl <= 0)) return(0);
339 
340 		n= (inl+ ctx->buf_len > OK_BLOCK_SIZE+ OK_BLOCK_BLOCK) ?
341 			(int)(OK_BLOCK_SIZE+OK_BLOCK_BLOCK-ctx->buf_len) : inl;
342 
343 		memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])),(unsigned char *)in,n);
344 		ctx->buf_len+= n;
345 		inl-=n;
346 		in+=n;
347 
348 		if(ctx->buf_len >= OK_BLOCK_SIZE+ OK_BLOCK_BLOCK)
349 			{
350 			if (!block_out(b))
351 				{
352 				BIO_clear_retry_flags(b);
353 				return 0;
354 				}
355 			}
356 	}while(inl > 0);
357 
358 	BIO_clear_retry_flags(b);
359 	BIO_copy_next_retry(b);
360 	return(ret);
361 	}
362 
363 static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
364 	{
365 	BIO_OK_CTX *ctx;
366 	EVP_MD *md;
367 	const EVP_MD **ppmd;
368 	long ret=1;
369 	int i;
370 
371 	ctx=b->ptr;
372 
373 	switch (cmd)
374 		{
375 	case BIO_CTRL_RESET:
376 		ctx->buf_len=0;
377 		ctx->buf_off=0;
378 		ctx->buf_len_save=0;
379 		ctx->buf_off_save=0;
380 		ctx->cont=1;
381 		ctx->finished=0;
382 		ctx->blockout= 0;
383 		ctx->sigio=1;
384 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
385 		break;
386 	case BIO_CTRL_EOF:	/* More to read */
387 		if (ctx->cont <= 0)
388 			ret=1;
389 		else
390 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
391 		break;
392 	case BIO_CTRL_PENDING: /* More to read in buffer */
393 	case BIO_CTRL_WPENDING: /* More to read in buffer */
394 		ret=ctx->blockout ? ctx->buf_len-ctx->buf_off : 0;
395 		if (ret <= 0)
396 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
397 		break;
398 	case BIO_CTRL_FLUSH:
399 		/* do a final write */
400 		if(ctx->blockout == 0)
401 			if (!block_out(b))
402 				return 0;
403 
404 		while (ctx->blockout)
405 			{
406 			i=ok_write(b,NULL,0);
407 			if (i < 0)
408 				{
409 				ret=i;
410 				break;
411 				}
412 			}
413 
414 		ctx->finished=1;
415 		ctx->buf_off=ctx->buf_len=0;
416 		ctx->cont=(int)ret;
417 
418 		/* Finally flush the underlying BIO */
419 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
420 		break;
421 	case BIO_C_DO_STATE_MACHINE:
422 		BIO_clear_retry_flags(b);
423 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
424 		BIO_copy_next_retry(b);
425 		break;
426 	case BIO_CTRL_INFO:
427 		ret=(long)ctx->cont;
428 		break;
429 	case BIO_C_SET_MD:
430 		md=ptr;
431 		if (!EVP_DigestInit_ex(&ctx->md, md, NULL))
432 			return 0;
433 		b->init=1;
434 		break;
435 	case BIO_C_GET_MD:
436 		if (b->init)
437 			{
438 			ppmd=ptr;
439 			*ppmd=ctx->md.digest;
440 			}
441 		else
442 			ret=0;
443 		break;
444 	default:
445 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
446 		break;
447 		}
448 	return(ret);
449 	}
450 
451 static long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
452 	{
453 	long ret=1;
454 
455 	if (b->next_bio == NULL) return(0);
456 	switch (cmd)
457 		{
458 	default:
459 		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
460 		break;
461 		}
462 	return(ret);
463 	}
464 
465 static void longswap(void *_ptr, size_t len)
466 {	const union { long one; char little; } is_endian = {1};
467 
468 	if (is_endian.little) {
469 		size_t i;
470 		unsigned char *p=_ptr,c;
471 
472 		for(i= 0;i < len;i+= 4) {
473 			c=p[0],p[0]=p[3],p[3]=c;
474 			c=p[1],p[1]=p[2],p[2]=c;
475 		}
476 	}
477 }
478 
479 static int sig_out(BIO* b)
480 	{
481 	BIO_OK_CTX *ctx;
482 	EVP_MD_CTX *md;
483 
484 	ctx=b->ptr;
485 	md=&ctx->md;
486 
487 	if(ctx->buf_len+ 2* md->digest->md_size > OK_BLOCK_SIZE) return 1;
488 
489 	if (!EVP_DigestInit_ex(md, md->digest, NULL))
490 		goto berr;
491 	/* FIXME: there's absolutely no guarantee this makes any sense at all,
492 	 * particularly now EVP_MD_CTX has been restructured.
493 	 */
494 	RAND_pseudo_bytes(md->md_data, md->digest->md_size);
495 	memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size);
496 	longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size);
497 	ctx->buf_len+= md->digest->md_size;
498 
499 	if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
500 		goto berr;
501 	if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
502 		goto berr;
503 	ctx->buf_len+= md->digest->md_size;
504 	ctx->blockout= 1;
505 	ctx->sigio= 0;
506 	return 1;
507 	berr:
508 	BIO_clear_retry_flags(b);
509 	return 0;
510 	}
511 
512 static int sig_in(BIO* b)
513 	{
514 	BIO_OK_CTX *ctx;
515 	EVP_MD_CTX *md;
516 	unsigned char tmp[EVP_MAX_MD_SIZE];
517 	int ret= 0;
518 
519 	ctx=b->ptr;
520 	md=&ctx->md;
521 
522 	if((int)(ctx->buf_len-ctx->buf_off) < 2*md->digest->md_size) return 1;
523 
524 	if (!EVP_DigestInit_ex(md, md->digest, NULL))
525 		goto berr;
526 	memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size);
527 	longswap(md->md_data, md->digest->md_size);
528 	ctx->buf_off+= md->digest->md_size;
529 
530 	if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
531 		goto berr;
532 	if (!EVP_DigestFinal_ex(md, tmp, NULL))
533 		goto berr;
534 	ret= memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0;
535 	ctx->buf_off+= md->digest->md_size;
536 	if(ret == 1)
537 		{
538 		ctx->sigio= 0;
539 		if(ctx->buf_len != ctx->buf_off)
540 			{
541 			memmove(ctx->buf, &(ctx->buf[ctx->buf_off]), ctx->buf_len- ctx->buf_off);
542 			}
543 		ctx->buf_len-= ctx->buf_off;
544 		ctx->buf_off= 0;
545 		}
546 	else
547 		{
548 		ctx->cont= 0;
549 		}
550 	return 1;
551 	berr:
552 	BIO_clear_retry_flags(b);
553 	return 0;
554 	}
555 
556 static int block_out(BIO* b)
557 	{
558 	BIO_OK_CTX *ctx;
559 	EVP_MD_CTX *md;
560 	unsigned long tl;
561 
562 	ctx=b->ptr;
563 	md=&ctx->md;
564 
565 	tl= ctx->buf_len- OK_BLOCK_BLOCK;
566 	ctx->buf[0]=(unsigned char)(tl>>24);
567 	ctx->buf[1]=(unsigned char)(tl>>16);
568 	ctx->buf[2]=(unsigned char)(tl>>8);
569 	ctx->buf[3]=(unsigned char)(tl);
570 	if (!EVP_DigestUpdate(md,
571 		(unsigned char*) &(ctx->buf[OK_BLOCK_BLOCK]), tl))
572 		goto berr;
573 	if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
574 		goto berr;
575 	ctx->buf_len+= md->digest->md_size;
576 	ctx->blockout= 1;
577 	return 1;
578 	berr:
579 	BIO_clear_retry_flags(b);
580 	return 0;
581 	}
582 
583 static int block_in(BIO* b)
584 	{
585 	BIO_OK_CTX *ctx;
586 	EVP_MD_CTX *md;
587 	unsigned long tl= 0;
588 	unsigned char tmp[EVP_MAX_MD_SIZE];
589 
590 	ctx=b->ptr;
591 	md=&ctx->md;
592 
593 	assert(sizeof(tl)>=OK_BLOCK_BLOCK);	/* always true */
594 	tl =ctx->buf[0]; tl<<=8;
595 	tl|=ctx->buf[1]; tl<<=8;
596 	tl|=ctx->buf[2]; tl<<=8;
597 	tl|=ctx->buf[3];
598 
599 	if (ctx->buf_len < tl+ OK_BLOCK_BLOCK+ md->digest->md_size) return 1;
600 
601 	if (!EVP_DigestUpdate(md,
602 			(unsigned char*) &(ctx->buf[OK_BLOCK_BLOCK]), tl))
603 		goto berr;
604 	if (!EVP_DigestFinal_ex(md, tmp, NULL))
605 		goto berr;
606 	if(memcmp(&(ctx->buf[tl+ OK_BLOCK_BLOCK]), tmp, md->digest->md_size) == 0)
607 		{
608 		/* there might be parts from next block lurking around ! */
609 		ctx->buf_off_save= tl+ OK_BLOCK_BLOCK+ md->digest->md_size;
610 		ctx->buf_len_save= ctx->buf_len;
611 		ctx->buf_off= OK_BLOCK_BLOCK;
612 		ctx->buf_len= tl+ OK_BLOCK_BLOCK;
613 		ctx->blockout= 1;
614 		}
615 	else
616 		{
617 		ctx->cont= 0;
618 		}
619 	return 1;
620 	berr:
621 	BIO_clear_retry_flags(b);
622 	return 0;
623 	}
624 
625