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