2#include <winpr/string.h>
3#include <winpr/print.h>
5#include <freerdp/crypto/certificate.h>
7#include "../x509_utils.h"
9typedef char* (*get_field_pr)(
const X509*);
17 const char* field_description;
18 get_field_pr get_field;
19 const char* expected_result;
22static char* x509_utils_subject_common_name_wo_length(
const X509* xcert)
25 return x509_utils_get_common_name(xcert, &length);
28static char* certificate_path(
const char* filename)
36 static const char dirsep =
'/';
38 const char* file = TEST_SOURCE_DIR;
39 const size_t flen = strlen(file) +
sizeof(dirsep) + strlen(filename) +
sizeof(char);
40 char* result = calloc(1, flen);
43 (void)_snprintf(result, flen,
"%s%c%s", file, dirsep, filename);
46 const char* file = __FILE__;
47 const char* last_dirsep = strrchr(file, dirsep);
51 const size_t filenameLen = strlen(filename);
52 const size_t dirsepLen = last_dirsep - file + 1;
53 char* result = malloc(dirsepLen + filenameLen + 1);
56 strncpy(result, file, dirsepLen);
57 strncpy(result + dirsepLen, filename, filenameLen + 1);
63 return _strdup(filename);
68static const certificate_test_t certificate_tests[] = {
70 { ENABLED,
"Certificate Common Name", x509_utils_subject_common_name_wo_length,
71 "TESTJEAN TESTMARTIN 9999999" },
73 { ENABLED,
"Certificate subject", x509_utils_get_subject,
74 "CN = TESTJEAN TESTMARTIN 9999999, C = FR, O = MINISTERE DES TESTS, OU = 0002 110014016, OU "
75 "= PERSONNES, UID = 9999999, GN = TESTJEAN, SN = TESTMARTIN" },
77 { DISABLED,
"Kerberos principal name",
nullptr,
"testjean.testmartin@kpn.test.example.com" },
79 { ENABLED,
"Certificate e-mail", x509_utils_get_email,
"testjean.testmartin@test.example.com"
83 { ENABLED,
"Microsoft's Universal Principal Name", x509_utils_get_upn,
84 "testjean.testmartin.9999999@upn.test.example.com" },
86 { ENABLED,
"Certificate issuer", x509_utils_get_issuer,
87 "CN = ADMINISTRATION CENTRALE DES TESTS, C = FR, O = MINISTERE DES TESTS, OU = 0002 "
91static int TestCertificateFile(
const char* certificate_path,
92 const certificate_test_t* ccertificate_tests,
size_t count)
96 X509* certificate = x509_utils_from_pem(certificate_path, strlen(certificate_path), TRUE);
100 printf(
"%s: failure: cannot read certificate file '%s'\n", __func__, certificate_path);
105 for (
size_t i = 0; i < count; i++)
107 const certificate_test_t* test = &ccertificate_tests[i];
108 char* result =
nullptr;
110 if (test->status == DISABLED)
115 result = (test->get_field ? test->get_field(certificate) :
nullptr);
119 printf(
"%s: crypto got %-40s -> \"%s\"\n", __func__, test->field_description, result);
121 if (0 != strcmp(result, test->expected_result))
123 printf(
"%s: failure: for %s, actual: \"%s\", expected \"%s\"\n", __func__,
124 test->field_description, result, test->expected_result);
132 printf(
"%s: failure: cannot get %s\n", __func__, test->field_description);
137 X509_free(certificate);
166 const char* filename;
167 WINPR_MD_TYPE expected;
168} signature_alg_test_t;
170static const signature_alg_test_t signature_alg_tests[] = {
171 {
"rsa_pkcs1_sha1_cert.pem", WINPR_MD_SHA1 },
172 {
"rsa_pkcs1_sha256_cert.pem", WINPR_MD_SHA256 },
173 {
"rsa_pkcs1_sha384_cert.pem", WINPR_MD_SHA384 },
174 {
"rsa_pkcs1_sha512_cert.pem", WINPR_MD_SHA512 },
176 {
"ecdsa_sha1_cert.pem", WINPR_MD_SHA1 },
177 {
"ecdsa_sha256_cert.pem", WINPR_MD_SHA256 },
178 {
"ecdsa_sha384_cert.pem", WINPR_MD_SHA384 },
179 {
"ecdsa_sha512_cert.pem", WINPR_MD_SHA512 },
181 {
"rsa_pss_sha1_cert.pem", WINPR_MD_SHA1 },
182 {
"rsa_pss_sha256_cert.pem", WINPR_MD_SHA256 },
183 {
"rsa_pss_sha384_cert.pem", WINPR_MD_SHA384 },
184 {
"rsa_pss_sha512_cert.pem", WINPR_MD_SHA512 },
189 {
"rsa_pss_sha256_mgf1_sha384_cert.pem", WINPR_MD_NONE },
192static int TestSignatureAlgorithm(
const signature_alg_test_t* test)
195 WINPR_MD_TYPE signature_alg = WINPR_MD_NONE;
196 char* path = certificate_path(test->filename);
197 X509* certificate = x509_utils_from_pem(path, strlen(path), TRUE);
201 printf(
"%s: failure: cannot read certificate file '%s'\n", __func__, path);
206 signature_alg = x509_utils_get_signature_alg(certificate);
207 if (signature_alg != test->expected)
209 const char* signature_alg_string =
210 signature_alg == WINPR_MD_NONE ?
"none" : winpr_md_type_to_string(signature_alg);
211 const char* expected_string =
212 test->expected == WINPR_MD_NONE ?
"none" : winpr_md_type_to_string(test->expected);
213 printf(
"%s: failure: for \"%s\", actual: %s, expected %s\n", __func__, test->filename,
214 signature_alg_string, expected_string);
220 X509_free(certificate);
237 const char* filename;
243static const hashless_test_t hashless_tests[] = {
244#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(LIBRESSL_VERSION_NUMBER)
245 {
"ed25519_cert.pem",
"sha512", 64,
246 "C90BB22E50EB78613F5653A90F62DEF03E08BCFDC125748980073D0ECEACE02AE31EAA9EA13A199BAAB11B1241DE"
247 "9FEDECEE70C6B1A26D661B27FAF70DD8687F" },
248 {
"ed448_cert.pem",
"SHAKE256", 32,
249 "C72FF0B946C03583BAB0827497EE9601F8E45551A9C2E6E20C2AC95C31688298" },
250#if OPENSSL_VERSION_NUMBER >= 0x30500000L
251 {
"ml_dsa_87_cert.pem",
"sha256", 32,
252 "8862AE0B056198D99A0FBEC3596B59683E79EB3863058BD57896AAEBBD761931" },
255 {
"rsa_pkcs1_sha256_cert.pem",
nullptr, 0,
nullptr },
256 {
"ecdsa_sha384_cert.pem",
nullptr, 0,
nullptr },
257 {
"rsa_pss_sha256_mgf1_sha384_cert.pem",
nullptr, 0,
nullptr },
260static int TestHashlessSignatureHash(
const hashless_test_t* test)
264 BYTE* hash =
nullptr;
265 BYTE* expected =
nullptr;
266 size_t expected_length = 0;
267 char* path = certificate_path(test->filename);
268 X509* certificate = path ? x509_utils_from_pem(path, strlen(path), TRUE) : nullptr;
272 printf(
"%s: failure: cannot read certificate file '%s'\n", __func__,
273 path ? path :
"(null)");
277 hash = x509_utils_get_hashless_signature_hash(certificate, &length);
278 if (test->len != length)
280 printf(
"%s: failure: \"%s\" has a return length %" PRIuz
", but expected %" PRIuz
"\n",
281 __func__, test->filename, length, test->len);
289 printf(
"%s: failure: \"%s\" has a hash in its signature algorithm\n", __func__,
298 char* cmp = winpr_BinToHexString(hash, length, FALSE);
301 printf(
"%s: failure: \"%s\" has a hash of type %s but could not convert data to HEX\n",
302 __func__, test->filename, test->hash);
305 const int c = memcmp(cmp, test->data, test->len);
311 expected = x509_utils_get_hash(certificate, test->hash, &expected_length);
312 winpr_HexDump(
"testtest", WLOG_INFO, expected, expected_length);
313 if (!hash || !expected || (length != expected_length) || (memcmp(hash, expected, length) != 0))
315 printf(
"%s: failure: \"%s\" is not hashed with %s\n", __func__, test->filename, test->hash);
322 X509_free(certificate);
328static int TestPublicKey(
const char* filename)
332 DWORD key_length = 0;
333 const unsigned char* spk =
nullptr;
335 char* path = certificate_path(filename);
336 X509* x509 = path ? x509_utils_from_pem(path, strlen(path), TRUE) : nullptr;
337 rdpCertificate* certificate = path ? freerdp_certificate_new_from_file(path) : nullptr;
339 if (!x509 || !certificate ||
340 (X509_PUBKEY_get0_param(
nullptr, &spk, &spk_length,
nullptr, X509_get_X509_PUBKEY(x509)) !=
343 printf(
"%s: failure: cannot read certificate file '%s'\n", __func__,
344 path ? path :
"(null)");
348 if (!freerdp_certificate_get_public_key(certificate, &key, &key_length) ||
349 (key_length != (DWORD)spk_length) || (memcmp(key, spk, key_length) != 0))
351 printf(
"%s: failure: \"%s\" public key is not its SubjectPublicKey\n", __func__, filename);
357 freerdp_certificate_free(certificate);
363static const char* public_key_tests[] = {
364 "rsa_pkcs1_sha256_cert.pem",
365 "ecdsa_sha256_cert.pem",
366#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(LIBRESSL_VERSION_NUMBER)
368#if OPENSSL_VERSION_NUMBER >= 0x30500000L
369 "ml_dsa_87_cert.pem",
380static int TestWildcardNames(
void)
384 size_t* lengths =
nullptr;
385 char** names =
nullptr;
386 char* common_name =
nullptr;
387 char* path = certificate_path(
"Test_x509_wildcard_cert.pem");
388 X509* certificate = path ? x509_utils_from_pem(path, strlen(path), TRUE) : nullptr;
392 printf(
"%s: failure: cannot read certificate file '%s'\n", __func__,
393 path ? path :
"(null)");
397 common_name = x509_utils_get_common_name(certificate,
nullptr);
398 if (!common_name || (strcmp(common_name,
"*.wildcard.example.com") != 0))
400 printf(
"%s: failure: wildcard common name not returned: \"%s\"\n", __func__,
401 common_name ? common_name :
"(null)");
405 names = x509_utils_get_dns_names(certificate, &count, &lengths);
406 if (!names || (count != 2) || (strcmp(names[0],
"*.wildcard.example.com") != 0) ||
407 (strcmp(names[1],
"host.example.com") != 0))
409 printf(
"%s: failure: expected only the valid wildcard and host names, got %" PRIuz
"\n",
416 x509_utils_dns_names_free(count, lengths, names);
418 X509_free(certificate);
423int Test_x509_utils(
int argc,
char* argv[])
425 char* cert_path = certificate_path(
"Test_x509_cert_info.pem");
430 ret = TestCertificateFile(cert_path, certificate_tests, ARRAYSIZE(certificate_tests));
435 ret = TestWildcardNames();
439 for (
size_t i = 0; i < ARRAYSIZE(signature_alg_tests); i++)
441 ret = TestSignatureAlgorithm(&signature_alg_tests[i]);
446 for (
size_t i = 0; i < ARRAYSIZE(hashless_tests); i++)
448 ret = TestHashlessSignatureHash(&hashless_tests[i]);
453 for (
size_t i = 0; i < ARRAYSIZE(public_key_tests); i++)
455 ret = TestPublicKey(public_key_tests[i]);