Home | History | Annotate | Line # | Download | only in test
      1 /*
      2  * Copyright 2024 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 
     10 #include "testutil.h"
     11 
     12 #include <openssl/bio.h>
     13 #include <openssl/pem.h>
     14 
     15 /* dummy data that needs to be passed to the callback */
     16 typedef struct CallbackData {
     17     char magic;
     18     int result;
     19 } CALLBACK_DATA;
     20 
     21 /* constants */
     22 static const char weak_password[] = "weak_password";
     23 static const char a0a_password[] = "aaaaaaaa\0aaaaaaaa";
     24 static const char a0b_password[] = "aaaaaaaa\0bbbbbbbb";
     25 static const char cb_magic = 'p';
     26 
     27 /* shared working data for all tests */
     28 static char *key_file = NULL;
     29 static EVP_PKEY *original_pkey = NULL;
     30 
     31 /* the test performed by the callback */
     32 typedef enum CallbackTest {
     33     CB_TEST_NEGATIVE = 0,
     34     CB_TEST_ZERO_LENGTH,
     35     CB_TEST_WEAK,
     36     CB_TEST_16ZERO,
     37     CB_TEST_A0A,
     38     CB_TEST_A0B,
     39     CB_TEST_MATCH_SIZE,
     40     CB_TEST_EXCEED_SIZE
     41 } CALLBACK_TEST;
     42 static CALLBACK_TEST callback_test = CB_TEST_NEGATIVE;
     43 
     44 typedef enum KeyEncoding {
     45     KE_PEM = 0,
     46     KE_PKCS8
     47 } KEY_ENCODING;
     48 
     49 typedef enum ExpectedResult {
     50     ER_FAILURE = 0,
     51     ER_SUCCESS
     52 } EXPECTED_RESULT;
     53 
     54 typedef enum OPTION_choice {
     55     OPT_ERR = -1,
     56     OPT_EOF = 0,
     57     OPT_KEY_FILE,
     58     OPT_TEST_ENUM
     59 } OPTION_CHOICE;
     60 
     61 const OPTIONS *test_get_options(void)
     62 {
     63     static const OPTIONS test_options[] = {
     64         OPT_TEST_OPTIONS_DEFAULT_USAGE,
     65         { "keyfile", OPT_KEY_FILE, '<',
     66           "The PEM file with the encrypted key to load" },
     67         { NULL }
     68     };
     69     return test_options;
     70 }
     71 
     72 static int callback_copy_password(char *buf, int size)
     73 {
     74     int ret = -1;
     75 
     76     switch (callback_test) {
     77     case CB_TEST_NEGATIVE:
     78         break;
     79     case CB_TEST_ZERO_LENGTH:
     80         ret = 0;
     81         break;
     82     case CB_TEST_WEAK:
     83         ret = sizeof(weak_password) - 1;
     84         memcpy(buf, weak_password, ret);
     85         break;
     86     case CB_TEST_16ZERO:
     87         memset(buf, 0, 16);
     88         ret = 16;
     89         break;
     90     case CB_TEST_A0A:
     91         ret = sizeof(a0a_password) - 1;
     92         memcpy(buf, a0a_password, ret);
     93         break;
     94     case CB_TEST_A0B:
     95         ret = sizeof(a0b_password) - 1;
     96         memcpy(buf, a0b_password, ret);
     97         break;
     98     case CB_TEST_MATCH_SIZE:
     99         memset(buf, 'e', size);
    100         ret = size;
    101         break;
    102     case CB_TEST_EXCEED_SIZE:
    103         memset(buf, 'e', size);
    104         ret = 1000000;
    105         break;
    106     }
    107     return ret;
    108 }
    109 
    110 static int read_callback(char *buf, int size, int rwflag, void *u)
    111 {
    112     CALLBACK_DATA *cb_data = (CALLBACK_DATA *)u;
    113     int ret = -1;
    114 
    115     /* basic verification of the received data */
    116     if (!TEST_ptr(cb_data))
    117         goto err;
    118     if (!TEST_char_eq(cb_data->magic, cb_magic))
    119         goto err;
    120     if (!TEST_ptr(buf))
    121         goto err;
    122     if (!TEST_int_gt(size, 0))
    123         goto err;
    124     if (!TEST_int_eq(rwflag, 0))
    125         goto err;
    126     ret = callback_copy_password(buf, size);
    127     cb_data->result = 1;
    128 err:
    129     return ret;
    130 }
    131 
    132 static int write_callback(char *buf, int size, int rwflag, void *u)
    133 {
    134     CALLBACK_DATA *cb_data = (CALLBACK_DATA *)u;
    135     int ret = -1;
    136 
    137     /* basic verification of the received data */
    138     if (!TEST_ptr(cb_data))
    139         goto err;
    140     if (!TEST_char_eq(cb_data->magic, cb_magic))
    141         goto err;
    142     if (!TEST_ptr(buf))
    143         goto err;
    144     if (!TEST_int_gt(size, 0))
    145         goto err;
    146     if (!TEST_int_eq(rwflag, 1))
    147         goto err;
    148     ret = callback_copy_password(buf, size);
    149     cb_data->result = 1;
    150 err:
    151     return ret;
    152 }
    153 
    154 static int re_encrypt_key(char **enc_data, int *enc_data_size,
    155                           KEY_ENCODING key_encoding)
    156 {
    157     CALLBACK_DATA cb_data;
    158     int w_ret = 0;
    159     BUF_MEM *bptr = NULL;
    160     BIO *bio = NULL;
    161     int ret = 0;
    162 
    163     if (!TEST_ptr(enc_data))
    164         goto err;
    165     if (!TEST_ptr(enc_data_size))
    166         goto err;
    167     if (!TEST_ptr(bio = BIO_new(BIO_s_mem())))
    168         goto err;
    169     cb_data.magic = cb_magic;
    170     cb_data.result = 0;
    171     switch (key_encoding) {
    172     case KE_PEM:
    173         w_ret = PEM_write_bio_PrivateKey(bio, original_pkey, EVP_aes_256_cbc(),
    174                                          NULL, 0, write_callback, &cb_data);
    175         break;
    176     case KE_PKCS8:
    177         w_ret = i2d_PKCS8PrivateKey_bio(bio, original_pkey, EVP_aes_256_cbc(),
    178                                         NULL, 0, write_callback, &cb_data);
    179         break;
    180     }
    181     if (!TEST_int_ne(w_ret, 0))
    182         goto err;
    183     if (!TEST_char_eq(cb_data.magic, cb_magic))
    184         goto err;
    185     if (!TEST_int_eq(cb_data.result, 1))
    186         goto err;
    187     *enc_data_size = BIO_get_mem_data(bio, enc_data);
    188     BIO_get_mem_ptr(bio, &bptr);
    189     if (!BIO_set_close(bio, BIO_NOCLOSE))
    190         goto err;
    191     bptr->data = NULL;
    192     ret = 1;
    193 err:
    194     BUF_MEM_free(bptr);
    195     BIO_free(bio);
    196     return ret;
    197 }
    198 
    199 static int decrypt_key(char *enc_data, int enc_data_size,
    200                        KEY_ENCODING key_encoding,
    201                        EXPECTED_RESULT expected_result)
    202 {
    203     CALLBACK_DATA cb_data;
    204     EVP_PKEY *r_ret = NULL;
    205     BIO *bio = NULL;
    206     EVP_PKEY *pkey = NULL;
    207     int ret = 0;
    208 
    209     if (!TEST_ptr(bio = BIO_new_mem_buf(enc_data, enc_data_size)))
    210         goto err;
    211     cb_data.magic = cb_magic;
    212     cb_data.result = 0;
    213     switch (key_encoding) {
    214     case KE_PEM:
    215         r_ret = PEM_read_bio_PrivateKey(bio, &pkey, read_callback, &cb_data);
    216         break;
    217     case KE_PKCS8:
    218         r_ret = d2i_PKCS8PrivateKey_bio(bio, &pkey, read_callback, &cb_data);
    219         break;
    220     }
    221     if (expected_result == ER_SUCCESS) {
    222         if (!TEST_ptr(r_ret))
    223             goto err;
    224     } else {
    225         if (!TEST_ptr_null(r_ret))
    226             goto err;
    227     }
    228     if (!TEST_char_eq(cb_data.magic, cb_magic))
    229         goto err;
    230     if (!TEST_int_eq(cb_data.result, 1))
    231         goto err;
    232     ret = 1;
    233 err:
    234     EVP_PKEY_free(pkey);
    235     BIO_free(bio);
    236     return ret;
    237 }
    238 
    239 static int full_cycle_test(KEY_ENCODING key_encoding, CALLBACK_TEST write_test,
    240                            CALLBACK_TEST read_test,
    241                            EXPECTED_RESULT expected_read_result)
    242 {
    243     char *enc_data = NULL;
    244     int enc_data_size = 0;
    245     int ret = 0;
    246 
    247     callback_test = write_test;
    248     if (!re_encrypt_key(&enc_data, &enc_data_size, key_encoding))
    249         goto err;
    250     callback_test = read_test;
    251     if (!decrypt_key(enc_data, enc_data_size, key_encoding,
    252                      expected_read_result))
    253         goto err;
    254     ret = 1;
    255 err:
    256     OPENSSL_free(enc_data);
    257     return ret;
    258 }
    259 
    260 static int test_pem_negative(void)
    261 {
    262     return full_cycle_test(KE_PEM, CB_TEST_WEAK, CB_TEST_NEGATIVE, ER_FAILURE);
    263 }
    264 
    265 static int test_pem_zero_length(void)
    266 {
    267     return full_cycle_test(KE_PEM, CB_TEST_ZERO_LENGTH, CB_TEST_ZERO_LENGTH,
    268                            ER_SUCCESS);
    269 }
    270 
    271 static int test_pem_weak(void)
    272 {
    273     return full_cycle_test(KE_PEM, CB_TEST_WEAK, CB_TEST_WEAK, ER_SUCCESS);
    274 }
    275 
    276 static int test_pem_16zero(void)
    277 {
    278     return full_cycle_test(KE_PEM, CB_TEST_16ZERO, CB_TEST_16ZERO, ER_SUCCESS);
    279 }
    280 
    281 static int test_pem_a0a(void)
    282 {
    283     return full_cycle_test(KE_PEM, CB_TEST_A0A, CB_TEST_A0A, ER_SUCCESS);
    284 }
    285 
    286 static int test_pem_a0a_a0b(void)
    287 {
    288     return full_cycle_test(KE_PEM, CB_TEST_A0A, CB_TEST_A0B, ER_FAILURE);
    289 }
    290 
    291 static int test_pem_match_size(void)
    292 {
    293     return full_cycle_test(KE_PEM, CB_TEST_MATCH_SIZE, CB_TEST_MATCH_SIZE,
    294                            ER_SUCCESS);
    295 }
    296 
    297 static int test_pem_exceed_size(void)
    298 {
    299     return full_cycle_test(KE_PEM, CB_TEST_MATCH_SIZE, CB_TEST_EXCEED_SIZE,
    300                            ER_FAILURE);
    301 }
    302 
    303 static int test_pkcs8_negative(void)
    304 {
    305     return full_cycle_test(KE_PKCS8, CB_TEST_WEAK, CB_TEST_NEGATIVE, ER_FAILURE);
    306 }
    307 
    308 static int test_pkcs8_zero_length(void)
    309 {
    310     return full_cycle_test(KE_PKCS8, CB_TEST_ZERO_LENGTH, CB_TEST_ZERO_LENGTH,
    311                            ER_SUCCESS);
    312 }
    313 
    314 static int test_pkcs8_weak(void)
    315 {
    316     return full_cycle_test(KE_PKCS8, CB_TEST_WEAK, CB_TEST_WEAK, ER_SUCCESS);
    317 }
    318 
    319 static int test_pkcs8_16zero(void)
    320 {
    321     return full_cycle_test(KE_PKCS8, CB_TEST_16ZERO, CB_TEST_16ZERO,
    322                            ER_SUCCESS);
    323 }
    324 
    325 static int test_pkcs8_a0a(void)
    326 {
    327     return full_cycle_test(KE_PKCS8, CB_TEST_A0A, CB_TEST_A0A, ER_SUCCESS);
    328 }
    329 
    330 static int test_pkcs8_a0a_a0b(void)
    331 {
    332     return full_cycle_test(KE_PKCS8, CB_TEST_A0A, CB_TEST_A0B, ER_FAILURE);
    333 }
    334 
    335 static int test_pkcs8_match_size(void)
    336 {
    337     return full_cycle_test(KE_PKCS8, CB_TEST_MATCH_SIZE, CB_TEST_MATCH_SIZE,
    338                            ER_SUCCESS);
    339 }
    340 
    341 static int test_pkcs8_exceed_size(void)
    342 {
    343     return full_cycle_test(KE_PKCS8, CB_TEST_MATCH_SIZE, CB_TEST_EXCEED_SIZE,
    344                            ER_FAILURE);
    345 }
    346 
    347 static int callback_original_pw(char *buf, int size, int rwflag, void *u)
    348 {
    349     memcpy(buf, weak_password, sizeof(weak_password) - 1);
    350     return sizeof(weak_password) - 1;
    351 }
    352 
    353 int setup_tests(void)
    354 {
    355     OPTION_CHOICE o;
    356     BIO *bio = NULL;
    357 
    358     while ((o = opt_next()) != OPT_EOF) {
    359         switch (o) {
    360         case OPT_KEY_FILE:
    361             key_file = opt_arg();
    362             break;
    363         case OPT_TEST_CASES:
    364             break;
    365         default:
    366         case OPT_ERR:
    367             return 0;
    368         }
    369     }
    370 
    371     /* read the original key */
    372     if (!TEST_ptr(bio = BIO_new_file(key_file, "r")))
    373         return 0;
    374     if (!TEST_ptr(PEM_read_bio_PrivateKey(bio, &original_pkey,
    375                                           callback_original_pw, NULL)))
    376         return 0;
    377     BIO_free(bio);
    378 
    379     /* add all tests */
    380     ADD_TEST(test_pem_negative);
    381     ADD_TEST(test_pem_zero_length);
    382     ADD_TEST(test_pem_weak);
    383     ADD_TEST(test_pem_16zero);
    384     ADD_TEST(test_pem_a0a);
    385     ADD_TEST(test_pem_a0a_a0b);
    386     ADD_TEST(test_pem_match_size);
    387     ADD_TEST(test_pem_exceed_size);
    388     ADD_TEST(test_pkcs8_negative);
    389     ADD_TEST(test_pkcs8_zero_length);
    390     ADD_TEST(test_pkcs8_weak);
    391     ADD_TEST(test_pkcs8_16zero);
    392     ADD_TEST(test_pkcs8_a0a);
    393     ADD_TEST(test_pkcs8_a0a_a0b);
    394     ADD_TEST(test_pkcs8_match_size);
    395     ADD_TEST(test_pkcs8_exceed_size);
    396     return 1;
    397 }
    398 
    399 void cleanup_tests(void)
    400 {
    401     EVP_PKEY_free(original_pkey);
    402 }
    403