VirtualBox

source: vbox/trunk/src/libs/openssl-3.3.2/crypto/evp/bio_ok.c@ 108358

最後變更 在這個檔案從108358是 108206,由 vboxsync 提交於 6 週 前

openssl-3.3.2: Exported all files to OSE and removed .scm-settings ​bugref:10757

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

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