34#if defined(HAVE_XKEY_PROVIDER) && defined(ENABLE_CRYPTOAPI)
37#include <openssl/bio.h>
38#include <openssl/pem.h>
39#include <openssl/core_names.h>
40#include <openssl/evp.h>
41#include <openssl/pkcs12.h>
65 while ((e = ERR_get_error()))
67 msg(flags,
"OpenSSL error %lu: %s", e, ERR_error_string(e, NULL));
75#define _countof(x) sizeof((x)) / sizeof(*(x))
79static const uint8_t test_hash[] = { 0x77, 0x38, 0x65, 0x00, 0x1e, 0x96, 0x48, 0xc6, 0x57, 0x0b,
80 0xae, 0xc0, 0xb7, 0x96, 0xf9, 0x66, 0x4d, 0x5f, 0xd0, 0xb7 };
83static const char *valid_str[] = {
84 "773865001e9648c6570baec0b796f9664d5fd0b7",
85 " 77 386500 1e 96 48 c6570b aec0b7 96f9664d5f d0 b7",
86 " 773865001e9648c6570baec0b796f9664d5fd0b7 ",
90static const char *invalid_str[] = {
91 "773 865001e9648c6570baec0b796f9664d5fd0b7",
92 "77:38:65001e9648c6570baec0b796f9664d5fd0b7",
93 "7738x5001e9648c6570baec0b796f9664d5fd0b7",
101 const char *
const cert;
102 const char *
const key;
103 const char *
const cname;
110static bool certs_loaded;
111static HCERTSTORE user_store;
124 assert(
sizeof(certs_local) ==
sizeof(
certs));
125 memcpy(
certs, certs_local,
sizeof(certs_local));
137 return c->
cert ? c : NULL;
142import_certs(
void **state)
151 CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
152 CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG, L
"MY");
153 assert_non_null(user_store);
157 const char *pass =
"opensesame";
158 const wchar_t *wpass = L
"opensesame";
161 EVP_PKEY *pkey = NULL;
163 BIO *buf = BIO_new_mem_buf(c->
cert, -1);
166 x509 = PEM_read_bio_X509(buf, NULL, NULL, NULL);
170 buf = BIO_new_mem_buf(c->
key, -1);
173 pkey = PEM_read_bio_PrivateKey(buf, NULL, NULL, NULL);
179 fail_msg(
"Failed to parse certificate/key data: <%s>", c->
friendly_name);
183 PKCS12 *p12 = PKCS12_create(pass, c->
friendly_name, pkey, x509, NULL, 0, 0, 0, 0, 0);
188 fail_msg(
"Failed to convert to PKCS12: <%s>", c->
friendly_name);
192 CRYPT_DATA_BLOB blob = { .cbData = 0, .pbData = NULL };
193 int len = i2d_PKCS12(p12, &blob.pbData);
196 fail_msg(
"Failed to DER encode PKCS12: <%s>", c->
friendly_name);
201 DWORD flags = PKCS12_ALLOW_OVERWRITE_KEY | PKCS12_ALWAYS_CNG_KSP;
202 HCERTSTORE tmp_store = PFXImportCertStore(&blob, wpass, flags);
204 OPENSSL_free(blob.pbData);
206 assert_non_null(tmp_store);
214 const CERT_CONTEXT *ctx = CertEnumCertificatesInStore(tmp_store, NULL);
215 assert_non_null(ctx);
216 bool added = CertAddCertificateContextToStore(user_store, ctx,
217 CERT_STORE_ADD_REPLACE_EXISTING, NULL);
220 CertFreeCertificateContext(ctx);
221 CertCloseStore(tmp_store, 0);
233 const CERT_CONTEXT *ctx = NULL;
234 while ((ctx = CertEnumCertificatesInStore(user_store, ctx)))
236 char *friendly_name = get_cert_name(ctx, &
gc);
237 if (!lookup_cert(friendly_name))
243 const CERT_CONTEXT *ctx_dup = CertDuplicateCertificateContext(ctx);
246 CertDeleteCertificateFromStore(ctx_dup);
250 CertCloseStore(user_store, 0);
253 certs_loaded =
false;
259test_find_cert_bythumb(
void **state)
262 char select_string[64];
264 const CERT_CONTEXT *ctx;
267 assert_non_null(user_store);
271 snprintf(select_string,
sizeof(select_string),
"THUMB:%s", c->
hash);
272 ctx = find_certificate_in_store(select_string, user_store);
276 assert_int_equal(c->valid, 1);
277 char *friendly_name = get_cert_name(ctx, &
gc);
279 CertFreeCertificateContext(ctx);
284 assert_int_equal(c->valid, 0);
292test_find_cert_byname(
void **state)
295 char select_string[64];
297 const CERT_CONTEXT *ctx;
300 assert_non_null(user_store);
304 snprintf(select_string,
sizeof(select_string),
"SUBJ:%s", c->
cname);
305 ctx = find_certificate_in_store(select_string, user_store);
311 assert_non_null(ctx);
313 char *friendly_name = get_cert_name(ctx, &
gc);
315 assert_non_null(found);
317 assert_int_equal(found->valid, 1);
318 CertFreeCertificateContext(ctx);
325test_find_cert_byissuer(
void **state)
328 char select_string[64];
330 const CERT_CONTEXT *ctx;
333 assert_non_null(user_store);
337 snprintf(select_string,
sizeof(select_string),
"ISSUER:%s", c->
issuer);
338 ctx = find_certificate_in_store(select_string, user_store);
344 assert_non_null(ctx);
346 char *friendly_name = get_cert_name(ctx, &
gc);
348 assert_non_null(found);
350 assert_int_equal(found->valid, 1);
351 CertFreeCertificateContext(ctx);
358setup_xkey_provider(
void **state)
363 prov[0] = OSSL_PROVIDER_load(
tls_libctx,
"default");
364 OSSL_PROVIDER_add_builtin(
tls_libctx,
"ovpn.xkey", xkey_provider_init);
365 prov[1] = OSSL_PROVIDER_load(
tls_libctx,
"ovpn.xkey");
368 EVP_set_default_properties(
tls_libctx,
"?provider!=ovpn.xkey");
373teardown_xkey_provider(
void **state)
376 for (
size_t i = 0;
i < _countof(prov);
i++)
380 OSSL_PROVIDER_unload(prov[
i]);
395test_cryptoapi_sign(
void **state)
398 char select_string[64];
400 EVP_PKEY *privkey = NULL;
403 assert_true(certs_loaded);
411 snprintf(select_string,
sizeof(select_string),
"THUMB:%s", c->
hash);
412 if (Load_CryptoAPI_certificate(select_string, &x509, &privkey) != 1)
414 fail_msg(
"Load_CryptoAPI_certificate failed: <%s>", c->
friendly_name);
417 EVP_PKEY *pubkey = X509_get0_pubkey(x509);
418 assert_non_null(pubkey);
421 EVP_PKEY_free(privkey);
429test_ssl_ctx_use_cryptoapicert(
void **state)
432 char select_string[64];
435 assert_true(certs_loaded);
444 assert_non_null(ssl_ctx);
446 snprintf(select_string,
sizeof(select_string),
"THUMB:%s", c->
hash);
449 fail_msg(
"SSL_CTX_use_CryptoAPI_certificate failed: <%s>", c->
friendly_name);
453 if (!SSL_CTX_check_private_key(ssl_ctx))
455 fail_msg(
"Certificate and private key in ssl_ctx do not match for <%s>",
460 SSL_CTX_free(ssl_ctx);
465test_parse_hexstring(
void **state)
467 unsigned char hash[255];
470 for (
int i = 0;
i < _countof(valid_str);
i++)
472 int len = parse_hexstring(valid_str[
i],
hash, _countof(
hash));
473 assert_int_equal(len,
sizeof(test_hash));
474 assert_memory_equal(
hash, test_hash,
sizeof(test_hash));
478 for (
int i = 0;
i < _countof(invalid_str);
i++)
480 int len = parse_hexstring(invalid_str[
i],
hash, _countof(
hash));
481 assert_int_equal(len, 0);
489 const struct CMUnitTest tests[] = {
490 cmocka_unit_test(test_parse_hexstring),
491 cmocka_unit_test(import_certs),
492 cmocka_unit_test(test_find_cert_bythumb),
493 cmocka_unit_test(test_find_cert_byname),
494 cmocka_unit_test(test_find_cert_byissuer),
495 cmocka_unit_test_setup_teardown(test_cryptoapi_sign, setup_xkey_provider,
496 teardown_xkey_provider),
497 cmocka_unit_test_setup_teardown(test_ssl_ctx_use_cryptoapicert, setup_xkey_provider,
498 teardown_xkey_provider),
501 int ret = cmocka_run_group_tests_name(
"cryptoapi tests", tests, NULL,
cleanup);
static void gc_free(struct gc_arena *a)
static struct gc_arena gc_new(void)
static const char *const cert2
static const char *const hash2
static const char *const cert3
static const char *const key3
static const char *const cert4
static const char *const cname2
static const char *const cname1
static const char *const hash3
static const char *const cname3
static const char *const cert1
static const char *const hash4
static const char *const key1
static const char *const hash1
void crypto_print_openssl_errors(const unsigned int flags)
Retrieve any occurred OpenSSL errors and print those errors.
int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
char * management_query_pk_sig(struct management *man, const char *b64_data, const char *algorithm)
#define SSL_CTX_new_ex(libctx, propq, method)
Reduce SSL_CTX_new_ex() to SSL_CTX_new() for OpenSSL < 3.
OSSL_LIB_CTX * tls_libctx
Garbage collection arena used to keep track of dynamically allocated memory.
const char *const friendly_name
static void openvpn_unit_test_setup(void)
Sets up the environment for unit tests like making both stderr and stdout non-buffered to avoid messa...
static struct test_cert certs[5]
static int cleanup(void **state)
void init_cert_data(void)
int digest_sign_verify(EVP_PKEY *privkey, EVP_PKEY *pubkey)