1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2024-12-12 11:10:33 +00:00

Read type of public key (#16)

* Clang Tidy fixes

* Improve reading public key type

* Update osnma_nav_data_manager.cc

hotfix

---------

Co-authored-by: cesaaargm <cesare.martinez@proton.me>
This commit is contained in:
Carles Fernandez 2024-08-02 09:38:37 +02:00 committed by GitHub
parent 960e76e3a0
commit 6beb92278f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 307 additions and 146 deletions

View File

@ -29,6 +29,7 @@
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <fstream> // for std::ifstream and std::ofstream
#include <iomanip> // for std::setfill
#include <ios> // for std::hex, std::uppercase
#include <iostream>
@ -37,7 +38,6 @@
#include <tuple>
#include <typeinfo> // for typeid
#include <utility>
#include <fstream> // for std::ifstream and std::ofstream
#if USE_GLOG_AND_GFLAGS
@ -68,21 +68,23 @@ osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath,
osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath) : gr::block("osnma_msg_receiver",
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(0, 0, 0))
gr::io_signature::make(0, 0, 0),
gr::io_signature::make(0, 0, 0))
{
d_dsm_reader = std::make_unique<OSNMA_DSM_Reader>();
d_crypto = std::make_unique<Gnss_Crypto>(crtFilePath, merkleFilePath);
d_helper = std::make_unique<Osnma_Helper>();
d_nav_data_manager = std::make_unique<OSNMA_nav_data_Manager>();
if(d_crypto->have_public_key()){ // Hot start is enabled
if (d_crypto->have_public_key())
{ // Hot start is enabled
LOG(WARNING) << "OSNMA Public Key available, trying to find DSM-KROOT saved";
std::cout << "OSNMA Public Key available, trying to find DSM-KROOT saved" << std::endl;
d_public_key_verified = true;
auto dsm_nmah = parse_dsm_kroot();
if (!dsm_nmah.first.empty()){
if (!dsm_nmah.first.empty())
{
LOG(WARNING) << "OSNMA DSM-KROOT and NMA Header successfully read from file " << KROOTFILE_DEFAULT;
std::cout << "OSNMA DSM-KROOT and NMA Header successfully read from file " << KROOTFILE_DEFAULT << std::endl;
d_flag_hot_start = true;
@ -113,20 +115,22 @@ osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, const std
#endif
#endif
std::chrono::time_point<std::chrono::system_clock> now;
if (d_flag_debug){
if (d_flag_debug)
{
// d_GST_Rx = d_helper->compute_gst(d_initial_debug_time);
LOG(WARNING) << "Galileo OSNMA: Debug mode, time artificially set up.";
std::cout << "Galileo OSNMA: Debug mode, time artificially set up." << std::endl;
// TODO - need to synchronize time lapse with Gnss_Synchro?
}
else{
else
{
d_GST_Rx = d_helper->compute_gst_now();
}
d_WN = d_helper->get_WN(d_GST_Rx);
d_TOW = d_helper->get_TOW(d_GST_Rx);
LOG(WARNING) << "Galileo OSNMA: initial receiver time GST=["<< d_WN << " " << d_TOW <<"]";
std::cout << "Galileo OSNMA: initial receiver time GST=["<< d_WN << " " << d_TOW <<"]" << std::endl;
LOG(WARNING) << "Galileo OSNMA: initial receiver time GST=[" << d_WN << " " << d_TOW << "]";
std::cout << "Galileo OSNMA: initial receiver time GST=[" << d_WN << " " << d_TOW << "]" << std::endl;
}
@ -155,16 +159,20 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg)
// Receiver time update
d_GST_SIS = d_helper->compute_gst(nma_msg->WN_sf0, nma_msg->TOW_sf0);
if (d_last_verified_key_GST == 0){
if (d_last_verified_key_GST == 0)
{
d_last_received_GST = d_GST_SIS;
}
else if (d_GST_SIS > d_last_received_GST){
else if (d_GST_SIS > d_last_received_GST)
{
d_last_received_GST = d_GST_SIS;
}
if (d_flag_debug){
if (d_flag_debug)
{
d_GST_Rx = d_last_received_GST;
}
else{
else
{
d_GST_Rx = d_helper->compute_gst_now();
}
LOG(INFO) << "Galileo OSNMA: Receiver Time GST=[" << d_helper->get_WN(d_GST_Rx) << " " << d_helper->get_TOW(d_GST_Rx) << "]";
@ -198,7 +206,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg)
}
process_osnma_message(nma_msg);
} // OSNMA frame received
} // OSNMA frame received
else if (msg_type_hash_code == typeid(std::shared_ptr<std::tuple<uint32_t, std::string, uint32_t>>).hash_code()) // Navigation data bits for OSNMA received
{
const auto inav_data = wht::any_cast<std::shared_ptr<std::tuple<uint32_t, std::string, uint32_t>>>(pmt::any_ref(msg));
@ -231,26 +239,30 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg)
void osnma_msg_receiver::process_osnma_message(const std::shared_ptr<OSNMA_msg>& osnma_msg)
{
if (d_flag_alert_message && (d_public_key_verified || d_kroot_verified)){
if (d_flag_alert_message && (d_public_key_verified || d_kroot_verified))
{
return;
}
read_nma_header(osnma_msg->hkroot[0]);
// Check for corner cases: renewal, revocation, alert message
if (d_osnma_data.d_nma_header.nmas == 0 /* RES */){
if (d_osnma_data.d_nma_header.nmas == 0 /* RES */)
{
LOG(WARNING) << "Galileo OSNMA: NMAS invalid (RES), skipping osnma message";
return;
}
// TODO - trusting the NMAS and CPKS shall be done upon PKR verification or Tag verification.
// It's ok to activate the flags, but the final decision should happen after verifying it.
// For OAM is solved, but NPK and PKREV I think not yet
if (d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 4 /* NPK */ && d_GST_PKR_PKREV_start == 0){
if (d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 4 /* NPK */ && d_GST_PKR_PKREV_start == 0)
{
d_flag_PK_renewal = true;
d_GST_PKR_PKREV_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0);
LOG(INFO) << "Galileo OSNMA: Public Key Renewal :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]";
std::cout << "Galileo OSNMA: Public Key Renewal :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << std::endl;
}
if (d_flag_PK_renewal && d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 1 /* Nominal */ ){
if (d_flag_PK_renewal && d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 1 /* Nominal */)
{
d_flag_PK_renewal = false;
uint32_t final_GST = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0);
double duration_hours = (final_GST - d_GST_PKR_PKREV_start) / 3600;
@ -258,7 +270,8 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr<OSNMA_msg>&
std::cout << "Galileo OSNMA: Public Key Renewal :: Finished at GST=" << duration_hours << ", Duration=" << duration_hours << " h" << std::endl;
}
if (d_osnma_data.d_nma_header.nmas == 3 /* DU */ && d_osnma_data.d_nma_header.cpks == 5 /* PKREV */ && d_GST_PKR_PKREV_start == 0){
if (d_osnma_data.d_nma_header.nmas == 3 /* DU */ && d_osnma_data.d_nma_header.cpks == 5 /* PKREV */ && d_GST_PKR_PKREV_start == 0)
{
d_flag_PK_revocation = true;
d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0;
d_public_key_verified = false;
@ -268,16 +281,20 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr<OSNMA_msg>&
LOG(INFO) << "Galileo OSNMA: Public Key Revocation :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]";
std::cout << "Galileo OSNMA: Public Key Revocation :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << std::endl;
}
if (d_flag_PK_revocation && d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 1 /* Nominal */ ){
if (d_flag_PK_revocation && d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 1 /* Nominal */)
{
// step 2 , start using new chain
d_flag_PK_revocation = false;
uint32_t final_GST = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0);
double duration_hours = (final_GST - d_GST_PKR_PKREV_start) / 3600;
LOG(INFO) << "Galileo OSNMA: Public Key Revocation :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << ", Duration=" << duration_hours << "h";
std::cout << "Galileo OSNMA: Public Key Revocation :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << ", Duration=" << duration_hours << "h" << std::endl;
LOG(INFO) << "Galileo OSNMA: Public Key Revocation :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]"
<< ", Duration=" << duration_hours << "h";
std::cout << "Galileo OSNMA: Public Key Revocation :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]"
<< ", Duration=" << duration_hours << "h" << std::endl;
}
if (d_osnma_data.d_nma_header.nmas == 3 /* DU */ && d_osnma_data.d_nma_header.cpks == 7 /* AM */ && d_GST_PKR_AM_start == 0){
if (d_osnma_data.d_nma_header.nmas == 3 /* DU */ && d_osnma_data.d_nma_header.cpks == 7 /* AM */ && d_GST_PKR_AM_start == 0)
{
d_flag_alert_message = true;
d_GST_PKR_AM_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0);
d_public_key_verified = false;
@ -289,7 +306,8 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr<OSNMA_msg>&
read_dsm_header(osnma_msg->hkroot[1]);
read_dsm_block(osnma_msg);
process_dsm_block(osnma_msg); // will process dsm block if received a complete one, then will call mack processing upon re-setting the dsm block to 0
if (d_osnma_data.d_dsm_kroot_message.towh_k != 0){
if (d_osnma_data.d_dsm_kroot_message.towh_k != 0)
{
d_GST_0 = d_helper->compute_gst(d_osnma_data.d_dsm_kroot_message.wn_k, d_osnma_data.d_dsm_kroot_message.towh_k * 3600);
d_GST_Sf = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G.
}
@ -474,7 +492,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
d_osnma_data.d_dsm_kroot_message.kroot = d_dsm_reader->get_kroot(dsm_msg, l_lk_bytes);
// DS field
uint16_t l_ds_bits = 0;
const auto it = OSNMA_TABLE_15.find(d_crypto->d_PublicKeyType);
const auto it = OSNMA_TABLE_15.find(d_crypto->get_public_key_type());
if (it != OSNMA_TABLE_15.cend())
{
l_ds_bits = it->second;
@ -507,12 +525,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
const uint16_t size_m = 13 + l_lk_bytes;
std::vector<uint8_t> MSG;
MSG.reserve(size_m + l_ds_bytes + 1);
MSG.push_back(nma_header); // NMA header
MSG.push_back(nma_header); // NMA header
for (uint16_t i = 1; i < size_m; i++)
{
MSG.push_back(dsm_msg[i]);
}
std::vector<uint8_t> message = MSG; // MSG = (M | DS) from ICD. Eq. 7
std::vector<uint8_t> message = MSG; // MSG = (M | DS) from ICD. Eq. 7
for (uint16_t k = 0; k < l_ds_bytes; k++)
{
MSG.push_back(d_osnma_data.d_dsm_kroot_message.ds[k]);
@ -549,7 +567,8 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
// local_time_verification(osnma_msg); // FIXME TODO: real time verification needed
// If new PK verified and the new KROOT arrived, set the new PK before attempting verification
if(d_flag_PK_renewal && d_osnma_data.d_dsm_kroot_message.pkid == d_new_public_key_id && d_flag_NPK_set == false){
if (d_flag_PK_renewal && d_osnma_data.d_dsm_kroot_message.pkid == d_new_public_key_id && d_flag_NPK_set == false)
{
d_crypto->set_public_key(d_new_public_key);
d_crypto->store_public_key(PEMFILE_DEFAULT);
d_flag_NPK_set = true;
@ -566,7 +585,8 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
{
std::cout << "Galileo OSNMA: DSM-KROOT authentication successful!" << std::endl;
LOG(INFO) << "Galileo OSNMA: DSM-KROOT authentication successful!";
if (d_flag_alert_message){
if (d_flag_alert_message)
{
LOG(WARNING) << "Galileo OSNMA: DSM-KROOT :: Alert message verification :: SUCCESS. ";
}
else
@ -576,7 +596,8 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
<< "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks);
}
// Save DSM-Kroot and NMA header into a permanent storage
if (d_flag_hot_start){
if (d_flag_hot_start)
{
d_flag_hot_start = false;
return;
}
@ -586,10 +607,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
{
LOG(WARNING) << "Galileo OSNMA: DSM-KROOT authentication failed.";
std::cerr << "Galileo OSNMA: DSM-KROOT authentication failed." << std::endl;
if (d_flag_alert_message){
if (d_flag_alert_message)
{
d_flag_alert_message = false;
}
d_count_failed_Kroot ++;
d_count_failed_Kroot++;
}
}
else
@ -613,7 +635,8 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
}
d_osnma_data.d_dsm_pkr_message.npkt = d_dsm_reader->get_npkt(dsm_msg);
uint8_t npktid = d_dsm_reader->get_npktid(dsm_msg);
if (d_flag_PK_renewal && npktid > d_osnma_data.d_dsm_pkr_message.npktid){
if (d_flag_PK_renewal && npktid > d_osnma_data.d_dsm_pkr_message.npktid)
{
d_new_public_key_id = npktid;
}
d_osnma_data.d_dsm_pkr_message.npktid = npktid;
@ -668,15 +691,18 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
{
LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: SUCCESS";
d_public_key_verified = true;
if (d_flag_PK_renewal){
if (d_flag_PK_renewal)
{
d_new_public_key = d_osnma_data.d_dsm_pkr_message.npk;
}
else if (d_flag_alert_message){
else if (d_flag_alert_message)
{
LOG(WARNING) << "Galileo OSNMA: DSM-PKR verification :: Alert message verification :: SUCCESS. OSNMA disabled. Contact Galileo Service Centre";
std::cout << "Galileo OSNMA: DSM-PKR verification :: Alert message verification :: SUCCESS. OSNMA disabled. Contact Galileo Service Centre" << std::endl;
}
else{
d_crypto->d_PublicKeyType = PKT;
else
{
d_crypto->set_public_key_type(PKT);
d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk);
d_crypto->store_public_key(PEMFILE_DEFAULT);
}
@ -685,8 +711,9 @@ void osnma_msg_receiver::process_dsm_message(const std::vector<uint8_t>& dsm_msg
{
LOG(ERROR) << "Galileo OSNMA: DSM-PKR verification :: FAILURE";
d_public_key_verified = false;
d_count_failed_pubKey ++;
if (d_flag_alert_message){
d_count_failed_pubKey++;
if (d_flag_alert_message)
{
d_flag_alert_message = false; // disregard message as its authenticity could not be verified.
}
}
@ -724,9 +751,10 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr<OSNMA
d_osnma_data.d_nav_data.set_tow_sf0(osnma_msg->TOW_sf0);
bool can_process_mack_block = (d_osnma_data.d_nma_header.nmas != 3 && d_kroot_verified) || // NMAS different than DU
(d_osnma_data.d_nma_header.nmas == 3 && !d_kroot_verified); // NMAS is DU, but must be disregarded
bool can_verify_tesla_key = d_kroot_verified || d_tesla_key_verified; // Either of those suffices for verifying the incoming TESLA key
bool can_parse_tag_fields = d_osnma_data.d_dsm_kroot_message.ts != 0; // calculating the number of tags is based on the TS of the DSM-KROOT.
if (can_verify_tesla_key && can_parse_tag_fields && can_process_mack_block){
bool can_verify_tesla_key = d_kroot_verified || d_tesla_key_verified; // Either of those suffices for verifying the incoming TESLA key
bool can_parse_tag_fields = d_osnma_data.d_dsm_kroot_message.ts != 0; // calculating the number of tags is based on the TS of the DSM-KROOT.
if (can_verify_tesla_key && can_parse_tag_fields && can_process_mack_block)
{
read_mack_header();
d_osnma_data.d_mack_message.PRNa = osnma_msg->PRN; // FIXME this is ugly.
d_osnma_data.d_mack_message.TOW = osnma_msg->TOW_sf0;
@ -1617,8 +1645,8 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack)
return true;
}
// Fixed as well as FLX Tags share first part - Eq. 22 ICD
std::vector<uint8_t> m(5 + 2 * flxTags.size()); // each flx tag brings two bytes
m[0] = static_cast<uint8_t>(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag
std::vector<uint8_t> m(5 + 2 * flxTags.size()); // each flx tag brings two bytes
m[0] = static_cast<uint8_t>(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag
m[1] = static_cast<uint8_t>((GST_SFi & 0xFF000000) >> 24);
m[2] = static_cast<uint8_t>((GST_SFi & 0x00FF0000) >> 16);
m[3] = static_cast<uint8_t>((GST_SFi & 0x0000FF00) >> 8);
@ -1863,7 +1891,7 @@ std::vector<MACK_tag_and_info> osnma_msg_receiver::verify_macseq_new(const MACK_
LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: ADKD mismatch against MAC Look-up table for Tag=0x"
<< std::setfill('0') << std::setw(10) << std::hex << std::uppercase
<< mack.tag_and_info[i].tag << std::dec;
d_count_failed_macseq ++;
d_count_failed_macseq++;
}
}
@ -1873,8 +1901,8 @@ std::vector<MACK_tag_and_info> osnma_msg_receiver::verify_macseq_new(const MACK_
return verified_tags;
}
// Fixed as well as FLX Tags share first part - Eq. 22 ICD
std::vector<uint8_t> m(5 + 2 * flxTags.size()); // each flx tag brings two bytes
m[0] = static_cast<uint8_t>(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag
std::vector<uint8_t> m(5 + 2 * flxTags.size()); // each flx tag brings two bytes
m[0] = static_cast<uint8_t>(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag
m[1] = static_cast<uint8_t>((GST_Sfi & 0xFF000000) >> 24);
m[2] = static_cast<uint8_t>((GST_Sfi & 0x00FF0000) >> 16);
m[3] = static_cast<uint8_t>((GST_Sfi & 0x0000FF00) >> 8);
@ -1924,7 +1952,7 @@ void osnma_msg_receiver::send_data_to_pvt(const std::vector<OSNMA_NavData>& data
{
if (!data.empty())
{
for (auto & i : data)
for (auto& i : data)
{
const auto tmp_obj = std::make_shared<OSNMA_NavData>(i);
this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(tmp_obj));
@ -1936,7 +1964,8 @@ bool osnma_msg_receiver::store_dsm_kroot(const std::vector<uint8_t>& dsm, const
{
std::ofstream file(KROOTFILE_DEFAULT, std::ios::binary | std::ios::out);
if (!file.is_open()) {
if (!file.is_open())
{
return false;
}
@ -1952,7 +1981,8 @@ bool osnma_msg_receiver::store_dsm_kroot(const std::vector<uint8_t>& dsm, const
std::pair<std::vector<uint8_t>, uint8_t> osnma_msg_receiver::parse_dsm_kroot() const
{
std::ifstream file(KROOTFILE_DEFAULT, std::ios::binary | std::ios::in);
if (!file) {
if (!file)
{
return {std::vector<uint8_t>(), 0};
}
@ -1965,7 +1995,8 @@ std::pair<std::vector<uint8_t>, uint8_t> osnma_msg_receiver::parse_dsm_kroot() c
file.close();
if (file.bad()) {
if (file.bad())
{
return {std::vector<uint8_t>(), 0};
}

View File

@ -124,6 +124,7 @@ Gnss_Crypto::~Gnss_Crypto()
#endif
}
bool Gnss_Crypto::have_public_key() const
{
#if USE_GNUTLS_FALLBACK
@ -133,6 +134,7 @@ bool Gnss_Crypto::have_public_key() const
#endif
}
bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const
{
if (!have_public_key())
@ -782,63 +784,6 @@ std::vector<uint8_t> Gnss_Crypto::compute_CMAC_AES(const std::vector<uint8_t>& k
return output;
}
// TODO - deprecate: change return type to respective key type, PEM is not needed.
std::vector<uint8_t> Gnss_Crypto::get_public_key() const
{
if (!have_public_key())
{
return {};
}
#if USE_GNUTLS_FALLBACK
gnutls_datum_t pem_data = {nullptr, 0};
#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(WARNING) << "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(WARNING) << "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(WARNING) << "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;
}
std::vector<uint8_t> Gnss_Crypto::get_merkle_root() const
{
@ -846,8 +791,15 @@ std::vector<uint8_t> Gnss_Crypto::get_merkle_root() const
}
std::string Gnss_Crypto::get_public_key_type() const
{
return d_PublicKeyType;
}
void Gnss_Crypto::set_public_key(const std::vector<uint8_t>& publicKey)
{
d_PublicKeyType = "Unknown";
#if USE_GNUTLS_FALLBACK
gnutls_pubkey_t pubkey{};
gnutls_ecc_curve_t curve;
@ -859,16 +811,19 @@ void Gnss_Crypto::set_public_key(const std::vector<uint8_t>& publicKey)
if (size_pk == 33)
{
curve = GNUTLS_ECC_CURVE_SECP256R1;
d_PublicKeyType = "ECDSA P-256";
decompress_public_key_secp256r1(publicKey, x, y);
}
else if (size_pk == 67)
{
curve = GNUTLS_ECC_CURVE_SECP521R1;
d_PublicKeyType = "ECDSA P-521";
decompress_public_key_secp521r1(publicKey, x, y);
}
else
{
LOG(WARNING) << "GnuTLS: Invalid public key size";
gnutls_pubkey_deinit(pubkey);
return;
}
@ -893,22 +848,41 @@ void Gnss_Crypto::set_public_key(const std::vector<uint8_t>& publicKey)
EVP_PKEY_CTX* ctx = nullptr;
OSSL_PARAM_BLD* param_bld;
OSSL_PARAM* params = nullptr;
const size_t public_key_size = publicKey.size();
param_bld = OSSL_PARAM_BLD_new();
if (param_bld != nullptr &&
OSSL_PARAM_BLD_push_utf8_string(param_bld, "group", (publicKey.size() == 33) ? "prime256v1" : "secp521r1", 0) &&
OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", publicKey.data(), publicKey.size())) {
params = OSSL_PARAM_BLD_to_param(param_bld);
OSSL_PARAM_BLD_push_utf8_string(param_bld, "group", (public_key_size == 33) ? "prime256v1" : "secp521r1", 0) &&
OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", publicKey.data(), public_key_size))
{
params = OSSL_PARAM_BLD_to_param(param_bld);
}
if (public_key_size == 33)
{
d_PublicKeyType = "ECDSA P-256";
}
else if (public_key_size == 67)
{
d_PublicKeyType = "ECDSA P-521";
}
ctx = EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr);
if (ctx == nullptr || params == nullptr || EVP_PKEY_fromdata_init(ctx) <= 0 || EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
{
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
OSSL_PARAM_free(params);
OSSL_PARAM_BLD_free(param_bld);
return;
}
if (!pubkey_copy(pkey, &d_PublicKey))
{
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
OSSL_PARAM_free(params);
OSSL_PARAM_BLD_free(param_bld);
return;
}
@ -923,10 +897,12 @@ void Gnss_Crypto::set_public_key(const std::vector<uint8_t>& publicKey)
if (publicKey.size() == 33) // ECDSA-P-256
{
group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
d_PublicKeyType = "ECDSA P-256";
}
else // ECDSA-P-521
{
group = EC_GROUP_new_by_curve_name(NID_secp521r1);
d_PublicKeyType = "ECDSA P-256";
}
if (!group)
{
@ -974,6 +950,15 @@ void Gnss_Crypto::set_public_key(const std::vector<uint8_t>& publicKey)
}
void Gnss_Crypto::set_public_key_type(const std::string& public_key_type)
{
if (public_key_type == "ECDSA P-256" || public_key_type == "ECDSA P-521")
{
d_PublicKeyType = public_key_type;
}
}
void Gnss_Crypto::set_merkle_root(const std::vector<uint8_t>& v)
{
d_x_4_0 = v;
@ -1038,6 +1023,14 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath)
LOG(INFO) << "OSNMA Merkletree - Length in Bits: " << lengthInBits;
LOG(INFO) << "OSNMA Merkletree - Point: " << point;
LOG(INFO) << "OSNMA Merkletree - PK Type: " << pkType;
if (pkType == "ECDSA P-256/SHA-256")
{
d_PublicKeyType = "ECDSA P-256";
}
else if (pkType == "ECDSA P-521/SHA-512")
{
d_PublicKeyType = "ECDSA P-521";
}
}
for (pugi::xml_node treeNode : merkleTree.children("TreeNode"))
{
@ -1122,6 +1115,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath)
bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath)
{
d_PublicKeyType = "Unknown";
#if USE_GNUTLS_FALLBACK
// Open the .crt file
std::ifstream crtFile(crtFilePath, std::ios::binary);
@ -1160,6 +1154,72 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath)
gnutls_x509_crt_deinit(cert);
return false;
}
// 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: " << gnutls_strerror(ret);
gnutls_pubkey_deinit(pubkey);
gnutls_x509_crt_deinit(cert);
return false;
}
pk_algorithm = static_cast<gnutls_pk_algorithm_t>(ret);
if (pk_algorithm == GNUTLS_PK_ECDSA)
{
gnutls_datum_t params;
ret = gnutls_pubkey_export_ecc_raw(pubkey, nullptr, &params, 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<const char*>(params.data));
gnutls_free(params.data);
if (ret < 0)
{
LOG(WARNING) << "GnuTLS: Failed to get EC curve: " << gnutls_strerror(ret);
gnutls_pubkey_deinit(pubkey);
gnutls_x509_crt_deinit(cert);
return false;
}
curve = static_cast<gnutls_ecc_curve_t>(ret);
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";
gnutls_x509_crt_deinit(cert);
gnutls_pubkey_deinit(pubkey);
return false;
}
}
else
{
LOG(WARNING) << "GnuTLS: Trying to read unknown key type";
gnutls_x509_crt_deinit(cert);
gnutls_pubkey_deinit(pubkey);
return false;
}
pubkey_copy(pubkey, &d_PublicKey);
gnutls_x509_crt_deinit(cert);
gnutls_pubkey_deinit(pubkey);
@ -1190,27 +1250,69 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath)
// Read the public key from the certificate
EVP_PKEY* pubkey = X509_get_pubkey(cert);
// store the key type - needed for the Kroot in case no DSM-PKR available
// TODO - only way I have found to find the curve type
const auto *const ec_key = EVP_PKEY_get0_EC_KEY(pubkey);
const EC_GROUP *group = EC_KEY_get0_group(ec_key);
int nid = EC_GROUP_get_curve_name(group);
if (nid == NID_X9_62_prime256v1) {
d_PublicKeyType = "ECDSA P-256";
} else if (nid == NID_secp521r1) {
d_PublicKeyType = "ECDSA P-521";
}
#if USE_OPENSSL_3
if (!pubkey)
{
LOG(WARNING) << "OpenSSL: Failed to extract the public key";
X509_free(cert);
return false;
}
#if USE_OPENSSL_3
// 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";
X509_free(cert);
return false;
}
}
else
{
d_PublicKeyType = "Unknown EC curve";
LOG(WARNING) << "OpenSSL: Trying to read an unknown EC curve";
X509_free(cert);
return false;
}
}
else
{
LOG(WARNING) << "OpenSSL: Trying to read an unknown key type";
X509_free(cert);
return false;
}
pubkey_copy(pubkey, &d_PublicKey);
EVP_PKEY_free(pubkey);
#else // OpenSSL 1.x
// store the key type - needed for the Kroot in case no DSM-PKR available
const auto ec_key = EVP_PKEY_get0_EC_KEY(pubkey);
const EC_GROUP* group = EC_KEY_get0_group(ec_key);
const int nid = EC_GROUP_get_curve_name(group);
if (nid == NID_X9_62_prime256v1)
{
d_PublicKeyType = "ECDSA P-256";
}
else if (nid == NID_secp521r1)
{
d_PublicKeyType = "ECDSA P-521";
}
EC_KEY* ec_pubkey = EVP_PKEY_get1_EC_KEY(pubkey);
EVP_PKEY_free(pubkey);
if (!ec_pubkey)
@ -1299,6 +1401,7 @@ std::vector<uint8_t> Gnss_Crypto::convert_from_hex_str(const std::string& input)
return result;
}
#if USE_GNUTLS_FALLBACK // GnuTLS-specific functions
bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest)
{

View File

@ -66,13 +66,13 @@ public:
std::vector<uint8_t> compute_HMAC_SHA_256(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input) const; //!< Computes HMAC-SHA-256 message authentication code
std::vector<uint8_t> compute_CMAC_AES(const std::vector<uint8_t>& key, const std::vector<uint8_t>& input) const; //!< Computes CMAC-AES message authentication code
std::vector<uint8_t> get_public_key() const; //!< Gets the ECDSA Public Key in PEM format
std::vector<uint8_t> get_merkle_root() const; //!< Gets the Merkle Tree root node (\f$ x_{4,0} \f$)
std::string get_public_key_type() const; //!< Gets the ECDSA Public Key type (ECDSA P-256 / ECDSA P-521 / Unknown)
void set_public_key(const std::vector<uint8_t>& publickey); //!< Sets the ECDSA Public Key (publickey compressed format)
void set_merkle_root(const std::vector<uint8_t>& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$)
void read_merkle_xml(const std::string& merkleFilePath);
std::string d_PublicKeyType;
void set_public_key(const std::vector<uint8_t>& publickey); //!< Sets the ECDSA Public Key (publickey compressed format)
void set_public_key_type(const std::string& public_key_type); //!< Sets the ECDSA Public Key type (ECDSA P-256 / ECDSA P-521)
void set_merkle_root(const std::vector<uint8_t>& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$)
void read_merkle_xml(const std::string& merkleFilePath); //!> Reads the XML file provided from the GSC OSNMA server
private:
void readPublicKeyFromPEM(const std::string& pemFilePath);
@ -94,6 +94,7 @@ private:
#endif
#endif
std::vector<uint8_t> d_x_4_0;
std::string d_PublicKeyType;
};
/** \} */

View File

@ -38,6 +38,8 @@ void OSNMA_nav_data_Manager::add_navigation_data(const std::string& nav_bits, ui
_satellite_nav_data[PRNd][TOW].set_tow_sf0(TOW);
}
}
/**
* @brief loops over the verified tags and updates the navigation data tag length
*/
@ -55,7 +57,8 @@ void OSNMA_nav_data_Manager::update_nav_data(const std::multimap<uint32_t, Tag>&
for (auto & tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset
{
std::string nav_data;
if (tag.second.ADKD == 0 || tag.second.ADKD == 12){
if (tag.second.ADKD == 0 || tag.second.ADKD == 12)
{
nav_data = tow_it.second.get_ephemeris_data();
}
else if (tag.second.ADKD == 4){
@ -70,11 +73,15 @@ void OSNMA_nav_data_Manager::update_nav_data(const std::multimap<uint32_t, Tag>&
}
}
}
bool OSNMA_nav_data_Manager::have_PRNd_nav_data(uint32_t PRNd)
{
// check if have data from PRNd in _satellite_nav_data
return _satellite_nav_data.find(PRNd) != _satellite_nav_data.end();
}
std::vector<OSNMA_NavData> OSNMA_nav_data_Manager::get_verified_data()
{
std::vector<OSNMA_NavData> result;
@ -91,6 +98,8 @@ std::vector<OSNMA_NavData> OSNMA_nav_data_Manager::get_verified_data()
}
return result;
}
bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD)
{
if (ADKD == 0 || ADKD == 12)
@ -119,6 +128,8 @@ bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t
}
return false;
}
/**
* @brief returns OSNMA_NavData object.
* @remarks assumes it exists (called have_nav_data before), otherwise undefined behavior
@ -140,13 +151,16 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag)
{
if (tag.ADKD == 0 || tag.ADKD == 12)
{
if (!tow_it.second.get_ephemeris_data().empty()){
if (!tow_it.second.get_ephemeris_data().empty())
{
return tow_it.second.get_ephemeris_data();
}
}
else if(tag.ADKD == 4)
{
if (!tow_it.second.get_utc_data().empty()){
if (!tow_it.second.get_utc_data().empty())
{
return tow_it.second.get_utc_data();
}
}
@ -154,6 +168,8 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag)
}
return "";
}
/**
* @brief Checks if the OSNMA_NavData bits are already present. In case affirmative, it updates the OSNMA_NavData 'last received' timestamp
* @remarks e.g.: a SV may repeat the bits over several subframes. In that case, need to save them only once.
@ -182,6 +198,8 @@ bool OSNMA_nav_data_Manager::have_nav_data(const std::string& nav_bits, uint32_t
}
return false;
}
/**
* @brief Checks if there is a OSNMA_NavData element within the COP time interval for a Tag t
* @param t Tag object
@ -202,13 +220,15 @@ bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const
{
if (t.ADKD == 0 || t.ADKD == 12)
{
if (!tow_it.second.get_ephemeris_data().empty()){
if (!tow_it.second.get_ephemeris_data().empty())
{
return true;
}
}
else if (t.ADKD == 4)
{
if (!tow_it.second.get_utc_data().empty()){
if (!tow_it.second.get_utc_data().empty())
{
return true;
}
}
@ -216,6 +236,8 @@ bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const
}
return false;
}
void OSNMA_nav_data_Manager::print_status()
{
for (const auto& satellite : _satellite_nav_data){

View File

@ -34,8 +34,10 @@ TEST(GnssCryptoTest, VerifyPubKeyImport)
// Input taken from RG 1.3 A7.1
// compressed ECDSA P-256 format
std::vector<uint8_t> publicKey = {
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B, 0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86,
0x32, 0x0D, 0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7, 0x79, 0x80, 0xEA};
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B,
0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D,
0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7,
0x79, 0x80, 0xEA};
ASSERT_FALSE(d_crypto->have_public_key());
@ -55,8 +57,10 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage)
// Input taken from RG 1.3 A7.1
// compressed ECDSA P-256 format
std::vector<uint8_t> publicKey = {
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B, 0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86,
0x32, 0x0D, 0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7, 0x79, 0x80, 0xEA};
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B,
0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D,
0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7,
0x79, 0x80, 0xEA};
d_crypto->set_public_key(publicKey);
bool result = d_crypto->store_public_key(f1);
@ -75,10 +79,6 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage)
ASSERT_EQ(content_file, content_file2);
// TODO - this cannot be tested right now
// std::vector<uint8_t> readkey = d_crypto2->get_public_key();
// ASSERT_EQ(publicKey, readkey);
errorlib::error_code ec;
ASSERT_TRUE(fs::remove(fs::path(f1), ec));
ASSERT_TRUE(fs::remove(fs::path(f2), ec));
@ -93,8 +93,9 @@ TEST(GnssCryptoTest, TestComputeSHA_256)
std::vector<uint8_t> expected_output = {
0x18, 0x94, 0xA1, 0x9C, 0x85, 0xBA, 0x15, 0x3A, 0xCB, 0xF7,
0x43, 0xAC, 0x4E, 0x43, 0xFC, 0x00, 0x4C, 0x89, 0x16, 0x04, 0xB2,
0x6F, 0x8C, 0x69, 0xE1, 0xE8, 0x3E, 0xA2, 0xAF, 0xC7, 0xC4, 0x8F};
0x43, 0xAC, 0x4E, 0x43, 0xFC, 0x00, 0x4C, 0x89, 0x16, 0x04,
0xB2, 0x6F, 0x8C, 0x69, 0xE1, 0xE8, 0x3E, 0xA2, 0xAF, 0xC7,
0xC4, 0x8F};
std::vector<uint8_t> output = d_crypto->compute_SHA_256(message);
@ -111,7 +112,8 @@ TEST(GnssCryptoTest, TestComputeSHA3_256)
std::vector<uint8_t> expected_output = {
0xCC, 0xB8, 0xF9, 0x23, 0x5F, 0x4A, 0x93, 0x2C, 0xA0, 0xAB,
0xBB, 0x2C, 0x24, 0x36, 0x72, 0x5E, 0x2E, 0x8D, 0xC7, 0x5B,
0x99, 0xE7, 0xF6, 0xC4, 0x50, 0x5B, 0x2A, 0x93, 0x6E, 0xB6, 0x3B, 0x3F};
0x99, 0xE7, 0xF6, 0xC4, 0x50, 0x5B, 0x2A, 0x93, 0x6E, 0xB6,
0x3B, 0x3F};
std::vector<uint8_t> output = d_crypto->compute_SHA3_256(message);
@ -254,8 +256,10 @@ TEST(GnssCryptoTest, VerifySignatureP256)
// Input taken from RG 1.3 A7.1
// compressed ECDSA P-256 format
std::vector<uint8_t> publicKey = {
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B, 0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86,
0x32, 0x0D, 0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7, 0x79, 0x80, 0xEA};
0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B,
0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D,
0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7,
0x79, 0x80, 0xEA};
d_crypto->set_public_key(publicKey);
bool result = d_crypto->verify_signature_ecdsa_p256(message, signature);