Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,817 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Pionix GmbH and Contributors to EVerest
#include "gtest/gtest.h"
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <everest/tls/openssl_util.hpp>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <vector>
#include <evse_security/crypto/openssl/openssl_provider.hpp>
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 <typename T> constexpr void setCharacters(T& dest, const std::string& s) {
dest.charactersLen = s.size();
std::memcpy(&dest.characters[0], s.c_str(), s.size());
}
template <typename T> 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<std::uint8_t, 512> 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<std::uint8_t, 512> 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<std::uint8_t, 16> 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<std::uint8_t, 256> 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<std::uint8_t, 256> 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<std::uint8_t, 80> 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<std::uint8_t, 256> 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<const char*> 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<const char*> files{};
auto certs = ::openssl::load_certificates(files);
ASSERT_EQ(certs.size(), 0);
}
TEST(certificateLoad, multiFileMissing) {
std::vector<const char*> 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<const char*> 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