VirtualBox

source: vbox/trunk/src/libs/openssl-1.1.1l/crypto/evp/bio_ok.c@ 91772

Last change on this file since 91772 was 91772, checked in by vboxsync, 3 years ago

openssl-1.1.1l: Applied and adjusted our OpenSSL changes to 1.1.1l. bugref:10126

File size: 15.9 KB
Line 
1/*
2 * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
3 *
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
8 */
9
10/*-
11 From: Arne Ansper
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 its length and suffixed with its digest. So you need only
42 several Kbytes of memory to buffer single block before verifying
43 its 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.
68
69*/
70
71#include <stdio.h>
72#include <errno.h>
73#include <assert.h>
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 "crypto/evp.h"
80
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);
84static int ok_new(BIO *h);
85static int ok_free(BIO *data);
86static long ok_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
87
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)
95#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
96
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;
104 EVP_MD_CTX *md;
105 int blockout; /* output block is ready */
106 int sigio; /* must process signature */
107 unsigned char buf[IOBS];
108} BIO_OK_CTX;
109
110static const BIO_METHOD methods_ok = {
111 BIO_TYPE_CIPHER,
112 "reliable",
113 /* TODO: Convert to new style write function */
114 bwrite_conv,
115 ok_write,
116 /* TODO: Convert to new style read function */
117 bread_conv,
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};
126
127const BIO_METHOD *BIO_f_reliable(void)
128{
129 return &methods_ok;
130}
131
132static int ok_new(BIO *bi)
133{
134 BIO_OK_CTX *ctx;
135
136 if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
137 EVPerr(EVP_F_OK_NEW, ERR_R_MALLOC_FAILURE);
138 return 0;
139 }
140
141 ctx->cont = 1;
142 ctx->sigio = 1;
143 ctx->md = EVP_MD_CTX_new();
144 if (ctx->md == NULL) {
145 OPENSSL_free(ctx);
146 return 0;
147 }
148 BIO_set_init(bi, 0);
149 BIO_set_data(bi, ctx);
150
151 return 1;
152}
153
154static int ok_free(BIO *a)
155{
156 BIO_OK_CTX *ctx;
157
158 if (a == NULL)
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;
169}
170
171static int ok_read(BIO *b, char *out, int outl)
172{
173 int ret = 0, i, n;
174 BIO_OK_CTX *ctx;
175 BIO *next;
176
177 if (out == NULL)
178 return 0;
179
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;
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) {
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;
223 i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n);
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);
254 return ret;
255}
256
257static int ok_write(BIO *b, const char *in, int inl)
258{
259 int ret = 0, n, i;
260 BIO_OK_CTX *ctx;
261 BIO *next;
262
263 if (inl <= 0)
264 return inl;
265
266 ctx = BIO_get_data(b);
267 next = BIO_next(b);
268 ret = inl;
269
270 if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
271 return 0;
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) {
280 i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
281 if (i <= 0) {
282 BIO_copy_next_retry(b);
283 if (!BIO_should_retry(b))
284 ctx->cont = 0;
285 return i;
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))
299 return 0;
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
304 memcpy(&ctx->buf[ctx->buf_len], in, n);
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);
319 return ret;
320}
321
322static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
323{
324 BIO_OK_CTX *ctx;
325 EVP_MD *md;
326 const EVP_MD **ppmd;
327 long ret = 1;
328 int i;
329 BIO *next;
330
331 ctx = BIO_get_data(b);
332 next = BIO_next(b);
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;
344 ret = BIO_ctrl(next, cmd, num, ptr);
345 break;
346 case BIO_CTRL_EOF: /* More to read */
347 if (ctx->cont <= 0)
348 ret = 1;
349 else
350 ret = BIO_ctrl(next, cmd, num, ptr);
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)
356 ret = BIO_ctrl(next, cmd, num, ptr);
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 */
377 ret = BIO_ctrl(next, cmd, num, ptr);
378 break;
379 case BIO_C_DO_STATE_MACHINE:
380 BIO_clear_retry_flags(b);
381 ret = BIO_ctrl(next, cmd, num, ptr);
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;
389 if (!EVP_DigestInit_ex(ctx->md, md, NULL))
390 return 0;
391 BIO_set_init(b, 1);
392 break;
393 case BIO_C_GET_MD:
394 if (BIO_get_init(b)) {
395 ppmd = ptr;
396 *ppmd = EVP_MD_CTX_md(ctx->md);
397 } else
398 ret = 0;
399 break;
400 default:
401 ret = BIO_ctrl(next, cmd, num, ptr);
402 break;
403 }
404 return ret;
405}
406
407static long ok_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
408{
409 long ret = 1;
410 BIO *next;
411
412 next = BIO_next(b);
413
414 if (next == NULL)
415 return 0;
416
417 switch (cmd) {
418 default:
419 ret = BIO_callback_ctrl(next, cmd, fp);
420 break;
421 }
422
423 return ret;
424}
425
426static void longswap(void *_ptr, size_t len)
427{
428 const union {
429 long one;
430 char little;
431 } is_endian = {
432 1
433 };
434
435 if (is_endian.little) {
436 size_t i;
437 unsigned char *p = _ptr, c;
438
439 for (i = 0; i < len; i += 4) {
440 c = p[0], p[0] = p[3], p[3] = c;
441 c = p[1], p[1] = p[2], p[2] = c;
442 }
443 }
444}
445
446static int sig_out(BIO *b)
447{
448 BIO_OK_CTX *ctx;
449 EVP_MD_CTX *md;
450 const EVP_MD *digest;
451 int md_size;
452 void *md_data;
453
454 ctx = BIO_get_data(b);
455 md = ctx->md;
456 digest = EVP_MD_CTX_md(md);
457 md_size = EVP_MD_size(digest);
458 md_data = EVP_MD_CTX_md_data(md);
459
460 if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
461 return 1;
462
463 if (!EVP_DigestInit_ex(md, digest, NULL))
464 goto berr;
465 /*
466 * FIXME: there's absolutely no guarantee this makes any sense at all,
467 * particularly now EVP_MD_CTX has been restructured.
468 */
469 if (RAND_bytes(md_data, md_size) <= 0)
470 goto berr;
471 memcpy(&(ctx->buf[ctx->buf_len]), md_data, md_size);
472 longswap(&(ctx->buf[ctx->buf_len]), md_size);
473 ctx->buf_len += md_size;
474
475 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
476 goto berr;
477 if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
478 goto berr;
479 ctx->buf_len += md_size;
480 ctx->blockout = 1;
481 ctx->sigio = 0;
482 return 1;
483 berr:
484 BIO_clear_retry_flags(b);
485 return 0;
486}
487
488static int sig_in(BIO *b)
489{
490 BIO_OK_CTX *ctx;
491 EVP_MD_CTX *md;
492 unsigned char tmp[EVP_MAX_MD_SIZE];
493 int ret = 0;
494 const EVP_MD *digest;
495 int md_size;
496 void *md_data;
497
498 ctx = BIO_get_data(b);
499 md = ctx->md;
500 digest = EVP_MD_CTX_md(md);
501 md_size = EVP_MD_size(digest);
502 md_data = EVP_MD_CTX_md_data(md);
503
504 if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
505 return 1;
506
507 if (!EVP_DigestInit_ex(md, digest, NULL))
508 goto berr;
509 memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
510 longswap(md_data, md_size);
511 ctx->buf_off += md_size;
512
513 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
514 goto berr;
515 if (!EVP_DigestFinal_ex(md, tmp, NULL))
516 goto berr;
517 ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
518 ctx->buf_off += md_size;
519 if (ret == 1) {
520 ctx->sigio = 0;
521 if (ctx->buf_len != ctx->buf_off) {
522 memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
523 ctx->buf_len - ctx->buf_off);
524 }
525 ctx->buf_len -= ctx->buf_off;
526 ctx->buf_off = 0;
527 } else {
528 ctx->cont = 0;
529 }
530 return 1;
531 berr:
532 BIO_clear_retry_flags(b);
533 return 0;
534}
535
536static int block_out(BIO *b)
537{
538 BIO_OK_CTX *ctx;
539 EVP_MD_CTX *md;
540 unsigned long tl;
541 const EVP_MD *digest;
542 int md_size;
543
544 ctx = BIO_get_data(b);
545 md = ctx->md;
546 digest = EVP_MD_CTX_md(md);
547 md_size = EVP_MD_size(digest);
548
549 tl = ctx->buf_len - OK_BLOCK_BLOCK;
550 ctx->buf[0] = (unsigned char)(tl >> 24);
551 ctx->buf[1] = (unsigned char)(tl >> 16);
552 ctx->buf[2] = (unsigned char)(tl >> 8);
553 ctx->buf[3] = (unsigned char)(tl);
554 if (!EVP_DigestUpdate(md,
555 (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
556 goto berr;
557 if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
558 goto berr;
559 ctx->buf_len += md_size;
560 ctx->blockout = 1;
561 return 1;
562 berr:
563 BIO_clear_retry_flags(b);
564 return 0;
565}
566
567static int block_in(BIO *b)
568{
569 BIO_OK_CTX *ctx;
570 EVP_MD_CTX *md;
571 unsigned long tl = 0;
572 unsigned char tmp[EVP_MAX_MD_SIZE];
573 int md_size;
574
575 ctx = BIO_get_data(b);
576 md = ctx->md;
577 md_size = EVP_MD_size(EVP_MD_CTX_md(md));
578
579 assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
580 tl = ctx->buf[0];
581 tl <<= 8;
582 tl |= ctx->buf[1];
583 tl <<= 8;
584 tl |= ctx->buf[2];
585 tl <<= 8;
586 tl |= ctx->buf[3];
587
588 if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size)
589 return 1;
590
591 if (!EVP_DigestUpdate(md,
592 (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
593 goto berr;
594 if (!EVP_DigestFinal_ex(md, tmp, NULL))
595 goto berr;
596 if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md_size) == 0) {
597 /* there might be parts from next block lurking around ! */
598 ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size;
599 ctx->buf_len_save = ctx->buf_len;
600 ctx->buf_off = OK_BLOCK_BLOCK;
601 ctx->buf_len = tl + OK_BLOCK_BLOCK;
602 ctx->blockout = 1;
603 } else {
604 ctx->cont = 0;
605 }
606 return 1;
607 berr:
608 BIO_clear_retry_flags(b);
609 return 0;
610}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette