]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/evp/bio_ok.c
Fix invalid function type casts.
[thirdparty/openssl.git] / crypto / evp / bio_ok.c
CommitLineData
aa6bb135
RS
1/*
2 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
1745a3fb 3 *
aa6bb135
RS
4 * Licensed under the OpenSSL license (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
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
41 with it's length and suffixed with it's digest. So you need only
42 several Kbytes of memory to buffer single block before verifying
43 it's 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.
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>
ab0a14bb 79#include "internal/evp_int.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
64b25758 136 ctx = OPENSSL_zalloc(sizeof(*ctx));
0f113f3e 137 if (ctx == NULL)
a146ae55 138 return 0;
0f113f3e 139
0f113f3e 140 ctx->cont = 1;
0f113f3e 141 ctx->sigio = 1;
bfb0641f 142 ctx->md = EVP_MD_CTX_new();
cb1d435c
MRA
143 if (ctx->md == NULL) {
144 OPENSSL_free(ctx);
145 return 0;
146 }
a146ae55
MC
147 BIO_set_init(bi, 0);
148 BIO_set_data(bi, ctx);
149
150 return 1;
0f113f3e 151}
1745a3fb 152
6b691a5c 153static int ok_free(BIO *a)
0f113f3e 154{
a146ae55
MC
155 BIO_OK_CTX *ctx;
156
0f113f3e 157 if (a == NULL)
a146ae55
MC
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;
0f113f3e
MC
168}
169
6b691a5c 170static int ok_read(BIO *b, char *out, int outl)
0f113f3e
MC
171{
172 int ret = 0, i, n;
173 BIO_OK_CTX *ctx;
a146ae55 174 BIO *next;
0f113f3e
MC
175
176 if (out == NULL)
a146ae55 177 return 0;
0f113f3e 178
a146ae55
MC
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;
0f113f3e
MC
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 > 0) {
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;
a146ae55 222 i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n);
0f113f3e
MC
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);
a146ae55 253 return ret;
0f113f3e 254}
1745a3fb 255
0e1c0612 256static int ok_write(BIO *b, const char *in, int inl)
0f113f3e
MC
257{
258 int ret = 0, n, i;
259 BIO_OK_CTX *ctx;
a146ae55 260 BIO *next;
0f113f3e
MC
261
262 if (inl <= 0)
263 return inl;
264
a146ae55
MC
265 ctx = BIO_get_data(b);
266 next = BIO_next(b);
0f113f3e
MC
267 ret = inl;
268
a146ae55 269 if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
26a7d938 270 return 0;
0f113f3e
MC
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) {
a146ae55 279 i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
0f113f3e
MC
280 if (i <= 0) {
281 BIO_copy_next_retry(b);
282 if (!BIO_should_retry(b))
283 ctx->cont = 0;
26a7d938 284 return i;
0f113f3e
MC
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))
26a7d938 298 return 0;
0f113f3e
MC
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
16f8d4eb 303 memcpy(&ctx->buf[ctx->buf_len], in, n);
0f113f3e
MC
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);
26a7d938 318 return ret;
0f113f3e 319}
1745a3fb 320
0e1c0612 321static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
0f113f3e
MC
322{
323 BIO_OK_CTX *ctx;
324 EVP_MD *md;
325 const EVP_MD **ppmd;
326 long ret = 1;
327 int i;
a146ae55 328 BIO *next;
0f113f3e 329
a146ae55
MC
330 ctx = BIO_get_data(b);
331 next = BIO_next(b);
0f113f3e
MC
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;
a146ae55 343 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
344 break;
345 case BIO_CTRL_EOF: /* More to read */
346 if (ctx->cont <= 0)
347 ret = 1;
348 else
a146ae55 349 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
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)
a146ae55 355 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
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 */
a146ae55 376 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
377 break;
378 case BIO_C_DO_STATE_MACHINE:
379 BIO_clear_retry_flags(b);
a146ae55 380 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
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;
77a01145 388 if (!EVP_DigestInit_ex(ctx->md, md, NULL))
0f113f3e 389 return 0;
a146ae55 390 BIO_set_init(b, 1);
0f113f3e
MC
391 break;
392 case BIO_C_GET_MD:
a146ae55 393 if (BIO_get_init(b)) {
0f113f3e 394 ppmd = ptr;
77a01145 395 *ppmd = EVP_MD_CTX_md(ctx->md);
0f113f3e
MC
396 } else
397 ret = 0;
398 break;
399 default:
a146ae55 400 ret = BIO_ctrl(next, cmd, num, ptr);
0f113f3e
MC
401 break;
402 }
a146ae55 403 return ret;
0f113f3e 404}
1745a3fb 405
fce78bd4 406static long ok_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
0f113f3e
MC
407{
408 long ret = 1;
a146ae55 409 BIO *next;
02e112a8 410
a146ae55
MC
411 next = BIO_next(b);
412
413 if (next == NULL)
414 return 0;
0f113f3e 415
0f113f3e
MC
416 switch (cmd) {
417 default:
a146ae55 418 ret = BIO_callback_ctrl(next, cmd, fp);
0f113f3e
MC
419 break;
420 }
a146ae55
MC
421
422 return ret;
0f113f3e 423}
d3442bc7 424
3205db2b 425static void longswap(void *_ptr, size_t len)
0f113f3e
MC
426{
427 const union {
428 long one;
429 char little;
430 } is_endian = {
431 1
432 };
433
434 if (is_endian.little) {
435 size_t i;
436 unsigned char *p = _ptr, c;
437
438 for (i = 0; i < len; i += 4) {
439 c = p[0], p[0] = p[3], p[3] = c;
440 c = p[1], p[1] = p[2], p[2] = c;
441 }
442 }
443}
3205db2b 444
0f113f3e
MC
445static int sig_out(BIO *b)
446{
447 BIO_OK_CTX *ctx;
448 EVP_MD_CTX *md;
77a01145
RL
449 const EVP_MD *digest;
450 int md_size;
451 void *md_data;
0f113f3e 452
a146ae55 453 ctx = BIO_get_data(b);
77a01145
RL
454 md = ctx->md;
455 digest = EVP_MD_CTX_md(md);
456 md_size = EVP_MD_size(digest);
457 md_data = EVP_MD_CTX_md_data(md);
0f113f3e 458
77a01145 459 if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
0f113f3e
MC
460 return 1;
461
77a01145 462 if (!EVP_DigestInit_ex(md, digest, NULL))
0f113f3e
MC
463 goto berr;
464 /*
465 * FIXME: there's absolutely no guarantee this makes any sense at all,
466 * particularly now EVP_MD_CTX has been restructured.
467 */
77a01145 468 if (RAND_bytes(md_data, md_size) <= 0)
266483d2 469 goto berr;
77a01145
RL
470 memcpy(&(ctx->buf[ctx->buf_len]), md_data, md_size);
471 longswap(&(ctx->buf[ctx->buf_len]), md_size);
472 ctx->buf_len += md_size;
0f113f3e
MC
473
474 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
475 goto berr;
476 if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
477 goto berr;
77a01145 478 ctx->buf_len += md_size;
0f113f3e
MC
479 ctx->blockout = 1;
480 ctx->sigio = 0;
481 return 1;
482 berr:
483 BIO_clear_retry_flags(b);
484 return 0;
485}
1745a3fb 486
0f113f3e
MC
487static int sig_in(BIO *b)
488{
489 BIO_OK_CTX *ctx;
490 EVP_MD_CTX *md;
491 unsigned char tmp[EVP_MAX_MD_SIZE];
492 int ret = 0;
77a01145
RL
493 const EVP_MD *digest;
494 int md_size;
495 void *md_data;
0f113f3e 496
a146ae55 497 ctx = BIO_get_data(b);
77a01145
RL
498 md = ctx->md;
499 digest = EVP_MD_CTX_md(md);
500 md_size = EVP_MD_size(digest);
501 md_data = EVP_MD_CTX_md_data(md);
0f113f3e 502
77a01145 503 if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
0f113f3e
MC
504 return 1;
505
77a01145 506 if (!EVP_DigestInit_ex(md, digest, NULL))
0f113f3e 507 goto berr;
77a01145
RL
508 memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
509 longswap(md_data, md_size);
510 ctx->buf_off += md_size;
0f113f3e
MC
511
512 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
513 goto berr;
514 if (!EVP_DigestFinal_ex(md, tmp, NULL))
515 goto berr;
77a01145
RL
516 ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
517 ctx->buf_off += md_size;
0f113f3e
MC
518 if (ret == 1) {
519 ctx->sigio = 0;
520 if (ctx->buf_len != ctx->buf_off) {
521 memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
522 ctx->buf_len - ctx->buf_off);
523 }
524 ctx->buf_len -= ctx->buf_off;
525 ctx->buf_off = 0;
526 } else {
527 ctx->cont = 0;
528 }
529 return 1;
530 berr:
531 BIO_clear_retry_flags(b);
532 return 0;
1745a3fb
BL
533}
534
0f113f3e
MC
535static int block_out(BIO *b)
536{
537 BIO_OK_CTX *ctx;
538 EVP_MD_CTX *md;
539 unsigned long tl;
77a01145
RL
540 const EVP_MD *digest;
541 int md_size;
0f113f3e 542
a146ae55 543 ctx = BIO_get_data(b);
77a01145
RL
544 md = ctx->md;
545 digest = EVP_MD_CTX_md(md);
546 md_size = EVP_MD_size(digest);
0f113f3e
MC
547
548 tl = ctx->buf_len - OK_BLOCK_BLOCK;
549 ctx->buf[0] = (unsigned char)(tl >> 24);
550 ctx->buf[1] = (unsigned char)(tl >> 16);
551 ctx->buf[2] = (unsigned char)(tl >> 8);
552 ctx->buf[3] = (unsigned char)(tl);
553 if (!EVP_DigestUpdate(md,
554 (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
555 goto berr;
556 if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
557 goto berr;
77a01145 558 ctx->buf_len += md_size;
0f113f3e
MC
559 ctx->blockout = 1;
560 return 1;
561 berr:
562 BIO_clear_retry_flags(b);
563 return 0;
564}
1745a3fb 565
0f113f3e
MC
566static int block_in(BIO *b)
567{
568 BIO_OK_CTX *ctx;
569 EVP_MD_CTX *md;
570 unsigned long tl = 0;
571 unsigned char tmp[EVP_MAX_MD_SIZE];
77a01145 572 int md_size;
0f113f3e 573
a146ae55 574 ctx = BIO_get_data(b);
77a01145
RL
575 md = ctx->md;
576 md_size = EVP_MD_size(EVP_MD_CTX_md(md));
0f113f3e
MC
577
578 assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
579 tl = ctx->buf[0];
580 tl <<= 8;
581 tl |= ctx->buf[1];
582 tl <<= 8;
583 tl |= ctx->buf[2];
584 tl <<= 8;
585 tl |= ctx->buf[3];
586
77a01145 587 if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size)
0f113f3e
MC
588 return 1;
589
590 if (!EVP_DigestUpdate(md,
591 (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
592 goto berr;
593 if (!EVP_DigestFinal_ex(md, tmp, NULL))
594 goto berr;
77a01145 595 if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md_size) == 0) {
0f113f3e 596 /* there might be parts from next block lurking around ! */
77a01145 597 ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size;
0f113f3e
MC
598 ctx->buf_len_save = ctx->buf_len;
599 ctx->buf_off = OK_BLOCK_BLOCK;
600 ctx->buf_len = tl + OK_BLOCK_BLOCK;
601 ctx->blockout = 1;
602 } else {
603 ctx->cont = 0;
604 }
605 return 1;
606 berr:
607 BIO_clear_retry_flags(b);
608 return 0;
609}