Home | History | Annotate | Line # | Download | only in test
      1 /*
      2  * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 #include <stdio.h>
     10 #include <string.h>
     11 #include <openssl/evp.h>
     12 #include <openssl/bio.h>
     13 #include <openssl/rand.h>
     14 
     15 #include "testutil.h"
     16 
     17 #define ENCRYPT 1
     18 #define DECRYPT 0
     19 
     20 #define DATA_SIZE 1024
     21 #define MAX_IV 32
     22 #define BUF_SIZE (DATA_SIZE + MAX_IV)
     23 
     24 static const unsigned char KEY[] = {
     25     0x51, 0x50, 0xd1, 0x77, 0x2f, 0x50, 0x83, 0x4a,
     26     0x50, 0x3e, 0x06, 0x9a, 0x97, 0x3f, 0xbd, 0x7c,
     27     0xe6, 0x1c, 0x43, 0x2b, 0x72, 0x0b, 0x19, 0xd1,
     28     0x8e, 0xc8, 0xd8, 0x4b, 0xdc, 0x63, 0x15, 0x1b
     29 };
     30 
     31 static const unsigned char IV[] = {
     32     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
     33     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
     34     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
     35     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
     36 };
     37 
     38 static int do_bio_cipher(const EVP_CIPHER *cipher, const unsigned char *key,
     39     const unsigned char *iv)
     40 {
     41     BIO *b, *mem;
     42     static unsigned char inp[BUF_SIZE] = { 0 };
     43     unsigned char out[BUF_SIZE], ref[BUF_SIZE];
     44     int i, lref, len, tmplen;
     45 
     46     /* Fill buffer with non-zero data so that over steps can be detected */
     47     if (!TEST_int_gt(RAND_bytes(inp, DATA_SIZE), 0))
     48         return 0;
     49 
     50     /* Encrypt tests */
     51 
     52     /* reference output for single-chunk operation */
     53     b = BIO_new(BIO_f_cipher());
     54     if (!TEST_ptr(b))
     55         return 0;
     56     if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, ENCRYPT)))
     57         goto err;
     58     mem = BIO_new_mem_buf(inp, DATA_SIZE);
     59     if (!TEST_ptr(mem))
     60         goto err;
     61     BIO_push(b, mem);
     62     lref = BIO_read(b, ref, sizeof(ref));
     63     BIO_free_all(b);
     64 
     65     /* perform split operations and compare to reference */
     66     for (i = 1; i < lref; i++) {
     67         b = BIO_new(BIO_f_cipher());
     68         if (!TEST_ptr(b))
     69             return 0;
     70         if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, ENCRYPT))) {
     71             TEST_info("Split encrypt failed @ operation %d", i);
     72             goto err;
     73         }
     74         mem = BIO_new_mem_buf(inp, DATA_SIZE);
     75         if (!TEST_ptr(mem))
     76             goto err;
     77         BIO_push(b, mem);
     78         memset(out, 0, sizeof(out));
     79         out[i] = ~ref[i];
     80         tmplen = BIO_read(b, out, i);
     81         if (tmplen < 0)
     82             goto err;
     83         len = tmplen;
     84         /* check for overstep */
     85         if (!TEST_uchar_eq(out[i], (unsigned char)~ref[i])) {
     86             TEST_info("Encrypt overstep check failed @ operation %d", i);
     87             goto err;
     88         }
     89         tmplen = BIO_read(b, out + len, sizeof(out) - len);
     90         if (tmplen < 0)
     91             goto err;
     92         len += tmplen;
     93 
     94         BIO_free_all(b);
     95 
     96         if (!TEST_mem_eq(out, len, ref, lref)) {
     97             TEST_info("Encrypt compare failed @ operation %d", i);
     98             return 0;
     99         }
    100     }
    101 
    102     /* perform small-chunk operations and compare to reference */
    103     for (i = 1; i < lref / 2; i++) {
    104         int delta;
    105 
    106         b = BIO_new(BIO_f_cipher());
    107         if (!TEST_ptr(b))
    108             return 0;
    109         if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, ENCRYPT))) {
    110             TEST_info("Small chunk encrypt failed @ operation %d", i);
    111             goto err;
    112         }
    113         mem = BIO_new_mem_buf(inp, DATA_SIZE);
    114         if (!TEST_ptr(mem))
    115             goto err;
    116         BIO_push(b, mem);
    117         memset(out, 0, sizeof(out));
    118         for (len = 0; (delta = BIO_read(b, out + len, i));) {
    119             len += delta;
    120         }
    121         BIO_free_all(b);
    122 
    123         if (!TEST_mem_eq(out, len, ref, lref)) {
    124             TEST_info("Small chunk encrypt compare failed @ operation %d", i);
    125             return 0;
    126         }
    127     }
    128 
    129     /* Decrypt tests */
    130 
    131     /* reference output for single-chunk operation */
    132     b = BIO_new(BIO_f_cipher());
    133     if (!TEST_ptr(b))
    134         return 0;
    135     if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT)))
    136         goto err;
    137     /* Use original reference output as input */
    138     mem = BIO_new_mem_buf(ref, lref);
    139     if (!TEST_ptr(mem))
    140         goto err;
    141     BIO_push(b, mem);
    142 #if 0
    143     /*
    144      * This is wrong to do, it always fails, and incorrectly ends up
    145      * calling `EVP_CipherFinal()` and setting ctx->finished = 1, ...
    146      * all of which are unwanted.  But just deleting this is less
    147      * instructive to future readers of the code.  Don't call BIO_flush
    148      * until you're done either reading or writing and want to finalise
    149      * the state.
    150      */
    151     (void)BIO_flush(b);
    152 #endif
    153     memset(out, 0, sizeof(out));
    154     len = BIO_read(b, out, sizeof(out));
    155     BIO_free_all(b);
    156 
    157     if (!TEST_mem_eq(inp, DATA_SIZE, out, len))
    158         return 0;
    159 
    160     /* perform split operations and compare to reference */
    161     for (i = 1; i < lref; i++) {
    162         b = BIO_new(BIO_f_cipher());
    163         if (!TEST_ptr(b))
    164             return 0;
    165         if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT))) {
    166             TEST_info("Split decrypt failed @ operation %d", i);
    167             goto err;
    168         }
    169         mem = BIO_new_mem_buf(ref, lref);
    170         if (!TEST_ptr(mem))
    171             goto err;
    172         BIO_push(b, mem);
    173         memset(out, 0, sizeof(out));
    174         out[i] = ~ref[i];
    175         len = BIO_read(b, out, i);
    176         /* check for overstep */
    177         if (!TEST_uchar_eq(out[i], (unsigned char)~ref[i])) {
    178             TEST_info("Decrypt overstep check failed @ operation %d", i);
    179             goto err;
    180         }
    181         len += BIO_read(b, out + len, sizeof(out) - len);
    182         BIO_free_all(b);
    183 
    184         if (!TEST_mem_eq(inp, DATA_SIZE, out, len)) {
    185             TEST_info("Decrypt compare failed @ operation %d", i);
    186             return 0;
    187         }
    188     }
    189 
    190     /* perform small-chunk operations and compare to reference */
    191     for (i = 1; i < lref / 2; i++) {
    192         int delta;
    193 
    194         b = BIO_new(BIO_f_cipher());
    195         if (!TEST_ptr(b))
    196             return 0;
    197         if (!TEST_true(BIO_set_cipher(b, cipher, key, iv, DECRYPT))) {
    198             TEST_info("Small chunk decrypt failed @ operation %d", i);
    199             goto err;
    200         }
    201         mem = BIO_new_mem_buf(ref, lref);
    202         if (!TEST_ptr(mem))
    203             goto err;
    204         BIO_push(b, mem);
    205         memset(out, 0, sizeof(out));
    206         for (len = 0; (delta = BIO_read(b, out + len, i));) {
    207             len += delta;
    208         }
    209         BIO_free_all(b);
    210 
    211         if (!TEST_mem_eq(inp, DATA_SIZE, out, len)) {
    212             TEST_info("Small chunk decrypt compare failed @ operation %d", i);
    213             return 0;
    214         }
    215     }
    216 
    217     return 1;
    218 
    219 err:
    220     BIO_free_all(b);
    221     return 0;
    222 }
    223 
    224 static int do_test_bio_cipher(const EVP_CIPHER *cipher, int idx)
    225 {
    226     switch (idx) {
    227     case 0:
    228         return do_bio_cipher(cipher, KEY, NULL);
    229     case 1:
    230         return do_bio_cipher(cipher, KEY, IV);
    231     }
    232     return 0;
    233 }
    234 
    235 static int test_bio_enc_aes_128_cbc(int idx)
    236 {
    237     return do_test_bio_cipher(EVP_aes_128_cbc(), idx);
    238 }
    239 
    240 static int test_bio_enc_aes_128_ctr(int idx)
    241 {
    242     return do_test_bio_cipher(EVP_aes_128_ctr(), idx);
    243 }
    244 
    245 static int test_bio_enc_aes_256_cfb(int idx)
    246 {
    247     return do_test_bio_cipher(EVP_aes_256_cfb(), idx);
    248 }
    249 
    250 static int test_bio_enc_aes_256_ofb(int idx)
    251 {
    252     return do_test_bio_cipher(EVP_aes_256_ofb(), idx);
    253 }
    254 
    255 #ifndef OPENSSL_NO_CHACHA
    256 static int test_bio_enc_chacha20(int idx)
    257 {
    258     return do_test_bio_cipher(EVP_chacha20(), idx);
    259 }
    260 
    261 #ifndef OPENSSL_NO_POLY1305
    262 static int test_bio_enc_chacha20_poly1305(int idx)
    263 {
    264     return do_test_bio_cipher(EVP_chacha20_poly1305(), idx);
    265 }
    266 #endif
    267 #endif
    268 
    269 static int test_bio_enc_eof_read_flush(void)
    270 {
    271     /* Length chosen to ensure base64 encoding employs padding */
    272     const unsigned char pbuf[] = "Attack at dawn";
    273     unsigned char cbuf[16]; /* At least as long as pbuf */
    274     const EVP_CIPHER *cipher = EVP_aes_256_gcm();
    275     EVP_CIPHER_CTX *ctx = NULL;
    276     BIO *mem = NULL, *b64 = NULL, *cbio = NULL;
    277     unsigned char tag[16];
    278     size_t key_size, iv_size;
    279     int n, ret = 0;
    280 
    281     memset(tag, 0, sizeof(tag));
    282     if (!TEST_ptr(cipher)
    283         || !TEST_int_gt((key_size = EVP_CIPHER_key_length(cipher)), 0)
    284         || !TEST_int_gt((iv_size = EVP_CIPHER_iv_length(cipher)), 0)
    285         || !TEST_ptr(mem = BIO_new(BIO_s_mem()))
    286         || !TEST_ptr(b64 = BIO_new(BIO_f_base64()))
    287         || !TEST_ptr(cbio = BIO_new(BIO_f_cipher()))
    288         || !TEST_ptr(BIO_push(b64, mem))
    289         || !TEST_ptr(BIO_push(cbio, b64))
    290         || !TEST_int_gt(BIO_get_cipher_ctx(cbio, &ctx), 0)
    291         || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, KEY, IV, ENCRYPT))
    292         || !TEST_int_gt(BIO_write(cbio, pbuf, sizeof(pbuf) - 1), 0)
    293         || !TEST_int_gt(BIO_flush(cbio), 0)
    294         || !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG,
    295                             sizeof(tag), tag),
    296             0))
    297         goto end;
    298     BIO_free(cbio);
    299     BIO_free(b64);
    300     b64 = cbio = NULL;
    301 
    302     BIO_set_mem_eof_return(mem, 0);
    303     BIO_set_flags(mem, BIO_FLAGS_NONCLEAR_RST);
    304     if (!TEST_int_gt(BIO_reset(mem), 0)
    305         || !TEST_ptr(b64 = BIO_new(BIO_f_base64()))
    306         || !TEST_ptr(cbio = BIO_new(BIO_f_cipher()))
    307         || !TEST_ptr(BIO_push(b64, mem))
    308         || !TEST_ptr(BIO_push(cbio, b64))
    309         || !TEST_int_gt(BIO_get_cipher_ctx(cbio, &ctx), 0)
    310         || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, KEY, IV, DECRYPT))
    311         || !TEST_int_gt(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG,
    312                             sizeof(tag), tag),
    313             0)
    314         || !TEST_int_gt((n = BIO_read(cbio, cbuf, sizeof(cbuf))), 0)
    315         || !TEST_true(BIO_get_cipher_status(cbio))
    316         /* Evaluate both and report whether either or both failed */
    317         || (!TEST_int_gt(BIO_flush(cbio), 0) + !TEST_true(BIO_get_cipher_status(cbio)))
    318         || !TEST_mem_eq(cbuf, n, pbuf, sizeof(pbuf) - 1))
    319         goto end;
    320 
    321     ret = 1;
    322 
    323 end:
    324     BIO_free(cbio);
    325     BIO_free(b64);
    326     BIO_free(mem);
    327     return ret;
    328 }
    329 
    330 int setup_tests(void)
    331 {
    332     ADD_ALL_TESTS(test_bio_enc_aes_128_cbc, 2);
    333     ADD_ALL_TESTS(test_bio_enc_aes_128_ctr, 2);
    334     ADD_ALL_TESTS(test_bio_enc_aes_256_cfb, 2);
    335     ADD_ALL_TESTS(test_bio_enc_aes_256_ofb, 2);
    336 #ifndef OPENSSL_NO_CHACHA
    337     ADD_ALL_TESTS(test_bio_enc_chacha20, 2);
    338 #ifndef OPENSSL_NO_POLY1305
    339     ADD_ALL_TESTS(test_bio_enc_chacha20_poly1305, 2);
    340 #endif
    341 #endif
    342     ADD_TEST(test_bio_enc_eof_read_flush);
    343     return 1;
    344 }
    345