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. 8280304Sjkim * 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). 15280304Sjkim * 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. 22280304Sjkim * 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 :-). 37280304Sjkim * 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)" 40280304Sjkim * 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. 52280304Sjkim * 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 59280304Sjkim/*- 60280304Sjkim From: Arne Ansper <arne@cyber.ee> 6155714Skris 62280304Sjkim Why BIO_f_reliable? 6355714Skris 64280304Sjkim I wrote function which took BIO* as argument, read data from it 65280304Sjkim and processed it. Then I wanted to store the input file in 66280304Sjkim encrypted form. OK I pushed BIO_f_cipher to the BIO stack 67280304Sjkim and everything was OK. BUT if user types wrong password 68280304Sjkim BIO_f_cipher outputs only garbage and my function crashes. Yes 69280304Sjkim I can and I should fix my function, but BIO_f_cipher is 70280304Sjkim easy way to add encryption support to many existing applications 71280304Sjkim and it's hard to debug and fix them all. 7255714Skris 73280304Sjkim So I wanted another BIO which would catch the incorrect passwords and 74280304Sjkim file damages which cause garbage on BIO_f_cipher's output. 7555714Skris 76280304Sjkim The easy way is to push the BIO_f_md and save the checksum at 77280304Sjkim the end of the file. However there are several problems with this 78280304Sjkim approach: 7955714Skris 80280304Sjkim 1) you must somehow separate checksum from actual data. 81280304Sjkim 2) you need lot's of memory when reading the file, because you 82280304Sjkim must read to the end of the file and verify the checksum before 83280304Sjkim letting the application to read the data. 8455714Skris 85280304Sjkim BIO_f_reliable tries to solve both problems, so that you can 86280304Sjkim read and write arbitrary long streams using only fixed amount 87280304Sjkim of memory. 8855714Skris 89280304Sjkim BIO_f_reliable splits data stream into blocks. Each block is prefixed 90280304Sjkim with it's length and suffixed with it's digest. So you need only 91280304Sjkim several Kbytes of memory to buffer single block before verifying 92280304Sjkim it's digest. 9355714Skris 94280304Sjkim BIO_f_reliable goes further and adds several important capabilities: 9555714Skris 96280304Sjkim 1) the digest of the block is computed over the whole stream 97280304Sjkim -- so nobody can rearrange the blocks or remove or replace them. 9855714Skris 99280304Sjkim 2) to detect invalid passwords right at the start BIO_f_reliable 100280304Sjkim adds special prefix to the stream. In order to avoid known plain-text 101280304Sjkim attacks this prefix is generated as follows: 10255714Skris 103280304Sjkim *) digest is initialized with random seed instead of 104280304Sjkim standardized one. 105280304Sjkim *) same seed is written to output 106280304Sjkim *) well-known text is then hashed and the output 107280304Sjkim of the digest is also written to output. 10855714Skris 109280304Sjkim reader can now read the seed from stream, hash the same string 110280304Sjkim and then compare the digest output. 11155714Skris 112280304Sjkim Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I 113280304Sjkim initially wrote and tested this code on x86 machine and wrote the 114280304Sjkim digests out in machine-dependent order :( There are people using 115280304Sjkim this code and I cannot change this easily without making existing 116280304Sjkim data files unreadable. 117280304Sjkim 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 136280304Sjkimstatic int sig_out(BIO *b); 137280304Sjkimstatic int sig_in(BIO *b); 138280304Sjkimstatic int block_out(BIO *b); 139280304Sjkimstatic int block_in(BIO *b); 140280304Sjkim#define OK_BLOCK_SIZE (1024*4) 141280304Sjkim#define OK_BLOCK_BLOCK 4 142280304Sjkim#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 145280304Sjkimtypedef struct ok_struct { 146280304Sjkim size_t buf_len; 147280304Sjkim size_t buf_off; 148280304Sjkim size_t buf_len_save; 149280304Sjkim size_t buf_off_save; 150280304Sjkim int cont; /* <= 0 when finished */ 151280304Sjkim int finished; 152280304Sjkim EVP_MD_CTX md; 153280304Sjkim int blockout; /* output block is ready */ 154280304Sjkim int sigio; /* must process signature */ 155280304Sjkim unsigned char buf[IOBS]; 156280304Sjkim} BIO_OK_CTX; 15755714Skris 158280304Sjkimstatic BIO_METHOD methods_ok = { 159280304Sjkim BIO_TYPE_CIPHER, "reliable", 160280304Sjkim ok_write, 161280304Sjkim ok_read, 162280304Sjkim NULL, /* ok_puts, */ 163280304Sjkim NULL, /* ok_gets, */ 164280304Sjkim ok_ctrl, 165280304Sjkim ok_new, 166280304Sjkim ok_free, 167280304Sjkim ok_callback_ctrl, 168280304Sjkim}; 16955714Skris 17055714SkrisBIO_METHOD *BIO_f_reliable(void) 171280304Sjkim{ 172280304Sjkim return (&methods_ok); 173280304Sjkim} 17455714Skris 17555714Skrisstatic int ok_new(BIO *bi) 176280304Sjkim{ 177280304Sjkim BIO_OK_CTX *ctx; 17855714Skris 179280304Sjkim ctx = (BIO_OK_CTX *)OPENSSL_malloc(sizeof(BIO_OK_CTX)); 180280304Sjkim if (ctx == NULL) 181280304Sjkim return (0); 18255714Skris 183280304Sjkim ctx->buf_len = 0; 184280304Sjkim ctx->buf_off = 0; 185280304Sjkim ctx->buf_len_save = 0; 186280304Sjkim ctx->buf_off_save = 0; 187280304Sjkim ctx->cont = 1; 188280304Sjkim ctx->finished = 0; 189280304Sjkim ctx->blockout = 0; 190280304Sjkim ctx->sigio = 1; 19155714Skris 192280304Sjkim EVP_MD_CTX_init(&ctx->md); 193109998Smarkm 194280304Sjkim bi->init = 0; 195280304Sjkim bi->ptr = (char *)ctx; 196280304Sjkim bi->flags = 0; 197280304Sjkim return (1); 198280304Sjkim} 19955714Skris 20055714Skrisstatic int ok_free(BIO *a) 201280304Sjkim{ 202280304Sjkim if (a == NULL) 203280304Sjkim return (0); 204280304Sjkim EVP_MD_CTX_cleanup(&((BIO_OK_CTX *)a->ptr)->md); 205280304Sjkim OPENSSL_cleanse(a->ptr, sizeof(BIO_OK_CTX)); 206280304Sjkim OPENSSL_free(a->ptr); 207280304Sjkim a->ptr = NULL; 208280304Sjkim a->init = 0; 209280304Sjkim a->flags = 0; 210280304Sjkim return (1); 211280304Sjkim} 212280304Sjkim 21355714Skrisstatic int ok_read(BIO *b, char *out, int outl) 214280304Sjkim{ 215280304Sjkim int ret = 0, i, n; 216280304Sjkim BIO_OK_CTX *ctx; 21755714Skris 218280304Sjkim if (out == NULL) 219280304Sjkim return (0); 220280304Sjkim ctx = (BIO_OK_CTX *)b->ptr; 22155714Skris 222280304Sjkim if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) 223280304Sjkim return (0); 22455714Skris 225280304Sjkim while (outl > 0) { 22655714Skris 227280304Sjkim /* copy clean bytes to output buffer */ 228280304Sjkim if (ctx->blockout) { 229280304Sjkim i = ctx->buf_len - ctx->buf_off; 230280304Sjkim if (i > outl) 231280304Sjkim i = outl; 232280304Sjkim memcpy(out, &(ctx->buf[ctx->buf_off]), i); 233280304Sjkim ret += i; 234280304Sjkim out += i; 235280304Sjkim outl -= i; 236280304Sjkim ctx->buf_off += i; 23755714Skris 238280304Sjkim /* all clean bytes are out */ 239280304Sjkim if (ctx->buf_len == ctx->buf_off) { 240280304Sjkim ctx->buf_off = 0; 24155714Skris 242280304Sjkim /* 243280304Sjkim * copy start of the next block into proper place 244280304Sjkim */ 245280304Sjkim if (ctx->buf_len_save - ctx->buf_off_save > 0) { 246280304Sjkim ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save; 247280304Sjkim memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]), 248280304Sjkim ctx->buf_len); 249280304Sjkim } else { 250280304Sjkim ctx->buf_len = 0; 251280304Sjkim } 252280304Sjkim ctx->blockout = 0; 253280304Sjkim } 254280304Sjkim } 25555714Skris 256280304Sjkim /* output buffer full -- cancel */ 257280304Sjkim if (outl == 0) 258280304Sjkim break; 25955714Skris 260280304Sjkim /* no clean bytes in buffer -- fill it */ 261280304Sjkim n = IOBS - ctx->buf_len; 262280304Sjkim i = BIO_read(b->next_bio, &(ctx->buf[ctx->buf_len]), n); 26355714Skris 264280304Sjkim if (i <= 0) 265280304Sjkim break; /* nothing new */ 26655714Skris 267280304Sjkim ctx->buf_len += i; 26855714Skris 269280304Sjkim /* no signature yet -- check if we got one */ 270280304Sjkim if (ctx->sigio == 1) { 271280304Sjkim if (!sig_in(b)) { 272280304Sjkim BIO_clear_retry_flags(b); 273280304Sjkim return 0; 274280304Sjkim } 275280304Sjkim } 27655714Skris 277280304Sjkim /* signature ok -- check if we got block */ 278280304Sjkim if (ctx->sigio == 0) { 279280304Sjkim if (!block_in(b)) { 280280304Sjkim BIO_clear_retry_flags(b); 281280304Sjkim return 0; 282280304Sjkim } 283280304Sjkim } 28455714Skris 285280304Sjkim /* invalid block -- cancel */ 286280304Sjkim if (ctx->cont <= 0) 287280304Sjkim break; 28855714Skris 289280304Sjkim } 29055714Skris 291280304Sjkim BIO_clear_retry_flags(b); 292280304Sjkim BIO_copy_next_retry(b); 293280304Sjkim return (ret); 294280304Sjkim} 295280304Sjkim 29668651Skrisstatic int ok_write(BIO *b, const char *in, int inl) 297280304Sjkim{ 298280304Sjkim int ret = 0, n, i; 299280304Sjkim BIO_OK_CTX *ctx; 30055714Skris 301280304Sjkim if (inl <= 0) 302280304Sjkim return inl; 303160814Ssimon 304280304Sjkim ctx = (BIO_OK_CTX *)b->ptr; 305280304Sjkim ret = inl; 30655714Skris 307280304Sjkim if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0)) 308280304Sjkim return (0); 30955714Skris 310280304Sjkim if (ctx->sigio && !sig_out(b)) 311280304Sjkim return 0; 31255714Skris 313280304Sjkim do { 314280304Sjkim BIO_clear_retry_flags(b); 315280304Sjkim n = ctx->buf_len - ctx->buf_off; 316280304Sjkim while (ctx->blockout && n > 0) { 317280304Sjkim i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); 318280304Sjkim if (i <= 0) { 319280304Sjkim BIO_copy_next_retry(b); 320280304Sjkim if (!BIO_should_retry(b)) 321280304Sjkim ctx->cont = 0; 322280304Sjkim return (i); 323280304Sjkim } 324280304Sjkim ctx->buf_off += i; 325280304Sjkim n -= i; 326280304Sjkim } 32755714Skris 328280304Sjkim /* at this point all pending data has been written */ 329280304Sjkim ctx->blockout = 0; 330280304Sjkim if (ctx->buf_len == ctx->buf_off) { 331280304Sjkim ctx->buf_len = OK_BLOCK_BLOCK; 332280304Sjkim ctx->buf_off = 0; 333280304Sjkim } 33455714Skris 335280304Sjkim if ((in == NULL) || (inl <= 0)) 336280304Sjkim return (0); 33755714Skris 338280304Sjkim n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ? 339280304Sjkim (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl; 34055714Skris 341280304Sjkim memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])), 342280304Sjkim (unsigned char *)in, n); 343280304Sjkim ctx->buf_len += n; 344280304Sjkim inl -= n; 345280304Sjkim in += n; 34655714Skris 347280304Sjkim if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) { 348280304Sjkim if (!block_out(b)) { 349280304Sjkim BIO_clear_retry_flags(b); 350280304Sjkim return 0; 351280304Sjkim } 352280304Sjkim } 353280304Sjkim } while (inl > 0); 35455714Skris 355280304Sjkim BIO_clear_retry_flags(b); 356280304Sjkim BIO_copy_next_retry(b); 357280304Sjkim return (ret); 358280304Sjkim} 359280304Sjkim 36068651Skrisstatic long ok_ctrl(BIO *b, int cmd, long num, void *ptr) 361280304Sjkim{ 362280304Sjkim BIO_OK_CTX *ctx; 363280304Sjkim EVP_MD *md; 364280304Sjkim const EVP_MD **ppmd; 365280304Sjkim long ret = 1; 366280304Sjkim int i; 36755714Skris 368280304Sjkim ctx = b->ptr; 36955714Skris 370280304Sjkim switch (cmd) { 371280304Sjkim case BIO_CTRL_RESET: 372280304Sjkim ctx->buf_len = 0; 373280304Sjkim ctx->buf_off = 0; 374280304Sjkim ctx->buf_len_save = 0; 375280304Sjkim ctx->buf_off_save = 0; 376280304Sjkim ctx->cont = 1; 377280304Sjkim ctx->finished = 0; 378280304Sjkim ctx->blockout = 0; 379280304Sjkim ctx->sigio = 1; 380280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 381280304Sjkim break; 382280304Sjkim case BIO_CTRL_EOF: /* More to read */ 383280304Sjkim if (ctx->cont <= 0) 384280304Sjkim ret = 1; 385280304Sjkim else 386280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 387280304Sjkim break; 388280304Sjkim case BIO_CTRL_PENDING: /* More to read in buffer */ 389280304Sjkim case BIO_CTRL_WPENDING: /* More to read in buffer */ 390280304Sjkim ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0; 391280304Sjkim if (ret <= 0) 392280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 393280304Sjkim break; 394280304Sjkim case BIO_CTRL_FLUSH: 395280304Sjkim /* do a final write */ 396280304Sjkim if (ctx->blockout == 0) 397280304Sjkim if (!block_out(b)) 398280304Sjkim return 0; 39955714Skris 400280304Sjkim while (ctx->blockout) { 401280304Sjkim i = ok_write(b, NULL, 0); 402280304Sjkim if (i < 0) { 403280304Sjkim ret = i; 404280304Sjkim break; 405280304Sjkim } 406280304Sjkim } 40755714Skris 408280304Sjkim ctx->finished = 1; 409280304Sjkim ctx->buf_off = ctx->buf_len = 0; 410280304Sjkim ctx->cont = (int)ret; 41155714Skris 412280304Sjkim /* Finally flush the underlying BIO */ 413280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 414280304Sjkim break; 415280304Sjkim case BIO_C_DO_STATE_MACHINE: 416280304Sjkim BIO_clear_retry_flags(b); 417280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 418280304Sjkim BIO_copy_next_retry(b); 419280304Sjkim break; 420280304Sjkim case BIO_CTRL_INFO: 421280304Sjkim ret = (long)ctx->cont; 422280304Sjkim break; 423280304Sjkim case BIO_C_SET_MD: 424280304Sjkim md = ptr; 425280304Sjkim if (!EVP_DigestInit_ex(&ctx->md, md, NULL)) 426280304Sjkim return 0; 427280304Sjkim b->init = 1; 428280304Sjkim break; 429280304Sjkim case BIO_C_GET_MD: 430280304Sjkim if (b->init) { 431280304Sjkim ppmd = ptr; 432280304Sjkim *ppmd = ctx->md.digest; 433280304Sjkim } else 434280304Sjkim ret = 0; 435280304Sjkim break; 436280304Sjkim default: 437280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 438280304Sjkim break; 439280304Sjkim } 440280304Sjkim return (ret); 441280304Sjkim} 442280304Sjkim 44368651Skrisstatic long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 444280304Sjkim{ 445280304Sjkim long ret = 1; 44659191Skris 447280304Sjkim if (b->next_bio == NULL) 448280304Sjkim return (0); 449280304Sjkim switch (cmd) { 450280304Sjkim default: 451280304Sjkim ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 452280304Sjkim break; 453280304Sjkim } 454280304Sjkim return (ret); 455280304Sjkim} 45659191Skris 457160814Ssimonstatic void longswap(void *_ptr, size_t len) 458280304Sjkim{ 459280304Sjkim const union { 460280304Sjkim long one; 461280304Sjkim char little; 462280304Sjkim } is_endian = { 463280304Sjkim 1 464280304Sjkim }; 46555714Skris 466280304Sjkim if (is_endian.little) { 467280304Sjkim size_t i; 468280304Sjkim unsigned char *p = _ptr, c; 469160814Ssimon 470280304Sjkim for (i = 0; i < len; i += 4) { 471280304Sjkim c = p[0], p[0] = p[3], p[3] = c; 472280304Sjkim c = p[1], p[1] = p[2], p[2] = c; 473280304Sjkim } 474280304Sjkim } 47555714Skris} 47655714Skris 477280304Sjkimstatic int sig_out(BIO *b) 478280304Sjkim{ 479280304Sjkim BIO_OK_CTX *ctx; 480280304Sjkim EVP_MD_CTX *md; 48155714Skris 482280304Sjkim ctx = b->ptr; 483280304Sjkim md = &ctx->md; 48455714Skris 485280304Sjkim if (ctx->buf_len + 2 * md->digest->md_size > OK_BLOCK_SIZE) 486280304Sjkim return 1; 48755714Skris 488280304Sjkim if (!EVP_DigestInit_ex(md, md->digest, NULL)) 489280304Sjkim goto berr; 490280304Sjkim /* 491280304Sjkim * FIXME: there's absolutely no guarantee this makes any sense at all, 492280304Sjkim * particularly now EVP_MD_CTX has been restructured. 493280304Sjkim */ 494306196Sjkim if (RAND_bytes(md->md_data, md->digest->md_size) <= 0) 495284285Sjkim goto berr; 496280304Sjkim memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size); 497280304Sjkim longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size); 498280304Sjkim ctx->buf_len += md->digest->md_size; 49955714Skris 500280304Sjkim if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN))) 501280304Sjkim goto berr; 502280304Sjkim if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL)) 503280304Sjkim goto berr; 504280304Sjkim ctx->buf_len += md->digest->md_size; 505280304Sjkim ctx->blockout = 1; 506280304Sjkim ctx->sigio = 0; 507280304Sjkim return 1; 508280304Sjkim berr: 509280304Sjkim BIO_clear_retry_flags(b); 510280304Sjkim return 0; 511280304Sjkim} 51255714Skris 513280304Sjkimstatic int sig_in(BIO *b) 514280304Sjkim{ 515280304Sjkim BIO_OK_CTX *ctx; 516280304Sjkim EVP_MD_CTX *md; 517280304Sjkim unsigned char tmp[EVP_MAX_MD_SIZE]; 518280304Sjkim int ret = 0; 51955714Skris 520280304Sjkim ctx = b->ptr; 521280304Sjkim md = &ctx->md; 52255714Skris 523280304Sjkim if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md->digest->md_size) 524280304Sjkim return 1; 52555714Skris 526280304Sjkim if (!EVP_DigestInit_ex(md, md->digest, NULL)) 527280304Sjkim goto berr; 528280304Sjkim memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size); 529280304Sjkim longswap(md->md_data, md->digest->md_size); 530280304Sjkim ctx->buf_off += md->digest->md_size; 53155714Skris 532280304Sjkim if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN))) 533280304Sjkim goto berr; 534280304Sjkim if (!EVP_DigestFinal_ex(md, tmp, NULL)) 535280304Sjkim goto berr; 536280304Sjkim ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0; 537280304Sjkim ctx->buf_off += md->digest->md_size; 538280304Sjkim if (ret == 1) { 539280304Sjkim ctx->sigio = 0; 540280304Sjkim if (ctx->buf_len != ctx->buf_off) { 541280304Sjkim memmove(ctx->buf, &(ctx->buf[ctx->buf_off]), 542280304Sjkim ctx->buf_len - ctx->buf_off); 543280304Sjkim } 544280304Sjkim ctx->buf_len -= ctx->buf_off; 545280304Sjkim ctx->buf_off = 0; 546280304Sjkim } else { 547280304Sjkim ctx->cont = 0; 548280304Sjkim } 549280304Sjkim return 1; 550280304Sjkim berr: 551280304Sjkim BIO_clear_retry_flags(b); 552280304Sjkim return 0; 553280304Sjkim} 55455714Skris 555280304Sjkimstatic int block_out(BIO *b) 556280304Sjkim{ 557280304Sjkim BIO_OK_CTX *ctx; 558280304Sjkim EVP_MD_CTX *md; 559280304Sjkim unsigned long tl; 56055714Skris 561280304Sjkim ctx = b->ptr; 562280304Sjkim md = &ctx->md; 56355714Skris 564280304Sjkim tl = ctx->buf_len - OK_BLOCK_BLOCK; 565280304Sjkim ctx->buf[0] = (unsigned char)(tl >> 24); 566280304Sjkim ctx->buf[1] = (unsigned char)(tl >> 16); 567280304Sjkim ctx->buf[2] = (unsigned char)(tl >> 8); 568280304Sjkim ctx->buf[3] = (unsigned char)(tl); 569280304Sjkim if (!EVP_DigestUpdate(md, 570280304Sjkim (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl)) 571280304Sjkim goto berr; 572280304Sjkim if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL)) 573280304Sjkim goto berr; 574280304Sjkim ctx->buf_len += md->digest->md_size; 575280304Sjkim ctx->blockout = 1; 576280304Sjkim return 1; 577280304Sjkim berr: 578280304Sjkim BIO_clear_retry_flags(b); 579280304Sjkim return 0; 580280304Sjkim} 58155714Skris 582280304Sjkimstatic int block_in(BIO *b) 583280304Sjkim{ 584280304Sjkim BIO_OK_CTX *ctx; 585280304Sjkim EVP_MD_CTX *md; 586280304Sjkim unsigned long tl = 0; 587280304Sjkim unsigned char tmp[EVP_MAX_MD_SIZE]; 58855714Skris 589280304Sjkim ctx = b->ptr; 590280304Sjkim md = &ctx->md; 59155714Skris 592280304Sjkim assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */ 593280304Sjkim tl = ctx->buf[0]; 594280304Sjkim tl <<= 8; 595280304Sjkim tl |= ctx->buf[1]; 596280304Sjkim tl <<= 8; 597280304Sjkim tl |= ctx->buf[2]; 598280304Sjkim tl <<= 8; 599280304Sjkim tl |= ctx->buf[3]; 600160814Ssimon 601280304Sjkim if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md->digest->md_size) 602280304Sjkim return 1; 60355714Skris 604280304Sjkim if (!EVP_DigestUpdate(md, 605280304Sjkim (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl)) 606280304Sjkim goto berr; 607280304Sjkim if (!EVP_DigestFinal_ex(md, tmp, NULL)) 608280304Sjkim goto berr; 609280304Sjkim if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md->digest->md_size) == 610280304Sjkim 0) { 611280304Sjkim /* there might be parts from next block lurking around ! */ 612280304Sjkim ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md->digest->md_size; 613280304Sjkim ctx->buf_len_save = ctx->buf_len; 614280304Sjkim ctx->buf_off = OK_BLOCK_BLOCK; 615280304Sjkim ctx->buf_len = tl + OK_BLOCK_BLOCK; 616280304Sjkim ctx->blockout = 1; 617280304Sjkim } else { 618280304Sjkim ctx->cont = 0; 619280304Sjkim } 620280304Sjkim return 1; 621280304Sjkim berr: 622280304Sjkim BIO_clear_retry_flags(b); 623280304Sjkim return 0; 624280304Sjkim} 625