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 int sig_out(BIO *b);
137 static int sig_in(BIO *b);
138 static int block_out(BIO *b);
139 static 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     size_t buf_len;
147     size_t buf_off;
148     size_t buf_len_save;
149     size_t buf_off_save;
150     int cont;                   /* <= 0 when finished */
151     int finished;
152     EVP_MD_CTX md;
153     int blockout;               /* output block is ready */
154     int sigio;                  /* must process signature */
155     unsigned char buf[IOBS];
156 } BIO_OK_CTX;
157 
158 static BIO_METHOD methods_ok = {
159     BIO_TYPE_CIPHER, "reliable",
160     ok_write,
161     ok_read,
162     NULL,                       /* ok_puts, */
163     NULL,                       /* ok_gets, */
164     ok_ctrl,
165     ok_new,
166     ok_free,
167     ok_callback_ctrl,
168 };
169 
BIO_f_reliable(void)170 BIO_METHOD *BIO_f_reliable(void)
171 {
172     return (&methods_ok);
173 }
174 
ok_new(BIO * bi)175 static int ok_new(BIO *bi)
176 {
177     BIO_OK_CTX *ctx;
178 
179     ctx = (BIO_OK_CTX *)OPENSSL_malloc(sizeof(BIO_OK_CTX));
180     if (ctx == NULL)
181         return (0);
182 
183     ctx->buf_len = 0;
184     ctx->buf_off = 0;
185     ctx->buf_len_save = 0;
186     ctx->buf_off_save = 0;
187     ctx->cont = 1;
188     ctx->finished = 0;
189     ctx->blockout = 0;
190     ctx->sigio = 1;
191 
192     EVP_MD_CTX_init(&ctx->md);
193 
194     bi->init = 0;
195     bi->ptr = (char *)ctx;
196     bi->flags = 0;
197     return (1);
198 }
199 
ok_free(BIO * a)200 static int ok_free(BIO *a)
201 {
202     if (a == NULL)
203         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 
ok_read(BIO * b,char * out,int outl)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)
219         return (0);
220     ctx = (BIO_OK_CTX *)b->ptr;
221 
222     if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0))
223         return (0);
224 
225     while (outl > 0) {
226 
227         /* copy clean bytes to output buffer */
228         if (ctx->blockout) {
229             i = ctx->buf_len - ctx->buf_off;
230             if (i > outl)
231                 i = outl;
232             memcpy(out, &(ctx->buf[ctx->buf_off]), i);
233             ret += i;
234             out += i;
235             outl -= i;
236             ctx->buf_off += i;
237 
238             /* all clean bytes are out */
239             if (ctx->buf_len == ctx->buf_off) {
240                 ctx->buf_off = 0;
241 
242                 /*
243                  * copy start of the next block into proper place
244                  */
245                 if (ctx->buf_len_save - ctx->buf_off_save > 0) {
246                     ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save;
247                     memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
248                             ctx->buf_len);
249                 } else {
250                     ctx->buf_len = 0;
251                 }
252                 ctx->blockout = 0;
253             }
254         }
255 
256         /* output buffer full -- cancel */
257         if (outl == 0)
258             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)
265             break;              /* nothing new */
266 
267         ctx->buf_len += i;
268 
269         /* no signature yet -- check if we got one */
270         if (ctx->sigio == 1) {
271             if (!sig_in(b)) {
272                 BIO_clear_retry_flags(b);
273                 return 0;
274             }
275         }
276 
277         /* signature ok -- check if we got block */
278         if (ctx->sigio == 0) {
279             if (!block_in(b)) {
280                 BIO_clear_retry_flags(b);
281                 return 0;
282             }
283         }
284 
285         /* invalid block -- cancel */
286         if (ctx->cont <= 0)
287             break;
288 
289     }
290 
291     BIO_clear_retry_flags(b);
292     BIO_copy_next_retry(b);
293     return (ret);
294 }
295 
ok_write(BIO * b,const char * in,int inl)296 static int ok_write(BIO *b, const char *in, int inl)
297 {
298     int ret = 0, n, i;
299     BIO_OK_CTX *ctx;
300 
301     if (inl <= 0)
302         return inl;
303 
304     ctx = (BIO_OK_CTX *)b->ptr;
305     ret = inl;
306 
307     if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0))
308         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             i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n);
318             if (i <= 0) {
319                 BIO_copy_next_retry(b);
320                 if (!BIO_should_retry(b))
321                     ctx->cont = 0;
322                 return (i);
323             }
324             ctx->buf_off += i;
325             n -= i;
326         }
327 
328         /* at this point all pending data has been written */
329         ctx->blockout = 0;
330         if (ctx->buf_len == ctx->buf_off) {
331             ctx->buf_len = OK_BLOCK_BLOCK;
332             ctx->buf_off = 0;
333         }
334 
335         if ((in == NULL) || (inl <= 0))
336             return (0);
337 
338         n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ?
339             (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl;
340 
341         memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])),
342                (unsigned char *)in, n);
343         ctx->buf_len += n;
344         inl -= n;
345         in += n;
346 
347         if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) {
348             if (!block_out(b)) {
349                 BIO_clear_retry_flags(b);
350                 return 0;
351             }
352         }
353     } while (inl > 0);
354 
355     BIO_clear_retry_flags(b);
356     BIO_copy_next_retry(b);
357     return (ret);
358 }
359 
ok_ctrl(BIO * b,int cmd,long num,void * ptr)360 static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
361 {
362     BIO_OK_CTX *ctx;
363     EVP_MD *md;
364     const EVP_MD **ppmd;
365     long ret = 1;
366     int i;
367 
368     ctx = b->ptr;
369 
370     switch (cmd) {
371     case BIO_CTRL_RESET:
372         ctx->buf_len = 0;
373         ctx->buf_off = 0;
374         ctx->buf_len_save = 0;
375         ctx->buf_off_save = 0;
376         ctx->cont = 1;
377         ctx->finished = 0;
378         ctx->blockout = 0;
379         ctx->sigio = 1;
380         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
381         break;
382     case BIO_CTRL_EOF:         /* More to read */
383         if (ctx->cont <= 0)
384             ret = 1;
385         else
386             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
387         break;
388     case BIO_CTRL_PENDING:     /* More to read in buffer */
389     case BIO_CTRL_WPENDING:    /* More to read in buffer */
390         ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0;
391         if (ret <= 0)
392             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
393         break;
394     case BIO_CTRL_FLUSH:
395         /* do a final write */
396         if (ctx->blockout == 0)
397             if (!block_out(b))
398                 return 0;
399 
400         while (ctx->blockout) {
401             i = ok_write(b, NULL, 0);
402             if (i < 0) {
403                 ret = i;
404                 break;
405             }
406         }
407 
408         ctx->finished = 1;
409         ctx->buf_off = ctx->buf_len = 0;
410         ctx->cont = (int)ret;
411 
412         /* Finally flush the underlying BIO */
413         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
414         break;
415     case BIO_C_DO_STATE_MACHINE:
416         BIO_clear_retry_flags(b);
417         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
418         BIO_copy_next_retry(b);
419         break;
420     case BIO_CTRL_INFO:
421         ret = (long)ctx->cont;
422         break;
423     case BIO_C_SET_MD:
424         md = ptr;
425         if (!EVP_DigestInit_ex(&ctx->md, md, NULL))
426             return 0;
427         b->init = 1;
428         break;
429     case BIO_C_GET_MD:
430         if (b->init) {
431             ppmd = ptr;
432             *ppmd = ctx->md.digest;
433         } else
434             ret = 0;
435         break;
436     default:
437         ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
438         break;
439     }
440     return (ret);
441 }
442 
ok_callback_ctrl(BIO * b,int cmd,bio_info_cb * fp)443 static long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
444 {
445     long ret = 1;
446 
447     if (b->next_bio == NULL)
448         return (0);
449     switch (cmd) {
450     default:
451         ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
452         break;
453     }
454     return (ret);
455 }
456 
longswap(void * _ptr,size_t len)457 static void longswap(void *_ptr, size_t len)
458 {
459     const union {
460         long one;
461         char little;
462     } is_endian = {
463         1
464     };
465 
466     if (is_endian.little) {
467         size_t i;
468         unsigned char *p = _ptr, c;
469 
470         for (i = 0; i < len; i += 4) {
471             c = p[0], p[0] = p[3], p[3] = c;
472             c = p[1], p[1] = p[2], p[2] = c;
473         }
474     }
475 }
476 
sig_out(BIO * b)477 static int sig_out(BIO *b)
478 {
479     BIO_OK_CTX *ctx;
480     EVP_MD_CTX *md;
481 
482     ctx = b->ptr;
483     md = &ctx->md;
484 
485     if (ctx->buf_len + 2 * md->digest->md_size > OK_BLOCK_SIZE)
486         return 1;
487 
488     if (!EVP_DigestInit_ex(md, md->digest, NULL))
489         goto berr;
490     /*
491      * FIXME: there's absolutely no guarantee this makes any sense at all,
492      * particularly now EVP_MD_CTX has been restructured.
493      */
494     if (RAND_bytes(md->md_data, md->digest->md_size) <= 0)
495         goto berr;
496     memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size);
497     longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size);
498     ctx->buf_len += md->digest->md_size;
499 
500     if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
501         goto berr;
502     if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
503         goto berr;
504     ctx->buf_len += md->digest->md_size;
505     ctx->blockout = 1;
506     ctx->sigio = 0;
507     return 1;
508  berr:
509     BIO_clear_retry_flags(b);
510     return 0;
511 }
512 
sig_in(BIO * b)513 static int sig_in(BIO *b)
514 {
515     BIO_OK_CTX *ctx;
516     EVP_MD_CTX *md;
517     unsigned char tmp[EVP_MAX_MD_SIZE];
518     int ret = 0;
519 
520     ctx = b->ptr;
521     md = &ctx->md;
522 
523     if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md->digest->md_size)
524         return 1;
525 
526     if (!EVP_DigestInit_ex(md, md->digest, NULL))
527         goto berr;
528     memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size);
529     longswap(md->md_data, md->digest->md_size);
530     ctx->buf_off += md->digest->md_size;
531 
532     if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
533         goto berr;
534     if (!EVP_DigestFinal_ex(md, tmp, NULL))
535         goto berr;
536     ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0;
537     ctx->buf_off += md->digest->md_size;
538     if (ret == 1) {
539         ctx->sigio = 0;
540         if (ctx->buf_len != ctx->buf_off) {
541             memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
542                     ctx->buf_len - ctx->buf_off);
543         }
544         ctx->buf_len -= ctx->buf_off;
545         ctx->buf_off = 0;
546     } else {
547         ctx->cont = 0;
548     }
549     return 1;
550  berr:
551     BIO_clear_retry_flags(b);
552     return 0;
553 }
554 
block_out(BIO * b)555 static int block_out(BIO *b)
556 {
557     BIO_OK_CTX *ctx;
558     EVP_MD_CTX *md;
559     unsigned long tl;
560 
561     ctx = b->ptr;
562     md = &ctx->md;
563 
564     tl = ctx->buf_len - OK_BLOCK_BLOCK;
565     ctx->buf[0] = (unsigned char)(tl >> 24);
566     ctx->buf[1] = (unsigned char)(tl >> 16);
567     ctx->buf[2] = (unsigned char)(tl >> 8);
568     ctx->buf[3] = (unsigned char)(tl);
569     if (!EVP_DigestUpdate(md,
570                           (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
571         goto berr;
572     if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
573         goto berr;
574     ctx->buf_len += md->digest->md_size;
575     ctx->blockout = 1;
576     return 1;
577  berr:
578     BIO_clear_retry_flags(b);
579     return 0;
580 }
581 
block_in(BIO * b)582 static int block_in(BIO *b)
583 {
584     BIO_OK_CTX *ctx;
585     EVP_MD_CTX *md;
586     unsigned long tl = 0;
587     unsigned char tmp[EVP_MAX_MD_SIZE];
588 
589     ctx = b->ptr;
590     md = &ctx->md;
591 
592     assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
593     tl = ctx->buf[0];
594     tl <<= 8;
595     tl |= ctx->buf[1];
596     tl <<= 8;
597     tl |= ctx->buf[2];
598     tl <<= 8;
599     tl |= ctx->buf[3];
600 
601     if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md->digest->md_size)
602         return 1;
603 
604     if (!EVP_DigestUpdate(md,
605                           (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
606         goto berr;
607     if (!EVP_DigestFinal_ex(md, tmp, NULL))
608         goto berr;
609     if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md->digest->md_size) ==
610         0) {
611         /* there might be parts from next block lurking around ! */
612         ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md->digest->md_size;
613         ctx->buf_len_save = ctx->buf_len;
614         ctx->buf_off = OK_BLOCK_BLOCK;
615         ctx->buf_len = tl + OK_BLOCK_BLOCK;
616         ctx->blockout = 1;
617     } else {
618         ctx->cont = 0;
619     }
620     return 1;
621  berr:
622     BIO_clear_retry_flags(b);
623     return 0;
624 }
625