// SPDX-License-Identifier: Apache-2.0 // Copyright 2024 Pionix GmbH and Contributors to EVerest #include "gtest/gtest.h" #include #include #include #include #include #include #include #include #include #include bool operator==(const ::openssl::certificate_ptr& lhs, const ::openssl::certificate_ptr& rhs) { using ::openssl::certificate_to_pem; if (lhs && rhs) { const auto res_lhs = certificate_to_pem(lhs.get()); const auto res_rhs = certificate_to_pem(rhs.get()); return res_lhs == res_rhs; } return false; } namespace { template constexpr void setCharacters(T& dest, const std::string& s) { dest.charactersLen = s.size(); std::memcpy(&dest.characters[0], s.c_str(), s.size()); } template constexpr void setBytes(T& dest, const std::uint8_t* b, std::size_t len) { dest.bytesLen = len; std::memcpy(&dest.bytes[0], b, len); } struct test_vectors_t { const char* input; const std::uint8_t digest[32]; }; constexpr std::uint8_t sign_test[] = {0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; constexpr test_vectors_t sha_256_test[] = { {"", {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}}, {"abc", {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}}}; // EXI AuthorizationReq: checked okay (hash computes correctly) constexpr std::uint8_t iso_exi_a[] = {0x80, 0x04, 0x01, 0x52, 0x51, 0x0c, 0x40, 0x82, 0x9b, 0x7b, 0x6b, 0x29, 0x02, 0x93, 0x0b, 0x73, 0x23, 0x7b, 0x69, 0x02, 0x23, 0x0b, 0xa3, 0x09, 0xe8}; // checked okay constexpr std::uint8_t iso_exi_a_hash[] = {0xd1, 0xb5, 0xe0, 0x3d, 0x00, 0x65, 0xbe, 0xe5, 0x6b, 0x31, 0x79, 0x84, 0x45, 0x30, 0x51, 0xeb, 0x54, 0xca, 0x18, 0xfc, 0x0e, 0x09, 0x16, 0x17, 0x4f, 0x8b, 0x3c, 0x77, 0xa9, 0x8f, 0x4a, 0xa9}; // EXI AuthorizationReq signature block: checked okay (hash computes correctly) constexpr std::uint8_t iso_exi_b[] = { 0x80, 0x81, 0x12, 0xb4, 0x3a, 0x3a, 0x38, 0x1d, 0x17, 0x97, 0xbb, 0xbb, 0xbb, 0x97, 0x3b, 0x99, 0x97, 0x37, 0xb9, 0x33, 0x97, 0xaa, 0x29, 0x17, 0xb1, 0xb0, 0xb7, 0x37, 0xb7, 0x34, 0xb1, 0xb0, 0xb6, 0x16, 0xb2, 0xbc, 0x34, 0x97, 0xa1, 0xab, 0x43, 0xa3, 0xa3, 0x81, 0xd1, 0x79, 0x7b, 0xbb, 0xbb, 0xb9, 0x73, 0xb9, 0x99, 0x73, 0x7b, 0x93, 0x39, 0x79, 0x91, 0x81, 0x81, 0x89, 0x79, 0x81, 0xa1, 0x7b, 0xc3, 0x6b, 0x63, 0x23, 0x9b, 0x4b, 0x39, 0x6b, 0x6b, 0x7b, 0x93, 0x29, 0x1b, 0x2b, 0x1b, 0x23, 0x9b, 0x09, 0x6b, 0x9b, 0x43, 0x09, 0x91, 0xa9, 0xb2, 0x20, 0x62, 0x34, 0x94, 0x43, 0x10, 0x25, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x54, 0x52, 0x2f, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x2d, 0x65, 0x78, 0x69, 0x2f, 0x48, 0x52, 0xd0, 0xe8, 0xe8, 0xe0, 0x74, 0x5e, 0x5e, 0xee, 0xee, 0xee, 0x5c, 0xee, 0x66, 0x5c, 0xde, 0xe4, 0xce, 0x5e, 0x64, 0x60, 0x60, 0x62, 0x5e, 0x60, 0x68, 0x5e, 0xf0, 0xda, 0xd8, 0xca, 0xdc, 0xc6, 0x46, 0xe6, 0xd0, 0xc2, 0x64, 0x6a, 0x6c, 0x84, 0x1a, 0x36, 0xbc, 0x07, 0xa0, 0x0c, 0xb7, 0xdc, 0xad, 0x66, 0x2f, 0x30, 0x88, 0xa6, 0x0a, 0x3d, 0x6a, 0x99, 0x43, 0x1f, 0x81, 0xc1, 0x22, 0xc2, 0xe9, 0xf1, 0x67, 0x8e, 0xf5, 0x31, 0xe9, 0x55, 0x23, 0x70}; // checked okay constexpr std::uint8_t iso_exi_b_hash[] = {0xa4, 0xe9, 0x03, 0xe1, 0x82, 0x43, 0x04, 0x1b, 0x55, 0x4e, 0x11, 0x64, 0x7e, 0x10, 0x1e, 0xd2, 0x5f, 0xc9, 0xf2, 0x15, 0x2a, 0xf4, 0x67, 0x40, 0x14, 0xfe, 0x2a, 0xde, 0xac, 0x1e, 0x1c, 0xf7}; // checked okay (verifies iso_exi_b_hash with iso_priv.pem) constexpr std::uint8_t iso_exi_sig[] = {0x4c, 0x8f, 0x20, 0xc1, 0x40, 0x0b, 0xa6, 0x76, 0x06, 0xaa, 0x48, 0x11, 0x57, 0x2a, 0x2f, 0x1a, 0xd3, 0xc1, 0x50, 0x89, 0xd9, 0x54, 0x20, 0x36, 0x34, 0x30, 0xbb, 0x26, 0xb4, 0x9d, 0xb1, 0x04, 0xf0, 0x8d, 0xfa, 0x8b, 0xf8, 0x05, 0x5e, 0x63, 0xa4, 0xb7, 0x5a, 0x8d, 0x31, 0x69, 0x20, 0x6f, 0xa8, 0xd5, 0x43, 0x08, 0xba, 0x58, 0xf0, 0x56, 0x6b, 0x96, 0xba, 0xf6, 0x92, 0xce, 0x59, 0x50}; const char iso_exi_a_hash_b64[] = "0bXgPQBlvuVrMXmERTBR61TKGPwOCRYXT4s8d6mPSqk="; const char iso_exi_a_hash_b64_nl[] = "0bXgPQBlvuVrMXmERTBR61TKGPwOCRYXT4s8d6mPSqk=\n"; const char iso_exi_a_hash_b64_crlf[] = "0bXgPQBlvuVrMXmERTBR61TKGPwOCRYXT4s8d6mPSqk=\r\n"; const char iso_exi_a_hash_b64_cr[] = "0bXgPQBlvuVrMXmERTBR61TKGPwOCRYXT4s8d6mPSqk=\r"; const char iso_exi_a_hash_b64_spaces[] = "0bXgPQBlvuVr MXmERTBR61TK GPwOCRYXT4s8d6mPSqk="; const char iso_exi_a_hash_b64_tabs[] = "0bXgPQBlvuVr\tMXmERTBR61TKGPwOCRYXT4s8d6mPSqk="; const char iso_exi_sig_b64[] = "TI8gwUALpnYGqkgRVyovGtPBUInZVCA2NDC7JrSdsQTwjfqL+AVeY6S3Wo0xaSBvqNVDCLpY8FZrlrr2ks5ZUA=="; const char iso_exi_sig_b64_nl[] = "TI8gwUALpnYGqkgRVyovGtPBUInZVCA2NDC7JrSdsQTwjfqL+AVeY6S3Wo0xaSBv\nqNVDCLpY8FZrlrr2ks5ZUA==\n"; const char test_cert_pem[] = "-----BEGIN CERTIFICATE-----\n" "MIICBDCCAaqgAwIBAgIUQnMkyWtvc/a5OG8dZr9ziA5uQqYwCgYIKoZIzj0EAwIw\n" "TjELMAkGA1UEBhMCR0IxDzANBgNVBAcMBkxvbmRvbjEPMA0GA1UECgwGUGlvbml4\n" "MR0wGwYDVQQDDBRDUyBSb290IFRydXN0IEFuY2hvcjAeFw0yNDA5MTkxMzQwMDBa\n" "Fw0yNDEwMjExMzQwMDBaME4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQHDAZMb25kb24x\n" "DzANBgNVBAoMBlBpb25peDEdMBsGA1UEAwwUQ1MgUm9vdCBUcnVzdCBBbmNob3Iw\n" "WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARLkawitst5NtPoYGpDCp8/GBTDrNRJ\n" "pCzS3KHT2lZJDOwzegRn+Zhs0csqXIQgbkCqdSozg+d83QNKcpmJk4FYo2YwZDAO\n" "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFB6Ytfi9uSF7NSYGXmyZEcKsWHwJMB8G\n" "A1UdIwQYMBaAFB6Ytfi9uSF7NSYGXmyZEcKsWHwJMBIGA1UdEwEB/wQIMAYBAf8C\n" "AQIwCgYIKoZIzj0EAwIDSAAwRQIge4+uxc2EFYD7AkHR+9d/NbULUnKFIBRLqYE+\n" "Ib4h2CMCIQCtFWyvxwOUNidUTZGqyZXFmDyutJiNM0mi1iuFk8/8Mw==\n" "-----END CERTIFICATE-----\n"; const char test_cert_hash[] = "082f891b26de97c8bdedb159f8d59113cfb55dc0"; const char test_cert_key_hash[] = "3b094e5f2594a3ae4511a9ff4285acd91fcd11c0"; inline const auto to_hex_string(const openssl::sha_1_digest_t& b) { std::stringstream string_stream; string_stream << std::hex; for (int idx = 0; idx < sizeof(b); ++idx) string_stream << std::setw(2) << std::setfill('0') << (int)b[idx]; return string_stream.str(); } TEST(util, removeHyphen) { const std::string expected{"UKSWI123456791A"}; std::string cert_emaid{"UKSWI123456791A"}; EXPECT_EQ(cert_emaid, expected); cert_emaid.erase(std::remove(cert_emaid.begin(), cert_emaid.end(), '-'), cert_emaid.end()); EXPECT_EQ(cert_emaid, expected); cert_emaid = std::string{"-UKSWI-123456791-A-"}; cert_emaid.erase(std::remove(cert_emaid.begin(), cert_emaid.end(), '-'), cert_emaid.end()); EXPECT_EQ(cert_emaid, expected); } TEST(certificate_sha_1, hash) { auto cert = openssl::pem_to_certificate(test_cert_pem); EXPECT_TRUE(cert); openssl::sha_1_digest_t digest; auto res = openssl::certificate_sha_1(digest, cert.get()); EXPECT_TRUE(res); EXPECT_EQ(to_hex_string(digest), test_cert_hash); } TEST(certificate_subject_public_key_sha_1, hash) { auto cert = openssl::pem_to_certificate(test_cert_pem); EXPECT_TRUE(cert); openssl::sha_1_digest_t digest; auto res = openssl::certificate_subject_public_key_sha_1(digest, cert.get()); EXPECT_TRUE(res); EXPECT_EQ(to_hex_string(digest), test_cert_key_hash); } TEST(DER, equal) { const std::uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; openssl::DER a; openssl::DER b(sizeof(data)); openssl::DER c1(&data[0], sizeof(data)); openssl::DER c2(&data[0], sizeof(data)); openssl::DER d(&data[0], sizeof(data) - 1); EXPECT_FALSE(a); EXPECT_TRUE(b); EXPECT_TRUE(c1); EXPECT_TRUE(c2); EXPECT_TRUE(d); EXPECT_EQ(a, nullptr); EXPECT_NE(b, nullptr); EXPECT_NE(c1, nullptr); EXPECT_NE(c2, nullptr); EXPECT_NE(d, nullptr); EXPECT_NE(c1.get(), c2.get()); EXPECT_EQ(c1.size(), c2.size()); EXPECT_EQ(c1, c2); EXPECT_EQ(c1, c1); EXPECT_NE(c1, a); EXPECT_NE(c1, b); EXPECT_NE(c1, d); EXPECT_NE(a, c1); EXPECT_NE(b, c1); EXPECT_NE(d, c1); } TEST(DER, construct) { const std::uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; const openssl::DER a(&data[0], sizeof(data)); auto b = a; EXPECT_NE(a.get(), b.get()); EXPECT_EQ(a, b); auto c{a}; EXPECT_NE(a.get(), c.get()); EXPECT_EQ(a, c); EXPECT_EQ(b, c); auto d = std::move(b); EXPECT_EQ(a, d); EXPECT_EQ(b.size(), 0); EXPECT_EQ(b, nullptr); EXPECT_FALSE(b); auto e(std::move(c)); EXPECT_EQ(a, e); EXPECT_EQ(c.size(), 0); EXPECT_EQ(c, nullptr); EXPECT_FALSE(c); const std::uint8_t alt[] = {9, 8, 7, 6, 5, 4}; openssl::DER x(&alt[0], sizeof(alt)); x = e; EXPECT_EQ(x, a); EXPECT_NE(x, a.get()); EXPECT_NE(x, e.get()); } TEST(DER, release) { const std::uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; openssl::DER a(&data[0], sizeof(data)); EXPECT_EQ(a.size(), sizeof(data)); EXPECT_NE(a.get(), &data[0]); const auto* tmp_p = a.get(); auto* ptr = a.release(); EXPECT_EQ(a.size(), 0); EXPECT_EQ(a.get(), nullptr); EXPECT_EQ(ptr, tmp_p); openssl::DER::free(ptr); } TEST(openssl, sizes) { EXPECT_EQ(sizeof(openssl::sha_1_digest_t), openssl::sha_1_digest_size); EXPECT_EQ(sizeof(openssl::sha_256_digest_t), openssl::sha_256_digest_size); EXPECT_EQ(sizeof(openssl::sha_384_digest_t), openssl::sha_384_digest_size); EXPECT_EQ(sizeof(openssl::sha_512_digest_t), openssl::sha_512_digest_size); } TEST(openssl, base64Encode) { auto res = openssl::base64_encode(&iso_exi_a_hash[0], sizeof(iso_exi_a_hash)); EXPECT_EQ(res, iso_exi_a_hash_b64); res = openssl::base64_encode(&iso_exi_sig[0], sizeof(iso_exi_sig)); EXPECT_EQ(res, iso_exi_sig_b64); } TEST(openssl, base64EncodeNl) { auto res = openssl::base64_encode(&iso_exi_a_hash[0], sizeof(iso_exi_a_hash), true); EXPECT_EQ(res, iso_exi_a_hash_b64_nl); res = openssl::base64_encode(&iso_exi_sig[0], sizeof(iso_exi_sig), true); EXPECT_EQ(res, iso_exi_sig_b64_nl); } TEST(openssl, base64Decode) { auto res = openssl::base64_decode(&iso_exi_a_hash_b64[0], sizeof(iso_exi_a_hash_b64) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_a_hash[0], res.size()), 0); res = openssl::base64_decode(&iso_exi_sig_b64[0], sizeof(iso_exi_sig_b64) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_sig)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_sig[0], res.size()), 0); std::array buffer{}; std::size_t buffer_len = buffer.size(); EXPECT_TRUE( openssl::base64_decode(&iso_exi_a_hash_b64[0], sizeof(iso_exi_a_hash_b64) - 1, buffer.data(), buffer_len)); ASSERT_EQ(buffer_len, sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(buffer.data(), &iso_exi_a_hash[0], buffer_len), 0); } TEST(openssl, base64DecodeNl) { auto res = openssl::base64_decode(&iso_exi_a_hash_b64_nl[0], sizeof(iso_exi_a_hash_b64_nl) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_a_hash[0], res.size()), 0); res = openssl::base64_decode(&iso_exi_sig_b64_nl[0], sizeof(iso_exi_sig_b64_nl) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_sig)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_sig[0], res.size()), 0); std::array buffer{}; std::size_t buffer_len = buffer.size(); EXPECT_TRUE(openssl::base64_decode(&iso_exi_a_hash_b64_nl[0], sizeof(iso_exi_a_hash_b64_nl) - 1, buffer.data(), buffer_len)); ASSERT_EQ(buffer_len, sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(buffer.data(), &iso_exi_a_hash[0], buffer_len), 0); } TEST(openssl, base64DecodeCrlf) { auto res = openssl::base64_decode(&iso_exi_a_hash_b64_crlf[0], sizeof(iso_exi_a_hash_b64_crlf) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_a_hash[0], res.size()), 0); } TEST(openssl, base64DecodeCrOnly) { auto res = openssl::base64_decode(&iso_exi_a_hash_b64_cr[0], sizeof(iso_exi_a_hash_b64_cr) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_a_hash[0], res.size()), 0); } TEST(openssl, base64DecodeInternalSpaces) { auto res = openssl::base64_decode(&iso_exi_a_hash_b64_spaces[0], sizeof(iso_exi_a_hash_b64_spaces) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_a_hash[0], res.size()), 0); } TEST(openssl, base64DecodeTabs) { auto res = openssl::base64_decode(&iso_exi_a_hash_b64_tabs[0], sizeof(iso_exi_a_hash_b64_tabs) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_a_hash[0], res.size()), 0); } TEST(openssl, base64DecodeTrailingNulIsTolerated) { // sizeof(literal) includes the trailing NUL; impl must skip it. auto res = openssl::base64_decode(&iso_exi_a_hash_b64[0], sizeof(iso_exi_a_hash_b64)); ASSERT_EQ(res.size(), sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_a_hash[0], res.size()), 0); } TEST(openssl, base64DecodeVerticalTabAndFormFeed) { const char vt_ff[] = "0bXgPQBlvuVr\vMXmERTBR61TKGPwOC\fRYXT4s8d6mPSqk="; auto res = openssl::base64_decode(&vt_ff[0], sizeof(vt_ff) - 1); ASSERT_EQ(res.size(), sizeof(iso_exi_a_hash)); EXPECT_EQ(std::memcmp(res.data(), &iso_exi_a_hash[0], res.size()), 0); } TEST(openssl, base64DecodeInvalidByteRejected) { // Non-whitespace non-alphabet bytes still produce empty output. auto res = openssl::base64_decode("@@@@", 4); EXPECT_TRUE(res.empty()); } TEST(openssl, base64DecodeEmptyInputReturnsEmpty) { auto res = openssl::base64_decode("", 0); EXPECT_TRUE(res.empty()); std::array buffer{}; std::size_t buffer_len = buffer.size(); EXPECT_FALSE(openssl::base64_decode("", 0, buffer.data(), buffer_len)); } TEST(openssl, base64EncodeEmptyInputReturnsEmpty) { const std::uint8_t empty_buf[1] = {0}; auto res = openssl::base64_encode(empty_buf, 0); EXPECT_TRUE(res.empty()); } TEST(openssl, sha256) { openssl::sha_256_digest_t digest; EXPECT_TRUE(openssl::sha_256(sha_256_test[0].input, 0, digest)); EXPECT_EQ(std::memcmp(digest.data(), &sha_256_test[0].digest[0], 32), 0); EXPECT_TRUE(openssl::sha_256(sha_256_test[1].input, 3, digest)); EXPECT_EQ(std::memcmp(digest.data(), &sha_256_test[1].digest[0], 32), 0); } TEST(openssl, sha256Exi) { openssl::sha_256_digest_t digest; EXPECT_TRUE(openssl::sha_256(&iso_exi_a[0], sizeof(iso_exi_a), digest)); EXPECT_EQ(std::memcmp(digest.data(), &iso_exi_a_hash[0], 32), 0); EXPECT_TRUE(openssl::sha_256(&iso_exi_b[0], sizeof(iso_exi_b), digest)); EXPECT_EQ(std::memcmp(digest.data(), &iso_exi_b_hash[0], 32), 0); } TEST(openssl, signVerify) { auto pkey = openssl::load_private_key("server_priv.pem", nullptr); ASSERT_TRUE(pkey); std::array sig_der{}; std::size_t sig_der_len{sig_der.size()}; openssl::sha_256_digest_t digest; EXPECT_TRUE(openssl::sha_256(&sign_test[0], openssl::sha_256_digest_size, digest)); EXPECT_TRUE(openssl::sign(pkey.get(), sig_der.data(), sig_der_len, digest.data(), digest.size())); // std::cout << "signature size: " << sig_der_len << std::endl; EXPECT_TRUE(openssl::verify(pkey.get(), sig_der.data(), sig_der_len, digest.data(), digest.size())); } #ifdef USING_TPM2 TEST(opensslTpm, signVerify) { auto pkey = openssl::load_private_key("tpm_pki/server_priv.pem", nullptr); ASSERT_TRUE(pkey); // looks like sign/verify may not be supported // TODO(james-ctc) investigation needed // perhaps the public key needs to be extracted #if 0 if (EVP_PKEY_can_sign(pkey.get()) == 1) { std::array sig_der{}; std::size_t sig_der_len{sig_der.size()}; openssl::sha_256_digest_t digest; evse_security::OpenSSLProvider provider; provider.set_global_mode(evse_security::OpenSSLProvider::mode_t::custom_provider); EXPECT_TRUE(openssl::sha_256(&sign_test[0], openssl::sha_256_digest_size, digest)); EXPECT_TRUE(openssl::sign(pkey.get(), sig_der.data(), sig_der_len, digest.data(), digest.size())); // std::cout << "signature size: " << sig_der_len << std::endl; EXPECT_TRUE(openssl::verify(pkey.get(), sig_der.data(), sig_der_len, digest.data(), digest.size())); } else { std::cout << "sign/verify not supported" << std::endl; } #endif } #endif TEST(openssl, signVerifyBn) { auto pkey = openssl::load_private_key("server_priv.pem", nullptr); ASSERT_TRUE(pkey); openssl::bn_t r; openssl::bn_t s; openssl::sha_256_digest_t digest; EXPECT_TRUE(openssl::sha_256(&sign_test[0], openssl::sha_256_digest_size, digest)); EXPECT_TRUE(openssl::sign(pkey.get(), r, s, digest)); // std::cout << "signature size: " << sig_der_len << std::endl; EXPECT_TRUE(openssl::verify(pkey.get(), r, s, digest)); } TEST(openssl, signVerifyMix) { auto pkey = openssl::load_private_key("server_priv.pem", nullptr); ASSERT_TRUE(pkey); std::array sig_der; std::size_t sig_der_len{sig_der.size()}; openssl::sha_256_digest_t digest; EXPECT_TRUE(openssl::sha_256(&sign_test[0], openssl::sha_256_digest_size, digest)); EXPECT_TRUE(openssl::sign(pkey.get(), sig_der.data(), sig_der_len, digest.data(), digest.size())); openssl::bn_t r; openssl::bn_t s; EXPECT_TRUE(openssl::signature_to_bn(r, s, sig_der.data(), sig_der_len)); EXPECT_TRUE(openssl::verify(pkey.get(), r, s, digest)); } TEST(openssl, signVerifyFail) { auto pkey = openssl::load_private_key("server_priv.pem", nullptr); ASSERT_TRUE(pkey); auto pkey_inv = openssl::load_private_key("client_priv.pem", nullptr); ASSERT_TRUE(pkey); std::array sig_der; std::size_t sig_der_len{sig_der.size()}; openssl::sha_256_digest_t digest; EXPECT_TRUE(openssl::sha_256(&sign_test[0], openssl::sha_256_digest_size, digest)); EXPECT_TRUE(openssl::sign(pkey.get(), sig_der.data(), sig_der_len, digest.data(), digest.size())); // std::cout << "signature size: " << sig_der_len << std::endl; EXPECT_FALSE(openssl::verify(pkey_inv.get(), sig_der.data(), sig_der_len, digest.data(), digest.size())); } TEST(openssl, verifyIso) { auto pkey = openssl::load_private_key("iso_priv.pem", nullptr); ASSERT_TRUE(pkey); auto sig = openssl::bn_to_signature(&iso_exi_sig[0], &iso_exi_sig[32]); EXPECT_TRUE(openssl::verify(pkey.get(), sig.get(), sig.size(), &iso_exi_b_hash[0], sizeof(iso_exi_b_hash))); } TEST(certificateLoad, single) { auto certs = ::openssl::load_certificates("server_cert.pem"); EXPECT_EQ(certs.size(), 1); } TEST(certificateLoad, chain) { auto certs = ::openssl::load_certificates("server_chain.pem"); EXPECT_EQ(certs.size(), 2); } TEST(certificateLoad, key) { auto certs = ::openssl::load_certificates("server_priv.pem"); EXPECT_EQ(certs.size(), 0); } TEST(certificateLoad, missing) { auto certs = ::openssl::load_certificates("server_priv.pem-not-found"); EXPECT_EQ(certs.size(), 0); } TEST(certificateLoad, nullptr) { auto certs = ::openssl::load_certificates(nullptr); EXPECT_EQ(certs.size(), 0); } TEST(certificateLoad, empty) { auto certs = ::openssl::load_certificates(""); EXPECT_EQ(certs.size(), 0); } TEST(certificateLoad, multiFile) { std::vector files{"server_chain.pem", "alt_server_chain.pem"}; auto certs = ::openssl::load_certificates(files); ASSERT_EQ(certs.size(), 4); auto server = ::openssl::load_certificates("server_cert.pem"); auto ca = ::openssl::load_certificates("server_ca_cert.pem"); auto alt_server = ::openssl::load_certificates("alt_server_cert.pem"); auto alt_ca = ::openssl::load_certificates("alt_server_ca_cert.pem"); EXPECT_EQ(certs[0], server[0]); EXPECT_EQ(certs[1], ca[0]); EXPECT_EQ(certs[2], alt_server[0]); EXPECT_EQ(certs[3], alt_ca[0]); } TEST(certificateLoad, multiFileEmpty) { std::vector files{}; auto certs = ::openssl::load_certificates(files); ASSERT_EQ(certs.size(), 0); } TEST(certificateLoad, multiFileMissing) { std::vector files{"server_chain.pem", "alt_server_chain.pem-not-found"}; auto certs = ::openssl::load_certificates(files); ASSERT_EQ(certs.size(), 2); auto server = ::openssl::load_certificates("server_cert.pem"); auto ca = ::openssl::load_certificates("server_ca_cert.pem"); EXPECT_EQ(certs[0], server[0]); EXPECT_EQ(certs[1], ca[0]); } TEST(certificateLoad, multiFileNullptr) { std::vector files{nullptr, "alt_server_chain.pem"}; auto certs = ::openssl::load_certificates(files); ASSERT_EQ(certs.size(), 2); auto alt_server = ::openssl::load_certificates("alt_server_cert.pem"); auto alt_ca = ::openssl::load_certificates("alt_server_ca_cert.pem"); EXPECT_EQ(certs[0], alt_server[0]); EXPECT_EQ(certs[1], alt_ca[0]); } TEST(certificateLoadPki, none) { auto certs = ::openssl::load_certificates(nullptr, nullptr, nullptr); EXPECT_EQ(certs.leaf, nullptr); EXPECT_EQ(certs.chain.size(), 0); EXPECT_EQ(certs.trust_anchors.size(), 0); certs = ::openssl::load_certificates("server_cert.pem", nullptr, nullptr); EXPECT_EQ(certs.leaf, nullptr); EXPECT_EQ(certs.chain.size(), 0); EXPECT_EQ(certs.trust_anchors.size(), 0); certs = ::openssl::load_certificates(nullptr, "server_chain.pem", nullptr); EXPECT_EQ(certs.leaf, nullptr); EXPECT_EQ(certs.chain.size(), 0); EXPECT_EQ(certs.trust_anchors.size(), 0); certs = ::openssl::load_certificates(nullptr, nullptr, "server_root_cert.pem"); EXPECT_EQ(certs.leaf, nullptr); EXPECT_EQ(certs.chain.size(), 0); EXPECT_EQ(certs.trust_anchors.size(), 0); } TEST(certificateLoadPki, full) { auto certs = ::openssl::load_certificates("server_cert.pem", "server_ca_cert.pem", "server_root_cert.pem"); auto server = ::openssl::load_certificates("server_cert.pem"); ASSERT_EQ(server.size(), 1); auto chain = ::openssl::load_certificates("server_ca_cert.pem"); ASSERT_EQ(chain.size(), 1); auto trust_anchors = ::openssl::load_certificates("server_root_cert.pem"); ASSERT_EQ(trust_anchors.size(), 1); ASSERT_NE(certs.leaf, nullptr); EXPECT_EQ(certs.leaf, server[0]); ASSERT_EQ(certs.chain.size(), 1); ASSERT_EQ(certs.trust_anchors.size(), 1); EXPECT_EQ(certs.chain, chain); EXPECT_EQ(certs.trust_anchors, trust_anchors); } TEST(certificateLoadPki, noLeaf) { // should work since leaf is 1st certificate in server_chain.pem auto certs = ::openssl::load_certificates(nullptr, "server_chain.pem", "server_root_cert.pem"); auto server = ::openssl::load_certificates("server_cert.pem"); ASSERT_EQ(server.size(), 1); auto chain = ::openssl::load_certificates("server_ca_cert.pem"); ASSERT_EQ(chain.size(), 1); auto trust_anchors = ::openssl::load_certificates("server_root_cert.pem"); ASSERT_EQ(trust_anchors.size(), 1); EXPECT_EQ(certs.leaf, server[0]); ASSERT_EQ(certs.chain.size(), 1); ASSERT_EQ(certs.trust_anchors.size(), 1); EXPECT_EQ(certs.chain, chain); EXPECT_EQ(certs.trust_anchors, trust_anchors); } TEST(certificateLoadPki, invalid) { auto certs = ::openssl::load_certificates("client_cert.pem", "server_ca_cert.pem", "server_root_cert.pem"); EXPECT_EQ(certs.leaf, nullptr); EXPECT_EQ(certs.chain.size(), 0); EXPECT_EQ(certs.trust_anchors.size(), 0); certs = ::openssl::load_certificates("server_cert.pem", "client_ca_cert.pem", "server_root_cert.pem"); EXPECT_EQ(certs.leaf, nullptr); EXPECT_EQ(certs.chain.size(), 0); EXPECT_EQ(certs.trust_anchors.size(), 0); certs = ::openssl::load_certificates("server_cert.pem", "server_ca_cert.pem", "client_root_cert.pem"); EXPECT_EQ(certs.leaf, nullptr); EXPECT_EQ(certs.chain.size(), 0); EXPECT_EQ(certs.trust_anchors.size(), 0); certs = ::openssl::load_certificates(nullptr, "server_chain.pem", "client_root_cert.pem"); EXPECT_EQ(certs.leaf, nullptr); EXPECT_EQ(certs.chain.size(), 0); EXPECT_EQ(certs.trust_anchors.size(), 0); } TEST(certificate, toPem) { auto certs = ::openssl::load_certificates("client_ca_cert.pem"); ASSERT_EQ(certs.size(), 1); auto pem = ::openssl::certificate_to_pem(certs[0].get()); EXPECT_FALSE(pem.empty()); // std::cout << pem << std::endl; } TEST(certificate, loadPemSingle) { auto certs = ::openssl::load_certificates("client_ca_cert.pem"); ASSERT_EQ(certs.size(), 1); auto pem = ::openssl::certificate_to_pem(certs[0].get()); EXPECT_FALSE(pem.empty()); auto pem_certs = ::openssl::load_certificates_pem(pem.c_str()); ASSERT_EQ(pem_certs.size(), 1); EXPECT_EQ(certs[0], pem_certs[0]); } TEST(certificate, loadPemMulti) { auto certs = ::openssl::load_certificates("client_chain.pem"); ASSERT_GT(certs.size(), 1); std::string pem; for (const auto& cert : certs) { pem += ::openssl::certificate_to_pem(cert.get()); } EXPECT_FALSE(pem.empty()); // std::cout << pem << std::endl << "Output" << std::endl; auto pem_certs = ::openssl::load_certificates_pem(pem.c_str()); ASSERT_EQ(pem_certs.size(), certs.size()); for (auto i = 0; i < certs.size(); i++) { SCOPED_TRACE(std::to_string(i)); // std::cout << ::openssl::certificate_to_pem(pem_certs[i].get()) << std::endl; EXPECT_EQ(certs[i], pem_certs[i]); } } TEST(certificate, verify) { auto client = ::openssl::load_certificates("client_cert.pem"); auto chain = ::openssl::load_certificates("client_chain.pem"); auto root = ::openssl::load_certificates("client_root_cert.pem"); ASSERT_EQ(client.size(), 1); EXPECT_GT(chain.size(), 0); EXPECT_EQ(root.size(), 1); EXPECT_EQ(::openssl::verify_certificate(client[0].get(), root, chain), openssl::verify_result_t::Verified); } TEST(certificate, verifyCross) { auto client = ::openssl::load_certificates("server_cert.pem"); auto chain = ::openssl::load_certificates("cross_ca_cert.pem"); auto root = ::openssl::load_certificates("client_root_cert.pem"); ASSERT_EQ(client.size(), 1); EXPECT_GT(chain.size(), 0); EXPECT_EQ(root.size(), 1); EXPECT_EQ(::openssl::verify_certificate(client[0].get(), root, chain), openssl::verify_result_t::Verified); } TEST(certificate, verifyRemoveClientFromChain) { auto client = ::openssl::load_certificates("client_cert.pem"); auto chain = ::openssl::load_certificates("client_chain.pem"); auto root = ::openssl::load_certificates("client_root_cert.pem"); ASSERT_EQ(client.size(), 1); EXPECT_GT(chain.size(), 0); EXPECT_EQ(root.size(), 1); // client certificate is 1st in the list openssl::certificate_list new_chain; for (auto itt = std::next(chain.begin()); itt != chain.end(); itt++) { new_chain.push_back(std::move(*itt)); } EXPECT_EQ(::openssl::verify_certificate(client[0].get(), root, new_chain), openssl::verify_result_t::Verified); } TEST(certificate, verifyNoClient) { // client certificate is in the chain auto chain = ::openssl::load_certificates("client_chain.pem"); auto root = ::openssl::load_certificates("client_root_cert.pem"); EXPECT_GT(chain.size(), 0); EXPECT_EQ(root.size(), 1); EXPECT_EQ(::openssl::verify_certificate(nullptr, root, chain), openssl::verify_result_t::Verified); } TEST(certificate, verifyFailWrongClient) { auto client = ::openssl::load_certificates("server_cert.pem"); auto chain = ::openssl::load_certificates("client_chain.pem"); auto root = ::openssl::load_certificates("client_root_cert.pem"); ASSERT_EQ(client.size(), 1); EXPECT_GT(chain.size(), 0); EXPECT_EQ(root.size(), 1); EXPECT_NE(::openssl::verify_certificate(client[0].get(), root, chain), openssl::verify_result_t::Verified); } TEST(certificate, verifyFailWrongRoot) { auto client = ::openssl::load_certificates("client_cert.pem"); auto chain = ::openssl::load_certificates("client_chain.pem"); auto root = ::openssl::load_certificates("server_root_cert.pem"); ASSERT_EQ(client.size(), 1); EXPECT_GT(chain.size(), 0); EXPECT_EQ(root.size(), 1); EXPECT_NE(::openssl::verify_certificate(client[0].get(), root, chain), openssl::verify_result_t::Verified); } TEST(certificate, verifyFailWrongChain) { auto client = ::openssl::load_certificates("client_cert.pem"); auto chain = ::openssl::load_certificates("server_chain.pem"); auto root = ::openssl::load_certificates("client_root_cert.pem"); ASSERT_EQ(client.size(), 1); EXPECT_GT(chain.size(), 0); EXPECT_EQ(root.size(), 1); EXPECT_NE(::openssl::verify_certificate(client[0].get(), root, chain), openssl::verify_result_t::Verified); } TEST(certificate, subjectName) { auto chain = ::openssl::load_certificates("client_chain.pem"); EXPECT_GT(chain.size(), 0); for (const auto& cert : chain) { auto subject = ::openssl::certificate_subject(cert.get()); EXPECT_GT(subject.size(), 0); } } TEST(certificateChainInfo, valid) { auto chain = openssl::load_certificates("client_cert.pem", "client_ca_cert.pem", "client_root_cert.pem"); EXPECT_TRUE(openssl::verify_chain(chain)); } TEST(certificateChainInfo, invalid) { auto chain = openssl::load_certificates("server_cert.pem", "client_ca_cert.pem", "client_root_cert.pem"); EXPECT_FALSE(openssl::verify_chain(chain)); chain = openssl::load_certificates("client_cert.pem", "server_ca_cert.pem", "client_root_cert.pem"); EXPECT_FALSE(openssl::verify_chain(chain)); chain = openssl::load_certificates("client_cert.pem", "client_ca_cert.pem", "server_root_cert.pem"); EXPECT_FALSE(openssl::verify_chain(chain)); } TEST(certificateChain, valid) { auto pkey = openssl::load_private_key("client_priv.pem", nullptr); auto chain_info = openssl::load_certificates("client_cert.pem", "client_ca_cert.pem", "client_root_cert.pem"); openssl::chain_t chain = {std::move(chain_info), std::move(pkey)}; EXPECT_TRUE(openssl::verify_chain(chain)); } TEST(certificateChain, invalid) { auto pkey = openssl::load_private_key("server_priv.pem", nullptr); auto chain_info = openssl::load_certificates("client_cert.pem", "client_ca_cert.pem", "client_root_cert.pem"); openssl::chain_t chain = {std::move(chain_info), std::move(pkey)}; EXPECT_FALSE(openssl::verify_chain(chain)); chain_info = openssl::load_certificates("server_cert.pem", "client_ca_cert.pem", "client_root_cert.pem"); chain.chain = std::move(chain_info); EXPECT_FALSE(openssl::verify_chain(chain)); chain_info = openssl::load_certificates("client_cert.pem", "server_ca_cert.pem", "client_root_cert.pem"); chain.chain = std::move(chain_info); EXPECT_FALSE(openssl::verify_chain(chain)); chain_info = openssl::load_certificates("client_cert.pem", "client_ca_cert.pem", "server_root_cert.pem"); chain.chain = std::move(chain_info); EXPECT_FALSE(openssl::verify_chain(chain)); } TEST(certificate, apply) { auto pkey = openssl::load_private_key("client_priv.pem", nullptr); auto chain_info = openssl::load_certificates("client_cert.pem", "client_ca_cert.pem", "client_root_cert.pem"); openssl::chain_t chain = {std::move(chain_info), std::move(pkey)}; auto* ctx = SSL_CTX_new(TLS_server_method()); auto* ssl = SSL_new(ctx); EXPECT_TRUE(openssl::use_certificate_and_key(ssl, chain)); SSL_free(ssl); SSL_CTX_free(ctx); } } // namespace