diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index fdcba15bc..0396b1e25 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -93,7 +93,6 @@ target_link_libraries(core_libs core_libs_supl core_system_parameters pvt_libs - algorithms_libs PRIVATE algorithms_libs Boost::serialization diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 16ade4101..e77260be5 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -22,9 +22,9 @@ #include "Galileo_OSNMA.h" #include "gnss_crypto.h" #include "gnss_satellite.h" -#include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader -#include "osnma_helper.h" -#include "osnma_nav_data_manager.h" +#include "gnss_sdr_make_unique.h" // for std::make_unique in C++11 +#include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader +#include "osnma_helper.h" // for Osnma_Helper #include // for gr::io_signature::make #include #include @@ -237,6 +237,12 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) } +void osnma_msg_receiver::read_merkle_xml(const std::string& merklepath) +{ + d_crypto->read_merkle_xml(merklepath); +} + + void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& osnma_msg) { if (d_flag_alert_message && (d_public_key_verified || d_kroot_verified)) diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index e48b6e5c3..7039889ef 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -23,21 +23,20 @@ #define FRIEND_TEST(test_case_name, test_name) \ friend class test_case_name##_##test_name##_Test -#include "galileo_inav_message.h" // for OSNMA_msg -#include "gnss_block_interface.h" // for gnss_shared_ptr -#include "gnss_sdr_make_unique.h" // for std::make:unique in C++11 -#include "osnma_data.h" // for OSNMA_data structures -#include "osnma_nav_data_manager.h" -#include // for gr::block -#include // for pmt::pmt_t -#include // for std::array -#include // for uint8_t -#include // for std::time_t -#include // for std::map, std::multimap -#include // for std::shared_ptr -#include // for std::string -#include // for std::pair -#include // for std::vector +#include "galileo_inav_message.h" // for OSNMA_msg +#include "gnss_block_interface.h" // for gnss_shared_ptr +#include "osnma_data.h" // for OSNMA_data structures +#include "osnma_nav_data_manager.h" // for OSNMA_nav_data_Manager +#include // for gr::block +#include // for pmt::pmt_t +#include // for std::array +#include // for uint8_t +#include // for std::time_t +#include // for std::map, std::multimap +#include // for std::shared_ptr +#include // for std::string +#include // for std::pair +#include // for std::vector /** \addtogroup Core * \{ */ @@ -62,9 +61,10 @@ osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, class osnma_msg_receiver : public gr::block { public: - ~osnma_msg_receiver() = default; //!< Default destructor - std::unique_ptr d_crypto; // access to cryptographic functions - void msg_handler_osnma(const pmt::pmt_t& msg); // GnssCrypto and the message handler are needed by public method within TestVectors fixture + ~osnma_msg_receiver() = default; //!< Default destructor + void msg_handler_osnma(const pmt::pmt_t& msg); //!< For testing purposes + void read_merkle_xml(const std::string& merklepath); //!< Public for testing purposes + private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode); osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath, bool strict_mode); @@ -112,6 +112,7 @@ private: std::array d_number_of_blocks{}; std::array d_mack_message{}; // C: 480 b + std::unique_ptr d_crypto; // class for cryptographic functions std::unique_ptr d_dsm_reader; // osnma parameters parser std::unique_ptr d_helper; // helper class with auxiliary functions std::unique_ptr d_nav_data_manager; // refactor for holding and processing navigation data diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index ac8723ab5..9d7662d09 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -20,6 +20,7 @@ #include "Galileo_OSNMA.h" #include #include +#include #include #include #include @@ -912,11 +913,14 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) point = EC_POINT_new(group); if (!point) { + EC_GROUP_free(group); return; } if (!EC_POINT_oct2point(group, point, publicKey.data(), publicKey.size(), nullptr)) { + EC_GROUP_free(group); + EC_POINT_free(point); return; } @@ -930,11 +934,16 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) } if (!ec_key) { + EC_GROUP_free(group); + EC_POINT_free(point); return; } if (!EC_KEY_set_public_key(ec_key, point)) { + EC_KEY_free(ec_key); + EC_POINT_free(point); + EC_GROUP_free(group); return; } if (!pubkey_copy(ec_key, &d_PublicKey)) @@ -1066,6 +1075,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) { return; } + d_PublicKeyType = "Unknown"; std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); #if USE_GNUTLS_FALLBACK // Import the PEM data @@ -1085,6 +1095,52 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) return; } + // store the key type - needed for the Kroot in case no DSM-PKR available + gnutls_pk_algorithm_t pk_algorithm; + unsigned int bits; + + ret = gnutls_pubkey_get_pk_algorithm(pubkey, &bits); + if (ret < 0) + { + LOG(WARNING) << "GnuTLS: Failed to get public key algorithm from .pem file: " << gnutls_strerror(ret); + gnutls_pubkey_deinit(pubkey); + return; + } + + pk_algorithm = static_cast(ret); + + if (pk_algorithm == GNUTLS_PK_ECDSA) + { + gnutls_ecc_curve_t curve; + ret = gnutls_pubkey_export_ecc_raw(pubkey, &curve, nullptr, nullptr); + if (ret < 0) + { + LOG(WARNING) << "GnuTLS: Failed to get EC curve from .pem file: " << gnutls_strerror(ret); + gnutls_pubkey_deinit(pubkey); + return; + } + + if (curve == GNUTLS_ECC_CURVE_SECP256R1) + { + d_PublicKeyType = "ECDSA P-256"; + } + else if (curve == GNUTLS_ECC_CURVE_SECP521R1) + { + d_PublicKeyType = "ECDSA P-521"; + } + else + { + LOG(WARNING) << "GnuTLS: Trying to read unknown EC curve from .pem file"; + gnutls_pubkey_deinit(pubkey); + return; + } + } + else + { + LOG(WARNING) << "GnuTLS: Trying to read unknown key type from .pem file"; + gnutls_pubkey_deinit(pubkey); + return; + } pubkey_copy(pubkey, &d_PublicKey); gnutls_pubkey_deinit(pubkey); #else // OpenSSL @@ -1096,9 +1152,77 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) return; } #if USE_OPENSSL_3 - d_PublicKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); + EVP_PKEY* pubkey = nullptr; + pubkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); + + // store the key type - needed for the Kroot in case no DSM-PKR available + // Get the key type + int key_type = EVP_PKEY_base_id(pubkey); + if (key_type == EVP_PKEY_EC) + { + // It's an EC key, now we need to determine the curve + char curve_name[256]; + size_t curve_name_len = sizeof(curve_name); + + if (EVP_PKEY_get_utf8_string_param(pubkey, OSSL_PKEY_PARAM_GROUP_NAME, curve_name, curve_name_len, &curve_name_len) == 1) + { + if (strcmp(curve_name, "prime256v1") == 0 || strcmp(curve_name, "P-256") == 0) + { + d_PublicKeyType = "ECDSA P-256"; + } + else if (strcmp(curve_name, "secp521r1") == 0 || strcmp(curve_name, "P-521") == 0) + { + d_PublicKeyType = "ECDSA P-521"; + } + else + { + LOG(WARNING) << "OpenSSL: Trying to read an unknown EC curve from .pem file"; + BIO_free(bio); + EVP_PKEY_free(pubkey); + return; + } + } + else + { + LOG(WARNING) << "OpenSSL: Trying to read an unknown EC curve from .pem file"; + BIO_free(bio); + EVP_PKEY_free(pubkey); + return; + } + } + else + { + LOG(WARNING) << "OpenSSL: Trying to read an unknown key type from .pem file"; + BIO_free(bio); + EVP_PKEY_free(pubkey); + return; + } + pubkey_copy(pubkey, &d_PublicKey); + EVP_PKEY_free(pubkey); #else // OpenSSL 1.x - d_PublicKey = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); + EC_KEY* pubkey = nullptr; + pubkey = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); + if (!pubkey) + { + LOG(WARNING) << "OpenSSL: Failed to extract the public key from .pem file"; + BIO_free(bio); + return; + } + const EC_GROUP* group = EC_KEY_get0_group(pubkey); + int nid = EC_GROUP_get_curve_name(group); + const char* curve_name = OBJ_nid2sn(nid); + const std::string curve_str(curve_name); + if (curve_str == "prime256v1") + { + d_PublicKeyType = "ECDSA P-256"; + } + else if (curve_str == "secp521r1") + { + d_PublicKeyType = "ECDSA P-521"; + } + + pubkey_copy(pubkey, &d_PublicKey); + EC_KEY_free(pubkey); #endif BIO_free(bio); if (d_PublicKey == nullptr) @@ -1172,20 +1296,8 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) if (pk_algorithm == GNUTLS_PK_ECDSA) { - gnutls_datum_t params; - ret = gnutls_pubkey_export_ecc_raw(pubkey, nullptr, ¶ms, nullptr); - if (ret < 0) - { - LOG(WARNING) << "GnuTLS: Failed to export EC parameters: " << gnutls_strerror(ret); - gnutls_pubkey_deinit(pubkey); - gnutls_x509_crt_deinit(cert); - return false; - } - gnutls_ecc_curve_t curve; - ret = gnutls_ecc_curve_get_id(reinterpret_cast(params.data)); - gnutls_free(params.data); - + ret = gnutls_pubkey_export_ecc_raw(pubkey, &curve, nullptr, nullptr); if (ret < 0) { LOG(WARNING) << "GnuTLS: Failed to get EC curve: " << gnutls_strerror(ret); @@ -1194,8 +1306,6 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) return false; } - curve = static_cast(ret); - if (curve == GNUTLS_ECC_CURVE_SECP256R1) { d_PublicKeyType = "ECDSA P-256"; diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc index 6b4813975..1904a16e9 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc @@ -70,6 +70,7 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) auto d_crypto2 = std::make_unique(f1, ""); bool result2 = d_crypto2->store_public_key(f2); ASSERT_TRUE(result2); + ASSERT_TRUE(d_crypto2->get_public_key_type() == "ECDSA P-256"); std::ifstream t(f1); std::string content_file((std::istreambuf_iterator(t)), std::istreambuf_iterator()); diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc index 0b525805c..73e5eb25c 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc @@ -243,7 +243,7 @@ bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_ob if (test_step == 1 && d_flag_NPK == true ){ // step 2: this simulates the osnma connecting to the GSC server and downloading the Merkle tree of the next public key - osnma_object->d_crypto->read_merkle_xml( + osnma_object->read_merkle_xml( std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007081500_PKID_8.xml"); }