1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*-
11e1051a39Sopenharmony_ci        From: Arne Ansper
12e1051a39Sopenharmony_ci
13e1051a39Sopenharmony_ci        Why BIO_f_reliable?
14e1051a39Sopenharmony_ci
15e1051a39Sopenharmony_ci        I wrote function which took BIO* as argument, read data from it
16e1051a39Sopenharmony_ci        and processed it. Then I wanted to store the input file in
17e1051a39Sopenharmony_ci        encrypted form. OK I pushed BIO_f_cipher to the BIO stack
18e1051a39Sopenharmony_ci        and everything was OK. BUT if user types wrong password
19e1051a39Sopenharmony_ci        BIO_f_cipher outputs only garbage and my function crashes. Yes
20e1051a39Sopenharmony_ci        I can and I should fix my function, but BIO_f_cipher is
21e1051a39Sopenharmony_ci        easy way to add encryption support to many existing applications
22e1051a39Sopenharmony_ci        and it's hard to debug and fix them all.
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ci        So I wanted another BIO which would catch the incorrect passwords and
25e1051a39Sopenharmony_ci        file damages which cause garbage on BIO_f_cipher's output.
26e1051a39Sopenharmony_ci
27e1051a39Sopenharmony_ci        The easy way is to push the BIO_f_md and save the checksum at
28e1051a39Sopenharmony_ci        the end of the file. However there are several problems with this
29e1051a39Sopenharmony_ci        approach:
30e1051a39Sopenharmony_ci
31e1051a39Sopenharmony_ci        1) you must somehow separate checksum from actual data.
32e1051a39Sopenharmony_ci        2) you need lot's of memory when reading the file, because you
33e1051a39Sopenharmony_ci        must read to the end of the file and verify the checksum before
34e1051a39Sopenharmony_ci        letting the application to read the data.
35e1051a39Sopenharmony_ci
36e1051a39Sopenharmony_ci        BIO_f_reliable tries to solve both problems, so that you can
37e1051a39Sopenharmony_ci        read and write arbitrary long streams using only fixed amount
38e1051a39Sopenharmony_ci        of memory.
39e1051a39Sopenharmony_ci
40e1051a39Sopenharmony_ci        BIO_f_reliable splits data stream into blocks. Each block is prefixed
41e1051a39Sopenharmony_ci        with its length and suffixed with its digest. So you need only
42e1051a39Sopenharmony_ci        several Kbytes of memory to buffer single block before verifying
43e1051a39Sopenharmony_ci        its digest.
44e1051a39Sopenharmony_ci
45e1051a39Sopenharmony_ci        BIO_f_reliable goes further and adds several important capabilities:
46e1051a39Sopenharmony_ci
47e1051a39Sopenharmony_ci        1) the digest of the block is computed over the whole stream
48e1051a39Sopenharmony_ci        -- so nobody can rearrange the blocks or remove or replace them.
49e1051a39Sopenharmony_ci
50e1051a39Sopenharmony_ci        2) to detect invalid passwords right at the start BIO_f_reliable
51e1051a39Sopenharmony_ci        adds special prefix to the stream. In order to avoid known plain-text
52e1051a39Sopenharmony_ci        attacks this prefix is generated as follows:
53e1051a39Sopenharmony_ci
54e1051a39Sopenharmony_ci                *) digest is initialized with random seed instead of
55e1051a39Sopenharmony_ci                standardized one.
56e1051a39Sopenharmony_ci                *) same seed is written to output
57e1051a39Sopenharmony_ci                *) well-known text is then hashed and the output
58e1051a39Sopenharmony_ci                of the digest is also written to output.
59e1051a39Sopenharmony_ci
60e1051a39Sopenharmony_ci        reader can now read the seed from stream, hash the same string
61e1051a39Sopenharmony_ci        and then compare the digest output.
62e1051a39Sopenharmony_ci
63e1051a39Sopenharmony_ci        Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I
64e1051a39Sopenharmony_ci        initially wrote and tested this code on x86 machine and wrote the
65e1051a39Sopenharmony_ci        digests out in machine-dependent order :( There are people using
66e1051a39Sopenharmony_ci        this code and I cannot change this easily without making existing
67e1051a39Sopenharmony_ci        data files unreadable.
68e1051a39Sopenharmony_ci
69e1051a39Sopenharmony_ci*/
70e1051a39Sopenharmony_ci
71e1051a39Sopenharmony_ci#include <stdio.h>
72e1051a39Sopenharmony_ci#include <errno.h>
73e1051a39Sopenharmony_ci#include <assert.h>
74e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
75e1051a39Sopenharmony_ci#include <openssl/buffer.h>
76e1051a39Sopenharmony_ci#include "internal/bio.h"
77e1051a39Sopenharmony_ci#include <openssl/evp.h>
78e1051a39Sopenharmony_ci#include <openssl/rand.h>
79e1051a39Sopenharmony_ci#include "internal/endian.h"
80e1051a39Sopenharmony_ci#include "crypto/evp.h"
81e1051a39Sopenharmony_ci
82e1051a39Sopenharmony_cistatic int ok_write(BIO *h, const char *buf, int num);
83e1051a39Sopenharmony_cistatic int ok_read(BIO *h, char *buf, int size);
84e1051a39Sopenharmony_cistatic long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
85e1051a39Sopenharmony_cistatic int ok_new(BIO *h);
86e1051a39Sopenharmony_cistatic int ok_free(BIO *data);
87e1051a39Sopenharmony_cistatic long ok_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
88e1051a39Sopenharmony_ci
89e1051a39Sopenharmony_cistatic __owur int sig_out(BIO *b);
90e1051a39Sopenharmony_cistatic __owur int sig_in(BIO *b);
91e1051a39Sopenharmony_cistatic __owur int block_out(BIO *b);
92e1051a39Sopenharmony_cistatic __owur int block_in(BIO *b);
93e1051a39Sopenharmony_ci#define OK_BLOCK_SIZE   (1024*4)
94e1051a39Sopenharmony_ci#define OK_BLOCK_BLOCK  4
95e1051a39Sopenharmony_ci#define IOBS            (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE)
96e1051a39Sopenharmony_ci#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_citypedef struct ok_struct {
99e1051a39Sopenharmony_ci    size_t buf_len;
100e1051a39Sopenharmony_ci    size_t buf_off;
101e1051a39Sopenharmony_ci    size_t buf_len_save;
102e1051a39Sopenharmony_ci    size_t buf_off_save;
103e1051a39Sopenharmony_ci    int cont;                   /* <= 0 when finished */
104e1051a39Sopenharmony_ci    int finished;
105e1051a39Sopenharmony_ci    EVP_MD_CTX *md;
106e1051a39Sopenharmony_ci    int blockout;               /* output block is ready */
107e1051a39Sopenharmony_ci    int sigio;                  /* must process signature */
108e1051a39Sopenharmony_ci    unsigned char buf[IOBS];
109e1051a39Sopenharmony_ci} BIO_OK_CTX;
110e1051a39Sopenharmony_ci
111e1051a39Sopenharmony_cistatic const BIO_METHOD methods_ok = {
112e1051a39Sopenharmony_ci    BIO_TYPE_CIPHER,
113e1051a39Sopenharmony_ci    "reliable",
114e1051a39Sopenharmony_ci    bwrite_conv,
115e1051a39Sopenharmony_ci    ok_write,
116e1051a39Sopenharmony_ci    bread_conv,
117e1051a39Sopenharmony_ci    ok_read,
118e1051a39Sopenharmony_ci    NULL,                       /* ok_puts, */
119e1051a39Sopenharmony_ci    NULL,                       /* ok_gets, */
120e1051a39Sopenharmony_ci    ok_ctrl,
121e1051a39Sopenharmony_ci    ok_new,
122e1051a39Sopenharmony_ci    ok_free,
123e1051a39Sopenharmony_ci    ok_callback_ctrl,
124e1051a39Sopenharmony_ci};
125e1051a39Sopenharmony_ci
126e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_f_reliable(void)
127e1051a39Sopenharmony_ci{
128e1051a39Sopenharmony_ci    return &methods_ok;
129e1051a39Sopenharmony_ci}
130e1051a39Sopenharmony_ci
131e1051a39Sopenharmony_cistatic int ok_new(BIO *bi)
132e1051a39Sopenharmony_ci{
133e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
134e1051a39Sopenharmony_ci
135e1051a39Sopenharmony_ci    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) {
136e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
137e1051a39Sopenharmony_ci        return 0;
138e1051a39Sopenharmony_ci    }
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci    ctx->cont = 1;
141e1051a39Sopenharmony_ci    ctx->sigio = 1;
142e1051a39Sopenharmony_ci    ctx->md = EVP_MD_CTX_new();
143e1051a39Sopenharmony_ci    if (ctx->md == NULL) {
144e1051a39Sopenharmony_ci        OPENSSL_free(ctx);
145e1051a39Sopenharmony_ci        return 0;
146e1051a39Sopenharmony_ci    }
147e1051a39Sopenharmony_ci    BIO_set_init(bi, 0);
148e1051a39Sopenharmony_ci    BIO_set_data(bi, ctx);
149e1051a39Sopenharmony_ci
150e1051a39Sopenharmony_ci    return 1;
151e1051a39Sopenharmony_ci}
152e1051a39Sopenharmony_ci
153e1051a39Sopenharmony_cistatic int ok_free(BIO *a)
154e1051a39Sopenharmony_ci{
155e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
156e1051a39Sopenharmony_ci
157e1051a39Sopenharmony_ci    if (a == NULL)
158e1051a39Sopenharmony_ci        return 0;
159e1051a39Sopenharmony_ci
160e1051a39Sopenharmony_ci    ctx = BIO_get_data(a);
161e1051a39Sopenharmony_ci
162e1051a39Sopenharmony_ci    EVP_MD_CTX_free(ctx->md);
163e1051a39Sopenharmony_ci    OPENSSL_clear_free(ctx, sizeof(BIO_OK_CTX));
164e1051a39Sopenharmony_ci    BIO_set_data(a, NULL);
165e1051a39Sopenharmony_ci    BIO_set_init(a, 0);
166e1051a39Sopenharmony_ci
167e1051a39Sopenharmony_ci    return 1;
168e1051a39Sopenharmony_ci}
169e1051a39Sopenharmony_ci
170e1051a39Sopenharmony_cistatic int ok_read(BIO *b, char *out, int outl)
171e1051a39Sopenharmony_ci{
172e1051a39Sopenharmony_ci    int ret = 0, i, n;
173e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
174e1051a39Sopenharmony_ci    BIO *next;
175e1051a39Sopenharmony_ci
176e1051a39Sopenharmony_ci    if (out == NULL)
177e1051a39Sopenharmony_ci        return 0;
178e1051a39Sopenharmony_ci
179e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
180e1051a39Sopenharmony_ci    next = BIO_next(b);
181e1051a39Sopenharmony_ci
182e1051a39Sopenharmony_ci    if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
183e1051a39Sopenharmony_ci        return 0;
184e1051a39Sopenharmony_ci
185e1051a39Sopenharmony_ci    while (outl > 0) {
186e1051a39Sopenharmony_ci
187e1051a39Sopenharmony_ci        /* copy clean bytes to output buffer */
188e1051a39Sopenharmony_ci        if (ctx->blockout) {
189e1051a39Sopenharmony_ci            i = ctx->buf_len - ctx->buf_off;
190e1051a39Sopenharmony_ci            if (i > outl)
191e1051a39Sopenharmony_ci                i = outl;
192e1051a39Sopenharmony_ci            memcpy(out, &(ctx->buf[ctx->buf_off]), i);
193e1051a39Sopenharmony_ci            ret += i;
194e1051a39Sopenharmony_ci            out += i;
195e1051a39Sopenharmony_ci            outl -= i;
196e1051a39Sopenharmony_ci            ctx->buf_off += i;
197e1051a39Sopenharmony_ci
198e1051a39Sopenharmony_ci            /* all clean bytes are out */
199e1051a39Sopenharmony_ci            if (ctx->buf_len == ctx->buf_off) {
200e1051a39Sopenharmony_ci                ctx->buf_off = 0;
201e1051a39Sopenharmony_ci
202e1051a39Sopenharmony_ci                /*
203e1051a39Sopenharmony_ci                 * copy start of the next block into proper place
204e1051a39Sopenharmony_ci                 */
205e1051a39Sopenharmony_ci                if (ctx->buf_len_save > ctx->buf_off_save) {
206e1051a39Sopenharmony_ci                    ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save;
207e1051a39Sopenharmony_ci                    memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
208e1051a39Sopenharmony_ci                            ctx->buf_len);
209e1051a39Sopenharmony_ci                } else {
210e1051a39Sopenharmony_ci                    ctx->buf_len = 0;
211e1051a39Sopenharmony_ci                }
212e1051a39Sopenharmony_ci                ctx->blockout = 0;
213e1051a39Sopenharmony_ci            }
214e1051a39Sopenharmony_ci        }
215e1051a39Sopenharmony_ci
216e1051a39Sopenharmony_ci        /* output buffer full -- cancel */
217e1051a39Sopenharmony_ci        if (outl == 0)
218e1051a39Sopenharmony_ci            break;
219e1051a39Sopenharmony_ci
220e1051a39Sopenharmony_ci        /* no clean bytes in buffer -- fill it */
221e1051a39Sopenharmony_ci        n = IOBS - ctx->buf_len;
222e1051a39Sopenharmony_ci        i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n);
223e1051a39Sopenharmony_ci
224e1051a39Sopenharmony_ci        if (i <= 0)
225e1051a39Sopenharmony_ci            break;              /* nothing new */
226e1051a39Sopenharmony_ci
227e1051a39Sopenharmony_ci        ctx->buf_len += i;
228e1051a39Sopenharmony_ci
229e1051a39Sopenharmony_ci        /* no signature yet -- check if we got one */
230e1051a39Sopenharmony_ci        if (ctx->sigio == 1) {
231e1051a39Sopenharmony_ci            if (!sig_in(b)) {
232e1051a39Sopenharmony_ci                BIO_clear_retry_flags(b);
233e1051a39Sopenharmony_ci                return 0;
234e1051a39Sopenharmony_ci            }
235e1051a39Sopenharmony_ci        }
236e1051a39Sopenharmony_ci
237e1051a39Sopenharmony_ci        /* signature ok -- check if we got block */
238e1051a39Sopenharmony_ci        if (ctx->sigio == 0) {
239e1051a39Sopenharmony_ci            if (!block_in(b)) {
240e1051a39Sopenharmony_ci                BIO_clear_retry_flags(b);
241e1051a39Sopenharmony_ci                return 0;
242e1051a39Sopenharmony_ci            }
243e1051a39Sopenharmony_ci        }
244e1051a39Sopenharmony_ci
245e1051a39Sopenharmony_ci        /* invalid block -- cancel */
246e1051a39Sopenharmony_ci        if (ctx->cont <= 0)
247e1051a39Sopenharmony_ci            break;
248e1051a39Sopenharmony_ci
249e1051a39Sopenharmony_ci    }
250e1051a39Sopenharmony_ci
251e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
252e1051a39Sopenharmony_ci    BIO_copy_next_retry(b);
253e1051a39Sopenharmony_ci    return ret;
254e1051a39Sopenharmony_ci}
255e1051a39Sopenharmony_ci
256e1051a39Sopenharmony_cistatic int ok_write(BIO *b, const char *in, int inl)
257e1051a39Sopenharmony_ci{
258e1051a39Sopenharmony_ci    int ret = 0, n, i;
259e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
260e1051a39Sopenharmony_ci    BIO *next;
261e1051a39Sopenharmony_ci
262e1051a39Sopenharmony_ci    if (inl <= 0)
263e1051a39Sopenharmony_ci        return inl;
264e1051a39Sopenharmony_ci
265e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
266e1051a39Sopenharmony_ci    next = BIO_next(b);
267e1051a39Sopenharmony_ci    ret = inl;
268e1051a39Sopenharmony_ci
269e1051a39Sopenharmony_ci    if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
270e1051a39Sopenharmony_ci        return 0;
271e1051a39Sopenharmony_ci
272e1051a39Sopenharmony_ci    if (ctx->sigio && !sig_out(b))
273e1051a39Sopenharmony_ci        return 0;
274e1051a39Sopenharmony_ci
275e1051a39Sopenharmony_ci    do {
276e1051a39Sopenharmony_ci        BIO_clear_retry_flags(b);
277e1051a39Sopenharmony_ci        n = ctx->buf_len - ctx->buf_off;
278e1051a39Sopenharmony_ci        while (ctx->blockout && n > 0) {
279e1051a39Sopenharmony_ci            i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
280e1051a39Sopenharmony_ci            if (i <= 0) {
281e1051a39Sopenharmony_ci                BIO_copy_next_retry(b);
282e1051a39Sopenharmony_ci                if (!BIO_should_retry(b))
283e1051a39Sopenharmony_ci                    ctx->cont = 0;
284e1051a39Sopenharmony_ci                return i;
285e1051a39Sopenharmony_ci            }
286e1051a39Sopenharmony_ci            ctx->buf_off += i;
287e1051a39Sopenharmony_ci            n -= i;
288e1051a39Sopenharmony_ci        }
289e1051a39Sopenharmony_ci
290e1051a39Sopenharmony_ci        /* at this point all pending data has been written */
291e1051a39Sopenharmony_ci        ctx->blockout = 0;
292e1051a39Sopenharmony_ci        if (ctx->buf_len == ctx->buf_off) {
293e1051a39Sopenharmony_ci            ctx->buf_len = OK_BLOCK_BLOCK;
294e1051a39Sopenharmony_ci            ctx->buf_off = 0;
295e1051a39Sopenharmony_ci        }
296e1051a39Sopenharmony_ci
297e1051a39Sopenharmony_ci        if ((in == NULL) || (inl <= 0))
298e1051a39Sopenharmony_ci            return 0;
299e1051a39Sopenharmony_ci
300e1051a39Sopenharmony_ci        n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ?
301e1051a39Sopenharmony_ci            (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl;
302e1051a39Sopenharmony_ci
303e1051a39Sopenharmony_ci        memcpy(&ctx->buf[ctx->buf_len], in, n);
304e1051a39Sopenharmony_ci        ctx->buf_len += n;
305e1051a39Sopenharmony_ci        inl -= n;
306e1051a39Sopenharmony_ci        in += n;
307e1051a39Sopenharmony_ci
308e1051a39Sopenharmony_ci        if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) {
309e1051a39Sopenharmony_ci            if (!block_out(b)) {
310e1051a39Sopenharmony_ci                BIO_clear_retry_flags(b);
311e1051a39Sopenharmony_ci                return 0;
312e1051a39Sopenharmony_ci            }
313e1051a39Sopenharmony_ci        }
314e1051a39Sopenharmony_ci    } while (inl > 0);
315e1051a39Sopenharmony_ci
316e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
317e1051a39Sopenharmony_ci    BIO_copy_next_retry(b);
318e1051a39Sopenharmony_ci    return ret;
319e1051a39Sopenharmony_ci}
320e1051a39Sopenharmony_ci
321e1051a39Sopenharmony_cistatic long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
322e1051a39Sopenharmony_ci{
323e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
324e1051a39Sopenharmony_ci    EVP_MD *md;
325e1051a39Sopenharmony_ci    const EVP_MD **ppmd;
326e1051a39Sopenharmony_ci    long ret = 1;
327e1051a39Sopenharmony_ci    int i;
328e1051a39Sopenharmony_ci    BIO *next;
329e1051a39Sopenharmony_ci
330e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
331e1051a39Sopenharmony_ci    next = BIO_next(b);
332e1051a39Sopenharmony_ci
333e1051a39Sopenharmony_ci    switch (cmd) {
334e1051a39Sopenharmony_ci    case BIO_CTRL_RESET:
335e1051a39Sopenharmony_ci        ctx->buf_len = 0;
336e1051a39Sopenharmony_ci        ctx->buf_off = 0;
337e1051a39Sopenharmony_ci        ctx->buf_len_save = 0;
338e1051a39Sopenharmony_ci        ctx->buf_off_save = 0;
339e1051a39Sopenharmony_ci        ctx->cont = 1;
340e1051a39Sopenharmony_ci        ctx->finished = 0;
341e1051a39Sopenharmony_ci        ctx->blockout = 0;
342e1051a39Sopenharmony_ci        ctx->sigio = 1;
343e1051a39Sopenharmony_ci        ret = BIO_ctrl(next, cmd, num, ptr);
344e1051a39Sopenharmony_ci        break;
345e1051a39Sopenharmony_ci    case BIO_CTRL_EOF:         /* More to read */
346e1051a39Sopenharmony_ci        if (ctx->cont <= 0)
347e1051a39Sopenharmony_ci            ret = 1;
348e1051a39Sopenharmony_ci        else
349e1051a39Sopenharmony_ci            ret = BIO_ctrl(next, cmd, num, ptr);
350e1051a39Sopenharmony_ci        break;
351e1051a39Sopenharmony_ci    case BIO_CTRL_PENDING:     /* More to read in buffer */
352e1051a39Sopenharmony_ci    case BIO_CTRL_WPENDING:    /* More to read in buffer */
353e1051a39Sopenharmony_ci        ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0;
354e1051a39Sopenharmony_ci        if (ret <= 0)
355e1051a39Sopenharmony_ci            ret = BIO_ctrl(next, cmd, num, ptr);
356e1051a39Sopenharmony_ci        break;
357e1051a39Sopenharmony_ci    case BIO_CTRL_FLUSH:
358e1051a39Sopenharmony_ci        /* do a final write */
359e1051a39Sopenharmony_ci        if (ctx->blockout == 0)
360e1051a39Sopenharmony_ci            if (!block_out(b))
361e1051a39Sopenharmony_ci                return 0;
362e1051a39Sopenharmony_ci
363e1051a39Sopenharmony_ci        while (ctx->blockout) {
364e1051a39Sopenharmony_ci            i = ok_write(b, NULL, 0);
365e1051a39Sopenharmony_ci            if (i < 0) {
366e1051a39Sopenharmony_ci                ret = i;
367e1051a39Sopenharmony_ci                break;
368e1051a39Sopenharmony_ci            }
369e1051a39Sopenharmony_ci        }
370e1051a39Sopenharmony_ci
371e1051a39Sopenharmony_ci        ctx->finished = 1;
372e1051a39Sopenharmony_ci        ctx->buf_off = ctx->buf_len = 0;
373e1051a39Sopenharmony_ci        ctx->cont = (int)ret;
374e1051a39Sopenharmony_ci
375e1051a39Sopenharmony_ci        /* Finally flush the underlying BIO */
376e1051a39Sopenharmony_ci        ret = BIO_ctrl(next, cmd, num, ptr);
377e1051a39Sopenharmony_ci        break;
378e1051a39Sopenharmony_ci    case BIO_C_DO_STATE_MACHINE:
379e1051a39Sopenharmony_ci        BIO_clear_retry_flags(b);
380e1051a39Sopenharmony_ci        ret = BIO_ctrl(next, cmd, num, ptr);
381e1051a39Sopenharmony_ci        BIO_copy_next_retry(b);
382e1051a39Sopenharmony_ci        break;
383e1051a39Sopenharmony_ci    case BIO_CTRL_INFO:
384e1051a39Sopenharmony_ci        ret = (long)ctx->cont;
385e1051a39Sopenharmony_ci        break;
386e1051a39Sopenharmony_ci    case BIO_C_SET_MD:
387e1051a39Sopenharmony_ci        md = ptr;
388e1051a39Sopenharmony_ci        if (!EVP_DigestInit_ex(ctx->md, md, NULL))
389e1051a39Sopenharmony_ci            return 0;
390e1051a39Sopenharmony_ci        BIO_set_init(b, 1);
391e1051a39Sopenharmony_ci        break;
392e1051a39Sopenharmony_ci    case BIO_C_GET_MD:
393e1051a39Sopenharmony_ci        if (BIO_get_init(b)) {
394e1051a39Sopenharmony_ci            ppmd = ptr;
395e1051a39Sopenharmony_ci            *ppmd = EVP_MD_CTX_get0_md(ctx->md);
396e1051a39Sopenharmony_ci        } else
397e1051a39Sopenharmony_ci            ret = 0;
398e1051a39Sopenharmony_ci        break;
399e1051a39Sopenharmony_ci    default:
400e1051a39Sopenharmony_ci        ret = BIO_ctrl(next, cmd, num, ptr);
401e1051a39Sopenharmony_ci        break;
402e1051a39Sopenharmony_ci    }
403e1051a39Sopenharmony_ci    return ret;
404e1051a39Sopenharmony_ci}
405e1051a39Sopenharmony_ci
406e1051a39Sopenharmony_cistatic long ok_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
407e1051a39Sopenharmony_ci{
408e1051a39Sopenharmony_ci    BIO *next;
409e1051a39Sopenharmony_ci
410e1051a39Sopenharmony_ci    next = BIO_next(b);
411e1051a39Sopenharmony_ci
412e1051a39Sopenharmony_ci    if (next == NULL)
413e1051a39Sopenharmony_ci        return 0;
414e1051a39Sopenharmony_ci
415e1051a39Sopenharmony_ci    return BIO_callback_ctrl(next, cmd, fp);
416e1051a39Sopenharmony_ci}
417e1051a39Sopenharmony_ci
418e1051a39Sopenharmony_cistatic void longswap(void *_ptr, size_t len)
419e1051a39Sopenharmony_ci{
420e1051a39Sopenharmony_ci    DECLARE_IS_ENDIAN;
421e1051a39Sopenharmony_ci
422e1051a39Sopenharmony_ci    if (IS_LITTLE_ENDIAN) {
423e1051a39Sopenharmony_ci        size_t i;
424e1051a39Sopenharmony_ci        unsigned char *p = _ptr, c;
425e1051a39Sopenharmony_ci
426e1051a39Sopenharmony_ci        for (i = 0; i < len; i += 4) {
427e1051a39Sopenharmony_ci            c = p[0], p[0] = p[3], p[3] = c;
428e1051a39Sopenharmony_ci            c = p[1], p[1] = p[2], p[2] = c;
429e1051a39Sopenharmony_ci        }
430e1051a39Sopenharmony_ci    }
431e1051a39Sopenharmony_ci}
432e1051a39Sopenharmony_ci
433e1051a39Sopenharmony_cistatic int sig_out(BIO *b)
434e1051a39Sopenharmony_ci{
435e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
436e1051a39Sopenharmony_ci    EVP_MD_CTX *md;
437e1051a39Sopenharmony_ci    const EVP_MD *digest;
438e1051a39Sopenharmony_ci    int md_size;
439e1051a39Sopenharmony_ci    void *md_data;
440e1051a39Sopenharmony_ci
441e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
442e1051a39Sopenharmony_ci    md = ctx->md;
443e1051a39Sopenharmony_ci    digest = EVP_MD_CTX_get0_md(md);
444e1051a39Sopenharmony_ci    md_size = EVP_MD_get_size(digest);
445e1051a39Sopenharmony_ci    md_data = EVP_MD_CTX_get0_md_data(md);
446e1051a39Sopenharmony_ci
447e1051a39Sopenharmony_ci    if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
448e1051a39Sopenharmony_ci        return 1;
449e1051a39Sopenharmony_ci
450e1051a39Sopenharmony_ci    if (!EVP_DigestInit_ex(md, digest, NULL))
451e1051a39Sopenharmony_ci        goto berr;
452e1051a39Sopenharmony_ci    /*
453e1051a39Sopenharmony_ci     * FIXME: there's absolutely no guarantee this makes any sense at all,
454e1051a39Sopenharmony_ci     * particularly now EVP_MD_CTX has been restructured.
455e1051a39Sopenharmony_ci     */
456e1051a39Sopenharmony_ci    if (RAND_bytes(md_data, md_size) <= 0)
457e1051a39Sopenharmony_ci        goto berr;
458e1051a39Sopenharmony_ci    memcpy(&(ctx->buf[ctx->buf_len]), md_data, md_size);
459e1051a39Sopenharmony_ci    longswap(&(ctx->buf[ctx->buf_len]), md_size);
460e1051a39Sopenharmony_ci    ctx->buf_len += md_size;
461e1051a39Sopenharmony_ci
462e1051a39Sopenharmony_ci    if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
463e1051a39Sopenharmony_ci        goto berr;
464e1051a39Sopenharmony_ci    if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
465e1051a39Sopenharmony_ci        goto berr;
466e1051a39Sopenharmony_ci    ctx->buf_len += md_size;
467e1051a39Sopenharmony_ci    ctx->blockout = 1;
468e1051a39Sopenharmony_ci    ctx->sigio = 0;
469e1051a39Sopenharmony_ci    return 1;
470e1051a39Sopenharmony_ci berr:
471e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
472e1051a39Sopenharmony_ci    return 0;
473e1051a39Sopenharmony_ci}
474e1051a39Sopenharmony_ci
475e1051a39Sopenharmony_cistatic int sig_in(BIO *b)
476e1051a39Sopenharmony_ci{
477e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
478e1051a39Sopenharmony_ci    EVP_MD_CTX *md;
479e1051a39Sopenharmony_ci    unsigned char tmp[EVP_MAX_MD_SIZE];
480e1051a39Sopenharmony_ci    int ret = 0;
481e1051a39Sopenharmony_ci    const EVP_MD *digest;
482e1051a39Sopenharmony_ci    int md_size;
483e1051a39Sopenharmony_ci    void *md_data;
484e1051a39Sopenharmony_ci
485e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
486e1051a39Sopenharmony_ci    if ((md = ctx->md) == NULL)
487e1051a39Sopenharmony_ci        goto berr;
488e1051a39Sopenharmony_ci    digest = EVP_MD_CTX_get0_md(md);
489e1051a39Sopenharmony_ci    if ((md_size = EVP_MD_get_size(digest)) < 0)
490e1051a39Sopenharmony_ci        goto berr;
491e1051a39Sopenharmony_ci    md_data = EVP_MD_CTX_get0_md_data(md);
492e1051a39Sopenharmony_ci
493e1051a39Sopenharmony_ci    if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
494e1051a39Sopenharmony_ci        return 1;
495e1051a39Sopenharmony_ci
496e1051a39Sopenharmony_ci    if (!EVP_DigestInit_ex(md, digest, NULL))
497e1051a39Sopenharmony_ci        goto berr;
498e1051a39Sopenharmony_ci    memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
499e1051a39Sopenharmony_ci    longswap(md_data, md_size);
500e1051a39Sopenharmony_ci    ctx->buf_off += md_size;
501e1051a39Sopenharmony_ci
502e1051a39Sopenharmony_ci    if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
503e1051a39Sopenharmony_ci        goto berr;
504e1051a39Sopenharmony_ci    if (!EVP_DigestFinal_ex(md, tmp, NULL))
505e1051a39Sopenharmony_ci        goto berr;
506e1051a39Sopenharmony_ci    ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
507e1051a39Sopenharmony_ci    ctx->buf_off += md_size;
508e1051a39Sopenharmony_ci    if (ret == 1) {
509e1051a39Sopenharmony_ci        ctx->sigio = 0;
510e1051a39Sopenharmony_ci        if (ctx->buf_len != ctx->buf_off) {
511e1051a39Sopenharmony_ci            memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
512e1051a39Sopenharmony_ci                    ctx->buf_len - ctx->buf_off);
513e1051a39Sopenharmony_ci        }
514e1051a39Sopenharmony_ci        ctx->buf_len -= ctx->buf_off;
515e1051a39Sopenharmony_ci        ctx->buf_off = 0;
516e1051a39Sopenharmony_ci    } else {
517e1051a39Sopenharmony_ci        ctx->cont = 0;
518e1051a39Sopenharmony_ci    }
519e1051a39Sopenharmony_ci    return 1;
520e1051a39Sopenharmony_ci berr:
521e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
522e1051a39Sopenharmony_ci    return 0;
523e1051a39Sopenharmony_ci}
524e1051a39Sopenharmony_ci
525e1051a39Sopenharmony_cistatic int block_out(BIO *b)
526e1051a39Sopenharmony_ci{
527e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
528e1051a39Sopenharmony_ci    EVP_MD_CTX *md;
529e1051a39Sopenharmony_ci    unsigned long tl;
530e1051a39Sopenharmony_ci    const EVP_MD *digest;
531e1051a39Sopenharmony_ci    int md_size;
532e1051a39Sopenharmony_ci
533e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
534e1051a39Sopenharmony_ci    md = ctx->md;
535e1051a39Sopenharmony_ci    digest = EVP_MD_CTX_get0_md(md);
536e1051a39Sopenharmony_ci    md_size = EVP_MD_get_size(digest);
537e1051a39Sopenharmony_ci
538e1051a39Sopenharmony_ci    tl = ctx->buf_len - OK_BLOCK_BLOCK;
539e1051a39Sopenharmony_ci    ctx->buf[0] = (unsigned char)(tl >> 24);
540e1051a39Sopenharmony_ci    ctx->buf[1] = (unsigned char)(tl >> 16);
541e1051a39Sopenharmony_ci    ctx->buf[2] = (unsigned char)(tl >> 8);
542e1051a39Sopenharmony_ci    ctx->buf[3] = (unsigned char)(tl);
543e1051a39Sopenharmony_ci    if (!EVP_DigestUpdate(md,
544e1051a39Sopenharmony_ci                          (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
545e1051a39Sopenharmony_ci        goto berr;
546e1051a39Sopenharmony_ci    if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
547e1051a39Sopenharmony_ci        goto berr;
548e1051a39Sopenharmony_ci    ctx->buf_len += md_size;
549e1051a39Sopenharmony_ci    ctx->blockout = 1;
550e1051a39Sopenharmony_ci    return 1;
551e1051a39Sopenharmony_ci berr:
552e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
553e1051a39Sopenharmony_ci    return 0;
554e1051a39Sopenharmony_ci}
555e1051a39Sopenharmony_ci
556e1051a39Sopenharmony_cistatic int block_in(BIO *b)
557e1051a39Sopenharmony_ci{
558e1051a39Sopenharmony_ci    BIO_OK_CTX *ctx;
559e1051a39Sopenharmony_ci    EVP_MD_CTX *md;
560e1051a39Sopenharmony_ci    unsigned long tl = 0;
561e1051a39Sopenharmony_ci    unsigned char tmp[EVP_MAX_MD_SIZE];
562e1051a39Sopenharmony_ci    int md_size;
563e1051a39Sopenharmony_ci
564e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
565e1051a39Sopenharmony_ci    md = ctx->md;
566e1051a39Sopenharmony_ci    md_size = EVP_MD_get_size(EVP_MD_CTX_get0_md(md));
567e1051a39Sopenharmony_ci    if (md_size < 0)
568e1051a39Sopenharmony_ci        goto berr;
569e1051a39Sopenharmony_ci
570e1051a39Sopenharmony_ci    assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
571e1051a39Sopenharmony_ci    tl = ctx->buf[0];
572e1051a39Sopenharmony_ci    tl <<= 8;
573e1051a39Sopenharmony_ci    tl |= ctx->buf[1];
574e1051a39Sopenharmony_ci    tl <<= 8;
575e1051a39Sopenharmony_ci    tl |= ctx->buf[2];
576e1051a39Sopenharmony_ci    tl <<= 8;
577e1051a39Sopenharmony_ci    tl |= ctx->buf[3];
578e1051a39Sopenharmony_ci
579e1051a39Sopenharmony_ci    if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md_size)
580e1051a39Sopenharmony_ci        return 1;
581e1051a39Sopenharmony_ci
582e1051a39Sopenharmony_ci    if (!EVP_DigestUpdate(md,
583e1051a39Sopenharmony_ci                          (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
584e1051a39Sopenharmony_ci        goto berr;
585e1051a39Sopenharmony_ci    if (!EVP_DigestFinal_ex(md, tmp, NULL))
586e1051a39Sopenharmony_ci        goto berr;
587e1051a39Sopenharmony_ci    if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md_size) == 0) {
588e1051a39Sopenharmony_ci        /* there might be parts from next block lurking around ! */
589e1051a39Sopenharmony_ci        ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size;
590e1051a39Sopenharmony_ci        ctx->buf_len_save = ctx->buf_len;
591e1051a39Sopenharmony_ci        ctx->buf_off = OK_BLOCK_BLOCK;
592e1051a39Sopenharmony_ci        ctx->buf_len = tl + OK_BLOCK_BLOCK;
593e1051a39Sopenharmony_ci        ctx->blockout = 1;
594e1051a39Sopenharmony_ci    } else {
595e1051a39Sopenharmony_ci        ctx->cont = 0;
596e1051a39Sopenharmony_ci    }
597e1051a39Sopenharmony_ci    return 1;
598e1051a39Sopenharmony_ci berr:
599e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
600e1051a39Sopenharmony_ci    return 0;
601e1051a39Sopenharmony_ci}
602