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