]>
Commit | Line | Data |
---|---|---|
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 |
81 | static int ok_write(BIO *h, const char *buf, int num); |
82 | static int ok_read(BIO *h, char *buf, int size); | |
83 | static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2); | |
1745a3fb BL |
84 | static int ok_new(BIO *h); |
85 | static int ok_free(BIO *data); | |
13083215 | 86 | static long ok_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); |
d3442bc7 | 87 | |
0f113f3e MC |
88 | static __owur int sig_out(BIO *b); |
89 | static __owur int sig_in(BIO *b); | |
90 | static __owur int block_out(BIO *b); | |
91 | static __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 |
97 | typedef 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 | 110 | static 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 | 122 | const BIO_METHOD *BIO_f_reliable(void) |
0f113f3e MC |
123 | { |
124 | return (&methods_ok); | |
125 | } | |
1745a3fb | 126 | |
6b691a5c | 127 | static 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 | 148 | static 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 | 165 | static 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 | 251 | static 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 | 316 | static 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 | 401 | static 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 | 420 | static 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 |
440 | static 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 |
482 | static 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 |
530 | static 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 |
561 | static 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 | } |