source: EcnlProtoTool/trunk/openssl-1.1.0e/crypto/evp/bio_ok.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 15.7 KB
Line 
1/*
2 * Copyright 1995-2016 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 <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.
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/evp_int.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, "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};
121
122const BIO_METHOD *BIO_f_reliable(void)
123{
124 return (&methods_ok);
125}
126
127static int ok_new(BIO *bi)
128{
129 BIO_OK_CTX *ctx;
130
131 ctx = OPENSSL_zalloc(sizeof(*ctx));
132 if (ctx == NULL)
133 return 0;
134
135 ctx->cont = 1;
136 ctx->sigio = 1;
137 ctx->md = EVP_MD_CTX_new();
138 if (ctx->md == NULL) {
139 OPENSSL_free(ctx);
140 return 0;
141 }
142 BIO_set_init(bi, 0);
143 BIO_set_data(bi, ctx);
144
145 return 1;
146}
147
148static int ok_free(BIO *a)
149{
150 BIO_OK_CTX *ctx;
151
152 if (a == NULL)
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;
163}
164
165static int ok_read(BIO *b, char *out, int outl)
166{
167 int ret = 0, i, n;
168 BIO_OK_CTX *ctx;
169 BIO *next;
170
171 if (out == NULL)
172 return 0;
173
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;
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;
217 i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n);
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);
248 return ret;
249}
250
251static int ok_write(BIO *b, const char *in, int inl)
252{
253 int ret = 0, n, i;
254 BIO_OK_CTX *ctx;
255 BIO *next;
256
257 if (inl <= 0)
258 return inl;
259
260 ctx = BIO_get_data(b);
261 next = BIO_next(b);
262 ret = inl;
263
264 if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
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) {
274 i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
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
298 memcpy(&ctx->buf[ctx->buf_len], in, n);
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}
315
316static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
317{
318 BIO_OK_CTX *ctx;
319 EVP_MD *md;
320 const EVP_MD **ppmd;
321 long ret = 1;
322 int i;
323 BIO *next;
324
325 ctx = BIO_get_data(b);
326 next = BIO_next(b);
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;
338 ret = BIO_ctrl(next, cmd, num, ptr);
339 break;
340 case BIO_CTRL_EOF: /* More to read */
341 if (ctx->cont <= 0)
342 ret = 1;
343 else
344 ret = BIO_ctrl(next, cmd, num, ptr);
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)
350 ret = BIO_ctrl(next, cmd, num, ptr);
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 */
371 ret = BIO_ctrl(next, cmd, num, ptr);
372 break;
373 case BIO_C_DO_STATE_MACHINE:
374 BIO_clear_retry_flags(b);
375 ret = BIO_ctrl(next, cmd, num, ptr);
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;
383 if (!EVP_DigestInit_ex(ctx->md, md, NULL))
384 return 0;
385 BIO_set_init(b, 1);
386 break;
387 case BIO_C_GET_MD:
388 if (BIO_get_init(b)) {
389 ppmd = ptr;
390 *ppmd = EVP_MD_CTX_md(ctx->md);
391 } else
392 ret = 0;
393 break;
394 default:
395 ret = BIO_ctrl(next, cmd, num, ptr);
396 break;
397 }
398 return ret;
399}
400
401static long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
402{
403 long ret = 1;
404 BIO *next;
405
406 next = BIO_next(b);
407
408 if (next == NULL)
409 return 0;
410
411 switch (cmd) {
412 default:
413 ret = BIO_callback_ctrl(next, cmd, fp);
414 break;
415 }
416
417 return ret;
418}
419
420static void longswap(void *_ptr, size_t len)
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}
439
440static int sig_out(BIO *b)
441{
442 BIO_OK_CTX *ctx;
443 EVP_MD_CTX *md;
444 const EVP_MD *digest;
445 int md_size;
446 void *md_data;
447
448 ctx = BIO_get_data(b);
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);
453
454 if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
455 return 1;
456
457 if (!EVP_DigestInit_ex(md, digest, NULL))
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 */
463 if (RAND_bytes(md_data, md_size) <= 0)
464 goto berr;
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;
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;
473 ctx->buf_len += md_size;
474 ctx->blockout = 1;
475 ctx->sigio = 0;
476 return 1;
477 berr:
478 BIO_clear_retry_flags(b);
479 return 0;
480}
481
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;
488 const EVP_MD *digest;
489 int md_size;
490 void *md_data;
491
492 ctx = BIO_get_data(b);
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);
497
498 if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
499 return 1;
500
501 if (!EVP_DigestInit_ex(md, digest, NULL))
502 goto berr;
503 memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
504 longswap(md_data, md_size);
505 ctx->buf_off += md_size;
506
507 if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
508 goto berr;
509 if (!EVP_DigestFinal_ex(md, tmp, NULL))
510 goto berr;
511 ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
512 ctx->buf_off += md_size;
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;
528}
529
530static int block_out(BIO *b)
531{
532 BIO_OK_CTX *ctx;
533 EVP_MD_CTX *md;
534 unsigned long tl;
535 const EVP_MD *digest;
536 int md_size;
537
538 ctx = BIO_get_data(b);
539 md = ctx->md;
540 digest = EVP_MD_CTX_md(md);
541 md_size = EVP_MD_size(digest);
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;
553 ctx->buf_len += md_size;
554 ctx->blockout = 1;
555 return 1;
556 berr:
557 BIO_clear_retry_flags(b);
558 return 0;
559}
560
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];
567 int md_size;
568
569 ctx = BIO_get_data(b);
570 md = ctx->md;
571 md_size = EVP_MD_size(EVP_MD_CTX_md(md));
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
582 if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size)
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;
590 if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md_size) == 0) {
591 /* there might be parts from next block lurking around ! */
592 ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size;
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}
Note: See TracBrowser for help on using the repository browser.