155714Skris/* crypto/evp/bio_ok.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8296465Sdelphij * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15296465Sdelphij * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22296465Sdelphij * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40296465Sdelphij * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52296465Sdelphij * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 59296465Sdelphij/*- 60296465Sdelphij From: Arne Ansper <arne@cyber.ee> 6155714Skris 62296465Sdelphij Why BIO_f_reliable? 6355714Skris 64296465Sdelphij I wrote function which took BIO* as argument, read data from it 65296465Sdelphij and processed it. Then I wanted to store the input file in 66296465Sdelphij encrypted form. OK I pushed BIO_f_cipher to the BIO stack 67296465Sdelphij and everything was OK. BUT if user types wrong password 68296465Sdelphij BIO_f_cipher outputs only garbage and my function crashes. Yes 69296465Sdelphij I can and I should fix my function, but BIO_f_cipher is 70296465Sdelphij easy way to add encryption support to many existing applications 71296465Sdelphij and it's hard to debug and fix them all. 7255714Skris 73296465Sdelphij So I wanted another BIO which would catch the incorrect passwords and 74296465Sdelphij file damages which cause garbage on BIO_f_cipher's output. 7555714Skris 76296465Sdelphij The easy way is to push the BIO_f_md and save the checksum at 77296465Sdelphij the end of the file. However there are several problems with this 78296465Sdelphij approach: 7955714Skris 80296465Sdelphij 1) you must somehow separate checksum from actual data. 81296465Sdelphij 2) you need lot's of memory when reading the file, because you 82296465Sdelphij must read to the end of the file and verify the checksum before 83296465Sdelphij letting the application to read the data. 8455714Skris 85296465Sdelphij BIO_f_reliable tries to solve both problems, so that you can 86296465Sdelphij read and write arbitrary long streams using only fixed amount 87296465Sdelphij of memory. 8855714Skris 89296465Sdelphij BIO_f_reliable splits data stream into blocks. Each block is prefixed 90296465Sdelphij with it's length and suffixed with it's digest. So you need only 91296465Sdelphij several Kbytes of memory to buffer single block before verifying 92296465Sdelphij it's digest. 9355714Skris 94296465Sdelphij BIO_f_reliable goes further and adds several important capabilities: 9555714Skris 96296465Sdelphij 1) the digest of the block is computed over the whole stream 97296465Sdelphij -- so nobody can rearrange the blocks or remove or replace them. 9855714Skris 99296465Sdelphij 2) to detect invalid passwords right at the start BIO_f_reliable 100296465Sdelphij adds special prefix to the stream. In order to avoid known plain-text 101296465Sdelphij attacks this prefix is generated as follows: 10255714Skris 103296465Sdelphij *) digest is initialized with random seed instead of 104296465Sdelphij standardized one. 105296465Sdelphij *) same seed is written to output 106296465Sdelphij *) well-known text is then hashed and the output 107296465Sdelphij of the digest is also written to output. 10855714Skris 109296465Sdelphij reader can now read the seed from stream, hash the same string 110296465Sdelphij and then compare the digest output. 11155714Skris 112296465Sdelphij Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I 113296465Sdelphij initially wrote and tested this code on x86 machine and wrote the 114296465Sdelphij digests out in machine-dependent order :( There are people using 115296465Sdelphij this code and I cannot change this easily without making existing 116296465Sdelphij data files unreadable. 117296465Sdelphij 11855714Skris*/ 11955714Skris 12055714Skris#include <stdio.h> 12155714Skris#include <errno.h> 122160814Ssimon#include <assert.h> 12355714Skris#include "cryptlib.h" 12455714Skris#include <openssl/buffer.h> 12555714Skris#include <openssl/bio.h> 12655714Skris#include <openssl/evp.h> 12755714Skris#include <openssl/rand.h> 12855714Skris 12968651Skrisstatic int ok_write(BIO *h, const char *buf, int num); 13068651Skrisstatic int ok_read(BIO *h, char *buf, int size); 13168651Skrisstatic long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2); 13255714Skrisstatic int ok_new(BIO *h); 13355714Skrisstatic int ok_free(BIO *data); 13468651Skrisstatic long ok_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 13559191Skris 136296465Sdelphijstatic void sig_out(BIO *b); 137296465Sdelphijstatic void sig_in(BIO *b); 138296465Sdelphijstatic void block_out(BIO *b); 139296465Sdelphijstatic void block_in(BIO *b); 140296465Sdelphij#define OK_BLOCK_SIZE (1024*4) 141296465Sdelphij#define OK_BLOCK_BLOCK 4 142296465Sdelphij#define IOBS (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE) 14355714Skris#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back." 14455714Skris 145296465Sdelphijtypedef struct ok_struct { 146296465Sdelphij size_t buf_len; 147296465Sdelphij size_t buf_off; 148296465Sdelphij size_t buf_len_save; 149296465Sdelphij size_t buf_off_save; 150296465Sdelphij int cont; /* <= 0 when finished */ 151296465Sdelphij int finished; 152296465Sdelphij EVP_MD_CTX md; 153296465Sdelphij int blockout; /* output block is ready */ 154296465Sdelphij int sigio; /* must process signature */ 155296465Sdelphij unsigned char buf[IOBS]; 156296465Sdelphij} BIO_OK_CTX; 15755714Skris 158296465Sdelphijstatic BIO_METHOD methods_ok = { 159296465Sdelphij BIO_TYPE_CIPHER, "reliable", 160296465Sdelphij ok_write, 161296465Sdelphij ok_read, 162296465Sdelphij NULL, /* ok_puts, */ 163296465Sdelphij NULL, /* ok_gets, */ 164296465Sdelphij ok_ctrl, 165296465Sdelphij ok_new, 166296465Sdelphij ok_free, 167296465Sdelphij ok_callback_ctrl, 168296465Sdelphij}; 16955714Skris 17055714SkrisBIO_METHOD *BIO_f_reliable(void) 171296465Sdelphij{ 172296465Sdelphij return (&methods_ok); 173296465Sdelphij} 17455714Skris 17555714Skrisstatic int ok_new(BIO *bi) 176296465Sdelphij{ 177296465Sdelphij BIO_OK_CTX *ctx; 17855714Skris 179296465Sdelphij ctx = (BIO_OK_CTX *)OPENSSL_malloc(sizeof(BIO_OK_CTX)); 180296465Sdelphij if (ctx == NULL) 181296465Sdelphij return (0); 18255714Skris 183296465Sdelphij ctx->buf_len = 0; 184296465Sdelphij ctx->buf_off = 0; 185296465Sdelphij ctx->buf_len_save = 0; 186296465Sdelphij ctx->buf_off_save = 0; 187296465Sdelphij ctx->cont = 1; 188296465Sdelphij ctx->finished = 0; 189296465Sdelphij ctx->blockout = 0; 190296465Sdelphij ctx->sigio = 1; 19155714Skris 192296465Sdelphij EVP_MD_CTX_init(&ctx->md); 193109998Smarkm 194296465Sdelphij bi->init = 0; 195296465Sdelphij bi->ptr = (char *)ctx; 196296465Sdelphij bi->flags = 0; 197296465Sdelphij return (1); 198296465Sdelphij} 19955714Skris 20055714Skrisstatic int ok_free(BIO *a) 201296465Sdelphij{ 202296465Sdelphij if (a == NULL) 203296465Sdelphij return (0); 204296465Sdelphij EVP_MD_CTX_cleanup(&((BIO_OK_CTX *)a->ptr)->md); 205296465Sdelphij OPENSSL_cleanse(a->ptr, sizeof(BIO_OK_CTX)); 206296465Sdelphij OPENSSL_free(a->ptr); 207296465Sdelphij a->ptr = NULL; 208296465Sdelphij a->init = 0; 209296465Sdelphij a->flags = 0; 210296465Sdelphij return (1); 211296465Sdelphij} 212296465Sdelphij 21355714Skrisstatic int ok_read(BIO *b, char *out, int outl) 214296465Sdelphij{ 215296465Sdelphij int ret = 0, i, n; 216296465Sdelphij BIO_OK_CTX *ctx; 21755714Skris 218296465Sdelphij if (out == NULL) 219296465Sdelphij return (0); 220296465Sdelphij ctx = (BIO_OK_CTX *)b->ptr; 22155714Skris 222296465Sdelphij if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) 223296465Sdelphij return (0); 22455714Skris 225296465Sdelphij while (outl > 0) { 22655714Skris 227296465Sdelphij /* copy clean bytes to output buffer */ 228296465Sdelphij if (ctx->blockout) { 229296465Sdelphij i = ctx->buf_len - ctx->buf_off; 230296465Sdelphij if (i > outl) 231296465Sdelphij i = outl; 232296465Sdelphij memcpy(out, &(ctx->buf[ctx->buf_off]), i); 233296465Sdelphij ret += i; 234296465Sdelphij out += i; 235296465Sdelphij outl -= i; 236296465Sdelphij ctx->buf_off += i; 23755714Skris 238296465Sdelphij /* all clean bytes are out */ 239296465Sdelphij if (ctx->buf_len == ctx->buf_off) { 240296465Sdelphij ctx->buf_off = 0; 24155714Skris 242296465Sdelphij /* 243296465Sdelphij * copy start of the next block into proper place 244296465Sdelphij */ 245296465Sdelphij if (ctx->buf_len_save - ctx->buf_off_save > 0) { 246296465Sdelphij ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save; 247296465Sdelphij memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]), 248296465Sdelphij ctx->buf_len); 249296465Sdelphij } else { 250296465Sdelphij ctx->buf_len = 0; 251296465Sdelphij } 252296465Sdelphij ctx->blockout = 0; 253296465Sdelphij } 254296465Sdelphij } 25555714Skris 256296465Sdelphij /* output buffer full -- cancel */ 257296465Sdelphij if (outl == 0) 258296465Sdelphij break; 25955714Skris 260296465Sdelphij /* no clean bytes in buffer -- fill it */ 261296465Sdelphij n = IOBS - ctx->buf_len; 262296465Sdelphij i = BIO_read(b->next_bio, &(ctx->buf[ctx->buf_len]), n); 26355714Skris 264296465Sdelphij if (i <= 0) 265296465Sdelphij break; /* nothing new */ 26655714Skris 267296465Sdelphij ctx->buf_len += i; 26855714Skris 269296465Sdelphij /* no signature yet -- check if we got one */ 270296465Sdelphij if (ctx->sigio == 1) 271296465Sdelphij sig_in(b); 27255714Skris 273296465Sdelphij /* signature ok -- check if we got block */ 274296465Sdelphij if (ctx->sigio == 0) 275296465Sdelphij block_in(b); 27655714Skris 277296465Sdelphij /* invalid block -- cancel */ 278296465Sdelphij if (ctx->cont <= 0) 279296465Sdelphij break; 28055714Skris 281296465Sdelphij } 28255714Skris 283296465Sdelphij BIO_clear_retry_flags(b); 284296465Sdelphij BIO_copy_next_retry(b); 285296465Sdelphij return (ret); 286296465Sdelphij} 287296465Sdelphij 28868651Skrisstatic int ok_write(BIO *b, const char *in, int inl) 289296465Sdelphij{ 290296465Sdelphij int ret = 0, n, i; 291296465Sdelphij BIO_OK_CTX *ctx; 29255714Skris 293296465Sdelphij if (inl <= 0) 294296465Sdelphij return inl; 295160814Ssimon 296296465Sdelphij ctx = (BIO_OK_CTX *)b->ptr; 297296465Sdelphij ret = inl; 29855714Skris 299296465Sdelphij if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) 300296465Sdelphij return (0); 30155714Skris 302296465Sdelphij if (ctx->sigio) 303296465Sdelphij sig_out(b); 30455714Skris 305296465Sdelphij do { 306296465Sdelphij BIO_clear_retry_flags(b); 307296465Sdelphij n = ctx->buf_len - ctx->buf_off; 308296465Sdelphij while (ctx->blockout && n > 0) { 309296465Sdelphij i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 310296465Sdelphij if (i <= 0) { 311296465Sdelphij BIO_copy_next_retry(b); 312296465Sdelphij if (!BIO_should_retry(b)) 313296465Sdelphij ctx->cont = 0; 314296465Sdelphij return (i); 315296465Sdelphij } 316296465Sdelphij ctx->buf_off += i; 317296465Sdelphij n -= i; 318296465Sdelphij } 31955714Skris 320296465Sdelphij /* at this point all pending data has been written */ 321296465Sdelphij ctx->blockout = 0; 322296465Sdelphij if (ctx->buf_len == ctx->buf_off) { 323296465Sdelphij ctx->buf_len = OK_BLOCK_BLOCK; 324296465Sdelphij ctx->buf_off = 0; 325296465Sdelphij } 32655714Skris 327296465Sdelphij if ((in == NULL) || (inl <= 0)) 328296465Sdelphij return (0); 32955714Skris 330296465Sdelphij n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ? 331296465Sdelphij (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl; 33255714Skris 333296465Sdelphij memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])), 334296465Sdelphij (unsigned char *)in, n); 335296465Sdelphij ctx->buf_len += n; 336296465Sdelphij inl -= n; 337296465Sdelphij in += n; 33855714Skris 339296465Sdelphij if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) { 340296465Sdelphij block_out(b); 341296465Sdelphij } 342296465Sdelphij } while (inl > 0); 34355714Skris 344296465Sdelphij BIO_clear_retry_flags(b); 345296465Sdelphij BIO_copy_next_retry(b); 346296465Sdelphij return (ret); 347296465Sdelphij} 348296465Sdelphij 34968651Skrisstatic long ok_ctrl(BIO *b, int cmd, long num, void *ptr) 350296465Sdelphij{ 351296465Sdelphij BIO_OK_CTX *ctx; 352296465Sdelphij EVP_MD *md; 353296465Sdelphij const EVP_MD **ppmd; 354296465Sdelphij long ret = 1; 355296465Sdelphij int i; 35655714Skris 357296465Sdelphij ctx = b->ptr; 35855714Skris 359296465Sdelphij switch (cmd) { 360296465Sdelphij case BIO_CTRL_RESET: 361296465Sdelphij ctx->buf_len = 0; 362296465Sdelphij ctx->buf_off = 0; 363296465Sdelphij ctx->buf_len_save = 0; 364296465Sdelphij ctx->buf_off_save = 0; 365296465Sdelphij ctx->cont = 1; 366296465Sdelphij ctx->finished = 0; 367296465Sdelphij ctx->blockout = 0; 368296465Sdelphij ctx->sigio = 1; 369296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 370296465Sdelphij break; 371296465Sdelphij case BIO_CTRL_EOF: /* More to read */ 372296465Sdelphij if (ctx->cont <= 0) 373296465Sdelphij ret = 1; 374296465Sdelphij else 375296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 376296465Sdelphij break; 377296465Sdelphij case BIO_CTRL_PENDING: /* More to read in buffer */ 378296465Sdelphij case BIO_CTRL_WPENDING: /* More to read in buffer */ 379296465Sdelphij ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0; 380296465Sdelphij if (ret <= 0) 381296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 382296465Sdelphij break; 383296465Sdelphij case BIO_CTRL_FLUSH: 384296465Sdelphij /* do a final write */ 385296465Sdelphij if (ctx->blockout == 0) 386296465Sdelphij block_out(b); 38755714Skris 388296465Sdelphij while (ctx->blockout) { 389296465Sdelphij i = ok_write(b, NULL, 0); 390296465Sdelphij if (i < 0) { 391296465Sdelphij ret = i; 392296465Sdelphij break; 393296465Sdelphij } 394296465Sdelphij } 39555714Skris 396296465Sdelphij ctx->finished = 1; 397296465Sdelphij ctx->buf_off = ctx->buf_len = 0; 398296465Sdelphij ctx->cont = (int)ret; 39955714Skris 400296465Sdelphij /* Finally flush the underlying BIO */ 401296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 402296465Sdelphij break; 403296465Sdelphij case BIO_C_DO_STATE_MACHINE: 404296465Sdelphij BIO_clear_retry_flags(b); 405296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 406296465Sdelphij BIO_copy_next_retry(b); 407296465Sdelphij break; 408296465Sdelphij case BIO_CTRL_INFO: 409296465Sdelphij ret = (long)ctx->cont; 410296465Sdelphij break; 411296465Sdelphij case BIO_C_SET_MD: 412296465Sdelphij md = ptr; 413296465Sdelphij EVP_DigestInit_ex(&ctx->md, md, NULL); 414296465Sdelphij b->init = 1; 415296465Sdelphij break; 416296465Sdelphij case BIO_C_GET_MD: 417296465Sdelphij if (b->init) { 418296465Sdelphij ppmd = ptr; 419296465Sdelphij *ppmd = ctx->md.digest; 420296465Sdelphij } else 421296465Sdelphij ret = 0; 422296465Sdelphij break; 423296465Sdelphij default: 424296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 425296465Sdelphij break; 426296465Sdelphij } 427296465Sdelphij return (ret); 428296465Sdelphij} 429296465Sdelphij 43068651Skrisstatic long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 431296465Sdelphij{ 432296465Sdelphij long ret = 1; 43359191Skris 434296465Sdelphij if (b->next_bio == NULL) 435296465Sdelphij return (0); 436296465Sdelphij switch (cmd) { 437296465Sdelphij default: 438296465Sdelphij ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 439296465Sdelphij break; 440296465Sdelphij } 441296465Sdelphij return (ret); 442296465Sdelphij} 44359191Skris 444160814Ssimonstatic void longswap(void *_ptr, size_t len) 445296465Sdelphij{ 446296465Sdelphij const union { 447296465Sdelphij long one; 448296465Sdelphij char little; 449296465Sdelphij } is_endian = { 450296465Sdelphij 1 451296465Sdelphij }; 45255714Skris 453296465Sdelphij if (is_endian.little) { 454296465Sdelphij size_t i; 455296465Sdelphij unsigned char *p = _ptr, c; 456160814Ssimon 457296465Sdelphij for (i = 0; i < len; i += 4) { 458296465Sdelphij c = p[0], p[0] = p[3], p[3] = c; 459296465Sdelphij c = p[1], p[1] = p[2], p[2] = c; 460296465Sdelphij } 461296465Sdelphij } 46255714Skris} 46355714Skris 464296465Sdelphijstatic void sig_out(BIO *b) 465296465Sdelphij{ 466296465Sdelphij BIO_OK_CTX *ctx; 467296465Sdelphij EVP_MD_CTX *md; 46855714Skris 469296465Sdelphij ctx = b->ptr; 470296465Sdelphij md = &ctx->md; 47155714Skris 472296465Sdelphij if (ctx->buf_len + 2 * md->digest->md_size > OK_BLOCK_SIZE) 473296465Sdelphij return; 47455714Skris 475296465Sdelphij EVP_DigestInit_ex(md, md->digest, NULL); 476296465Sdelphij /* 477296465Sdelphij * FIXME: there's absolutely no guarantee this makes any sense at all, 478296465Sdelphij * particularly now EVP_MD_CTX has been restructured. 479296465Sdelphij */ 480296465Sdelphij RAND_pseudo_bytes(md->md_data, md->digest->md_size); 481296465Sdelphij memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size); 482296465Sdelphij longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size); 483296465Sdelphij ctx->buf_len += md->digest->md_size; 48455714Skris 485296465Sdelphij EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)); 486296465Sdelphij EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL); 487296465Sdelphij ctx->buf_len += md->digest->md_size; 488296465Sdelphij ctx->blockout = 1; 489296465Sdelphij ctx->sigio = 0; 490296465Sdelphij} 49155714Skris 492296465Sdelphijstatic void sig_in(BIO *b) 493296465Sdelphij{ 494296465Sdelphij BIO_OK_CTX *ctx; 495296465Sdelphij EVP_MD_CTX *md; 496296465Sdelphij unsigned char tmp[EVP_MAX_MD_SIZE]; 497296465Sdelphij int ret = 0; 49855714Skris 499296465Sdelphij ctx = b->ptr; 500296465Sdelphij md = &ctx->md; 50155714Skris 502296465Sdelphij if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md->digest->md_size) 503296465Sdelphij return; 50455714Skris 505296465Sdelphij EVP_DigestInit_ex(md, md->digest, NULL); 506296465Sdelphij memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size); 507296465Sdelphij longswap(md->md_data, md->digest->md_size); 508296465Sdelphij ctx->buf_off += md->digest->md_size; 50955714Skris 510296465Sdelphij EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)); 511296465Sdelphij EVP_DigestFinal_ex(md, tmp, NULL); 512296465Sdelphij ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0; 513296465Sdelphij ctx->buf_off += md->digest->md_size; 514296465Sdelphij if (ret == 1) { 515296465Sdelphij ctx->sigio = 0; 516296465Sdelphij if (ctx->buf_len != ctx->buf_off) { 517296465Sdelphij memmove(ctx->buf, &(ctx->buf[ctx->buf_off]), 518296465Sdelphij ctx->buf_len - ctx->buf_off); 519296465Sdelphij } 520296465Sdelphij ctx->buf_len -= ctx->buf_off; 521296465Sdelphij ctx->buf_off = 0; 522296465Sdelphij } else { 523296465Sdelphij ctx->cont = 0; 524296465Sdelphij } 525296465Sdelphij} 52655714Skris 527296465Sdelphijstatic void block_out(BIO *b) 528296465Sdelphij{ 529296465Sdelphij BIO_OK_CTX *ctx; 530296465Sdelphij EVP_MD_CTX *md; 531296465Sdelphij unsigned long tl; 53255714Skris 533296465Sdelphij ctx = b->ptr; 534296465Sdelphij md = &ctx->md; 53555714Skris 536296465Sdelphij tl = ctx->buf_len - OK_BLOCK_BLOCK; 537296465Sdelphij ctx->buf[0] = (unsigned char)(tl >> 24); 538296465Sdelphij ctx->buf[1] = (unsigned char)(tl >> 16); 539296465Sdelphij ctx->buf[2] = (unsigned char)(tl >> 8); 540296465Sdelphij ctx->buf[3] = (unsigned char)(tl); 541296465Sdelphij EVP_DigestUpdate(md, (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl); 542296465Sdelphij EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL); 543296465Sdelphij ctx->buf_len += md->digest->md_size; 544296465Sdelphij ctx->blockout = 1; 545296465Sdelphij} 54655714Skris 547296465Sdelphijstatic void block_in(BIO *b) 548296465Sdelphij{ 549296465Sdelphij BIO_OK_CTX *ctx; 550296465Sdelphij EVP_MD_CTX *md; 551296465Sdelphij unsigned long tl = 0; 552296465Sdelphij unsigned char tmp[EVP_MAX_MD_SIZE]; 55355714Skris 554296465Sdelphij ctx = b->ptr; 555296465Sdelphij md = &ctx->md; 55655714Skris 557296465Sdelphij assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */ 558296465Sdelphij tl = ctx->buf[0]; 559296465Sdelphij tl <<= 8; 560296465Sdelphij tl |= ctx->buf[1]; 561296465Sdelphij tl <<= 8; 562296465Sdelphij tl |= ctx->buf[2]; 563296465Sdelphij tl <<= 8; 564296465Sdelphij tl |= ctx->buf[3]; 565160814Ssimon 566296465Sdelphij if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md->digest->md_size) 567296465Sdelphij return; 56855714Skris 569296465Sdelphij EVP_DigestUpdate(md, (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl); 570296465Sdelphij EVP_DigestFinal_ex(md, tmp, NULL); 571296465Sdelphij if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md->digest->md_size) == 572296465Sdelphij 0) { 573296465Sdelphij /* there might be parts from next block lurking around ! */ 574296465Sdelphij ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md->digest->md_size; 575296465Sdelphij ctx->buf_len_save = ctx->buf_len; 576296465Sdelphij ctx->buf_off = OK_BLOCK_BLOCK; 577296465Sdelphij ctx->buf_len = tl + OK_BLOCK_BLOCK; 578296465Sdelphij ctx->blockout = 1; 579296465Sdelphij } else { 580296465Sdelphij ctx->cont = 0; 581296465Sdelphij } 582296465Sdelphij} 583