]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/evp/bio_ok.c
Update copyright year
[thirdparty/openssl.git] / crypto / evp / bio_ok.c
CommitLineData
aa6bb135 1/*
33388b44 2 * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
1745a3fb 3 *
4a8b0c55 4 * Licensed under the Apache License 2.0 (the "License"). You may not use
aa6bb135
RS
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
1745a3fb
BL
8 */
9
1d97c843 10/*-
e3713c36 11 From: Arne Ansper
0f113f3e
MC
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
68756b12 41 with its length and suffixed with its digest. So you need only
0f113f3e 42 several Kbytes of memory to buffer single block before verifying
68756b12 43 its digest.
0f113f3e
MC
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.
1745a3fb
BL
68
69*/
70
71#include <stdio.h>
72#include <errno.h>
3205db2b 73#include <assert.h>
b39fc560 74#include "internal/cryptlib.h"
ec577822 75#include <openssl/buffer.h>
a146ae55 76#include "internal/bio.h"
ec577822
BM
77#include <openssl/evp.h>
78#include <openssl/rand.h>
25f2138b 79#include "crypto/evp.h"
1745a3fb 80
0e1c0612
UM
81static int ok_write(BIO *h, const char *buf, int num);
82static int ok_read(BIO *h, char *buf, int size);
83static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
1745a3fb
BL
84static int ok_new(BIO *h);
85static int ok_free(BIO *data);
fce78bd4 86static long ok_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
d3442bc7 87
0f113f3e
MC
88static __owur int sig_out(BIO *b);
89static __owur int sig_in(BIO *b);
90static __owur int block_out(BIO *b);
91static __owur int block_in(BIO *b);
92#define OK_BLOCK_SIZE (1024*4)
93#define OK_BLOCK_BLOCK 4
94#define IOBS (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE)
1745a3fb
BL
95#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
96
0f113f3e
MC
97typedef struct ok_struct {
98 size_t buf_len;
99 size_t buf_off;
100 size_t buf_len_save;
101 size_t buf_off_save;
102 int cont; /* <= 0 when finished */
103 int finished;
77a01145 104 EVP_MD_CTX *md;
0f113f3e
MC
105 int blockout; /* output block is ready */
106 int sigio; /* must process signature */
107 unsigned char buf[IOBS];
108} BIO_OK_CTX;
109
04f6b0fd 110static const BIO_METHOD methods_ok = {
27ab9195
DB
111 BIO_TYPE_CIPHER,
112 "reliable",
3befffa3
MC
113 /* TODO: Convert to new style write function */
114 bwrite_conv,
0f113f3e 115 ok_write,
d07aee2c
MC
116 /* TODO: Convert to new style read function */
117 bread_conv,
0f113f3e
MC
118 ok_read,
119 NULL, /* ok_puts, */
120 NULL, /* ok_gets, */
121 ok_ctrl,
122 ok_new,
123 ok_free,
124 ok_callback_ctrl,
125};
1745a3fb 126
04f6b0fd 127const BIO_METHOD *BIO_f_reliable(void)
0f113f3e 128{
26a7d938 129 return &methods_ok;
0f113f3e 130}
1745a3fb 131
6b691a5c 132static int ok_new(BIO *bi)
0f113f3e
MC
133{
134 BIO_OK_CTX *ctx;
135
cdb10bae
RS
136 if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
137 EVPerr(EVP_F_OK_NEW, ERR_R_MALLOC_FAILURE);
a146ae55 138 return 0;
cdb10bae 139 }
0f113f3e 140
0f113f3e 141 ctx->cont = 1;
0f113f3e 142 ctx->sigio = 1;
bfb0641f 143 ctx->md = EVP_MD_CTX_new();
cb1d435c
MRA
144 if (ctx->md == NULL) {
145 OPENSSL_free(ctx);
146 return 0;
147 }
a146ae55
MC
148 BIO_set_init(bi, 0);
149 BIO_set_data(bi, ctx);
150
151 return 1;
0f113f3e 152}
1745a3fb 153
6b691a5c 154static int ok_free(BIO *a)
0f113f3e 155{
a146ae55
MC
156 BIO_OK_CTX *ctx;
157
0f113f3e 158 if (a == NULL)
a146ae55
MC
159 return 0;
160
161 ctx = BIO_get_data(a);
162
163 EVP_MD_CTX_free(ctx->md);
164 OPENSSL_clear_free(ctx, sizeof(BIO_OK_CTX));
165 BIO_set_data(a, NULL);
166 BIO_set_init(a, 0);
167
168 return 1;
0f113f3e
MC
169}
170
6b691a5c 171static int ok_read(BIO *b, char *out, int outl)
0f113f3e
MC
172{
173 int ret = 0, i, n;
174 BIO_OK_CTX *ctx;
a146ae55 175 BIO *next;
0f113f3e
MC
176
177 if (out == NULL)
a146ae55 178 return 0;
0f113f3e 179
a146ae55
MC
180 ctx = BIO_get_data(b);
181 next = BIO_next(b);
182
183 if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
184 return 0;
0f113f3e
MC
185
186 while (outl > 0) {
187
188 /* copy clean bytes to output buffer */
189 if (ctx->blockout) {
190 i = ctx->buf_len - ctx->buf_off;
191 if (i > outl)
192 i = outl;
193 memcpy(out, &(ctx->buf[ctx->buf_off]), i);
194 ret += i;
195 out += i;
196 outl -= i;
197 ctx->buf_off += i;
198
199 /* all clean bytes are out */
200 if (ctx->buf_len == ctx->buf_off) {
201 ctx->buf_off = 0;
202
203 /*
204 * copy start of the next block into proper place
205 */
206 if (ctx->buf_len_save - ctx->buf_off_save > 0) {
207 ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save;
208 memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
209 ctx->buf_len);
210 } else {
211 ctx->buf_len = 0;
212 }
213 ctx->blockout = 0;
214 }
215 }
216
217 /* output buffer full -- cancel */
218 if (outl == 0)
219 break;
220
221 /* no clean bytes in buffer -- fill it */
222 n = IOBS - ctx->buf_len;
a146ae55 223 i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n);
0f113f3e
MC
224
225 if (i <= 0)
226 break; /* nothing new */
227
228 ctx->buf_len += i;
229
230 /* no signature yet -- check if we got one */
231 if (ctx->sigio == 1) {
232 if (!sig_in(b)) {
233 BIO_clear_retry_flags(b);
234 return 0;
235 }
236 }
237
238 /* signature ok -- check if we got block */
239 if (ctx->sigio == 0) {
240 if (!block_in(b)) {
241 BIO_clear_retry_flags(b);
242 return 0;
243 }
244 }
245
246 /* invalid block -- cancel */
247 if (ctx->cont <= 0)
248 break;
249
250 }
251
252 BIO_clear_retry_flags(b);
253 BIO_copy_next_retry(b);
a146ae55 254 return ret;
0f113f3e 255}
1745a3fb 256
0e1c0612 257static int ok_write(BIO *b, const char *in, int inl)
0f113f3e
MC
258{
259 int ret = 0, n, i;
260 BIO_OK_CTX *ctx;
a146ae55 261 BIO *next;
0f113f3e
MC
262
263 if (inl <= 0)
264 return inl;
265
a146ae55
MC
266 ctx = BIO_get_data(b);
267 next = BIO_next(b);
0f113f3e
MC
268 ret = inl;
269
a146ae55 270 if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
26a7d938 271 return 0;
0f113f3e
MC
272
273 if (ctx->sigio && !sig_out(b))
274 return 0;
275
276 do {
277 BIO_clear_retry_flags(b);
278 n = ctx->buf_len - ctx->buf_off;
279 while (ctx->blockout && n > 0) {
a146ae55 280 i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
0f113f3e
MC
281 if (i <= 0) {
282 BIO_copy_next_retry(b);
283 if (!BIO_should_retry(b))
284 ctx->cont = 0;
26a7d938 285 return i;
0f113f3e
MC
286 }
287 ctx->buf_off += i;
288 n -= i;
289 }
290
291 /* at this point all pending data has been written */
292 ctx->blockout = 0;
293 if (ctx->buf_len == ctx->buf_off) {
294 ctx->buf_len = OK_BLOCK_BLOCK;
295 ctx->buf_off = 0;
296 }
297
298 if ((in == NULL) || (inl <= 0))
26a7d938 299 return 0;
0f113f3e
MC
300
301 n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ?
302 (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl;
303
16f8d4eb 304 memcpy(&ctx->buf[ctx->buf_len], in, n);
0f113f3e
MC
305 ctx->buf_len += n;
306 inl -= n;
307 in += n;
308
309 if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) {
310 if (!block_out(b)) {
311 BIO_clear_retry_flags(b);
312 return 0;
313 }
314 }
315 } while (inl > 0);
316
317 BIO_clear_retry_flags(b);
318 BIO_copy_next_retry(b);
26a7d938 319 return ret;
0f113f3e 320}
1745a3fb 321
0e1c0612 322static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
0f113f3e
MC
323{
324 BIO_OK_CTX *ctx;
325 EVP_MD *md;
326 const EVP_MD **ppmd;
327 long ret = 1;
328 int i;
a146ae55 329 BIO *next;
0f113f3e 330
a146ae55
MC
331 ctx = BIO_get_data(b);
332 next = BIO_next(b);
0f113f3e
MC
333
334 switch (cmd) {
335 case BIO_CTRL_RESET:
336 ctx->buf_len = 0;
337 ctx->buf_off = 0;
338 ctx->buf_len_save = 0;
339 ctx->buf_off_save = 0;
340 ctx->cont = 1;
341 ctx->finished = 0;
342 ctx->blockout = 0;
343 ctx->sigio = 1;
a146ae55 344 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
345 break;
346 case BIO_CTRL_EOF: /* More to read */
347 if (ctx->cont <= 0)
348 ret = 1;
349 else
a146ae55 350 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
351 break;
352 case BIO_CTRL_PENDING: /* More to read in buffer */
353 case BIO_CTRL_WPENDING: /* More to read in buffer */
354 ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0;
355 if (ret <= 0)
a146ae55 356 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
357 break;
358 case BIO_CTRL_FLUSH:
359 /* do a final write */
360 if (ctx->blockout == 0)
361 if (!block_out(b))
362 return 0;
363
364 while (ctx->blockout) {
365 i = ok_write(b, NULL, 0);
366 if (i < 0) {
367 ret = i;
368 break;
369 }
370 }
371
372 ctx->finished = 1;
373 ctx->buf_off = ctx->buf_len = 0;
374 ctx->cont = (int)ret;
375
376 /* Finally flush the underlying BIO */
a146ae55 377 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
378 break;
379 case BIO_C_DO_STATE_MACHINE:
380 BIO_clear_retry_flags(b);
a146ae55 381 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
382 BIO_copy_next_retry(b);
383 break;
384 case BIO_CTRL_INFO:
385 ret = (long)ctx->cont;
386 break;
387 case BIO_C_SET_MD:
388 md = ptr;
77a01145 389 if (!EVP_DigestInit_ex(ctx->md, md, NULL))
0f113f3e 390 return 0;
a146ae55 391 BIO_set_init(b, 1);
0f113f3e
MC
392 break;
393 case BIO_C_GET_MD:
a146ae55 394 if (BIO_get_init(b)) {
0f113f3e 395 ppmd = ptr;
77a01145 396 *ppmd = EVP_MD_CTX_md(ctx->md);
0f113f3e
MC
397 } else
398 ret = 0;
399 break;
400 default:
a146ae55 401 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
402 break;
403 }
a146ae55 404 return ret;
0f113f3e 405}
1745a3fb 406
fce78bd4 407static long ok_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
0f113f3e 408{
a146ae55 409 BIO *next;
02e112a8 410
a146ae55
MC
411 next = BIO_next(b);
412
413 if (next == NULL)
414 return 0;
0f113f3e 415
1f2235ea 416 return BIO_callback_ctrl(next, cmd, fp);
0f113f3e 417}
d3442bc7 418
3205db2b 419static void longswap(void *_ptr, size_t len)
0f113f3e
MC
420{
421 const union {
422 long one;
423 char little;
424 } is_endian = {
425 1
426 };
427
428 if (is_endian.little) {
429 size_t i;
430 unsigned char *p = _ptr, c;
431
432 for (i = 0; i < len; i += 4) {
433 c = p[0], p[0] = p[3], p[3] = c;
434 c = p[1], p[1] = p[2], p[2] = c;
435 }
436 }
437}
3205db2b 438
0f113f3e
MC
439static int sig_out(BIO *b)
440{
441 BIO_OK_CTX *ctx;
442 EVP_MD_CTX *md;
77a01145
RL
443 const EVP_MD *digest;
444 int md_size;
445 void *md_data;
0f113f3e 446
a146ae55 447 ctx = BIO_get_data(b);
77a01145
RL
448 md = ctx->md;
449 digest = EVP_MD_CTX_md(md);
450 md_size = EVP_MD_size(digest);
451 md_data = EVP_MD_CTX_md_data(md);
0f113f3e 452
77a01145 453 if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
0f113f3e
MC
454 return 1;
455
77a01145 456 if (!EVP_DigestInit_ex(md, digest, NULL))
0f113f3e
MC
457 goto berr;
458 /*
459 * FIXME: there's absolutely no guarantee this makes any sense at all,
460 * particularly now EVP_MD_CTX has been restructured.
461 */
77a01145 462 if (RAND_bytes(md_data, md_size) <= 0)
266483d2 463 goto berr;
77a01145
RL
464 memcpy(&(ctx->buf[ctx->buf_len]), md_data, md_size);
465 longswap(&(ctx->buf[ctx->buf_len]), md_size);
466 ctx->buf_len += md_size;
0f113f3e
MC
467
468 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
469 goto berr;
470 if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
471 goto berr;
77a01145 472 ctx->buf_len += md_size;
0f113f3e
MC
473 ctx->blockout = 1;
474 ctx->sigio = 0;
475 return 1;
476 berr:
477 BIO_clear_retry_flags(b);
478 return 0;
479}
1745a3fb 480
0f113f3e
MC
481static int sig_in(BIO *b)
482{
483 BIO_OK_CTX *ctx;
484 EVP_MD_CTX *md;
485 unsigned char tmp[EVP_MAX_MD_SIZE];
486 int ret = 0;
77a01145
RL
487 const EVP_MD *digest;
488 int md_size;
489 void *md_data;
0f113f3e 490
a146ae55 491 ctx = BIO_get_data(b);
77a01145
RL
492 md = ctx->md;
493 digest = EVP_MD_CTX_md(md);
494 md_size = EVP_MD_size(digest);
495 md_data = EVP_MD_CTX_md_data(md);
0f113f3e 496
77a01145 497 if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
0f113f3e
MC
498 return 1;
499
77a01145 500 if (!EVP_DigestInit_ex(md, digest, NULL))
0f113f3e 501 goto berr;
77a01145
RL
502 memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
503 longswap(md_data, md_size);
504 ctx->buf_off += md_size;
0f113f3e
MC
505
506 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
507 goto berr;
508 if (!EVP_DigestFinal_ex(md, tmp, NULL))
509 goto berr;
77a01145
RL
510 ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
511 ctx->buf_off += md_size;
0f113f3e
MC
512 if (ret == 1) {
513 ctx->sigio = 0;
514 if (ctx->buf_len != ctx->buf_off) {
515 memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
516 ctx->buf_len - ctx->buf_off);
517 }
518 ctx->buf_len -= ctx->buf_off;
519 ctx->buf_off = 0;
520 } else {
521 ctx->cont = 0;
522 }
523 return 1;
524 berr:
525 BIO_clear_retry_flags(b);
526 return 0;
1745a3fb
BL
527}
528
0f113f3e
MC
529static int block_out(BIO *b)
530{
531 BIO_OK_CTX *ctx;
532 EVP_MD_CTX *md;
533 unsigned long tl;
77a01145
RL
534 const EVP_MD *digest;
535 int md_size;
0f113f3e 536
a146ae55 537 ctx = BIO_get_data(b);
77a01145
RL
538 md = ctx->md;
539 digest = EVP_MD_CTX_md(md);
540 md_size = EVP_MD_size(digest);
0f113f3e
MC
541
542 tl = ctx->buf_len - OK_BLOCK_BLOCK;
543 ctx->buf[0] = (unsigned char)(tl >> 24);
544 ctx->buf[1] = (unsigned char)(tl >> 16);
545 ctx->buf[2] = (unsigned char)(tl >> 8);
546 ctx->buf[3] = (unsigned char)(tl);
547 if (!EVP_DigestUpdate(md,
548 (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
549 goto berr;
550 if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
551 goto berr;
77a01145 552 ctx->buf_len += md_size;
0f113f3e
MC
553 ctx->blockout = 1;
554 return 1;
555 berr:
556 BIO_clear_retry_flags(b);
557 return 0;
558}
1745a3fb 559
0f113f3e
MC
560static int block_in(BIO *b)
561{
562 BIO_OK_CTX *ctx;
563 EVP_MD_CTX *md;
564 unsigned long tl = 0;
565 unsigned char tmp[EVP_MAX_MD_SIZE];
77a01145 566 int md_size;
0f113f3e 567
a146ae55 568 ctx = BIO_get_data(b);
77a01145
RL
569 md = ctx->md;
570 md_size = EVP_MD_size(EVP_MD_CTX_md(md));
0f113f3e
MC
571
572 assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
573 tl = ctx->buf[0];
574 tl <<= 8;
575 tl |= ctx->buf[1];
576 tl <<= 8;
577 tl |= ctx->buf[2];
578 tl <<= 8;
579 tl |= ctx->buf[3];
580
77a01145 581 if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size)
0f113f3e
MC
582 return 1;
583
584 if (!EVP_DigestUpdate(md,
585 (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
586 goto berr;
587 if (!EVP_DigestFinal_ex(md, tmp, NULL))
588 goto berr;
77a01145 589 if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md_size) == 0) {
0f113f3e 590 /* there might be parts from next block lurking around ! */
77a01145 591 ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size;
0f113f3e
MC
592 ctx->buf_len_save = ctx->buf_len;
593 ctx->buf_off = OK_BLOCK_BLOCK;
594 ctx->buf_len = tl + OK_BLOCK_BLOCK;
595 ctx->blockout = 1;
596 } else {
597 ctx->cont = 0;
598 }
599 return 1;
600 berr:
601 BIO_clear_retry_flags(b);
602 return 0;
603}