1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-01-31 11:19:18 +00:00

Add function to store the public key in a .pem file

This commit is contained in:
Carles Fernandez 2024-07-12 16:18:41 +02:00 committed by cesaaargm
parent ef8f00f6d6
commit 1c26d43e2d
3 changed files with 177 additions and 11 deletions

View File

@ -93,7 +93,7 @@ Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& mer
#endif #endif
if (!readPublicKeyFromCRT(certFilePath)) if (!readPublicKeyFromCRT(certFilePath))
{ {
readPublicKeyFromPEM(PEMFILE_DEFAULT); readPublicKeyFromPEM(certFilePath);
} }
read_merkle_xml(merkleTreePath); read_merkle_xml(merkleTreePath);
} }
@ -1142,3 +1142,120 @@ bool Gnss_Crypto::pubkey_copy(EC_KEY* src, EC_KEY** dest)
} }
#endif #endif
#endif #endif
bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const
{
if (!have_public_key())
{
return false;
}
std::ofstream pubKeyFile(pubKeyFilePath, std::ios::binary);
if (!pubKeyFile.is_open())
{
LOG(INFO) << "Unable to open file: " << pubKeyFilePath;
return false;
}
#if USE_GNUTLS_FALLBACK
gnutls_datum_t pem_data;
#if HAVE_GNUTLS_PUBKEY_EXPORT2
int ret = gnutls_pubkey_export2(d_PublicKey, GNUTLS_X509_FMT_PEM, &pem_data);
#else
size_t output_stata_size;
int ret = gnutls_pubkey_export(d_PublicKey, GNUTLS_X509_FMT_PEM, &pem_data, &output_stata_size);
#endif
if (ret != GNUTLS_E_SUCCESS)
{
LOG(INFO) << "GnuTLS: Failed to export public key: " << gnutls_strerror(ret);
return false;
}
pubKeyFile.write((const char*)pem_data.data, pem_data.size);
pubKeyFile.close();
gnutls_free(pem_data.data);
#else // OpenSSL
BIO* bio = BIO_new(BIO_s_mem());
if (!bio)
{
LOG(INFO) << "OpenSSL: Failed to create BIO";
return false;
}
#if USE_OPENSSL_3
if (!PEM_write_bio_PUBKEY(bio, d_PublicKey))
#else // OpenSSL 1.x
if (!PEM_write_bio_EC_PUBKEY(bio, d_PublicKey))
#endif
{
LOG(INFO) << "OpenSSL: Failed to write public key to BIO";
BIO_free(bio);
return false;
}
char* bio_data;
auto bio_len = BIO_get_mem_data(bio, &bio_data);
if (bio_len <= 0)
{
LOG(INFO) << "OpenSSL: Failed to get BIO data";
BIO_free(bio);
return false;
}
pubKeyFile.write(bio_data, bio_len);
pubKeyFile.close();
BIO_free(bio);
#endif
return true;
}
std::vector<uint8_t> Gnss_Crypto::getPublicKey() const
{
if (!have_public_key())
{
return {};
}
#if USE_GNUTLS_FALLBACK
gnutls_datum_t pem_data = {nullptr, 0};
int ret = gnutls_pubkey_export2(d_PublicKey, GNUTLS_X509_FMT_PEM, &pem_data);
if (ret != GNUTLS_E_SUCCESS)
{
LOG(INFO) << "GnuTLS: Failed to export public key to PEM format.";
return {};
}
std::vector<uint8_t> output(pem_data.data, pem_data.data + pem_data.size);
// Free the allocated memory by gnutls_pubkey_export2
gnutls_free(pem_data.data);
#else // OpenSSL
// Create a BIO for the memory buffer
BIO* mem = BIO_new(BIO_s_mem());
if (!mem)
{
LOG(INFO) << "OpenSSL: Failed to create BIO.";
return {};
}
#if USE_OPENSSL_3
if (!PEM_write_bio_PUBKEY(mem, d_PublicKey))
#else // OpenSSL 1.x
if (!PEM_write_bio_EC_PUBKEY(mem, d_PublicKey))
#endif
{
BIO_free(mem);
LOG(INFO) << "OpenSSL: Failed to write public key to PEM format.";
return {};
}
// Get the length of the data in the BIO
BUF_MEM* mem_ptr;
BIO_get_mem_ptr(mem, &mem_ptr);
// Copy the data from the BIO to a std::vector<uint8_t>
std::vector<uint8_t> output(mem_ptr->length);
memcpy(output.data(), mem_ptr->data, mem_ptr->length);
// Clean up the BIO
BIO_free(mem);
#endif
return output;
}

View File

@ -44,17 +44,19 @@ public:
void set_public_key(const std::vector<uint8_t>& publickey); void set_public_key(const std::vector<uint8_t>& publickey);
bool have_public_key() const; bool have_public_key() const;
bool verify_signature(const std::vector<uint8_t>& message, const std::vector<uint8_t>& signature) const; bool verify_signature(const std::vector<uint8_t>& message, const std::vector<uint8_t>& signature) const;
bool store_public_key(const std::string& pubKeyFilePath) const;
std::vector<uint8_t> computeSHA256(const std::vector<uint8_t>& input) const; std::vector<uint8_t> computeSHA256(const std::vector<uint8_t>& input) const;
std::vector<uint8_t> computeSHA3_256(const std::vector<uint8_t>& input) const; std::vector<uint8_t> computeSHA3_256(const std::vector<uint8_t>& input) const;
std::vector<uint8_t> computeHMAC_SHA_256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input) const; std::vector<uint8_t> computeHMAC_SHA_256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input) const;
std::vector<uint8_t> computeCMAC_AES(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input) const; std::vector<uint8_t> computeCMAC_AES(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input) const;
std::vector<uint8_t> getMerkleRoot(const std::vector<std::vector<uint8_t>>& merkle) const; std::vector<uint8_t> getMerkleRoot(const std::vector<std::vector<uint8_t>>& merkle) const;
std::vector<uint8_t> getPublicKey() const;
inline std::vector<uint8_t> getMerkleRoot() const inline std::vector<uint8_t> getMerkleRoot() const
{ {
return d_x_4_0; return d_x_4_0;
} }
inline void setMerkleRoot(std::vector<uint8_t> v){ inline void setMerkleRoot(std::vector<uint8_t> v)
{
d_x_4_0 = v; d_x_4_0 = v;
} }

View File

@ -1,5 +1,10 @@
#include "gnss_crypto.h" #include "gnss_crypto.h"
#include "gnss_sdr_filesystem.h"
#include "gnss_sdr_make_unique.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <fstream>
#include <iterator>
class GnssCryptoTest : public ::testing::Test class GnssCryptoTest : public ::testing::Test
{ {
}; };
@ -7,7 +12,7 @@ class GnssCryptoTest : public ::testing::Test
TEST(GnssCryptoTest, TestComputeSHA_256) TEST(GnssCryptoTest, TestComputeSHA_256)
{ {
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); auto d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world std::vector<uint8_t> message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world
std::vector<uint8_t> expected_output = { std::vector<uint8_t> expected_output = {
@ -23,7 +28,7 @@ TEST(GnssCryptoTest, TestComputeSHA_256)
TEST(GnssCryptoTest, TestComputeSHA3_256) TEST(GnssCryptoTest, TestComputeSHA3_256)
{ {
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); auto d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world std::vector<uint8_t> message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world
std::vector<uint8_t> expected_output = { std::vector<uint8_t> expected_output = {
@ -39,7 +44,7 @@ TEST(GnssCryptoTest, TestComputeSHA3_256)
TEST(GnssCryptoTest, VerifySignature) TEST(GnssCryptoTest, VerifySignature)
{ {
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); auto d_crypto = std::make_unique<Gnss_Crypto>();
// RG example - import crt certificate - result: FAIL // RG example - import crt certificate - result: FAIL
std::vector<uint8_t> message = {0x82, 0x10, 0x49, 0x22, 0x04, 0xE0, 0x60, 0x61, 0x0B, 0xDF, 0x26, 0xD7, 0x7B, 0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; std::vector<uint8_t> message = {0x82, 0x10, 0x49, 0x22, 0x04, 0xE0, 0x60, 0x61, 0x0B, 0xDF, 0x26, 0xD7, 0x7B, 0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF};
@ -61,7 +66,7 @@ TEST(GnssCryptoTest, VerifySignature)
TEST(GnssCryptoTest, VerifyPubKeyImport) TEST(GnssCryptoTest, VerifyPubKeyImport)
{ {
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); auto d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> publicKey{// PEM std::vector<uint8_t> publicKey{// PEM
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A,
@ -80,10 +85,52 @@ TEST(GnssCryptoTest, VerifyPubKeyImport)
} }
TEST(GnssCryptoTest, VerifyPublicKeyStorage)
{
auto d_crypto = std::make_unique<Gnss_Crypto>();
const std::string f1("./osnma_test_file1.pem");
const std::string f2("./osnma_test_file2.pem");
std::vector<uint8_t> publicKey{
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A,
0x4D, 0x46, 0x6B, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4B, 0x6F, 0x5A, 0x49, 0x7A, 0x6A, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4B, 0x6F, 0x5A, 0x49,
0x7A, 0x6A, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x41, 0x37, 0x4C, 0x4F, 0x5A, 0x4C, 0x77, 0x67, 0x65, 0x39, 0x32, 0x4C, 0x78, 0x4E, 0x2B,
0x46, 0x6B, 0x59, 0x66, 0x38, 0x74, 0x6F, 0x59, 0x79, 0x44, 0x57, 0x50, 0x2F, 0x0A, 0x6F, 0x4A, 0x46, 0x42, 0x44, 0x38, 0x46, 0x59, 0x2B, 0x37,
0x64, 0x35, 0x67, 0x4F, 0x71, 0x49, 0x61, 0x45, 0x32, 0x52, 0x6A, 0x50, 0x41, 0x6E, 0x4B, 0x49, 0x36, 0x38, 0x73, 0x2F, 0x4F, 0x4B, 0x2F, 0x48, 0x50, 0x67, 0x6F,
0x4C, 0x6B, 0x4F, 0x32, 0x69, 0x6A, 0x51, 0x38, 0x78, 0x41, 0x5A, 0x79, 0x44, 0x64, 0x50, 0x42, 0x31, 0x64, 0x48, 0x53, 0x51, 0x3D, 0x3D, 0x0A,
0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x50, 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x4B, 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A};
d_crypto->set_public_key(publicKey);
bool result = d_crypto->store_public_key(f1);
ASSERT_TRUE(result);
auto d_crypto2 = std::make_unique<Gnss_Crypto>(f1, "");
bool result2 = d_crypto2->store_public_key(f2);
ASSERT_TRUE(result2);
std::ifstream t(f1);
std::string content_file((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
std::ifstream t2(f2);
std::string content_file2((std::istreambuf_iterator<char>(t2)), std::istreambuf_iterator<char>());
ASSERT_EQ(content_file, content_file2);
std::vector<uint8_t> readkey = d_crypto2->getPublicKey();
ASSERT_EQ(publicKey, readkey);
errorlib::error_code ec;
ASSERT_TRUE(fs::remove(fs::path(f1), ec));
ASSERT_TRUE(fs::remove(fs::path(f2), ec));
}
// Unit test for computeHMAC_SHA_256 function. // Unit test for computeHMAC_SHA_256 function.
TEST(GnssCryptoTest, TestComputeHMACSHA256) TEST(GnssCryptoTest, TestComputeHMACSHA256)
{ {
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); auto d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> key = { std::vector<uint8_t> key = {
0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7, 0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7,
@ -107,7 +154,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256)
TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) TEST(GnssCryptoTest, TestComputeHMACSHA256_m0)
{ {
// key and message generated from RG A.6.5.1 // key and message generated from RG A.6.5.1
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); auto d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> key = {// RG K4 @ 345690 std::vector<uint8_t> key = {// RG K4 @ 345690
0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6,
@ -134,7 +181,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_m0)
TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4)
{ {
// key and message generated from RG A.6.5.2 // key and message generated from RG A.6.5.2
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); auto d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> key = {// RG K4 @ 345690 std::vector<uint8_t> key = {// RG K4 @ 345690
0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6,
@ -159,7 +206,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4)
TEST(GnssCryptoTest, TestComputeCMAC_AES) TEST(GnssCryptoTest, TestComputeCMAC_AES)
{ {
// Tests vectors from https://datatracker.ietf.org/doc/html/rfc4493#appendix-A // Tests vectors from https://datatracker.ietf.org/doc/html/rfc4493#appendix-A
std::unique_ptr<Gnss_Crypto> d_crypto = std::make_unique<Gnss_Crypto>(); auto d_crypto = std::make_unique<Gnss_Crypto>();
std::vector<uint8_t> key = { std::vector<uint8_t> key = {
0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,