1 /* 2 * Copyright 2022-2026 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 <stdio.h> 11 #include <string.h> 12 #include <stdlib.h> 13 14 #include "internal/nelem.h" 15 16 #include <openssl/pkcs12.h> 17 #include <openssl/x509.h> 18 #include <openssl/x509v3.h> 19 #include <openssl/pem.h> 20 21 #include "testutil.h" 22 #include "helpers/pkcs12.h" 23 24 static OSSL_LIB_CTX *testctx = NULL; 25 static OSSL_PROVIDER *nullprov = NULL; 26 27 static int test_null_args(void) 28 { 29 return TEST_false(PKCS12_parse(NULL, NULL, NULL, NULL, NULL)); 30 } 31 32 static PKCS12 *PKCS12_load(const char *fpath) 33 { 34 BIO *bio = NULL; 35 PKCS12 *p12 = NULL; 36 37 bio = BIO_new_file(fpath, "rb"); 38 if (!TEST_ptr(bio)) 39 goto err; 40 41 p12 = PKCS12_init_ex(NID_pkcs7_data, testctx, "provider=default"); 42 if (!TEST_ptr(p12)) 43 goto err; 44 45 if (!TEST_true(p12 == d2i_PKCS12_bio(bio, &p12))) 46 goto err; 47 48 BIO_free(bio); 49 50 return p12; 51 52 err: 53 BIO_free(bio); 54 PKCS12_free(p12); 55 return NULL; 56 } 57 58 static const char *in_file = NULL; 59 static const char *in_pass = ""; 60 static int has_key = 0; 61 static int has_cert = 0; 62 static int has_ca = 0; 63 64 static int changepass(PKCS12 *p12, EVP_PKEY *key, X509 *cert, STACK_OF(X509) *ca) 65 { 66 int ret = 0; 67 PKCS12 *p12new = NULL; 68 EVP_PKEY *key2 = NULL; 69 X509 *cert2 = NULL; 70 STACK_OF(X509) *ca2 = NULL; 71 BIO *bio = NULL; 72 73 if (!TEST_true(PKCS12_newpass(p12, in_pass, "NEWPASS"))) 74 goto err; 75 if (!TEST_ptr(bio = BIO_new(BIO_s_mem()))) 76 goto err; 77 if (!TEST_true(i2d_PKCS12_bio(bio, p12))) 78 goto err; 79 if (!TEST_ptr(p12new = PKCS12_init_ex(NID_pkcs7_data, testctx, "provider=default"))) 80 goto err; 81 if (!TEST_ptr(d2i_PKCS12_bio(bio, &p12new))) 82 goto err; 83 if (!TEST_true(PKCS12_parse(p12new, "NEWPASS", &key2, &cert2, &ca2))) 84 goto err; 85 if (has_key) { 86 if (!TEST_ptr(key2) || !TEST_int_eq(EVP_PKEY_eq(key, key2), 1)) 87 goto err; 88 } 89 if (has_cert) { 90 if (!TEST_ptr(cert2) || !TEST_int_eq(X509_cmp(cert, cert2), 0)) 91 goto err; 92 } 93 ret = 1; 94 err: 95 BIO_free(bio); 96 PKCS12_free(p12new); 97 EVP_PKEY_free(key2); 98 X509_free(cert2); 99 OSSL_STACK_OF_X509_free(ca2); 100 return ret; 101 } 102 103 static int pkcs12_parse_test(void) 104 { 105 int ret = 0; 106 PKCS12 *p12 = NULL; 107 EVP_PKEY *key = NULL; 108 X509 *cert = NULL; 109 STACK_OF(X509) *ca = NULL; 110 111 if (in_file != NULL) { 112 p12 = PKCS12_load(in_file); 113 if (!TEST_ptr(p12)) 114 goto err; 115 116 if (!TEST_true(PKCS12_parse(p12, in_pass, &key, &cert, &ca))) 117 goto err; 118 119 if ((has_key && !TEST_ptr(key)) || (!has_key && !TEST_ptr_null(key))) 120 goto err; 121 if ((has_cert && !TEST_ptr(cert)) || (!has_cert && !TEST_ptr_null(cert))) 122 goto err; 123 if ((has_ca && !TEST_ptr(ca)) || (!has_ca && !TEST_ptr_null(ca))) 124 goto err; 125 if (has_key && !changepass(p12, key, cert, ca)) 126 goto err; 127 } 128 ret = 1; 129 err: 130 PKCS12_free(p12); 131 EVP_PKEY_free(key); 132 X509_free(cert); 133 OSSL_STACK_OF_X509_free(ca); 134 return TEST_true(ret); 135 } 136 137 static int pkcs12_create_cb(PKCS12_SAFEBAG *bag, void *cbarg) 138 { 139 int cb_ret = *((int *)cbarg); 140 return cb_ret; 141 } 142 143 static PKCS12 *pkcs12_create_ex2_setup(EVP_PKEY **key, X509 **cert, STACK_OF(X509) **ca) 144 { 145 PKCS12 *p12 = NULL; 146 p12 = PKCS12_load("out6.p12"); 147 if (!TEST_ptr(p12)) 148 goto err; 149 150 if (!TEST_true(PKCS12_parse(p12, "", key, cert, ca))) 151 goto err; 152 153 return p12; 154 err: 155 PKCS12_free(p12); 156 return NULL; 157 } 158 159 static int pkcs12_create_ex2_test(int test) 160 { 161 int ret = 0, cb_ret = 0; 162 PKCS12 *ptr = NULL, *p12 = NULL; 163 EVP_PKEY *key = NULL; 164 X509 *cert = NULL; 165 STACK_OF(X509) *ca = NULL; 166 167 p12 = pkcs12_create_ex2_setup(&key, &cert, &ca); 168 if (!TEST_ptr(p12)) 169 goto err; 170 171 if (test == 0) { 172 /* Confirm PKCS12_create_ex2 returns NULL */ 173 ptr = PKCS12_create_ex2(NULL, NULL, NULL, 174 NULL, NULL, NID_undef, NID_undef, 175 0, 0, 0, 176 testctx, NULL, 177 NULL, NULL); 178 if (!TEST_ptr_null(ptr)) 179 goto err; 180 181 /* Can't proceed without a valid cert at least */ 182 if (!TEST_ptr(cert)) 183 goto err; 184 185 /* Specified call back called - return success */ 186 cb_ret = 1; 187 ptr = PKCS12_create_ex2(NULL, NULL, NULL, 188 cert, NULL, NID_undef, NID_undef, 189 0, 0, 0, 190 testctx, NULL, 191 pkcs12_create_cb, (void *)&cb_ret); 192 /* PKCS12 successfully created */ 193 if (!TEST_ptr(ptr)) 194 goto err; 195 } else if (test == 1) { 196 /* Specified call back called - return error*/ 197 cb_ret = -1; 198 ptr = PKCS12_create_ex2(NULL, NULL, NULL, 199 cert, NULL, NID_undef, NID_undef, 200 0, 0, 0, 201 testctx, NULL, 202 pkcs12_create_cb, (void *)&cb_ret); 203 /* PKCS12 not created */ 204 if (!TEST_ptr_null(ptr)) 205 goto err; 206 } else if (test == 2) { 207 /* Specified call back called - return failure */ 208 cb_ret = 0; 209 ptr = PKCS12_create_ex2(NULL, NULL, NULL, 210 cert, NULL, NID_undef, NID_undef, 211 0, 0, 0, 212 testctx, NULL, 213 pkcs12_create_cb, (void *)&cb_ret); 214 /* PKCS12 successfully created */ 215 if (!TEST_ptr(ptr)) 216 goto err; 217 } 218 219 ret = 1; 220 err: 221 PKCS12_free(p12); 222 PKCS12_free(ptr); 223 EVP_PKEY_free(key); 224 X509_free(cert); 225 OSSL_STACK_OF_X509_free(ca); 226 return TEST_true(ret); 227 } 228 229 typedef enum OPTION_choice { 230 OPT_ERR = -1, 231 OPT_EOF = 0, 232 OPT_IN_FILE, 233 OPT_IN_PASS, 234 OPT_IN_HAS_KEY, 235 OPT_IN_HAS_CERT, 236 OPT_IN_HAS_CA, 237 OPT_LEGACY, 238 OPT_TEST_ENUM 239 } OPTION_CHOICE; 240 241 const OPTIONS *test_get_options(void) 242 { 243 static const OPTIONS options[] = { 244 OPT_TEST_OPTIONS_DEFAULT_USAGE, 245 { "in", OPT_IN_FILE, '<', "PKCS12 input file" }, 246 { "pass", OPT_IN_PASS, 's', "PKCS12 input file password" }, 247 { "has-key", OPT_IN_HAS_KEY, 'n', "Whether the input file does contain an user key" }, 248 { "has-cert", OPT_IN_HAS_CERT, 'n', "Whether the input file does contain an user certificate" }, 249 { "has-ca", OPT_IN_HAS_CA, 'n', "Whether the input file does contain other certificate" }, 250 { "legacy", OPT_LEGACY, '-', "Test the legacy APIs" }, 251 { NULL } 252 }; 253 return options; 254 } 255 256 static int test_PKCS12_set_pbmac1_pbkdf2_invalid_saltlen(void) 257 { 258 int ret = 0; 259 unsigned char salt[8] = { 0 }; 260 EVP_PKEY *key = NULL; 261 X509 *cert = NULL; 262 STACK_OF(X509) *ca = NULL; 263 PKCS12 *p12 = NULL; 264 265 if (!TEST_ptr(p12 = PKCS12_load(in_file))) 266 return 0; 267 if (!TEST_true(PKCS12_parse(p12, in_pass, &key, &cert, &ca))) 268 goto err; 269 PKCS12_free(p12); 270 271 if (!TEST_ptr(p12 = PKCS12_create_ex2("pass", NULL, key, cert, ca, 272 NID_undef, NID_undef, 0, -1, 0, 273 testctx, NULL, NULL, NULL))) 274 goto err; 275 ret = TEST_false(PKCS12_set_pbmac1_pbkdf2(p12, "pass", -1, 276 salt, -1, 0, NULL, NULL)); 277 err: 278 PKCS12_free(p12); 279 EVP_PKEY_free(key); 280 X509_free(cert); 281 OSSL_STACK_OF_X509_free(ca); 282 return ret; 283 } 284 285 int setup_tests(void) 286 { 287 OPTION_CHOICE o; 288 289 while ((o = opt_next()) != OPT_EOF) { 290 switch (o) { 291 case OPT_IN_FILE: 292 in_file = opt_arg(); 293 break; 294 case OPT_IN_PASS: 295 in_pass = opt_arg(); 296 break; 297 case OPT_LEGACY: 298 break; 299 case OPT_IN_HAS_KEY: 300 has_key = opt_int_arg(); 301 break; 302 case OPT_IN_HAS_CERT: 303 has_cert = opt_int_arg(); 304 break; 305 case OPT_IN_HAS_CA: 306 has_ca = opt_int_arg(); 307 break; 308 case OPT_TEST_CASES: 309 break; 310 default: 311 return 0; 312 } 313 } 314 315 if (!test_get_libctx(&testctx, &nullprov, NULL, NULL, NULL)) { 316 OSSL_LIB_CTX_free(testctx); 317 testctx = NULL; 318 return 0; 319 } 320 321 ADD_TEST(test_null_args); 322 ADD_TEST(pkcs12_parse_test); 323 ADD_ALL_TESTS(pkcs12_create_ex2_test, 3); 324 ADD_TEST(test_PKCS12_set_pbmac1_pbkdf2_invalid_saltlen); 325 return 1; 326 } 327 328 void cleanup_tests(void) 329 { 330 OSSL_LIB_CTX_free(testctx); 331 OSSL_PROVIDER_unload(nullprov); 332 } 333