1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include <openssl/asn1.h> 11e1051a39Sopenharmony_ci#include <openssl/pem.h> 12e1051a39Sopenharmony_ci#include "internal/sizes.h" 13e1051a39Sopenharmony_ci#include "crypto/evp.h" 14e1051a39Sopenharmony_ci#include "testutil.h" 15e1051a39Sopenharmony_ci 16e1051a39Sopenharmony_ci/* Collected arguments */ 17e1051a39Sopenharmony_cistatic const char *eecert_filename = NULL; /* For test_x509_file() */ 18e1051a39Sopenharmony_cistatic const char *cacert_filename = NULL; /* For test_x509_file() */ 19e1051a39Sopenharmony_cistatic const char *pubkey_filename = NULL; /* For test_spki_file() */ 20e1051a39Sopenharmony_ci 21e1051a39Sopenharmony_ci#define ALGORITHMID_NAME "algorithm-id" 22e1051a39Sopenharmony_ci 23e1051a39Sopenharmony_cistatic int test_spki_aid(X509_PUBKEY *pubkey, const char *filename) 24e1051a39Sopenharmony_ci{ 25e1051a39Sopenharmony_ci const ASN1_OBJECT *oid; 26e1051a39Sopenharmony_ci X509_ALGOR *alg = NULL; 27e1051a39Sopenharmony_ci EVP_PKEY *pkey = NULL; 28e1051a39Sopenharmony_ci EVP_KEYMGMT *keymgmt = NULL; 29e1051a39Sopenharmony_ci void *keydata = NULL; 30e1051a39Sopenharmony_ci char name[OSSL_MAX_NAME_SIZE] = ""; 31e1051a39Sopenharmony_ci unsigned char *algid_legacy = NULL; 32e1051a39Sopenharmony_ci int algid_legacy_len = 0; 33e1051a39Sopenharmony_ci static unsigned char algid_prov[OSSL_MAX_ALGORITHM_ID_SIZE]; 34e1051a39Sopenharmony_ci size_t algid_prov_len = 0; 35e1051a39Sopenharmony_ci const OSSL_PARAM *gettable_params = NULL; 36e1051a39Sopenharmony_ci OSSL_PARAM params[] = { 37e1051a39Sopenharmony_ci OSSL_PARAM_octet_string(ALGORITHMID_NAME, 38e1051a39Sopenharmony_ci &algid_prov, sizeof(algid_prov)), 39e1051a39Sopenharmony_ci OSSL_PARAM_END 40e1051a39Sopenharmony_ci }; 41e1051a39Sopenharmony_ci int ret = 0; 42e1051a39Sopenharmony_ci 43e1051a39Sopenharmony_ci if (!TEST_true(X509_PUBKEY_get0_param(NULL, NULL, NULL, &alg, pubkey)) 44e1051a39Sopenharmony_ci || !TEST_ptr(pkey = X509_PUBKEY_get0(pubkey))) 45e1051a39Sopenharmony_ci goto end; 46e1051a39Sopenharmony_ci 47e1051a39Sopenharmony_ci if (!TEST_int_ge(algid_legacy_len = i2d_X509_ALGOR(alg, &algid_legacy), 0)) 48e1051a39Sopenharmony_ci goto end; 49e1051a39Sopenharmony_ci 50e1051a39Sopenharmony_ci X509_ALGOR_get0(&oid, NULL, NULL, alg); 51e1051a39Sopenharmony_ci if (!TEST_int_gt(OBJ_obj2txt(name, sizeof(name), oid, 0), 0)) 52e1051a39Sopenharmony_ci goto end; 53e1051a39Sopenharmony_ci 54e1051a39Sopenharmony_ci /* 55e1051a39Sopenharmony_ci * We use an internal functions to ensure we have a provided key. 56e1051a39Sopenharmony_ci * Note that |keydata| should not be freed, as it's cached in |pkey|. 57e1051a39Sopenharmony_ci * The |keymgmt|, however, should, as its reference count is incremented 58e1051a39Sopenharmony_ci * in this function. 59e1051a39Sopenharmony_ci */ 60e1051a39Sopenharmony_ci if ((keydata = evp_pkey_export_to_provider(pkey, NULL, 61e1051a39Sopenharmony_ci &keymgmt, NULL)) == NULL) { 62e1051a39Sopenharmony_ci TEST_info("The public key found in '%s' doesn't have provider support." 63e1051a39Sopenharmony_ci " Skipping...", 64e1051a39Sopenharmony_ci filename); 65e1051a39Sopenharmony_ci ret = 1; 66e1051a39Sopenharmony_ci goto end; 67e1051a39Sopenharmony_ci } 68e1051a39Sopenharmony_ci 69e1051a39Sopenharmony_ci if (!TEST_true(EVP_KEYMGMT_is_a(keymgmt, name))) { 70e1051a39Sopenharmony_ci TEST_info("The AlgorithmID key type (%s) for the public key found in" 71e1051a39Sopenharmony_ci " '%s' doesn't match the key type of the extracted public" 72e1051a39Sopenharmony_ci " key.", 73e1051a39Sopenharmony_ci name, filename); 74e1051a39Sopenharmony_ci ret = 1; 75e1051a39Sopenharmony_ci goto end; 76e1051a39Sopenharmony_ci } 77e1051a39Sopenharmony_ci 78e1051a39Sopenharmony_ci if (!TEST_ptr(gettable_params = EVP_KEYMGMT_gettable_params(keymgmt)) 79e1051a39Sopenharmony_ci || !TEST_ptr(OSSL_PARAM_locate_const(gettable_params, ALGORITHMID_NAME))) { 80e1051a39Sopenharmony_ci TEST_info("The %s provider keymgmt appears to lack support for algorithm-id." 81e1051a39Sopenharmony_ci " Skipping...", 82e1051a39Sopenharmony_ci name); 83e1051a39Sopenharmony_ci ret = 1; 84e1051a39Sopenharmony_ci goto end; 85e1051a39Sopenharmony_ci } 86e1051a39Sopenharmony_ci 87e1051a39Sopenharmony_ci algid_prov[0] = '\0'; 88e1051a39Sopenharmony_ci if (!TEST_true(evp_keymgmt_get_params(keymgmt, keydata, params))) 89e1051a39Sopenharmony_ci goto end; 90e1051a39Sopenharmony_ci algid_prov_len = params[0].return_size; 91e1051a39Sopenharmony_ci 92e1051a39Sopenharmony_ci /* We now have all the algorithm IDs we need, let's compare them */ 93e1051a39Sopenharmony_ci if (TEST_mem_eq(algid_legacy, algid_legacy_len, 94e1051a39Sopenharmony_ci algid_prov, algid_prov_len)) 95e1051a39Sopenharmony_ci ret = 1; 96e1051a39Sopenharmony_ci 97e1051a39Sopenharmony_ci end: 98e1051a39Sopenharmony_ci EVP_KEYMGMT_free(keymgmt); 99e1051a39Sopenharmony_ci OPENSSL_free(algid_legacy); 100e1051a39Sopenharmony_ci return ret; 101e1051a39Sopenharmony_ci} 102e1051a39Sopenharmony_ci 103e1051a39Sopenharmony_cistatic int test_x509_spki_aid(X509 *cert, const char *filename) 104e1051a39Sopenharmony_ci{ 105e1051a39Sopenharmony_ci X509_PUBKEY *pubkey = X509_get_X509_PUBKEY(cert); 106e1051a39Sopenharmony_ci 107e1051a39Sopenharmony_ci return test_spki_aid(pubkey, filename); 108e1051a39Sopenharmony_ci} 109e1051a39Sopenharmony_ci 110e1051a39Sopenharmony_cistatic int test_x509_sig_aid(X509 *eecert, const char *ee_filename, 111e1051a39Sopenharmony_ci X509 *cacert, const char *ca_filename) 112e1051a39Sopenharmony_ci{ 113e1051a39Sopenharmony_ci const ASN1_OBJECT *sig_oid = NULL; 114e1051a39Sopenharmony_ci const X509_ALGOR *alg = NULL; 115e1051a39Sopenharmony_ci int sig_nid = NID_undef, dig_nid = NID_undef, pkey_nid = NID_undef; 116e1051a39Sopenharmony_ci EVP_MD_CTX *mdctx = NULL; 117e1051a39Sopenharmony_ci EVP_PKEY_CTX *pctx = NULL; 118e1051a39Sopenharmony_ci EVP_PKEY *pkey = NULL; 119e1051a39Sopenharmony_ci unsigned char *algid_legacy = NULL; 120e1051a39Sopenharmony_ci int algid_legacy_len = 0; 121e1051a39Sopenharmony_ci static unsigned char algid_prov[OSSL_MAX_ALGORITHM_ID_SIZE]; 122e1051a39Sopenharmony_ci size_t algid_prov_len = 0; 123e1051a39Sopenharmony_ci const OSSL_PARAM *gettable_params = NULL; 124e1051a39Sopenharmony_ci OSSL_PARAM params[] = { 125e1051a39Sopenharmony_ci OSSL_PARAM_octet_string("algorithm-id", 126e1051a39Sopenharmony_ci &algid_prov, sizeof(algid_prov)), 127e1051a39Sopenharmony_ci OSSL_PARAM_END 128e1051a39Sopenharmony_ci }; 129e1051a39Sopenharmony_ci int ret = 0; 130e1051a39Sopenharmony_ci 131e1051a39Sopenharmony_ci X509_get0_signature(NULL, &alg, eecert); 132e1051a39Sopenharmony_ci X509_ALGOR_get0(&sig_oid, NULL, NULL, alg); 133e1051a39Sopenharmony_ci if (!TEST_int_eq(X509_ALGOR_cmp(alg, X509_get0_tbs_sigalg(eecert)), 0)) 134e1051a39Sopenharmony_ci goto end; 135e1051a39Sopenharmony_ci if (!TEST_int_ne(sig_nid = OBJ_obj2nid(sig_oid), NID_undef) 136e1051a39Sopenharmony_ci || !TEST_true(OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) 137e1051a39Sopenharmony_ci || !TEST_ptr(pkey = X509_get0_pubkey(cacert))) 138e1051a39Sopenharmony_ci goto end; 139e1051a39Sopenharmony_ci 140e1051a39Sopenharmony_ci if (!TEST_true(EVP_PKEY_is_a(pkey, OBJ_nid2sn(pkey_nid)))) { 141e1051a39Sopenharmony_ci TEST_info("The '%s' pubkey can't be used to verify the '%s' signature", 142e1051a39Sopenharmony_ci ca_filename, ee_filename); 143e1051a39Sopenharmony_ci TEST_info("Signature algorithm is %s (pkey type %s, hash type %s)", 144e1051a39Sopenharmony_ci OBJ_nid2sn(sig_nid), OBJ_nid2sn(pkey_nid), OBJ_nid2sn(dig_nid)); 145e1051a39Sopenharmony_ci TEST_info("Pkey key type is %s", EVP_PKEY_get0_type_name(pkey)); 146e1051a39Sopenharmony_ci goto end; 147e1051a39Sopenharmony_ci } 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ci if (!TEST_int_ge(algid_legacy_len = i2d_X509_ALGOR(alg, &algid_legacy), 0)) 150e1051a39Sopenharmony_ci goto end; 151e1051a39Sopenharmony_ci 152e1051a39Sopenharmony_ci if (!TEST_ptr(mdctx = EVP_MD_CTX_new()) 153e1051a39Sopenharmony_ci || !TEST_true(EVP_DigestVerifyInit_ex(mdctx, &pctx, 154e1051a39Sopenharmony_ci OBJ_nid2sn(dig_nid), 155e1051a39Sopenharmony_ci NULL, NULL, pkey, NULL))) { 156e1051a39Sopenharmony_ci TEST_info("Couldn't initialize a DigestVerify operation with " 157e1051a39Sopenharmony_ci "pkey type %s and hash type %s", 158e1051a39Sopenharmony_ci OBJ_nid2sn(pkey_nid), OBJ_nid2sn(dig_nid)); 159e1051a39Sopenharmony_ci goto end; 160e1051a39Sopenharmony_ci } 161e1051a39Sopenharmony_ci 162e1051a39Sopenharmony_ci if (!TEST_ptr(gettable_params = EVP_PKEY_CTX_gettable_params(pctx)) 163e1051a39Sopenharmony_ci || !TEST_ptr(OSSL_PARAM_locate_const(gettable_params, ALGORITHMID_NAME))) { 164e1051a39Sopenharmony_ci TEST_info("The %s provider keymgmt appears to lack support for algorithm-id" 165e1051a39Sopenharmony_ci " Skipping...", 166e1051a39Sopenharmony_ci OBJ_nid2sn(pkey_nid)); 167e1051a39Sopenharmony_ci ret = 1; 168e1051a39Sopenharmony_ci goto end; 169e1051a39Sopenharmony_ci } 170e1051a39Sopenharmony_ci 171e1051a39Sopenharmony_ci algid_prov[0] = '\0'; 172e1051a39Sopenharmony_ci if (!TEST_true(EVP_PKEY_CTX_get_params(pctx, params))) 173e1051a39Sopenharmony_ci goto end; 174e1051a39Sopenharmony_ci algid_prov_len = params[0].return_size; 175e1051a39Sopenharmony_ci 176e1051a39Sopenharmony_ci /* We now have all the algorithm IDs we need, let's compare them */ 177e1051a39Sopenharmony_ci if (TEST_mem_eq(algid_legacy, algid_legacy_len, 178e1051a39Sopenharmony_ci algid_prov, algid_prov_len)) 179e1051a39Sopenharmony_ci ret = 1; 180e1051a39Sopenharmony_ci 181e1051a39Sopenharmony_ci end: 182e1051a39Sopenharmony_ci EVP_MD_CTX_free(mdctx); 183e1051a39Sopenharmony_ci /* pctx is free by EVP_MD_CTX_free() */ 184e1051a39Sopenharmony_ci OPENSSL_free(algid_legacy); 185e1051a39Sopenharmony_ci return ret; 186e1051a39Sopenharmony_ci} 187e1051a39Sopenharmony_ci 188e1051a39Sopenharmony_cistatic int test_spki_file(void) 189e1051a39Sopenharmony_ci{ 190e1051a39Sopenharmony_ci X509_PUBKEY *pubkey = NULL; 191e1051a39Sopenharmony_ci BIO *b = BIO_new_file(pubkey_filename, "r"); 192e1051a39Sopenharmony_ci int ret = 0; 193e1051a39Sopenharmony_ci 194e1051a39Sopenharmony_ci if (b == NULL) { 195e1051a39Sopenharmony_ci TEST_error("Couldn't open '%s' for reading\n", pubkey_filename); 196e1051a39Sopenharmony_ci TEST_openssl_errors(); 197e1051a39Sopenharmony_ci goto end; 198e1051a39Sopenharmony_ci } 199e1051a39Sopenharmony_ci 200e1051a39Sopenharmony_ci if ((pubkey = PEM_read_bio_X509_PUBKEY(b, NULL, NULL, NULL)) == NULL) { 201e1051a39Sopenharmony_ci TEST_error("'%s' doesn't appear to be a SubjectPublicKeyInfo in PEM format\n", 202e1051a39Sopenharmony_ci pubkey_filename); 203e1051a39Sopenharmony_ci TEST_openssl_errors(); 204e1051a39Sopenharmony_ci goto end; 205e1051a39Sopenharmony_ci } 206e1051a39Sopenharmony_ci 207e1051a39Sopenharmony_ci ret = test_spki_aid(pubkey, pubkey_filename); 208e1051a39Sopenharmony_ci end: 209e1051a39Sopenharmony_ci BIO_free(b); 210e1051a39Sopenharmony_ci X509_PUBKEY_free(pubkey); 211e1051a39Sopenharmony_ci return ret; 212e1051a39Sopenharmony_ci} 213e1051a39Sopenharmony_ci 214e1051a39Sopenharmony_cistatic int test_x509_files(void) 215e1051a39Sopenharmony_ci{ 216e1051a39Sopenharmony_ci X509 *eecert = NULL, *cacert = NULL; 217e1051a39Sopenharmony_ci BIO *bee = NULL, *bca = NULL; 218e1051a39Sopenharmony_ci int ret = 0; 219e1051a39Sopenharmony_ci 220e1051a39Sopenharmony_ci if ((bee = BIO_new_file(eecert_filename, "r")) == NULL) { 221e1051a39Sopenharmony_ci TEST_error("Couldn't open '%s' for reading\n", eecert_filename); 222e1051a39Sopenharmony_ci TEST_openssl_errors(); 223e1051a39Sopenharmony_ci goto end; 224e1051a39Sopenharmony_ci } 225e1051a39Sopenharmony_ci if ((bca = BIO_new_file(cacert_filename, "r")) == NULL) { 226e1051a39Sopenharmony_ci TEST_error("Couldn't open '%s' for reading\n", cacert_filename); 227e1051a39Sopenharmony_ci TEST_openssl_errors(); 228e1051a39Sopenharmony_ci goto end; 229e1051a39Sopenharmony_ci } 230e1051a39Sopenharmony_ci 231e1051a39Sopenharmony_ci if ((eecert = PEM_read_bio_X509(bee, NULL, NULL, NULL)) == NULL) { 232e1051a39Sopenharmony_ci TEST_error("'%s' doesn't appear to be a X.509 certificate in PEM format\n", 233e1051a39Sopenharmony_ci eecert_filename); 234e1051a39Sopenharmony_ci TEST_openssl_errors(); 235e1051a39Sopenharmony_ci goto end; 236e1051a39Sopenharmony_ci } 237e1051a39Sopenharmony_ci if ((cacert = PEM_read_bio_X509(bca, NULL, NULL, NULL)) == NULL) { 238e1051a39Sopenharmony_ci TEST_error("'%s' doesn't appear to be a X.509 certificate in PEM format\n", 239e1051a39Sopenharmony_ci cacert_filename); 240e1051a39Sopenharmony_ci TEST_openssl_errors(); 241e1051a39Sopenharmony_ci goto end; 242e1051a39Sopenharmony_ci } 243e1051a39Sopenharmony_ci 244e1051a39Sopenharmony_ci ret = test_x509_sig_aid(eecert, eecert_filename, cacert, cacert_filename) 245e1051a39Sopenharmony_ci & test_x509_spki_aid(eecert, eecert_filename) 246e1051a39Sopenharmony_ci & test_x509_spki_aid(cacert, cacert_filename); 247e1051a39Sopenharmony_ci end: 248e1051a39Sopenharmony_ci BIO_free(bee); 249e1051a39Sopenharmony_ci BIO_free(bca); 250e1051a39Sopenharmony_ci X509_free(eecert); 251e1051a39Sopenharmony_ci X509_free(cacert); 252e1051a39Sopenharmony_ci return ret; 253e1051a39Sopenharmony_ci} 254e1051a39Sopenharmony_ci 255e1051a39Sopenharmony_citypedef enum OPTION_choice { 256e1051a39Sopenharmony_ci OPT_ERR = -1, 257e1051a39Sopenharmony_ci OPT_EOF = 0, 258e1051a39Sopenharmony_ci OPT_X509, 259e1051a39Sopenharmony_ci OPT_SPKI, 260e1051a39Sopenharmony_ci OPT_TEST_ENUM 261e1051a39Sopenharmony_ci} OPTION_CHOICE; 262e1051a39Sopenharmony_ci 263e1051a39Sopenharmony_ciconst OPTIONS *test_get_options(void) 264e1051a39Sopenharmony_ci{ 265e1051a39Sopenharmony_ci static const OPTIONS test_options[] = { 266e1051a39Sopenharmony_ci OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("file...\n"), 267e1051a39Sopenharmony_ci { "x509", OPT_X509, '-', "Test X.509 certificates. Requires two files" }, 268e1051a39Sopenharmony_ci { "spki", OPT_SPKI, '-', "Test public keys in SubjectPublicKeyInfo form. Requires one file" }, 269e1051a39Sopenharmony_ci { OPT_HELP_STR, 1, '-', 270e1051a39Sopenharmony_ci "file...\tFile(s) to run tests on. All files must be PEM encoded.\n" }, 271e1051a39Sopenharmony_ci { NULL } 272e1051a39Sopenharmony_ci }; 273e1051a39Sopenharmony_ci return test_options; 274e1051a39Sopenharmony_ci} 275e1051a39Sopenharmony_ci 276e1051a39Sopenharmony_ciint setup_tests(void) 277e1051a39Sopenharmony_ci{ 278e1051a39Sopenharmony_ci OPTION_CHOICE o; 279e1051a39Sopenharmony_ci int n, x509 = 0, spki = 0, testcount = 0; 280e1051a39Sopenharmony_ci 281e1051a39Sopenharmony_ci while ((o = opt_next()) != OPT_EOF) { 282e1051a39Sopenharmony_ci switch (o) { 283e1051a39Sopenharmony_ci case OPT_X509: 284e1051a39Sopenharmony_ci x509 = 1; 285e1051a39Sopenharmony_ci break; 286e1051a39Sopenharmony_ci case OPT_SPKI: 287e1051a39Sopenharmony_ci spki = 1; 288e1051a39Sopenharmony_ci break; 289e1051a39Sopenharmony_ci case OPT_TEST_CASES: 290e1051a39Sopenharmony_ci break; 291e1051a39Sopenharmony_ci default: 292e1051a39Sopenharmony_ci case OPT_ERR: 293e1051a39Sopenharmony_ci return 0; 294e1051a39Sopenharmony_ci } 295e1051a39Sopenharmony_ci } 296e1051a39Sopenharmony_ci 297e1051a39Sopenharmony_ci /* |testcount| adds all the given test types together */ 298e1051a39Sopenharmony_ci testcount = x509 + spki; 299e1051a39Sopenharmony_ci 300e1051a39Sopenharmony_ci if (testcount < 1) 301e1051a39Sopenharmony_ci BIO_printf(bio_err, "No test type given\n"); 302e1051a39Sopenharmony_ci else if (testcount > 1) 303e1051a39Sopenharmony_ci BIO_printf(bio_err, "Only one test type may be given\n"); 304e1051a39Sopenharmony_ci if (testcount != 1) 305e1051a39Sopenharmony_ci return 0; 306e1051a39Sopenharmony_ci 307e1051a39Sopenharmony_ci n = test_get_argument_count(); 308e1051a39Sopenharmony_ci if (spki && n == 1) { 309e1051a39Sopenharmony_ci pubkey_filename = test_get_argument(0); 310e1051a39Sopenharmony_ci } else if (x509 && n == 2) { 311e1051a39Sopenharmony_ci eecert_filename = test_get_argument(0); 312e1051a39Sopenharmony_ci cacert_filename = test_get_argument(1); 313e1051a39Sopenharmony_ci } 314e1051a39Sopenharmony_ci 315e1051a39Sopenharmony_ci if (spki && pubkey_filename == NULL) { 316e1051a39Sopenharmony_ci BIO_printf(bio_err, "Missing -spki argument\n"); 317e1051a39Sopenharmony_ci return 0; 318e1051a39Sopenharmony_ci } else if (x509 && (eecert_filename == NULL || cacert_filename == NULL)) { 319e1051a39Sopenharmony_ci BIO_printf(bio_err, "Missing -x509 argument(s)\n"); 320e1051a39Sopenharmony_ci return 0; 321e1051a39Sopenharmony_ci } 322e1051a39Sopenharmony_ci 323e1051a39Sopenharmony_ci if (x509) 324e1051a39Sopenharmony_ci ADD_TEST(test_x509_files); 325e1051a39Sopenharmony_ci if (spki) 326e1051a39Sopenharmony_ci ADD_TEST(test_spki_file); 327e1051a39Sopenharmony_ci return 1; 328e1051a39Sopenharmony_ci} 329