2 * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
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
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.
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.
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
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.
36 BIO_f_reliable tries to solve both problems, so that you can
37 read and write arbitrary long streams using only fixed amount
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
45 BIO_f_reliable goes further and adds several important capabilities:
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.
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:
54 *) digest is initialized with random seed instead of
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.
60 reader can now read the seed from stream, hash the same string
61 and then compare the digest output.
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.
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"
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);
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."
98 typedef struct ok_struct {
103 int cont; /* <= 0 when finished */
106 int blockout; /* output block is ready */
107 int sigio; /* must process signature */
108 unsigned char buf[IOBS];
111 static const BIO_METHOD methods_ok = {
126 const BIO_METHOD *BIO_f_reliable(void)
131 static int ok_new(BIO *bi)
135 if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
140 ctx->md = EVP_MD_CTX_new();
141 if (ctx->md == NULL) {
146 BIO_set_data(bi, ctx);
151 static int ok_free(BIO *a)
158 ctx = BIO_get_data(a);
160 EVP_MD_CTX_free(ctx->md);
161 OPENSSL_clear_free(ctx, sizeof(BIO_OK_CTX));
162 BIO_set_data(a, NULL);
168 static int ok_read(BIO *b, char *out, int outl)
177 ctx = BIO_get_data(b);
180 if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
185 /* copy clean bytes to output buffer */
187 i = ctx->buf_len - ctx->buf_off;
190 memcpy(out, &(ctx->buf[ctx->buf_off]), i);
196 /* all clean bytes are out */
197 if (ctx->buf_len == ctx->buf_off) {
201 * copy start of the next block into proper place
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]),
214 /* output buffer full -- cancel */
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);
223 break; /* nothing new */
227 /* no signature yet -- check if we got one */
228 if (ctx->sigio == 1) {
230 BIO_clear_retry_flags(b);
235 /* signature ok -- check if we got block */
236 if (ctx->sigio == 0) {
238 BIO_clear_retry_flags(b);
243 /* invalid block -- cancel */
249 BIO_clear_retry_flags(b);
250 BIO_copy_next_retry(b);
254 static int ok_write(BIO *b, const char *in, int inl)
263 ctx = BIO_get_data(b);
267 if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
270 if (ctx->sigio && !sig_out(b))
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);
279 BIO_copy_next_retry(b);
280 if (!BIO_should_retry(b))
288 /* at this point all pending data has been written */
290 if (ctx->buf_len == ctx->buf_off) {
291 ctx->buf_len = OK_BLOCK_BLOCK;
295 if ((in == NULL) || (inl <= 0))
298 n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ?
299 (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl;
301 memcpy(&ctx->buf[ctx->buf_len], in, n);
306 if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) {
308 BIO_clear_retry_flags(b);
314 BIO_clear_retry_flags(b);
315 BIO_copy_next_retry(b);
319 static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
328 ctx = BIO_get_data(b);
335 ctx->buf_len_save = 0;
336 ctx->buf_off_save = 0;
341 ret = BIO_ctrl(next, cmd, num, ptr);
343 case BIO_CTRL_EOF: /* More to read */
347 ret = BIO_ctrl(next, cmd, num, ptr);
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;
353 ret = BIO_ctrl(next, cmd, num, ptr);
356 /* do a final write */
357 if (ctx->blockout == 0)
361 while (ctx->blockout) {
362 i = ok_write(b, NULL, 0);
370 ctx->buf_off = ctx->buf_len = 0;
371 ctx->cont = (int)ret;
373 /* Finally flush the underlying BIO */
374 ret = BIO_ctrl(next, cmd, num, ptr);
375 BIO_copy_next_retry(b);
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);
383 ret = (long)ctx->cont;
387 if (!EVP_DigestInit_ex(ctx->md, md, NULL))
392 if (BIO_get_init(b)) {
394 *ppmd = EVP_MD_CTX_get0_md(ctx->md);
399 ret = BIO_ctrl(next, cmd, num, ptr);
405 static long ok_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
414 return BIO_callback_ctrl(next, cmd, fp);
417 static void longswap(void *_ptr, size_t len)
421 if (IS_LITTLE_ENDIAN) {
423 unsigned char *p = _ptr, c;
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;
432 static int sig_out(BIO *b)
436 const EVP_MD *digest;
440 ctx = BIO_get_data(b);
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);
446 if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
449 if (!EVP_DigestInit_ex(md, digest, NULL))
452 * FIXME: there's absolutely no guarantee this makes any sense at all,
453 * particularly now EVP_MD_CTX has been restructured.
455 if (RAND_bytes(md_data, md_size) <= 0)
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;
461 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
463 if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
465 ctx->buf_len += md_size;
470 BIO_clear_retry_flags(b);
474 static int sig_in(BIO *b)
478 unsigned char tmp[EVP_MAX_MD_SIZE];
480 const EVP_MD *digest;
484 ctx = BIO_get_data(b);
485 if ((md = ctx->md) == NULL)
487 digest = EVP_MD_CTX_get0_md(md);
488 if ((md_size = EVP_MD_get_size(digest)) < 0)
490 md_data = EVP_MD_CTX_get0_md_data(md);
492 if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
495 if (!EVP_DigestInit_ex(md, digest, NULL))
497 memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
498 longswap(md_data, md_size);
499 ctx->buf_off += md_size;
501 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
503 if (!EVP_DigestFinal_ex(md, tmp, NULL))
505 ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
506 ctx->buf_off += md_size;
509 if (ctx->buf_len != ctx->buf_off) {
510 memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
511 ctx->buf_len - ctx->buf_off);
513 ctx->buf_len -= ctx->buf_off;
520 BIO_clear_retry_flags(b);
524 static int block_out(BIO *b)
529 const EVP_MD *digest;
532 ctx = BIO_get_data(b);
534 digest = EVP_MD_CTX_get0_md(md);
535 md_size = EVP_MD_get_size(digest);
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))
545 if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
547 ctx->buf_len += md_size;
551 BIO_clear_retry_flags(b);
555 static int block_in(BIO *b)
559 unsigned long tl = 0;
560 unsigned char tmp[EVP_MAX_MD_SIZE];
563 ctx = BIO_get_data(b);
565 md_size = EVP_MD_get_size(EVP_MD_CTX_get0_md(md));
569 assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
578 if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size)
581 if (!EVP_DigestUpdate(md,
582 (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
584 if (!EVP_DigestFinal_ex(md, tmp, NULL))
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;
598 BIO_clear_retry_flags(b);