xref: /freebsd/crypto/openssl/crypto/evp/bio_ok.c (revision aa0a1e58)
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 void sig_out(BIO* b);
137 static void sig_in(BIO* b);
138 static void block_out(BIO* b);
139 static 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 
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) 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 
284 static 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 
344 static 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 
430 static 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 
444 static 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 
458 static 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 
484 static 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 
521 static 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 
541 static 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