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