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