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