1 /* 2 * Copyright 2022-2023 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(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(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 int setup_tests(void) 257 { 258 OPTION_CHOICE o; 259 260 while ((o = opt_next()) != OPT_EOF) { 261 switch (o) { 262 case OPT_IN_FILE: 263 in_file = opt_arg(); 264 break; 265 case OPT_IN_PASS: 266 in_pass = opt_arg(); 267 break; 268 case OPT_LEGACY: 269 break; 270 case OPT_IN_HAS_KEY: 271 has_key = opt_int_arg(); 272 break; 273 case OPT_IN_HAS_CERT: 274 has_cert = opt_int_arg(); 275 break; 276 case OPT_IN_HAS_CA: 277 has_ca = opt_int_arg(); 278 break; 279 case OPT_TEST_CASES: 280 break; 281 default: 282 return 0; 283 } 284 } 285 286 if (!test_get_libctx(&testctx, &nullprov, NULL, NULL, NULL)) { 287 OSSL_LIB_CTX_free(testctx); 288 testctx = NULL; 289 return 0; 290 } 291 292 ADD_TEST(test_null_args); 293 ADD_TEST(pkcs12_parse_test); 294 ADD_ALL_TESTS(pkcs12_create_ex2_test, 3); 295 return 1; 296 } 297 298 void cleanup_tests(void) 299 { 300 OSSL_LIB_CTX_free(testctx); 301 OSSL_PROVIDER_unload(nullprov); 302 } 303