bio_ok.c revision 296465
1/* crypto/evp/bio_ok.c */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to.  The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 *    must display the following acknowledgement:
33 *    "This product includes cryptographic software written by
34 *     Eric Young (eay@cryptsoft.com)"
35 *    The word 'cryptographic' can be left out if the rouines from the library
36 *    being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 *    the apps directory (application code) you must include an acknowledgement:
39 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59/*-
60        From: Arne Ansper <arne@cyber.ee>
61
62        Why BIO_f_reliable?
63
64        I wrote function which took BIO* as argument, read data from it
65        and processed it. Then I wanted to store the input file in
66        encrypted form. OK I pushed BIO_f_cipher to the BIO stack
67        and everything was OK. BUT if user types wrong password
68        BIO_f_cipher outputs only garbage and my function crashes. Yes
69        I can and I should fix my function, but BIO_f_cipher is
70        easy way to add encryption support to many existing applications
71        and it's hard to debug and fix them all.
72
73        So I wanted another BIO which would catch the incorrect passwords and
74        file damages which cause garbage on BIO_f_cipher's output.
75
76        The easy way is to push the BIO_f_md and save the checksum at
77        the end of the file. However there are several problems with this
78        approach:
79
80        1) you must somehow separate checksum from actual data.
81        2) you need lot's of memory when reading the file, because you
82        must read to the end of the file and verify the checksum before
83        letting the application to read the data.
84
85        BIO_f_reliable tries to solve both problems, so that you can
86        read and write arbitrary long streams using only fixed amount
87        of memory.
88
89        BIO_f_reliable splits data stream into blocks. Each block is prefixed
90        with it's length and suffixed with it's digest. So you need only
91        several Kbytes of memory to buffer single block before verifying
92        it's digest.
93
94        BIO_f_reliable goes further and adds several important capabilities:
95
96        1) the digest of the block is computed over the whole stream
97        -- so nobody can rearrange the blocks or remove or replace them.
98
99        2) to detect invalid passwords right at the start BIO_f_reliable
100        adds special prefix to the stream. In order to avoid known plain-text
101        attacks this prefix is generated as follows:
102
103                *) digest is initialized with random seed instead of
104                standardized one.
105                *) same seed is written to output
106                *) well-known text is then hashed and the output
107                of the digest is also written to output.
108
109        reader can now read the seed from stream, hash the same string
110        and then compare the digest output.
111
112        Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I
113        initially wrote and tested this code on x86 machine and wrote the
114        digests out in machine-dependent order :( There are people using
115        this code and I cannot change this easily without making existing
116        data files unreadable.
117
118*/
119
120#include <stdio.h>
121#include <errno.h>
122#include <assert.h>
123#include "cryptlib.h"
124#include <openssl/buffer.h>
125#include <openssl/bio.h>
126#include <openssl/evp.h>
127#include <openssl/rand.h>
128
129static int ok_write(BIO *h, const char *buf, int num);
130static int ok_read(BIO *h, char *buf, int size);
131static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
132static int ok_new(BIO *h);
133static int ok_free(BIO *data);
134static long ok_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
135
136static void sig_out(BIO *b);
137static void sig_in(BIO *b);
138static void block_out(BIO *b);
139static void block_in(BIO *b);
140#define OK_BLOCK_SIZE   (1024*4)
141#define OK_BLOCK_BLOCK  4
142#define IOBS            (OK_BLOCK_SIZE+ OK_BLOCK_BLOCK+ 3*EVP_MAX_MD_SIZE)
143#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
144
145typedef struct ok_struct {
146    size_t buf_len;
147    size_t buf_off;
148    size_t buf_len_save;
149    size_t buf_off_save;
150    int cont;                   /* <= 0 when finished */
151    int finished;
152    EVP_MD_CTX md;
153    int blockout;               /* output block is ready */
154    int sigio;                  /* must process signature */
155    unsigned char buf[IOBS];
156} BIO_OK_CTX;
157
158static BIO_METHOD methods_ok = {
159    BIO_TYPE_CIPHER, "reliable",
160    ok_write,
161    ok_read,
162    NULL,                       /* ok_puts, */
163    NULL,                       /* ok_gets, */
164    ok_ctrl,
165    ok_new,
166    ok_free,
167    ok_callback_ctrl,
168};
169
170BIO_METHOD *BIO_f_reliable(void)
171{
172    return (&methods_ok);
173}
174
175static int ok_new(BIO *bi)
176{
177    BIO_OK_CTX *ctx;
178
179    ctx = (BIO_OK_CTX *)OPENSSL_malloc(sizeof(BIO_OK_CTX));
180    if (ctx == NULL)
181        return (0);
182
183    ctx->buf_len = 0;
184    ctx->buf_off = 0;
185    ctx->buf_len_save = 0;
186    ctx->buf_off_save = 0;
187    ctx->cont = 1;
188    ctx->finished = 0;
189    ctx->blockout = 0;
190    ctx->sigio = 1;
191
192    EVP_MD_CTX_init(&ctx->md);
193
194    bi->init = 0;
195    bi->ptr = (char *)ctx;
196    bi->flags = 0;
197    return (1);
198}
199
200static int ok_free(BIO *a)
201{
202    if (a == NULL)
203        return (0);
204    EVP_MD_CTX_cleanup(&((BIO_OK_CTX *)a->ptr)->md);
205    OPENSSL_cleanse(a->ptr, sizeof(BIO_OK_CTX));
206    OPENSSL_free(a->ptr);
207    a->ptr = NULL;
208    a->init = 0;
209    a->flags = 0;
210    return (1);
211}
212
213static int ok_read(BIO *b, char *out, int outl)
214{
215    int ret = 0, i, n;
216    BIO_OK_CTX *ctx;
217
218    if (out == NULL)
219        return (0);
220    ctx = (BIO_OK_CTX *)b->ptr;
221
222    if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0))
223        return (0);
224
225    while (outl > 0) {
226
227        /* copy clean bytes to output buffer */
228        if (ctx->blockout) {
229            i = ctx->buf_len - ctx->buf_off;
230            if (i > outl)
231                i = outl;
232            memcpy(out, &(ctx->buf[ctx->buf_off]), i);
233            ret += i;
234            out += i;
235            outl -= i;
236            ctx->buf_off += i;
237
238            /* all clean bytes are out */
239            if (ctx->buf_len == ctx->buf_off) {
240                ctx->buf_off = 0;
241
242                /*
243                 * copy start of the next block into proper place
244                 */
245                if (ctx->buf_len_save - ctx->buf_off_save > 0) {
246                    ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save;
247                    memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
248                            ctx->buf_len);
249                } else {
250                    ctx->buf_len = 0;
251                }
252                ctx->blockout = 0;
253            }
254        }
255
256        /* output buffer full -- cancel */
257        if (outl == 0)
258            break;
259
260        /* no clean bytes in buffer -- fill it */
261        n = IOBS - ctx->buf_len;
262        i = BIO_read(b->next_bio, &(ctx->buf[ctx->buf_len]), n);
263
264        if (i <= 0)
265            break;              /* nothing new */
266
267        ctx->buf_len += i;
268
269        /* no signature yet -- check if we got one */
270        if (ctx->sigio == 1)
271            sig_in(b);
272
273        /* signature ok -- check if we got block */
274        if (ctx->sigio == 0)
275            block_in(b);
276
277        /* invalid block -- cancel */
278        if (ctx->cont <= 0)
279            break;
280
281    }
282
283    BIO_clear_retry_flags(b);
284    BIO_copy_next_retry(b);
285    return (ret);
286}
287
288static int ok_write(BIO *b, const char *in, int inl)
289{
290    int ret = 0, n, i;
291    BIO_OK_CTX *ctx;
292
293    if (inl <= 0)
294        return inl;
295
296    ctx = (BIO_OK_CTX *)b->ptr;
297    ret = inl;
298
299    if ((ctx == NULL) || (b->next_bio == NULL) || (b->init == 0))
300        return (0);
301
302    if (ctx->sigio)
303        sig_out(b);
304
305    do {
306        BIO_clear_retry_flags(b);
307        n = ctx->buf_len - ctx->buf_off;
308        while (ctx->blockout && n > 0) {
309            i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n);
310            if (i <= 0) {
311                BIO_copy_next_retry(b);
312                if (!BIO_should_retry(b))
313                    ctx->cont = 0;
314                return (i);
315            }
316            ctx->buf_off += i;
317            n -= i;
318        }
319
320        /* at this point all pending data has been written */
321        ctx->blockout = 0;
322        if (ctx->buf_len == ctx->buf_off) {
323            ctx->buf_len = OK_BLOCK_BLOCK;
324            ctx->buf_off = 0;
325        }
326
327        if ((in == NULL) || (inl <= 0))
328            return (0);
329
330        n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ?
331            (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl;
332
333        memcpy((unsigned char *)(&(ctx->buf[ctx->buf_len])),
334               (unsigned char *)in, n);
335        ctx->buf_len += n;
336        inl -= n;
337        in += n;
338
339        if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) {
340            block_out(b);
341        }
342    } while (inl > 0);
343
344    BIO_clear_retry_flags(b);
345    BIO_copy_next_retry(b);
346    return (ret);
347}
348
349static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
350{
351    BIO_OK_CTX *ctx;
352    EVP_MD *md;
353    const EVP_MD **ppmd;
354    long ret = 1;
355    int i;
356
357    ctx = b->ptr;
358
359    switch (cmd) {
360    case BIO_CTRL_RESET:
361        ctx->buf_len = 0;
362        ctx->buf_off = 0;
363        ctx->buf_len_save = 0;
364        ctx->buf_off_save = 0;
365        ctx->cont = 1;
366        ctx->finished = 0;
367        ctx->blockout = 0;
368        ctx->sigio = 1;
369        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
370        break;
371    case BIO_CTRL_EOF:         /* More to read */
372        if (ctx->cont <= 0)
373            ret = 1;
374        else
375            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
376        break;
377    case BIO_CTRL_PENDING:     /* More to read in buffer */
378    case BIO_CTRL_WPENDING:    /* More to read in buffer */
379        ret = ctx->blockout ? ctx->buf_len - ctx->buf_off : 0;
380        if (ret <= 0)
381            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
382        break;
383    case BIO_CTRL_FLUSH:
384        /* do a final write */
385        if (ctx->blockout == 0)
386            block_out(b);
387
388        while (ctx->blockout) {
389            i = ok_write(b, NULL, 0);
390            if (i < 0) {
391                ret = i;
392                break;
393            }
394        }
395
396        ctx->finished = 1;
397        ctx->buf_off = ctx->buf_len = 0;
398        ctx->cont = (int)ret;
399
400        /* Finally flush the underlying BIO */
401        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
402        break;
403    case BIO_C_DO_STATE_MACHINE:
404        BIO_clear_retry_flags(b);
405        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
406        BIO_copy_next_retry(b);
407        break;
408    case BIO_CTRL_INFO:
409        ret = (long)ctx->cont;
410        break;
411    case BIO_C_SET_MD:
412        md = ptr;
413        EVP_DigestInit_ex(&ctx->md, md, NULL);
414        b->init = 1;
415        break;
416    case BIO_C_GET_MD:
417        if (b->init) {
418            ppmd = ptr;
419            *ppmd = ctx->md.digest;
420        } else
421            ret = 0;
422        break;
423    default:
424        ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
425        break;
426    }
427    return (ret);
428}
429
430static long ok_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
431{
432    long ret = 1;
433
434    if (b->next_bio == NULL)
435        return (0);
436    switch (cmd) {
437    default:
438        ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
439        break;
440    }
441    return (ret);
442}
443
444static void longswap(void *_ptr, size_t len)
445{
446    const union {
447        long one;
448        char little;
449    } is_endian = {
450        1
451    };
452
453    if (is_endian.little) {
454        size_t i;
455        unsigned char *p = _ptr, c;
456
457        for (i = 0; i < len; i += 4) {
458            c = p[0], p[0] = p[3], p[3] = c;
459            c = p[1], p[1] = p[2], p[2] = c;
460        }
461    }
462}
463
464static void sig_out(BIO *b)
465{
466    BIO_OK_CTX *ctx;
467    EVP_MD_CTX *md;
468
469    ctx = b->ptr;
470    md = &ctx->md;
471
472    if (ctx->buf_len + 2 * md->digest->md_size > OK_BLOCK_SIZE)
473        return;
474
475    EVP_DigestInit_ex(md, md->digest, NULL);
476    /*
477     * FIXME: there's absolutely no guarantee this makes any sense at all,
478     * particularly now EVP_MD_CTX has been restructured.
479     */
480    RAND_pseudo_bytes(md->md_data, md->digest->md_size);
481    memcpy(&(ctx->buf[ctx->buf_len]), md->md_data, md->digest->md_size);
482    longswap(&(ctx->buf[ctx->buf_len]), md->digest->md_size);
483    ctx->buf_len += md->digest->md_size;
484
485    EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN));
486    EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL);
487    ctx->buf_len += md->digest->md_size;
488    ctx->blockout = 1;
489    ctx->sigio = 0;
490}
491
492static void sig_in(BIO *b)
493{
494    BIO_OK_CTX *ctx;
495    EVP_MD_CTX *md;
496    unsigned char tmp[EVP_MAX_MD_SIZE];
497    int ret = 0;
498
499    ctx = b->ptr;
500    md = &ctx->md;
501
502    if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md->digest->md_size)
503        return;
504
505    EVP_DigestInit_ex(md, md->digest, NULL);
506    memcpy(md->md_data, &(ctx->buf[ctx->buf_off]), md->digest->md_size);
507    longswap(md->md_data, md->digest->md_size);
508    ctx->buf_off += md->digest->md_size;
509
510    EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN));
511    EVP_DigestFinal_ex(md, tmp, NULL);
512    ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md->digest->md_size) == 0;
513    ctx->buf_off += md->digest->md_size;
514    if (ret == 1) {
515        ctx->sigio = 0;
516        if (ctx->buf_len != ctx->buf_off) {
517            memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
518                    ctx->buf_len - ctx->buf_off);
519        }
520        ctx->buf_len -= ctx->buf_off;
521        ctx->buf_off = 0;
522    } else {
523        ctx->cont = 0;
524    }
525}
526
527static void block_out(BIO *b)
528{
529    BIO_OK_CTX *ctx;
530    EVP_MD_CTX *md;
531    unsigned long tl;
532
533    ctx = b->ptr;
534    md = &ctx->md;
535
536    tl = ctx->buf_len - OK_BLOCK_BLOCK;
537    ctx->buf[0] = (unsigned char)(tl >> 24);
538    ctx->buf[1] = (unsigned char)(tl >> 16);
539    ctx->buf[2] = (unsigned char)(tl >> 8);
540    ctx->buf[3] = (unsigned char)(tl);
541    EVP_DigestUpdate(md, (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl);
542    EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL);
543    ctx->buf_len += md->digest->md_size;
544    ctx->blockout = 1;
545}
546
547static void block_in(BIO *b)
548{
549    BIO_OK_CTX *ctx;
550    EVP_MD_CTX *md;
551    unsigned long tl = 0;
552    unsigned char tmp[EVP_MAX_MD_SIZE];
553
554    ctx = b->ptr;
555    md = &ctx->md;
556
557    assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
558    tl = ctx->buf[0];
559    tl <<= 8;
560    tl |= ctx->buf[1];
561    tl <<= 8;
562    tl |= ctx->buf[2];
563    tl <<= 8;
564    tl |= ctx->buf[3];
565
566    if (ctx->buf_len < tl + OK_BLOCK_BLOCK + md->digest->md_size)
567        return;
568
569    EVP_DigestUpdate(md, (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl);
570    EVP_DigestFinal_ex(md, tmp, NULL);
571    if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, md->digest->md_size) ==
572        0) {
573        /* there might be parts from next block lurking around ! */
574        ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md->digest->md_size;
575        ctx->buf_len_save = ctx->buf_len;
576        ctx->buf_off = OK_BLOCK_BLOCK;
577        ctx->buf_len = tl + OK_BLOCK_BLOCK;
578        ctx->blockout = 1;
579    } else {
580        ctx->cont = 0;
581    }
582}
583