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