2 * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include <openssl/asn1.h>
11 #include <openssl/pem.h>
12 #include "internal/sizes.h"
13 #include "crypto/evp.h"
16 /* Collected arguments */
17 static const char *eecert_filename
= NULL
; /* For test_x509_file() */
18 static const char *cacert_filename
= NULL
; /* For test_x509_file() */
19 static const char *pubkey_filename
= NULL
; /* For test_spki_file() */
21 #define ALGORITHMID_NAME "algorithm-id"
23 static int test_spki_aid(X509_PUBKEY
*pubkey
, const char *filename
)
25 const ASN1_OBJECT
*oid
;
26 X509_ALGOR
*alg
= NULL
;
27 EVP_PKEY
*pkey
= NULL
;
28 EVP_KEYMGMT
*keymgmt
= NULL
;
30 char name
[OSSL_MAX_NAME_SIZE
] = "";
31 unsigned char *algid_legacy
= NULL
;
32 int algid_legacy_len
= 0;
33 static unsigned char algid_prov
[OSSL_MAX_ALGORITHM_ID_SIZE
];
34 size_t algid_prov_len
= 0;
35 const OSSL_PARAM
*gettable_params
= NULL
;
36 OSSL_PARAM params
[] = {
37 OSSL_PARAM_octet_string(ALGORITHMID_NAME
,
38 &algid_prov
, sizeof(algid_prov
)),
43 if (!TEST_true(X509_PUBKEY_get0_param(NULL
, NULL
, NULL
, &alg
, pubkey
))
44 || !TEST_ptr(pkey
= X509_PUBKEY_get0(pubkey
)))
47 if (!TEST_int_ge(algid_legacy_len
= i2d_X509_ALGOR(alg
, &algid_legacy
), 0))
50 X509_ALGOR_get0(&oid
, NULL
, NULL
, alg
);
51 if (!TEST_int_gt(OBJ_obj2txt(name
, sizeof(name
), oid
, 0), 0))
55 * We use an internal functions to ensure we have a provided key.
56 * Note that |keydata| should not be freed, as it's cached in |pkey|.
57 * The |keymgmt|, however, should, as its reference count is incremented
60 if ((keydata
= evp_pkey_export_to_provider(pkey
, NULL
,
61 &keymgmt
, NULL
)) == NULL
) {
62 TEST_info("The public key found in '%s' doesn't have provider support."
69 if (!TEST_true(EVP_KEYMGMT_is_a(keymgmt
, name
))) {
70 TEST_info("The AlgorithmID key type (%s) for the public key found in"
71 " '%s' doesn't match the key type of the extracted public"
78 if (!TEST_ptr(gettable_params
= EVP_KEYMGMT_gettable_params(keymgmt
))
79 || !TEST_ptr(OSSL_PARAM_locate_const(gettable_params
, ALGORITHMID_NAME
))) {
80 TEST_info("The %s provider keymgmt appears to lack support for algorithm-id."
88 if (!TEST_true(evp_keymgmt_get_params(keymgmt
, keydata
, params
)))
90 algid_prov_len
= params
[0].return_size
;
92 /* We now have all the algorithm IDs we need, let's compare them */
93 if (TEST_mem_eq(algid_legacy
, algid_legacy_len
,
94 algid_prov
, algid_prov_len
))
98 EVP_KEYMGMT_free(keymgmt
);
99 OPENSSL_free(algid_legacy
);
103 static int test_x509_spki_aid(X509
*cert
, const char *filename
)
105 X509_PUBKEY
*pubkey
= X509_get_X509_PUBKEY(cert
);
107 return test_spki_aid(pubkey
, filename
);
110 static int test_x509_sig_aid(X509
*eecert
, const char *ee_filename
,
111 X509
*cacert
, const char *ca_filename
)
113 const ASN1_OBJECT
*sig_oid
= NULL
;
114 const X509_ALGOR
*alg
= NULL
;
115 int sig_nid
= NID_undef
, dig_nid
= NID_undef
, pkey_nid
= NID_undef
;
116 EVP_MD_CTX
*mdctx
= NULL
;
117 EVP_PKEY_CTX
*pctx
= NULL
;
118 EVP_PKEY
*pkey
= NULL
;
119 unsigned char *algid_legacy
= NULL
;
120 int algid_legacy_len
= 0;
121 static unsigned char algid_prov
[OSSL_MAX_ALGORITHM_ID_SIZE
];
122 size_t algid_prov_len
= 0;
123 const OSSL_PARAM
*gettable_params
= NULL
;
124 OSSL_PARAM params
[] = {
125 OSSL_PARAM_octet_string("algorithm-id",
126 &algid_prov
, sizeof(algid_prov
)),
131 X509_get0_signature(NULL
, &alg
, eecert
);
132 X509_ALGOR_get0(&sig_oid
, NULL
, NULL
, alg
);
133 if (!TEST_int_eq(X509_ALGOR_cmp(alg
, X509_get0_tbs_sigalg(eecert
)), 0))
135 if (!TEST_int_ne(sig_nid
= OBJ_obj2nid(sig_oid
), NID_undef
)
136 || !TEST_true(OBJ_find_sigid_algs(sig_nid
, &dig_nid
, &pkey_nid
))
137 || !TEST_ptr(pkey
= X509_get0_pubkey(cacert
)))
140 if (!TEST_true(EVP_PKEY_is_a(pkey
, OBJ_nid2sn(pkey_nid
)))) {
141 TEST_info("The '%s' pubkey can't be used to verify the '%s' signature",
142 ca_filename
, ee_filename
);
143 TEST_info("Signature algorithm is %s (pkey type %s, hash type %s)",
144 OBJ_nid2sn(sig_nid
), OBJ_nid2sn(pkey_nid
), OBJ_nid2sn(dig_nid
));
145 TEST_info("Pkey key type is %s", EVP_PKEY_get0_type_name(pkey
));
149 if (!TEST_int_ge(algid_legacy_len
= i2d_X509_ALGOR(alg
, &algid_legacy
), 0))
152 if (!TEST_ptr(mdctx
= EVP_MD_CTX_new())
153 || !TEST_true(EVP_DigestVerifyInit_ex(mdctx
, &pctx
,
155 NULL
, NULL
, pkey
, NULL
))) {
156 TEST_info("Couldn't initialize a DigestVerify operation with "
157 "pkey type %s and hash type %s",
158 OBJ_nid2sn(pkey_nid
), OBJ_nid2sn(dig_nid
));
162 if (!TEST_ptr(gettable_params
= EVP_PKEY_CTX_gettable_params(pctx
))
163 || !TEST_ptr(OSSL_PARAM_locate_const(gettable_params
, ALGORITHMID_NAME
))) {
164 TEST_info("The %s provider keymgmt appears to lack support for algorithm-id"
166 OBJ_nid2sn(pkey_nid
));
171 algid_prov
[0] = '\0';
172 if (!TEST_true(EVP_PKEY_CTX_get_params(pctx
, params
)))
174 algid_prov_len
= params
[0].return_size
;
176 /* We now have all the algorithm IDs we need, let's compare them */
177 if (TEST_mem_eq(algid_legacy
, algid_legacy_len
,
178 algid_prov
, algid_prov_len
))
182 EVP_MD_CTX_free(mdctx
);
183 /* pctx is free by EVP_MD_CTX_free() */
184 OPENSSL_free(algid_legacy
);
188 static int test_spki_file(void)
190 X509_PUBKEY
*pubkey
= NULL
;
191 BIO
*b
= BIO_new_file(pubkey_filename
, "r");
195 TEST_error("Couldn't open '%s' for reading\n", pubkey_filename
);
196 TEST_openssl_errors();
200 if ((pubkey
= PEM_read_bio_X509_PUBKEY(b
, NULL
, NULL
, NULL
)) == NULL
) {
201 TEST_error("'%s' doesn't appear to be a SubjectPublicKeyInfo in PEM format\n",
203 TEST_openssl_errors();
207 ret
= test_spki_aid(pubkey
, pubkey_filename
);
210 X509_PUBKEY_free(pubkey
);
214 static int test_x509_files(void)
216 X509
*eecert
= NULL
, *cacert
= NULL
;
217 BIO
*bee
= NULL
, *bca
= NULL
;
220 if ((bee
= BIO_new_file(eecert_filename
, "r")) == NULL
) {
221 TEST_error("Couldn't open '%s' for reading\n", eecert_filename
);
222 TEST_openssl_errors();
225 if ((bca
= BIO_new_file(cacert_filename
, "r")) == NULL
) {
226 TEST_error("Couldn't open '%s' for reading\n", cacert_filename
);
227 TEST_openssl_errors();
231 if ((eecert
= PEM_read_bio_X509(bee
, NULL
, NULL
, NULL
)) == NULL
) {
232 TEST_error("'%s' doesn't appear to be a X.509 certificate in PEM format\n",
234 TEST_openssl_errors();
237 if ((cacert
= PEM_read_bio_X509(bca
, NULL
, NULL
, NULL
)) == NULL
) {
238 TEST_error("'%s' doesn't appear to be a X.509 certificate in PEM format\n",
240 TEST_openssl_errors();
244 ret
= test_x509_sig_aid(eecert
, eecert_filename
, cacert
, cacert_filename
)
245 & test_x509_spki_aid(eecert
, eecert_filename
)
246 & test_x509_spki_aid(cacert
, cacert_filename
);
255 typedef enum OPTION_choice
{
263 const OPTIONS
*test_get_options(void)
265 static const OPTIONS test_options
[] = {
266 OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("file...\n"),
267 { "x509", OPT_X509
, '-', "Test X.509 certificates. Requires two files" },
268 { "spki", OPT_SPKI
, '-', "Test public keys in SubjectPublicKeyInfo form. Requires one file" },
269 { OPT_HELP_STR
, 1, '-',
270 "file...\tFile(s) to run tests on. All files must be PEM encoded.\n" },
276 int setup_tests(void)
279 int n
, x509
= 0, spki
= 0, testcount
= 0;
281 while ((o
= opt_next()) != OPT_EOF
) {
297 /* |testcount| adds all the given test types together */
298 testcount
= x509
+ spki
;
301 BIO_printf(bio_err
, "No test type given\n");
302 else if (testcount
> 1)
303 BIO_printf(bio_err
, "Only one test type may be given\n");
307 n
= test_get_argument_count();
308 if (spki
&& n
== 1) {
309 pubkey_filename
= test_get_argument(0);
310 } else if (x509
&& n
== 2) {
311 eecert_filename
= test_get_argument(0);
312 cacert_filename
= test_get_argument(1);
315 if (spki
&& pubkey_filename
== NULL
) {
316 BIO_printf(bio_err
, "Missing -spki argument\n");
318 } else if (x509
&& (eecert_filename
== NULL
|| cacert_filename
== NULL
)) {
319 BIO_printf(bio_err
, "Missing -x509 argument(s)\n");
324 ADD_TEST(test_x509_files
);
326 ADD_TEST(test_spki_file
);