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