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