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. 8296341Sdelphij * 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). 15296341Sdelphij * 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. 22296341Sdelphij * 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 :-). 37296341Sdelphij * 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)" 40296341Sdelphij * 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. 52296341Sdelphij * 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 59296341Sdelphij/*- 60296341Sdelphij From: Arne Ansper <arne@cyber.ee> 6155714Skris 62296341Sdelphij Why BIO_f_reliable? 6355714Skris 64296341Sdelphij I wrote function which took BIO* as argument, read data from it 65296341Sdelphij and processed it. Then I wanted to store the input file in 66296341Sdelphij encrypted form. OK I pushed BIO_f_cipher to the BIO stack 67296341Sdelphij and everything was OK. BUT if user types wrong password 68296341Sdelphij BIO_f_cipher outputs only garbage and my function crashes. Yes 69296341Sdelphij I can and I should fix my function, but BIO_f_cipher is 70296341Sdelphij easy way to add encryption support to many existing applications 71296341Sdelphij and it's hard to debug and fix them all. 7255714Skris 73296341Sdelphij So I wanted another BIO which would catch the incorrect passwords and 74296341Sdelphij file damages which cause garbage on BIO_f_cipher's output. 7555714Skris 76296341Sdelphij The easy way is to push the BIO_f_md and save the checksum at 77296341Sdelphij the end of the file. However there are several problems with this 78296341Sdelphij approach: 7955714Skris 80296341Sdelphij 1) you must somehow separate checksum from actual data. 81296341Sdelphij 2) you need lot's of memory when reading the file, because you 82296341Sdelphij must read to the end of the file and verify the checksum before 83296341Sdelphij letting the application to read the data. 8455714Skris 85296341Sdelphij BIO_f_reliable tries to solve both problems, so that you can 86296341Sdelphij read and write arbitrary long streams using only fixed amount 87296341Sdelphij of memory. 8855714Skris 89296341Sdelphij BIO_f_reliable splits data stream into blocks. Each block is prefixed 90296341Sdelphij with it's length and suffixed with it's digest. So you need only 91296341Sdelphij several Kbytes of memory to buffer single block before verifying 92296341Sdelphij it's digest. 9355714Skris 94296341Sdelphij BIO_f_reliable goes further and adds several important capabilities: 9555714Skris 96296341Sdelphij 1) the digest of the block is computed over the whole stream 97296341Sdelphij -- so nobody can rearrange the blocks or remove or replace them. 9855714Skris 99296341Sdelphij 2) to detect invalid passwords right at the start BIO_f_reliable 100296341Sdelphij adds special prefix to the stream. In order to avoid known plain-text 101296341Sdelphij attacks this prefix is generated as follows: 10255714Skris 103296341Sdelphij *) digest is initialized with random seed instead of 104296341Sdelphij standardized one. 105296341Sdelphij *) same seed is written to output 106296341Sdelphij *) well-known text is then hashed and the output 107296341Sdelphij of the digest is also written to output. 10855714Skris 109296341Sdelphij reader can now read the seed from stream, hash the same string 110296341Sdelphij and then compare the digest output. 11155714Skris 112296341Sdelphij Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I 113296341Sdelphij initially wrote and tested this code on x86 machine and wrote the 114296341Sdelphij digests out in machine-dependent order :( There are people using 115296341Sdelphij this code and I cannot change this easily without making existing 116296341Sdelphij data files unreadable. 117296341Sdelphij 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 136296341Sdelphijstatic int sig_out(BIO *b); 137296341Sdelphijstatic int sig_in(BIO *b); 138296341Sdelphijstatic int block_out(BIO *b); 139296341Sdelphijstatic int block_in(BIO *b); 140296341Sdelphij#define OK_BLOCK_SIZE (1024*4) 141296341Sdelphij#define OK_BLOCK_BLOCK 4 142296341Sdelphij#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 145296341Sdelphijtypedef struct ok_struct { 146296341Sdelphij size_t buf_len; 147296341Sdelphij size_t buf_off; 148296341Sdelphij size_t buf_len_save; 149296341Sdelphij size_t buf_off_save; 150296341Sdelphij int cont; /* <= 0 when finished */ 151296341Sdelphij int finished; 152296341Sdelphij EVP_MD_CTX md; 153296341Sdelphij int blockout; /* output block is ready */ 154296341Sdelphij int sigio; /* must process signature */ 155296341Sdelphij unsigned char buf[IOBS]; 156296341Sdelphij} BIO_OK_CTX; 15755714Skris 158296341Sdelphijstatic BIO_METHOD methods_ok = { 159296341Sdelphij BIO_TYPE_CIPHER, "reliable", 160296341Sdelphij ok_write, 161296341Sdelphij ok_read, 162296341Sdelphij NULL, /* ok_puts, */ 163296341Sdelphij NULL, /* ok_gets, */ 164296341Sdelphij ok_ctrl, 165296341Sdelphij ok_new, 166296341Sdelphij ok_free, 167296341Sdelphij ok_callback_ctrl, 168296341Sdelphij}; 16955714Skris 17055714SkrisBIO_METHOD *BIO_f_reliable(void) 171296341Sdelphij{ 172296341Sdelphij return (&methods_ok); 173296341Sdelphij} 17455714Skris 17555714Skrisstatic int ok_new(BIO *bi) 176296341Sdelphij{ 177296341Sdelphij BIO_OK_CTX *ctx; 17855714Skris 179296341Sdelphij ctx = (BIO_OK_CTX *)OPENSSL_malloc(sizeof(BIO_OK_CTX)); 180296341Sdelphij if (ctx == NULL) 181296341Sdelphij return (0); 18255714Skris 183296341Sdelphij ctx->buf_len = 0; 184296341Sdelphij ctx->buf_off = 0; 185296341Sdelphij ctx->buf_len_save = 0; 186296341Sdelphij ctx->buf_off_save = 0; 187296341Sdelphij ctx->cont = 1; 188296341Sdelphij ctx->finished = 0; 189296341Sdelphij ctx->blockout = 0; 190296341Sdelphij ctx->sigio = 1; 19155714Skris 192296341Sdelphij EVP_MD_CTX_init(&ctx->md); 193109998Smarkm 194296341Sdelphij bi->init = 0; 195296341Sdelphij bi->ptr = (char *)ctx; 196296341Sdelphij bi->flags = 0; 197296341Sdelphij return (1); 198296341Sdelphij} 19955714Skris 20055714Skrisstatic int ok_free(BIO *a) 201296341Sdelphij{ 202296341Sdelphij if (a == NULL) 203296341Sdelphij return (0); 204296341Sdelphij EVP_MD_CTX_cleanup(&((BIO_OK_CTX *)a->ptr)->md); 205296341Sdelphij OPENSSL_cleanse(a->ptr, sizeof(BIO_OK_CTX)); 206296341Sdelphij OPENSSL_free(a->ptr); 207296341Sdelphij a->ptr = NULL; 208296341Sdelphij a->init = 0; 209296341Sdelphij a->flags = 0; 210296341Sdelphij return (1); 211296341Sdelphij} 212296341Sdelphij 21355714Skrisstatic int ok_read(BIO *b, char *out, int outl) 214296341Sdelphij{ 215296341Sdelphij int ret = 0, i, n; 216296341Sdelphij BIO_OK_CTX *ctx; 21755714Skris 218296341Sdelphij if (out == NULL) 219296341Sdelphij return (0); 220296341Sdelphij ctx = (BIO_OK_CTX *)b->ptr; 22155714Skris 222296341Sdelphij if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) 223296341Sdelphij return (0); 22455714Skris 225296341Sdelphij while (outl > 0) { 22655714Skris 227296341Sdelphij /* copy clean bytes to output buffer */ 228296341Sdelphij if (ctx->blockout) { 229296341Sdelphij i = ctx->buf_len - ctx->buf_off; 230296341Sdelphij if (i > outl) 231296341Sdelphij i = outl; 232296341Sdelphij memcpy(out, &(ctx->buf[ctx->buf_off]), i); 233296341Sdelphij ret += i; 234296341Sdelphij out += i; 235296341Sdelphij outl -= i; 236296341Sdelphij ctx->buf_off += i; 23755714Skris 238296341Sdelphij /* all clean bytes are out */ 239296341Sdelphij if (ctx->buf_len == ctx->buf_off) { 240296341Sdelphij ctx->buf_off = 0; 24155714Skris 242296341Sdelphij /* 243296341Sdelphij * copy start of the next block into proper place 244296341Sdelphij */ 245296341Sdelphij if (ctx->buf_len_save - ctx->buf_off_save > 0) { 246296341Sdelphij ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save; 247296341Sdelphij memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]), 248296341Sdelphij ctx->buf_len); 249296341Sdelphij } else { 250296341Sdelphij ctx->buf_len = 0; 251296341Sdelphij } 252296341Sdelphij ctx->blockout = 0; 253296341Sdelphij } 254296341Sdelphij } 25555714Skris 256296341Sdelphij /* output buffer full -- cancel */ 257296341Sdelphij if (outl == 0) 258296341Sdelphij break; 25955714Skris 260296341Sdelphij /* no clean bytes in buffer -- fill it */ 261296341Sdelphij n = IOBS - ctx->buf_len; 262296341Sdelphij i = BIO_read(b->next_bio, &(ctx->buf[ctx->buf_len]), n); 26355714Skris 264296341Sdelphij if (i <= 0) 265296341Sdelphij break; /* nothing new */ 26655714Skris 267296341Sdelphij ctx->buf_len += i; 26855714Skris 269296341Sdelphij /* no signature yet -- check if we got one */ 270296341Sdelphij if (ctx->sigio == 1) { 271296341Sdelphij if (!sig_in(b)) { 272296341Sdelphij BIO_clear_retry_flags(b); 273296341Sdelphij return 0; 274296341Sdelphij } 275296341Sdelphij } 27655714Skris 277296341Sdelphij /* signature ok -- check if we got block */ 278296341Sdelphij if (ctx->sigio == 0) { 279296341Sdelphij if (!block_in(b)) { 280296341Sdelphij BIO_clear_retry_flags(b); 281296341Sdelphij return 0; 282296341Sdelphij } 283296341Sdelphij } 28455714Skris 285296341Sdelphij /* invalid block -- cancel */ 286296341Sdelphij if (ctx->cont <= 0) 287296341Sdelphij break; 28855714Skris 289296341Sdelphij } 29055714Skris 291296341Sdelphij BIO_clear_retry_flags(b); 292296341Sdelphij BIO_copy_next_retry(b); 293296341Sdelphij return (ret); 294296341Sdelphij} 295296341Sdelphij 29668651Skrisstatic int ok_write(BIO *b, const char *in, int inl) 297296341Sdelphij{ 298296341Sdelphij int ret = 0, n, i; 299296341Sdelphij BIO_OK_CTX *ctx; 30055714Skris 301296341Sdelphij if (inl <= 0) 302296341Sdelphij return inl; 303160814Ssimon 304296341Sdelphij ctx = (BIO_OK_CTX *)b->ptr; 305296341Sdelphij ret = inl; 30655714Skris 307296341Sdelphij if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) 308296341Sdelphij return (0); 30955714Skris 310296341Sdelphij if (ctx->sigio && !sig_out(b)) 311296341Sdelphij return 0; 31255714Skris 313296341Sdelphij do { 314296341Sdelphij BIO_clear_retry_flags(b); 315296341Sdelphij n = ctx->buf_len - ctx->buf_off; 316296341Sdelphij while (ctx->blockout && n > 0) { 317296341Sdelphij i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 318296341Sdelphij if (i <= 0) { 319296341Sdelphij BIO_copy_next_retry(b); 320296341Sdelphij if (!BIO_should_retry(b)) 321296341Sdelphij ctx->cont = 0; 322296341Sdelphij return (i); 323296341Sdelphij } 324296341Sdelphij ctx->buf_off += i; 325296341Sdelphij n -= i; 326296341Sdelphij } 32755714Skris 328296341Sdelphij /* at this point all pending data has been written */ 329296341Sdelphij ctx->blockout = 0; 330296341Sdelphij if (ctx->buf_len == ctx->buf_off) { 331296341Sdelphij ctx->buf_len = OK_BLOCK_BLOCK; 332296341Sdelphij ctx->buf_off = 0; 333296341Sdelphij } 33455714Skris 335296341Sdelphij if ((in == NULL) || (inl <= 0)) 336296341Sdelphij return (0); 33755714Skris 338296341Sdelphij n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ? 339296341Sdelphij (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl; 34055714Skris 341296341Sdelphij memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])), 342296341Sdelphij (unsigned char *)in, n); 343296341Sdelphij ctx->buf_len += n; 344296341Sdelphij inl -= n; 345296341Sdelphij in += n; 34655714Skris 347296341Sdelphij if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) { 348296341Sdelphij if (!block_out(b)) { 349296341Sdelphij BIO_clear_retry_flags(b); 350296341Sdelphij return 0; 351296341Sdelphij } 352296341Sdelphij } 353296341Sdelphij } while (inl > 0); 35455714Skris 355296341Sdelphij BIO_clear_retry_flags(b); 356296341Sdelphij BIO_copy_next_retry(b); 357296341Sdelphij return (ret); 358296341Sdelphij} 359296341Sdelphij 36068651Skrisstatic long ok_ctrl(BIO *b, int cmd, long num, void *ptr) 361296341Sdelphij{ 362296341Sdelphij BIO_OK_CTX *ctx; 363296341Sdelphij EVP_MD *md; 364296341Sdelphij const EVP_MD **ppmd; 365296341Sdelphij long ret = 1; 366296341Sdelphij int i; 36755714Skris 368296341Sdelphij ctx = b->ptr; 36955714Skris 370296341Sdelphij switch (cmd) { 371296341Sdelphij case BIO_CTRL_RESET: 372296341Sdelphij ctx->buf_len = 0; 373296341Sdelphij ctx->buf_off = 0; 374296341Sdelphij ctx->buf_len_save = 0; 375296341Sdelphij ctx->buf_off_save = 0; 376296341Sdelphij ctx->cont = 1; 377296341Sdelphij ctx->finished = 0; 378296341Sdelphij ctx->blockout = 0; 379296341Sdelphij ctx->sigio = 1; 380296341Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 381296341Sdelphij break; 382296341Sdelphij case BIO_CTRL_EOF: /* More to read */ 383296341Sdelphij if (ctx->cont <= 0) 384296341Sdelphij ret = 1; 385296341Sdelphij else 386296341Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 387296341Sdelphij break; 388296341Sdelphij case BIO_CTRL_PENDING: /* More to read in buffer */ 389296341Sdelphij case BIO_CTRL_WPENDING: /* More to read in buffer */ 390296341Sdelphij ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0; 391296341Sdelphij if (ret <= 0) 392296341Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 393296341Sdelphij break; 394296341Sdelphij case BIO_CTRL_FLUSH: 395296341Sdelphij /* do a final write */ 396296341Sdelphij if (ctx->blockout == 0) 397296341Sdelphij if (!block_out(b)) 398296341Sdelphij return 0; 39955714Skris 400296341Sdelphij while (ctx->blockout) { 401296341Sdelphij i = ok_write(b, NULL, 0); 402296341Sdelphij if (i < 0) { 403296341Sdelphij ret = i; 404296341Sdelphij break; 405296341Sdelphij } 406296341Sdelphij } 40755714Skris 408296341Sdelphij ctx->finished = 1; 409296341Sdelphij ctx->buf_off = ctx->buf_len = 0; 410296341Sdelphij ctx->cont = (int)ret; 41155714Skris 412296341Sdelphij /* Finally flush the underlying BIO */ 413296341Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 414296341Sdelphij break; 415296341Sdelphij case BIO_C_DO_STATE_MACHINE: 416296341Sdelphij BIO_clear_retry_flags(b); 417296341Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 418296341Sdelphij BIO_copy_next_retry(b); 419296341Sdelphij break; 420296341Sdelphij case BIO_CTRL_INFO: 421296341Sdelphij ret = (long)ctx->cont; 422296341Sdelphij break; 423296341Sdelphij case BIO_C_SET_MD: 424296341Sdelphij md = ptr; 425296341Sdelphij if (!EVP_DigestInit_ex(&ctx->md, md, NULL)) 426296341Sdelphij return 0; 427296341Sdelphij b->init = 1; 428296341Sdelphij break; 429296341Sdelphij case BIO_C_GET_MD: 430296341Sdelphij if (b->init) { 431296341Sdelphij ppmd = ptr; 432296341Sdelphij *ppmd = ctx->md.digest; 433296341Sdelphij } else 434296341Sdelphij ret = 0; 435296341Sdelphij break; 436296341Sdelphij default: 437296341Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 438296341Sdelphij break; 439296341Sdelphij } 440296341Sdelphij return (ret); 441296341Sdelphij} 442296341Sdelphij 44368651Skrisstatic long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 444296341Sdelphij{ 445296341Sdelphij long ret = 1; 44659191Skris 447296341Sdelphij if (b->next_bio == NULL) 448296341Sdelphij return (0); 449296341Sdelphij switch (cmd) { 450296341Sdelphij default: 451296341Sdelphij ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 452296341Sdelphij break; 453296341Sdelphij } 454296341Sdelphij return (ret); 455296341Sdelphij} 45659191Skris 457160814Ssimonstatic void longswap(void *_ptr, size_t len) 458296341Sdelphij{ 459296341Sdelphij const union { 460296341Sdelphij long one; 461296341Sdelphij char little; 462296341Sdelphij } is_endian = { 463296341Sdelphij 1 464296341Sdelphij }; 46555714Skris 466296341Sdelphij if (is_endian.little) { 467296341Sdelphij size_t i; 468296341Sdelphij unsigned char *p = _ptr, c; 469160814Ssimon 470296341Sdelphij for (i = 0; i < len; i += 4) { 471296341Sdelphij c = p[0], p[0] = p[3], p[3] = c; 472296341Sdelphij c = p[1], p[1] = p[2], p[2] = c; 473296341Sdelphij } 474296341Sdelphij } 47555714Skris} 47655714Skris 477296341Sdelphijstatic int sig_out(BIO *b) 478296341Sdelphij{ 479296341Sdelphij BIO_OK_CTX *ctx; 480296341Sdelphij EVP_MD_CTX *md; 48155714Skris 482296341Sdelphij ctx = b->ptr; 483296341Sdelphij md = &ctx->md; 48455714Skris 485296341Sdelphij if (ctx->buf_len + 2 * md->digest->md_size > OK_BLOCK_SIZE) 486296341Sdelphij return 1; 48755714Skris 488296341Sdelphij if (!EVP_DigestInit_ex(md, md->digest, NULL)) 489296341Sdelphij goto berr; 490296341Sdelphij /* 491296341Sdelphij * FIXME: there's absolutely no guarantee this makes any sense at all, 492296341Sdelphij * particularly now EVP_MD_CTX has been restructured. 493296341Sdelphij */ 494296341Sdelphij if (RAND_pseudo_bytes(md->md_data, md->digest->md_size) < 0) 495296341Sdelphij goto berr; 496296341Sdelphij memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size); 497296341Sdelphij longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size); 498296341Sdelphij ctx->buf_len += md->digest->md_size; 49955714Skris 500296341Sdelphij if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN))) 501296341Sdelphij goto berr; 502296341Sdelphij if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL)) 503296341Sdelphij goto berr; 504296341Sdelphij ctx->buf_len += md->digest->md_size; 505296341Sdelphij ctx->blockout = 1; 506296341Sdelphij ctx->sigio = 0; 507296341Sdelphij return 1; 508296341Sdelphij berr: 509296341Sdelphij BIO_clear_retry_flags(b); 510296341Sdelphij return 0; 511296341Sdelphij} 51255714Skris 513296341Sdelphijstatic int sig_in(BIO *b) 514296341Sdelphij{ 515296341Sdelphij BIO_OK_CTX *ctx; 516296341Sdelphij EVP_MD_CTX *md; 517296341Sdelphij unsigned char tmp[EVP_MAX_MD_SIZE]; 518296341Sdelphij int ret = 0; 51955714Skris 520296341Sdelphij ctx = b->ptr; 521296341Sdelphij md = &ctx->md; 52255714Skris 523296341Sdelphij if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md->digest->md_size) 524296341Sdelphij return 1; 52555714Skris 526296341Sdelphij if (!EVP_DigestInit_ex(md, md->digest, NULL)) 527296341Sdelphij goto berr; 528296341Sdelphij memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size); 529296341Sdelphij longswap(md->md_data, md->digest->md_size); 530296341Sdelphij ctx->buf_off += md->digest->md_size; 53155714Skris 532296341Sdelphij if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN))) 533296341Sdelphij goto berr; 534296341Sdelphij if (!EVP_DigestFinal_ex(md, tmp, NULL)) 535296341Sdelphij goto berr; 536296341Sdelphij ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0; 537296341Sdelphij ctx->buf_off += md->digest->md_size; 538296341Sdelphij if (ret == 1) { 539296341Sdelphij ctx->sigio = 0; 540296341Sdelphij if (ctx->buf_len != ctx->buf_off) { 541296341Sdelphij memmove(ctx->buf, &(ctx->buf[ctx->buf_off]), 542296341Sdelphij ctx->buf_len - ctx->buf_off); 543296341Sdelphij } 544296341Sdelphij ctx->buf_len -= ctx->buf_off; 545296341Sdelphij ctx->buf_off = 0; 546296341Sdelphij } else { 547296341Sdelphij ctx->cont = 0; 548296341Sdelphij } 549296341Sdelphij return 1; 550296341Sdelphij berr: 551296341Sdelphij BIO_clear_retry_flags(b); 552296341Sdelphij return 0; 553296341Sdelphij} 55455714Skris 555296341Sdelphijstatic int block_out(BIO *b) 556296341Sdelphij{ 557296341Sdelphij BIO_OK_CTX *ctx; 558296341Sdelphij EVP_MD_CTX *md; 559296341Sdelphij unsigned long tl; 56055714Skris 561296341Sdelphij ctx = b->ptr; 562296341Sdelphij md = &ctx->md; 56355714Skris 564296341Sdelphij tl = ctx->buf_len - OK_BLOCK_BLOCK; 565296341Sdelphij ctx->buf[0] = (unsigned char)(tl >> 24); 566296341Sdelphij ctx->buf[1] = (unsigned char)(tl >> 16); 567296341Sdelphij ctx->buf[2] = (unsigned char)(tl >> 8); 568296341Sdelphij ctx->buf[3] = (unsigned char)(tl); 569296341Sdelphij if (!EVP_DigestUpdate(md, 570296341Sdelphij (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl)) 571296341Sdelphij goto berr; 572296341Sdelphij if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL)) 573296341Sdelphij goto berr; 574296341Sdelphij ctx->buf_len += md->digest->md_size; 575296341Sdelphij ctx->blockout = 1; 576296341Sdelphij return 1; 577296341Sdelphij berr: 578296341Sdelphij BIO_clear_retry_flags(b); 579296341Sdelphij return 0; 580296341Sdelphij} 58155714Skris 582296341Sdelphijstatic int block_in(BIO *b) 583296341Sdelphij{ 584296341Sdelphij BIO_OK_CTX *ctx; 585296341Sdelphij EVP_MD_CTX *md; 586296341Sdelphij unsigned long tl = 0; 587296341Sdelphij unsigned char tmp[EVP_MAX_MD_SIZE]; 58855714Skris 589296341Sdelphij ctx = b->ptr; 590296341Sdelphij md = &ctx->md; 59155714Skris 592296341Sdelphij assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */ 593296341Sdelphij tl = ctx->buf[0]; 594296341Sdelphij tl <<= 8; 595296341Sdelphij tl |= ctx->buf[1]; 596296341Sdelphij tl <<= 8; 597296341Sdelphij tl |= ctx->buf[2]; 598296341Sdelphij tl <<= 8; 599296341Sdelphij tl |= ctx->buf[3]; 600160814Ssimon 601296341Sdelphij if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md->digest->md_size) 602296341Sdelphij return 1; 60355714Skris 604296341Sdelphij if (!EVP_DigestUpdate(md, 605296341Sdelphij (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl)) 606296341Sdelphij goto berr; 607296341Sdelphij if (!EVP_DigestFinal_ex(md, tmp, NULL)) 608296341Sdelphij goto berr; 609296341Sdelphij if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md->digest->md_size) == 610296341Sdelphij 0) { 611296341Sdelphij /* there might be parts from next block lurking around ! */ 612296341Sdelphij ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md->digest->md_size; 613296341Sdelphij ctx->buf_len_save = ctx->buf_len; 614296341Sdelphij ctx->buf_off = OK_BLOCK_BLOCK; 615296341Sdelphij ctx->buf_len = tl + OK_BLOCK_BLOCK; 616296341Sdelphij ctx->blockout = 1; 617296341Sdelphij } else { 618296341Sdelphij ctx->cont = 0; 619296341Sdelphij } 620296341Sdelphij return 1; 621296341Sdelphij berr: 622296341Sdelphij BIO_clear_retry_flags(b); 623296341Sdelphij return 0; 624296341Sdelphij} 625