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