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