From d8a3ae005d290e84e03365738bea3cb173cafa4a Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 23 May 2023 02:23:36 +0200 Subject: [PATCH 001/219] Start work on OSNMA --- .../galileo_telemetry_decoder_gs.cc | 35 ++++---- .../system_parameters/galileo_inav_message.cc | 82 +++++++++++++++---- .../system_parameters/galileo_inav_message.h | 40 +++++++-- 3 files changed, 119 insertions(+), 38 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 2c2693c44..32f9656fc 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -430,11 +430,11 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_ephemeris()); if (d_band == '1') { - std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << '\n'; + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << std::endl; } else if (d_band == '7') { - std::cout << TEXT_BLUE << "New Galileo E5b I/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << '\n'; + std::cout << TEXT_BLUE << "New Galileo E5b I/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << std::endl; } this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); d_first_eph_sent = true; // do not send reduced CED anymore, since we have the full ephemeris set @@ -445,7 +445,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in if ((d_band == '1') && !d_first_eph_sent && (d_inav_nav.have_new_reduced_ced() == true)) { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_reduced_ced()); - std::cout << "New Galileo E1 I/NAV reduced CED message received in channel " << d_channel << " from satellite " << d_satellite << '\n'; + std::cout << "New Galileo E1 I/NAV reduced CED message received in channel " << d_channel << " from satellite " << d_satellite << std::endl; this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); } } @@ -456,11 +456,11 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_iono()); if (d_band == '1') { - std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << '\n'; + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << std::endl; } else if (d_band == '7') { - std::cout << TEXT_BLUE << "New Galileo E5b I/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << TEXT_RESET << '\n'; + std::cout << TEXT_BLUE << "New Galileo E5b I/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; } this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); } @@ -471,11 +471,11 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_utc_model()); if (d_band == '1') { - std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << '\n'; + std::cout << "New Galileo E1 I/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << std::endl; } else if (d_band == '7') { - std::cout << TEXT_BLUE << "New Galileo E5b I/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << '\n'; + std::cout << TEXT_BLUE << "New Galileo E5b I/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; } this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); d_delta_t = tmp_obj->A_0G + tmp_obj->A_1G * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - tmp_obj->t_0G + 604800 * (std::fmod(static_cast(d_inav_nav.get_Galileo_week() - tmp_obj->WN_0G), 64.0))); @@ -489,16 +489,23 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in // debug if (d_band == '1') { - std::cout << "Galileo E1 I/NAV almanac received in channel " << d_channel << " from satellite " << d_satellite << '\n'; + std::cout << "Galileo E1 I/NAV almanac received in channel " << d_channel << " from satellite " << d_satellite << std::endl; } else if (d_band == '7') { - std::cout << TEXT_BLUE << "Galileo E5b I/NAV almanac received in channel " << d_channel << " from satellite " << d_satellite << TEXT_RESET << '\n'; + std::cout << TEXT_BLUE << "Galileo E5b I/NAV almanac received in channel " << d_channel << " from satellite " << d_satellite << TEXT_RESET << std::endl; } DLOG(INFO) << "Current parameters:"; DLOG(INFO) << "d_TOW_at_current_symbol_ms=" << d_TOW_at_current_symbol_ms; DLOG(INFO) << "d_nav.WN_0=" << d_inav_nav.get_Galileo_week(); } + + if (d_band == '1' && d_inav_nav.have_new_nma() == true) + { + const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); + // this->message_port_pub(pmt::mp("whatever"), pmt::make_any(tmp_obj)); + std::cout << "Galileo OSNMA message received in channel " << d_channel << " from satellite " << d_satellite << std::endl; + } } @@ -557,21 +564,21 @@ void galileo_telemetry_decoder_gs::decode_FNAV_word(float *page_symbols, int32_t if (d_fnav_nav.have_new_ephemeris() == true) { const std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_ephemeris()); - std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << '\n'; + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": ephemeris from satellite " << d_satellite << TEXT_RESET << std::endl; this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); } if (d_fnav_nav.have_new_iono_and_GST() == true) { const std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_iono()); - std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << TEXT_RESET << '\n'; + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": iono/GST model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); } if (d_fnav_nav.have_new_utc_model() == true) { const std::shared_ptr tmp_obj = std::make_shared(d_fnav_nav.get_utc_model()); - std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << '\n'; + std::cout << TEXT_MAGENTA << "New Galileo E5a F/NAV message received in channel " << d_channel << ": UTC model parameters from satellite " << d_satellite << TEXT_RESET << std::endl; this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); } } @@ -631,7 +638,7 @@ void galileo_telemetry_decoder_gs::decode_CNAV_word(uint64_t time_stamp, float * d_cnav_dummy_page = is_page_dummy; std::cout << TEXT_MAGENTA << "Receiving Galileo E6 CNAV dummy pages in channel " << d_channel << " from satellite " << d_satellite - << TEXT_RESET << '\n'; + << TEXT_RESET << std::endl; } } else @@ -648,7 +655,7 @@ void galileo_telemetry_decoder_gs::decode_CNAV_word(uint64_t time_stamp, float * std::cout << TEXT_MAGENTA << "Receiving Galileo E6 HAS pages" << (d_cnav_nav.is_HAS_in_test_mode() == true ? " (test mode) " : " ") << "in channel " << d_channel << " from satellite " << d_satellite - << TEXT_RESET << '\n'; + << TEXT_RESET << std::endl; } } } diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index 3c946b487..d852d9405 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -176,8 +176,6 @@ bool Galileo_Inav_Message::read_navigation_bool(const std::bitset page_type_bits(page_number_bits); // from string to bitset - Page_type = static_cast(read_page_type_unsigned(page_type_bits, TYPE)); - Page_type_time_stamp = Page_type; const std::string Data_jk_ephemeris = Data_k + Data_j; page_jk_decoder(Data_jk_ephemeris.c_str()); + + // Fill OSNMA data + if (page_position_in_inav_subframe != 255) + { + if (page_position_in_inav_subframe == 0) + { + nma_position_filled = std::array{}; + nma_msg.mack = std::array{}; + nma_msg.hkroot = std::array{}; + } + std::bitset<8> hkroot_bs(osnma_sis.substr(0, 8)); + std::bitset<32> mack_bs(osnma_sis.substr(8, 32)); + if (hkroot_bs.count() != 0 && mack_bs.count() != 0) + { + hkroot_sis = static_cast(hkroot_bs.to_ulong()); + mack_sis = static_cast(mack_bs.to_ulong()); + nma_msg.mack[page_position_in_inav_subframe] = mack_sis; + nma_msg.hkroot[page_position_in_inav_subframe] = hkroot_sis; + nma_position_filled[page_position_in_inav_subframe] = 1; + } + } } else { @@ -690,6 +700,7 @@ void Galileo_Inav_Message::read_page_4(const std::bitset& IOD_nav_4 = static_cast(read_navigation_unsigned(data_bits, IOD_NAV_4_BIT)); DLOG(INFO) << "IOD_nav_4= " << IOD_nav_4; SV_ID_PRN_4 = static_cast(read_navigation_unsigned(data_bits, SV_ID_PRN_4_BIT)); + nma_msg.PRN = static_cast(SV_ID_PRN_4); DLOG(INFO) << "SV_ID_PRN_4= " << SV_ID_PRN_4; C_ic_4 = static_cast(read_navigation_signed(data_bits, C_IC_4_BIT)); C_ic_4 = C_ic_4 * C_IC_4_LSB; @@ -844,6 +855,11 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) const auto page_number = static_cast(read_navigation_unsigned(data_jk_bits, PAGE_TYPE_BIT)); DLOG(INFO) << "Page number = " << page_number; + if (page_position_in_inav_subframe != 255) + { + page_position_in_inav_subframe++; + } + switch (page_number) { case 1: // Word type 1: Ephemeris (1/4) @@ -884,6 +900,10 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) case 2: // Word type 2: Ephemeris (2/4) { + page_position_in_inav_subframe = 0; + nma_msg.mack = std::array{}; + nma_msg.hkroot = std::array{}; + nma_position_filled = std::array{}; read_page_2(data_jk_bits); if (enable_rs) { @@ -1371,5 +1391,35 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) default: break; } + + if (page_position_in_inav_subframe > 14 && page_position_in_inav_subframe != 255) + { + // something weird happened, reset + page_position_in_inav_subframe = 255; + nma_position_filled = std::array{}; + nma_msg.mack = std::array{}; + nma_msg.hkroot = std::array{}; + } + return page_number; } + + +OSNMA_msg Galileo_Inav_Message::get_osnma_msg() const +{ + return nma_msg; +} + + +bool Galileo_Inav_Message::have_new_nma() +{ + if (std::all_of(nma_position_filled.begin(), nma_position_filled.end(), + [](int32_t element) { return element == 1; })) + { + return true; + } + else + { + return false; + } +} diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 1b37e9083..1d986a1b4 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -25,6 +25,7 @@ #include "galileo_iono.h" #include "galileo_utc_model.h" #include "gnss_sdr_make_unique.h" // for std::unique_ptr in C++11 +#include #include #include #include @@ -39,6 +40,14 @@ class ReedSolomon; // Forward declaration of the ReedSolomon class /** \addtogroup System_Parameters * \{ */ +class OSNMA_msg +{ +public: + OSNMA_msg() = default; + std::array mack{}; + std::array hkroot{}; + uint32_t PRN{}; +}; /*! * \brief This class handles the Galileo I/NAV Data message, as described in the @@ -57,13 +66,6 @@ public: */ void split_page(std::string page_string, int32_t flag_even_word); - /* - * \brief Takes in input Data_jk (128 bit) and split it in ephemeris parameters according ICD 4.3.5 - * - * Takes in input Data_jk (128 bit) and split it in ephemeris parameters according ICD 4.3.5 - */ - int32_t page_jk_decoder(const char* data_jk); - /* * \brief Returns true if new Ephemeris has arrived. The flag is set to false when the function is executed */ @@ -89,6 +91,11 @@ public: */ bool have_new_reduced_ced(); + /* + * \brief Returns true if new NMA data have arrived. The flag is set to false when the function is executed + */ + bool have_new_nma(); + /* * \brief Returns a Galileo_Ephemeris object filled with the latest navigation data received */ @@ -114,6 +121,11 @@ public: */ Galileo_Ephemeris get_reduced_ced() const; + /* + * \brief Returns an OSNMA_msg object filled with the latest NMA message received. Resets msg buffer. + */ + OSNMA_msg get_osnma_msg() const; + inline bool get_flag_CRC_test() const { return flag_CRC_test; @@ -210,6 +222,11 @@ public: inline void init_PRN(uint32_t prn) { SV_ID_PRN_4 = prn; + nma_msg.PRN = prn; + nma_msg.mack = std::array{}; + nma_msg.hkroot = std::array{}; + page_position_in_inav_subframe = 255; + nma_position_filled = std::array{}; } /* @@ -242,7 +259,7 @@ private: std::unique_ptr rs; // The Reed-Solomon decoder std::vector inav_rs_pages; // Pages 1,2,3,4,17,18,19,20. Holds 1 if the page has arrived, 0 otherwise. - int32_t Page_type_time_stamp{}; + int32_t page_jk_decoder(const char* data_jk); int32_t IOD_ephemeris{}; // Word type 1: Ephemeris (1/4) @@ -394,6 +411,13 @@ private: int32_t current_IODnav{}; + // OSNMA + uint32_t mack_sis{}; + uint8_t hkroot_sis{}; + uint8_t page_position_in_inav_subframe{255}; + std::array nma_position_filled{}; + OSNMA_msg nma_msg{}; + uint8_t IODnav_LSB17{}; uint8_t IODnav_LSB18{}; uint8_t IODnav_LSB19{}; From 916dde2174fe33eee7c2be252b02f25b6599a40e Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 23 May 2023 12:11:53 +0200 Subject: [PATCH 002/219] Add work on OSNMA receiver --- .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 27 ++++ .../PVT/gnuradio_blocks/rtklib_pvt_gs.h | 2 + .../galileo_telemetry_decoder_gs.cc | 30 ++++- .../galileo_telemetry_decoder_gs.h | 1 + .../telemetry_decoder/libs/tlm_conf.cc | 5 + .../telemetry_decoder/libs/tlm_conf.h | 1 + src/core/libs/CMakeLists.txt | 2 + src/core/libs/osnma_msg_receiver.cc | 124 ++++++++++++++++++ src/core/libs/osnma_msg_receiver.h | 66 ++++++++++ src/core/receiver/gnss_flowgraph.cc | 63 +++++++++ src/core/receiver/gnss_flowgraph.h | 4 + src/core/system_parameters/CMakeLists.txt | 2 + src/core/system_parameters/osnma_data.cc | 17 +++ src/core/system_parameters/osnma_data.h | 69 ++++++++++ 14 files changed, 411 insertions(+), 2 deletions(-) create mode 100644 src/core/libs/osnma_msg_receiver.cc create mode 100644 src/core/libs/osnma_msg_receiver.h create mode 100644 src/core/system_parameters/osnma_data.cc create mode 100644 src/core/system_parameters/osnma_data.h diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 8f6f1648a..6f882448c 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -213,6 +213,19 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, #else boost::bind(&rtklib_pvt_gs::msg_handler_has_data, this, _1)); #endif +#endif + + // Galileo OSNMA messages port in + this->message_port_register_in(pmt::mp("OSNMA_to_PVT")); + this->set_msg_handler(pmt::mp("OSNMA_to_PVT"), +#if HAS_GENERIC_LAMBDA + [this](auto&& PH1) { msg_handler_osnma(PH1); }); +#else +#if USE_BOOST_BIND_PLACEHOLDERS + boost::bind(&rtklib_pvt_gs::msg_handler_osnma, this, boost::placeholders::_1)); +#else + boost::bind(&rtklib_pvt_gs::msg_handler_osnma, this, _1)); +#endif #endif d_initial_carrier_phase_offset_estimation_rads = std::vector(nchannels, 0.0); @@ -1633,6 +1646,20 @@ void rtklib_pvt_gs::msg_handler_has_data(const pmt::pmt_t& msg) } +void rtklib_pvt_gs::msg_handler_osnma(const pmt::pmt_t& msg) +{ + try + { + const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); + // Process NMA data + } + catch (const wht::bad_any_cast& e) + { + LOG(WARNING) << "msg_handler_osnma Bad any_cast: " << e.what(); + } +} + + std::map rtklib_pvt_gs::get_gps_ephemeris_map() const { return d_internal_pvt_solver->gps_ephemeris_map; diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h index 747c31c65..3bbccd0cc 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h @@ -144,6 +144,8 @@ private: void msg_handler_has_data(const pmt::pmt_t& msg); + void msg_handler_osnma(const pmt::pmt_t& msg); + void initialize_and_apply_carrier_phase_offset(); void apply_rx_clock_offset(std::map& observables_map, diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 32f9656fc..e041d2c99 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -105,6 +105,7 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs( d_enable_reed_solomon_inav(false), d_valid_timetag(false), d_E6_TOW_set(false), + d_there_are_e1_channels(conf.there_are_e1_channels), d_there_are_e6_channels(conf.there_are_e6_channels) { // prevent telemetry symbols accumulation in output buffers @@ -114,12 +115,19 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs( // Control messages to tracking block this->message_port_register_out(pmt::mp("telemetry_to_trk")); + if (d_there_are_e1_channels) + { + // register OSM out + this->message_port_register_out(pmt::mp("OSNMA_from_TLM")); + } + if (d_there_are_e6_channels) { // register Gal E6 messages HAS out this->message_port_register_out(pmt::mp("E6_HAS_from_TLM")); // register TOW from map out this->message_port_register_out(pmt::mp("TOW_from_TLM")); + // register TOW to TLM input this->message_port_register_in(pmt::mp("TOW_to_TLM")); // handler for input port @@ -503,8 +511,26 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in if (d_band == '1' && d_inav_nav.have_new_nma() == true) { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); - // this->message_port_pub(pmt::mp("whatever"), pmt::make_any(tmp_obj)); - std::cout << "Galileo OSNMA message received in channel " << d_channel << " from satellite " << d_satellite << std::endl; + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); + uint8_t nma_status = (tmp_obj->hkroot[0] & 0b11000000) << 6; + std::string nma_status_string; + if (nma_status == 0) + { + nma_status_string = std::string("(Reserved mode)"); + } + else if (nma_status == 1) + { + nma_status_string = std::string("(Test mode)"); + } + else if (nma_status == 2) + { + nma_status_string = std::string("(Operational mode)"); + } + else if (nma_status == 3) + { + nma_status_string = std::string("(Do not use mode)"); + } + std::cout << "Galileo OSNMA message " << nma_status_string << " received in channel " << d_channel << " from satellite " << d_satellite << std::endl; } } diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h index dd6253829..eee7dd4b4 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h @@ -151,6 +151,7 @@ private: bool d_enable_reed_solomon_inav; bool d_valid_timetag; bool d_E6_TOW_set; + bool d_there_are_e1_channels; bool d_there_are_e6_channels; }; diff --git a/src/algorithms/telemetry_decoder/libs/tlm_conf.cc b/src/algorithms/telemetry_decoder/libs/tlm_conf.cc index 2b9b3c59d..cf4a248c9 100644 --- a/src/algorithms/telemetry_decoder/libs/tlm_conf.cc +++ b/src/algorithms/telemetry_decoder/libs/tlm_conf.cc @@ -30,6 +30,11 @@ void Tlm_Conf::SetFromConfiguration(const ConfigurationInterface *configuration, const std::string default_crc_stats_dumpname("telemetry_crc_stats"); dump_crc_stats_filename = configuration->property(role + ".dump_crc_stats_filename", default_crc_stats_dumpname); enable_navdata_monitor = configuration->property("NavDataMonitor.enable_monitor", false); + if (configuration->property("Channels_1B.count", 0) > 0) + { + there_are_e1_channels = true; + } + if (configuration->property("Channels_E6.count", 0) > 0) { there_are_e6_channels = true; diff --git a/src/algorithms/telemetry_decoder/libs/tlm_conf.h b/src/algorithms/telemetry_decoder/libs/tlm_conf.h index abac3ac87..c0e14695c 100644 --- a/src/algorithms/telemetry_decoder/libs/tlm_conf.h +++ b/src/algorithms/telemetry_decoder/libs/tlm_conf.h @@ -42,6 +42,7 @@ public: bool enable_reed_solomon{false}; // for INAV message in Galileo E1B bool dump_crc_stats{false}; // telemetry CRC statistics bool enable_navdata_monitor{false}; + bool there_are_e1_channels{false}; bool there_are_e6_channels{false}; }; diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index 994501ecf..1c0c6e811 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -21,6 +21,7 @@ set(CORE_LIBS_SOURCES nav_message_monitor.cc nav_message_udp_sink.cc galileo_tow_map.cc + osnma_msg_receiver.cc ) set(CORE_LIBS_HEADERS @@ -37,6 +38,7 @@ set(CORE_LIBS_HEADERS serdes_nav_message.h nav_message_monitor.h galileo_tow_map.h + osnma_msg_receiver.h ) if(ENABLE_FPGA) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc new file mode 100644 index 000000000..79ebcc48d --- /dev/null +++ b/src/core/libs/osnma_msg_receiver.cc @@ -0,0 +1,124 @@ +/*! + * \file osnma_msg_receiver.cc + * \brief GNU Radio block that processes Galileo OSNMA data received from + * Galileo E1B telemetry blocks. After successful decoding, sends the content to + * the PVT block. + * \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#include "osnma_msg_receiver.h" +#include "display.h" // for colors in terminal +#include "gnss_sdr_make_unique.h" // for std::make_unique in C++11 +#include // for DLOG +#include // for gr::io_signature::make +#include +#include +#include +#include // for typeid + +#if HAS_GENERIC_LAMBDA +#else +#include +#endif + +#if PMT_USES_BOOST_ANY +#include +namespace wht = boost; +#else +#include +namespace wht = std; +#endif + +osnma_msg_receiver_sptr osnma_msg_receiver_make() +{ + return osnma_msg_receiver_sptr(new osnma_msg_receiver()); +} + + +osnma_msg_receiver::osnma_msg_receiver() : gr::block("osnma_msg_receiver", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) +{ + // register OSNMA input message port from telemetry blocks + this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); + // register OSNMA output message port to PVT block + this->message_port_register_out(pmt::mp("OSNMA_to_PVT")); + + this->set_msg_handler(pmt::mp("OSNMA_from_TLM"), +#if HAS_GENERIC_LAMBDA + [this](auto&& PH1) { msg_handler_osnma(PH1); }); +#else +#if USE_BOOST_BIND_PLACEHOLDERS + boost::bind(&osnma_msg_receiver::msg_handler_osnma, this, boost::placeholders::_1)); +#else + boost::bind(&osnma_msg_receiver::msg_handler_osnma, this, _1)); +#endif +#endif +} + + +void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) +{ + gr::thread::scoped_lock lock(d_setlock); // require mutex with msg_handler_osnma function called by the scheduler + try + { + const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); + if (msg_type_hash_code == typeid(OSNMA_msg).hash_code()) + { + const auto nma_msg = wht::any_cast(pmt::any_ref(msg)); + process_osnma_message(nma_msg); + } + else + { + LOG(WARNING) << "osnma_msg_receiver received an unknown object type!"; + } + } + catch (const wht::bad_any_cast& e) + { + LOG(WARNING) << "osnma_msg_receiver Bad any_cast: " << e.what(); + } + + // Send the resulting decoded NMA data (if available) to PVT + if (d_new_data == true) + { + auto osnma_data_ptr = std::make_shared(d_osnma_data); + this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); + d_new_data = false; + DLOG(INFO) << "NMA info sent to the PVT block through the OSNMA_to_PVT async message port"; + } +} + + +void osnma_msg_receiver::process_osnma_message(const OSNMA_msg& osnma_msg) +{ + auto hkroot_msg = osnma_msg.hkroot; + read_nma_header(hkroot_msg[0]); + read_dsm_header(hkroot_msg[1]); +} + + +void osnma_msg_receiver::read_nma_header(uint8_t nma_header) +{ + d_osnma_data.d_nma_header.nmas = (nma_header & 0b11000000) << 6; + d_osnma_data.d_nma_header.cid = (nma_header & 0b00110000) << 4; + d_osnma_data.d_nma_header.cpks = (nma_header & 0b00001110) << 1; + d_osnma_data.d_nma_header.reserved = ((nma_header & 0b00000001) ? true : false); +} + + +void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) +{ + d_osnma_data.d_dsm_header.dsm_id = (dsm_header & 0b11110000) << 4; + d_osnma_data.d_dsm_header.dsm_block_id = dsm_header & 0b00001111; +} \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h new file mode 100644 index 000000000..f9629d133 --- /dev/null +++ b/src/core/libs/osnma_msg_receiver.h @@ -0,0 +1,66 @@ +/*! + * \file osnma_msg_receiver.h + * \brief GNU Radio block that processes Galileo OSNMA data received from + * Galileo E1B telemetry blocks. After successful decoding, sends the content to + * the PVT block. + * \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_OSNMA_MSG_RECEIVER_H +#define GNSS_SDR_OSNMA_MSG_RECEIVER_H + +#include "galileo_inav_message.h" // for OSNMA_msg +#include "gnss_block_interface.h" // for gnss_shared_ptr +#include "osnma_data.h" +#include // for gr::block +#include // for pmt::pmt_t + + +/** \addtogroup Core + * \{ */ +/** \addtogroup Core_Receiver_Library + * \{ */ + +class osnma_msg_receiver; + +using osnma_msg_receiver_sptr = gnss_shared_ptr; + +osnma_msg_receiver_sptr osnma_msg_receiver_make(); + +/*! + * \brief GNU Radio block that receives asynchronous OSNMA messages + * from the telemetry blocks, stores them in memory, and decodes OSNMA info + * when enough data have been received. + * The decoded OSNMA data is sent to the PVT block. + */ +class osnma_msg_receiver : public gr::block +{ +public: + ~osnma_msg_receiver() = default; //!< Default destructor + +private: + friend osnma_msg_receiver_sptr osnma_msg_receiver_make(); + osnma_msg_receiver(); + + void msg_handler_osnma(const pmt::pmt_t& msg); + void process_osnma_message(const OSNMA_msg& osnma_msg); + void read_nma_header(uint8_t nma_header); + void read_dsm_header(uint8_t dsm_header); + OSNMA_data d_osnma_data{}; + bool d_new_data{false}; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_OSNMA_MSG_RECEIVER_H diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index d5505b4f9..4fde5eea3 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -76,6 +76,7 @@ GNSSFlowgraph::GNSSFlowgraph(std::shared_ptr configurati connected_(false), running_(false), multiband_(GNSSFlowgraph::is_multiband()), + enable_osnma_rx_(false), enable_e6_has_rx_(false) { enable_fpga_offloading_ = configuration_->property("GNSS-SDR.enable_FPGA", false); @@ -114,6 +115,16 @@ void GNSSFlowgraph::init() galileo_tow_map_ = nullptr; } + if (configuration_->property("Channels_1B.count", 0) > 0) + { + enable_osnma_rx_ = true; + osnma_rx_ = osnma_msg_receiver_make(); + } + else + { + osnma_rx_ = nullptr; + } + // 1. read the number of RF front-ends available (one file_source per RF front-end) int sources_count_deprecated = configuration_->property("Receiver.sources_count", 1); sources_count_ = configuration_->property("GNSS-SDR.num_sources", sources_count_deprecated); @@ -490,6 +501,14 @@ int GNSSFlowgraph::connect_desktop_flowgraph() } } + if (enable_osnma_rx_) + { + if (connect_osnma() != 0) + { + return 1; + } + } + // Activate acquisition in enabled channels for (int i = 0; i < channels_count_; i++) { @@ -609,6 +628,14 @@ int GNSSFlowgraph::connect_fpga_flowgraph() } } + if (enable_osnma_rx_) + { + if (connect_osnma() != 0) + { + return 1; + } + } + check_desktop_conf_in_fpga_env(); LOG(INFO) << "The GNU Radio flowgraph for the current GNSS-SDR configuration with FPGA off-loading has been successfully connected"; @@ -1334,6 +1361,42 @@ int GNSSFlowgraph::connect_monitors() } +int GNSSFlowgraph::connect_osnma() +{ + try + { + bool gal_e1_channels = false; + for (int i = 0; i < channels_count_; i++) + { + const std::string gnss_signal = channels_.at(i)->get_signal().get_signal_str(); + switch (mapStringValues_[gnss_signal]) + { + case evGAL_1B: + top_block_->msg_connect(channels_.at(i)->get_right_block(), pmt::mp("OSNMA_from_TLM"), osnma_rx_, pmt::mp("OSNMA_from_TLM")); + gal_e1_channels = true; + break; + + default: + break; + } + } + + if (gal_e1_channels == true) + { + top_block_->msg_connect(osnma_rx_, pmt::mp("OSNMA_to_PVT"), pvt_->get_left_block(), pmt::mp("OSNMA_to_PVT")); + } + } + catch (const std::exception& e) + { + LOG(ERROR) << "Can't connect Galileo OSNMA msg ports: " << e.what(); + top_block_->disconnect_all(); + return 1; + } + DLOG(INFO) << "Galileo OSNMA message ports connected"; + return 0; +} + + int GNSSFlowgraph::connect_gal_e6_has() { try diff --git a/src/core/receiver/gnss_flowgraph.h b/src/core/receiver/gnss_flowgraph.h index be7c5e8bf..2616c8025 100644 --- a/src/core/receiver/gnss_flowgraph.h +++ b/src/core/receiver/gnss_flowgraph.h @@ -30,6 +30,7 @@ #include "galileo_tow_map.h" #include "gnss_sdr_sample_counter.h" #include "gnss_signal.h" +#include "osnma_msg_receiver.h" #include "pvt_interface.h" #include // for null_sink #include // for basic_block_sptr, top_block_sptr @@ -179,6 +180,7 @@ private: int connect_channels_to_observables(); int connect_observables_to_pvt(); int connect_monitors(); + int connect_osnma(); int connect_gal_e6_has(); int connect_gnss_synchro_monitor(); int connect_acquisition_monitor(); @@ -234,6 +236,7 @@ private: channel_status_msg_receiver_sptr channels_status_; // class that receives and stores the current status of the receiver channels galileo_e6_has_msg_receiver_sptr gal_e6_has_rx_; galileo_tow_map_sptr galileo_tow_map_; + osnma_msg_receiver_sptr osnma_rx_; gnss_sdr_sample_counter_sptr ch_out_sample_counter_; #if ENABLE_FPGA @@ -290,6 +293,7 @@ private: bool enable_tracking_monitor_; bool enable_navdata_monitor_; bool enable_fpga_offloading_; + bool enable_osnma_rx_; bool enable_e6_has_rx_; }; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 3e25387ed..51b64b18e 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -27,6 +27,7 @@ set(SYSTEM_PARAMETERS_SOURCES glonass_gnav_ephemeris.cc glonass_gnav_utc_model.cc glonass_gnav_navigation_message.cc + osnma_data.cc reed_solomon.cc ) @@ -89,6 +90,7 @@ set(SYSTEM_PARAMETERS_HEADERS MATH_CONSTANTS.h reed_solomon.h galileo_has_page.h + osnma_data.h ) list(SORT SYSTEM_PARAMETERS_HEADERS) diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc new file mode 100644 index 000000000..dde58b44a --- /dev/null +++ b/src/core/system_parameters/osnma_data.cc @@ -0,0 +1,17 @@ +/*! + * \file osnma_data.cc + * \brief Class for Galileo OSNMA data storage + * \author Carles Fernandez-Prades, 2020-2023 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "osnma_data.h" diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h new file mode 100644 index 000000000..3fa6b6232 --- /dev/null +++ b/src/core/system_parameters/osnma_data.h @@ -0,0 +1,69 @@ +/*! + * \file osnma_data.h + * \brief Class for Galileo OSNMA data storage + * \author Carles Fernandez-Prades, 2020-2023 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_OSNMA_DATA_H +#define GNSS_SDR_OSNMA_DATA_H + +#include +#include +#include +#include + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + +struct nma_header +{ + uint8_t nmas; + uint8_t cid; + uint8_t cpks; + bool reserved; +}; + +struct dsm_header +{ + uint8_t dsm_id; + uint8_t dsm_block_id; +}; + + +/*! + * \brief This class handles ONSMA data + * See https://www.gsc-europa.eu/sites/default/files/sites/all/files/Galileo_OSNMA_User_ICD_for_Test_Phase_v1.0.pdf + */ +class OSNMA_data +{ +public: + OSNMA_data() = default; + + std::string itn; // bitset<1024> + std::string npk; + std::string p_dp; + nma_header d_nma_header; + dsm_header d_dsm_header; + uint8_t nb_dp; + uint8_t mid; + uint8_t npkt; + uint8_t npktid; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_OSNMA_DATA_H From 29f43b72c5d1499a5ecfdd200705f230d9790a4c Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 23 May 2023 12:45:36 +0200 Subject: [PATCH 003/219] Fix shift direction --- .../gnuradio_blocks/galileo_telemetry_decoder_gs.cc | 4 ++-- src/core/libs/osnma_msg_receiver.cc | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index e041d2c99..fedef7456 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -512,7 +512,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - uint8_t nma_status = (tmp_obj->hkroot[0] & 0b11000000) << 6; + uint8_t nma_status = (tmp_obj->hkroot[0] & 0b11000000) >> 6; std::string nma_status_string; if (nma_status == 0) { @@ -526,7 +526,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in { nma_status_string = std::string("(Operational mode)"); } - else if (nma_status == 3) + else { nma_status_string = std::string("(Do not use mode)"); } diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 79ebcc48d..e26dc51f8 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -110,15 +110,15 @@ void osnma_msg_receiver::process_osnma_message(const OSNMA_msg& osnma_msg) void osnma_msg_receiver::read_nma_header(uint8_t nma_header) { - d_osnma_data.d_nma_header.nmas = (nma_header & 0b11000000) << 6; - d_osnma_data.d_nma_header.cid = (nma_header & 0b00110000) << 4; - d_osnma_data.d_nma_header.cpks = (nma_header & 0b00001110) << 1; + d_osnma_data.d_nma_header.nmas = (nma_header & 0b11000000) >> 6; + d_osnma_data.d_nma_header.cid = (nma_header & 0b00110000) >> 4; + d_osnma_data.d_nma_header.cpks = (nma_header & 0b00001110) >> 1; d_osnma_data.d_nma_header.reserved = ((nma_header & 0b00000001) ? true : false); } void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { - d_osnma_data.d_dsm_header.dsm_id = (dsm_header & 0b11110000) << 4; + d_osnma_data.d_dsm_header.dsm_id = (dsm_header & 0b11110000) >> 4; d_osnma_data.d_dsm_header.dsm_block_id = dsm_header & 0b00001111; } \ No newline at end of file From 9f2264a9709f3845d47f6ba6c758fc0289ed9e01 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 23 May 2023 12:58:51 +0200 Subject: [PATCH 004/219] Do not repeat NMA messages --- src/core/system_parameters/galileo_inav_message.cc | 3 ++- src/core/system_parameters/galileo_inav_message.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index d852d9405..581f55a7f 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1405,8 +1405,9 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) } -OSNMA_msg Galileo_Inav_Message::get_osnma_msg() const +OSNMA_msg Galileo_Inav_Message::get_osnma_msg() { + nma_position_filled = std::array{}; return nma_msg; } diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 1d986a1b4..043b05a14 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -124,7 +124,7 @@ public: /* * \brief Returns an OSNMA_msg object filled with the latest NMA message received. Resets msg buffer. */ - OSNMA_msg get_osnma_msg() const; + OSNMA_msg get_osnma_msg(); inline bool get_flag_CRC_test() const { From 6408d7428838f50ee12c01445e51b78eb24f0658 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 23 May 2023 14:11:20 +0200 Subject: [PATCH 005/219] Fix internal communications --- src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 6 +++++- src/core/libs/osnma_msg_receiver.cc | 13 +++++++------ src/core/libs/osnma_msg_receiver.h | 10 ++++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 6f882448c..0e64c4c64 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -52,6 +52,7 @@ #include "monitor_pvt.h" #include "monitor_pvt_udp_sink.h" #include "nmea_printer.h" +#include "osnma_data.h" #include "pvt_conf.h" #include "rinex_printer.h" #include "rtcm_printer.h" @@ -1651,7 +1652,10 @@ void rtklib_pvt_gs::msg_handler_osnma(const pmt::pmt_t& msg) try { const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); - // Process NMA data + if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) + { + // Act according to NMA data + } } catch (const wht::bad_any_cast& e) { diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e26dc51f8..756b89b5b 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -70,13 +70,14 @@ osnma_msg_receiver::osnma_msg_receiver() : gr::block("osnma_msg_receiver", void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) { - gr::thread::scoped_lock lock(d_setlock); // require mutex with msg_handler_osnma function called by the scheduler + // requires mutex with msg_handler_osnma function called by the scheduler + gr::thread::scoped_lock lock(d_setlock); try { const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); - if (msg_type_hash_code == typeid(OSNMA_msg).hash_code()) + if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) { - const auto nma_msg = wht::any_cast(pmt::any_ref(msg)); + const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); process_osnma_message(nma_msg); } else @@ -100,9 +101,9 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) } -void osnma_msg_receiver::process_osnma_message(const OSNMA_msg& osnma_msg) +void osnma_msg_receiver::process_osnma_message(std::shared_ptr osnma_msg) { - auto hkroot_msg = osnma_msg.hkroot; + const auto hkroot_msg = osnma_msg->hkroot; read_nma_header(hkroot_msg[0]); read_dsm_header(hkroot_msg[1]); } @@ -120,5 +121,5 @@ void osnma_msg_receiver::read_nma_header(uint8_t nma_header) void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { d_osnma_data.d_dsm_header.dsm_id = (dsm_header & 0b11110000) >> 4; - d_osnma_data.d_dsm_header.dsm_block_id = dsm_header & 0b00001111; + d_osnma_data.d_dsm_header.dsm_block_id = dsm_header & 0b00001111; // BID } \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index f9629d133..b9b51293b 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -21,9 +21,10 @@ #include "galileo_inav_message.h" // for OSNMA_msg #include "gnss_block_interface.h" // for gnss_shared_ptr -#include "osnma_data.h" -#include // for gr::block -#include // for pmt::pmt_t +#include "osnma_data.h" // for OSNMA_data +#include // for gr::block +#include // for pmt::pmt_t +#include // for std::shared_ptr /** \addtogroup Core @@ -53,9 +54,10 @@ private: osnma_msg_receiver(); void msg_handler_osnma(const pmt::pmt_t& msg); - void process_osnma_message(const OSNMA_msg& osnma_msg); + void process_osnma_message(std::shared_ptr osnma_msg); void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); + OSNMA_data d_osnma_data{}; bool d_new_data{false}; }; From 0ba7b1611e449a0a7d507d6b0fd855849f037427 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 25 May 2023 07:48:27 +0200 Subject: [PATCH 006/219] Add work on retrieving OSNMA data --- src/core/libs/osnma_msg_receiver.cc | 244 +++++++++++++++++++++++- src/core/libs/osnma_msg_receiver.h | 10 +- src/core/system_parameters/osnma_data.h | 40 +++- 3 files changed, 281 insertions(+), 13 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 756b89b5b..759c2db0b 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -18,14 +18,18 @@ #include "osnma_msg_receiver.h" -#include "display.h" // for colors in terminal #include "gnss_sdr_make_unique.h" // for std::make_unique in C++11 #include // for DLOG #include // for gr::io_signature::make #include +#include #include #include +#include +#include #include // for typeid +#include +#include #if HAS_GENERIC_LAMBDA #else @@ -40,6 +44,96 @@ namespace wht = boost; namespace wht = std; #endif + +// OSNMA SIS ICD v1.0 Table 3 +const std::unordered_map> OSNMA_TABLE_3 = { + {0, {0, 0}}, + {1, {0, 0}}, + {2, {0, 0}}, + {3, {0, 0}}, + {4, {0, 0}}, + {5, {0, 0}}, + {6, {0, 0}}, + {7, {13, 1352}}, + {8, {14, 1456}}, + {9, {15, 1560}}, + {10, {16, 1664}}, + {11, {0, 0}}, + {12, {0, 0}}, + {13, {0, 0}}, + {14, {0, 0}}, + {15, {0, 0}}}; // key: nb_dp, value: {num_blocks, l_dp_bits} + +const std::unordered_map OSNMA_TABLE_5 = { + {0, std::string("Reserved")}, + {1, std::string("ECDSA P-256")}, + {2, std::string("Reserved")}, + {3, std::string("ECDSA P-521")}, + {4, std::string("OAM")}, + {5, std::string("Reserved")}, + {6, std::string("Reserved")}, + {7, std::string("Reserved")}, + {8, std::string("Reserved")}, + {9, std::string("Reserved")}, + {10, std::string("Reserved")}, + {11, std::string("Reserved")}, + {12, std::string("Reserved")}, + {13, std::string("Reserved")}, + {14, std::string("Reserved")}, + {15, std::string("Reserved")}}; // key: nptk, value: message + +const std::unordered_map OSNMA_TABLE_6 = { + {std::string("ECDSA P-256"), 264}, + {std::string("ECDSA P-521"), 536}}; + +// OSNMA SIS ICD v1.0 Table 7 +const std::unordered_map> OSNMA_TABLE_7 = { + {0, {0, 0}}, + {1, {7, 728}}, + {2, {8, 832}}, + {3, {9, 936}}, + {4, {10, 1040}}, + {5, {11, 1144}}, + {6, {12, 1248}}, + {7, {13, 1352}}, + {8, {14, 1456}}, + {9, {0, 0}}, + {10, {0, 0}}, + {11, {0, 0}}, + {12, {0, 0}}, + {13, {0, 0}}, + {14, {0, 0}}, + {15, {0, 0}}}; // key: nb_dk, value: {num_blocks, l_dk_bits} + +const std::unordered_map OSNMA_TABLE_8 = { + {0, std::string("SHA-256")}, + {1, std::string("Reserved")}, + {2, std::string("SHA3-256")}, + {3, std::string("Reserved")}}; // key: hs, value: hash_function + +const std::unordered_map OSNMA_TABLE_10 = { + {0, 96}, + {1, 104}, + {2, 112}, + {3, 120}, + {4, 128}, + {5, 160}, + {6, 192}, + {7, 224}, + {8, 256}, + {9, 0}, + {10, 0}, + {11, 0}, + {12, 0}, + {13, 0}, + {15, 0}, + {15, 0}}; // key: ks, value: lk_bits + +const std::unordered_map> OSNMA_TABLE_15 = { + {std::string("ECDSA P-256"), {512, 256}}, + {std::string("ECDSA P-521"), {1059, 521}}}; // key: ECDSA Curve and hash function, value: {l_ds_bits, key_lenght_bits} + + osnma_msg_receiver_sptr osnma_msg_receiver_make() { return osnma_msg_receiver_sptr(new osnma_msg_receiver()); @@ -101,11 +195,12 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) } -void osnma_msg_receiver::process_osnma_message(std::shared_ptr osnma_msg) +void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& osnma_msg) { const auto hkroot_msg = osnma_msg->hkroot; read_nma_header(hkroot_msg[0]); read_dsm_header(hkroot_msg[1]); + read_dsm_block(osnma_msg); } @@ -122,4 +217,147 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { d_osnma_data.d_dsm_header.dsm_id = (dsm_header & 0b11110000) >> 4; d_osnma_data.d_dsm_header.dsm_block_id = dsm_header & 0b00001111; // BID -} \ No newline at end of file +} + + +void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_msg) +{ + size_t i = 0; + for (auto it = osnma_msg->hkroot.cbegin() + 2; it != osnma_msg->hkroot.cend(); ++it) + { + d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][13 * d_osnma_data.d_dsm_header.dsm_block_id + i] = *it; + i++; + } + if (d_osnma_data.d_dsm_header.dsm_block_id == 0) + { + // Get number of blocks in message + uint8_t nb = (osnma_msg->hkroot[2] & 0b11110000) >> 4; + uint16_t number_of_blocks = 0; + if (d_osnma_data.d_dsm_header.dsm_id >= 0 && d_osnma_data.d_dsm_header.dsm_id < 12) + { + // Table 3 + const auto it = OSNMA_TABLE_3.find(nb); + if (it != OSNMA_TABLE_3.cend()) + { + number_of_blocks = it->second.first; + } + } + else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) + { + // Table 7 + const auto it = OSNMA_TABLE_7.find(nb); + if (it != OSNMA_TABLE_7.cend()) + { + number_of_blocks = it->second.first; + } + } + + d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = number_of_blocks; + } + // Annotate bid + d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; + // is message complete? -> process_dsm_message(osnma_msg) + if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].begin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].end(), 0))) + { + std::vector dsm_msg(std::size_t(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) * 13, 0); + for (uint32_t i = 0; i < d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]; i++) + { + for (uint32_t j = 0; j < 14; j++) + { + dsm_msg[i * 13 + j] = d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][i * 13 + j]; + } + } + process_dsm_message(osnma_msg, dsm_msg); + } +} + + +void osnma_msg_receiver::process_dsm_message(const std::shared_ptr& osnma_msg, const std::vector& dsm_msg) +{ + if (d_osnma_data.d_dsm_header.dsm_id >= 0 && d_osnma_data.d_dsm_header.dsm_id < 12) + { + // DSM-KROOT message + d_osnma_data.d_dsm_kroot_message.nb_dk = (dsm_msg[0] & 0b11110000) >> 4; + d_osnma_data.d_dsm_kroot_message.pkid = (dsm_msg[0] & 0b00001111); + d_osnma_data.d_dsm_kroot_message.cidkr = (dsm_msg[1] & 0b11000000) >> 6; + d_osnma_data.d_dsm_kroot_message.reserved1 = (dsm_msg[1] & 0b00110000) >> 4; + d_osnma_data.d_dsm_kroot_message.hf = (dsm_msg[1] & 0b00001100) >> 2; + + d_osnma_data.d_dsm_kroot_message.mf = (dsm_msg[1] & 0b00000011); + d_osnma_data.d_dsm_kroot_message.ks = (dsm_msg[2] & 0b11110000) >> 4; + d_osnma_data.d_dsm_kroot_message.ts = (dsm_msg[2] & 0b00001111); + d_osnma_data.d_dsm_kroot_message.maclt = dsm_msg[3]; + d_osnma_data.d_dsm_kroot_message.reserved = (dsm_msg[4] & 0b11110000) >> 4; + d_osnma_data.d_dsm_kroot_message.wn_k = static_cast((dsm_msg[4] & 0b00001111) << 8) + + static_cast(dsm_msg[5]); + d_osnma_data.d_dsm_kroot_message.towh_k = dsm_msg[6]; + + uint32_t lk = 0; + const auto it = OSNMA_TABLE_10.find(d_osnma_data.d_dsm_kroot_message.ks); + if (it != OSNMA_TABLE_10.cend()) + { + lk = it->second; + } + + d_osnma_data.d_dsm_kroot_message.alpha = (static_cast(dsm_msg[7]) << 40) + + (static_cast(dsm_msg[8]) << 32) + + (static_cast(dsm_msg[9]) << 24) + + (static_cast(dsm_msg[10]) << 16) + + (static_cast(dsm_msg[11]) << 8) + + static_cast(dsm_msg[12]); + uint32_t bytes_lk = lk / 8; + d_osnma_data.d_dsm_kroot_message.kroot = std::vector(bytes_lk, 0); + for (uint32_t k = 0; k < bytes_lk; k++) + { + d_osnma_data.d_dsm_kroot_message.kroot[k] = dsm_msg[13 + k]; + } + // uint32_t l_ld = 0; + // const auto it2 = OSNMA_TABLE_5.find() + // d_osnma_data.d_dsm_kroot_message.ds = "0"; + // d_osnma_data.d_dsm_kroot_message.p_dk; + } + else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) + { + // DSM-PKR message + d_osnma_data.d_dsm_pkr_message.nb_dp = (dsm_msg[0] & 0b11110000) >> 4; + d_osnma_data.d_dsm_pkr_message.mid = (dsm_msg[0] & 0b00001111); + for (int k = 0; k > 128; k++) + { + d_osnma_data.d_dsm_pkr_message.itn[k] = dsm_msg[k + 1]; + } + + d_osnma_data.d_dsm_pkr_message.npkt = (dsm_msg[129] & 0b11110000) >> 4; + d_osnma_data.d_dsm_pkr_message.npktid = (dsm_msg[129] & 0b00001111); + + // Table 5 + uint32_t l_npk = 0; + const auto it = OSNMA_TABLE_5.find(d_osnma_data.d_dsm_pkr_message.npkt); + if (it != OSNMA_TABLE_5.cend()) + { + const auto it2 = OSNMA_TABLE_6.find(it->second); + if (it2 != OSNMA_TABLE_6.cend()) + { + l_npk = it2->second / 8; + } + } + + if (d_osnma_data.d_dsm_pkr_message.npkt == 4) + { + // OAM + l_npk = 0; // ? + } + + d_osnma_data.d_dsm_pkr_message.npk = std::vector(l_npk, 0); + for (uint32_t k = 0; k > l_npk; k++) + { + d_osnma_data.d_dsm_pkr_message.npk[k] = dsm_msg[k + 130]; + } + uint32_t l_dp = dsm_msg.size(); + uint32_t l_pd = l_dp - 130 - l_npk; + d_osnma_data.d_dsm_pkr_message.p_dp = std::vector(l_pd, 0); + for (uint32_t k = 0; k > l_pd; k++) + { + d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; + } + } +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index b9b51293b..ba51a874b 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -24,8 +24,9 @@ #include "osnma_data.h" // for OSNMA_data #include // for gr::block #include // for pmt::pmt_t +#include // for std::array #include // for std::shared_ptr - +#include /** \addtogroup Core * \{ */ @@ -54,10 +55,15 @@ private: osnma_msg_receiver(); void msg_handler_osnma(const pmt::pmt_t& msg); - void process_osnma_message(std::shared_ptr osnma_msg); + void process_osnma_message(const std::shared_ptr& osnma_msg); void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); + void read_dsm_block(const std::shared_ptr& osnma_msg); + void process_dsm_message(const std::shared_ptr& osnma_msg, const std::vector& dsm_msg); + std::array, 16> d_dsm_message{}; + std::array, 16> d_dsm_id_received{}; + std::array d_number_of_blocks{}; OSNMA_data d_osnma_data{}; bool d_new_data{false}; }; diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 3fa6b6232..966e425ac 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -42,6 +42,36 @@ struct dsm_header uint8_t dsm_block_id; }; +struct DSM_PKR_message +{ + uint8_t nb_dp; + uint8_t mid; + std::array itn; // bitset<1024> + uint8_t npkt; + uint8_t npktid; + std::vector npk; + std::vector p_dp; +}; + +struct DSM_KROOT_message +{ + uint8_t nb_dk; + uint8_t pkid; + uint8_t cidkr; + uint8_t reserved1; + uint8_t hf; + uint8_t mf; + uint8_t ks; + uint8_t ts; + uint8_t maclt; + uint8_t reserved; + uint16_t wn_k; + uint8_t towh_k; + uint64_t alpha; + std::vector kroot; + std::vector ds; + std::vector p_dk; +}; /*! * \brief This class handles ONSMA data @@ -51,16 +81,10 @@ class OSNMA_data { public: OSNMA_data() = default; - - std::string itn; // bitset<1024> - std::string npk; - std::string p_dp; nma_header d_nma_header; dsm_header d_dsm_header; - uint8_t nb_dp; - uint8_t mid; - uint8_t npkt; - uint8_t npktid; + DSM_PKR_message d_dsm_pkr_message; + DSM_KROOT_message d_dsm_kroot_message; }; From f7c14e3041cc4757d54e7380b3f5d17396e01255 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 25 May 2023 07:53:11 +0200 Subject: [PATCH 007/219] Remove comparisons that are always true --- src/core/libs/osnma_msg_receiver.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 759c2db0b..0baedb6a1 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -233,7 +233,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ // Get number of blocks in message uint8_t nb = (osnma_msg->hkroot[2] & 0b11110000) >> 4; uint16_t number_of_blocks = 0; - if (d_osnma_data.d_dsm_header.dsm_id >= 0 && d_osnma_data.d_dsm_header.dsm_id < 12) + if (d_osnma_data.d_dsm_header.dsm_id < 12) { // Table 3 const auto it = OSNMA_TABLE_3.find(nb); @@ -274,7 +274,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ void osnma_msg_receiver::process_dsm_message(const std::shared_ptr& osnma_msg, const std::vector& dsm_msg) { - if (d_osnma_data.d_dsm_header.dsm_id >= 0 && d_osnma_data.d_dsm_header.dsm_id < 12) + if (d_osnma_data.d_dsm_header.dsm_id < 12) { // DSM-KROOT message d_osnma_data.d_dsm_kroot_message.nb_dk = (dsm_msg[0] & 0b11110000) >> 4; From 78847e33a32f853e5e8b5c69bf100b36702a6631 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 27 May 2023 10:22:13 +0200 Subject: [PATCH 008/219] Add work on osnma receiver --- src/core/libs/osnma_msg_receiver.cc | 149 ++++----------- src/core/libs/osnma_msg_receiver.h | 2 +- src/core/system_parameters/CMakeLists.txt | 1 + src/core/system_parameters/Galileo_OSNMA.h | 180 ++++++++++++++++++ .../system_parameters/galileo_inav_message.cc | 4 +- 5 files changed, 226 insertions(+), 110 deletions(-) create mode 100644 src/core/system_parameters/Galileo_OSNMA.h diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 0baedb6a1..c551ae1b0 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -18,6 +18,7 @@ #include "osnma_msg_receiver.h" +#include "Galileo_OSNMA.h" #include "gnss_sdr_make_unique.h" // for std::make_unique in C++11 #include // for DLOG #include // for gr::io_signature::make @@ -28,8 +29,7 @@ #include #include #include // for typeid -#include -#include + #if HAS_GENERIC_LAMBDA #else @@ -44,96 +44,6 @@ namespace wht = boost; namespace wht = std; #endif - -// OSNMA SIS ICD v1.0 Table 3 -const std::unordered_map> OSNMA_TABLE_3 = { - {0, {0, 0}}, - {1, {0, 0}}, - {2, {0, 0}}, - {3, {0, 0}}, - {4, {0, 0}}, - {5, {0, 0}}, - {6, {0, 0}}, - {7, {13, 1352}}, - {8, {14, 1456}}, - {9, {15, 1560}}, - {10, {16, 1664}}, - {11, {0, 0}}, - {12, {0, 0}}, - {13, {0, 0}}, - {14, {0, 0}}, - {15, {0, 0}}}; // key: nb_dp, value: {num_blocks, l_dp_bits} - -const std::unordered_map OSNMA_TABLE_5 = { - {0, std::string("Reserved")}, - {1, std::string("ECDSA P-256")}, - {2, std::string("Reserved")}, - {3, std::string("ECDSA P-521")}, - {4, std::string("OAM")}, - {5, std::string("Reserved")}, - {6, std::string("Reserved")}, - {7, std::string("Reserved")}, - {8, std::string("Reserved")}, - {9, std::string("Reserved")}, - {10, std::string("Reserved")}, - {11, std::string("Reserved")}, - {12, std::string("Reserved")}, - {13, std::string("Reserved")}, - {14, std::string("Reserved")}, - {15, std::string("Reserved")}}; // key: nptk, value: message - -const std::unordered_map OSNMA_TABLE_6 = { - {std::string("ECDSA P-256"), 264}, - {std::string("ECDSA P-521"), 536}}; - -// OSNMA SIS ICD v1.0 Table 7 -const std::unordered_map> OSNMA_TABLE_7 = { - {0, {0, 0}}, - {1, {7, 728}}, - {2, {8, 832}}, - {3, {9, 936}}, - {4, {10, 1040}}, - {5, {11, 1144}}, - {6, {12, 1248}}, - {7, {13, 1352}}, - {8, {14, 1456}}, - {9, {0, 0}}, - {10, {0, 0}}, - {11, {0, 0}}, - {12, {0, 0}}, - {13, {0, 0}}, - {14, {0, 0}}, - {15, {0, 0}}}; // key: nb_dk, value: {num_blocks, l_dk_bits} - -const std::unordered_map OSNMA_TABLE_8 = { - {0, std::string("SHA-256")}, - {1, std::string("Reserved")}, - {2, std::string("SHA3-256")}, - {3, std::string("Reserved")}}; // key: hs, value: hash_function - -const std::unordered_map OSNMA_TABLE_10 = { - {0, 96}, - {1, 104}, - {2, 112}, - {3, 120}, - {4, 128}, - {5, 160}, - {6, 192}, - {7, 224}, - {8, 256}, - {9, 0}, - {10, 0}, - {11, 0}, - {12, 0}, - {13, 0}, - {15, 0}, - {15, 0}}; // key: ks, value: lk_bits - -const std::unordered_map> OSNMA_TABLE_15 = { - {std::string("ECDSA P-256"), {512, 256}}, - {std::string("ECDSA P-521"), {1059, 521}}}; // key: ECDSA Curve and hash function, value: {l_ds_bits, key_lenght_bits} - - osnma_msg_receiver_sptr osnma_msg_receiver_make() { return osnma_msg_receiver_sptr(new osnma_msg_receiver()); @@ -190,6 +100,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) auto osnma_data_ptr = std::make_shared(d_osnma_data); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); d_new_data = false; + d_osnma_data = OSNMA_data(); DLOG(INFO) << "NMA info sent to the PVT block through the OSNMA_to_PVT async message port"; } } @@ -197,36 +108,42 @@ 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) { - const auto hkroot_msg = osnma_msg->hkroot; - read_nma_header(hkroot_msg[0]); - read_dsm_header(hkroot_msg[1]); + read_nma_header(osnma_msg->hkroot[0]); + read_dsm_header(osnma_msg->hkroot[1]); read_dsm_block(osnma_msg); } void osnma_msg_receiver::read_nma_header(uint8_t nma_header) { - d_osnma_data.d_nma_header.nmas = (nma_header & 0b11000000) >> 6; - d_osnma_data.d_nma_header.cid = (nma_header & 0b00110000) >> 4; - d_osnma_data.d_nma_header.cpks = (nma_header & 0b00001110) >> 1; - d_osnma_data.d_nma_header.reserved = ((nma_header & 0b00000001) ? true : false); + d_osnma_data.d_nma_header.nmas = get_nmas(nma_header); + d_osnma_data.d_nma_header.cid = get_cid(nma_header); + d_osnma_data.d_nma_header.cpks = get_cpks(nma_header); + d_osnma_data.d_nma_header.reserved = get_nma_header_reserved(nma_header); + + // debug + const auto it = OSNMA_TABLE_2.find(d_osnma_data.d_nma_header.cpks); + if (it != OSNMA_TABLE_2.cend()) + { + LOG(WARNING) << "Chain and Public Key Status: " << it->second; + } } void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { - d_osnma_data.d_dsm_header.dsm_id = (dsm_header & 0b11110000) >> 4; - d_osnma_data.d_dsm_header.dsm_block_id = dsm_header & 0b00001111; // BID + d_osnma_data.d_dsm_header.dsm_id = get_dsm_id(dsm_header); + d_osnma_data.d_dsm_header.dsm_block_id = get_dsm_block_id(dsm_header); // BID } void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_msg) { - size_t i = 0; - for (auto it = osnma_msg->hkroot.cbegin() + 2; it != osnma_msg->hkroot.cend(); ++it) + size_t index = 0; + for (const auto* it = osnma_msg->hkroot.cbegin() + 2; it != osnma_msg->hkroot.cend(); ++it) { - d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][13 * d_osnma_data.d_dsm_header.dsm_block_id + i] = *it; - i++; + d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][13 * d_osnma_data.d_dsm_header.dsm_block_id + index] = *it; + index++; } if (d_osnma_data.d_dsm_header.dsm_block_id == 0) { @@ -256,8 +173,17 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } // Annotate bid d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; + + std::cout << "d_dsm_id_received"; + for (auto v : d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id]) + { + std::cout << " " << static_cast(v); + } + std::cout << std::endl; + LOG(WARNING) << "d_number_of blocks: " << static_cast(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) << " BID: " << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) << " DSM ID: " << static_cast(d_osnma_data.d_dsm_header.dsm_id); // is message complete? -> process_dsm_message(osnma_msg) - if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].begin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].end(), 0))) + if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && + (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].begin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].end(), 0))) { std::vector dsm_msg(std::size_t(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) * 13, 0); for (uint32_t i = 0; i < d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]; i++) @@ -267,15 +193,16 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ dsm_msg[i * 13 + j] = d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][i * 13 + j]; } } - process_dsm_message(osnma_msg, dsm_msg); + process_dsm_message(dsm_msg); } } -void osnma_msg_receiver::process_dsm_message(const std::shared_ptr& osnma_msg, const std::vector& dsm_msg) +void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg) { if (d_osnma_data.d_dsm_header.dsm_id < 12) { + LOG(WARNING) << "OSNMA: DSM-KROOT message received."; // DSM-KROOT message d_osnma_data.d_dsm_kroot_message.nb_dk = (dsm_msg[0] & 0b11110000) >> 4; d_osnma_data.d_dsm_kroot_message.pkid = (dsm_msg[0] & 0b00001111); @@ -318,6 +245,7 @@ void osnma_msg_receiver::process_dsm_message(const std::shared_ptr& o } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) { + LOG(WARNING) << "OSNMA: DSM-PKR message received."; // DSM-PKR message d_osnma_data.d_dsm_pkr_message.nb_dp = (dsm_msg[0] & 0b11110000) >> 4; d_osnma_data.d_dsm_pkr_message.mid = (dsm_msg[0] & 0b00001111); @@ -360,4 +288,9 @@ void osnma_msg_receiver::process_dsm_message(const std::shared_ptr& o d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; } } + else + { + // Reserved message? + d_osnma_data = OSNMA_data(); + } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index ba51a874b..59c65bfe2 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -59,7 +59,7 @@ private: void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); - void process_dsm_message(const std::shared_ptr& osnma_msg, const std::vector& dsm_msg); + void process_dsm_message(const std::vector& dsm_msg); std::array, 16> d_dsm_message{}; std::array, 16> d_dsm_id_received{}; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 51b64b18e..81fd4318a 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -90,6 +90,7 @@ set(SYSTEM_PARAMETERS_HEADERS MATH_CONSTANTS.h reed_solomon.h galileo_has_page.h + Galileo_OSNMA.h osnma_data.h ) diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h new file mode 100644 index 000000000..7c233a294 --- /dev/null +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -0,0 +1,180 @@ +/*! + * \file Galileo_OSNMA.h + * \brief Galileo OSNMA mesage constants + * \author Carles Fernandez, 2023. cfernandez(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GALILEO_OSNMA_H +#define GNSS_SDR_GALILEO_OSNMA_H + +#include +#include +#include +#include + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + +// OSNMA User ICD for the Test Phase, Issue 1.0, Table 2 +const std::unordered_map OSNMA_TABLE_2 = { + {0, std::string("Reserved")}, + {1, std::string("Nominal")}, + {2, std::string("End of Chain (EOC)")}, + {3, std::string("Chain Revoked (CREV)")}, + {4, std::string("New Public Key (NPK)")}, + {5, std::string("Public Key Revoked (PKREV)")}, + {6, std::string("Reserved")}, + {7, std::string("Reserved")}}; // key: cpks, value: Chain and Public Key Status + +// OSNMA User ICD for the Test Phase, Issue 1.0, Table 3 +const std::unordered_map> OSNMA_TABLE_3 = { + {0, {0, 0}}, + {1, {0, 0}}, + {2, {0, 0}}, + {3, {0, 0}}, + {4, {0, 0}}, + {5, {0, 0}}, + {6, {0, 0}}, + {7, {13, 1352}}, + {8, {14, 1456}}, + {9, {15, 1560}}, + {10, {16, 1664}}, + {11, {0, 0}}, + {12, {0, 0}}, + {13, {0, 0}}, + {14, {0, 0}}, + {15, {0, 0}}}; // key: nb_dp, value: {num_blocks, l_dp_bits} + +const std::unordered_map OSNMA_TABLE_5 = { + {0, std::string("Reserved")}, + {1, std::string("ECDSA P-256")}, + {2, std::string("Reserved")}, + {3, std::string("ECDSA P-521")}, + {4, std::string("OAM")}, + {5, std::string("Reserved")}, + {6, std::string("Reserved")}, + {7, std::string("Reserved")}, + {8, std::string("Reserved")}, + {9, std::string("Reserved")}, + {10, std::string("Reserved")}, + {11, std::string("Reserved")}, + {12, std::string("Reserved")}, + {13, std::string("Reserved")}, + {14, std::string("Reserved")}, + {15, std::string("Reserved")}}; // key: nptk, value: message + +const std::unordered_map OSNMA_TABLE_6 = { + {std::string("ECDSA P-256"), 264}, + {std::string("ECDSA P-521"), 536}}; + +// OSNMA User ICD for the Test Phase, Issue 1.0, Table 7 +const std::unordered_map> OSNMA_TABLE_7 = { + {0, {0, 0}}, + {1, {7, 728}}, + {2, {8, 832}}, + {3, {9, 936}}, + {4, {10, 1040}}, + {5, {11, 1144}}, + {6, {12, 1248}}, + {7, {13, 1352}}, + {8, {14, 1456}}, + {9, {0, 0}}, + {10, {0, 0}}, + {11, {0, 0}}, + {12, {0, 0}}, + {13, {0, 0}}, + {14, {0, 0}}, + {15, {0, 0}}}; // key: nb_dk, value: {num_blocks, l_dk_bits} + +const std::unordered_map OSNMA_TABLE_8 = { + {0, std::string("SHA-256")}, + {1, std::string("Reserved")}, + {2, std::string("SHA3-256")}, + {3, std::string("Reserved")}}; // key: hs, value: hash_function + +const std::unordered_map OSNMA_TABLE_10 = { + {0, 96}, + {1, 104}, + {2, 112}, + {3, 120}, + {4, 128}, + {5, 160}, + {6, 192}, + {7, 224}, + {8, 256}, + {9, 0}, + {10, 0}, + {11, 0}, + {12, 0}, + {13, 0}, + {15, 0}, + {15, 0}}; // key: ks, value: lk_bits + +const std::unordered_map> OSNMA_TABLE_15 = { + {std::string("ECDSA P-256"), {512, 256}}, + {std::string("ECDSA P-521"), {1059, 521}}}; // key: ECDSA Curve and hash function, value: {l_ds_bits, key_lenght_bits} + +#if __cplusplus == 201103L +constexpr std::uint8_t mask_nmas{0xC0}; +constexpr std::uint8_t mask_cid{0x30}; +constexpr std::uint8_t mask_cpks{0x07}; +constexpr std::uint8_t mask_nma_header_reserved{0x01}; +constexpr std::uint8_t mask_dsm_id{0x01}; +constexpr std::uint8_t mask_dsm_block_id{0x0F}; +#else +constexpr std::uint8_t mask_nmas{0b1100'0000}; +constexpr std::uint8_t mask_cid{0b0011'0000}; +constexpr std::uint8_t mask_cpks{0b0000'1110}; +constexpr std::uint8_t mask_nma_header_reserved{0b0000'0001}; +constexpr std::uint8_t mask_dsm_id{0b0000'0001}; +constexpr std::uint8_t mask_dsm_block_id{0b0000'1111}; + +#endif + +inline uint8_t get_nmas(uint8_t nma_header) +{ + return (nma_header & mask_nmas) >> 6; +} + +inline uint8_t get_cid(uint8_t nma_header) +{ + return (nma_header & mask_cid) >> 4; +} + +inline uint8_t get_cpks(uint8_t nma_header) +{ + return (nma_header & mask_cpks) >> 1; +} + +inline bool get_nma_header_reserved(uint8_t nma_header) +{ + return ((nma_header & mask_nma_header_reserved) ? true : false); +} + +inline uint8_t get_dsm_id(uint8_t dsm_header) +{ + return (dsm_header & mask_dsm_id) >> 4; +} + +inline uint8_t get_dsm_block_id(uint8_t dsm_header) +{ + return dsm_header & mask_dsm_block_id; +} + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_GALILEO_OSNMA_H \ No newline at end of file diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index 581f55a7f..dd9f9df6a 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1392,7 +1392,9 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) break; } - if (page_position_in_inav_subframe > 14 && page_position_in_inav_subframe != 255) + if (page_position_in_inav_subframe != 0 && + page_position_in_inav_subframe > 14 && + page_position_in_inav_subframe != 255) { // something weird happened, reset page_position_in_inav_subframe = 255; From ee13784dd2780c7275ce6cbd10c76cd83f4ce43f Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 27 May 2023 10:27:44 +0200 Subject: [PATCH 009/219] Avoid string literals (not available in C++11) --- .../gnuradio_blocks/galileo_telemetry_decoder_gs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index fedef7456..60b83efc8 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -512,7 +512,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - uint8_t nma_status = (tmp_obj->hkroot[0] & 0b11000000) >> 6; + uint8_t nma_status = (tmp_obj->hkroot[0] & 0xC0) >> 6; std::string nma_status_string; if (nma_status == 0) { From 46aca38adec96cb96dd15bcd4f08596233bddd9f Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 27 May 2023 11:43:41 +0200 Subject: [PATCH 010/219] Add work on osnma receiver --- src/core/libs/osnma_msg_receiver.cc | 5 ++++- src/core/system_parameters/Galileo_OSNMA.h | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index c551ae1b0..ec875d696 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -148,7 +148,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ if (d_osnma_data.d_dsm_header.dsm_block_id == 0) { // Get number of blocks in message - uint8_t nb = (osnma_msg->hkroot[2] & 0b11110000) >> 4; + uint8_t nb = get_number_blocks(d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][0]); uint16_t number_of_blocks = 0; if (d_osnma_data.d_dsm_header.dsm_id < 12) { @@ -194,6 +194,9 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } } process_dsm_message(dsm_msg); + d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; + d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; + d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } } diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 7c233a294..89cc06d92 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -134,6 +134,7 @@ constexpr std::uint8_t mask_cpks{0x07}; constexpr std::uint8_t mask_nma_header_reserved{0x01}; constexpr std::uint8_t mask_dsm_id{0x01}; constexpr std::uint8_t mask_dsm_block_id{0x0F}; +constexpr std::uint8_t mask_dsm_number_blocks{0XF0}; #else constexpr std::uint8_t mask_nmas{0b1100'0000}; constexpr std::uint8_t mask_cid{0b0011'0000}; @@ -141,6 +142,7 @@ constexpr std::uint8_t mask_cpks{0b0000'1110}; constexpr std::uint8_t mask_nma_header_reserved{0b0000'0001}; constexpr std::uint8_t mask_dsm_id{0b0000'0001}; constexpr std::uint8_t mask_dsm_block_id{0b0000'1111}; +constexpr std::uint8_t mask_dsm_number_blocks{0b1111'0000}; #endif @@ -174,6 +176,10 @@ inline uint8_t get_dsm_block_id(uint8_t dsm_header) return dsm_header & mask_dsm_block_id; } +inline uint8_t get_number_blocks(uint8_t dsm_message_0) +{ + return (dsm_message_0 & mask_dsm_number_blocks) >> 4; +} /** \} */ /** \} */ From e6419a2063d1cdc5f621072ac1688a4efff4d650 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 29 May 2023 14:52:30 +0200 Subject: [PATCH 011/219] Add work on OSNMA receiver --- .../system_parameters/galileo_inav_message.cc | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index dd9f9df6a..48d973d97 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -195,6 +195,11 @@ void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even // const std::string Reserved_2 = page_INAV.substr(220, 8); // const std::string Tail_odd = page_INAV.substr(228, 6); + if (page_position_in_inav_subframe != 255) + { + page_position_in_inav_subframe++; + } + // ************ CRC checksum control *******/ std::stringstream TLM_word_for_CRC_stream; TLM_word_for_CRC_stream << page_INAV; @@ -855,15 +860,11 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) const auto page_number = static_cast(read_navigation_unsigned(data_jk_bits, PAGE_TYPE_BIT)); DLOG(INFO) << "Page number = " << page_number; - if (page_position_in_inav_subframe != 255) - { - page_position_in_inav_subframe++; - } - switch (page_number) { case 1: // Word type 1: Ephemeris (1/4) { + page_position_in_inav_subframe = 10; read_page_1(data_jk_bits); if (enable_rs) { @@ -935,6 +936,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) } case 3: // Word type 3: Ephemeris (3/4) and SISA { + page_position_in_inav_subframe = 11; read_page_3(data_jk_bits); if (enable_rs) { @@ -967,6 +969,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) case 4: // Word type 4: Ephemeris (4/4) and Clock correction parameters { + page_position_in_inav_subframe = 1; read_page_4(data_jk_bits); if (enable_rs) { @@ -998,6 +1001,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) } case 5: // Word type 5: Ionospheric correction, BGD, signal health and data validity status and GST + page_position_in_inav_subframe = 12; // Ionospheric correction ai0_5 = static_cast(read_navigation_unsigned(data_jk_bits, AI0_5_BIT)); ai0_5 = ai0_5 * AI0_5_LSB; @@ -1048,6 +1052,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) break; case 6: // Word type 6: GST-UTC conversion parameters + page_position_in_inav_subframe = 2; A0_6 = static_cast(read_navigation_signed(data_jk_bits, A0_6_BIT)); A0_6 = A0_6 * A0_6_LSB; DLOG(INFO) << "A0_6= " << A0_6; @@ -1076,6 +1081,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) break; case 7: // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number + page_position_in_inav_subframe = 3; IOD_a_7 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_A_7_BIT)); DLOG(INFO) << "IOD_a_7= " << IOD_a_7; WN_a_7 = static_cast(read_navigation_unsigned(data_jk_bits, WN_A_7_BIT)); @@ -1110,7 +1116,8 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) DLOG(INFO) << "flag_tow_set" << flag_TOW_set; break; - case 8: // Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2)*/ + case 8: // Word type 8: Almanac for SVID1 (2/2) and SVID2 (1/2) + page_position_in_inav_subframe = 4; IOD_a_8 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_A_8_BIT)); DLOG(INFO) << "IOD_a_8= " << IOD_a_8; af0_8 = static_cast(read_navigation_signed(data_jk_bits, AF0_8_BIT)); @@ -1148,6 +1155,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) break; case 9: // Word type 9: Almanac for SVID2 (2/2) and SVID3 (1/2) + page_position_in_inav_subframe = 3; IOD_a_9 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_A_9_BIT)); DLOG(INFO) << "IOD_a_9= " << IOD_a_9; WN_a_9 = static_cast(read_navigation_unsigned(data_jk_bits, WN_A_9_BIT)); @@ -1187,6 +1195,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) break; case 10: // Word type 10: Almanac for SVID3 (2/2) and GST-GPS conversion parameters + page_position_in_inav_subframe = 4; IOD_a_10 = static_cast(read_navigation_unsigned(data_jk_bits, IOD_A_10_BIT)); DLOG(INFO) << "IOD_a_10= " << IOD_a_10; Omega0_10 = static_cast(read_navigation_signed(data_jk_bits, OMEGA0_10_BIT)); @@ -1258,6 +1267,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) case 17: // Word type 17: FEC2 Reed-Solomon for CED { + page_position_in_inav_subframe = 5; if (enable_rs) { IODnav_LSB17 = read_octet_unsigned(data_jk_bits, RS_IODNAV_LSBS); @@ -1287,6 +1297,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) case 18: // Word type 18: FEC2 Reed-Solomon for CED { + page_position_in_inav_subframe = 5; if (enable_rs) { IODnav_LSB18 = read_octet_unsigned(data_jk_bits, RS_IODNAV_LSBS); @@ -1316,6 +1327,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) case 19: // Word type 19: FEC2 Reed-Solomon for CED { + page_position_in_inav_subframe = 6; if (enable_rs) { IODnav_LSB19 = read_octet_unsigned(data_jk_bits, RS_IODNAV_LSBS); @@ -1345,6 +1357,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) case 20: // Word type 20: FEC2 Reed-Solomon for CED { + page_position_in_inav_subframe = 6; if (enable_rs) { IODnav_LSB20 = read_octet_unsigned(data_jk_bits, RS_IODNAV_LSBS); @@ -1392,8 +1405,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) break; } - if (page_position_in_inav_subframe != 0 && - page_position_in_inav_subframe > 14 && + if (page_position_in_inav_subframe > 14 && page_position_in_inav_subframe != 255) { // something weird happened, reset @@ -1416,8 +1428,7 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() bool Galileo_Inav_Message::have_new_nma() { - if (std::all_of(nma_position_filled.begin(), nma_position_filled.end(), - [](int32_t element) { return element == 1; })) + if (std::all_of(nma_position_filled.begin(), nma_position_filled.end(), [](int8_t element) { return element == 1; })) { return true; } From c6c0fc651a944867c2e32e657e1be386a2becc12 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 1 Jun 2023 11:52:27 +0200 Subject: [PATCH 012/219] Add work on OSNMA receiver --- src/core/libs/osnma_msg_receiver.cc | 62 +++++++++++++--------- src/core/system_parameters/Galileo_OSNMA.h | 24 ++++----- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index ec875d696..5ea504e4a 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -145,42 +145,42 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][13 * d_osnma_data.d_dsm_header.dsm_block_id + index] = *it; index++; } + if (d_osnma_data.d_dsm_header.dsm_block_id == 0) { // Get number of blocks in message - uint8_t nb = get_number_blocks(d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][0]); + uint8_t nb = get_number_blocks_index(d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][0]); uint16_t number_of_blocks = 0; if (d_osnma_data.d_dsm_header.dsm_id < 12) { - // Table 3 - const auto it = OSNMA_TABLE_3.find(nb); - if (it != OSNMA_TABLE_3.cend()) - { - number_of_blocks = it->second.first; - } - } - else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) - { - // Table 7 + // DSM-KROOT Table 7 const auto it = OSNMA_TABLE_7.find(nb); if (it != OSNMA_TABLE_7.cend()) { number_of_blocks = it->second.first; } } + else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) + { + // DSM-PKR Table 3 + const auto it = OSNMA_TABLE_3.find(nb); + if (it != OSNMA_TABLE_3.cend()) + { + number_of_blocks = it->second.first; + } + } d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = number_of_blocks; + if (number_of_blocks == 0) + { + // Something is wrong, start over + d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; + d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; + } } // Annotate bid d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; - std::cout << "d_dsm_id_received"; - for (auto v : d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id]) - { - std::cout << " " << static_cast(v); - } - std::cout << std::endl; - LOG(WARNING) << "d_number_of blocks: " << static_cast(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) << " BID: " << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) << " DSM ID: " << static_cast(d_osnma_data.d_dsm_header.dsm_id); // is message complete? -> process_dsm_message(osnma_msg) if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].begin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].end(), 0))) @@ -196,7 +196,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ process_dsm_message(dsm_msg); d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; - d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; + // d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } } @@ -207,7 +207,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { LOG(WARNING) << "OSNMA: DSM-KROOT message received."; // DSM-KROOT message - d_osnma_data.d_dsm_kroot_message.nb_dk = (dsm_msg[0] & 0b11110000) >> 4; + d_osnma_data.d_dsm_kroot_message.nb_dk = get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_kroot_message.pkid = (dsm_msg[0] & 0b00001111); d_osnma_data.d_dsm_kroot_message.cidkr = (dsm_msg[1] & 0b11000000) >> 6; d_osnma_data.d_dsm_kroot_message.reserved1 = (dsm_msg[1] & 0b00110000) >> 4; @@ -222,11 +222,17 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg static_cast(dsm_msg[5]); d_osnma_data.d_dsm_kroot_message.towh_k = dsm_msg[6]; - uint32_t lk = 0; - const auto it = OSNMA_TABLE_10.find(d_osnma_data.d_dsm_kroot_message.ks); - if (it != OSNMA_TABLE_10.cend()) + uint16_t l_dk_bits = 0; + const auto it = OSNMA_TABLE_7.find(d_osnma_data.d_dsm_kroot_message.nb_dk); + if (it != OSNMA_TABLE_7.cend()) { - lk = it->second; + l_dk_bits = it->second.second; + } + uint16_t lk_bits = 0; + const auto it2 = OSNMA_TABLE_10.find(d_osnma_data.d_dsm_kroot_message.ks); + if (it2 != OSNMA_TABLE_10.cend()) + { + lk_bits = it2->second; } d_osnma_data.d_dsm_kroot_message.alpha = (static_cast(dsm_msg[7]) << 40) + @@ -235,12 +241,18 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg (static_cast(dsm_msg[10]) << 16) + (static_cast(dsm_msg[11]) << 8) + static_cast(dsm_msg[12]); - uint32_t bytes_lk = lk / 8; + uint16_t bytes_lk = lk_bits / 8; d_osnma_data.d_dsm_kroot_message.kroot = std::vector(bytes_lk, 0); for (uint32_t k = 0; k < bytes_lk; k++) { d_osnma_data.d_dsm_kroot_message.kroot[k] = dsm_msg[13 + k]; } + uint16_t l_ds_bits; + const auto it3 = OSNMA_TABLE_15.find(""); + if (it3 != OSNMA_TABLE_15.cend()) + { + l_ds_bits = it3->second; + } // uint32_t l_ld = 0; // const auto it2 = OSNMA_TABLE_5.find() // d_osnma_data.d_dsm_kroot_message.ds = "0"; diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 89cc06d92..200c722fe 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -123,16 +123,16 @@ const std::unordered_map OSNMA_TABLE_10 = { {15, 0}, {15, 0}}; // key: ks, value: lk_bits -const std::unordered_map> OSNMA_TABLE_15 = { - {std::string("ECDSA P-256"), {512, 256}}, - {std::string("ECDSA P-521"), {1059, 521}}}; // key: ECDSA Curve and hash function, value: {l_ds_bits, key_lenght_bits} +const std::unordered_map OSNMA_TABLE_15 = { + {std::string("ECDSA P-256"), {512}}, + {std::string("ECDSA P-521"), {1056}}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} #if __cplusplus == 201103L constexpr std::uint8_t mask_nmas{0xC0}; constexpr std::uint8_t mask_cid{0x30}; constexpr std::uint8_t mask_cpks{0x07}; constexpr std::uint8_t mask_nma_header_reserved{0x01}; -constexpr std::uint8_t mask_dsm_id{0x01}; +constexpr std::uint8_t mask_dsm_id{0xF0}; constexpr std::uint8_t mask_dsm_block_id{0x0F}; constexpr std::uint8_t mask_dsm_number_blocks{0XF0}; #else @@ -140,43 +140,43 @@ constexpr std::uint8_t mask_nmas{0b1100'0000}; constexpr std::uint8_t mask_cid{0b0011'0000}; constexpr std::uint8_t mask_cpks{0b0000'1110}; constexpr std::uint8_t mask_nma_header_reserved{0b0000'0001}; -constexpr std::uint8_t mask_dsm_id{0b0000'0001}; +constexpr std::uint8_t mask_dsm_id{0b1111'0000}; constexpr std::uint8_t mask_dsm_block_id{0b0000'1111}; constexpr std::uint8_t mask_dsm_number_blocks{0b1111'0000}; #endif -inline uint8_t get_nmas(uint8_t nma_header) +uint8_t get_nmas(uint8_t nma_header) { return (nma_header & mask_nmas) >> 6; } -inline uint8_t get_cid(uint8_t nma_header) +uint8_t get_cid(uint8_t nma_header) { return (nma_header & mask_cid) >> 4; } -inline uint8_t get_cpks(uint8_t nma_header) +uint8_t get_cpks(uint8_t nma_header) { return (nma_header & mask_cpks) >> 1; } -inline bool get_nma_header_reserved(uint8_t nma_header) +bool get_nma_header_reserved(uint8_t nma_header) { return ((nma_header & mask_nma_header_reserved) ? true : false); } -inline uint8_t get_dsm_id(uint8_t dsm_header) +uint8_t get_dsm_id(uint8_t dsm_header) { return (dsm_header & mask_dsm_id) >> 4; } -inline uint8_t get_dsm_block_id(uint8_t dsm_header) +uint8_t get_dsm_block_id(uint8_t dsm_header) { return dsm_header & mask_dsm_block_id; } -inline uint8_t get_number_blocks(uint8_t dsm_message_0) +uint8_t get_number_blocks_index(uint8_t dsm_message_0) { return (dsm_message_0 & mask_dsm_number_blocks) >> 4; } From cc8fa9a4d218c32b4ab987c75af927772a3c4b6d Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 1 Jun 2023 13:41:30 +0200 Subject: [PATCH 013/219] Add work on OSNMA receiver --- src/core/libs/osnma_msg_receiver.cc | 72 +++++++++++++++++++--- src/core/libs/osnma_msg_receiver.h | 8 +++ src/core/system_parameters/Galileo_OSNMA.h | 6 +- src/core/system_parameters/osnma_data.h | 26 ++++++++ 4 files changed, 102 insertions(+), 10 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 5ea504e4a..0e8996072 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -111,6 +111,7 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& read_nma_header(osnma_msg->hkroot[0]); read_dsm_header(osnma_msg->hkroot[1]); read_dsm_block(osnma_msg); + read_mack_block(osnma_msg); } @@ -247,16 +248,34 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_osnma_data.d_dsm_kroot_message.kroot[k] = dsm_msg[13 + k]; } - uint16_t l_ds_bits; - const auto it3 = OSNMA_TABLE_15.find(""); - if (it3 != OSNMA_TABLE_15.cend()) + + std::string hash_function; + const auto it3 = OSNMA_TABLE_8.find(d_osnma_data.d_dsm_kroot_message.hf); + if (it3 != OSNMA_TABLE_8.cend()) { - l_ds_bits = it3->second; + hash_function = it3->second; } - // uint32_t l_ld = 0; - // const auto it2 = OSNMA_TABLE_5.find() - // d_osnma_data.d_dsm_kroot_message.ds = "0"; - // d_osnma_data.d_dsm_kroot_message.p_dk; + + uint16_t l_ds_bits = 0; + const auto it4 = OSNMA_TABLE_15.find(hash_function); + if (it4 != OSNMA_TABLE_15.cend()) + { + l_ds_bits = it4->second; + } + uint16_t l_ds_bytes = l_ds_bits / 8; + d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); + for (uint32_t k = 0; k < l_ds_bytes; k++) + { + d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + bytes_lk + k]; + } + uint16_t l_pdk_bytes = (l_dk_bits - 104 - lk_bits - l_ds_bits) / 8; + + d_osnma_data.d_dsm_kroot_message.p_dk = std::vector(l_pdk_bytes, 0); + for (uint32_t k = 0; k < l_ds_bytes; k++) + { + d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; + } + // validation? } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) { @@ -308,4 +327,41 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // Reserved message? d_osnma_data = OSNMA_data(); } + d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } + + +void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma_msg) +{ + uint32_t index = 0; + for (size_t i = 0; i < osnma_msg->mack.size(); i++) + { + uint32_t value = osnma_msg->mack[i]; + d_mack_message[index] = static_cast((value & 0xFF000000) >> 6); + d_mack_message[index + 1] = static_cast((value & 0x00FF0000) >> 4); + d_mack_message[index + 2] = static_cast((value & 0x0000FF00) >> 2); + d_mack_message[index + 3] = static_cast(value & 0x000000FF); + index = index + 4; + } + read_mack_header(osnma_msg); + read_mack_info_and_tags(osnma_msg); + read_mack_key(osnma_msg); + read_mack_padding(osnma_msg); +} + +void osnma_msg_receiver::read_mack_header(const std::shared_ptr& osnma_msg) +{ +} + +void osnma_msg_receiver::read_mack_info_and_tags(const std::shared_ptr& osnma_msg) +{ +} + + +void osnma_msg_receiver::read_mack_key(const std::shared_ptr& osnma_msg) +{ +} + +void osnma_msg_receiver::read_mack_padding(const std::shared_ptr& osnma_msg) +{ +} \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 59c65bfe2..65bcac037 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -59,11 +59,19 @@ private: void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); + void read_mack_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg); + void read_mack_header(const std::shared_ptr& osnma_msg); + void read_mack_info_and_tags(const std::shared_ptr& osnma_msg); + void read_mack_key(const std::shared_ptr& osnma_msg); + void read_mack_padding(const std::shared_ptr& osnma_msg); + std::array, 16> d_dsm_message{}; std::array, 16> d_dsm_id_received{}; std::array d_number_of_blocks{}; + std::array d_mack_message{}; + OSNMA_data d_osnma_data{}; bool d_new_data{false}; }; diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 200c722fe..6e0b1a6f8 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -124,8 +124,10 @@ const std::unordered_map OSNMA_TABLE_10 = { {15, 0}}; // key: ks, value: lk_bits const std::unordered_map OSNMA_TABLE_15 = { - {std::string("ECDSA P-256"), {512}}, - {std::string("ECDSA P-521"), {1056}}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} + {std::string("ECDSA P-256"), 512}, + {std::string("ECDSA P-521"), 1056}, + {std::string("SHA-256"), 512}, + {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} #if __cplusplus == 201103L constexpr std::uint8_t mask_nmas{0xC0}; diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 966e425ac..aa4eaf21f 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -42,6 +42,24 @@ struct dsm_header uint8_t dsm_block_id; }; +struct mack_header +{ + std::vector tag0; + uint16_t macsec; + uint8_t cop; +}; + +struct tag +{ + std::vector tag; + uint16_t tag_info; +}; + +struct tag_and_info +{ + std::vector tags; +}; + struct DSM_PKR_message { uint8_t nb_dp; @@ -73,6 +91,14 @@ struct DSM_KROOT_message std::vector p_dk; }; +struct MACK_message +{ + mack_header header; + tag_and_info tag_info; + std::vector key; + std::vector padding; +}; + /*! * \brief This class handles ONSMA data * See https://www.gsc-europa.eu/sites/default/files/sites/all/files/Galileo_OSNMA_User_ICD_for_Test_Phase_v1.0.pdf From ce50e160a7658fdab782d5ba3d9b57f81d353120 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 1 Jun 2023 14:41:01 +0200 Subject: [PATCH 014/219] Add work on OSNMA receiver --- src/core/libs/osnma_msg_receiver.cc | 39 +++++++++++----------- src/core/libs/osnma_msg_receiver.h | 8 ++--- src/core/system_parameters/Galileo_OSNMA.h | 19 +++++++++++ 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 0e8996072..89d4789c2 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include // for typeid @@ -121,13 +122,6 @@ void osnma_msg_receiver::read_nma_header(uint8_t nma_header) d_osnma_data.d_nma_header.cid = get_cid(nma_header); d_osnma_data.d_nma_header.cpks = get_cpks(nma_header); d_osnma_data.d_nma_header.reserved = get_nma_header_reserved(nma_header); - - // debug - const auto it = OSNMA_TABLE_2.find(d_osnma_data.d_nma_header.cpks); - if (it != OSNMA_TABLE_2.cend()) - { - LOG(WARNING) << "Chain and Public Key Status: " << it->second; - } } @@ -194,10 +188,9 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ dsm_msg[i * 13 + j] = d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][i * 13 + j]; } } - process_dsm_message(dsm_msg); d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; - // d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; + process_dsm_message(dsm_msg); } } @@ -273,7 +266,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_kroot_message.p_dk = std::vector(l_pdk_bytes, 0); for (uint32_t k = 0; k < l_ds_bytes; k++) { - d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; + d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; } // validation? } @@ -291,7 +284,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_pkr_message.npkt = (dsm_msg[129] & 0b11110000) >> 4; d_osnma_data.d_dsm_pkr_message.npktid = (dsm_msg[129] & 0b00001111); - // Table 5 uint32_t l_npk = 0; const auto it = OSNMA_TABLE_5.find(d_osnma_data.d_dsm_pkr_message.npkt); if (it != OSNMA_TABLE_5.cend()) @@ -343,25 +335,34 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma d_mack_message[index + 3] = static_cast(value & 0x000000FF); index = index + 4; } - read_mack_header(osnma_msg); - read_mack_info_and_tags(osnma_msg); - read_mack_key(osnma_msg); - read_mack_padding(osnma_msg); + read_mack_header(); + read_mack_info_and_tags(); + read_mack_key(); + read_mack_padding(); } -void osnma_msg_receiver::read_mack_header(const std::shared_ptr& osnma_msg) + +void osnma_msg_receiver::read_mack_header() { + uint8_t lt_bits = 0; + const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); + if (it != OSNMA_TABLE_11.cend()) + { + lt_bits = it->second; + } } -void osnma_msg_receiver::read_mack_info_and_tags(const std::shared_ptr& osnma_msg) + +void osnma_msg_receiver::read_mack_info_and_tags() { } -void osnma_msg_receiver::read_mack_key(const std::shared_ptr& osnma_msg) +void osnma_msg_receiver::read_mack_key() { } -void osnma_msg_receiver::read_mack_padding(const std::shared_ptr& osnma_msg) + +void osnma_msg_receiver::read_mack_padding() { } \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 65bcac037..56790d9df 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -62,10 +62,10 @@ private: void read_mack_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg); - void read_mack_header(const std::shared_ptr& osnma_msg); - void read_mack_info_and_tags(const std::shared_ptr& osnma_msg); - void read_mack_key(const std::shared_ptr& osnma_msg); - void read_mack_padding(const std::shared_ptr& osnma_msg); + void read_mack_header(); + void read_mack_info_and_tags(); + void read_mack_key(); + void read_mack_padding(); std::array, 16> d_dsm_message{}; std::array, 16> d_dsm_id_received{}; diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 6e0b1a6f8..9d243d6fc 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -123,6 +123,25 @@ const std::unordered_map OSNMA_TABLE_10 = { {15, 0}, {15, 0}}; // key: ks, value: lk_bits +const std::unordered_map OSNMA_TABLE_11 = { + {0, 0}, + {1, 0}, + {2, 0}, + {3, 0}, + {4, 0}, + {5, 20}, + {6, 24}, + {7, 26}, + {8, 32}, + {9, 40}, + {10, 0}, + {11, 0}, + {12, 0}, + {13, 0}, + {14, 0}, + {15, 0}, +}; + const std::unordered_map OSNMA_TABLE_15 = { {std::string("ECDSA P-256"), 512}, {std::string("ECDSA P-521"), 1056}, From 7147959186e278642dd0281300972da47faf2116 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 09:49:37 +0200 Subject: [PATCH 015/219] Add work on OSNMA rx --- src/core/libs/CMakeLists.txt | 2 + src/core/libs/osnma_msg_receiver.cc | 104 +++++------ src/core/libs/osnma_msg_receiver.h | 12 +- src/core/libs/sha256.cc | 193 +++++++++++++++++++++ src/core/libs/sha256.h | 68 ++++++++ src/core/system_parameters/Galileo_OSNMA.h | 140 ++++++++++++++- 6 files changed, 458 insertions(+), 61 deletions(-) create mode 100644 src/core/libs/sha256.cc create mode 100644 src/core/libs/sha256.h diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index 1c0c6e811..cd6a03ed0 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -22,6 +22,7 @@ set(CORE_LIBS_SOURCES nav_message_udp_sink.cc galileo_tow_map.cc osnma_msg_receiver.cc + sha256.cc ) set(CORE_LIBS_HEADERS @@ -39,6 +40,7 @@ set(CORE_LIBS_HEADERS nav_message_monitor.h galileo_tow_map.h osnma_msg_receiver.h + sha256.h ) if(ENABLE_FPGA) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 89d4789c2..e33f79dee 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -176,9 +176,9 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ // Annotate bid d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; - // is message complete? -> process_dsm_message(osnma_msg) + // is message complete? -> Process DSM message if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && - (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].begin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].end(), 0))) + (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cbegin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cend(), 0))) { std::vector dsm_msg(std::size_t(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) * 13, 0); for (uint32_t i = 0; i < d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]; i++) @@ -190,64 +190,35 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; - process_dsm_message(dsm_msg); + process_dsm_message(dsm_msg, osnma_msg->hkroot[0]); } } -void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg) +void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg, uint8_t nma_header) { if (d_osnma_data.d_dsm_header.dsm_id < 12) { LOG(WARNING) << "OSNMA: DSM-KROOT message received."; // DSM-KROOT message d_osnma_data.d_dsm_kroot_message.nb_dk = get_number_blocks_index(dsm_msg[0]); - d_osnma_data.d_dsm_kroot_message.pkid = (dsm_msg[0] & 0b00001111); - d_osnma_data.d_dsm_kroot_message.cidkr = (dsm_msg[1] & 0b11000000) >> 6; - d_osnma_data.d_dsm_kroot_message.reserved1 = (dsm_msg[1] & 0b00110000) >> 4; - d_osnma_data.d_dsm_kroot_message.hf = (dsm_msg[1] & 0b00001100) >> 2; + d_osnma_data.d_dsm_kroot_message.pkid = get_pkid(dsm_msg); // (dsm_msg[0] & 0b00001111); + d_osnma_data.d_dsm_kroot_message.cidkr = get_cidkr(dsm_msg); // (dsm_msg[1] & 0b11000000) >> 6; + d_osnma_data.d_dsm_kroot_message.reserved1 = get_dsm_reserved1(dsm_msg); // (dsm_msg[1] & 0b00110000) >> 4; + d_osnma_data.d_dsm_kroot_message.hf = get_hf(dsm_msg); // (dsm_msg[1] & 0b00001100) >> 2; + d_osnma_data.d_dsm_kroot_message.mf = get_mf(dsm_msg); // (dsm_msg[1] & 0b00000011); + d_osnma_data.d_dsm_kroot_message.ks = get_ks(dsm_msg); // (dsm_msg[2] & 0b11110000) >> 4; + d_osnma_data.d_dsm_kroot_message.ts = get_ts(dsm_msg); // (dsm_msg[2] & 0b00001111); + d_osnma_data.d_dsm_kroot_message.maclt = get_maclt(dsm_msg); // dsm_msg[3]; + d_osnma_data.d_dsm_kroot_message.reserved = get_dsm_reserved(dsm_msg); // (dsm_msg[4] & 0b11110000) >> 4; + d_osnma_data.d_dsm_kroot_message.wn_k = get_wn_k(dsm_msg); // static_cast((dsm_msg[4] & 0b00001111) << 8) + static_cast(dsm_msg[5]); + d_osnma_data.d_dsm_kroot_message.towh_k = get_towh_k(dsm_msg); // dsm_msg[6]; + d_osnma_data.d_dsm_kroot_message.alpha = get_alpha(dsm_msg); - d_osnma_data.d_dsm_kroot_message.mf = (dsm_msg[1] & 0b00000011); - d_osnma_data.d_dsm_kroot_message.ks = (dsm_msg[2] & 0b11110000) >> 4; - d_osnma_data.d_dsm_kroot_message.ts = (dsm_msg[2] & 0b00001111); - d_osnma_data.d_dsm_kroot_message.maclt = dsm_msg[3]; - d_osnma_data.d_dsm_kroot_message.reserved = (dsm_msg[4] & 0b11110000) >> 4; - d_osnma_data.d_dsm_kroot_message.wn_k = static_cast((dsm_msg[4] & 0b00001111) << 8) + - static_cast(dsm_msg[5]); - d_osnma_data.d_dsm_kroot_message.towh_k = dsm_msg[6]; + uint16_t bytes_lk = get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; + d_osnma_data.d_dsm_kroot_message.kroot = get_kroot(dsm_msg, bytes_lk); - uint16_t l_dk_bits = 0; - const auto it = OSNMA_TABLE_7.find(d_osnma_data.d_dsm_kroot_message.nb_dk); - if (it != OSNMA_TABLE_7.cend()) - { - l_dk_bits = it->second.second; - } - uint16_t lk_bits = 0; - const auto it2 = OSNMA_TABLE_10.find(d_osnma_data.d_dsm_kroot_message.ks); - if (it2 != OSNMA_TABLE_10.cend()) - { - lk_bits = it2->second; - } - - d_osnma_data.d_dsm_kroot_message.alpha = (static_cast(dsm_msg[7]) << 40) + - (static_cast(dsm_msg[8]) << 32) + - (static_cast(dsm_msg[9]) << 24) + - (static_cast(dsm_msg[10]) << 16) + - (static_cast(dsm_msg[11]) << 8) + - static_cast(dsm_msg[12]); - uint16_t bytes_lk = lk_bits / 8; - d_osnma_data.d_dsm_kroot_message.kroot = std::vector(bytes_lk, 0); - for (uint32_t k = 0; k < bytes_lk; k++) - { - d_osnma_data.d_dsm_kroot_message.kroot[k] = dsm_msg[13 + k]; - } - - std::string hash_function; - const auto it3 = OSNMA_TABLE_8.find(d_osnma_data.d_dsm_kroot_message.hf); - if (it3 != OSNMA_TABLE_8.cend()) - { - hash_function = it3->second; - } + std::string hash_function = get_hash_function(d_osnma_data.d_dsm_kroot_message.hf); uint16_t l_ds_bits = 0; const auto it4 = OSNMA_TABLE_15.find(hash_function); @@ -257,18 +228,43 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } uint16_t l_ds_bytes = l_ds_bits / 8; d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); - for (uint32_t k = 0; k < l_ds_bytes; k++) + for (uint16_t k = 0; k < l_ds_bytes; k++) { d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + bytes_lk + k]; } - uint16_t l_pdk_bytes = (l_dk_bits - 104 - lk_bits - l_ds_bits) / 8; + uint16_t l_pdk_bytes = (l_ds_bytes - 13 - bytes_lk - l_ds_bytes); d_osnma_data.d_dsm_kroot_message.p_dk = std::vector(l_pdk_bytes, 0); - for (uint32_t k = 0; k < l_ds_bytes; k++) + for (uint16_t k = 0; k < l_ds_bytes; k++) { d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; } - // validation? + // validation of padding + std::vector M; + M.push_back(nma_header); + for (int i = 1; i < 13; i++) + { + M.push_back(dsm_msg[i]); + } + for (uint16_t i = 0; i < bytes_lk; i++) + { + M.push_back(dsm_msg[13 + i]); + } + for (uint16_t k = 0; k < l_ds_bytes; k++) + { + M.push_back(dsm_msg[13 + bytes_lk + k]); + } + sha256.update(&M[0], M.size()); + uint8_t* digest = sha256.digest(); + std::vector p_dk_computed; + for (uint16_t i = 0; i < l_pdk_bytes; i++) + { + p_dk_computed.push_back(digest[i]); + } + if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_computed) + { + std::cout << "OSNMA: DSM-KROOT message validated" << std::endl; + } } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) { @@ -350,6 +346,10 @@ void osnma_msg_receiver::read_mack_header() { lt_bits = it->second; } + if (lt_bits == 0) + { + return; + } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 56790d9df..67aff46e5 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -22,10 +22,11 @@ #include "galileo_inav_message.h" // for OSNMA_msg #include "gnss_block_interface.h" // for gnss_shared_ptr #include "osnma_data.h" // for OSNMA_data -#include // for gr::block -#include // for pmt::pmt_t -#include // for std::array -#include // for std::shared_ptr +#include "sha256.h" +#include // for gr::block +#include // for pmt::pmt_t +#include // for std::array +#include // for std::shared_ptr #include /** \addtogroup Core @@ -60,12 +61,13 @@ private: void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); void read_mack_block(const std::shared_ptr& osnma_msg); - void process_dsm_message(const std::vector& dsm_msg); + void process_dsm_message(const std::vector& dsm_msg, uint8_t nma_header); void read_mack_header(); void read_mack_info_and_tags(); void read_mack_key(); void read_mack_padding(); + SHA256 sha256; std::array, 16> d_dsm_message{}; std::array, 16> d_dsm_id_received{}; diff --git a/src/core/libs/sha256.cc b/src/core/libs/sha256.cc new file mode 100644 index 000000000..e0b90189f --- /dev/null +++ b/src/core/libs/sha256.cc @@ -0,0 +1,193 @@ +/*! + * \file sha256.cc + * \brief Class foir computing SHA256 + * \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "sha256.h" +#include +#include +#include + +SHA256::SHA256() : d_blocklen(0), d_bitlen(0) +{ + d_state[0] = 0x6a09e667; + d_state[1] = 0xbb67ae85; + d_state[2] = 0x3c6ef372; + d_state[3] = 0xa54ff53a; + d_state[4] = 0x510e527f; + d_state[5] = 0x9b05688c; + d_state[6] = 0x1f83d9ab; + d_state[7] = 0x5be0cd19; +} + +void SHA256::update(const uint8_t *data, size_t length) +{ + for (size_t i = 0; i < length; i++) + { + d_data[d_blocklen++] = data[i]; + if (d_blocklen == 64) + { + transform(); + + // End of the block + d_bitlen += 512; + d_blocklen = 0; + } + } +} + +void SHA256::update(const std::string &data) +{ + update(reinterpret_cast(data.c_str()), data.size()); +} + +uint8_t *SHA256::digest() +{ + uint8_t *hash = new uint8_t[32]; + + pad(); + revert(hash); + + return hash; +} + +uint32_t SHA256::rotr(uint32_t x, uint32_t n) +{ + return (x >> n) | (x << (32 - n)); +} + +uint32_t SHA256::choose(uint32_t e, uint32_t f, uint32_t g) +{ + return (e & f) ^ (~e & g); +} + +uint32_t SHA256::majority(uint32_t a, uint32_t b, uint32_t c) +{ + return (a & (b | c)) | (b & c); +} + +uint32_t SHA256::sig0(uint32_t x) +{ + return SHA256::rotr(x, 7) ^ SHA256::rotr(x, 18) ^ (x >> 3); +} + +uint32_t SHA256::sig1(uint32_t x) +{ + return SHA256::rotr(x, 17) ^ SHA256::rotr(x, 19) ^ (x >> 10); +} + +void SHA256::transform() +{ + uint32_t maj, xorA, ch, xorE, sum, newA, newE, m[64]; + uint32_t state[8]; + + for (uint8_t i = 0, j = 0; i < 16; i++, j += 4) + { // Split data in 32 bit blocks for the 16 first words + m[i] = (d_data[j] << 24) | (d_data[j + 1] << 16) | (d_data[j + 2] << 8) | (d_data[j + 3]); + } + + for (uint8_t k = 16; k < 64; k++) + { // Remaining 48 blocks + m[k] = SHA256::sig1(m[k - 2]) + m[k - 7] + SHA256::sig0(m[k - 15]) + m[k - 16]; + } + + for (uint8_t i = 0; i < 8; i++) + { + state[i] = d_state[i]; + } + + for (uint8_t i = 0; i < 64; i++) + { + maj = SHA256::majority(state[0], state[1], state[2]); + xorA = SHA256::rotr(state[0], 2) ^ SHA256::rotr(state[0], 13) ^ SHA256::rotr(state[0], 22); + + ch = choose(state[4], state[5], state[6]); + + xorE = SHA256::rotr(state[4], 6) ^ SHA256::rotr(state[4], 11) ^ SHA256::rotr(state[4], 25); + + sum = m[i] + K[i] + state[7] + ch + xorE; + newA = xorA + maj + sum; + newE = state[3] + sum; + + state[7] = state[6]; + state[6] = state[5]; + state[5] = state[4]; + state[4] = newE; + state[3] = state[2]; + state[2] = state[1]; + state[1] = state[0]; + state[0] = newA; + } + + for (uint8_t i = 0; i < 8; i++) + { + d_state[i] += state[i]; + } +} + +void SHA256::pad() +{ + uint64_t i = d_blocklen; + uint8_t end = d_blocklen < 56 ? 56 : 64; + + d_data[i++] = 0x80; // Append a bit 1 + while (i < end) + { + d_data[i++] = 0x00; // Pad with zeros + } + + if (d_blocklen >= 56) + { + transform(); + memset(d_data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + d_bitlen += d_blocklen * 8; + d_data[63] = d_bitlen; + d_data[62] = d_bitlen >> 8; + d_data[61] = d_bitlen >> 16; + d_data[60] = d_bitlen >> 24; + d_data[59] = d_bitlen >> 32; + d_data[58] = d_bitlen >> 40; + d_data[57] = d_bitlen >> 48; + d_data[56] = d_bitlen >> 56; + transform(); +} + +void SHA256::revert(uint8_t *hash) +{ + // SHA uses big endian byte ordering + // Revert all bytes + for (uint8_t i = 0; i < 4; i++) + { + for (uint8_t j = 0; j < 8; j++) + { + hash[i + (j * 4)] = (d_state[j] >> (24 - i * 8)) & 0x000000ff; + } + } +} + +std::string SHA256::toString(const uint8_t *digest) +{ + std::stringstream s; + s << std::setfill('0') << std::hex; + + for (uint8_t i = 0; i < 32; i++) + { + s << std::setw(2) << (unsigned int)digest[i]; + } + + return s.str(); +} \ No newline at end of file diff --git a/src/core/libs/sha256.h b/src/core/libs/sha256.h new file mode 100644 index 000000000..8fb6b783c --- /dev/null +++ b/src/core/libs/sha256.h @@ -0,0 +1,68 @@ +/*! + * \file sha256.h + * \brief Class foir computing SHA256 + * \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +// https://github.com/System-Glitch/SHA256/blob/master/src/SHA256.cpp +#ifndef SHA256_H +#define SHA256_H + +#include +#include + +class SHA256 +{ +public: + SHA256(); + void update(const uint8_t *data, size_t length); + void update(const std::string &data); + uint8_t *digest(); + + static std::string toString(const uint8_t *digest); + +private: + uint8_t d_data[64]; + uint32_t d_blocklen; + uint64_t d_bitlen; + uint32_t d_state[8]; // A, B, C, D, E, F, G, H + + static constexpr std::array K = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + + static uint32_t rotr(uint32_t x, uint32_t n); + static uint32_t choose(uint32_t e, uint32_t f, uint32_t g); + static uint32_t majority(uint32_t a, uint32_t b, uint32_t c); + static uint32_t sig0(uint32_t x); + static uint32_t sig1(uint32_t x); + void transform(); + void pad(); + void revert(uint8_t *hash); +}; + +#endif \ No newline at end of file diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 9d243d6fc..14ccc6ad4 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -155,7 +155,16 @@ constexpr std::uint8_t mask_cpks{0x07}; constexpr std::uint8_t mask_nma_header_reserved{0x01}; constexpr std::uint8_t mask_dsm_id{0xF0}; constexpr std::uint8_t mask_dsm_block_id{0x0F}; -constexpr std::uint8_t mask_dsm_number_blocks{0XF0}; +constexpr std::uint8_t mask_dsm_number_blocks{0xF0}; +constexpr std::uint8_t mask_dsm_pkid{0x0F}; +constexpr std::uint8_t mask_dsm_cidkr{0xC0}; +constexpr std::uint8_t mask_dsm_reserved1{0x30}; +constexpr std::uint8_t mask_dsm_hf{0x0C}; +constexpr std::uint8_t mask_dsm_mf{0x03}; +constexpr std::uint8_t mask_dsm_ks{0xF0}; +constexpr std::uint8_t mask_dsm_ts{0x0F}; +constexpr std::uint8_t mask_dsm_reserved{0xF0}; +constexpr std::uint8_t mask_dsm_wk_k_msbyte{0x0F}; #else constexpr std::uint8_t mask_nmas{0b1100'0000}; constexpr std::uint8_t mask_cid{0b0011'0000}; @@ -164,9 +173,18 @@ constexpr std::uint8_t mask_nma_header_reserved{0b0000'0001}; constexpr std::uint8_t mask_dsm_id{0b1111'0000}; constexpr std::uint8_t mask_dsm_block_id{0b0000'1111}; constexpr std::uint8_t mask_dsm_number_blocks{0b1111'0000}; - +constexpr std::uint8_t mask_dsm_pkid{0b0000'1111}; +constexpr std::uint8_t mask_dsm_cidkr{0b1100'0000}; +constexpr std::uint8_t mask_dsm_reserved1{0b0011'0000}; +constexpr std::uint8_t mask_dsm_hf{0b0000'1100}; +constexpr std::uint8_t mask_dsm_mf{0b0000'0011}; +constexpr std::uint8_t mask_dsm_ks{0b1111'0000}; +constexpr std::uint8_t mask_dsm_ts{0b0000'1111}; +constexpr std::uint8_t mask_dsm_reserved{0b1111'0000}; +constexpr std::uint8_t mask_dsm_wk_k_msbyte{0b0000'1111}; #endif +// // hf = (dsm_msg[1] & 0b00001100) >> 2; uint8_t get_nmas(uint8_t nma_header) { return (nma_header & mask_nmas) >> 6; @@ -197,11 +215,125 @@ uint8_t get_dsm_block_id(uint8_t dsm_header) return dsm_header & mask_dsm_block_id; } -uint8_t get_number_blocks_index(uint8_t dsm_message_0) +uint8_t get_number_blocks_index(uint8_t dsm_msg_0) { - return (dsm_message_0 & mask_dsm_number_blocks) >> 4; + return (dsm_msg_0 & mask_dsm_number_blocks) >> 4; } +uint8_t get_pkid(const std::vector& dsm_msg) +{ + return (dsm_msg[0] & mask_dsm_pkid); +} + +uint8_t get_cidkr(const std::vector& dsm_msg) +{ + return (dsm_msg[1] & mask_dsm_cidkr) >> 6; +} + +uint8_t get_dsm_reserved1(const std::vector& dsm_msg) +{ + return (dsm_msg[1] & mask_dsm_reserved1) >> 4; +} + +uint8_t get_hf(const std::vector& dsm_msg) +{ + return (dsm_msg[1] & mask_dsm_hf) >> 2; +} + +uint8_t get_mf(const std::vector& dsm_msg) +{ + return (dsm_msg[1] & mask_dsm_mf); +} + +uint8_t get_ks(const std::vector& dsm_msg) +{ + return (dsm_msg[2] & mask_dsm_ks) >> 4; +} + +uint8_t get_ts(const std::vector& dsm_msg) +{ + return (dsm_msg[2] & mask_dsm_ts); +} + +uint8_t get_maclt(const std::vector& dsm_msg) +{ + return dsm_msg[3]; +} + +uint8_t get_dsm_reserved(const std::vector& dsm_msg) +{ + return (dsm_msg[4] & mask_dsm_reserved) >> 4; +} + +uint16_t get_wn_k(const std::vector& dsm_msg) +{ + return (static_cast((dsm_msg[4] & mask_dsm_wk_k_msbyte) << 8) + static_cast(dsm_msg[5])); +} + +uint8_t get_towh_k(const std::vector& dsm_msg) +{ + return dsm_msg[6]; +} + +uint64_t get_alpha(const std::vector& dsm_msg) +{ + uint64_t alpha = (static_cast(dsm_msg[8]) << 32) + + (static_cast(dsm_msg[9]) << 24) + + (static_cast(dsm_msg[10]) << 16) + + (static_cast(dsm_msg[11]) << 8) + + static_cast(dsm_msg[12]); + return alpha; +} + +uint16_t get_l_dk_bits(uint8_t nb_dk) +{ + const auto it = OSNMA_TABLE_7.find(nb_dk); + if (it != OSNMA_TABLE_7.cend()) + { + return it->second.second; + } + return 0; +} + +uint16_t get_lk_bits(uint8_t ks) +{ + const auto it = OSNMA_TABLE_10.find(ks); + if (it != OSNMA_TABLE_10.cend()) + { + return it->second; + } + return 0; +} + +std::vector get_kroot(const std::vector& dsm_msg, uint16_t bytes_lk) +{ + std::vector kroot = std::vector(bytes_lk, 0); + if (dsm_msg.size() > 13 + bytes_lk) + { + for (uint16_t k = 0; k < bytes_lk; k++) + { + kroot[k] = dsm_msg[13 + k]; + } + } + return kroot; +} + +std::string get_hash_function(uint8_t hf) +{ + std::string hash_; + const auto it = OSNMA_TABLE_8.find(hf); + if (it != OSNMA_TABLE_8.cend()) + { + hash_ = it->second; + } + return hash_; +} +// std::string hash_function; +// const auto it3 = OSNMA_TABLE_8.find(d_osnma_data.d_dsm_kroot_message.hf); +// if (it3 != OSNMA_TABLE_8.cend()) +// { +// hash_function = it3->second; +// } /** \} */ /** \} */ #endif // GNSS_SDR_GALILEO_OSNMA_H \ No newline at end of file From 9de1fd39ca25621d5454725698005a117f5026f0 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 11:33:58 +0200 Subject: [PATCH 016/219] Improve SHA256 computation --- src/core/libs/CMakeLists.txt | 17 +++++- src/core/libs/osnma_msg_receiver.cc | 64 ++++++++++++++++------ src/core/libs/osnma_msg_receiver.h | 12 ++-- src/core/system_parameters/Galileo_OSNMA.h | 2 +- 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index cd6a03ed0..02d6e31de 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -22,7 +22,6 @@ set(CORE_LIBS_SOURCES nav_message_udp_sink.cc galileo_tow_map.cc osnma_msg_receiver.cc - sha256.cc ) set(CORE_LIBS_HEADERS @@ -40,7 +39,6 @@ set(CORE_LIBS_HEADERS nav_message_monitor.h galileo_tow_map.h osnma_msg_receiver.h - sha256.h ) if(ENABLE_FPGA) @@ -104,6 +102,21 @@ target_link_libraries(core_libs Pugixml::pugixml ) +target_link_libraries(core_libs + PRIVATE + ${GNUTLS_LIBRARIES} + ${GNUTLS_OPENSSL_LIBRARY} +) + +target_include_directories(core_libs + PRIVATE + ${GNUTLS_INCLUDE_DIR} +) + +if(OPENSSL_FOUND) + target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_FALLBACK=1) +endif() + if(USE_GENERIC_LAMBDAS AND NOT GNURADIO_USES_STD_POINTERS) target_link_libraries(core_libs PUBLIC Boost::headers) else() diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e33f79dee..ac6d187b6 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -31,7 +31,6 @@ #include #include // for typeid - #if HAS_GENERIC_LAMBDA #else #include @@ -45,6 +44,13 @@ namespace wht = boost; namespace wht = std; #endif +#if USE_OPENSSL_FALLBACK +#include +#else +#include +#include +#endif + osnma_msg_receiver_sptr osnma_msg_receiver_make() { return osnma_msg_receiver_sptr(new osnma_msg_receiver()); @@ -202,17 +208,17 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg LOG(WARNING) << "OSNMA: DSM-KROOT message received."; // DSM-KROOT message d_osnma_data.d_dsm_kroot_message.nb_dk = get_number_blocks_index(dsm_msg[0]); - d_osnma_data.d_dsm_kroot_message.pkid = get_pkid(dsm_msg); // (dsm_msg[0] & 0b00001111); - d_osnma_data.d_dsm_kroot_message.cidkr = get_cidkr(dsm_msg); // (dsm_msg[1] & 0b11000000) >> 6; - d_osnma_data.d_dsm_kroot_message.reserved1 = get_dsm_reserved1(dsm_msg); // (dsm_msg[1] & 0b00110000) >> 4; - d_osnma_data.d_dsm_kroot_message.hf = get_hf(dsm_msg); // (dsm_msg[1] & 0b00001100) >> 2; - d_osnma_data.d_dsm_kroot_message.mf = get_mf(dsm_msg); // (dsm_msg[1] & 0b00000011); - d_osnma_data.d_dsm_kroot_message.ks = get_ks(dsm_msg); // (dsm_msg[2] & 0b11110000) >> 4; - d_osnma_data.d_dsm_kroot_message.ts = get_ts(dsm_msg); // (dsm_msg[2] & 0b00001111); - d_osnma_data.d_dsm_kroot_message.maclt = get_maclt(dsm_msg); // dsm_msg[3]; - d_osnma_data.d_dsm_kroot_message.reserved = get_dsm_reserved(dsm_msg); // (dsm_msg[4] & 0b11110000) >> 4; - d_osnma_data.d_dsm_kroot_message.wn_k = get_wn_k(dsm_msg); // static_cast((dsm_msg[4] & 0b00001111) << 8) + static_cast(dsm_msg[5]); - d_osnma_data.d_dsm_kroot_message.towh_k = get_towh_k(dsm_msg); // dsm_msg[6]; + d_osnma_data.d_dsm_kroot_message.pkid = get_pkid(dsm_msg); + d_osnma_data.d_dsm_kroot_message.cidkr = get_cidkr(dsm_msg); + d_osnma_data.d_dsm_kroot_message.reserved1 = get_dsm_reserved1(dsm_msg); + d_osnma_data.d_dsm_kroot_message.hf = get_hf(dsm_msg); + d_osnma_data.d_dsm_kroot_message.mf = get_mf(dsm_msg); + d_osnma_data.d_dsm_kroot_message.ks = get_ks(dsm_msg); + d_osnma_data.d_dsm_kroot_message.ts = get_ts(dsm_msg); + d_osnma_data.d_dsm_kroot_message.maclt = get_maclt(dsm_msg); + d_osnma_data.d_dsm_kroot_message.reserved = get_dsm_reserved(dsm_msg); + d_osnma_data.d_dsm_kroot_message.wn_k = get_wn_k(dsm_msg); + d_osnma_data.d_dsm_kroot_message.towh_k = get_towh_k(dsm_msg); d_osnma_data.d_dsm_kroot_message.alpha = get_alpha(dsm_msg); uint16_t bytes_lk = get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; @@ -254,12 +260,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { M.push_back(dsm_msg[13 + bytes_lk + k]); } - sha256.update(&M[0], M.size()); - uint8_t* digest = sha256.digest(); + + std::vector hash = computeSHA256(M); std::vector p_dk_computed; for (uint16_t i = 0; i < l_pdk_bytes; i++) { - p_dk_computed.push_back(digest[i]); + p_dk_computed.push_back(hash[i]); } if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_computed) { @@ -365,4 +371,30 @@ void osnma_msg_receiver::read_mack_key() void osnma_msg_receiver::read_mack_padding() { -} \ No newline at end of file +} + + +std::vector osnma_msg_receiver::computeSHA256(const std::vector& input) +{ + std::vector output_vector{32}; + uint8_t output[32]; + const uint8_t* input_ptr = input.data(); + size_t inputLength = input.size(); +#if USE_OPENSSL_FALLBACK + SHA256_CTX sha256Context; + SHA256_Init(&sha256Context); + SHA256_Update(&sha256Context, input_ptr, inputLength); + SHA256_Final(output, &sha256Context); +#else + gnutls_hash_hd_t hashHandle; + gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); + gnutls_hash(hashHandle, input_ptr, inputLength); + gnutls_hash_output(hashHandle, output); + gnutls_hash_deinit(hashHandle, output); +#endif + for (int i = 0; i < 32; i++) + { + output_vector[i] = output[i]; + } + return output_vector; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 67aff46e5..0b8635f7a 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -22,11 +22,10 @@ #include "galileo_inav_message.h" // for OSNMA_msg #include "gnss_block_interface.h" // for gnss_shared_ptr #include "osnma_data.h" // for OSNMA_data -#include "sha256.h" -#include // for gr::block -#include // for pmt::pmt_t -#include // for std::array -#include // for std::shared_ptr +#include // for gr::block +#include // for pmt::pmt_t +#include // for std::array +#include // for std::shared_ptr #include /** \addtogroup Core @@ -67,7 +66,8 @@ private: void read_mack_info_and_tags(); void read_mack_key(); void read_mack_padding(); - SHA256 sha256; + + std::vector computeSHA256(const std::vector& input); std::array, 16> d_dsm_message{}; std::array, 16> d_dsm_id_received{}; diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 14ccc6ad4..a79c88db7 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -308,7 +308,7 @@ uint16_t get_lk_bits(uint8_t ks) std::vector get_kroot(const std::vector& dsm_msg, uint16_t bytes_lk) { std::vector kroot = std::vector(bytes_lk, 0); - if (dsm_msg.size() > 13 + bytes_lk) + if (dsm_msg.size() > static_cast(13 + bytes_lk)) { for (uint16_t k = 0; k < bytes_lk; k++) { From 755045e6681d71c4178688937a701bc78a68c98d Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 11:36:15 +0200 Subject: [PATCH 017/219] Remove unused files --- src/core/libs/sha256.cc | 193 ---------------------------------------- src/core/libs/sha256.h | 68 -------------- 2 files changed, 261 deletions(-) delete mode 100644 src/core/libs/sha256.cc delete mode 100644 src/core/libs/sha256.h diff --git a/src/core/libs/sha256.cc b/src/core/libs/sha256.cc deleted file mode 100644 index e0b90189f..000000000 --- a/src/core/libs/sha256.cc +++ /dev/null @@ -1,193 +0,0 @@ -/*! - * \file sha256.cc - * \brief Class foir computing SHA256 - * \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es - * - * ----------------------------------------------------------------------------- - * - * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. - * This file is part of GNSS-SDR. - * - * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) - * SPDX-License-Identifier: GPL-3.0-or-later - * - * ----------------------------------------------------------------------------- - */ - -#include "sha256.h" -#include -#include -#include - -SHA256::SHA256() : d_blocklen(0), d_bitlen(0) -{ - d_state[0] = 0x6a09e667; - d_state[1] = 0xbb67ae85; - d_state[2] = 0x3c6ef372; - d_state[3] = 0xa54ff53a; - d_state[4] = 0x510e527f; - d_state[5] = 0x9b05688c; - d_state[6] = 0x1f83d9ab; - d_state[7] = 0x5be0cd19; -} - -void SHA256::update(const uint8_t *data, size_t length) -{ - for (size_t i = 0; i < length; i++) - { - d_data[d_blocklen++] = data[i]; - if (d_blocklen == 64) - { - transform(); - - // End of the block - d_bitlen += 512; - d_blocklen = 0; - } - } -} - -void SHA256::update(const std::string &data) -{ - update(reinterpret_cast(data.c_str()), data.size()); -} - -uint8_t *SHA256::digest() -{ - uint8_t *hash = new uint8_t[32]; - - pad(); - revert(hash); - - return hash; -} - -uint32_t SHA256::rotr(uint32_t x, uint32_t n) -{ - return (x >> n) | (x << (32 - n)); -} - -uint32_t SHA256::choose(uint32_t e, uint32_t f, uint32_t g) -{ - return (e & f) ^ (~e & g); -} - -uint32_t SHA256::majority(uint32_t a, uint32_t b, uint32_t c) -{ - return (a & (b | c)) | (b & c); -} - -uint32_t SHA256::sig0(uint32_t x) -{ - return SHA256::rotr(x, 7) ^ SHA256::rotr(x, 18) ^ (x >> 3); -} - -uint32_t SHA256::sig1(uint32_t x) -{ - return SHA256::rotr(x, 17) ^ SHA256::rotr(x, 19) ^ (x >> 10); -} - -void SHA256::transform() -{ - uint32_t maj, xorA, ch, xorE, sum, newA, newE, m[64]; - uint32_t state[8]; - - for (uint8_t i = 0, j = 0; i < 16; i++, j += 4) - { // Split data in 32 bit blocks for the 16 first words - m[i] = (d_data[j] << 24) | (d_data[j + 1] << 16) | (d_data[j + 2] << 8) | (d_data[j + 3]); - } - - for (uint8_t k = 16; k < 64; k++) - { // Remaining 48 blocks - m[k] = SHA256::sig1(m[k - 2]) + m[k - 7] + SHA256::sig0(m[k - 15]) + m[k - 16]; - } - - for (uint8_t i = 0; i < 8; i++) - { - state[i] = d_state[i]; - } - - for (uint8_t i = 0; i < 64; i++) - { - maj = SHA256::majority(state[0], state[1], state[2]); - xorA = SHA256::rotr(state[0], 2) ^ SHA256::rotr(state[0], 13) ^ SHA256::rotr(state[0], 22); - - ch = choose(state[4], state[5], state[6]); - - xorE = SHA256::rotr(state[4], 6) ^ SHA256::rotr(state[4], 11) ^ SHA256::rotr(state[4], 25); - - sum = m[i] + K[i] + state[7] + ch + xorE; - newA = xorA + maj + sum; - newE = state[3] + sum; - - state[7] = state[6]; - state[6] = state[5]; - state[5] = state[4]; - state[4] = newE; - state[3] = state[2]; - state[2] = state[1]; - state[1] = state[0]; - state[0] = newA; - } - - for (uint8_t i = 0; i < 8; i++) - { - d_state[i] += state[i]; - } -} - -void SHA256::pad() -{ - uint64_t i = d_blocklen; - uint8_t end = d_blocklen < 56 ? 56 : 64; - - d_data[i++] = 0x80; // Append a bit 1 - while (i < end) - { - d_data[i++] = 0x00; // Pad with zeros - } - - if (d_blocklen >= 56) - { - transform(); - memset(d_data, 0, 56); - } - - // Append to the padding the total message's length in bits and transform. - d_bitlen += d_blocklen * 8; - d_data[63] = d_bitlen; - d_data[62] = d_bitlen >> 8; - d_data[61] = d_bitlen >> 16; - d_data[60] = d_bitlen >> 24; - d_data[59] = d_bitlen >> 32; - d_data[58] = d_bitlen >> 40; - d_data[57] = d_bitlen >> 48; - d_data[56] = d_bitlen >> 56; - transform(); -} - -void SHA256::revert(uint8_t *hash) -{ - // SHA uses big endian byte ordering - // Revert all bytes - for (uint8_t i = 0; i < 4; i++) - { - for (uint8_t j = 0; j < 8; j++) - { - hash[i + (j * 4)] = (d_state[j] >> (24 - i * 8)) & 0x000000ff; - } - } -} - -std::string SHA256::toString(const uint8_t *digest) -{ - std::stringstream s; - s << std::setfill('0') << std::hex; - - for (uint8_t i = 0; i < 32; i++) - { - s << std::setw(2) << (unsigned int)digest[i]; - } - - return s.str(); -} \ No newline at end of file diff --git a/src/core/libs/sha256.h b/src/core/libs/sha256.h deleted file mode 100644 index 8fb6b783c..000000000 --- a/src/core/libs/sha256.h +++ /dev/null @@ -1,68 +0,0 @@ -/*! - * \file sha256.h - * \brief Class foir computing SHA256 - * \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es - * - * ----------------------------------------------------------------------------- - * - * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. - * This file is part of GNSS-SDR. - * - * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) - * SPDX-License-Identifier: GPL-3.0-or-later - * - * ----------------------------------------------------------------------------- - */ - -// https://github.com/System-Glitch/SHA256/blob/master/src/SHA256.cpp -#ifndef SHA256_H -#define SHA256_H - -#include -#include - -class SHA256 -{ -public: - SHA256(); - void update(const uint8_t *data, size_t length); - void update(const std::string &data); - uint8_t *digest(); - - static std::string toString(const uint8_t *digest); - -private: - uint8_t d_data[64]; - uint32_t d_blocklen; - uint64_t d_bitlen; - uint32_t d_state[8]; // A, B, C, D, E, F, G, H - - static constexpr std::array K = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; - - static uint32_t rotr(uint32_t x, uint32_t n); - static uint32_t choose(uint32_t e, uint32_t f, uint32_t g); - static uint32_t majority(uint32_t a, uint32_t b, uint32_t c); - static uint32_t sig0(uint32_t x); - static uint32_t sig1(uint32_t x); - void transform(); - void pad(); - void revert(uint8_t *hash); -}; - -#endif \ No newline at end of file From 6fc334942fcf1b206912f965123df58db552322b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 12:07:25 +0200 Subject: [PATCH 018/219] Add work on OSNMA Rx --- src/core/libs/osnma_msg_receiver.cc | 39 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index ac6d187b6..089a7f0a6 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -221,8 +221,24 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_kroot_message.towh_k = get_towh_k(dsm_msg); d_osnma_data.d_dsm_kroot_message.alpha = get_alpha(dsm_msg); + LOG(WARNING) << "nb_dk=" << static_cast(d_osnma_data.d_dsm_kroot_message.nb_dk); + LOG(WARNING) << "pkid=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid); + LOG(WARNING) << "cidkr=" << static_cast(d_osnma_data.d_dsm_kroot_message.cidkr); + LOG(WARNING) << "reserved1=" << static_cast(d_osnma_data.d_dsm_kroot_message.reserved1); + LOG(WARNING) << "hf=" << static_cast(d_osnma_data.d_dsm_kroot_message.hf); + LOG(WARNING) << "mf=" << static_cast(d_osnma_data.d_dsm_kroot_message.mf); + LOG(WARNING) << "ks=" << static_cast(d_osnma_data.d_dsm_kroot_message.ks); + LOG(WARNING) << "ts=" << static_cast(d_osnma_data.d_dsm_kroot_message.ts); + LOG(WARNING) << "maclt=" << static_cast(d_osnma_data.d_dsm_kroot_message.maclt); + LOG(WARNING) << "reserved=" << static_cast(d_osnma_data.d_dsm_kroot_message.reserved); + LOG(WARNING) << "wn_k=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k); + LOG(WARNING) << "towh_k=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k); + LOG(WARNING) << "alpha=" << d_osnma_data.d_dsm_kroot_message.alpha; + uint16_t bytes_lk = get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; d_osnma_data.d_dsm_kroot_message.kroot = get_kroot(dsm_msg, bytes_lk); + LOG(WARNING) << "lk_bits=" << static_cast(get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)); + LOG(WARNING) << "lk_bytes=" << static_cast(bytes_lk); std::string hash_function = get_hash_function(d_osnma_data.d_dsm_kroot_message.hf); @@ -233,13 +249,15 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg l_ds_bits = it4->second; } uint16_t l_ds_bytes = l_ds_bits / 8; + LOG(WARNING) << "ds_bits=" << static_cast(l_ds_bits); + LOG(WARNING) << "ds_bytes=" << static_cast(l_ds_bytes); d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); for (uint16_t k = 0; k < l_ds_bytes; k++) { d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + bytes_lk + k]; } uint16_t l_pdk_bytes = (l_ds_bytes - 13 - bytes_lk - l_ds_bytes); - + LOG(WARNING) << "pdk_bytes=" << static_cast(l_pdk_bytes); d_osnma_data.d_dsm_kroot_message.p_dk = std::vector(l_pdk_bytes, 0); for (uint16_t k = 0; k < l_ds_bytes; k++) { @@ -376,25 +394,18 @@ void osnma_msg_receiver::read_mack_padding() std::vector osnma_msg_receiver::computeSHA256(const std::vector& input) { - std::vector output_vector{32}; - uint8_t output[32]; - const uint8_t* input_ptr = input.data(); - size_t inputLength = input.size(); + std::vector output{32}; // SHA256 hash size #if USE_OPENSSL_FALLBACK SHA256_CTX sha256Context; SHA256_Init(&sha256Context); - SHA256_Update(&sha256Context, input_ptr, inputLength); + SHA256_Update(&sha256Context, input.data(), input.size()); SHA256_Final(output, &sha256Context); #else gnutls_hash_hd_t hashHandle; gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); - gnutls_hash(hashHandle, input_ptr, inputLength); - gnutls_hash_output(hashHandle, output); - gnutls_hash_deinit(hashHandle, output); + gnutls_hash(hashHandle, input.data(), input.size()); + gnutls_hash_output(hashHandle, output.data()); + gnutls_hash_deinit(hashHandle, output.data()); #endif - for (int i = 0; i < 32; i++) - { - output_vector[i] = output[i]; - } - return output_vector; + return output; } From 3d86bde405e4f78802c4331343ce9906f5a8d249 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 12:25:50 +0200 Subject: [PATCH 019/219] Add work on OSNMA Rx --- src/core/libs/osnma_msg_receiver.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 089a7f0a6..684a06000 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -256,7 +256,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + bytes_lk + k]; } - uint16_t l_pdk_bytes = (l_ds_bytes - 13 - bytes_lk - l_ds_bytes); + uint16_t l_dk_bits = get_l_dk_bits(d_osnma_data.d_dsm_kroot_message.nb_dk); + uint16_t l_dk_bytes = l_dk_bits / 8; + LOG(WARNING) << "dk_bits=" << static_cast(l_dk_bits); + LOG(WARNING) << "dk_bytes=" << static_cast(l_dk_bytes); + + uint16_t l_pdk_bytes = (l_dk_bytes - 13 - bytes_lk - l_ds_bytes); LOG(WARNING) << "pdk_bytes=" << static_cast(l_pdk_bytes); d_osnma_data.d_dsm_kroot_message.p_dk = std::vector(l_pdk_bytes, 0); for (uint16_t k = 0; k < l_ds_bytes; k++) From 3a803e01e4ae7e0afc2c1faed481c39e418f4fe5 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 13:13:55 +0200 Subject: [PATCH 020/219] Add work on OSNMA Rx --- src/core/libs/osnma_msg_receiver.cc | 76 +++++++++++++--------- src/core/system_parameters/Galileo_OSNMA.h | 29 +++++++-- 2 files changed, 70 insertions(+), 35 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 684a06000..b34186da2 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -23,6 +23,7 @@ #include // for DLOG #include // for gr::io_signature::make #include +#include #include #include #include @@ -268,46 +269,54 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; } - // validation of padding - std::vector M; - M.push_back(nma_header); - for (int i = 1; i < 13; i++) - { - M.push_back(dsm_msg[i]); - } - for (uint16_t i = 0; i < bytes_lk; i++) - { - M.push_back(dsm_msg[13 + i]); - } - for (uint16_t k = 0; k < l_ds_bytes; k++) - { - M.push_back(dsm_msg[13 + bytes_lk + k]); - } - std::vector hash = computeSHA256(M); - std::vector p_dk_computed; - for (uint16_t i = 0; i < l_pdk_bytes; i++) + uint16_t check_l_dk = 104 - std::ceil(1 + (((bytes_lk * 8) + l_ds_bits) / (104))); + if (l_dk_bits != check_l_dk) { - p_dk_computed.push_back(hash[i]); + std::cout << "OSNMA: Failed length reading" << std::endl; } - if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_computed) + else { - std::cout << "OSNMA: DSM-KROOT message validated" << std::endl; + // validation of padding + std::vector M; + M.push_back(nma_header); + for (int i = 1; i < 13; i++) + { + M.push_back(dsm_msg[i]); + } + for (uint16_t i = 0; i < bytes_lk; i++) + { + M.push_back(dsm_msg[13 + i]); + } + for (uint16_t k = 0; k < l_ds_bytes; k++) + { + M.push_back(dsm_msg[13 + bytes_lk + k]); + } + + std::vector hash = computeSHA256(M); + std::vector p_dk_computed; + for (uint16_t i = 0; i < l_pdk_bytes; i++) + { + p_dk_computed.push_back(hash[i]); + } + if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_computed) + { + std::cout << "OSNMA: DSM-KROOT message validated" << std::endl; + } } } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) { LOG(WARNING) << "OSNMA: DSM-PKR message received."; // DSM-PKR message - d_osnma_data.d_dsm_pkr_message.nb_dp = (dsm_msg[0] & 0b11110000) >> 4; - d_osnma_data.d_dsm_pkr_message.mid = (dsm_msg[0] & 0b00001111); + d_osnma_data.d_dsm_pkr_message.nb_dp = get_number_blocks_index(dsm_msg[0]); + d_osnma_data.d_dsm_pkr_message.mid = get_mid(dsm_msg); for (int k = 0; k > 128; k++) { d_osnma_data.d_dsm_pkr_message.itn[k] = dsm_msg[k + 1]; } - - d_osnma_data.d_dsm_pkr_message.npkt = (dsm_msg[129] & 0b11110000) >> 4; - d_osnma_data.d_dsm_pkr_message.npktid = (dsm_msg[129] & 0b00001111); + d_osnma_data.d_dsm_pkr_message.npkt = get_npkt(dsm_msg); + d_osnma_data.d_dsm_pkr_message.npktid = get_npktid(dsm_msg); uint32_t l_npk = 0; const auto it = OSNMA_TABLE_5.find(d_osnma_data.d_dsm_pkr_message.npkt); @@ -333,10 +342,19 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } uint32_t l_dp = dsm_msg.size(); uint32_t l_pd = l_dp - 130 - l_npk; - d_osnma_data.d_dsm_pkr_message.p_dp = std::vector(l_pd, 0); - for (uint32_t k = 0; k > l_pd; k++) + + uint32_t check_l_dp = 104 - std::ceil((1040 + l_npk * 8) / 104); + if (l_dp != check_l_dp) { - d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; + std::cout << "OSNMA: Failed length reading" << std::endl; + } + else + { + d_osnma_data.d_dsm_pkr_message.p_dp = std::vector(l_pd, 0); + for (uint32_t k = 0; k > l_pd; k++) + { + d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; + } } } else diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index a79c88db7..39f32752e 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -165,6 +165,9 @@ constexpr std::uint8_t mask_dsm_ks{0xF0}; constexpr std::uint8_t mask_dsm_ts{0x0F}; constexpr std::uint8_t mask_dsm_reserved{0xF0}; constexpr std::uint8_t mask_dsm_wk_k_msbyte{0x0F}; +constexpr std::uint8_t mask_dsm_mid{0x0F}; +constexpr std::uint8_t mask_dsm_npkt{0xF0}; +constexpr std::uint8_t mask_dsm_npktid{0x0F}; #else constexpr std::uint8_t mask_nmas{0b1100'0000}; constexpr std::uint8_t mask_cid{0b0011'0000}; @@ -182,6 +185,9 @@ constexpr std::uint8_t mask_dsm_ks{0b1111'0000}; constexpr std::uint8_t mask_dsm_ts{0b0000'1111}; constexpr std::uint8_t mask_dsm_reserved{0b1111'0000}; constexpr std::uint8_t mask_dsm_wk_k_msbyte{0b0000'1111}; +constexpr std::uint8_t mask_dsm_mid{0b0000'1111}; +constexpr std::uint8_t mask_dsm_npkt{0b1111'0000}; +constexpr std::uint8_t mask_dsm_npktid{0b0000'1111}; #endif // // hf = (dsm_msg[1] & 0b00001100) >> 2; @@ -328,12 +334,23 @@ std::string get_hash_function(uint8_t hf) } return hash_; } -// std::string hash_function; -// const auto it3 = OSNMA_TABLE_8.find(d_osnma_data.d_dsm_kroot_message.hf); -// if (it3 != OSNMA_TABLE_8.cend()) -// { -// hash_function = it3->second; -// } + +uint8_t get_mid(const std::vector& dsm_msg) +{ + return (dsm_msg[0] & mask_dsm_mid); +} + +uint8_t get_npkt(const std::vector& dsm_msg) +{ + return ((dsm_msg[129] & mask_dsm_npkt) >> 4); +} + +uint8_t get_npktid(const std::vector& dsm_msg) +{ + return (dsm_msg[129] & mask_dsm_npktid); +} + + /** \} */ /** \} */ #endif // GNSS_SDR_GALILEO_OSNMA_H \ No newline at end of file From 602c533c01694ffcafa9a4bb21865fddaf083131 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 13:42:24 +0200 Subject: [PATCH 021/219] Add debug info --- src/core/libs/osnma_msg_receiver.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index b34186da2..61a18d740 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -136,6 +136,8 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { d_osnma_data.d_dsm_header.dsm_id = get_dsm_id(dsm_header); d_osnma_data.d_dsm_header.dsm_block_id = get_dsm_block_id(dsm_header); // BID + LOG(WARNING) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); + LOG(WARNING) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); } @@ -173,9 +175,11 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = number_of_blocks; + LOG(WARNING) << "OSNMA: number_of_blocks=" << static_cast(number_of_blocks); if (number_of_blocks == 0) { // Something is wrong, start over + LOG(WARNING) << "OSNMA: Wrong number of blocks, start over"; d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; } @@ -271,6 +275,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } uint16_t check_l_dk = 104 - std::ceil(1 + (((bytes_lk * 8) + l_ds_bits) / (104))); + LOG(WARNING) << "check_l_dk_bits=" << static_cast(check_l_dk); if (l_dk_bits != check_l_dk) { std::cout << "OSNMA: Failed length reading" << std::endl; @@ -344,6 +349,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg uint32_t l_pd = l_dp - 130 - l_npk; uint32_t check_l_dp = 104 - std::ceil((1040 + l_npk * 8) / 104); + if (l_dp != check_l_dp) { std::cout << "OSNMA: Failed length reading" << std::endl; From 277e51b237c7d1c3d9ed819bdee172062509adde Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 14:00:00 +0200 Subject: [PATCH 022/219] Fix lenght check --- src/core/libs/osnma_msg_receiver.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 61a18d740..911522672 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -269,12 +269,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg uint16_t l_pdk_bytes = (l_dk_bytes - 13 - bytes_lk - l_ds_bytes); LOG(WARNING) << "pdk_bytes=" << static_cast(l_pdk_bytes); d_osnma_data.d_dsm_kroot_message.p_dk = std::vector(l_pdk_bytes, 0); - for (uint16_t k = 0; k < l_ds_bytes; k++) + for (uint16_t k = 0; k < l_pdk_bytes; k++) { d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; } - uint16_t check_l_dk = 104 - std::ceil(1 + (((bytes_lk * 8) + l_ds_bits) / (104))); + uint16_t check_l_dk = 104 * std::ceil(1 + (((bytes_lk * 8) + l_ds_bits) / (104))); LOG(WARNING) << "check_l_dk_bits=" << static_cast(check_l_dk); if (l_dk_bits != check_l_dk) { @@ -348,7 +348,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg uint32_t l_dp = dsm_msg.size(); uint32_t l_pd = l_dp - 130 - l_npk; - uint32_t check_l_dp = 104 - std::ceil((1040 + l_npk * 8) / 104); + uint32_t check_l_dp = 104 * std::ceil((1040 + l_npk * 8) / 104); if (l_dp != check_l_dp) { From da6b2a68318093d81f58f75cd5bcb2512d1f897b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 14:17:29 +0200 Subject: [PATCH 023/219] Fix lenght check --- src/core/libs/osnma_msg_receiver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 911522672..22db87cb7 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -274,7 +274,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; } - uint16_t check_l_dk = 104 * std::ceil(1 + (((bytes_lk * 8) + l_ds_bits) / (104))); + uint16_t check_l_dk = 104 * std::ceil(1 + (((bytes_lk * 8) + l_ds_bits) / 104)); LOG(WARNING) << "check_l_dk_bits=" << static_cast(check_l_dk); if (l_dk_bits != check_l_dk) { From db4b73724371a24338c348db673184a8b29ff34e Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 18:51:21 +0200 Subject: [PATCH 024/219] Add work on OSNMA Rx --- src/core/libs/osnma_msg_receiver.cc | 54 ++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 22db87cb7..a1583195d 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -274,7 +274,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; } - uint16_t check_l_dk = 104 * std::ceil(1 + (((bytes_lk * 8) + l_ds_bits) / 104)); + uint16_t check_l_dk = 104 * std::ceil(1.0 + static_cast((bytes_lk * 8.0) + l_ds_bits) / 104.0); LOG(WARNING) << "check_l_dk_bits=" << static_cast(check_l_dk); if (l_dk_bits != check_l_dk) { @@ -283,22 +283,36 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg else { // validation of padding - std::vector M; - M.push_back(nma_header); + std::vector MSG; + MSG.push_back(nma_header); for (int i = 1; i < 13; i++) { - M.push_back(dsm_msg[i]); + MSG.push_back(dsm_msg[i]); } for (uint16_t i = 0; i < bytes_lk; i++) { - M.push_back(dsm_msg[13 + i]); + MSG.push_back(dsm_msg[13 + i]); } for (uint16_t k = 0; k < l_ds_bytes; k++) { - M.push_back(dsm_msg[13 + bytes_lk + k]); + MSG.push_back(dsm_msg[13 + bytes_lk + k]); } - std::vector hash = computeSHA256(M); + std::vector hash = computeSHA256(MSG); + std::cout << "hash: "; + for (auto c : hash) + { + std::cout << static_cast(c); + } + std::cout << std::endl; + + std::cout << "pdk: "; + for (auto c : d_osnma_data.d_dsm_kroot_message.p_dk) + { + std::cout << static_cast(c); + } + std::cout << std::endl; + // truncate hash std::vector p_dk_computed; for (uint16_t i = 0; i < l_pdk_bytes; i++) { @@ -308,6 +322,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { std::cout << "OSNMA: DSM-KROOT message validated" << std::endl; } + // Validate signature } } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) @@ -336,11 +351,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg if (d_osnma_data.d_dsm_pkr_message.npkt == 4) { - // OAM + LOG(WARNING) << "OSNMA: OAM received"; l_npk = 0; // ? } - d_osnma_data.d_dsm_pkr_message.npk = std::vector(l_npk, 0); + d_osnma_data.d_dsm_pkr_message.npk = std::vector(l_npk, 0); // ECDSA Public Key for (uint32_t k = 0; k > l_npk; k++) { d_osnma_data.d_dsm_pkr_message.npk[k] = dsm_msg[k + 130]; @@ -348,7 +363,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg uint32_t l_dp = dsm_msg.size(); uint32_t l_pd = l_dp - 130 - l_npk; - uint32_t check_l_dp = 104 * std::ceil((1040 + l_npk * 8) / 104); + uint32_t check_l_dp = 104 * std::ceil(static_cast(1040.0 + l_npk * 8.0) / 104.0); if (l_dp != check_l_dp) { @@ -357,7 +372,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg else { d_osnma_data.d_dsm_pkr_message.p_dp = std::vector(l_pd, 0); - for (uint32_t k = 0; k > l_pd; k++) + for (uint32_t k = 0; k < l_pd; k++) { d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; } @@ -366,6 +381,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg else { // Reserved message? + LOG(WARNING) << "OSNMA Reserved message received"; d_osnma_data = OSNMA_data(); } d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; @@ -423,12 +439,12 @@ void osnma_msg_receiver::read_mack_padding() std::vector osnma_msg_receiver::computeSHA256(const std::vector& input) { - std::vector output{32}; // SHA256 hash size + std::vector output(32); // SHA256 hash size #if USE_OPENSSL_FALLBACK SHA256_CTX sha256Context; SHA256_Init(&sha256Context); SHA256_Update(&sha256Context, input.data(), input.size()); - SHA256_Final(output, &sha256Context); + SHA256_Final(output.data(), &sha256Context); #else gnutls_hash_hd_t hashHandle; gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); @@ -438,3 +454,15 @@ std::vector osnma_msg_receiver::computeSHA256(const std::vector& publicKey, const std::vector& publicKey) +// { +// bool success = false; +// #if USE_OPENSSL_FALLBACK +// #else +// gnutls_global_init(); +// int result = gnutls_pubkey_verify_data(publicKey, GNUTLS_SIGN_ECDSA_SHA256, digest, sizeof(digest), signature, signatureSize); +// success = (result == GNUTLS_E_SUCCESS); +// #endif +// return success; +// } From 8c4ae2253a3c1cd217e20ccce0031d0840aaad34 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 20:20:31 +0200 Subject: [PATCH 025/219] Try OpenSSL 3.0 --- src/core/libs/CMakeLists.txt | 42 +++++++++++++++++----- src/core/libs/osnma_msg_receiver.cc | 33 +++++++++++++++-- src/core/system_parameters/Galileo_OSNMA.h | 1 + 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index 02d6e31de..5757a2ddd 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -102,16 +102,40 @@ target_link_libraries(core_libs Pugixml::pugixml ) -target_link_libraries(core_libs - PRIVATE - ${GNUTLS_LIBRARIES} - ${GNUTLS_OPENSSL_LIBRARY} -) - -target_include_directories(core_libs - PRIVATE +if(OPENSSL_FOUND) + if(TARGET OpenSSL::SSL) + target_link_libraries(core_libs + PRIVATE + OpenSSL::SSL + ) + else() + target_link_libraries(core_libs + PRIVATE + ${OPENSSL_LIBRARIES} + ) + target_include_directories(core_libs + PRIVATE + ${OPENSSL_INCLUDE_DIR} + ) + endif() + if(OPENSSL_VERSION) + if(OPENSSL_VERSION VERSION_GREATER "3.0.0") + target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_3=1) + endif() + endif() +else() + target_link_libraries(core_libs + PRIVATE + ${GNUTLS_LIBRARIES} + ${GNUTLS_OPENSSL_LIBRARY} + ) + target_include_directories(core_libs + PRIVATE ${GNUTLS_INCLUDE_DIR} -) + ) +endif() + + if(OPENSSL_FOUND) target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_FALLBACK=1) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index a1583195d..e771d7de8 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -108,7 +108,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) auto osnma_data_ptr = std::make_shared(d_osnma_data); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); d_new_data = false; - d_osnma_data = OSNMA_data(); + // d_osnma_data = OSNMA_data(); DLOG(INFO) << "NMA info sent to the PVT block through the OSNMA_to_PVT async message port"; } } @@ -382,7 +382,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { // Reserved message? LOG(WARNING) << "OSNMA Reserved message received"; - d_osnma_data = OSNMA_data(); + // d_osnma_data = OSNMA_data(); } d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } @@ -441,10 +441,37 @@ std::vector osnma_msg_receiver::computeSHA256(const std::vector output(32); // SHA256 hash size #if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + // unsigned char mdVal[EVP_MAX_MD_SIZE]; + // unsigned char* md; + unsigned int mdLen; + EVP_MD_CTX* mdCtx = EVP_MD_CTX_new(); + if (!EVP_DigestInit_ex(mdCtx, EVP_sha256(), OPENSSL_ENGINE)) + { + // printf("Message digest initialization failed.\n"); + // EVP_MD_CTX_free(mdCtx); + // exit(EXIT_FAILURE); + } + if (!EVP_DigestUpdate(mdCtx, input.data(), input.size())) + { + // printf("Message digest update failed.\n"); + // EVP_MD_CTX_free(mdCtx); + // exit(EXIT_FAILURE); + } + if (!EVP_DigestFinal_ex(mdCtx, output.data(), &mdLen)) + { + printf("Message digest finalization failed.\n"); + EVP_MD_CTX_free(mdCtx); + exit(EXIT_FAILURE); + } + EVP_MD_CTX_free(mdCtx); + // md = mdVal; +#else SHA256_CTX sha256Context; SHA256_Init(&sha256Context); SHA256_Update(&sha256Context, input.data(), input.size()); SHA256_Final(output.data(), &sha256Context); +#endif #else gnutls_hash_hd_t hashHandle; gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); @@ -455,7 +482,7 @@ std::vector osnma_msg_receiver::computeSHA256(const std::vector& publicKey, const std::vector& publicKey) +// bool signature(const std::vector& publicKey, const std::vector& digest, const std::vector& signature) // { // bool success = false; // #if USE_OPENSSL_FALLBACK diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 39f32752e..62df5ccb1 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -22,6 +22,7 @@ #include #include #include +#include /** \addtogroup Core * \{ */ From 56031834a9ad3dd8b4cfcb3f3a5adb99338fec68 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 20:44:38 +0200 Subject: [PATCH 026/219] Fix indentation --- src/core/libs/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index 5757a2ddd..c5425d027 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -119,9 +119,9 @@ if(OPENSSL_FOUND) ) endif() if(OPENSSL_VERSION) - if(OPENSSL_VERSION VERSION_GREATER "3.0.0") - target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_3=1) - endif() + if(OPENSSL_VERSION VERSION_GREATER "3.0.0") + target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_3=1) + endif() endif() else() target_link_libraries(core_libs From be862bdd236ab7780ef861baa3c0ffc97127f2cd Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 21:14:24 +0200 Subject: [PATCH 027/219] Fix includes for openssl --- src/core/libs/osnma_msg_receiver.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e771d7de8..243ccb0ae 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -46,7 +46,11 @@ namespace wht = std; #endif #if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 +#include +#else #include +#endif #else #include #include From fec1468ec4f12ebf60043481698bbcaa751f04ad Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Jun 2023 21:16:45 +0200 Subject: [PATCH 028/219] Fix includes for openssl --- src/core/libs/osnma_msg_receiver.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 243ccb0ae..afa3eb746 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -48,6 +48,7 @@ namespace wht = std; #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 #include +#define OPENSSL_ENGINE NULL #else #include #endif From 1595c5f363684b3bd0d0c16fc95bad525bd8cec3 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 3 Jun 2023 12:06:16 +0200 Subject: [PATCH 029/219] Add osnma_dsm_reader --- .../galileo_telemetry_decoder_gs.cc | 2 +- src/core/libs/osnma_msg_receiver.cc | 82 +++---- src/core/libs/osnma_msg_receiver.h | 4 + src/core/system_parameters/CMakeLists.txt | 4 +- src/core/system_parameters/Galileo_OSNMA.h | 203 ----------------- .../system_parameters/osnma_dsm_reader.cc | 204 ++++++++++++++++++ src/core/system_parameters/osnma_dsm_reader.h | 109 ++++++++++ 7 files changed, 362 insertions(+), 246 deletions(-) create mode 100644 src/core/system_parameters/osnma_dsm_reader.cc create mode 100644 src/core/system_parameters/osnma_dsm_reader.h diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 60b83efc8..0868ab5e9 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -511,8 +511,8 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in if (d_band == '1' && d_inav_nav.have_new_nma() == true) { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); - this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); uint8_t nma_status = (tmp_obj->hkroot[0] & 0xC0) >> 6; + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); std::string nma_status_string; if (nma_status == 0) { diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index afa3eb746..41ab86aac 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -19,7 +19,7 @@ #include "osnma_msg_receiver.h" #include "Galileo_OSNMA.h" -#include "gnss_sdr_make_unique.h" // for std::make_unique in C++11 +#include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include // for DLOG #include // for gr::io_signature::make #include @@ -67,6 +67,7 @@ osnma_msg_receiver::osnma_msg_receiver() : gr::block("osnma_msg_receiver", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { + d_dsm_reader = std::make_unique(); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -130,17 +131,17 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& void osnma_msg_receiver::read_nma_header(uint8_t nma_header) { - d_osnma_data.d_nma_header.nmas = get_nmas(nma_header); - d_osnma_data.d_nma_header.cid = get_cid(nma_header); - d_osnma_data.d_nma_header.cpks = get_cpks(nma_header); - d_osnma_data.d_nma_header.reserved = get_nma_header_reserved(nma_header); + d_osnma_data.d_nma_header.nmas = d_dsm_reader->get_nmas(nma_header); + d_osnma_data.d_nma_header.cid = d_dsm_reader->get_cid(nma_header); + d_osnma_data.d_nma_header.cpks = d_dsm_reader->get_cpks(nma_header); + d_osnma_data.d_nma_header.reserved = d_dsm_reader->get_nma_header_reserved(nma_header); } void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { - d_osnma_data.d_dsm_header.dsm_id = get_dsm_id(dsm_header); - d_osnma_data.d_dsm_header.dsm_block_id = get_dsm_block_id(dsm_header); // BID + d_osnma_data.d_dsm_header.dsm_id = d_dsm_reader->get_dsm_id(dsm_header); + d_osnma_data.d_dsm_header.dsm_block_id = d_dsm_reader->get_dsm_block_id(dsm_header); // BID LOG(WARNING) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); LOG(WARNING) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); } @@ -158,7 +159,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ if (d_osnma_data.d_dsm_header.dsm_block_id == 0) { // Get number of blocks in message - uint8_t nb = get_number_blocks_index(d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][0]); + uint8_t nb = d_dsm_reader->get_number_blocks_index(d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][0]); uint16_t number_of_blocks = 0; if (d_osnma_data.d_dsm_header.dsm_id < 12) { @@ -217,19 +218,19 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { LOG(WARNING) << "OSNMA: DSM-KROOT message received."; // DSM-KROOT message - d_osnma_data.d_dsm_kroot_message.nb_dk = get_number_blocks_index(dsm_msg[0]); - d_osnma_data.d_dsm_kroot_message.pkid = get_pkid(dsm_msg); - d_osnma_data.d_dsm_kroot_message.cidkr = get_cidkr(dsm_msg); - d_osnma_data.d_dsm_kroot_message.reserved1 = get_dsm_reserved1(dsm_msg); - d_osnma_data.d_dsm_kroot_message.hf = get_hf(dsm_msg); - d_osnma_data.d_dsm_kroot_message.mf = get_mf(dsm_msg); - d_osnma_data.d_dsm_kroot_message.ks = get_ks(dsm_msg); - d_osnma_data.d_dsm_kroot_message.ts = get_ts(dsm_msg); - d_osnma_data.d_dsm_kroot_message.maclt = get_maclt(dsm_msg); - d_osnma_data.d_dsm_kroot_message.reserved = get_dsm_reserved(dsm_msg); - d_osnma_data.d_dsm_kroot_message.wn_k = get_wn_k(dsm_msg); - d_osnma_data.d_dsm_kroot_message.towh_k = get_towh_k(dsm_msg); - d_osnma_data.d_dsm_kroot_message.alpha = get_alpha(dsm_msg); + d_osnma_data.d_dsm_kroot_message.nb_dk = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); + d_osnma_data.d_dsm_kroot_message.pkid = d_dsm_reader->get_pkid(dsm_msg); + d_osnma_data.d_dsm_kroot_message.cidkr = d_dsm_reader->get_cidkr(dsm_msg); + d_osnma_data.d_dsm_kroot_message.reserved1 = d_dsm_reader->get_dsm_reserved1(dsm_msg); + d_osnma_data.d_dsm_kroot_message.hf = d_dsm_reader->get_hf(dsm_msg); + d_osnma_data.d_dsm_kroot_message.mf = d_dsm_reader->get_mf(dsm_msg); + d_osnma_data.d_dsm_kroot_message.ks = d_dsm_reader->get_ks(dsm_msg); + d_osnma_data.d_dsm_kroot_message.ts = d_dsm_reader->get_ts(dsm_msg); + d_osnma_data.d_dsm_kroot_message.maclt = d_dsm_reader->get_maclt(dsm_msg); + d_osnma_data.d_dsm_kroot_message.reserved = d_dsm_reader->get_dsm_reserved(dsm_msg); + d_osnma_data.d_dsm_kroot_message.wn_k = d_dsm_reader->get_wn_k(dsm_msg); + d_osnma_data.d_dsm_kroot_message.towh_k = d_dsm_reader->get_towh_k(dsm_msg); + d_osnma_data.d_dsm_kroot_message.alpha = d_dsm_reader->get_alpha(dsm_msg); LOG(WARNING) << "nb_dk=" << static_cast(d_osnma_data.d_dsm_kroot_message.nb_dk); LOG(WARNING) << "pkid=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid); @@ -245,12 +246,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg LOG(WARNING) << "towh_k=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k); LOG(WARNING) << "alpha=" << d_osnma_data.d_dsm_kroot_message.alpha; - uint16_t bytes_lk = get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; - d_osnma_data.d_dsm_kroot_message.kroot = get_kroot(dsm_msg, bytes_lk); - LOG(WARNING) << "lk_bits=" << static_cast(get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)); + uint16_t bytes_lk = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; + d_osnma_data.d_dsm_kroot_message.kroot = d_dsm_reader->get_kroot(dsm_msg, bytes_lk); + LOG(WARNING) << "lk_bits=" << static_cast(d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)); LOG(WARNING) << "lk_bytes=" << static_cast(bytes_lk); - std::string hash_function = get_hash_function(d_osnma_data.d_dsm_kroot_message.hf); + std::string hash_function = d_dsm_reader->get_hash_function(d_osnma_data.d_dsm_kroot_message.hf); uint16_t l_ds_bits = 0; const auto it4 = OSNMA_TABLE_15.find(hash_function); @@ -266,7 +267,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + bytes_lk + k]; } - uint16_t l_dk_bits = get_l_dk_bits(d_osnma_data.d_dsm_kroot_message.nb_dk); + uint16_t l_dk_bits = d_dsm_reader->get_l_dk_bits(d_osnma_data.d_dsm_kroot_message.nb_dk); uint16_t l_dk_bytes = l_dk_bits / 8; LOG(WARNING) << "dk_bits=" << static_cast(l_dk_bits); LOG(WARNING) << "dk_bytes=" << static_cast(l_dk_bytes); @@ -300,7 +301,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } for (uint16_t k = 0; k < l_ds_bytes; k++) { - MSG.push_back(dsm_msg[13 + bytes_lk + k]); + MSG.push_back(d_osnma_data.d_dsm_kroot_message.ds[k]); } std::vector hash = computeSHA256(MSG); @@ -334,14 +335,14 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { LOG(WARNING) << "OSNMA: DSM-PKR message received."; // DSM-PKR message - d_osnma_data.d_dsm_pkr_message.nb_dp = get_number_blocks_index(dsm_msg[0]); - d_osnma_data.d_dsm_pkr_message.mid = get_mid(dsm_msg); + d_osnma_data.d_dsm_pkr_message.nb_dp = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); + d_osnma_data.d_dsm_pkr_message.mid = d_dsm_reader->get_mid(dsm_msg); for (int k = 0; k > 128; k++) { d_osnma_data.d_dsm_pkr_message.itn[k] = dsm_msg[k + 1]; } - d_osnma_data.d_dsm_pkr_message.npkt = get_npkt(dsm_msg); - d_osnma_data.d_dsm_pkr_message.npktid = get_npktid(dsm_msg); + d_osnma_data.d_dsm_pkr_message.npkt = d_dsm_reader->get_npkt(dsm_msg); + d_osnma_data.d_dsm_pkr_message.npktid = d_dsm_reader->get_npktid(dsm_msg); uint32_t l_npk = 0; const auto it = OSNMA_TABLE_5.find(d_osnma_data.d_dsm_pkr_message.npkt); @@ -396,9 +397,8 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma_msg) { uint32_t index = 0; - for (size_t i = 0; i < osnma_msg->mack.size(); i++) + for (uint32_t value : osnma_msg->mack) { - uint32_t value = osnma_msg->mack[i]; d_mack_message[index] = static_cast((value & 0xFF000000) >> 6); d_mack_message[index + 1] = static_cast((value & 0x00FF0000) >> 4); d_mack_message[index + 2] = static_cast((value & 0x0000FF00) >> 2); @@ -453,21 +453,21 @@ std::vector osnma_msg_receiver::computeSHA256(const std::vector // for gr::block #include // for pmt::pmt_t @@ -33,6 +34,7 @@ /** \addtogroup Core_Receiver_Library * \{ */ +class OSNMA_DSM_Reader; class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; @@ -69,6 +71,8 @@ private: std::vector computeSHA256(const std::vector& input); + std::unique_ptr d_dsm_reader; + std::array, 16> d_dsm_message{}; std::array, 16> d_dsm_id_received{}; std::array d_number_of_blocks{}; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 81fd4318a..3f2e2a167 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -27,8 +27,9 @@ set(SYSTEM_PARAMETERS_SOURCES glonass_gnav_ephemeris.cc glonass_gnav_utc_model.cc glonass_gnav_navigation_message.cc - osnma_data.cc reed_solomon.cc + osnma_data.cc + osnma_dsm_reader.cc ) set(SYSTEM_PARAMETERS_HEADERS @@ -92,6 +93,7 @@ set(SYSTEM_PARAMETERS_HEADERS galileo_has_page.h Galileo_OSNMA.h osnma_data.h + osnma_dsm_reader.h ) list(SORT SYSTEM_PARAMETERS_HEADERS) diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 62df5ccb1..7d3010308 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -149,209 +149,6 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("SHA-256"), 512}, {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} -#if __cplusplus == 201103L -constexpr std::uint8_t mask_nmas{0xC0}; -constexpr std::uint8_t mask_cid{0x30}; -constexpr std::uint8_t mask_cpks{0x07}; -constexpr std::uint8_t mask_nma_header_reserved{0x01}; -constexpr std::uint8_t mask_dsm_id{0xF0}; -constexpr std::uint8_t mask_dsm_block_id{0x0F}; -constexpr std::uint8_t mask_dsm_number_blocks{0xF0}; -constexpr std::uint8_t mask_dsm_pkid{0x0F}; -constexpr std::uint8_t mask_dsm_cidkr{0xC0}; -constexpr std::uint8_t mask_dsm_reserved1{0x30}; -constexpr std::uint8_t mask_dsm_hf{0x0C}; -constexpr std::uint8_t mask_dsm_mf{0x03}; -constexpr std::uint8_t mask_dsm_ks{0xF0}; -constexpr std::uint8_t mask_dsm_ts{0x0F}; -constexpr std::uint8_t mask_dsm_reserved{0xF0}; -constexpr std::uint8_t mask_dsm_wk_k_msbyte{0x0F}; -constexpr std::uint8_t mask_dsm_mid{0x0F}; -constexpr std::uint8_t mask_dsm_npkt{0xF0}; -constexpr std::uint8_t mask_dsm_npktid{0x0F}; -#else -constexpr std::uint8_t mask_nmas{0b1100'0000}; -constexpr std::uint8_t mask_cid{0b0011'0000}; -constexpr std::uint8_t mask_cpks{0b0000'1110}; -constexpr std::uint8_t mask_nma_header_reserved{0b0000'0001}; -constexpr std::uint8_t mask_dsm_id{0b1111'0000}; -constexpr std::uint8_t mask_dsm_block_id{0b0000'1111}; -constexpr std::uint8_t mask_dsm_number_blocks{0b1111'0000}; -constexpr std::uint8_t mask_dsm_pkid{0b0000'1111}; -constexpr std::uint8_t mask_dsm_cidkr{0b1100'0000}; -constexpr std::uint8_t mask_dsm_reserved1{0b0011'0000}; -constexpr std::uint8_t mask_dsm_hf{0b0000'1100}; -constexpr std::uint8_t mask_dsm_mf{0b0000'0011}; -constexpr std::uint8_t mask_dsm_ks{0b1111'0000}; -constexpr std::uint8_t mask_dsm_ts{0b0000'1111}; -constexpr std::uint8_t mask_dsm_reserved{0b1111'0000}; -constexpr std::uint8_t mask_dsm_wk_k_msbyte{0b0000'1111}; -constexpr std::uint8_t mask_dsm_mid{0b0000'1111}; -constexpr std::uint8_t mask_dsm_npkt{0b1111'0000}; -constexpr std::uint8_t mask_dsm_npktid{0b0000'1111}; -#endif - -// // hf = (dsm_msg[1] & 0b00001100) >> 2; -uint8_t get_nmas(uint8_t nma_header) -{ - return (nma_header & mask_nmas) >> 6; -} - -uint8_t get_cid(uint8_t nma_header) -{ - return (nma_header & mask_cid) >> 4; -} - -uint8_t get_cpks(uint8_t nma_header) -{ - return (nma_header & mask_cpks) >> 1; -} - -bool get_nma_header_reserved(uint8_t nma_header) -{ - return ((nma_header & mask_nma_header_reserved) ? true : false); -} - -uint8_t get_dsm_id(uint8_t dsm_header) -{ - return (dsm_header & mask_dsm_id) >> 4; -} - -uint8_t get_dsm_block_id(uint8_t dsm_header) -{ - return dsm_header & mask_dsm_block_id; -} - -uint8_t get_number_blocks_index(uint8_t dsm_msg_0) -{ - return (dsm_msg_0 & mask_dsm_number_blocks) >> 4; -} - -uint8_t get_pkid(const std::vector& dsm_msg) -{ - return (dsm_msg[0] & mask_dsm_pkid); -} - -uint8_t get_cidkr(const std::vector& dsm_msg) -{ - return (dsm_msg[1] & mask_dsm_cidkr) >> 6; -} - -uint8_t get_dsm_reserved1(const std::vector& dsm_msg) -{ - return (dsm_msg[1] & mask_dsm_reserved1) >> 4; -} - -uint8_t get_hf(const std::vector& dsm_msg) -{ - return (dsm_msg[1] & mask_dsm_hf) >> 2; -} - -uint8_t get_mf(const std::vector& dsm_msg) -{ - return (dsm_msg[1] & mask_dsm_mf); -} - -uint8_t get_ks(const std::vector& dsm_msg) -{ - return (dsm_msg[2] & mask_dsm_ks) >> 4; -} - -uint8_t get_ts(const std::vector& dsm_msg) -{ - return (dsm_msg[2] & mask_dsm_ts); -} - -uint8_t get_maclt(const std::vector& dsm_msg) -{ - return dsm_msg[3]; -} - -uint8_t get_dsm_reserved(const std::vector& dsm_msg) -{ - return (dsm_msg[4] & mask_dsm_reserved) >> 4; -} - -uint16_t get_wn_k(const std::vector& dsm_msg) -{ - return (static_cast((dsm_msg[4] & mask_dsm_wk_k_msbyte) << 8) + static_cast(dsm_msg[5])); -} - -uint8_t get_towh_k(const std::vector& dsm_msg) -{ - return dsm_msg[6]; -} - -uint64_t get_alpha(const std::vector& dsm_msg) -{ - uint64_t alpha = (static_cast(dsm_msg[8]) << 32) + - (static_cast(dsm_msg[9]) << 24) + - (static_cast(dsm_msg[10]) << 16) + - (static_cast(dsm_msg[11]) << 8) + - static_cast(dsm_msg[12]); - return alpha; -} - -uint16_t get_l_dk_bits(uint8_t nb_dk) -{ - const auto it = OSNMA_TABLE_7.find(nb_dk); - if (it != OSNMA_TABLE_7.cend()) - { - return it->second.second; - } - return 0; -} - -uint16_t get_lk_bits(uint8_t ks) -{ - const auto it = OSNMA_TABLE_10.find(ks); - if (it != OSNMA_TABLE_10.cend()) - { - return it->second; - } - return 0; -} - -std::vector get_kroot(const std::vector& dsm_msg, uint16_t bytes_lk) -{ - std::vector kroot = std::vector(bytes_lk, 0); - if (dsm_msg.size() > static_cast(13 + bytes_lk)) - { - for (uint16_t k = 0; k < bytes_lk; k++) - { - kroot[k] = dsm_msg[13 + k]; - } - } - return kroot; -} - -std::string get_hash_function(uint8_t hf) -{ - std::string hash_; - const auto it = OSNMA_TABLE_8.find(hf); - if (it != OSNMA_TABLE_8.cend()) - { - hash_ = it->second; - } - return hash_; -} - -uint8_t get_mid(const std::vector& dsm_msg) -{ - return (dsm_msg[0] & mask_dsm_mid); -} - -uint8_t get_npkt(const std::vector& dsm_msg) -{ - return ((dsm_msg[129] & mask_dsm_npkt) >> 4); -} - -uint8_t get_npktid(const std::vector& dsm_msg) -{ - return (dsm_msg[129] & mask_dsm_npktid); -} - - /** \} */ /** \} */ #endif // GNSS_SDR_GALILEO_OSNMA_H \ No newline at end of file diff --git a/src/core/system_parameters/osnma_dsm_reader.cc b/src/core/system_parameters/osnma_dsm_reader.cc new file mode 100644 index 000000000..baf873bbb --- /dev/null +++ b/src/core/system_parameters/osnma_dsm_reader.cc @@ -0,0 +1,204 @@ +/*! + * \file osnma_dsm_reader.cc + * \brief Class for reading OSNMA DSM messages + * \author Carles Fernandez-Prades, 2023 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "osnma_dsm_reader.h" +#include "Galileo_OSNMA.h" + + +uint8_t OSNMA_DSM_Reader::get_nmas(uint8_t nma_header) const +{ + return (nma_header & mask_nmas) >> 6; +} + + +uint8_t OSNMA_DSM_Reader::get_cid(uint8_t nma_header) const +{ + return (nma_header & mask_cid) >> 4; +} + + +uint8_t OSNMA_DSM_Reader::get_cpks(uint8_t nma_header) const +{ + return (nma_header & mask_cpks) >> 1; +} + + +bool OSNMA_DSM_Reader::get_nma_header_reserved(uint8_t nma_header) const +{ + return ((nma_header & mask_nma_header_reserved) ? true : false); +} + + +uint8_t OSNMA_DSM_Reader::get_dsm_id(uint8_t dsm_header) const +{ + return (dsm_header & mask_dsm_id) >> 4; +} + + +uint8_t OSNMA_DSM_Reader::get_dsm_block_id(uint8_t dsm_header) const +{ + return dsm_header & mask_dsm_block_id; +} + + +uint8_t OSNMA_DSM_Reader::get_number_blocks_index(uint8_t dsm_msg_0) const +{ + return (dsm_msg_0 & mask_dsm_number_blocks) >> 4; +} + + +uint8_t OSNMA_DSM_Reader::get_pkid(const std::vector& dsm_msg) const +{ + return (dsm_msg[0] & mask_dsm_pkid); +} + + +uint8_t OSNMA_DSM_Reader::get_cidkr(const std::vector& dsm_msg) const +{ + return (dsm_msg[1] & mask_dsm_cidkr) >> 6; +} + + +uint8_t OSNMA_DSM_Reader::get_dsm_reserved1(const std::vector& dsm_msg) const +{ + return (dsm_msg[1] & mask_dsm_reserved1) >> 4; +} + + +uint8_t OSNMA_DSM_Reader::get_hf(const std::vector& dsm_msg) const +{ + return (dsm_msg[1] & mask_dsm_hf) >> 2; +} + + +uint8_t OSNMA_DSM_Reader::get_mf(const std::vector& dsm_msg) const +{ + return (dsm_msg[1] & mask_dsm_mf); +} + + +uint8_t OSNMA_DSM_Reader::get_ks(const std::vector& dsm_msg) const +{ + return (dsm_msg[2] & mask_dsm_ks) >> 4; +} + + +uint8_t OSNMA_DSM_Reader::get_ts(const std::vector& dsm_msg) const +{ + return (dsm_msg[2] & mask_dsm_ts); +} + + +uint8_t OSNMA_DSM_Reader::get_maclt(const std::vector& dsm_msg) const +{ + return dsm_msg[3]; +} + + +uint8_t OSNMA_DSM_Reader::get_dsm_reserved(const std::vector& dsm_msg) const +{ + return (dsm_msg[4] & mask_dsm_reserved) >> 4; +} + + +uint16_t OSNMA_DSM_Reader::get_wn_k(const std::vector& dsm_msg) const +{ + return (static_cast((dsm_msg[4] & mask_dsm_wk_k_msbyte) << 8) + static_cast(dsm_msg[5])); +} + + +uint8_t OSNMA_DSM_Reader::get_towh_k(const std::vector& dsm_msg) const +{ + return dsm_msg[6]; +} + + +uint64_t OSNMA_DSM_Reader::get_alpha(const std::vector& dsm_msg) const +{ + uint64_t alpha = (static_cast(dsm_msg[8]) << 40) + + (static_cast(dsm_msg[9]) << 32) + + (static_cast(dsm_msg[10]) << 24) + + (static_cast(dsm_msg[11]) << 16) + + (static_cast(dsm_msg[12]) << 8) + + (static_cast(dsm_msg[13])); + return alpha; +} + + +uint16_t OSNMA_DSM_Reader::get_l_dk_bits(uint8_t nb_dk) const +{ + const auto it = OSNMA_TABLE_7.find(nb_dk); + if (it != OSNMA_TABLE_7.cend()) + { + return it->second.second; + } + return 0; +} + + +uint16_t OSNMA_DSM_Reader::get_lk_bits(uint8_t ks) const +{ + const auto it = OSNMA_TABLE_10.find(ks); + if (it != OSNMA_TABLE_10.cend()) + { + return it->second; + } + return 0; +} + + +std::vector OSNMA_DSM_Reader::get_kroot(const std::vector& dsm_msg, uint16_t bytes_lk) const +{ + std::vector kroot = std::vector(bytes_lk, 0); + if (dsm_msg.size() > static_cast(13 + bytes_lk)) + { + for (uint16_t k = 0; k < bytes_lk; k++) + { + kroot[k] = dsm_msg[13 + k]; + } + } + return kroot; +} + + +std::string OSNMA_DSM_Reader::get_hash_function(uint8_t hf) const +{ + std::string hash_; + const auto it = OSNMA_TABLE_8.find(hf); + if (it != OSNMA_TABLE_8.cend()) + { + hash_ = it->second; + } + return hash_; +} + + +uint8_t OSNMA_DSM_Reader::get_mid(const std::vector& dsm_msg) const +{ + return (dsm_msg[0] & mask_dsm_mid); +} + + +uint8_t OSNMA_DSM_Reader::get_npkt(const std::vector& dsm_msg) const +{ + return ((dsm_msg[129] & mask_dsm_npkt) >> 4); +} + + +uint8_t OSNMA_DSM_Reader::get_npktid(const std::vector& dsm_msg) const +{ + return (dsm_msg[129] & mask_dsm_npktid); +} diff --git a/src/core/system_parameters/osnma_dsm_reader.h b/src/core/system_parameters/osnma_dsm_reader.h new file mode 100644 index 000000000..f90bd531b --- /dev/null +++ b/src/core/system_parameters/osnma_dsm_reader.h @@ -0,0 +1,109 @@ +/*! + * \file osnma_dsm_reader.h + * \brief Class for reading OSNMA DSM messages + * \author Carles Fernandez-Prades, 2023 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_OSNMA_DSM_READER_H +#define GNSS_SDR_OSNMA_DSM_READER_H + +#include +#include +#include + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + +class OSNMA_DSM_Reader +{ +public: + OSNMA_DSM_Reader() = default; + uint8_t get_nmas(uint8_t nma_header) const; + uint8_t get_cid(uint8_t nma_header) const; + uint8_t get_cpks(uint8_t nma_header) const; + bool get_nma_header_reserved(uint8_t nma_header) const; + + uint8_t get_dsm_id(uint8_t dsm_header) const; + uint8_t get_dsm_block_id(uint8_t dsm_header) const; + + uint8_t get_number_blocks_index(uint8_t dsm_msg_0) const; + uint8_t get_pkid(const std::vector& dsm_msg) const; + uint8_t get_cidkr(const std::vector& dsm_msg) const; + uint8_t get_dsm_reserved1(const std::vector& dsm_msg) const; + uint8_t get_hf(const std::vector& dsm_msg) const; + uint8_t get_mf(const std::vector& dsm_msg) const; + uint8_t get_ks(const std::vector& dsm_msg) const; + uint8_t get_ts(const std::vector& dsm_msg) const; + uint8_t get_maclt(const std::vector& dsm_msg) const; + uint8_t get_dsm_reserved(const std::vector& dsm_msg) const; + uint16_t get_wn_k(const std::vector& dsm_msg) const; + uint8_t get_towh_k(const std::vector& dsm_msg) const; + uint64_t get_alpha(const std::vector& dsm_msg) const; + uint16_t get_l_dk_bits(uint8_t nb_dk) const; + uint16_t get_lk_bits(uint8_t ks) const; + std::vector get_kroot(const std::vector& dsm_msg, uint16_t bytes_lk) const; + std::string get_hash_function(uint8_t hf) const; + + uint8_t get_mid(const std::vector& dsm_msg) const; + uint8_t get_npkt(const std::vector& dsm_msg) const; + uint8_t get_npktid(const std::vector& dsm_msg) const; + +private: +#if __cplusplus == 201103L + static constexpr std::uint8_t mask_nmas{0xC0}; + static constexpr std::uint8_t mask_cid{0x30}; + static constexpr std::uint8_t mask_cpks{0x07}; + static constexpr std::uint8_t mask_nma_header_reserved{0x01}; + static constexpr std::uint8_t mask_dsm_id{0xF0}; + static constexpr std::uint8_t mask_dsm_block_id{0x0F}; + static constexpr std::uint8_t mask_dsm_number_blocks{0xF0}; + static constexpr std::uint8_t mask_dsm_pkid{0x0F}; + static constexpr std::uint8_t mask_dsm_cidkr{0xC0}; + static constexpr std::uint8_t mask_dsm_reserved1{0x30}; + static constexpr std::uint8_t mask_dsm_hf{0x0C}; + static constexpr std::uint8_t mask_dsm_mf{0x03}; + static constexpr std::uint8_t mask_dsm_ks{0xF0}; + static constexpr std::uint8_t mask_dsm_ts{0x0F}; + static constexpr std::uint8_t mask_dsm_reserved{0xF0}; + static constexpr std::uint8_t mask_dsm_wk_k_msbyte{0x0F}; + static constexpr std::uint8_t mask_dsm_mid{0x0F}; + static constexpr std::uint8_t mask_dsm_npkt{0xF0}; + static constexpr std::uint8_t mask_dsm_npktid{0x0F}; +#else + static constexpr std::uint8_t mask_nmas{0b1100'0000}; + static constexpr std::uint8_t mask_cid{0b0011'0000}; + static constexpr std::uint8_t mask_cpks{0b0000'1110}; + static constexpr std::uint8_t mask_nma_header_reserved{0b0000'0001}; + static constexpr std::uint8_t mask_dsm_id{0b1111'0000}; + static constexpr std::uint8_t mask_dsm_block_id{0b0000'1111}; + static constexpr std::uint8_t mask_dsm_number_blocks{0b1111'0000}; + static constexpr std::uint8_t mask_dsm_pkid{0b0000'1111}; + static constexpr std::uint8_t mask_dsm_cidkr{0b1100'0000}; + static constexpr std::uint8_t mask_dsm_reserved1{0b0011'0000}; + static constexpr std::uint8_t mask_dsm_hf{0b0000'1100}; + static constexpr std::uint8_t mask_dsm_mf{0b0000'0011}; + static constexpr std::uint8_t mask_dsm_ks{0b1111'0000}; + static constexpr std::uint8_t mask_dsm_ts{0b0000'1111}; + static constexpr std::uint8_t mask_dsm_reserved{0b1111'0000}; + static constexpr std::uint8_t mask_dsm_wk_k_msbyte{0b0000'1111}; + static constexpr std::uint8_t mask_dsm_mid{0b0000'1111}; + static constexpr std::uint8_t mask_dsm_npkt{0b1111'0000}; + static constexpr std::uint8_t mask_dsm_npktid{0b0000'1111}; +#endif +}; + +/** \} */ +/** \} */ +#endif // GNSS_SDR_OSNMA_DSM_READER_H \ No newline at end of file From f20f4ede0c4c3482e0f38beec79e6ac48e9a64bc Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 3 Jun 2023 12:45:20 +0200 Subject: [PATCH 030/219] Use classes instead of structs --- src/core/system_parameters/osnma_data.h | 82 +++++++++++++++---------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index aa4eaf21f..9c97c1186 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -28,73 +28,91 @@ /** \addtogroup System_Parameters * \{ */ -struct nma_header +class DSM_nma_header { +public: + DSM_nma_header() = default; uint8_t nmas; uint8_t cid; uint8_t cpks; bool reserved; }; -struct dsm_header +class DSM_dsm_header { +public: + DSM_dsm_header() = default; uint8_t dsm_id; uint8_t dsm_block_id; }; -struct mack_header +class MACK_header { +public: + MACK_header() = default; std::vector tag0; - uint16_t macsec; - uint8_t cop; + uint16_t macsec{}; + uint8_t cop{}; }; -struct tag +class MACK_tag { +public: + MACK_tag() = default; std::vector tag; uint16_t tag_info; }; -struct tag_and_info +class MACK_tag_and_info { - std::vector tags; +public: + MACK_tag_and_info() = default; + std::vector tags; }; -struct DSM_PKR_message +class DSM_PKR_message { - uint8_t nb_dp; - uint8_t mid; +public: + DSM_PKR_message() = default; + std::array itn; // bitset<1024> - uint8_t npkt; - uint8_t npktid; std::vector npk; std::vector p_dp; + uint8_t nb_dp; + uint8_t mid; + uint8_t npkt; + uint8_t npktid; }; -struct DSM_KROOT_message +class DSM_KROOT_message { - uint8_t nb_dk; - uint8_t pkid; - uint8_t cidkr; - uint8_t reserved1; - uint8_t hf; - uint8_t mf; - uint8_t ks; - uint8_t ts; - uint8_t maclt; - uint8_t reserved; - uint16_t wn_k; - uint8_t towh_k; - uint64_t alpha; +public: + DSM_KROOT_message() = default; + std::vector kroot; std::vector ds; std::vector p_dk; + uint64_t alpha{}; + uint16_t wn_k{}; + uint8_t nb_dk{}; + uint8_t pkid{}; + uint8_t cidkr{}; + uint8_t reserved1{}; + uint8_t hf{}; + uint8_t mf{}; + uint8_t ks{}; + uint8_t ts{}; + uint8_t maclt{}; + uint8_t reserved{}; + uint8_t towh_k{}; }; -struct MACK_message +class MACK_message { - mack_header header; - tag_and_info tag_info; +public: + MACK_message() = default; + MACK_header header; + MACK_tag_and_info tag_info; std::vector key; std::vector padding; }; @@ -107,8 +125,8 @@ class OSNMA_data { public: OSNMA_data() = default; - nma_header d_nma_header; - dsm_header d_dsm_header; + DSM_nma_header d_nma_header; + DSM_dsm_header d_dsm_header; DSM_PKR_message d_dsm_pkr_message; DSM_KROOT_message d_dsm_kroot_message; }; From c3b36c380a4d344a37cdadfe4214e73f142182ef Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 3 Jun 2023 14:13:31 +0200 Subject: [PATCH 031/219] Fix wrong memory access --- src/core/libs/osnma_msg_receiver.cc | 8 ++++---- src/core/system_parameters/Galileo_OSNMA.h | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 41ab86aac..78a9135a7 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -152,7 +152,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ size_t index = 0; for (const auto* it = osnma_msg->hkroot.cbegin() + 2; it != osnma_msg->hkroot.cend(); ++it) { - d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][13 * d_osnma_data.d_dsm_header.dsm_block_id + index] = *it; + d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][SIZE_DSM_BLOCKS_BYTES * d_osnma_data.d_dsm_header.dsm_block_id + index] = *it; index++; } @@ -197,12 +197,12 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cbegin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cend(), 0))) { - std::vector dsm_msg(std::size_t(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) * 13, 0); + std::vector dsm_msg(std::size_t(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) * SIZE_DSM_BLOCKS_BYTES, 0); for (uint32_t i = 0; i < d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]; i++) { - for (uint32_t j = 0; j < 14; j++) + for (size_t j = 0; j < SIZE_DSM_BLOCKS_BYTES; j++) { - dsm_msg[i * 13 + j] = d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][i * 13 + j]; + dsm_msg[i * SIZE_DSM_BLOCKS_BYTES + j] = d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][i * SIZE_DSM_BLOCKS_BYTES + j]; } } d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 7d3010308..bb3781c3f 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -18,6 +18,7 @@ #ifndef GNSS_SDR_GALILEO_OSNMA_H #define GNSS_SDR_GALILEO_OSNMA_H +#include #include #include #include @@ -29,6 +30,8 @@ /** \addtogroup System_Parameters * \{ */ +constexpr size_t SIZE_DSM_BLOCKS_BYTES = 13; + // OSNMA User ICD for the Test Phase, Issue 1.0, Table 2 const std::unordered_map OSNMA_TABLE_2 = { {0, std::string("Reserved")}, From 66e58de3825e80ffa2cf5887a8a2568eed948371 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 6 Jun 2023 16:22:36 +0200 Subject: [PATCH 032/219] Read DSM-KROOT messages --- src/core/libs/osnma_msg_receiver.cc | 138 ++++++++++++++++------------ src/core/libs/osnma_msg_receiver.h | 1 + 2 files changed, 78 insertions(+), 61 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 78a9135a7..0c3cdd62f 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -155,7 +155,12 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][SIZE_DSM_BLOCKS_BYTES * d_osnma_data.d_dsm_header.dsm_block_id + index] = *it; index++; } - + std::cout << "dsm_message:"; + for (auto c : d_dsm_message[d_osnma_data.d_dsm_header.dsm_id]) + { + std::cout << " " << static_cast(c); + } + std::cout << std::endl; if (d_osnma_data.d_dsm_header.dsm_block_id == 0) { // Get number of blocks in message @@ -232,56 +237,32 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_kroot_message.towh_k = d_dsm_reader->get_towh_k(dsm_msg); d_osnma_data.d_dsm_kroot_message.alpha = d_dsm_reader->get_alpha(dsm_msg); - LOG(WARNING) << "nb_dk=" << static_cast(d_osnma_data.d_dsm_kroot_message.nb_dk); - LOG(WARNING) << "pkid=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid); - LOG(WARNING) << "cidkr=" << static_cast(d_osnma_data.d_dsm_kroot_message.cidkr); - LOG(WARNING) << "reserved1=" << static_cast(d_osnma_data.d_dsm_kroot_message.reserved1); - LOG(WARNING) << "hf=" << static_cast(d_osnma_data.d_dsm_kroot_message.hf); - LOG(WARNING) << "mf=" << static_cast(d_osnma_data.d_dsm_kroot_message.mf); - LOG(WARNING) << "ks=" << static_cast(d_osnma_data.d_dsm_kroot_message.ks); - LOG(WARNING) << "ts=" << static_cast(d_osnma_data.d_dsm_kroot_message.ts); - LOG(WARNING) << "maclt=" << static_cast(d_osnma_data.d_dsm_kroot_message.maclt); - LOG(WARNING) << "reserved=" << static_cast(d_osnma_data.d_dsm_kroot_message.reserved); - LOG(WARNING) << "wn_k=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k); - LOG(WARNING) << "towh_k=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k); - LOG(WARNING) << "alpha=" << d_osnma_data.d_dsm_kroot_message.alpha; - - uint16_t bytes_lk = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; - d_osnma_data.d_dsm_kroot_message.kroot = d_dsm_reader->get_kroot(dsm_msg, bytes_lk); - LOG(WARNING) << "lk_bits=" << static_cast(d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)); - LOG(WARNING) << "lk_bytes=" << static_cast(bytes_lk); + const uint16_t l_lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; + d_osnma_data.d_dsm_kroot_message.kroot = d_dsm_reader->get_kroot(dsm_msg, l_lk_bytes); std::string hash_function = d_dsm_reader->get_hash_function(d_osnma_data.d_dsm_kroot_message.hf); - uint16_t l_ds_bits = 0; const auto it4 = OSNMA_TABLE_15.find(hash_function); if (it4 != OSNMA_TABLE_15.cend()) { l_ds_bits = it4->second; } - uint16_t l_ds_bytes = l_ds_bits / 8; - LOG(WARNING) << "ds_bits=" << static_cast(l_ds_bits); - LOG(WARNING) << "ds_bytes=" << static_cast(l_ds_bytes); + const uint16_t l_ds_bytes = l_ds_bits / 8; d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); for (uint16_t k = 0; k < l_ds_bytes; k++) { - d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + bytes_lk + k]; + d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + l_lk_bytes + k]; } - uint16_t l_dk_bits = d_dsm_reader->get_l_dk_bits(d_osnma_data.d_dsm_kroot_message.nb_dk); - uint16_t l_dk_bytes = l_dk_bits / 8; - LOG(WARNING) << "dk_bits=" << static_cast(l_dk_bits); - LOG(WARNING) << "dk_bytes=" << static_cast(l_dk_bytes); - - uint16_t l_pdk_bytes = (l_dk_bytes - 13 - bytes_lk - l_ds_bytes); - LOG(WARNING) << "pdk_bytes=" << static_cast(l_pdk_bytes); + const uint16_t l_dk_bits = d_dsm_reader->get_l_dk_bits(d_osnma_data.d_dsm_kroot_message.nb_dk); + const uint16_t l_dk_bytes = l_dk_bits / 8; + const uint16_t l_pdk_bytes = (l_dk_bytes - 13 - l_lk_bytes - l_ds_bytes); d_osnma_data.d_dsm_kroot_message.p_dk = std::vector(l_pdk_bytes, 0); for (uint16_t k = 0; k < l_pdk_bytes; k++) { - d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + bytes_lk + l_ds_bytes + k]; + d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + l_lk_bytes + l_ds_bytes + k]; } - uint16_t check_l_dk = 104 * std::ceil(1.0 + static_cast((bytes_lk * 8.0) + l_ds_bits) / 104.0); - LOG(WARNING) << "check_l_dk_bits=" << static_cast(check_l_dk); + const uint16_t check_l_dk = 104 * std::ceil(1.0 + static_cast((l_lk_bytes * 8.0) + l_ds_bits) / 104.0); if (l_dk_bits != check_l_dk) { std::cout << "OSNMA: Failed length reading" << std::endl; @@ -289,43 +270,44 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg else { // validation of padding + const uint16_t size_m = 13 + l_lk_bytes; std::vector MSG; + MSG.reserve(size_m + l_ds_bytes + 1); MSG.push_back(nma_header); - for (int i = 1; i < 13; i++) + for (uint16_t i = 1; i < size_m; i++) { MSG.push_back(dsm_msg[i]); } - for (uint16_t i = 0; i < bytes_lk; i++) - { - MSG.push_back(dsm_msg[13 + i]); - } + for (uint16_t k = 0; k < l_ds_bytes; k++) { MSG.push_back(d_osnma_data.d_dsm_kroot_message.ds[k]); } - std::vector hash = computeSHA256(MSG); - std::cout << "hash: "; - for (auto c : hash) + std::vector hash; + if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. { - std::cout << static_cast(c); + hash = computeSHA256(MSG); } - std::cout << std::endl; - - std::cout << "pdk: "; - for (auto c : d_osnma_data.d_dsm_kroot_message.p_dk) + else if (d_osnma_data.d_dsm_kroot_message.hf == 2) { - std::cout << static_cast(c); + hash = computeSHA3_256(MSG); + } + else + { + hash = std::vector(32); } - std::cout << std::endl; // truncate hash - std::vector p_dk_computed; + std::vector p_dk_truncated; + p_dk_truncated.reserve(l_pdk_bytes); for (uint16_t i = 0; i < l_pdk_bytes; i++) { - p_dk_computed.push_back(hash[i]); + p_dk_truncated.push_back(hash[i]); } - if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_computed) + // check DS signature + if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { + LOG(WARNING) << "OSNMA: DSM-KROOT message received ok."; std::cout << "OSNMA: DSM-KROOT message validated" << std::endl; } // Validate signature @@ -354,11 +336,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg l_npk = it2->second / 8; } } - + uint32_t l_dp = dsm_msg.size(); if (d_osnma_data.d_dsm_pkr_message.npkt == 4) { LOG(WARNING) << "OSNMA: OAM received"; - l_npk = 0; // ? + l_npk = l_dp - 130; // bytes } d_osnma_data.d_dsm_pkr_message.npk = std::vector(l_npk, 0); // ECDSA Public Key @@ -366,11 +348,9 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_osnma_data.d_dsm_pkr_message.npk[k] = dsm_msg[k + 130]; } - uint32_t l_dp = dsm_msg.size(); + uint32_t l_pd = l_dp - 130 - l_npk; - uint32_t check_l_dp = 104 * std::ceil(static_cast(1040.0 + l_npk * 8.0) / 104.0); - if (l_dp != check_l_dp) { std::cout << "OSNMA: Failed length reading" << std::endl; @@ -478,23 +458,59 @@ std::vector osnma_msg_receiver::computeSHA256(const std::vector output_aux(32); gnutls_hash_hd_t hashHandle; gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); gnutls_hash(hashHandle, input.data(), input.size()); - gnutls_hash_output(hashHandle, output.data()); - gnutls_hash_deinit(hashHandle, output.data()); + gnutls_hash_output(hashHandle, output_aux.data()); + output = output_aux; + gnutls_hash_deinit(hashHandle, output_aux.data()); #endif return output; } -// bool signature(const std::vector& publicKey, const std::vector& digest, const std::vector& signature) + +std::vector osnma_msg_receiver::computeSHA3_256(const std::vector& input) +{ + std::vector output(32); // SHA256 hash size +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); + const EVP_MD* md = EVP_sha3_256(); + + EVP_DigestInit_ex(mdctx, md, NULL); + EVP_DigestUpdate(mdctx, input.data(), input.size()); + EVP_DigestFinal_ex(mdctx, output.data(), NULL); + EVP_MD_CTX_free(mdctx); +#else + // SHA3-256 not implemented in OpenSSL < 3.0 +#endif +#else + std::vector output_aux(32); + gnutls_hash_hd_t hashHandle; + gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); + gnutls_hash(hashHandle, input.data(), input.size()); + gnutls_hash_output(hashHandle, output_aux.data()); + output = output_aux; + gnutls_hash_deinit(hashHandle, output_aux.data()); +#endif + return output; +} + + +// bool signature(const std::vector& publicKey, const std::vector& digest, std::vector& signature) // { // bool success = false; // #if USE_OPENSSL_FALLBACK // #else // gnutls_global_init(); -// int result = gnutls_pubkey_verify_data(publicKey, GNUTLS_SIGN_ECDSA_SHA256, digest, sizeof(digest), signature, signatureSize); +// int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data, digest.size(), signature.data(), signature.size()); // success = (result == GNUTLS_E_SUCCESS); +// gnutls_global_deinit(); // #endif // return success; // } +// bool verifyDigitalSignature(const unsigned char* signature, size_t signatureSize, const unsigned char* message, size_t messageSize, gnutls_pubkey_t publicKey) +// { +// int verificationStatus = gnutls_pubkey_verify_data(publicKey, GNUTLS_DIG_SHA256, 0, message, messageSize, signature, signatureSize); +// return verificationStatus == 0; \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 9ec3370c4..beb33f50b 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -70,6 +70,7 @@ private: void read_mack_padding(); std::vector computeSHA256(const std::vector& input); + std::vector computeSHA3_256(const std::vector& input); std::unique_ptr d_dsm_reader; From 6d69b9db552a6f54a729c90b5b9d64a528072564 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 00:24:54 +0200 Subject: [PATCH 033/219] Add work on the OSNMA receiver --- src/core/libs/osnma_msg_receiver.cc | 97 ++++++++++++++++++++++--- src/core/system_parameters/osnma_data.h | 39 +++++----- 2 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 0c3cdd62f..9c36a3ac4 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -242,10 +242,10 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg std::string hash_function = d_dsm_reader->get_hash_function(d_osnma_data.d_dsm_kroot_message.hf); uint16_t l_ds_bits = 0; - const auto it4 = OSNMA_TABLE_15.find(hash_function); - if (it4 != OSNMA_TABLE_15.cend()) + const auto it = OSNMA_TABLE_15.find(hash_function); + if (it != OSNMA_TABLE_15.cend()) { - l_ds_bits = it4->second; + l_ds_bits = it->second; } const uint16_t l_ds_bytes = l_ds_bits / 8; d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); @@ -362,6 +362,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; } + // std::vector mi; // (NPKT + NPKID + NPK) } } else @@ -385,10 +386,13 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma d_mack_message[index + 3] = static_cast(value & 0x000000FF); index = index + 4; } - read_mack_header(); - read_mack_info_and_tags(); - read_mack_key(); - read_mack_padding(); + if (d_osnma_data.d_dsm_kroot_message.ts != 0) + { + read_mack_header(); + read_mack_info_and_tags(); + read_mack_key(); + read_mack_padding(); + } } @@ -404,11 +408,86 @@ void osnma_msg_receiver::read_mack_header() { return; } + uint16_t macseq = 0; + uint8_t cop = 0; + uint64_t first_lt_bits = static_cast(d_mack_message[0]) << (lt_bits - 8); + first_lt_bits += (static_cast(d_mack_message[1]) << (lt_bits - 16)); + if (lt_bits == 20) + { + first_lt_bits += (static_cast(d_mack_message[1] & 0xF0) >> 4); + macseq += (static_cast(d_mack_message[1] & 0x0F) << 8); + macseq += static_cast(d_mack_message[2]); + cop += ((d_mack_message[3] & 0xF0) >> 4); + } + else if (lt_bits == 24) + { + first_lt_bits += static_cast(d_mack_message[2]); + macseq += (static_cast(d_mack_message[3]) << 8); + macseq += (static_cast(d_mack_message[4] & 0xF0) >> 4); + cop += (d_mack_message[4] & 0x0F); + } + else if (lt_bits == 28) + { + first_lt_bits += (static_cast(d_mack_message[2]) << 4); + first_lt_bits += (static_cast(d_mack_message[3] & 0xF0) >> 4); + macseq += (static_cast(d_mack_message[3] & 0x0F) << 8); + macseq += (static_cast(d_mack_message[4])); + cop += ((d_mack_message[5] & 0xF0) >> 4); + } + else if (lt_bits == 32) + { + first_lt_bits += (static_cast(d_mack_message[2]) << 8); + first_lt_bits += static_cast(d_mack_message[3]); + macseq += (static_cast(d_mack_message[4]) << 8); + macseq += (static_cast(d_mack_message[5] & 0xF0) >> 4); + cop += (d_mack_message[5] & 0x0F); + } + else if (lt_bits == 40) + { + first_lt_bits += (static_cast(d_mack_message[2]) << 16); + first_lt_bits += (static_cast(d_mack_message[3]) << 8); + first_lt_bits += static_cast(d_mack_message[4]); + macseq += (static_cast(d_mack_message[5]) << 8); + macseq += (static_cast(d_mack_message[6] & 0xF0) >> 4); + cop += (d_mack_message[6] & 0x0F); + } + d_osnma_data.d_mack_message.header.tag0 = first_lt_bits; + d_osnma_data.d_mack_message.header.macseq = macseq; + d_osnma_data.d_mack_message.header.macseq = cop; } void osnma_msg_receiver::read_mack_info_and_tags() { + uint8_t lt_bits = 0; + const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); + if (it != OSNMA_TABLE_11.cend()) + { + lt_bits = it->second; + } + if (lt_bits == 0) + { + return; + } + uint16_t lk_bits = 0; + const auto it2 = OSNMA_TABLE_10.find(d_osnma_data.d_dsm_kroot_message.ks); + if (it2 != OSNMA_TABLE_10.cend()) + { + lk_bits = it2->second; + } + if (lk_bits == 0) + { + return; + } + uint16_t nt = std::floor((480.0 + float(lk_bits)) / (float(lt_bits) + 16.0)); + d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); + for (uint16_t k = 0; k < (nt - 1); k++) + { + d_osnma_data.d_mack_message.tag_and_info[k].tag = 0; + d_osnma_data.d_mack_message.tag_and_info[k].tag_info.PRN_d = 0; + d_osnma_data.d_mack_message.tag_and_info[k].tag_info.ADKD = 0; + d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = 0; + } } @@ -478,9 +557,9 @@ std::vector osnma_msg_receiver::computeSHA3_256(const std::vector tag0; - uint16_t macsec{}; + uint64_t tag0{}; + uint16_t macseq{}; uint8_t cop{}; }; -class MACK_tag +class MACK_tag_info { public: - MACK_tag() = default; - std::vector tag; - uint16_t tag_info; + MACK_tag_info() = default; + uint8_t PRN_d{}; + uint8_t ADKD{}; + uint8_t cop{}; }; class MACK_tag_and_info { public: MACK_tag_and_info() = default; - std::vector tags; + uint64_t tag; + MACK_tag_info tag_info; }; class DSM_PKR_message @@ -78,10 +80,10 @@ public: std::array itn; // bitset<1024> std::vector npk; std::vector p_dp; - uint8_t nb_dp; - uint8_t mid; - uint8_t npkt; - uint8_t npktid; + uint8_t nb_dp{}; + uint8_t mid{}; + uint8_t npkt{}; + uint8_t npktid{}; }; class DSM_KROOT_message @@ -112,7 +114,7 @@ class MACK_message public: MACK_message() = default; MACK_header header; - MACK_tag_and_info tag_info; + std::vector tag_and_info; std::vector key; std::vector padding; }; @@ -129,6 +131,7 @@ public: DSM_dsm_header d_dsm_header; DSM_PKR_message d_dsm_pkr_message; DSM_KROOT_message d_dsm_kroot_message; + MACK_message d_mack_message; }; From dafb322018a2584c1a4ca2305389e0e982d633d5 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 02:43:34 +0200 Subject: [PATCH 034/219] Read MACK tag and info --- src/core/libs/osnma_msg_receiver.cc | 90 +++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 9c36a3ac4..d62214848 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -483,10 +483,92 @@ void osnma_msg_receiver::read_mack_info_and_tags() d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); for (uint16_t k = 0; k < (nt - 1); k++) { - d_osnma_data.d_mack_message.tag_and_info[k].tag = 0; - d_osnma_data.d_mack_message.tag_and_info[k].tag_info.PRN_d = 0; - d_osnma_data.d_mack_message.tag_and_info[k].tag_info.ADKD = 0; - d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = 0; + uint64_t tag = 0; + uint8_t PRN_d = 0; + uint8_t ADKD = 0; + uint8_t cop = 0; + if (lt_bits == 20) + { + const uint16_t step = std::ceil(4.5 * k); + if (k % 2 == 0) + { + tag += (static_cast((d_mack_message[3 + step] & 0x0F)) << 16); + tag += (static_cast(d_mack_message[4 + step]) << 8); + tag += static_cast(d_mack_message[5 + step]); + PRN_d += d_mack_message[6 + step]; + ADKD += ((d_mack_message[7 + step] & 0xF0) >> 4); + cop += (d_mack_message[7 + step] & 0x0F); + } + else + { + tag += (static_cast(d_mack_message[3 + step]) << 12); + tag += (static_cast(d_mack_message[4 + step]) << 4); + tag += (static_cast((d_mack_message[5 + step] & 0xF0)) >> 4); + PRN_d += (d_mack_message[5 + step] & 0x0F) << 4; + PRN_d += (d_mack_message[6 + step] & 0xF0) >> 4; + ADKD += (d_mack_message[6 + step] & 0x0F); + cop += (d_mack_message[7 + step] & 0xF0) >> 4; + } + } + else if (lt_bits == 24) + { + tag += (static_cast((d_mack_message[5 + k * 5])) << 16); + tag += (static_cast((d_mack_message[6 + k * 5])) << 8); + tag += static_cast(d_mack_message[7 + k * 5]); + PRN_d += d_mack_message[8 + k * 5]; + ADKD += ((d_mack_message[9 + k * 5] & 0xF0) >> 4); + cop += (d_mack_message[9 + k * 5] & 0x0F); + } + else if (lt_bits == 28) + { + const uint16_t step = std::ceil(5.5 * k); + if (k % 2 == 0) + { + tag += (static_cast((d_mack_message[5 + step] & 0x0F)) << 24); + tag += (static_cast(d_mack_message[6 + step]) << 16); + tag += (static_cast(d_mack_message[7 + step]) << 8); + tag += static_cast(d_mack_message[8 + step]); + PRN_d += d_mack_message[9 + step]; + ADKD += ((d_mack_message[10 + step] & 0xF0) >> 4); + cop += (d_mack_message[10 + step] & 0x0F); + } + else + { + tag += (static_cast((d_mack_message[5 + step])) << 20); + tag += (static_cast((d_mack_message[6 + step])) << 12); + tag += (static_cast((d_mack_message[7 + step])) << 4); + tag += (static_cast((d_mack_message[8 + step] & 0xF0)) >> 4); + PRN_d += ((d_mack_message[8 + step] & 0x0F) << 4); + PRN_d += ((d_mack_message[9 + step] & 0xF0) >> 4); + ADKD += (d_mack_message[9 + step] & 0x0F); + cop += ((d_mack_message[10 + step] & 0xF0) >> 4); + } + } + else if (lt_bits == 32) + { + tag += (static_cast((d_mack_message[6 + k * 6])) << 24); + tag += (static_cast((d_mack_message[7 + k * 6])) << 16); + tag += (static_cast((d_mack_message[8 + k * 6])) << 8); + tag += static_cast(d_mack_message[9 + k * 6]); + PRN_d += d_mack_message[10 + k * 6]; + ADKD += ((d_mack_message[11 + k * 6] & 0xF0) >> 4); + cop += (d_mack_message[11 + k * 6] & 0x0F); + } + else if (lt_bits == 40) + { + tag += (static_cast((d_mack_message[7 + k * 7])) << 32); + tag += (static_cast((d_mack_message[8 + k * 7])) << 24); + tag += (static_cast((d_mack_message[9 + k * 7])) << 16); + tag += (static_cast((d_mack_message[10 + k * 7])) << 8); + tag += static_cast(d_mack_message[11 + k * 7]); + PRN_d += d_mack_message[12 + k * 7]; + ADKD += ((d_mack_message[13 + k * 7] & 0xF0) >> 4); + cop += (d_mack_message[13 + k * 7] & 0x0F); + } + d_osnma_data.d_mack_message.tag_and_info[k].tag = tag; + d_osnma_data.d_mack_message.tag_and_info[k].tag_info.PRN_d = PRN_d; + d_osnma_data.d_mack_message.tag_and_info[k].tag_info.ADKD = ADKD; + d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = cop; } } From 37fe8eb523bfb8934556a3fc5e11580a7706d71b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 10:19:13 +0200 Subject: [PATCH 035/219] Add more cryptographic functions --- src/core/libs/osnma_msg_receiver.cc | 85 +++++++++++++++++++++++++++++ src/core/libs/osnma_msg_receiver.h | 2 + 2 files changed, 87 insertions(+) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index d62214848..75029e95c 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -46,6 +46,7 @@ namespace wht = std; #endif #if USE_OPENSSL_FALLBACK +#include #if USE_OPENSSL_3 #include #define OPENSSL_ENGINE NULL @@ -659,6 +660,90 @@ std::vector osnma_msg_receiver::computeSHA3_256(const std::vector osnma_msg_receiver::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) +{ + std::vector output(32); +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + std::vector hmac(SHA256_DIGEST_LENGTH); // HMAC-SHA256 output size + + // Create HMAC context + EVP_MD_CTX* ctx = EVP_MD_CTX_new(); + HMAC_CTX_reset(ctx); + + // Initialize HMAC context with the key and HMAC algorithm + HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); + + // Update HMAC context with the message + HMAC_Update(ctx, input.data(), input.size()); + + // Finalize HMAC computation and obtain the result + unsigned int hmacLen; + HMAC_Final(ctx, hmac.data(), &hmacLen); + + // Clean up HMAC context + EVP_MD_CTX_free(ctx); + + // Resize the HMAC vector to the actual length + hmac.resize(hmacLen); + output = hmac; +#else + std::vector hmac(SHA256_DIGEST_LENGTH); + // Create HMAC context + HMAC_CTX* ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); + + // Update HMAC context with the message + HMAC_Update(ctx, input.data(), input.size()); + + // Finalize HMAC computation + unsigned int hmacLen; + HMAC_Final(ctx, hmac.data(), &hmacLen); + + // Clean up HMAC context + HMAC_CTX_free(ctx); + + // Resize the HMAC vector to the actual length + hmac.resize(hmacLen); + + output = hmac; +#endif +#else + std::vector output_aux(32); + gnutls_hmac_hd_t hmac; + gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); + gnutls_hmac(hmac, input.data(), input.size()); + gnutls_hmac_output(hmac, output_aux.data()); + output = output_aux; + gnutls_hmac_deinit(hmac, output_aux.data()); + +#endif + return output; +} + + +std::vector osnma_msg_receiver::computeCMAC_AES(const std::vector& key, const std::vector& input) +{ + std::vector output(16); +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 +#else +#endif +#else + gnutls_cipher_hd_t cipher; + std::vector mac(16); + std::vector message = input; + gnutls_datum_t key_data = {const_cast(key.data()), static_cast(key.size())}; + gnutls_cipher_init(&cipher, GNUTLS_CIPHER_AES_128_CBC, &key_data, nullptr); + gnutls_cipher_set_iv(cipher, nullptr, 16); // Set IV to zero + gnutls_cipher_encrypt(cipher, message.data(), message.size()); // Encrypt the message with AES-128 + gnutls_cipher_tag(cipher, mac.data(), mac.size()); // Get the CMAC-AES tag + output = mac; + gnutls_cipher_deinit(cipher); +#endif + return output; +} + // bool signature(const std::vector& publicKey, const std::vector& digest, std::vector& signature) // { // bool success = false; diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index beb33f50b..0a182f216 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -71,6 +71,8 @@ private: std::vector computeSHA256(const std::vector& input); std::vector computeSHA3_256(const std::vector& input); + std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); + std::vector computeCMAC_AES(const std::vector& key, const std::vector& input); std::unique_ptr d_dsm_reader; From 3902b6154de81836b4f128b12dcd902fe1bf7e89 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 11:15:15 +0200 Subject: [PATCH 036/219] Add work on crypto functions --- src/core/libs/osnma_msg_receiver.cc | 66 ++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 75029e95c..27b2553b2 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -51,6 +51,7 @@ namespace wht = std; #include #define OPENSSL_ENGINE NULL #else +#include #include #endif #else @@ -665,30 +666,27 @@ std::vector osnma_msg_receiver::computeHMAC_SHA_256(const std::vector output(32); #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 - std::vector hmac(SHA256_DIGEST_LENGTH); // HMAC-SHA256 output size + std::vector hmac(EVP_MAX_MD_SIZE); - // Create HMAC context + // Create HMAC-SHA256 context EVP_MD_CTX* ctx = EVP_MD_CTX_new(); - HMAC_CTX_reset(ctx); + EVP_PKEY* pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key.data(), key.size()); - // Initialize HMAC context with the key and HMAC algorithm - HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); + // Initialize HMAC-SHA256 context + EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, pkey); - // Update HMAC context with the message - HMAC_Update(ctx, input.data(), input.size()); + // Compute HMAC-SHA256 + EVP_DigestSignUpdate(ctx, input.data(), input.size()); + size_t macLength; + EVP_DigestSignFinal(ctx, hmac.data(), &macLength); - // Finalize HMAC computation and obtain the result - unsigned int hmacLen; - HMAC_Final(ctx, hmac.data(), &hmacLen); - - // Clean up HMAC context + EVP_PKEY_free(pkey); EVP_MD_CTX_free(ctx); - // Resize the HMAC vector to the actual length - hmac.resize(hmacLen); + mac.resize(macLength); output = hmac; #else - std::vector hmac(SHA256_DIGEST_LENGTH); + std::vector hmac(32); // Create HMAC context HMAC_CTX* ctx = HMAC_CTX_new(); HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); @@ -727,7 +725,45 @@ std::vector osnma_msg_receiver::computeCMAC_AES(const std::vector output(16); #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 + std::vector mac(EVP_MAX_MD_SIZE); // CMAC-AES output size + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + + // Initialize CMAC-AES context + EVP_CIPHER_CTX* cmacCtx = EVP_CIPHER_CTX_new(); + EVP_CMAC_CTX* cmac = EVP_CMAC_CTX_new(); + + EVP_CIPHER_CTX_reset(ctx); + EVP_CMAC_CTX_reset(cmac); + + // Set AES-128 CMAC cipher and key + EVP_CMAC_init(cmac, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); + + // Compute CMAC-AES + EVP_CMAC_update(cmac, input.data(), input.size()); + size_t macLength; + EVP_CMAC_final(cmac, mac.data(), &macLength); + + EVP_CIPHER_CTX_free(ctx); + EVP_CMAC_CTX_free(cmac); + + mac.resize(macLength); + output = mac; #else + std::vector mac(CMAC_DIGEST_LENGTH); // CMAC-AES output size + + // Create CMAC context + CMAC_CTX* cmacCtx = CMAC_CTX_new(); + CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); + + // Compute CMAC-AES + CMAC_Update(cmacCtx, input.data(), input.size()); + CMAC_Final(cmacCtx, mac.data(), nullptr); + + // Clean up CMAC context + CMAC_CTX_free(cmacCtx); + + output = mac; #endif #else gnutls_cipher_hd_t cipher; From a75c2acb31869d0c820fd5edd36b3ba0b470b4d7 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 11:19:14 +0200 Subject: [PATCH 037/219] Fix typo --- src/core/libs/osnma_msg_receiver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 27b2553b2..d284dcd85 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -683,7 +683,7 @@ std::vector osnma_msg_receiver::computeHMAC_SHA_256(const std::vector hmac(32); From d351049eb28d09d60f5439db62479a5e930c24c8 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 12:42:21 +0200 Subject: [PATCH 038/219] Read .pem file with gnutls --- src/core/libs/osnma_msg_receiver.cc | 65 ++++++++++++++++++++++++++++- src/core/libs/osnma_msg_receiver.h | 1 + 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index d284dcd85..8572ec03d 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -46,17 +47,18 @@ namespace wht = std; #endif #if USE_OPENSSL_FALLBACK +#include #include #if USE_OPENSSL_3 #include #define OPENSSL_ENGINE NULL #else -#include #include #endif #else #include #include +#include #endif osnma_msg_receiver_sptr osnma_msg_receiver_make() @@ -795,4 +797,63 @@ std::vector osnma_msg_receiver::computeCMAC_AES(const std::vector osnma_msg_receiver::readPublicKeyFromPEM(const std::string& filePath) +{ + std::vector publicKey; +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 +#else +#endif +#else + // Open the .pem file + std::ifstream file(filePath); + if (!file) + { + std::cerr << "Failed to open the file: " << filePath << std::endl; + return publicKey; + } + + // Read the contents of the .pem file into a string + std::string pemContents((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + + gnutls_x509_crt_t cert; + gnutls_x509_crt_init(&cert); + + // Import the certificate from the PEM file + gnutls_datum_t pemData; + pemData.data = reinterpret_cast(const_cast(pemContents.data())); + pemData.size = pemContents.size(); + int ret = gnutls_x509_crt_import(cert, &pemData, GNUTLS_X509_FMT_PEM); + if (ret < 0) + { + std::cerr << "Failed to import certificate from PEM file" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + // Export the public key data + size_t pubkey_data_size = 0; + ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, nullptr, &pubkey_data_size); + if (ret < 0) + { + std::cerr << "Failed to export public key data" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + publicKey.resize(pubkey_data_size); + ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, publicKey.data(), &pubkey_data_size); + if (ret < 0) + { + std::cerr << "Failed to export public key data" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + gnutls_x509_crt_deinit(cert); + +#endif + return publicKey; +} \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 0a182f216..149d20b43 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -73,6 +73,7 @@ private: std::vector computeSHA3_256(const std::vector& input); std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); std::vector computeCMAC_AES(const std::vector& key, const std::vector& input); + std::vector readPublicKeyFromPEM(const std::string& filePath); std::unique_ptr d_dsm_reader; From 972ead3cae637939007b4bda7d2b1b4d876ed7d4 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 17:21:42 +0200 Subject: [PATCH 039/219] Introducing the crypto bro --- src/core/libs/CMakeLists.txt | 39 --- src/core/libs/osnma_msg_receiver.cc | 309 +---------------- src/core/libs/osnma_msg_receiver.h | 15 +- src/core/receiver/gnss_flowgraph.cc | 4 +- src/core/system_parameters/CMakeLists.txt | 38 ++ src/core/system_parameters/gnss_crypto.cc | 400 ++++++++++++++++++++++ src/core/system_parameters/gnss_crypto.h | 49 +++ 7 files changed, 507 insertions(+), 347 deletions(-) create mode 100644 src/core/system_parameters/gnss_crypto.cc create mode 100644 src/core/system_parameters/gnss_crypto.h diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index c5425d027..1c0c6e811 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -102,45 +102,6 @@ target_link_libraries(core_libs Pugixml::pugixml ) -if(OPENSSL_FOUND) - if(TARGET OpenSSL::SSL) - target_link_libraries(core_libs - PRIVATE - OpenSSL::SSL - ) - else() - target_link_libraries(core_libs - PRIVATE - ${OPENSSL_LIBRARIES} - ) - target_include_directories(core_libs - PRIVATE - ${OPENSSL_INCLUDE_DIR} - ) - endif() - if(OPENSSL_VERSION) - if(OPENSSL_VERSION VERSION_GREATER "3.0.0") - target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_3=1) - endif() - endif() -else() - target_link_libraries(core_libs - PRIVATE - ${GNUTLS_LIBRARIES} - ${GNUTLS_OPENSSL_LIBRARY} - ) - target_include_directories(core_libs - PRIVATE - ${GNUTLS_INCLUDE_DIR} - ) -endif() - - - -if(OPENSSL_FOUND) - target_compile_definitions(core_libs PRIVATE -DUSE_OPENSSL_FALLBACK=1) -endif() - if(USE_GENERIC_LAMBDAS AND NOT GNURADIO_USES_STD_POINTERS) target_link_libraries(core_libs PUBLIC Boost::headers) else() diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 8572ec03d..c8cd9e372 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -19,18 +19,15 @@ #include "osnma_msg_receiver.h" #include "Galileo_OSNMA.h" +#include "gnss_crypto.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include // for DLOG #include // for gr::io_signature::make -#include #include #include #include -#include #include -#include #include -#include #include // for typeid #if HAS_GENERIC_LAMBDA @@ -46,33 +43,21 @@ namespace wht = boost; namespace wht = std; #endif -#if USE_OPENSSL_FALLBACK -#include -#include -#if USE_OPENSSL_3 -#include -#define OPENSSL_ENGINE NULL -#else -#include -#endif -#else -#include -#include -#include -#endif -osnma_msg_receiver_sptr osnma_msg_receiver_make() +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath) { - return osnma_msg_receiver_sptr(new osnma_msg_receiver()); + return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath)); } -osnma_msg_receiver::osnma_msg_receiver() : gr::block("osnma_msg_receiver", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(0, 0, 0)) +osnma_msg_receiver::osnma_msg_receiver( + const std::string& pemFilePath) : gr::block("osnma_msg_receiver", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) { d_dsm_reader = std::make_unique(); - // register OSNMA input message port from telemetry blocks + d_crypto = std::make_unique(pemFilePath); + // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block this->message_port_register_out(pmt::mp("OSNMA_to_PVT")); @@ -291,11 +276,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg std::vector hash; if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. { - hash = computeSHA256(MSG); + hash = d_crypto->computeSHA256(MSG); } else if (d_osnma_data.d_dsm_kroot_message.hf == 2) { - hash = computeSHA3_256(MSG); + hash = d_crypto->computeSHA3_256(MSG); } else { @@ -585,275 +570,3 @@ void osnma_msg_receiver::read_mack_key() void osnma_msg_receiver::read_mack_padding() { } - - -std::vector osnma_msg_receiver::computeSHA256(const std::vector& input) -{ - std::vector output(32); // SHA256 hash size -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - // unsigned char mdVal[EVP_MAX_MD_SIZE]; - // unsigned char* md; - unsigned int mdLen; - EVP_MD_CTX* mdCtx = EVP_MD_CTX_new(); - if (!EVP_DigestInit_ex(mdCtx, EVP_sha256(), OPENSSL_ENGINE)) - { - LOG(WARNING) << "OSNMA SHA-256: Message digest initialization failed."; - EVP_MD_CTX_free(mdCtx); - return output; - } - if (!EVP_DigestUpdate(mdCtx, input.data(), input.size())) - { - LOG(WARNING) << "OSNMA SHA-256: Message digest update failed."; - EVP_MD_CTX_free(mdCtx); - return output; - } - if (!EVP_DigestFinal_ex(mdCtx, output.data(), &mdLen)) - { - LOG(WARNING) << "OSNMA SHA-256: Message digest finalization failed."; - EVP_MD_CTX_free(mdCtx); - return output; - } - EVP_MD_CTX_free(mdCtx); - // md = mdVal; -#else - SHA256_CTX sha256Context; - SHA256_Init(&sha256Context); - SHA256_Update(&sha256Context, input.data(), input.size()); - SHA256_Final(output.data(), &sha256Context); -#endif -#else - std::vector output_aux(32); - gnutls_hash_hd_t hashHandle; - gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); - gnutls_hash(hashHandle, input.data(), input.size()); - gnutls_hash_output(hashHandle, output_aux.data()); - output = output_aux; - gnutls_hash_deinit(hashHandle, output_aux.data()); -#endif - return output; -} - - -std::vector osnma_msg_receiver::computeSHA3_256(const std::vector& input) -{ - std::vector output(32); // SHA256 hash size -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); - const EVP_MD* md = EVP_sha3_256(); - - EVP_DigestInit_ex(mdctx, md, nullptr); - EVP_DigestUpdate(mdctx, input.data(), input.size()); - EVP_DigestFinal_ex(mdctx, output.data(), nullptr); - EVP_MD_CTX_free(mdctx); -#else - // SHA3-256 not implemented in OpenSSL < 3.0 -#endif -#else - std::vector output_aux(32); - gnutls_hash_hd_t hashHandle; - gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); - gnutls_hash(hashHandle, input.data(), input.size()); - gnutls_hash_output(hashHandle, output_aux.data()); - output = output_aux; - gnutls_hash_deinit(hashHandle, output_aux.data()); -#endif - return output; -} - - -std::vector osnma_msg_receiver::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) -{ - std::vector output(32); -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - std::vector hmac(EVP_MAX_MD_SIZE); - - // Create HMAC-SHA256 context - EVP_MD_CTX* ctx = EVP_MD_CTX_new(); - EVP_PKEY* pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key.data(), key.size()); - - // Initialize HMAC-SHA256 context - EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, pkey); - - // Compute HMAC-SHA256 - EVP_DigestSignUpdate(ctx, input.data(), input.size()); - size_t macLength; - EVP_DigestSignFinal(ctx, hmac.data(), &macLength); - - EVP_PKEY_free(pkey); - EVP_MD_CTX_free(ctx); - - hmac.resize(macLength); - output = hmac; -#else - std::vector hmac(32); - // Create HMAC context - HMAC_CTX* ctx = HMAC_CTX_new(); - HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); - - // Update HMAC context with the message - HMAC_Update(ctx, input.data(), input.size()); - - // Finalize HMAC computation - unsigned int hmacLen; - HMAC_Final(ctx, hmac.data(), &hmacLen); - - // Clean up HMAC context - HMAC_CTX_free(ctx); - - // Resize the HMAC vector to the actual length - hmac.resize(hmacLen); - - output = hmac; -#endif -#else - std::vector output_aux(32); - gnutls_hmac_hd_t hmac; - gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); - gnutls_hmac(hmac, input.data(), input.size()); - gnutls_hmac_output(hmac, output_aux.data()); - output = output_aux; - gnutls_hmac_deinit(hmac, output_aux.data()); - -#endif - return output; -} - - -std::vector osnma_msg_receiver::computeCMAC_AES(const std::vector& key, const std::vector& input) -{ - std::vector output(16); -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - std::vector mac(EVP_MAX_MD_SIZE); // CMAC-AES output size - - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - - // Initialize CMAC-AES context - EVP_CIPHER_CTX* cmacCtx = EVP_CIPHER_CTX_new(); - EVP_CMAC_CTX* cmac = EVP_CMAC_CTX_new(); - - EVP_CIPHER_CTX_reset(ctx); - EVP_CMAC_CTX_reset(cmac); - - // Set AES-128 CMAC cipher and key - EVP_CMAC_init(cmac, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); - - // Compute CMAC-AES - EVP_CMAC_update(cmac, input.data(), input.size()); - size_t macLength; - EVP_CMAC_final(cmac, mac.data(), &macLength); - - EVP_CIPHER_CTX_free(ctx); - EVP_CMAC_CTX_free(cmac); - - mac.resize(macLength); - output = mac; -#else - std::vector mac(CMAC_DIGEST_LENGTH); // CMAC-AES output size - - // Create CMAC context - CMAC_CTX* cmacCtx = CMAC_CTX_new(); - CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); - - // Compute CMAC-AES - CMAC_Update(cmacCtx, input.data(), input.size()); - CMAC_Final(cmacCtx, mac.data(), nullptr); - - // Clean up CMAC context - CMAC_CTX_free(cmacCtx); - - output = mac; -#endif -#else - gnutls_cipher_hd_t cipher; - std::vector mac(16); - std::vector message = input; - gnutls_datum_t key_data = {const_cast(key.data()), static_cast(key.size())}; - gnutls_cipher_init(&cipher, GNUTLS_CIPHER_AES_128_CBC, &key_data, nullptr); - gnutls_cipher_set_iv(cipher, nullptr, 16); // Set IV to zero - gnutls_cipher_encrypt(cipher, message.data(), message.size()); // Encrypt the message with AES-128 - gnutls_cipher_tag(cipher, mac.data(), mac.size()); // Get the CMAC-AES tag - output = mac; - gnutls_cipher_deinit(cipher); -#endif - return output; -} - -// bool signature(const std::vector& publicKey, const std::vector& digest, std::vector& signature) -// { -// bool success = false; -// #if USE_OPENSSL_FALLBACK -// #else -// gnutls_global_init(); -// int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data, digest.size(), signature.data(), signature.size()); -// success = (result == GNUTLS_E_SUCCESS); -// gnutls_global_deinit(); -// #endif -// return success; -// } -// bool verifyDigitalSignature(const unsigned char* signature, size_t signatureSize, const unsigned char* message, size_t messageSize, gnutls_pubkey_t publicKey) -// { -// int verificationStatus = gnutls_pubkey_verify_data(publicKey, GNUTLS_DIG_SHA256, 0, message, messageSize, signature, signatureSize); -// return verificationStatus == 0; - -std::vector osnma_msg_receiver::readPublicKeyFromPEM(const std::string& filePath) -{ - std::vector publicKey; -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 -#else -#endif -#else - // Open the .pem file - std::ifstream file(filePath); - if (!file) - { - std::cerr << "Failed to open the file: " << filePath << std::endl; - return publicKey; - } - - // Read the contents of the .pem file into a string - std::string pemContents((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - - gnutls_x509_crt_t cert; - gnutls_x509_crt_init(&cert); - - // Import the certificate from the PEM file - gnutls_datum_t pemData; - pemData.data = reinterpret_cast(const_cast(pemContents.data())); - pemData.size = pemContents.size(); - int ret = gnutls_x509_crt_import(cert, &pemData, GNUTLS_X509_FMT_PEM); - if (ret < 0) - { - std::cerr << "Failed to import certificate from PEM file" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; - } - - // Export the public key data - size_t pubkey_data_size = 0; - ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, nullptr, &pubkey_data_size); - if (ret < 0) - { - std::cerr << "Failed to export public key data" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; - } - - publicKey.resize(pubkey_data_size); - ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, publicKey.data(), &pubkey_data_size); - if (ret < 0) - { - std::cerr << "Failed to export public key data" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; - } - - gnutls_x509_crt_deinit(cert); - -#endif - return publicKey; -} \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 149d20b43..831ca29ab 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -27,6 +27,7 @@ #include // for pmt::pmt_t #include // for std::array #include // for std::shared_ptr +#include #include /** \addtogroup Core @@ -35,11 +36,12 @@ * \{ */ class OSNMA_DSM_Reader; +class Gnss_Crypto; class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; -osnma_msg_receiver_sptr osnma_msg_receiver_make(); +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath); /*! * \brief GNU Radio block that receives asynchronous OSNMA messages @@ -53,8 +55,8 @@ public: ~osnma_msg_receiver() = default; //!< Default destructor private: - friend osnma_msg_receiver_sptr osnma_msg_receiver_make(); - osnma_msg_receiver(); + friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath); + osnma_msg_receiver(const std::string& pemFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); @@ -69,13 +71,8 @@ private: void read_mack_key(); void read_mack_padding(); - std::vector computeSHA256(const std::vector& input); - std::vector computeSHA3_256(const std::vector& input); - std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); - std::vector computeCMAC_AES(const std::vector& key, const std::vector& input); - std::vector readPublicKeyFromPEM(const std::string& filePath); - std::unique_ptr d_dsm_reader; + std::unique_ptr d_crypto; std::array, 16> d_dsm_message{}; std::array, 16> d_dsm_id_received{}; diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 4fde5eea3..7d17fa1b0 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -118,7 +118,9 @@ void GNSSFlowgraph::init() if (configuration_->property("Channels_1B.count", 0) > 0) { enable_osnma_rx_ = true; - osnma_rx_ = osnma_msg_receiver_make(); + const std::string pemfile_default("./OSNMA_PublicKey_20210920133026.pem"); + auto pemFilePath = configuration_->property("GNSS-SDR.OSNMA_pem", pemfile_default); + osnma_rx_ = osnma_msg_receiver_make(pemFilePath); } else { diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 3f2e2a167..a39e45c6c 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -7,6 +7,7 @@ set(SYSTEM_PARAMETERS_SOURCES gnss_almanac.cc + gnss_crypto.cc gnss_ephemeris.cc gnss_satellite.cc gnss_signal.cc @@ -34,6 +35,7 @@ set(SYSTEM_PARAMETERS_SOURCES set(SYSTEM_PARAMETERS_HEADERS gnss_almanac.h + gnss_crypto.h gnss_ephemeris.h gnss_satellite.h gnss_signal.h @@ -130,6 +132,42 @@ target_include_directories(core_system_parameters ${GNSSSDR_SOURCE_DIR}/src/algorithms/libs ) +if(OPENSSL_FOUND) + if(TARGET OpenSSL::SSL) + target_link_libraries(core_system_parameters + PRIVATE + OpenSSL::SSL + ) + else() + target_link_libraries(core_system_parameters + PRIVATE + ${OPENSSL_LIBRARIES} + ) + target_include_directories(core_system_parameters + PRIVATE + ${OPENSSL_INCLUDE_DIR} + ) + endif() + if(OPENSSL_VERSION) + if(OPENSSL_VERSION VERSION_GREATER "3.0.0") + target_compile_definitions(core_system_parameters PRIVATE -DUSE_OPENSSL_3=1) + endif() + endif() +else() + target_link_libraries(core_system_parameters + PRIVATE + ${GNUTLS_LIBRARIES} + ${GNUTLS_OPENSSL_LIBRARY} + ) + target_include_directories(core_system_parameters + PRIVATE + ${GNUTLS_INCLUDE_DIR} + ) +endif() +if(OPENSSL_FOUND) + target_compile_definitions(core_system_parameters PRIVATE -DUSE_OPENSSL_FALLBACK=1) +endif() + if(ENABLE_CLANG_TIDY) if(CLANG_TIDY_EXE) set_target_properties(core_system_parameters diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc new file mode 100644 index 000000000..7f65f081b --- /dev/null +++ b/src/core/system_parameters/gnss_crypto.cc @@ -0,0 +1,400 @@ +/*! + * \file gnss_crypto.cc + * \brief Class for computing cryptografic functions + * \author Carles Fernandez, 2023. cfernandez(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "gnss_crypto.h" +#include +#include +#include +#include + +#if USE_OPENSSL_FALLBACK +#include +#include +#include +#if USE_OPENSSL_3 +#include +#define OPENSSL_ENGINE NULL +#else +#include +#include +#endif +#else +#include +#include +#include +#endif + +Gnss_Crypto::Gnss_Crypto(const std::string& filePath) +{ + d_PublicKey = readPublicKeyFromPEM(filePath); +} + + +std::vector Gnss_Crypto::computeSHA256(const std::vector& input) +{ + std::vector output(32); // SHA256 hash size +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + unsigned int mdLen; + EVP_MD_CTX* mdCtx = EVP_MD_CTX_new(); + if (!EVP_DigestInit_ex(mdCtx, EVP_sha256(), OPENSSL_ENGINE)) + { + // LOG(WARNING) << "OSNMA SHA-256: Message digest initialization failed."; + EVP_MD_CTX_free(mdCtx); + return output; + } + if (!EVP_DigestUpdate(mdCtx, input.data(), input.size())) + { + // LOG(WARNING) << "OSNMA SHA-256: Message digest update failed."; + EVP_MD_CTX_free(mdCtx); + return output; + } + if (!EVP_DigestFinal_ex(mdCtx, output.data(), &mdLen)) + { + // LOG(WARNING) << "OSNMA SHA-256: Message digest finalization failed."; + EVP_MD_CTX_free(mdCtx); + return output; + } + EVP_MD_CTX_free(mdCtx); +#else + SHA256_CTX sha256Context; + SHA256_Init(&sha256Context); + SHA256_Update(&sha256Context, input.data(), input.size()); + SHA256_Final(output.data(), &sha256Context); +#endif +#else + std::vector output_aux(32); + gnutls_hash_hd_t hashHandle; + gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); + gnutls_hash(hashHandle, input.data(), input.size()); + gnutls_hash_output(hashHandle, output_aux.data()); + output = output_aux; + gnutls_hash_deinit(hashHandle, output_aux.data()); +#endif + return output; +} + + +std::vector Gnss_Crypto::computeSHA3_256(const std::vector& input) +{ + std::vector output(32); // SHA256 hash size +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); + const EVP_MD* md = EVP_sha3_256(); + + EVP_DigestInit_ex(mdctx, md, nullptr); + EVP_DigestUpdate(mdctx, input.data(), input.size()); + EVP_DigestFinal_ex(mdctx, output.data(), nullptr); + EVP_MD_CTX_free(mdctx); +#else + // SHA3-256 not implemented in OpenSSL < 3.0 +#endif +#else + std::vector output_aux(32); + gnutls_hash_hd_t hashHandle; + gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); + gnutls_hash(hashHandle, input.data(), input.size()); + gnutls_hash_output(hashHandle, output_aux.data()); + output = output_aux; + gnutls_hash_deinit(hashHandle, output_aux.data()); +#endif + return output; +} + + +std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) +{ + std::vector output(32); +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + std::vector hmac(EVP_MAX_MD_SIZE); + + // Create HMAC-SHA256 context + EVP_MD_CTX* ctx = EVP_MD_CTX_new(); + EVP_PKEY* pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key.data(), key.size()); + + // Initialize HMAC-SHA256 context + EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, pkey); + + // Compute HMAC-SHA256 + EVP_DigestSignUpdate(ctx, input.data(), input.size()); + size_t macLength; + EVP_DigestSignFinal(ctx, hmac.data(), &macLength); + + EVP_PKEY_free(pkey); + EVP_MD_CTX_free(ctx); + + hmac.resize(macLength); + output = hmac; +#else + std::vector hmac(32); + // Create HMAC context + HMAC_CTX* ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); + + // Update HMAC context with the message + HMAC_Update(ctx, input.data(), input.size()); + + // Finalize HMAC computation + unsigned int hmacLen; + HMAC_Final(ctx, hmac.data(), &hmacLen); + + // Clean up HMAC context + HMAC_CTX_free(ctx); + + // Resize the HMAC vector to the actual length + hmac.resize(hmacLen); + + output = hmac; +#endif +#else + std::vector output_aux(32); + gnutls_hmac_hd_t hmac; + gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); + gnutls_hmac(hmac, input.data(), input.size()); + gnutls_hmac_output(hmac, output_aux.data()); + output = output_aux; + gnutls_hmac_deinit(hmac, output_aux.data()); + +#endif + return output; +} + + +std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& key, const std::vector& input) +{ + std::vector output(16); +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + std::vector mac(EVP_MAX_MD_SIZE); // CMAC-AES output size + + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + EVP_MAC* cmac = EVP_MAC_fetch(NULL, "CMAC-AES", NULL); + + EVP_MAC_CTX* cmacCtx = EVP_MAC_CTX_new(cmac); + + OSSL_PARAM params[4]; + params[0] = OSSL_PARAM_construct_utf8_string("key", (char*)key.data(), key.size()); + params[1] = OSSL_PARAM_construct_octet_string("iv", NULL, 0); // Set IV to NULL + params[2] = OSSL_PARAM_construct_octet_string("aad", NULL, 0); // Set AAD to NULL + params[3] = OSSL_PARAM_construct_end(); + + // Set AES-128 CMAC cipher and key + EVP_MAC_init(cmacCtx, nullptr, 0, params); + + // Compute CMAC-AES + EVP_MAC_update(cmacCtx, input.data(), input.size()); + size_t macLength = mac.size(); + size_t outputLength = 16; + + EVP_MAC_final(cmacCtx, mac.data(), &macLength, outputLength); + + EVP_MAC_free(cmac); + EVP_MAC_CTX_free(cmacCtx); + EVP_CIPHER_CTX_free(ctx); + + mac.resize(macLength); + output = mac; +#else + std::vector mac(16); // CMAC-AES output size + + // Create CMAC context + CMAC_CTX* cmacCtx = CMAC_CTX_new(); + CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); + + // Compute CMAC-AES + CMAC_Update(cmacCtx, input.data(), input.size()); + CMAC_Final(cmacCtx, mac.data(), nullptr); + + // Clean up CMAC context + CMAC_CTX_free(cmacCtx); + + output = mac; +#endif +#else + gnutls_cipher_hd_t cipher; + std::vector mac(16); + std::vector message = input; + gnutls_datum_t key_data = {const_cast(key.data()), static_cast(key.size())}; + gnutls_cipher_init(&cipher, GNUTLS_CIPHER_AES_128_CBC, &key_data, nullptr); + gnutls_cipher_set_iv(cipher, nullptr, 16); // Set IV to zero + gnutls_cipher_encrypt(cipher, message.data(), message.size()); // Encrypt the message with AES-128 + gnutls_cipher_tag(cipher, mac.data(), mac.size()); // Get the CMAC-AES tag + output = mac; + gnutls_cipher_deinit(cipher); +#endif + return output; +} + + +std::vector Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) +{ + std::vector publicKey; + // Open the .pem file + std::ifstream pemFile(filePath); + if (!pemFile) + { + std::cerr << "Failed to open the file: " << filePath << std::endl; + return publicKey; + } +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + // Read the contents of the file into a string + std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); + + // Create a BIO object from the string data + BIO* bio = BIO_new_mem_buf(pemContent.c_str(), pemContent.length()); + if (!bio) + { + // Handle BIO creation error + pemFile.close(); + // ... + } + + // Read the PEM data from the BIO + EVP_PKEY* evpKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); + if (!evpKey) + { + // Handle PEM reading error + BIO_free(bio); + pemFile.close(); + // ... + } + + // Create a memory BIO to write the public key data + BIO* memBio = BIO_new(BIO_s_mem()); + if (!memBio) + { + // Handle memory BIO creation error + EVP_PKEY_free(evpKey); + BIO_free(bio); + pemFile.close(); + // ... + } + + // Write the public key to the memory BIO + int result = PEM_write_bio_PUBKEY(memBio, evpKey); + if (result != 1) + { + // Handle public key writing error + BIO_free(memBio); + EVP_PKEY_free(evpKey); + BIO_free(bio); + pemFile.close(); + // ... + } + + // Get the pointer to the memory BIO data and its length + char* bioData; + long bioDataLength = BIO_get_mem_data(memBio, &bioData); + + // Copy the public key data to the vector + publicKey.assign(bioData, bioData + bioDataLength); + + // Free resources + BIO_free(memBio); + EVP_PKEY_free(evpKey); + BIO_free(bio); + pemFile.close(); +#else + // Read the PEM file contents into a string + std::string pemContents((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); + + // Create a BIO object to hold the PEM data + BIO* bio = BIO_new_mem_buf(pemContents.c_str(), -1); + + // Load the public key from the BIO + RSA* rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); + BIO_free(bio); + + if (rsa == nullptr) + { + // Handle error reading public key + return {}; + } + + // Get the RSA modulus and convert it to a vector of uint8_t + const BIGNUM* rsaModulus = nullptr; + RSA_get0_key(rsa, &rsaModulus, nullptr, nullptr); + + BN_bn2bin(rsaModulus, publicKey.data()); + + // Clean up the RSA object + RSA_free(rsa); +#endif +#else + // Read the contents of the .pem file into a string + std::string pemContents((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); + + gnutls_x509_crt_t cert; + gnutls_x509_crt_init(&cert); + + // Import the certificate from the PEM file + gnutls_datum_t pemData; + pemData.data = reinterpret_cast(const_cast(pemContents.data())); + pemData.size = pemContents.size(); + int ret = gnutls_x509_crt_import(cert, &pemData, GNUTLS_X509_FMT_PEM); + if (ret < 0) + { + std::cerr << "Failed to import certificate from PEM file" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + // Export the public key data + size_t pubkey_data_size = 0; + ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, nullptr, &pubkey_data_size); + if (ret < 0) + { + std::cerr << "Failed to export public key data" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + publicKey.resize(pubkey_data_size); + ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, publicKey.data(), &pubkey_data_size); + if (ret < 0) + { + std::cerr << "Failed to export public key data" << std::endl; + gnutls_x509_crt_deinit(cert); + return publicKey; + } + + gnutls_x509_crt_deinit(cert); +#endif + return publicKey; +} + + + +// // bool signature(const std::vector& publicKey, const std::vector& digest, std::vector& signature) +// // { +// // bool success = false; +// // #if USE_OPENSSL_FALLBACK +// // #else +// // gnutls_global_init(); +// // int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data, digest.size(), signature.data(), signature.size()); +// // success = (result == GNUTLS_E_SUCCESS); +// // gnutls_global_deinit(); +// // #endif +// // return success; +// // } +// // bool verifyDigitalSignature(const unsigned char* signature, size_t signatureSize, const unsigned char* message, size_t messageSize, gnutls_pubkey_t publicKey) +// // { +// // int verificationStatus = gnutls_pubkey_verify_data(publicKey, GNUTLS_DIG_SHA256, 0, message, messageSize, signature, signatureSize); +// // return verificationStatus == 0; diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h new file mode 100644 index 000000000..5dc20f4c3 --- /dev/null +++ b/src/core/system_parameters/gnss_crypto.h @@ -0,0 +1,49 @@ +/*! + * \file gnss_crypto.h + * \brief Class for computing cryptografic functions + * \author Carles Fernandez, 2023. cfernandez(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_GNSS_CRYPTO_H +#define GNSS_SDR_GNSS_CRYPTO_H + +#include +#include +#include + + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + + +class Gnss_Crypto +{ +public: + Gnss_Crypto() = default; + Gnss_Crypto(const std::string& filePath); + std::vector computeSHA256(const std::vector& input); + std::vector computeSHA3_256(const std::vector& input); + std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); + std::vector computeCMAC_AES(const std::vector& key, const std::vector& input); + std::vector readPublicKeyFromPEM(const std::string& filePath); + +private: + std::vector d_PublicKey; +}; + +/** \} */ +/** \} */ +#endif // GNSS_SDR_GNSS_CRYPTO_H \ No newline at end of file From 84cc4c79abf4a6f0137998a3b4278bf93b2ee037 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 17:31:10 +0200 Subject: [PATCH 040/219] Fix cpplint job --- src/core/libs/osnma_msg_receiver.h | 2 +- src/core/system_parameters/gnss_crypto.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 831ca29ab..4310a1bee 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -56,7 +56,7 @@ public: private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath); - osnma_msg_receiver(const std::string& pemFilePath); + explicit osnma_msg_receiver(const std::string& pemFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 5dc20f4c3..1eba17f7e 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -33,7 +33,7 @@ class Gnss_Crypto { public: Gnss_Crypto() = default; - Gnss_Crypto(const std::string& filePath); + explicit Gnss_Crypto(const std::string& filePath); std::vector computeSHA256(const std::vector& input); std::vector computeSHA3_256(const std::vector& input); std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); From ddbbcd8d970534d3f36a7ab1ef9479fd73dc4199 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 17:44:46 +0200 Subject: [PATCH 041/219] Fix clang-format --- src/core/system_parameters/gnss_crypto.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 7f65f081b..9f167de62 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -381,7 +381,6 @@ std::vector Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePa } - // // bool signature(const std::vector& publicKey, const std::vector& digest, std::vector& signature) // // { // // bool success = false; From 94d1df62c058f7370aadf2b11ed641a565fc54b4 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 18:12:27 +0200 Subject: [PATCH 042/219] Remove unused file --- src/core/system_parameters/CMakeLists.txt | 1 - src/core/system_parameters/gnss_crypto.cc | 12 ++++++++++++ src/core/system_parameters/gnss_crypto.h | 2 ++ src/core/system_parameters/osnma_data.cc | 17 ----------------- 4 files changed, 14 insertions(+), 18 deletions(-) delete mode 100644 src/core/system_parameters/osnma_data.cc diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index a39e45c6c..f321ab52c 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -29,7 +29,6 @@ set(SYSTEM_PARAMETERS_SOURCES glonass_gnav_utc_model.cc glonass_gnav_navigation_message.cc reed_solomon.cc - osnma_data.cc osnma_dsm_reader.cc ) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 9f167de62..0faa6d096 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -44,6 +44,18 @@ Gnss_Crypto::Gnss_Crypto(const std::string& filePath) } +bool Gnss_Crypto::have_public_key() const +{ + return !d_PublicKey.empty(); +} + + +void Gnss_Crypto::set_public_key(const std::vector& publickey) +{ + d_PublicKey = publickey; +} + + std::vector Gnss_Crypto::computeSHA256(const std::vector& input) { std::vector output(32); // SHA256 hash size diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 1eba17f7e..b6151454c 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -34,6 +34,8 @@ class Gnss_Crypto public: Gnss_Crypto() = default; explicit Gnss_Crypto(const std::string& filePath); + bool have_public_key() const; + void set_public_key(const std::vector& publickey); std::vector computeSHA256(const std::vector& input); std::vector computeSHA3_256(const std::vector& input); std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc deleted file mode 100644 index dde58b44a..000000000 --- a/src/core/system_parameters/osnma_data.cc +++ /dev/null @@ -1,17 +0,0 @@ -/*! - * \file osnma_data.cc - * \brief Class for Galileo OSNMA data storage - * \author Carles Fernandez-Prades, 2020-2023 cfernandez(at)cttc.es - * - * ----------------------------------------------------------------------------- - * - * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. - * This file is part of GNSS-SDR. - * - * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) - * SPDX-License-Identifier: GPL-3.0-or-later - * - * ----------------------------------------------------------------------------- - */ - -#include "osnma_data.h" From 274857a1a4e45c580ca5e6ae54c53b0f9e9b9b19 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Jun 2023 20:16:13 +0200 Subject: [PATCH 043/219] Use nullptr instead of null --- src/core/system_parameters/gnss_crypto.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 0faa6d096..89fdc9e01 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -27,7 +27,7 @@ #include #if USE_OPENSSL_3 #include -#define OPENSSL_ENGINE NULL +#define OPENSSL_ENGINE nullptr #else #include #include @@ -196,14 +196,14 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke std::vector mac(EVP_MAX_MD_SIZE); // CMAC-AES output size EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - EVP_MAC* cmac = EVP_MAC_fetch(NULL, "CMAC-AES", NULL); + EVP_MAC* cmac = EVP_MAC_fetch(nullptr, "CMAC-AES", nullptr); EVP_MAC_CTX* cmacCtx = EVP_MAC_CTX_new(cmac); OSSL_PARAM params[4]; params[0] = OSSL_PARAM_construct_utf8_string("key", (char*)key.data(), key.size()); - params[1] = OSSL_PARAM_construct_octet_string("iv", NULL, 0); // Set IV to NULL - params[2] = OSSL_PARAM_construct_octet_string("aad", NULL, 0); // Set AAD to NULL + params[1] = OSSL_PARAM_construct_octet_string("iv", nullptr, 0); // Set IV to nullptr + params[2] = OSSL_PARAM_construct_octet_string("aad", nullptr, 0); // Set AAD to nullptr params[3] = OSSL_PARAM_construct_end(); // Set AES-128 CMAC cipher and key From a7e822166fd89d9383c4196769a9e7efe102fe9b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 8 Jun 2023 16:14:00 +0200 Subject: [PATCH 044/219] Add work on OSNMA receiver --- src/core/libs/osnma_msg_receiver.cc | 47 ++++++++++++++----- src/core/libs/osnma_msg_receiver.h | 2 +- .../system_parameters/galileo_inav_message.cc | 8 ++++ .../system_parameters/galileo_inav_message.h | 2 + 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index c8cd9e372..8e9641a4c 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -85,6 +85,14 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) { const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); + std::cout << "Galileo OSNMA: Subframe received at " + << "WN=" + << nma_msg->WN_sf0 + << ", TOW=" + << nma_msg->TOW_sf0 + << ", from SVID=" + << nma_msg->PRN + << std::endl; process_osnma_message(nma_msg); } else @@ -133,6 +141,9 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) d_osnma_data.d_dsm_header.dsm_block_id = d_dsm_reader->get_dsm_block_id(dsm_header); // BID LOG(WARNING) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); LOG(WARNING) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); + std::cout << "Galileo OSNMA: Received block " << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) + << " from DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) + << std::endl; } @@ -144,12 +155,6 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][SIZE_DSM_BLOCKS_BYTES * d_osnma_data.d_dsm_header.dsm_block_id + index] = *it; index++; } - std::cout << "dsm_message:"; - for (auto c : d_dsm_message[d_osnma_data.d_dsm_header.dsm_id]) - { - std::cout << " " << static_cast(c); - } - std::cout << std::endl; if (d_osnma_data.d_dsm_header.dsm_block_id == 0) { // Get number of blocks in message @@ -187,6 +192,20 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ // Annotate bid d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; + std::cout << "Galileo OSNMA: Available blocks for DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << ": [ "; + for (auto id_received : d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id]) + { + if (id_received == 0) + { + std::cout << "- "; + } + else + { + std::cout << "X "; + } + } + std::cout << "]" << std::endl; + // is message complete? -> Process DSM message if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cbegin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cend(), 0))) @@ -201,12 +220,12 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; - process_dsm_message(dsm_msg, osnma_msg->hkroot[0]); + process_dsm_message(dsm_msg, osnma_msg); } } -void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg, uint8_t nma_header) +void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg) { if (d_osnma_data.d_dsm_header.dsm_id < 12) { @@ -254,7 +273,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg const uint16_t check_l_dk = 104 * std::ceil(1.0 + static_cast((l_lk_bytes * 8.0) + l_ds_bits) / 104.0); if (l_dk_bits != check_l_dk) { - std::cout << "OSNMA: Failed length reading" << std::endl; + std::cout << "Galileo OSNMA: Failed length reading" << std::endl; } else { @@ -262,7 +281,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg const uint16_t size_m = 13 + l_lk_bytes; std::vector MSG; MSG.reserve(size_m + l_ds_bytes + 1); - MSG.push_back(nma_header); + MSG.push_back(osnma_msg->hkroot[0]); for (uint16_t i = 1; i < size_m; i++) { MSG.push_back(dsm_msg[i]); @@ -297,7 +316,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { LOG(WARNING) << "OSNMA: DSM-KROOT message received ok."; - std::cout << "OSNMA: DSM-KROOT message validated" << std::endl; + std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) + << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) + << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) + << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) + << " validated" << std::endl; } // Validate signature } @@ -342,7 +365,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg uint32_t check_l_dp = 104 * std::ceil(static_cast(1040.0 + l_npk * 8.0) / 104.0); if (l_dp != check_l_dp) { - std::cout << "OSNMA: Failed length reading" << std::endl; + std::cout << "Galileo OSNMA: Failed length reading" << std::endl; } else { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 4310a1bee..bf8a87b10 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -64,7 +64,7 @@ private: void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); void read_mack_block(const std::shared_ptr& osnma_msg); - void process_dsm_message(const std::vector& dsm_msg, uint8_t nma_header); + void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); void read_mack_header(); void read_mack_info_and_tags(); diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index 48d973d97..13c843194 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1422,6 +1422,14 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) OSNMA_msg Galileo_Inav_Message::get_osnma_msg() { nma_position_filled = std::array{}; + // Fill TOW and WN + nma_msg.WN_sf0 = WN_0; + int32_t TOW_sf0 = TOW_5 - 24; + if (TOW_sf0 < 0) + { + TOW_sf0 += 604800; + } + nma_msg.TOW_sf0 = static_cast(TOW_sf0); return nma_msg; } diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 043b05a14..1ed9a8ae9 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -47,6 +47,8 @@ public: std::array mack{}; std::array hkroot{}; uint32_t PRN{}; + uint32_t WN_sf0{}; + uint32_t TOW_sf0{}; }; /*! From 46442ee0fc9c9a57976e71c3e394d8d9350a167f Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 8 Jun 2023 16:30:26 +0200 Subject: [PATCH 045/219] Add work on OSNMA receiver --- src/core/libs/osnma_msg_receiver.cc | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 8e9641a4c..4e3962ab0 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -193,15 +193,32 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; std::cout << "Galileo OSNMA: Available blocks for DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << ": [ "; - for (auto id_received : d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id]) + if (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == 0) { - if (id_received == 0) + for (auto id_received : d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id]) { - std::cout << "- "; + if (id_received == 0) + { + std::cout << "- "; + } + else + { + std::cout << "X "; + } } - else + } + else + { + for (uint8_t k = 0; k < d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]; k++) { - std::cout << "X "; + if (d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][k] == 0) + { + std::cout << "- "; + } + else + { + std::cout << "X "; + } } } std::cout << "]" << std::endl; From 9b560b6da2cd9a19e138ddbd20c9fc4fa5ede3af Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 8 Jun 2023 17:45:22 +0200 Subject: [PATCH 046/219] Add work on OSNMA receiver --- .../galileo_telemetry_decoder_gs.cc | 19 --------------- src/core/libs/osnma_msg_receiver.cc | 13 ++++++---- .../system_parameters/osnma_dsm_reader.cc | 24 +++++++++++++++++++ src/core/system_parameters/osnma_dsm_reader.h | 2 ++ 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 0868ab5e9..aaa3bc8f3 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -511,26 +511,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in if (d_band == '1' && d_inav_nav.have_new_nma() == true) { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); - uint8_t nma_status = (tmp_obj->hkroot[0] & 0xC0) >> 6; this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - std::string nma_status_string; - if (nma_status == 0) - { - nma_status_string = std::string("(Reserved mode)"); - } - else if (nma_status == 1) - { - nma_status_string = std::string("(Test mode)"); - } - else if (nma_status == 2) - { - nma_status_string = std::string("(Operational mode)"); - } - else - { - nma_status_string = std::string("(Do not use mode)"); - } - std::cout << "Galileo OSNMA message " << nma_status_string << " received in channel " << d_channel << " from satellite " << d_satellite << std::endl; } } diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 4e3962ab0..6d8275763 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -20,6 +20,7 @@ #include "osnma_msg_receiver.h" #include "Galileo_OSNMA.h" #include "gnss_crypto.h" +#include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include // for DLOG #include // for gr::io_signature::make @@ -85,13 +86,14 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) { const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); - std::cout << "Galileo OSNMA: Subframe received at " + const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); + std::cout << "Galileo OSNMA: Subframe received starting at " << "WN=" << nma_msg->WN_sf0 << ", TOW=" << nma_msg->TOW_sf0 - << ", from SVID=" - << nma_msg->PRN + << ", from satellite " + << sat << std::endl; process_osnma_message(nma_msg); } @@ -336,8 +338,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) - << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) + << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 << " validated" << std::endl; + std::cout << "Galileo OSNMA: NMAS is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " + << " Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " + << "CPSK is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; } // Validate signature } diff --git a/src/core/system_parameters/osnma_dsm_reader.cc b/src/core/system_parameters/osnma_dsm_reader.cc index baf873bbb..8a2a061d9 100644 --- a/src/core/system_parameters/osnma_dsm_reader.cc +++ b/src/core/system_parameters/osnma_dsm_reader.cc @@ -202,3 +202,27 @@ uint8_t OSNMA_DSM_Reader::get_npktid(const std::vector& dsm_msg) const { return (dsm_msg[129] & mask_dsm_npktid); } + + +std::string OSNMA_DSM_Reader::get_nmas_status(uint8_t nmas) const +{ + std::string status_; + const auto it = OSNMA_TABLE_1.find(nmas); + if (it != OSNMA_TABLE_1.cend()) + { + status_ = it->second; + } + return status_; +} + + +std::string OSNMA_DSM_Reader::get_cpks_status(uint8_t cpks) const +{ + std::string status_; + const auto it = OSNMA_TABLE_2.find(cpks); + if (it != OSNMA_TABLE_2.cend()) + { + status_ = it->second; + } + return status_; +} \ No newline at end of file diff --git a/src/core/system_parameters/osnma_dsm_reader.h b/src/core/system_parameters/osnma_dsm_reader.h index f90bd531b..3eeeb5bea 100644 --- a/src/core/system_parameters/osnma_dsm_reader.h +++ b/src/core/system_parameters/osnma_dsm_reader.h @@ -55,6 +55,8 @@ public: uint16_t get_lk_bits(uint8_t ks) const; std::vector get_kroot(const std::vector& dsm_msg, uint16_t bytes_lk) const; std::string get_hash_function(uint8_t hf) const; + std::string get_nmas_status(uint8_t nmas) const; + std::string get_cpks_status(uint8_t cpks) const; uint8_t get_mid(const std::vector& dsm_msg) const; uint8_t get_npkt(const std::vector& dsm_msg) const; From e343a48a6596a54a4e330d9e7d3417fae17bfc41 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 8 Jun 2023 17:46:58 +0200 Subject: [PATCH 047/219] Add work on OSNMA receiver --- src/core/system_parameters/Galileo_OSNMA.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index bb3781c3f..be43d91f2 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -32,16 +32,24 @@ constexpr size_t SIZE_DSM_BLOCKS_BYTES = 13; -// OSNMA User ICD for the Test Phase, Issue 1.0, Table 2 +// OSNMA User ICD for the Test Phase, Issue 1.0, Table 1 +const std::unordered_map OSNMA_TABLE_1 = { + {0, std::string("Reserved")}, + {1, std::string("Test")}, + {2, std::string("Operational")}, + {3, std::string("Don't use")}}; // key: nmas, value: nmas status + + +// OSNMA User ICD for the Test Phase, Issue 1.0, Table 1 const std::unordered_map OSNMA_TABLE_2 = { {0, std::string("Reserved")}, {1, std::string("Nominal")}, {2, std::string("End of Chain (EOC)")}, {3, std::string("Chain Revoked (CREV)")}, - {4, std::string("New Public Key (NPK)")}, - {5, std::string("Public Key Revoked (PKREV)")}, - {6, std::string("Reserved")}, - {7, std::string("Reserved")}}; // key: cpks, value: Chain and Public Key Status + {4, std::string("Public Key Revoked (PKREV)")}, + {5, std::string("Chain Revoked (CREV)")}, + {6, std::string("New Merkle Tree (NMT)")}, + {7, std::string("Alert Message (AM)")}}; // key: cpks, value: cpks status // OSNMA User ICD for the Test Phase, Issue 1.0, Table 3 const std::unordered_map> OSNMA_TABLE_3 = { From c8347584f8834643cc1179b0ebad2ed6892d86fa Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 11 Jun 2023 01:46:08 +0200 Subject: [PATCH 048/219] Add work on OSNMA receiver --- src/core/libs/osnma_msg_receiver.cc | 6 +- src/core/receiver/gnss_flowgraph.cc | 4 +- src/core/system_parameters/Galileo_OSNMA.h | 1 + src/core/system_parameters/gnss_crypto.cc | 340 ++++++++++++++------- src/core/system_parameters/gnss_crypto.h | 11 +- 5 files changed, 235 insertions(+), 127 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 6d8275763..b8da3b78b 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -340,9 +340,9 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 << " validated" << std::endl; - std::cout << "Galileo OSNMA: NMAS is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " - << " Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " - << "CPSK is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; + std::cout << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " + << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " + << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; } // Validate signature } diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 7d17fa1b0..3856876ca 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -27,6 +27,7 @@ #include "Galileo_E5a.h" #include "Galileo_E5b.h" #include "Galileo_E6.h" +#include "Galileo_OSNMA.h" #include "channel.h" #include "channel_fsm.h" #include "channel_interface.h" @@ -118,8 +119,7 @@ void GNSSFlowgraph::init() if (configuration_->property("Channels_1B.count", 0) > 0) { enable_osnma_rx_ = true; - const std::string pemfile_default("./OSNMA_PublicKey_20210920133026.pem"); - auto pemFilePath = configuration_->property("GNSS-SDR.OSNMA_pem", pemfile_default); + auto pemFilePath = configuration_->property("GNSS-SDR.OSNMA_pem", PEMFILE_DEFAULT); osnma_rx_ = osnma_msg_receiver_make(pemFilePath); } else diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index be43d91f2..2cb486248 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -160,6 +160,7 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("SHA-256"), 512}, {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} +const std::string PEMFILE_DEFAULT("./OSNMA_PublicKey_20210920133026.pem"); /** \} */ /** \} */ #endif // GNSS_SDR_GALILEO_OSNMA_H \ No newline at end of file diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 89fdc9e01..0a1eb6623 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -16,10 +16,12 @@ */ #include "gnss_crypto.h" +#include "Galileo_OSNMA.h" #include #include #include #include +#include #if USE_OPENSSL_FALLBACK #include @@ -29,7 +31,6 @@ #include #define OPENSSL_ENGINE nullptr #else -#include #include #endif #else @@ -40,7 +41,7 @@ Gnss_Crypto::Gnss_Crypto(const std::string& filePath) { - d_PublicKey = readPublicKeyFromPEM(filePath); + readPublicKeyFromPEM(filePath); } @@ -56,7 +57,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publickey) } -std::vector Gnss_Crypto::computeSHA256(const std::vector& input) +std::vector Gnss_Crypto::computeSHA256(const std::vector& input) const { std::vector output(32); // SHA256 hash size #if USE_OPENSSL_FALLBACK @@ -101,7 +102,7 @@ std::vector Gnss_Crypto::computeSHA256(const std::vector& inpu } -std::vector Gnss_Crypto::computeSHA3_256(const std::vector& input) +std::vector Gnss_Crypto::computeSHA3_256(const std::vector& input) const { std::vector output(32); // SHA256 hash size #if USE_OPENSSL_FALLBACK @@ -129,7 +130,7 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in } -std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) +std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const { std::vector output(32); #if USE_OPENSSL_FALLBACK @@ -171,7 +172,6 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector // Resize the HMAC vector to the actual length hmac.resize(hmacLen); - output = hmac; #endif #else @@ -182,13 +182,12 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector gnutls_hmac_output(hmac, output_aux.data()); output = output_aux; gnutls_hmac_deinit(hmac, output_aux.data()); - #endif return output; } -std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& key, const std::vector& input) +std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& key, const std::vector& input) const { std::vector output(16); #if USE_OPENSSL_FALLBACK @@ -254,158 +253,265 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke } -std::vector Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) +void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) { - std::vector publicKey; // Open the .pem file std::ifstream pemFile(filePath); if (!pemFile) { - std::cerr << "Failed to open the file: " << filePath << std::endl; - return publicKey; + // PEM file not found + // If it not was the default, maybe it is a configuration error + if (filePath != PEMFILE_DEFAULT) + { + std::cerr << "File " << filePath << " not found" << std::endl; + } + return; } -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 - // Read the contents of the file into a string + std::vector publicKey; std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); - +#if USE_OPENSSL_FALLBACK // Create a BIO object from the string data BIO* bio = BIO_new_mem_buf(pemContent.c_str(), pemContent.length()); if (!bio) { - // Handle BIO creation error - pemFile.close(); - // ... + std::cerr << "OpenSSL: error creating a BIO object with data read from file " << filePath << ". Aborting import" << std::endl; + return; } - - // Read the PEM data from the BIO +#if USE_OPENSSL_3 + // Read the PEM data from the BIO object EVP_PKEY* evpKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); + BIO_free(bio); if (!evpKey) { - // Handle PEM reading error - BIO_free(bio); - pemFile.close(); - // ... + std::cerr << "OpenSSL: error reading the Public Key from file " << filePath << ". Aborting import" << std::endl; + return; } - // Create a memory BIO to write the public key data - BIO* memBio = BIO_new(BIO_s_mem()); - if (!memBio) + // Check if the public key is an EC key + if (EVP_PKEY_base_id(evpKey) != EVP_PKEY_EC) { - // Handle memory BIO creation error + std::cerr << "OpenSSL: Public key imported from file " << filePath << " is not an EC key. Aborting import" << std::endl; EVP_PKEY_free(evpKey); - BIO_free(bio); - pemFile.close(); - // ... + return; } - // Write the public key to the memory BIO - int result = PEM_write_bio_PUBKEY(memBio, evpKey); - if (result != 1) - { - // Handle public key writing error - BIO_free(memBio); - EVP_PKEY_free(evpKey); - BIO_free(bio); - pemFile.close(); - // ... - } - - // Get the pointer to the memory BIO data and its length - char* bioData; - long bioDataLength = BIO_get_mem_data(memBio, &bioData); - - // Copy the public key data to the vector - publicKey.assign(bioData, bioData + bioDataLength); - - // Free resources - BIO_free(memBio); + // Get the EC key from the EVP_PKEY object + EC_KEY* ecKey = EVP_PKEY_get1_EC_KEY(evpKey); EVP_PKEY_free(evpKey); - BIO_free(bio); - pemFile.close(); + + if (ecKey == nullptr) + { + std::cout << "OpenSSL: Failed to get the EC key from file " << filePath << ". Aborting import" << std::endl; + return; + } + + // Get the EC group from the EC key + const EC_GROUP* ecGroup = EC_KEY_get0_group(ecKey); + + if (ecGroup == nullptr) + { + std::cout << "OpenSSL: Failed to extract the EC group from file " << filePath << ". Aborting import" << std::endl; + EC_KEY_free(ecKey); + return; + } + + // Check if it is ECDSA P-256 + if (EC_GROUP_get_curve_name(ecGroup) != NID_X9_62_prime256v1) + { + std::cerr << "Invalid curve name in file " << filePath << ". Expected P-256. Aborting import" << std::endl; + EC_KEY_free(ecKey); + return; + } + // Convert the EC parameters to an octet string (raw binary) + // size_t octetSize = i2o_ECPublicKey(ecKey, nullptr); + // std::vector ecParameters(octetSize); + // unsigned char* p = ecParameters.data(); + // i2o_ECPublicKey(ecKey, &p); + std::vector ecParameters(EC_GROUP_get_degree(ecGroup) / 8); + EC_POINT_point2oct(ecGroup, EC_KEY_get0_public_key(ecKey), POINT_CONVERSION_UNCOMPRESSED, ecParameters.data(), ecParameters.size(), nullptr); + + // Get the EC public key from the EC key + const EC_POINT* ecPoint = EC_KEY_get0_public_key(ecKey); + + // Convert the EC public key to an octet string (raw binary) + size_t pointSize = EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); + publicKey = std::vector(pointSize); + EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(), pointSize, nullptr); + size_t octetSize = i2o_ECPublicKey(ecKey, nullptr); + std::vector publicKey2(octetSize); + unsigned char* p2 = publicKey2.data(); + i2o_ECPublicKey(ecKey, &p2); + // Clean up the EC key + EC_KEY_free(ecKey); + + std::cout << "EC parameters (size: " << ecParameters.size() << "):"; + for (auto k : ecParameters) + { + std::cout << " " << static_cast(k); + } + std::cout << std::endl; + std::cout << "Public Key (size: " << publicKey.size() << "):"; + for (auto k : publicKey) + { + std::cout << " " << static_cast(k); + } + std::cout << "Public Key2: (size: " << publicKey2.size() << "):"; + for (auto k : publicKey2) + { + std::cout << " " << static_cast(k); + } + std::cout << std::endl; #else - // Read the PEM file contents into a string - std::string pemContents((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); - - // Create a BIO object to hold the PEM data - BIO* bio = BIO_new_mem_buf(pemContents.c_str(), -1); - // Load the public key from the BIO - RSA* rsa = PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr); + EC_KEY* ecKeyPublic = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); BIO_free(bio); - - if (rsa == nullptr) + if (ecKeyPublic == nullptr) { - // Handle error reading public key - return {}; + std::cerr << "OpenSSL: error reading the Public Key from file " << filePath << ". Aborting import" << std::endl; + return; } - // Get the RSA modulus and convert it to a vector of uint8_t - const BIGNUM* rsaModulus = nullptr; - RSA_get0_key(rsa, &rsaModulus, nullptr, nullptr); + // // Get the EC group and EC point from the EC key + const EC_GROUP* ecGroup = EC_KEY_get0_group(ecKeyPublic); + const EC_POINT* ecPoint = EC_KEY_get0_public_key(ecKeyPublic); + // Convert the EC point to an octet string (raw binary) + const size_t octetSize = EC_POINT_point2oct( + ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); + publicKey = std::vector(octetSize); + EC_POINT_point2oct( + ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(), octetSize, nullptr); + EC_KEY_free(ecKeyPublic); - BN_bn2bin(rsaModulus, publicKey.data()); - - // Clean up the RSA object - RSA_free(rsa); + std::cout << "Public Key:"; + for (auto k : publicKey) + { + std::cout << " " << static_cast(k); + } + std::cout << std::endl; #endif #else - // Read the contents of the .pem file into a string - std::string pemContents((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); - - gnutls_x509_crt_t cert; - gnutls_x509_crt_init(&cert); - - // Import the certificate from the PEM file - gnutls_datum_t pemData; - pemData.data = reinterpret_cast(const_cast(pemContents.data())); - pemData.size = pemContents.size(); - int ret = gnutls_x509_crt_import(cert, &pemData, GNUTLS_X509_FMT_PEM); - if (ret < 0) + // Find the beginning and end of the EC PARAMETERS section + std::size_t beginPos = pemContent.find("-----BEGIN EC PARAMETERS-----"); + std::size_t endPos = pemContent.find("-----END EC PARAMETERS-----"); + if (beginPos == std::string::npos || endPos == std::string::npos) { - std::cerr << "Failed to import certificate from PEM file" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; + std::cerr << "No EC Parameters found in file " << filePath << ". Aborting import" << std::endl; + return; } - // Export the public key data - size_t pubkey_data_size = 0; - ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, nullptr, &pubkey_data_size); - if (ret < 0) - { - std::cerr << "Failed to export public key data" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; - } + // Extract the EC parameters data + std::string ecParamsBase64 = pemContent.substr(beginPos + 30, endPos - beginPos - 31); + std::vector ecParameters = base64Decode(ecParamsBase64); - publicKey.resize(pubkey_data_size); - ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, publicKey.data(), &pubkey_data_size); - if (ret < 0) + std::cout << ecParamsBase64 << std::endl; + std::cout << "Size ecParamsBase64 : " << ecParamsBase64.size() << std::endl; + std::cout << "Size EC : " << ecParameters.size() << std::endl; + for (auto k : ecParameters) { - std::cerr << "Failed to export public key data" << std::endl; - gnutls_x509_crt_deinit(cert); - return publicKey; + std::cout << " " << static_cast(k); } + std::cout << std::endl; - gnutls_x509_crt_deinit(cert); + std::size_t beginPos2 = pemContent.find("-----BEGIN PUBLIC KEY-----"); + std::size_t endPos2 = pemContent.find("-----END PUBLIC KEY-----"); + if (beginPos2 == std::string::npos || endPos2 == std::string::npos) + { + std::cout << "No Public Key found in file " << filePath << ". Aborting import" << std::endl; + return; + } + auto PublickeyBase64 = pemContent.substr(beginPos2 + 27, endPos2 - beginPos2 - 28); + auto readpublickey_long = base64Decode(PublickeyBase64); + publicKey = std::vector(readpublickey_long.begin() + 26, readpublickey_long.end()); // ?? + + std::cout << "Public Key (size: " << publicKey.size() << "):" << std::endl; + for (auto k : publicKey) + { + std::cout << " " << static_cast(k); + } + std::cout << std::endl; #endif - return publicKey; + d_PublicKey = publicKey; + std::cout << "Public key successfully read from file " << filePath << std::endl; } -// // bool signature(const std::vector& publicKey, const std::vector& digest, std::vector& signature) -// // { -// // bool success = false; -// // #if USE_OPENSSL_FALLBACK -// // #else -// // gnutls_global_init(); -// // int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data, digest.size(), signature.data(), signature.size()); -// // success = (result == GNUTLS_E_SUCCESS); -// // gnutls_global_deinit(); -// // #endif -// // return success; -// // } +// bool signature(const std::vector& publicKey, const std::vector& digest, const std::vector& signature) +// { +// bool success = false; +// #if USE_OPENSSL_FALLBACK +// #else +// gnutls_global_init(); +// int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data(), digest.size(), signature.data(), signature.size()); +// success = (result == GNUTLS_E_SUCCESS); +// gnutls_global_deinit(); +// #endif +// return success; +// } // // bool verifyDigitalSignature(const unsigned char* signature, size_t signatureSize, const unsigned char* message, size_t messageSize, gnutls_pubkey_t publicKey) // // { // // int verificationStatus = gnutls_pubkey_verify_data(publicKey, GNUTLS_DIG_SHA256, 0, message, messageSize, signature, signatureSize); // // return verificationStatus == 0; + + +std::vector Gnss_Crypto::base64Decode(const std::string& encoded_string) +{ + const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + uint8_t char_array_4[4]; + uint8_t char_array_3[3]; + std::vector decoded; + + while (in_len-- && (encoded_string[in_] != '=') && + (isalnum(encoded_string[in_]) || (encoded_string[in_] == '+') || (encoded_string[in_] == '/'))) + { + char_array_4[i++] = encoded_string[in_]; + in_++; + if (i == 4) + { + for (i = 0; i < 4; i++) + { + char_array_4[i] = base64_chars.find(char_array_4[i]); + } + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + { + decoded.push_back(char_array_3[i]); + } + i = 0; + } + } + + if (i) + { + for (j = i; j < 4; j++) + { + char_array_4[j] = 0; + } + + for (j = 0; j < 4; j++) + { + char_array_4[j] = base64_chars.find(char_array_4[j]); + } + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) + { + decoded.push_back(char_array_3[j]); + } + } + + return decoded; +} \ No newline at end of file diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index b6151454c..8c4af9a5b 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -35,14 +35,15 @@ public: Gnss_Crypto() = default; explicit Gnss_Crypto(const std::string& filePath); bool have_public_key() const; + std::vector computeSHA256(const std::vector& input) const; + std::vector computeSHA3_256(const std::vector& input) const; + std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; + std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; void set_public_key(const std::vector& publickey); - std::vector computeSHA256(const std::vector& input); - std::vector computeSHA3_256(const std::vector& input); - std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input); - std::vector computeCMAC_AES(const std::vector& key, const std::vector& input); - std::vector readPublicKeyFromPEM(const std::string& filePath); + void readPublicKeyFromPEM(const std::string& filePath); private: + std::vector base64Decode(const std::string& encoded_string); std::vector d_PublicKey; }; From e75bdeb5f6e0b0130f54fb77605d8cb291851419 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 11 Jun 2023 20:30:03 +0200 Subject: [PATCH 049/219] Add work on OSNMA receiver --- src/core/libs/osnma_msg_receiver.cc | 5 + src/core/system_parameters/CMakeLists.txt | 14 +- src/core/system_parameters/gnss_crypto.cc | 240 ++++++---------------- src/core/system_parameters/gnss_crypto.h | 18 +- 4 files changed, 93 insertions(+), 184 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index b8da3b78b..8f7b82051 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -397,6 +397,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; } // std::vector mi; // (NPKT + NPKID + NPK) + std::cout << "Galileo OSNMA: DSM-PKR with CID=" << static_cast(d_osnma_data.d_nma_header.cid) + << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) + << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) + << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 + << " received" << std::endl; } } else diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index f321ab52c..c8b4c2d57 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -134,37 +134,37 @@ target_include_directories(core_system_parameters if(OPENSSL_FOUND) if(TARGET OpenSSL::SSL) target_link_libraries(core_system_parameters - PRIVATE + PUBLIC OpenSSL::SSL ) else() target_link_libraries(core_system_parameters - PRIVATE + PUBLIC ${OPENSSL_LIBRARIES} ) target_include_directories(core_system_parameters - PRIVATE + PUBLIC ${OPENSSL_INCLUDE_DIR} ) endif() if(OPENSSL_VERSION) if(OPENSSL_VERSION VERSION_GREATER "3.0.0") - target_compile_definitions(core_system_parameters PRIVATE -DUSE_OPENSSL_3=1) + target_compile_definitions(core_system_parameters PUBLIC -DUSE_OPENSSL_3=1) endif() endif() else() target_link_libraries(core_system_parameters - PRIVATE + PUBLIC ${GNUTLS_LIBRARIES} ${GNUTLS_OPENSSL_LIBRARY} ) target_include_directories(core_system_parameters - PRIVATE + PUBLIC ${GNUTLS_INCLUDE_DIR} ) endif() if(OPENSSL_FOUND) - target_compile_definitions(core_system_parameters PRIVATE -DUSE_OPENSSL_FALLBACK=1) + target_compile_definitions(core_system_parameters PUBLIC -DUSE_OPENSSL_FALLBACK=1) endif() if(ENABLE_CLANG_TIDY) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 0a1eb6623..df72beff0 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -25,6 +25,7 @@ #if USE_OPENSSL_FALLBACK #include +#include #include #include #if USE_OPENSSL_3 @@ -34,27 +35,49 @@ #include #endif #else +#include #include -#include #include #endif + Gnss_Crypto::Gnss_Crypto(const std::string& filePath) { +#if USE_OPENSSL_FALLBACK +#else + gnutls_global_init(); +#endif readPublicKeyFromPEM(filePath); } +Gnss_Crypto::~Gnss_Crypto() +{ +#if USE_OPENSSL_FALLBACK + if (d_PublicKey != nullptr) + { + EC_KEY_free(d_PublicKey); + } +#else + if (d_PublicKey != nullptr) + { + gnutls_pubkey_deinit(*d_PublicKey); + } + + gnutls_global_deinit(); +#endif +} + + bool Gnss_Crypto::have_public_key() const { - return !d_PublicKey.empty(); + return (d_PublicKey != nullptr); } -void Gnss_Crypto::set_public_key(const std::vector& publickey) -{ - d_PublicKey = publickey; -} +// void Gnss_Crypto::set_public_key(const std::vector& publickey) +// { +// } std::vector Gnss_Crypto::computeSHA256(const std::vector& input) const @@ -296,22 +319,22 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) } // Get the EC key from the EVP_PKEY object - EC_KEY* ecKey = EVP_PKEY_get1_EC_KEY(evpKey); + d_PublicKey = EVP_PKEY_get1_EC_KEY(evpKey); EVP_PKEY_free(evpKey); - if (ecKey == nullptr) + if (d_PublicKey == nullptr) { std::cout << "OpenSSL: Failed to get the EC key from file " << filePath << ". Aborting import" << std::endl; return; } // Get the EC group from the EC key - const EC_GROUP* ecGroup = EC_KEY_get0_group(ecKey); + const EC_GROUP* ecGroup = EC_KEY_get0_group(d_PublicKey); if (ecGroup == nullptr) { std::cout << "OpenSSL: Failed to extract the EC group from file " << filePath << ". Aborting import" << std::endl; - EC_KEY_free(ecKey); + EC_KEY_free(d_PublicKey); return; } @@ -319,131 +342,68 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) if (EC_GROUP_get_curve_name(ecGroup) != NID_X9_62_prime256v1) { std::cerr << "Invalid curve name in file " << filePath << ". Expected P-256. Aborting import" << std::endl; - EC_KEY_free(ecKey); + EC_KEY_free(d_PublicKey); return; } - // Convert the EC parameters to an octet string (raw binary) - // size_t octetSize = i2o_ECPublicKey(ecKey, nullptr); - // std::vector ecParameters(octetSize); - // unsigned char* p = ecParameters.data(); - // i2o_ECPublicKey(ecKey, &p); - std::vector ecParameters(EC_GROUP_get_degree(ecGroup) / 8); - EC_POINT_point2oct(ecGroup, EC_KEY_get0_public_key(ecKey), POINT_CONVERSION_UNCOMPRESSED, ecParameters.data(), ecParameters.size(), nullptr); - - // Get the EC public key from the EC key - const EC_POINT* ecPoint = EC_KEY_get0_public_key(ecKey); - - // Convert the EC public key to an octet string (raw binary) - size_t pointSize = EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); - publicKey = std::vector(pointSize); - EC_POINT_point2oct(ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(), pointSize, nullptr); - size_t octetSize = i2o_ECPublicKey(ecKey, nullptr); - std::vector publicKey2(octetSize); - unsigned char* p2 = publicKey2.data(); - i2o_ECPublicKey(ecKey, &p2); - // Clean up the EC key - EC_KEY_free(ecKey); - - std::cout << "EC parameters (size: " << ecParameters.size() << "):"; - for (auto k : ecParameters) - { - std::cout << " " << static_cast(k); - } - std::cout << std::endl; - std::cout << "Public Key (size: " << publicKey.size() << "):"; - for (auto k : publicKey) - { - std::cout << " " << static_cast(k); - } - std::cout << "Public Key2: (size: " << publicKey2.size() << "):"; - for (auto k : publicKey2) - { - std::cout << " " << static_cast(k); - } - std::cout << std::endl; #else // Load the public key from the BIO - EC_KEY* ecKeyPublic = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); + d_PublicKey = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); BIO_free(bio); - if (ecKeyPublic == nullptr) + if (d_PublicKey == nullptr) { std::cerr << "OpenSSL: error reading the Public Key from file " << filePath << ". Aborting import" << std::endl; return; } - - // // Get the EC group and EC point from the EC key - const EC_GROUP* ecGroup = EC_KEY_get0_group(ecKeyPublic); - const EC_POINT* ecPoint = EC_KEY_get0_public_key(ecKeyPublic); - // Convert the EC point to an octet string (raw binary) - const size_t octetSize = EC_POINT_point2oct( - ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr); - publicKey = std::vector(octetSize); - EC_POINT_point2oct( - ecGroup, ecPoint, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(), octetSize, nullptr); - EC_KEY_free(ecKeyPublic); - - std::cout << "Public Key:"; - for (auto k : publicKey) - { - std::cout << " " << static_cast(k); - } - std::cout << std::endl; #endif #else - // Find the beginning and end of the EC PARAMETERS section - std::size_t beginPos = pemContent.find("-----BEGIN EC PARAMETERS-----"); - std::size_t endPos = pemContent.find("-----END EC PARAMETERS-----"); - if (beginPos == std::string::npos || endPos == std::string::npos) + gnutls_pubkey_t pubKey; + gnutls_pubkey_init(&pubKey); + d_PublicKey = &pubKey; + // Import the PEM data + gnutls_datum_t pemDatum = {const_cast(reinterpret_cast(pemContent.data())), static_cast(pemContent.size())}; + int ret = gnutls_pubkey_import(*d_PublicKey, &pemDatum, GNUTLS_X509_FMT_PEM); + if (ret < 0) { - std::cerr << "No EC Parameters found in file " << filePath << ". Aborting import" << std::endl; + std::cerr << "GnuTLS: error reading the Public Key from file " + << filePath + << ". (Error: " << gnutls_strerror(ret) << "). Aborting import" << std::endl; + gnutls_pubkey_deinit(*d_PublicKey); return; } - - // Extract the EC parameters data - std::string ecParamsBase64 = pemContent.substr(beginPos + 30, endPos - beginPos - 31); - std::vector ecParameters = base64Decode(ecParamsBase64); - - std::cout << ecParamsBase64 << std::endl; - std::cout << "Size ecParamsBase64 : " << ecParamsBase64.size() << std::endl; - std::cout << "Size EC : " << ecParameters.size() << std::endl; - for (auto k : ecParameters) - { - std::cout << " " << static_cast(k); - } - std::cout << std::endl; - - std::size_t beginPos2 = pemContent.find("-----BEGIN PUBLIC KEY-----"); - std::size_t endPos2 = pemContent.find("-----END PUBLIC KEY-----"); - if (beginPos2 == std::string::npos || endPos2 == std::string::npos) - { - std::cout << "No Public Key found in file " << filePath << ". Aborting import" << std::endl; - return; - } - auto PublickeyBase64 = pemContent.substr(beginPos2 + 27, endPos2 - beginPos2 - 28); - auto readpublickey_long = base64Decode(PublickeyBase64); - publicKey = std::vector(readpublickey_long.begin() + 26, readpublickey_long.end()); // ?? - - std::cout << "Public Key (size: " << publicKey.size() << "):" << std::endl; - for (auto k : publicKey) - { - std::cout << " " << static_cast(k); - } - std::cout << std::endl; #endif - d_PublicKey = publicKey; std::cout << "Public key successfully read from file " << filePath << std::endl; } -// bool signature(const std::vector& publicKey, const std::vector& digest, const std::vector& signature) +// bool verify_signature(const std::vector& message, const std::vector& signature) // { // bool success = false; // #if USE_OPENSSL_FALLBACK +/** Verifies that the given signature is valid ECDSA signature + * of the supplied hash value using the specified public key. + * \param type this parameter is ignored + * \param dgst pointer to the hash value + * \param dgstlen length of the hash value + * \param sig pointer to the DER encoded signature + * \param siglen length of the DER encoded signature + * \param eckey EC_KEY object containing a public EC key + * \return 1 if the signature is valid, 0 if the signature is invalid + * and -1 on error + */ +// int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, const unsigned char *sig, int siglen, EC_KEY *eckey);) +// int verification = ECDSA_verify(0, digest, SHA256_DIGEST_LENGTH, signature, signature_len, key_pair_obj); // #else // gnutls_global_init(); // int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data(), digest.size(), signature.data(), signature.size()); // success = (result == GNUTLS_E_SUCCESS); // gnutls_global_deinit(); +// pubkey: Holds the public key +// algo: The signature algorithm used +// flags: Zero or an OR list of gnutls_certificate_verify_flags +// data: holds the signed data +// signature: contains the signature +// This function will verify the given signed data, using the parameters from the certificate. +// gnutls_pubkey_verify_data2 (gnutls_pubkey_t pubkey, gnutls_sign_algorithm_t algo, unsigned int flags, const gnutls_datum_t * data, const gnutls_datum_t * signature) // #endif // return success; // } @@ -451,67 +411,3 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) // // { // // int verificationStatus = gnutls_pubkey_verify_data(publicKey, GNUTLS_DIG_SHA256, 0, message, messageSize, signature, signatureSize); // // return verificationStatus == 0; - - -std::vector Gnss_Crypto::base64Decode(const std::string& encoded_string) -{ - const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - uint8_t char_array_4[4]; - uint8_t char_array_3[3]; - std::vector decoded; - - while (in_len-- && (encoded_string[in_] != '=') && - (isalnum(encoded_string[in_]) || (encoded_string[in_] == '+') || (encoded_string[in_] == '/'))) - { - char_array_4[i++] = encoded_string[in_]; - in_++; - if (i == 4) - { - for (i = 0; i < 4; i++) - { - char_array_4[i] = base64_chars.find(char_array_4[i]); - } - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - { - decoded.push_back(char_array_3[i]); - } - i = 0; - } - } - - if (i) - { - for (j = i; j < 4; j++) - { - char_array_4[j] = 0; - } - - for (j = 0; j < 4; j++) - { - char_array_4[j] = base64_chars.find(char_array_4[j]); - } - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) - { - decoded.push_back(char_array_3[j]); - } - } - - return decoded; -} \ No newline at end of file diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 8c4af9a5b..4e160ac2c 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -21,30 +21,38 @@ #include #include #include - +#if USE_OPENSSL_FALLBACK +#include +#else +#include +#endif /** \addtogroup Core * \{ */ /** \addtogroup System_Parameters * \{ */ - class Gnss_Crypto { public: Gnss_Crypto() = default; + ~Gnss_Crypto(); explicit Gnss_Crypto(const std::string& filePath); bool have_public_key() const; std::vector computeSHA256(const std::vector& input) const; std::vector computeSHA3_256(const std::vector& input) const; std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; - void set_public_key(const std::vector& publickey); + void readPublicKeyFromPEM(const std::string& filePath); + // void set_public_key(const std::vector& publickey); private: - std::vector base64Decode(const std::string& encoded_string); - std::vector d_PublicKey; +#if USE_OPENSSL_FALLBACK + EC_KEY* d_PublicKey = nullptr; +#else + gnutls_pubkey_t* d_PublicKey; +#endif }; /** \} */ From bece57d226edd27ffc2bea6cf046d8f150a7a6f7 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 12 Jun 2023 10:02:52 +0200 Subject: [PATCH 050/219] Add work on OSNMA receiver --- src/core/system_parameters/gnss_crypto.cc | 156 ++++++++++------------ src/core/system_parameters/gnss_crypto.h | 5 + 2 files changed, 74 insertions(+), 87 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index df72beff0..e8ea0b719 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -43,10 +43,6 @@ Gnss_Crypto::Gnss_Crypto(const std::string& filePath) { -#if USE_OPENSSL_FALLBACK -#else - gnutls_global_init(); -#endif readPublicKeyFromPEM(filePath); } @@ -54,10 +50,13 @@ Gnss_Crypto::Gnss_Crypto(const std::string& filePath) Gnss_Crypto::~Gnss_Crypto() { #if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 +#else if (d_PublicKey != nullptr) { EC_KEY_free(d_PublicKey); } +#endif #else if (d_PublicKey != nullptr) { @@ -300,52 +299,6 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) std::cerr << "OpenSSL: error creating a BIO object with data read from file " << filePath << ". Aborting import" << std::endl; return; } -#if USE_OPENSSL_3 - // Read the PEM data from the BIO object - EVP_PKEY* evpKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); - BIO_free(bio); - if (!evpKey) - { - std::cerr << "OpenSSL: error reading the Public Key from file " << filePath << ". Aborting import" << std::endl; - return; - } - - // Check if the public key is an EC key - if (EVP_PKEY_base_id(evpKey) != EVP_PKEY_EC) - { - std::cerr << "OpenSSL: Public key imported from file " << filePath << " is not an EC key. Aborting import" << std::endl; - EVP_PKEY_free(evpKey); - return; - } - - // Get the EC key from the EVP_PKEY object - d_PublicKey = EVP_PKEY_get1_EC_KEY(evpKey); - EVP_PKEY_free(evpKey); - - if (d_PublicKey == nullptr) - { - std::cout << "OpenSSL: Failed to get the EC key from file " << filePath << ". Aborting import" << std::endl; - return; - } - - // Get the EC group from the EC key - const EC_GROUP* ecGroup = EC_KEY_get0_group(d_PublicKey); - - if (ecGroup == nullptr) - { - std::cout << "OpenSSL: Failed to extract the EC group from file " << filePath << ". Aborting import" << std::endl; - EC_KEY_free(d_PublicKey); - return; - } - - // Check if it is ECDSA P-256 - if (EC_GROUP_get_curve_name(ecGroup) != NID_X9_62_prime256v1) - { - std::cerr << "Invalid curve name in file " << filePath << ". Expected P-256. Aborting import" << std::endl; - EC_KEY_free(d_PublicKey); - return; - } -#else // Load the public key from the BIO d_PublicKey = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); BIO_free(bio); @@ -354,8 +307,8 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) std::cerr << "OpenSSL: error reading the Public Key from file " << filePath << ". Aborting import" << std::endl; return; } -#endif #else + gnutls_global_init(); gnutls_pubkey_t pubKey; gnutls_pubkey_init(&pubKey); d_PublicKey = &pubKey; @@ -370,44 +323,73 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) gnutls_pubkey_deinit(*d_PublicKey); return; } + gnutls_pubkey_deinit(pubKey); #endif std::cout << "Public key successfully read from file " << filePath << std::endl; } -// bool verify_signature(const std::vector& message, const std::vector& signature) -// { -// bool success = false; -// #if USE_OPENSSL_FALLBACK -/** Verifies that the given signature is valid ECDSA signature - * of the supplied hash value using the specified public key. - * \param type this parameter is ignored - * \param dgst pointer to the hash value - * \param dgstlen length of the hash value - * \param sig pointer to the DER encoded signature - * \param siglen length of the DER encoded signature - * \param eckey EC_KEY object containing a public EC key - * \return 1 if the signature is valid, 0 if the signature is invalid - * and -1 on error - */ -// int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, const unsigned char *sig, int siglen, EC_KEY *eckey);) -// int verification = ECDSA_verify(0, digest, SHA256_DIGEST_LENGTH, signature, signature_len, key_pair_obj); -// #else -// gnutls_global_init(); -// int result = gnutls_pubkey_verify_data(publicKey.data(), GNUTLS_SIGN_ECDSA_SHA256, digest.data(), digest.size(), signature.data(), signature.size()); -// success = (result == GNUTLS_E_SUCCESS); -// gnutls_global_deinit(); -// pubkey: Holds the public key -// algo: The signature algorithm used -// flags: Zero or an OR list of gnutls_certificate_verify_flags -// data: holds the signed data -// signature: contains the signature -// This function will verify the given signed data, using the parameters from the certificate. -// gnutls_pubkey_verify_data2 (gnutls_pubkey_t pubkey, gnutls_sign_algorithm_t algo, unsigned int flags, const gnutls_datum_t * data, const gnutls_datum_t * signature) -// #endif -// return success; -// } -// // bool verifyDigitalSignature(const unsigned char* signature, size_t signatureSize, const unsigned char* message, size_t messageSize, gnutls_pubkey_t publicKey) -// // { -// // int verificationStatus = gnutls_pubkey_verify_data(publicKey, GNUTLS_DIG_SHA256, 0, message, messageSize, signature, signatureSize); -// // return verificationStatus == 0; +bool Gnss_Crypto::verify_signature(const std::vector& message, const std::vector& signature) +{ + bool success = false; +#if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + EVP_PKEY_CTX* ctx; + ctx = EVP_PKEY_CTX_new(d_PublicKey, NULL /* no engine */); + bool do_operation = true; + if (!ctx) + { + do_operation = false; + } + if (EVP_PKEY_verify_init(ctx) <= 0) + { + do_operation = false; + } + if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) + { + do_operation = false; + } + int verification = 0; + if (do_operation) + { + verification = EVP_PKEY_verify(ctx, signature.data(), signature.size(), message.data(), message.size()); + } + if (verification == 1) + { + success = true; + } +#else + auto digest = this->computeSHA256(message); + int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, signature.data(), static_cast(signature.size()), d_PublicKey); + if (verification == 1) + { + success = true; + } + else if (verification == 0) + { + std::cerr << "OpenSSL: invalid signature found when verifying message" << std::endl; + } + +#endif +#else + // Verify the dummy hash using the public key + gnutls_datum_t dummyHash = {nullptr, 0}; + int ret2 = gnutls_pubkey_verify_hash2(*d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &dummyHash, &dummyHash); + if (ret2 != GNUTLS_E_SUCCESS) + { + std::cout << "GnuTLS: The Public Key is invalid" << std::endl; + } + gnutls_datum_t signature_{}; + signature_.data = const_cast(signature.data()); + signature_.size = signature.size(); + gnutls_datum_t data_{}; + data_.data = const_cast(message.data()); + data_.size = message.size(); + int ret = gnutls_pubkey_verify_data2(*d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &data_, &signature_); + if (ret == GNUTLS_E_SUCCESS) + { + success = true; + } +#endif + return success; +} \ No newline at end of file diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 4e160ac2c..5a89d1fef 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -43,13 +43,18 @@ public: std::vector computeSHA3_256(const std::vector& input) const; std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; + bool verify_signature(const std::vector& message, const std::vector& signature); void readPublicKeyFromPEM(const std::string& filePath); // void set_public_key(const std::vector& publickey); private: #if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 + EVP_PKEY* d_PublicKey; +#else EC_KEY* d_PublicKey = nullptr; +#endif #else gnutls_pubkey_t* d_PublicKey; #endif From 45196a5251fc848a365d4c121aedd527b60edaf5 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 12 Jun 2023 10:15:48 +0200 Subject: [PATCH 051/219] Fixes for OpenSSL 3.0 --- src/core/system_parameters/gnss_crypto.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index e8ea0b719..e82f27b22 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -300,7 +300,11 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) return; } // Load the public key from the BIO +#if USE_OPENSSL_3 + d_PublicKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); +#else d_PublicKey = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); +#endif BIO_free(bio); if (d_PublicKey == nullptr) { From 2debff63077f2bb90a4c69cc10e9b4d933f4d3d7 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 12 Jun 2023 12:52:00 +0200 Subject: [PATCH 052/219] Fix segfault with gnutls --- src/core/system_parameters/gnss_crypto.cc | 43 +++++++++++++---------- src/core/system_parameters/gnss_crypto.h | 2 +- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index e82f27b22..8667eb7fd 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -43,6 +43,10 @@ Gnss_Crypto::Gnss_Crypto(const std::string& filePath) { +#if USE_OPENSSL_FALLBACK +#else + // gnutls_global_init(); +#endif readPublicKeyFromPEM(filePath); } @@ -57,20 +61,17 @@ Gnss_Crypto::~Gnss_Crypto() EC_KEY_free(d_PublicKey); } #endif -#else - if (d_PublicKey != nullptr) - { - gnutls_pubkey_deinit(*d_PublicKey); - } - - gnutls_global_deinit(); #endif } bool Gnss_Crypto::have_public_key() const { +#if USE_OPENSSL_FALLBACK return (d_PublicKey != nullptr); +#else + return (d_PublicKey != gnutls_pubkey_t{}); +#endif } @@ -299,7 +300,6 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) std::cerr << "OpenSSL: error creating a BIO object with data read from file " << filePath << ". Aborting import" << std::endl; return; } - // Load the public key from the BIO #if USE_OPENSSL_3 d_PublicKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); #else @@ -312,22 +312,23 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) return; } #else - gnutls_global_init(); - gnutls_pubkey_t pubKey; - gnutls_pubkey_init(&pubKey); - d_PublicKey = &pubKey; // Import the PEM data gnutls_datum_t pemDatum = {const_cast(reinterpret_cast(pemContent.data())), static_cast(pemContent.size())}; - int ret = gnutls_pubkey_import(*d_PublicKey, &pemDatum, GNUTLS_X509_FMT_PEM); - if (ret < 0) + gnutls_pubkey_t pubkey; + gnutls_pubkey_init(&pubkey); + + int ret = gnutls_pubkey_import(pubkey, &pemDatum, GNUTLS_X509_FMT_PEM); + if (ret != GNUTLS_E_SUCCESS) { + gnutls_pubkey_deinit(pubkey); std::cerr << "GnuTLS: error reading the Public Key from file " << filePath - << ". (Error: " << gnutls_strerror(ret) << "). Aborting import" << std::endl; - gnutls_pubkey_deinit(*d_PublicKey); + << ". Aborting import" << std::endl; return; } - gnutls_pubkey_deinit(pubKey); + gnutls_pubkey_init(&d_PublicKey); + d_PublicKey = pubkey; + gnutls_pubkey_deinit(pubkey); #endif std::cout << "Public key successfully read from file " << filePath << std::endl; } @@ -335,6 +336,10 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) bool Gnss_Crypto::verify_signature(const std::vector& message, const std::vector& signature) { + if (!have_public_key()) + { + return false; + } bool success = false; #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 @@ -378,7 +383,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st #else // Verify the dummy hash using the public key gnutls_datum_t dummyHash = {nullptr, 0}; - int ret2 = gnutls_pubkey_verify_hash2(*d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &dummyHash, &dummyHash); + int ret2 = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &dummyHash, &dummyHash); if (ret2 != GNUTLS_E_SUCCESS) { std::cout << "GnuTLS: The Public Key is invalid" << std::endl; @@ -389,7 +394,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st gnutls_datum_t data_{}; data_.data = const_cast(message.data()); data_.size = message.size(); - int ret = gnutls_pubkey_verify_data2(*d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &data_, &signature_); + int ret = gnutls_pubkey_verify_data2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &data_, &signature_); if (ret == GNUTLS_E_SUCCESS) { success = true; diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 5a89d1fef..44103b28b 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -56,7 +56,7 @@ private: EC_KEY* d_PublicKey = nullptr; #endif #else - gnutls_pubkey_t* d_PublicKey; + gnutls_pubkey_t d_PublicKey{}; #endif }; From 7ca6c42f7bee1bbe7cc5076eaa0ee3c8320504ab Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 12 Jun 2023 16:04:05 +0200 Subject: [PATCH 053/219] Add work on OSNMA receiver --- src/core/system_parameters/gnss_crypto.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 8667eb7fd..316289953 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -344,7 +344,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 EVP_PKEY_CTX* ctx; - ctx = EVP_PKEY_CTX_new(d_PublicKey, NULL /* no engine */); + ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr /* no engine */); bool do_operation = true; if (!ctx) { @@ -367,6 +367,10 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st { success = true; } + else + { + std::cerr << "OpenSSL: message authentication failed" << std::endl; + } #else auto digest = this->computeSHA256(message); int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, signature.data(), static_cast(signature.size()), d_PublicKey); @@ -378,16 +382,13 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st { std::cerr << "OpenSSL: invalid signature found when verifying message" << std::endl; } + else + { + std::cerr << "OpenSSL: message authentication failed" << std::endl; + } #endif #else - // Verify the dummy hash using the public key - gnutls_datum_t dummyHash = {nullptr, 0}; - int ret2 = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &dummyHash, &dummyHash); - if (ret2 != GNUTLS_E_SUCCESS) - { - std::cout << "GnuTLS: The Public Key is invalid" << std::endl; - } gnutls_datum_t signature_{}; signature_.data = const_cast(signature.data()); signature_.size = signature.size(); @@ -395,10 +396,14 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st data_.data = const_cast(message.data()); data_.size = message.size(); int ret = gnutls_pubkey_verify_data2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &data_, &signature_); - if (ret == GNUTLS_E_SUCCESS) + if (ret >= 0) { success = true; } + else + { + std::cerr << "GnuTLS: message authentication failed" << std::endl; + } #endif return success; } \ No newline at end of file From 9479f145521bbae872723ed6fdb7d4bace73c145 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 13 Jun 2023 13:36:30 +0200 Subject: [PATCH 054/219] Read MACK key --- src/core/libs/osnma_msg_receiver.cc | 89 ++++++++++++++++++++----- src/core/libs/osnma_msg_receiver.h | 6 +- src/core/system_parameters/osnma_data.h | 1 - 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 8f7b82051..6028506c5 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -305,7 +305,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { MSG.push_back(dsm_msg[i]); } - + std::vector message = MSG; for (uint16_t k = 0; k < l_ds_bytes; k++) { MSG.push_back(d_osnma_data.d_dsm_kroot_message.ds[k]); @@ -334,12 +334,20 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // check DS signature if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { + bool authenticated = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); LOG(WARNING) << "OSNMA: DSM-KROOT message received ok."; std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) - << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 - << " validated" << std::endl; + << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; + if (authenticated) + { + std::cout << " authenticated" << std::endl; + } + else + { + std::cout << " validated" << std::endl; + } std::cout << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; @@ -428,9 +436,8 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma if (d_osnma_data.d_dsm_kroot_message.ts != 0) { read_mack_header(); - read_mack_info_and_tags(); - read_mack_key(); - read_mack_padding(); + read_mack_body(); + d_old_mack_message = d_osnma_data.d_mack_message; } } @@ -496,7 +503,7 @@ void osnma_msg_receiver::read_mack_header() } -void osnma_msg_receiver::read_mack_info_and_tags() +void osnma_msg_receiver::read_mack_body() { uint8_t lt_bits = 0; const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); @@ -518,7 +525,7 @@ void osnma_msg_receiver::read_mack_info_and_tags() { return; } - uint16_t nt = std::floor((480.0 + float(lk_bits)) / (float(lt_bits) + 16.0)); + uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); for (uint16_t k = 0; k < (nt - 1); k++) { @@ -537,6 +544,14 @@ void osnma_msg_receiver::read_mack_info_and_tags() PRN_d += d_mack_message[6 + step]; ADKD += ((d_mack_message[7 + step] & 0xF0) >> 4); cop += (d_mack_message[7 + step] & 0x0F); + if (k == (nt - 2)) + { + d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); + for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) + { + d_osnma_data.d_mack_message.key[j] = d_mack_message[8 + step + j]; + } + } } else { @@ -547,6 +562,14 @@ void osnma_msg_receiver::read_mack_info_and_tags() PRN_d += (d_mack_message[6 + step] & 0xF0) >> 4; ADKD += (d_mack_message[6 + step] & 0x0F); cop += (d_mack_message[7 + step] & 0xF0) >> 4; + if (k == (nt - 2)) + { + d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); + for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) + { + d_osnma_data.d_mack_message.key[j] = ((d_mack_message[7 + step + j] & 0x0F) << 4) + ((d_mack_message[8 + step + j] & 0xF0) >> 4); + } + } } } else if (lt_bits == 24) @@ -557,6 +580,14 @@ void osnma_msg_receiver::read_mack_info_and_tags() PRN_d += d_mack_message[8 + k * 5]; ADKD += ((d_mack_message[9 + k * 5] & 0xF0) >> 4); cop += (d_mack_message[9 + k * 5] & 0x0F); + if (k == (nt - 2)) + { + d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); + for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) + { + d_osnma_data.d_mack_message.key[j] = d_mack_message[10 + k * 5 + j]; + } + } } else if (lt_bits == 28) { @@ -570,6 +601,14 @@ void osnma_msg_receiver::read_mack_info_and_tags() PRN_d += d_mack_message[9 + step]; ADKD += ((d_mack_message[10 + step] & 0xF0) >> 4); cop += (d_mack_message[10 + step] & 0x0F); + if (k == (nt - 2)) + { + d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); + for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) + { + d_osnma_data.d_mack_message.key[j] = d_mack_message[11 + step + j]; + } + } } else { @@ -581,6 +620,14 @@ void osnma_msg_receiver::read_mack_info_and_tags() PRN_d += ((d_mack_message[9 + step] & 0xF0) >> 4); ADKD += (d_mack_message[9 + step] & 0x0F); cop += ((d_mack_message[10 + step] & 0xF0) >> 4); + if (k == (nt - 2)) + { + d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); + for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) + { + d_osnma_data.d_mack_message.key[j] = ((d_mack_message[10 + step + j] & 0x0F) << 4) + ((d_mack_message[11 + step + j] & 0xF0) >> 4); + } + } } } else if (lt_bits == 32) @@ -592,6 +639,14 @@ void osnma_msg_receiver::read_mack_info_and_tags() PRN_d += d_mack_message[10 + k * 6]; ADKD += ((d_mack_message[11 + k * 6] & 0xF0) >> 4); cop += (d_mack_message[11 + k * 6] & 0x0F); + if (k == (nt - 2)) + { + d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); + for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) + { + d_osnma_data.d_mack_message.key[j] = d_mack_message[12 + k * 6 + j]; + } + } } else if (lt_bits == 40) { @@ -603,6 +658,14 @@ void osnma_msg_receiver::read_mack_info_and_tags() PRN_d += d_mack_message[12 + k * 7]; ADKD += ((d_mack_message[13 + k * 7] & 0xF0) >> 4); cop += (d_mack_message[13 + k * 7] & 0x0F); + if (k == (nt - 2)) + { + d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); + for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) + { + d_osnma_data.d_mack_message.key[j] = d_mack_message[14 + k * 7 + j]; + } + } } d_osnma_data.d_mack_message.tag_and_info[k].tag = tag; d_osnma_data.d_mack_message.tag_and_info[k].tag_info.PRN_d = PRN_d; @@ -610,13 +673,3 @@ void osnma_msg_receiver::read_mack_info_and_tags() d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = cop; } } - - -void osnma_msg_receiver::read_mack_key() -{ -} - - -void osnma_msg_receiver::read_mack_padding() -{ -} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index bf8a87b10..328e3d8d9 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -67,9 +67,9 @@ private: void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); void read_mack_header(); - void read_mack_info_and_tags(); - void read_mack_key(); - void read_mack_padding(); + void read_mack_body(); + + MACK_message d_old_mack_message; std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 315848a70..890eeb3a5 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -116,7 +116,6 @@ public: MACK_header header; std::vector tag_and_info; std::vector key; - std::vector padding; }; /*! From 5ebc544ff671d59a4a7c2bed49c6391ede4859d5 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 13 Jun 2023 14:30:53 +0200 Subject: [PATCH 055/219] Add table 16 --- src/core/system_parameters/Galileo_OSNMA.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 2cb486248..4a5d2b28c 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -161,6 +161,24 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} const std::string PEMFILE_DEFAULT("./OSNMA_PublicKey_20210920133026.pem"); + + +class Mack_lookup +{ +public: + Mack_lookup() = default; + uint8_t msg{}; + uint8_t nt{}; + std::vector sequence1; + std::vector sequence2; +}; + +const std::unordered_map OSNMA_TABLE_16 = { + {27, {2, 6, {"00S", "00E", "00E", "00E", "12S", "00E"}, {"00S ", "00E", "00E", "04S", "12S", "00E"}}}, + {28, {2, 10, {"00S", "00E", "00E", "00E", "00S", "00E", "00E", "12S", "00E", "00E"}, {"00S", "00E", "00E", "00S", "00E", "00E", "04S", "12S", "00E", "00E"}}}, + {31, {2, 5, {"00S", "00E", "00E", "12S", "00E"}, {"00S", "00E", "00E", "12S", "04S"}}}, + {33, {2, 6, {"00S", "00E", "04S", "00E", "12S", "00E"}, {"00S", "00E", "00E", "12S", "00E", "12E"}}}}; + /** \} */ /** \} */ #endif // GNSS_SDR_GALILEO_OSNMA_H \ No newline at end of file From 30b0230680a753b62515980fcef2d8c1a8d488ce Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 13 Jun 2023 16:41:15 +0200 Subject: [PATCH 056/219] Add work on MACSEQ validation --- src/core/libs/osnma_msg_receiver.cc | 44 +++++++++++++++++++++++++++-- src/core/libs/osnma_msg_receiver.h | 13 ++++----- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 6028506c5..4926c51dc 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -58,6 +58,7 @@ osnma_msg_receiver::osnma_msg_receiver( { d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(pemFilePath); + d_old_mack_message.set_capacity(10); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -352,7 +353,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; } - // Validate signature } } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) @@ -437,7 +437,47 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma { read_mack_header(); read_mack_body(); - d_old_mack_message = d_osnma_data.d_mack_message; + d_old_mack_message.push_back(d_osnma_data.d_mack_message); + + // MACSEQ validation + uint32_t GST_SF = osnma_msg->TOW_sf0; + + // Are there flexible tags? + std::vector m(5); + m[0] = static_cast(osnma_msg->PRN); // PRN_A + m[1] = ((GST_SF & 0xF000) >> 24); + m[2] = ((GST_SF & 0x0F00) >> 16); + m[3] = ((GST_SF & 0x00F0) >> 8); + m[4] = (GST_SF & 0x000F); + + std::vector applicable_key; + // if ADKD=12, pick d_old_mack_message.front() if d_old_mack_message[10] is full + // otherwise pick d_old_mack_message.back() + applicable_key = d_old_mack_message.back().key; + std::vector mac; + if (d_osnma_data.d_dsm_kroot_message.mf == 0) + { + mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + } + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) + { + mac = d_crypto->computeCMAC_AES(applicable_key, m); + } + uint16_t mac_msb = 0; + if (!mac.empty()) + { + mac_msb = (mac[0] << 8) + mac[1]; + } + uint16_t computed_macseq = (mac_msb & 0x0FFF); + int num_tags_added = 0; + if (computed_macseq == d_osnma_data.d_mack_message.header.macseq) + { + std::cout << "OSNMA: MACSEQ authenticated for PRN_A " + << osnma_msg->PRN << " with WN=" + << osnma_msg->WN_sf0 << ", TOW=" + << osnma_msg->TOW_sf0 << ". Tags added: " + << num_tags_added << std::endl; + } } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 328e3d8d9..dbe6f5493 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -23,10 +23,11 @@ #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 -#include // for gr::block -#include // for pmt::pmt_t -#include // for std::array -#include // for std::shared_ptr +#include +#include // for gr::block +#include // for pmt::pmt_t +#include // for std::array +#include // for std::shared_ptr #include #include @@ -65,12 +66,10 @@ private: void read_dsm_block(const std::shared_ptr& osnma_msg); void read_mack_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); - void read_mack_header(); void read_mack_body(); - MACK_message d_old_mack_message; - + boost::circular_buffer d_old_mack_message; std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; From 59b783d8399acea08922c79b9139fb02a6e4a1c8 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 14 Jun 2023 15:32:22 +0200 Subject: [PATCH 057/219] Bug fixes --- src/core/libs/osnma_msg_receiver.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 4926c51dc..d82eb3f68 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -427,9 +427,9 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma uint32_t index = 0; for (uint32_t value : osnma_msg->mack) { - d_mack_message[index] = static_cast((value & 0xFF000000) >> 6); - d_mack_message[index + 1] = static_cast((value & 0x00FF0000) >> 4); - d_mack_message[index + 2] = static_cast((value & 0x0000FF00) >> 2); + d_mack_message[index] = static_cast((value & 0xFF000000) >> 24); + d_mack_message[index + 1] = static_cast((value & 0x00FF0000) >> 16); + d_mack_message[index + 2] = static_cast((value & 0x0000FF00) >> 8); d_mack_message[index + 3] = static_cast(value & 0x000000FF); index = index + 4; } @@ -508,7 +508,7 @@ void osnma_msg_receiver::read_mack_header() else if (lt_bits == 24) { first_lt_bits += static_cast(d_mack_message[2]); - macseq += (static_cast(d_mack_message[3]) << 8); + macseq += (static_cast(d_mack_message[3]) << 4); macseq += (static_cast(d_mack_message[4] & 0xF0) >> 4); cop += (d_mack_message[4] & 0x0F); } @@ -524,7 +524,7 @@ void osnma_msg_receiver::read_mack_header() { first_lt_bits += (static_cast(d_mack_message[2]) << 8); first_lt_bits += static_cast(d_mack_message[3]); - macseq += (static_cast(d_mack_message[4]) << 8); + macseq += (static_cast(d_mack_message[4]) << 4); macseq += (static_cast(d_mack_message[5] & 0xF0) >> 4); cop += (d_mack_message[5] & 0x0F); } @@ -533,13 +533,13 @@ void osnma_msg_receiver::read_mack_header() first_lt_bits += (static_cast(d_mack_message[2]) << 16); first_lt_bits += (static_cast(d_mack_message[3]) << 8); first_lt_bits += static_cast(d_mack_message[4]); - macseq += (static_cast(d_mack_message[5]) << 8); + macseq += (static_cast(d_mack_message[5]) << 4); macseq += (static_cast(d_mack_message[6] & 0xF0) >> 4); cop += (d_mack_message[6] & 0x0F); } d_osnma_data.d_mack_message.header.tag0 = first_lt_bits; d_osnma_data.d_mack_message.header.macseq = macseq; - d_osnma_data.d_mack_message.header.macseq = cop; + d_osnma_data.d_mack_message.header.cop = cop; } From 020d711f5af4c0949d92028c4bc7b14669dd29da Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 15 Jun 2023 09:31:26 +0200 Subject: [PATCH 058/219] Fix leakage --- src/core/system_parameters/gnss_crypto.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 316289953..923483ce6 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -290,7 +290,6 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) } return; } - std::vector publicKey; std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); #if USE_OPENSSL_FALLBACK // Create a BIO object from the string data @@ -326,7 +325,6 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) << ". Aborting import" << std::endl; return; } - gnutls_pubkey_init(&d_PublicKey); d_PublicKey = pubkey; gnutls_pubkey_deinit(pubkey); #endif @@ -346,6 +344,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st EVP_PKEY_CTX* ctx; ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr /* no engine */); bool do_operation = true; + if (!ctx) { do_operation = false; @@ -363,6 +362,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st { verification = EVP_PKEY_verify(ctx, signature.data(), signature.size(), message.data(), message.size()); } + EVP_PKEY_CTX_free(ctx); if (verification == 1) { success = true; From 6fcf6d79b349a8ff67ef3aa8208fe10ef6a4681b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 19 Jun 2023 09:57:24 +0200 Subject: [PATCH 059/219] Add the Merkle Tree --- src/core/libs/osnma_msg_receiver.cc | 13 +- src/core/libs/osnma_msg_receiver.h | 6 +- src/core/receiver/gnss_flowgraph.cc | 3 +- src/core/system_parameters/CMakeLists.txt | 1 + src/core/system_parameters/Galileo_OSNMA.h | 2 +- src/core/system_parameters/gnss_crypto.cc | 180 +++++++++++++++++++-- src/core/system_parameters/gnss_crypto.h | 11 +- 7 files changed, 190 insertions(+), 26 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index d82eb3f68..3a6b81999 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -45,19 +45,20 @@ namespace wht = std; #endif -osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath) +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath) { - return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath)); + return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath, merkleFilePath)); } osnma_msg_receiver::osnma_msg_receiver( - const std::string& pemFilePath) : gr::block("osnma_msg_receiver", - gr::io_signature::make(0, 0, 0), - gr::io_signature::make(0, 0, 0)) + const std::string& pemFilePath, + const std::string& merkleFilePath) : gr::block("osnma_msg_receiver", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) { d_dsm_reader = std::make_unique(); - d_crypto = std::make_unique(pemFilePath); + d_crypto = std::make_unique(pemFilePath, merkleFilePath); d_old_mack_message.set_capacity(10); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index dbe6f5493..c2a2a7d90 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -42,7 +42,7 @@ class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; -osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath); +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); /*! * \brief GNU Radio block that receives asynchronous OSNMA messages @@ -56,8 +56,8 @@ public: ~osnma_msg_receiver() = default; //!< Default destructor private: - friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath); - explicit osnma_msg_receiver(const std::string& pemFilePath); + friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); + osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 3856876ca..2d1e3676f 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -120,7 +120,8 @@ void GNSSFlowgraph::init() { enable_osnma_rx_ = true; auto pemFilePath = configuration_->property("GNSS-SDR.OSNMA_pem", PEMFILE_DEFAULT); - osnma_rx_ = osnma_msg_receiver_make(pemFilePath); + auto merKleTreePath = configuration_->property("GNSS-SDR.OSNMA_MerkleTree", MERKLEFILE_DEFAULT); + osnma_rx_ = osnma_msg_receiver_make(pemFilePath, merKleTreePath); } else { diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index c8b4c2d57..9db20a317 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -123,6 +123,7 @@ target_link_libraries(core_system_parameters PRIVATE Gflags::gflags Glog::glog + Pugixml::pugixml ) # for gnss_sdr_make_unique.h diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 4a5d2b28c..5be8dfcce 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -161,7 +161,7 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} const std::string PEMFILE_DEFAULT("./OSNMA_PublicKey_20210920133026.pem"); - +const std::string MERKLEFILE_DEFAULT("./OSNMA_MerkleTree_20210920133026.xml"); class Mack_lookup { diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 923483ce6..eaab09bb5 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -17,6 +17,7 @@ #include "gnss_crypto.h" #include "Galileo_OSNMA.h" +#include #include #include #include @@ -41,13 +42,14 @@ #endif -Gnss_Crypto::Gnss_Crypto(const std::string& filePath) +Gnss_Crypto::Gnss_Crypto(const std::string& pemFilePath, const std::string& merkleTreePath) { #if USE_OPENSSL_FALLBACK #else // gnutls_global_init(); #endif - readPublicKeyFromPEM(filePath); + readPublicKeyFromPEM(pemFilePath); + read_merkle_xml(merkleTreePath); } @@ -75,6 +77,121 @@ bool Gnss_Crypto::have_public_key() const } +std::string Gnss_Crypto::convert_to_utf8_str(const std::vector& input) const +{ + const char hex[] = "0123456789ABCDEF"; + std::string str(input.size() * 2, '0'); + for (size_t i = 0; i < input.size(); i++) + { + str[(i * 2) + 0] = hex[((input[i] & 0xF0) >> 4)]; + str[(i * 2) + 1] = hex[((input[i] & 0x0F))]; + } + return str; +} + + +std::vector Gnss_Crypto::convert_from_hex_str(const std::string& input) const +{ + std::vector result; + + // Iterate over the input string in pairs + for (size_t i = 0; i < input.length(); i += 2) + { + // Extract two hexadecimal characters from the input string + std::string hexByte = input.substr(i, 2); + + // Convert the hexadecimal string to an integer value + uint8_t value = static_cast(std::stoul(hexByte, nullptr, 16)); + + // Append the value to the result vector + result.push_back(value); + } + + return result; +} + + +void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) +{ + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_file(merkleFilePath.c_str()); + if (!result) + { + // XML file not found + // If it was not the default, maybe it is a configuration error + if (merkleFilePath != MERKLEFILE_DEFAULT) + { + std::cerr << "File " << merkleFilePath << " not found" << std::endl; + } + return; + } + try + { + pugi::xml_node root = doc.child("signalData"); + pugi::xml_node header = root.child("header"); + pugi::xml_node body = root.child("body"); + + // Accessing data from the header + pugi::xml_node galHeader = header.child("GAL-header"); + pugi::xml_node source = galHeader.child("source").child("GAL-EXT-GOC-SC-GLAd"); + pugi::xml_node destination = galHeader.child("destination").child("GAL-EXT-GOC-SC-GLAd"); + std::string issueDate = galHeader.child("issueDate").text().get(); + std::string signalVersion = galHeader.child("signalVersion").text().get(); + std::string dataVersion = galHeader.child("dataVersion").text().get(); + + std::cout << " Source: " << source.child_value("mission") << " - " << source.child_value("segment") << " - " << source.child_value("element") << std::endl; + std::cout << " Destination: " << destination.child_value("mission") << " - " << destination.child_value("segment") << " - " << destination.child_value("element") << std::endl; + std::cout << " Issue Date: " << issueDate << std::endl; + std::cout << " Signal Version: " << signalVersion << std::endl; + std::cout << " Data Version: " << dataVersion << std::endl; + + // Accessing data from the body + pugi::xml_node merkleTree = body.child("MerkleTree"); + + int n = std::stoi(merkleTree.child_value("N")); + std::string hashFunction = merkleTree.child_value("HashFunction"); + + std::cout << " N: " << n << std::endl; + std::cout << " Hash Function: " << hashFunction << std::endl; + + for (pugi::xml_node publicKey : merkleTree.children("PublicKey")) + { + int i = std::stoi(publicKey.child_value("i")); + std::string pkid = publicKey.child_value("PKID"); + int lengthInBits = std::stoi(publicKey.child_value("lengthInBits")); + std::string point = publicKey.child_value("point"); + std::string pkType = publicKey.child_value("PKType"); + + std::cout << " Public Key: " << i << std::endl; + std::cout << " PKID: " << pkid << std::endl; + std::cout << " Length in Bits: " << lengthInBits << std::endl; + std::cout << " Point: " << point << std::endl; + std::cout << " PK Type: " << pkType << std::endl; + } + for (pugi::xml_node treeNode : merkleTree.children("TreeNode")) + { + int j = std::stoi(treeNode.child_value("j")); + int i = std::stoi(treeNode.child_value("i")); + int lengthInBits = std::stoi(treeNode.child_value("lengthInBits")); + std::cout << " Node length (bits): " << lengthInBits << std::endl; + std::string x_ji = treeNode.child_value("x_ji"); + std::cout << " Size string (bytes): " << x_ji.size() << std::endl; + std::cout << " m_" << j << "_" << i << " = " << x_ji << std::endl; + std::vector myVector2 = convert_from_hex_str(x_ji); + std::cout << "After the conversion is " << convert_to_utf8_str(myVector2) << std::endl; + std::vector myVector(x_ji.begin(), x_ji.end()); // No + std::cout << " Length Tree node (bytes): " << myVector.size() << std::endl; + } + } + catch (const std::exception& e) + { + std::cerr << "Exception raised reading the " << merkleFilePath << " file: " << e.what() << '\n'; + return; + } + std::cout << "Merkle Tree successfully read from file " << merkleFilePath << std::endl; +} + + // void Gnss_Crypto::set_public_key(const std::vector& publickey) // { // } @@ -276,17 +393,17 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke } -void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) +void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) { // Open the .pem file - std::ifstream pemFile(filePath); + std::ifstream pemFile(pemFilePath); if (!pemFile) { // PEM file not found - // If it not was the default, maybe it is a configuration error - if (filePath != PEMFILE_DEFAULT) + // If it was not the default, maybe it is a configuration error + if (pemFilePath != PEMFILE_DEFAULT) { - std::cerr << "File " << filePath << " not found" << std::endl; + std::cerr << "File " << pemFilePath << " not found" << std::endl; } return; } @@ -296,7 +413,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) BIO* bio = BIO_new_mem_buf(pemContent.c_str(), pemContent.length()); if (!bio) { - std::cerr << "OpenSSL: error creating a BIO object with data read from file " << filePath << ". Aborting import" << std::endl; + std::cerr << "OpenSSL: error creating a BIO object with data read from file " << pemFilePath << ". Aborting import" << std::endl; return; } #if USE_OPENSSL_3 @@ -307,7 +424,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) BIO_free(bio); if (d_PublicKey == nullptr) { - std::cerr << "OpenSSL: error reading the Public Key from file " << filePath << ". Aborting import" << std::endl; + std::cerr << "OpenSSL: error reading the Public Key from file " << pemFilePath << ". Aborting import" << std::endl; return; } #else @@ -321,14 +438,14 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& filePath) { gnutls_pubkey_deinit(pubkey); std::cerr << "GnuTLS: error reading the Public Key from file " - << filePath + << pemFilePath << ". Aborting import" << std::endl; return; } d_PublicKey = pubkey; gnutls_pubkey_deinit(pubkey); #endif - std::cout << "Public key successfully read from file " << filePath << std::endl; + std::cout << "Public key successfully read from file " << pemFilePath << std::endl; } @@ -389,6 +506,11 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st #endif #else + unsigned int bit_size; + if (gnutls_pubkey_get_pk_algorithm(d_PublicKey, &bit_size) != GNUTLS_PK_ECDSA) + { + std::cout << "GnuTLS: the Public Key does not contain a ECDSA key. Aborting signature verification" << std::endl; + } gnutls_datum_t signature_{}; signature_.data = const_cast(signature.data()); signature_.size = signature.size(); @@ -406,4 +528,38 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } #endif return success; -} \ No newline at end of file +} + + +std::vector Gnss_Crypto::getMerkleRoot(const std::vector>& merkle) +{ + if (merkle.empty()) + { + return {}; + } + else if (merkle.size() == 1) + { + return this->computeSHA3_256(merkle[0]); + } + + std::vector> new_merkle = merkle; + + while (new_merkle.size() > 1) + { + if (new_merkle.size() % 2 == 1) + new_merkle.push_back(merkle.back()); + + std::vector> result; + + for (size_t i = 0; i < new_merkle.size(); i += 2) + { + std::vector var1 = this->computeSHA3_256(new_merkle[i]); + std::vector var2 = this->computeSHA3_256(new_merkle[i + 1]); + var1.insert(var1.end(), var2.begin(), var2.end()); + std::vector hash = this->computeSHA3_256(var1); + result.push_back(hash); + } + new_merkle = result; + } + return new_merkle[0]; +} diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 44103b28b..c6acc728f 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -37,15 +37,20 @@ class Gnss_Crypto public: Gnss_Crypto() = default; ~Gnss_Crypto(); - explicit Gnss_Crypto(const std::string& filePath); + Gnss_Crypto(const std::string& pemFilePath, const std::string& merkleTreePath); bool have_public_key() const; + std::string convert_to_utf8_str(const std::vector& input) const; + std::vector convert_from_hex_str(const std::string& input) const; std::vector computeSHA256(const std::vector& input) const; std::vector computeSHA3_256(const std::vector& input) const; std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; - bool verify_signature(const std::vector& message, const std::vector& signature); - void readPublicKeyFromPEM(const std::string& filePath); + bool verify_signature(const std::vector& message, const std::vector& signature); + void readPublicKeyFromPEM(const std::string& pemFilePath); + void read_merkle_xml(const std::string& merkleFilePath); + std::vector getMerkleRoot(const std::vector>& merkle); + // void set_public_key(const std::vector& publickey); private: From e32a65b3a3def22bdf8f1e1a351194c872d8bf9c Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 19 Jun 2023 11:07:44 +0200 Subject: [PATCH 060/219] Fix building in macOS --- src/core/system_parameters/Galileo_OSNMA.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 5be8dfcce..2cf1104af 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -167,6 +167,13 @@ class Mack_lookup { public: Mack_lookup() = default; + Mack_lookup(uint8_t msg_, + uint8_t nt_, + const std::vector& s1_, + const std::vector& s2_) : msg(msg_), + nt(nt_), + sequence1(s1_), + sequence2(s2_){}; uint8_t msg{}; uint8_t nt{}; std::vector sequence1; From 2a41ed82783fe3620abbc5557bf803ab4caddf2f Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 19 Jun 2023 14:56:53 +0200 Subject: [PATCH 061/219] Store roots from Merkle Tree file, pick up defaults if not found --- src/core/system_parameters/gnss_crypto.cc | 49 +++++++++++++++++++---- src/core/system_parameters/gnss_crypto.h | 6 +++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index eaab09bb5..0492b1d23 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -101,7 +101,7 @@ std::vector Gnss_Crypto::convert_from_hex_str(const std::string& input) std::string hexByte = input.substr(i, 2); // Convert the hexadecimal string to an integer value - uint8_t value = static_cast(std::stoul(hexByte, nullptr, 16)); + auto value = static_cast(std::stoul(hexByte, nullptr, 16)); // Append the value to the result vector result.push_back(value); @@ -118,11 +118,18 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) if (!result) { // XML file not found - // If it was not the default, maybe it is a configuration error + // If it was not the default, maybe it is a configuration error, warn user if (merkleFilePath != MERKLEFILE_DEFAULT) { std::cerr << "File " << merkleFilePath << " not found" << std::endl; } + // fill default values + d_x_4_0 = convert_from_hex_str("C5B2A3BD24E819EF82B17ACE83C0E7F41D34AC9B488CB7CE4D765FDE7DCA0297"); + d_x_3_1 = convert_from_hex_str("C8314BA8084E0CA101E595E88F170012F1F5CE71EEEFAB27334283E15935E8E6"); + d_x_2_1 = convert_from_hex_str("6FB21E4DDF3F8E517A5C5B1C6D843F9236707FF11D96F9BA954BFEAA3A44E56B"); + d_x_1_1 = convert_from_hex_str("86E53A50D345FBDAD49835F3363EE4A7262DB738CBDFC399229AE2803679300D"); + d_x_0_0 = convert_from_hex_str("40CAA1D70F7B1D370219674A25721311170A49DE4E4A0CE4FE328674E01CF750"); + d_x_0_1 = convert_from_hex_str("AA1A8B68E5DB293106B5BC8806F9790E8ACF8DC2D28A6EF6C1AC7233A9813D3F"); return; } try @@ -177,15 +184,41 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) std::string x_ji = treeNode.child_value("x_ji"); std::cout << " Size string (bytes): " << x_ji.size() << std::endl; std::cout << " m_" << j << "_" << i << " = " << x_ji << std::endl; - std::vector myVector2 = convert_from_hex_str(x_ji); - std::cout << "After the conversion is " << convert_to_utf8_str(myVector2) << std::endl; - std::vector myVector(x_ji.begin(), x_ji.end()); // No - std::cout << " Length Tree node (bytes): " << myVector.size() << std::endl; + if (j == 4 && i == 0) + { + d_x_4_0 = convert_from_hex_str(x_ji); + } + if (j == 3 && i == 1) + { + d_x_3_1 = convert_from_hex_str(x_ji); + } + if (j == 2 && i == 1) + { + d_x_2_1 = convert_from_hex_str(x_ji); + } + if (j == 1 && i == 1) + { + d_x_1_1 = convert_from_hex_str(x_ji); + } + if (j == 0 && i == 0) + { + d_x_0_0 = convert_from_hex_str(x_ji); + } + if (j == 0 && i == 1) + { + d_x_0_0 = convert_from_hex_str(x_ji); + } } } catch (const std::exception& e) { std::cerr << "Exception raised reading the " << merkleFilePath << " file: " << e.what() << '\n'; + d_x_4_0 = convert_from_hex_str("C5B2A3BD24E819EF82B17ACE83C0E7F41D34AC9B488CB7CE4D765FDE7DCA0297"); + d_x_3_1 = convert_from_hex_str("C8314BA8084E0CA101E595E88F170012F1F5CE71EEEFAB27334283E15935E8E6"); + d_x_2_1 = convert_from_hex_str("6FB21E4DDF3F8E517A5C5B1C6D843F9236707FF11D96F9BA954BFEAA3A44E56B"); + d_x_1_1 = convert_from_hex_str("86E53A50D345FBDAD49835F3363EE4A7262DB738CBDFC399229AE2803679300D"); + d_x_0_0 = convert_from_hex_str("40CAA1D70F7B1D370219674A25721311170A49DE4E4A0CE4FE328674E01CF750"); + d_x_0_1 = convert_from_hex_str("AA1A8B68E5DB293106B5BC8806F9790E8ACF8DC2D28A6EF6C1AC7233A9813D3F"); return; } std::cout << "Merkle Tree successfully read from file " << merkleFilePath << std::endl; @@ -547,7 +580,9 @@ std::vector Gnss_Crypto::getMerkleRoot(const std::vector 1) { if (new_merkle.size() % 2 == 1) - new_merkle.push_back(merkle.back()); + { + new_merkle.push_back(merkle.back()); + } std::vector> result; diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index c6acc728f..83137f15e 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -63,6 +63,12 @@ private: #else gnutls_pubkey_t d_PublicKey{}; #endif + std::vector d_x_4_0; + std::vector d_x_3_1; + std::vector d_x_2_1; + std::vector d_x_1_1; + std::vector d_x_0_0; + std::vector d_x_0_1; }; /** \} */ From 2649406538d58cd8952a3c5a9980895475ca7dee Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 20 Jun 2023 08:20:45 +0200 Subject: [PATCH 062/219] Make clang-tidy happy --- src/core/system_parameters/gnss_crypto.cc | 2 +- src/core/system_parameters/gnss_crypto.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 0492b1d23..eab8ab23e 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -564,7 +564,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } -std::vector Gnss_Crypto::getMerkleRoot(const std::vector>& merkle) +std::vector Gnss_Crypto::getMerkleRoot(const std::vector>& merkle) const { if (merkle.empty()) { diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 83137f15e..c544020a9 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -49,7 +49,7 @@ public: bool verify_signature(const std::vector& message, const std::vector& signature); void readPublicKeyFromPEM(const std::string& pemFilePath); void read_merkle_xml(const std::string& merkleFilePath); - std::vector getMerkleRoot(const std::vector>& merkle); + std::vector getMerkleRoot(const std::vector>& merkle) const; // void set_public_key(const std::vector& publickey); From 28474b824f364756baa573bc0d74e8d93bcf8a86 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 3 Jul 2023 21:28:33 +0200 Subject: [PATCH 063/219] Reorder code --- src/core/libs/osnma_msg_receiver.cc | 88 +++++++++++++++-------------- src/core/libs/osnma_msg_receiver.h | 3 +- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 3a6b81999..39ac24843 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -438,47 +438,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma { read_mack_header(); read_mack_body(); - d_old_mack_message.push_back(d_osnma_data.d_mack_message); - - // MACSEQ validation - uint32_t GST_SF = osnma_msg->TOW_sf0; - - // Are there flexible tags? - std::vector m(5); - m[0] = static_cast(osnma_msg->PRN); // PRN_A - m[1] = ((GST_SF & 0xF000) >> 24); - m[2] = ((GST_SF & 0x0F00) >> 16); - m[3] = ((GST_SF & 0x00F0) >> 8); - m[4] = (GST_SF & 0x000F); - - std::vector applicable_key; - // if ADKD=12, pick d_old_mack_message.front() if d_old_mack_message[10] is full - // otherwise pick d_old_mack_message.back() - applicable_key = d_old_mack_message.back().key; - std::vector mac; - if (d_osnma_data.d_dsm_kroot_message.mf == 0) - { - mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); - } - else if (d_osnma_data.d_dsm_kroot_message.mf == 1) - { - mac = d_crypto->computeCMAC_AES(applicable_key, m); - } - uint16_t mac_msb = 0; - if (!mac.empty()) - { - mac_msb = (mac[0] << 8) + mac[1]; - } - uint16_t computed_macseq = (mac_msb & 0x0FFF); - int num_tags_added = 0; - if (computed_macseq == d_osnma_data.d_mack_message.header.macseq) - { - std::cout << "OSNMA: MACSEQ authenticated for PRN_A " - << osnma_msg->PRN << " with WN=" - << osnma_msg->WN_sf0 << ", TOW=" - << osnma_msg->TOW_sf0 << ". Tags added: " - << num_tags_added << std::endl; - } + process_mack_message(osnma_msg); } } @@ -714,3 +674,49 @@ void osnma_msg_receiver::read_mack_body() d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = cop; } } + + +void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) +{ + d_old_mack_message.push_back(d_osnma_data.d_mack_message); + + // MACSEQ validation + uint32_t GST_SF = osnma_msg->TOW_sf0; + + // Are there flexible tags? + std::vector m(5); + m[0] = static_cast(osnma_msg->PRN); // PRN_A + m[1] = ((GST_SF & 0xF000) >> 24); + m[2] = ((GST_SF & 0x0F00) >> 16); + m[3] = ((GST_SF & 0x00F0) >> 8); + m[4] = (GST_SF & 0x000F); + + std::vector applicable_key; + // if ADKD=12, pick d_old_mack_message.front() if d_old_mack_message[10] is full + // otherwise pick d_old_mack_message.back() + applicable_key = d_old_mack_message.back().key; + std::vector mac; + if (d_osnma_data.d_dsm_kroot_message.mf == 0) + { + mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + } + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) + { + mac = d_crypto->computeCMAC_AES(applicable_key, m); + } + uint16_t mac_msb = 0; + if (!mac.empty()) + { + mac_msb = (mac[0] << 8) + mac[1]; + } + uint16_t computed_macseq = (mac_msb & 0x0FFF); + int num_tags_added = 0; + if (computed_macseq == d_osnma_data.d_mack_message.header.macseq) + { + std::cout << "OSNMA: MACSEQ authenticated for PRN_A " + << osnma_msg->PRN << " with WN=" + << osnma_msg->WN_sf0 << ", TOW=" + << osnma_msg->TOW_sf0 << ". Tags added: " + << num_tags_added << std::endl; + } +} \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index c2a2a7d90..b07f4177b 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -64,10 +64,11 @@ private: void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); - void read_mack_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); + void read_mack_block(const std::shared_ptr& osnma_msg); void read_mack_header(); void read_mack_body(); + void process_mack_message(const std::shared_ptr& osnma_msg); boost::circular_buffer d_old_mack_message; std::unique_ptr d_dsm_reader; From 15840f6ae5b6bd1f1ad98d1014a7582751d1e097 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 26 Oct 2023 14:45:01 +0200 Subject: [PATCH 064/219] Fix merging --- .../gnuradio_blocks/galileo_telemetry_decoder_gs.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 9467f3994..1f7678ced 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -105,13 +105,9 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs( d_enable_reed_solomon_inav(false), d_valid_timetag(false), d_E6_TOW_set(false), -<<<<<<< HEAD d_there_are_e1_channels(conf.there_are_e1_channels), - d_there_are_e6_channels(conf.there_are_e6_channels) -======= d_there_are_e6_channels(conf.there_are_e6_channels), d_use_ced(conf.use_ced) ->>>>>>> 62a8547e62605a6b9fa6b1e128beceb046bde2dc { // prevent telemetry symbols accumulation in output buffers this->set_max_noutput_items(1); From ba357ebd9c39d90fa59639d217712685b108d4bf Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sun, 3 Dec 2023 15:50:16 +0100 Subject: [PATCH 065/219] Comments and questions | verify_dsm_pkr() structure --- src/core/libs/osnma_msg_receiver.cc | 54 +++++++++++++++++-------- src/core/libs/osnma_msg_receiver.h | 8 +++- src/core/system_parameters/osnma_data.h | 2 +- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 39ac24843..8f157414f 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -110,9 +110,9 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) } // Send the resulting decoded NMA data (if available) to PVT - if (d_new_data == true) + if (d_new_data == true) // TODO where is it set to true? { - auto osnma_data_ptr = std::make_shared(d_osnma_data); + auto osnma_data_ptr = std::make_shared(d_osnma_data); // C: why create new object and pass it empty to Pvt? this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); d_new_data = false; // d_osnma_data = OSNMA_data(); @@ -302,12 +302,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg const uint16_t size_m = 13 + l_lk_bytes; std::vector MSG; MSG.reserve(size_m + l_ds_bytes + 1); - MSG.push_back(osnma_msg->hkroot[0]); + MSG.push_back(osnma_msg->hkroot[0]); // C: NMA header for (uint16_t i = 1; i < size_m; i++) { MSG.push_back(dsm_msg[i]); } - std::vector message = MSG; + std::vector message = MSG; // C: 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]); @@ -344,16 +344,20 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; if (authenticated) { - std::cout << " authenticated" << std::endl; + std::cout << " authenticated" << std::endl; // C: proceed with Tesla chain key verification. } else { - std::cout << " validated" << std::endl; + std::cout << " validated" << std::endl; // C: Kroot not verified => retrieve it again } std::cout << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; } + else + { + std::cout << "Galileo OSNMA: Error computing padding bits." << std::endl; + } } } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) @@ -411,6 +415,9 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 << " received" << std::endl; + // C: NPK verification against Merkle tree root. + std::vector m_0; + d_public_key_verified = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message, m_0); } } else @@ -434,7 +441,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma d_mack_message[index + 3] = static_cast(value & 0x000000FF); index = index + 4; } - if (d_osnma_data.d_dsm_kroot_message.ts != 0) + if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts < ts < 10 { read_mack_header(); read_mack_body(); @@ -444,7 +451,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma void osnma_msg_receiver::read_mack_header() -{ +{ // C: still to review computations. uint8_t lt_bits = 0; const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); if (it != OSNMA_TABLE_11.cend()) @@ -453,7 +460,7 @@ void osnma_msg_receiver::read_mack_header() } if (lt_bits == 0) { - return; + return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. } uint16_t macseq = 0; uint8_t cop = 0; @@ -526,8 +533,8 @@ void osnma_msg_receiver::read_mack_body() { return; } - uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); - d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); + uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); // C: compute number of tags + d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); // C: nt - 1? for (uint16_t k = 0; k < (nt - 1); k++) { uint64_t tag = 0; @@ -680,11 +687,14 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& { d_old_mack_message.push_back(d_osnma_data.d_mack_message); - // MACSEQ validation + // MACSEQ validation - case no FLX Tags uint32_t GST_SF = osnma_msg->TOW_sf0; + // C: TODO check ADKD-MACLT for match, also identify which tags are FLX + // C: TODO if Tag_x FLX => MACSEQ, otherwise ___ ? // Are there flexible tags? - std::vector m(5); + + std::vector m(5); // C: ICD - Eq. 23 m[0] = static_cast(osnma_msg->PRN); // PRN_A m[1] = ((GST_SF & 0xF000) >> 24); m[2] = ((GST_SF & 0x0F00) >> 16); @@ -696,11 +706,11 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // otherwise pick d_old_mack_message.back() applicable_key = d_old_mack_message.back().key; std::vector mac; - if (d_osnma_data.d_dsm_kroot_message.mf == 0) + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); } - else if (d_osnma_data.d_dsm_kroot_message.mf == 1) + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { mac = d_crypto->computeCMAC_AES(applicable_key, m); } @@ -719,4 +729,16 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& << osnma_msg->TOW_sf0 << ". Tags added: " << num_tags_added << std::endl; } -} \ No newline at end of file + + // C: TODO - for each tag in tag_and_info[] && until l_t_verified <= L_t_min + // C: TODO - tag = trunc(l_t, mac(applicable_key,m)) + // C: TODO - where m = (PRNd || PRNa || GSTsf || CTR || NMAS || NavData || P) +} + +bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message, std::vector m0) +{ + // TODO concatenate message + // TODO create function for recursively apply hash + + return false; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index b07f4177b..89522bc69 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -65,6 +65,7 @@ private: void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); + bool verify_dsm_pkr(DSM_PKR_message message, std::vector input_message); void read_mack_block(const std::shared_ptr& osnma_msg); void read_mack_header(); void read_mack_body(); @@ -74,13 +75,16 @@ private: std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; - std::array, 16> d_dsm_message{}; + std::array, 16> d_dsm_message{}; // C: each dsm[0-15] has 2048 bits std::array, 16> d_dsm_id_received{}; std::array d_number_of_blocks{}; - std::array d_mack_message{}; + std::array d_mack_message{}; // C: 480 b OSNMA_data d_osnma_data{}; bool d_new_data{false}; + bool d_public_key_verified{false}; + bool d_kroot_verified{false}; + }; diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 890eeb3a5..5f82bb5a8 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -68,7 +68,7 @@ class MACK_tag_and_info { public: MACK_tag_and_info() = default; - uint64_t tag; + uint64_t tag; // C: 20-40 bits MACK_tag_info tag_info; }; From d01ea978c69205300c8afa51d4e778f2d187e5ff Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sun, 3 Dec 2023 17:45:15 +0100 Subject: [PATCH 066/219] [TAS-108] first implementation of verify_dsm_pkr() * osnma_msg_receiver : leafs computation without loop and root comparison * gnss_crypto : getMerkleRoot() to return d_x_4_0 --- src/core/libs/osnma_msg_receiver.cc | 48 +++++++++++++++++++++--- src/core/libs/osnma_msg_receiver.h | 2 +- src/core/system_parameters/gnss_crypto.h | 4 ++ 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 8f157414f..cf7e3adc9 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -416,8 +416,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 << " received" << std::endl; // C: NPK verification against Merkle tree root. - std::vector m_0; - d_public_key_verified = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message, m_0); + d_public_key_verified = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message); } } else @@ -735,10 +734,49 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // C: TODO - where m = (PRNd || PRNa || GSTsf || CTR || NMAS || NavData || P) } -bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message, std::vector m0) +bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) { - // TODO concatenate message + // TODO create leafe base message m_i // TODO create function for recursively apply hash - return false; + // build base leaf m_i +// auto leaf = message.mid; + std::vector m_i; + m_i.reserve(2 + message.npk.size()); + m_i[0] = message.npkt; + m_i[1] = message.npktid; + for (uint8_t i = 2; i < m_i.size(); i++) + { + m_i.push_back(message.npk[i]); + } + + // compute intermediate leafs' values + std::vector x_0,x_1,x_2,x_3,x_4; +// uint8_t k = 0; + x_0 = d_crypto->computeSHA256(m_i); + x_0.insert(x_0.end(),message.itn.begin(),&message.itn[31]); + x_1 = d_crypto->computeSHA256(x_0); + x_1.insert(x_1.end(),&message.itn[32],&message.itn[63]); + x_2 = d_crypto->computeSHA256(x_1); + x_2.insert(x_2.end(),&message.itn[64],&message.itn[95]); + x_3 = d_crypto->computeSHA256(x_2); + x_3.insert(x_3.end(),&message.itn[96],&message.itn[127]); + // root leaf computation + x_4 = d_crypto->computeSHA256(x_3); + + // C: d_crypto->getMerkleRoot([m_0:m_15]) I realised I could have done this... + // C: ... but why computing all the possible results? I have only one leaf in each osnma message... + // verify that computed root matches merkle root + + if(x_4 == d_crypto->getMerkleRoot()) + { + std::cout << "Galileo OSNMA: DSM-PKR verified successfully! " << std::endl; + return true; + // C: NPK verification against Merkle tree root. + } + else + { + std::cout << "Galileo OSNMA: DSM-PKR verification unsuccessful !" << std::endl; + return false; + } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 89522bc69..2c9cedcc7 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -65,7 +65,7 @@ private: void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); - bool verify_dsm_pkr(DSM_PKR_message message, std::vector input_message); + bool verify_dsm_pkr(DSM_PKR_message message); void read_mack_block(const std::shared_ptr& osnma_msg); void read_mack_header(); void read_mack_body(); diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index c544020a9..50047c440 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -50,6 +50,10 @@ public: void readPublicKeyFromPEM(const std::string& pemFilePath); void read_merkle_xml(const std::string& merkleFilePath); std::vector getMerkleRoot(const std::vector>& merkle) const; + std::vector getMerkleRoot() const + { + return d_x_4_0; + } // void set_public_key(const std::vector& publickey); From 51061f18ebbd365d7c53d403516bab6914d470b5 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 5 Dec 2023 20:16:03 +0100 Subject: [PATCH 067/219] [TAS-106] process_mack_message: tags ADKD-MCLT check (first draft) --- src/core/libs/osnma_msg_receiver.cc | 51 ++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index cf7e3adc9..80f67a5ef 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -533,7 +533,7 @@ void osnma_msg_receiver::read_mack_body() return; } uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); // C: compute number of tags - d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); // C: nt - 1? + d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); for (uint16_t k = 0; k < (nt - 1); k++) { uint64_t tag = 0; @@ -684,7 +684,7 @@ void osnma_msg_receiver::read_mack_body() void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) { - d_old_mack_message.push_back(d_osnma_data.d_mack_message); + d_old_mack_message.push_back(d_osnma_data.d_mack_message); // C: old mack message is needed for // MACSEQ validation - case no FLX Tags uint32_t GST_SF = osnma_msg->TOW_sf0; @@ -692,8 +692,47 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // C: TODO check ADKD-MACLT for match, also identify which tags are FLX // C: TODO if Tag_x FLX => MACSEQ, otherwise ___ ? // Are there flexible tags? + // d_osnma_data.d_dsm_kroot_message.maclt + // d_osnma_data.d_mack_message.tag_and_info[k].tag - std::vector m(5); // C: ICD - Eq. 23 + // retrieve data to verify MACK tags + uint8_t msg {0}; + uint8_t nt {0}; + std::vector sq1{}; + std::vector sq2{}; + const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); + if (it != OSNMA_TABLE_16.cend()) + { + auto msg = it->second.msg; + auto nt = it->second.nt; + auto sq1 = it->second.sequence1; + auto sq2 = it->second.sequence2; + } + if (msg == 0) + { + return; + } + // compare ADKD of Mack tags with MACLT defined ADKDs + // TODO - "When it is equal to 2, the sequence starts with the MACK message transmitted in the first 30 seconds of a GST minute." + if(d_osnma_data.d_mack_message.tag_and_info.size() != sq1.size()) // TODO - which sequence is retrieved in this Mack? + { + std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; + return; + } + bool allOk = true; + std::string selfAutenticated {}; + for (uint8_t i = 0; i < d_osnma_data.d_mack_message.tag_and_info.size(); i++) + { + if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(sq1[i])) // C: undefined if format is not "00S" + { + allOk = false; + break; + } + selfAutenticated = sq1[i][sq1[i].size()-1]; + } + + + std::vector m(5); // C: ICD - Eq. 22 m[0] = static_cast(osnma_msg->PRN); // PRN_A m[1] = ((GST_SF & 0xF000) >> 24); m[2] = ((GST_SF & 0x0F00) >> 16); @@ -730,8 +769,10 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& } // C: TODO - for each tag in tag_and_info[] && until l_t_verified <= L_t_min - // C: TODO - tag = trunc(l_t, mac(applicable_key,m)) - // C: TODO - where m = (PRNd || PRNa || GSTsf || CTR || NMAS || NavData || P) + // C: d_osnma_data.d_dsm_kroot_message.ts gives l_t of each tag for this mack + // C: tag = trunc(l_t, mac(applicable_key,m)) + // C: where m = (PRNd || PRNa || GSTsf || CTR || NMAS || NavData || P) + // C: si l_t_verified >= L_t_min d_new_data = true } bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) From 1356a3e87bd35ca0b7ae6701d1966731a471d056 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 7 Dec 2023 05:34:52 +0100 Subject: [PATCH 068/219] [TAS-110] verify_tesla_key-> implement retrieval tesla key --- src/core/libs/osnma_msg_receiver.cc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 80f67a5ef..ad361dd9f 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -512,6 +512,7 @@ void osnma_msg_receiver::read_mack_header() void osnma_msg_receiver::read_mack_body() { + uint8_t lt_bits = 0; const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); if (it != OSNMA_TABLE_11.cend()) @@ -534,7 +535,7 @@ void osnma_msg_receiver::read_mack_body() } uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); // C: compute number of tags d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); - for (uint16_t k = 0; k < (nt - 1); k++) + for (uint16_t k = 0; k < (nt - 1); k++) // C: retrieve Tag&Info { uint64_t tag = 0; uint8_t PRN_d = 0; @@ -679,6 +680,20 @@ void osnma_msg_receiver::read_mack_body() d_osnma_data.d_mack_message.tag_and_info[k].tag_info.ADKD = ADKD; d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = cop; } + // TODO - [TAS-110] + // retrieve TESLA key: index i is [479-MH(l_t)-(nt-1)*(16+l_t), i+l_k] + // compute I (GST_SFi,GST_Kroot) + // perform recursive hash calls until base case: i = 10...1 + + // retrieve tesla key + uint8_t start_index_bytes = ( 480 - (lt_bits + 16) - (nt - 1) * ( lt_bits + 16 ) - 1 ) / 8; // includes -1 to start at [i-1] + uint8_t last_index_bytes = ( start_index_bytes * 8 + lk_bits ) / 8; + uint8_t key_index_bytes = 0; + for (uint8_t i = start_index_bytes; i < last_index_bytes ; i++, key_index_bytes++) + { + d_osnma_data.d_mack_message.key[key_index_bytes] = d_mack_message[i]; + } + } From 33f6bacd9b0d21d5be6cb96632d3b555b5d677cb Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 12 Dec 2023 22:07:30 +0100 Subject: [PATCH 069/219] [TAS-110] tesla key verification first implementation * read_mack_block => computation of d_GST_Sf and d_GST_0 * read_mack_header => verify_tesla_key logic --- src/core/libs/osnma_msg_receiver.cc | 81 +++++++++++++++++++++++-- src/core/libs/osnma_msg_receiver.h | 3 +- src/core/system_parameters/osnma_data.h | 2 +- 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index ad361dd9f..62a0be6fa 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -440,6 +440,9 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma d_mack_message[index + 3] = static_cast(value & 0x000000FF); index = index + 4; } + // compute time of subrame and kroot time of applicability, used in read_mack_body and process_mack_message + d_GST_Sf = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; // TODO - find a better placement + d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k; if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts < ts < 10 { read_mack_header(); @@ -694,6 +697,75 @@ void osnma_msg_receiver::read_mack_body() d_osnma_data.d_mack_message.key[key_index_bytes] = d_mack_message[i]; } + // compute number of hashes required + uint8_t num_of_hashes_needed = (d_GST_Sf - d_GST_0) / 30 + 1; + uint32_t GST_SFi = d_GST_Sf; + std::vector K_II = d_osnma_data.d_mack_message.key; + std::vector K_I; // result of the recursive hash operations + uint8_t size_hash_f = d_osnma_data.d_dsm_kroot_message.ks / 8; + // compute the current tesla key + for (uint8_t i = 1; i < num_of_hashes_needed ; i++) + { + // build message digest m = (K_I+1 || GST_SFi || alpha) + std::vector msg(sizeof(K_II) + sizeof(d_GST_Sf) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); + std::copy(K_II.begin(),K_II.end(),msg.begin()); + + msg.push_back((d_GST_Sf & 0xF000) >> 24); + msg.push_back((d_GST_Sf & 0x0F00) >> 16); + msg.push_back((d_GST_Sf & 0x00F0) >> 8); + msg.push_back(d_GST_Sf & 0x000F); + + for (uint8_t k = 5; k >= 0;k--) + { + // TODO: static extracts the MSB in case from larger to shorter int? + msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. + } + + // compute hash + std::vector hash; + if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. + { + hash = d_crypto->computeSHA256(msg); + } + else if (d_osnma_data.d_dsm_kroot_message.hf == 2) + { + hash = d_crypto->computeSHA3_256(msg); + } + else + { + hash = std::vector(32); + } + // truncate hash + K_I.reserve(size_hash_f); // TODO - case hash function has 512 bits + for (uint16_t i = 0; i < size_hash_f; i++) + { + K_I.push_back(hash[i]); + } + + // set parameters + GST_SFi -= 30; // next SF time is the actual minus 30 seconds + K_II = K_I; // next key is the actual one + K_I.clear(); // empty the actual one for a new computation + } + // compare computed current key against received key + bool result_comparison; + if(K_I.size() != d_osnma_data.d_mack_message.key.size()) + { + std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + } + if (K_II == d_osnma_data.d_mack_message.key) + { + result_comparison = true; + std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; + // TODO - propagate result + // TODO - save current tesla key as latest one? + } + else + + { + result_comparison = false; + std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + } } @@ -702,7 +774,6 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& d_old_mack_message.push_back(d_osnma_data.d_mack_message); // C: old mack message is needed for // MACSEQ validation - case no FLX Tags - uint32_t GST_SF = osnma_msg->TOW_sf0; // C: TODO check ADKD-MACLT for match, also identify which tags are FLX // C: TODO if Tag_x FLX => MACSEQ, otherwise ___ ? @@ -749,10 +820,10 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& std::vector m(5); // C: ICD - Eq. 22 m[0] = static_cast(osnma_msg->PRN); // PRN_A - m[1] = ((GST_SF & 0xF000) >> 24); - m[2] = ((GST_SF & 0x0F00) >> 16); - m[3] = ((GST_SF & 0x00F0) >> 8); - m[4] = (GST_SF & 0x000F); + m[1] = ((d_GST_Sf & 0xF000) >> 24); + m[2] = ((d_GST_Sf & 0x0F00) >> 16); + m[3] = ((d_GST_Sf & 0x00F0) >> 8); + m[4] = (d_GST_Sf & 0x000F); std::vector applicable_key; // if ADKD=12, pick d_old_mack_message.front() if d_old_mack_message[10] is full diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 2c9cedcc7..6922ae5aa 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -84,7 +84,8 @@ private: bool d_new_data{false}; bool d_public_key_verified{false}; bool d_kroot_verified{false}; - + uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification + uint32_t d_GST_0 {}; }; diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 5f82bb5a8..ffd459fab 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -102,7 +102,7 @@ public: uint8_t reserved1{}; uint8_t hf{}; uint8_t mf{}; - uint8_t ks{}; + uint8_t ks{}; // key size, in bits uint8_t ts{}; uint8_t maclt{}; uint8_t reserved{}; From 7f3202be8e96105a64ddc3af5a884832586f855e Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sun, 17 Dec 2023 14:15:00 +0100 Subject: [PATCH 070/219] WIP --- src/core/libs/osnma_msg_receiver.cc | 21 +++++++++++++++------ src/core/libs/osnma_msg_receiver.h | 1 + 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 62a0be6fa..f7ab9e334 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -150,7 +150,9 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) << std::endl; } - +/* + * accumulates dsm messages until completeness, then calls process_dsm_message + * */ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_msg) { size_t index = 0; @@ -245,7 +247,13 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } } - +/* + * case DSM-Kroot: + * - computes the padding + * - if successful, tries to verify the digital signature + * case DSM-PKR: + * - calls verify_dsm_pkr to verify the public key + * */ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg) { if (d_osnma_data.d_dsm_header.dsm_id < 12) @@ -441,8 +449,9 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma index = index + 4; } // compute time of subrame and kroot time of applicability, used in read_mack_body and process_mack_message - d_GST_Sf = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; // TODO - find a better placement + d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; // TODO - find a better placement d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k; + d_GST_Sf = d_GST_0 + 30 * std::floor((d_GST_SIS-d_GST_0)/30); // TODO - find a better placement if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts < ts < 10 { read_mack_header(); @@ -703,11 +712,11 @@ void osnma_msg_receiver::read_mack_body() std::vector K_II = d_osnma_data.d_mack_message.key; std::vector K_I; // result of the recursive hash operations uint8_t size_hash_f = d_osnma_data.d_dsm_kroot_message.ks / 8; - // compute the current tesla key + // compute the current tesla key , GST_SFi and K_II change in each iteration for (uint8_t i = 1; i < num_of_hashes_needed ; i++) { // build message digest m = (K_I+1 || GST_SFi || alpha) - std::vector msg(sizeof(K_II) + sizeof(d_GST_Sf) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); + std::vector msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); std::copy(K_II.begin(),K_II.end(),msg.begin()); msg.push_back((d_GST_Sf & 0xF000) >> 24); @@ -772,7 +781,7 @@ void osnma_msg_receiver::read_mack_body() void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) { d_old_mack_message.push_back(d_osnma_data.d_mack_message); // C: old mack message is needed for - + // MACSEQ validation - case no FLX Tags // C: TODO check ADKD-MACLT for match, also identify which tags are FLX diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 6922ae5aa..0ba9169ff 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -86,6 +86,7 @@ private: bool d_kroot_verified{false}; uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification uint32_t d_GST_0 {}; + uint32_t d_GST_SIS {}; }; From 656684e39630066c7ab2f1dae1391b2f340e3e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Sun, 17 Dec 2023 21:01:01 +0100 Subject: [PATCH 071/219] DSM-PKR getter setter structure --- src/core/libs/osnma_msg_receiver.cc | 17 +++++++++++++---- src/core/system_parameters/gnss_crypto.cc | 23 +++++++++++++++++++++++ src/core/system_parameters/gnss_crypto.h | 3 ++- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index f7ab9e334..c08b669d3 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -341,7 +341,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { p_dk_truncated.push_back(hash[i]); } - // check DS signature + // Check that the padding bits received match the computed values if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { bool authenticated = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); @@ -371,7 +371,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) { LOG(WARNING) << "OSNMA: DSM-PKR message received."; - // DSM-PKR message + // Save DSM-PKR message d_osnma_data.d_dsm_pkr_message.nb_dp = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_pkr_message.mid = d_dsm_reader->get_mid(dsm_msg); for (int k = 0; k > 128; k++) @@ -424,7 +424,17 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 << " received" << std::endl; // C: NPK verification against Merkle tree root. - d_public_key_verified = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message); + if (!d_public_key_verified) + { + bool verification = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message); + if (verification) + { + d_public_key_verified = true; + d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk); + } + + } + } } else @@ -872,7 +882,6 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) { - // TODO create leafe base message m_i // TODO create function for recursively apply hash // build base leaf m_i diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index eab8ab23e..eb9d38ca0 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -598,3 +598,26 @@ std::vector Gnss_Crypto::getMerkleRoot(const std::vector& publicKey) +{ +#if USE_OPENSSL_FALLBACK + // TODO - convert to OSSL PubKey format +#else +// GNU-TLS + // TODO - convert to gnutls_pubkey_st +#endif + +} + +std::vector Gnss_Crypto::get_public_key() +{ +#if USE_OPENSSL_FALLBACK + // TODO +#else +// GNU-TLS + // TODO +#endif + return {}; +} diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 50047c440..6f405cc24 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -55,7 +55,8 @@ public: return d_x_4_0; } - // void set_public_key(const std::vector& publickey); + void set_public_key(const std::vector& publickey); + static std::vector get_public_key(); private: #if USE_OPENSSL_FALLBACK From fdbd99ce6b1928e8d0a828c5756c84a7aa9be88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Sat, 6 Jan 2024 16:47:29 +0100 Subject: [PATCH 072/219] [TAS-109] ADKD-MCLT check - changed GST mask, implement FLX tags --- src/core/libs/osnma_msg_receiver.cc | 101 ++++++++++++------ .../system_parameters/galileo_inav_message.cc | 3 + .../system_parameters/galileo_inav_message.h | 2 + src/core/system_parameters/osnma_data.h | 1 + 4 files changed, 73 insertions(+), 34 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index c08b669d3..819f5d6a9 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -249,7 +249,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ /* * case DSM-Kroot: - * - computes the padding + * - computes the padding and compares with received message * - if successful, tries to verify the digital signature * case DSM-PKR: * - calls verify_dsm_pkr to verify the public key @@ -459,9 +459,10 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma index = index + 4; } // compute time of subrame and kroot time of applicability, used in read_mack_body and process_mack_message - d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; // TODO - find a better placement + // TODO - find a better placement + d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k; - d_GST_Sf = d_GST_0 + 30 * std::floor((d_GST_SIS-d_GST_0)/30); // TODO - find a better placement + d_GST_Sf = d_GST_0 + 30 * std::floor((d_GST_SIS-d_GST_0)/30); // Eq. 3 R.G. if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts < ts < 10 { read_mack_header(); @@ -472,7 +473,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma void osnma_msg_receiver::read_mack_header() -{ // C: still to review computations. +{ // C: TODO - still to review computations. uint8_t lt_bits = 0; const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); if (it != OSNMA_TABLE_11.cend()) @@ -729,10 +730,10 @@ void osnma_msg_receiver::read_mack_body() std::vector msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); std::copy(K_II.begin(),K_II.end(),msg.begin()); - msg.push_back((d_GST_Sf & 0xF000) >> 24); - msg.push_back((d_GST_Sf & 0x0F00) >> 16); - msg.push_back((d_GST_Sf & 0x00F0) >> 8); - msg.push_back(d_GST_Sf & 0x000F); + msg.push_back((d_GST_Sf & 0xFF000000) >> 24); + msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); + msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); + msg.push_back(d_GST_Sf & 0x000000FF); for (uint8_t k = 5; k >= 0;k--) { @@ -767,7 +768,7 @@ void osnma_msg_receiver::read_mack_body() K_I.clear(); // empty the actual one for a new computation } // compare computed current key against received key - bool result_comparison; + bool result_comparison; // TODO - not needed? if(K_I.size() != d_osnma_data.d_mack_message.key.size()) { std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; @@ -778,6 +779,9 @@ void osnma_msg_receiver::read_mack_body() std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; // TODO - propagate result // TODO - save current tesla key as latest one? + // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence + + } else @@ -795,8 +799,8 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // MACSEQ validation - case no FLX Tags // C: TODO check ADKD-MACLT for match, also identify which tags are FLX - // C: TODO if Tag_x FLX => MACSEQ, otherwise ___ ? - // Are there flexible tags? + + // d_osnma_data.d_dsm_kroot_message.maclt // d_osnma_data.d_mack_message.tag_and_info[k].tag @@ -808,42 +812,69 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); if (it != OSNMA_TABLE_16.cend()) { - auto msg = it->second.msg; - auto nt = it->second.nt; - auto sq1 = it->second.sequence1; - auto sq2 = it->second.sequence2; + uint8_t msg = it->second.msg; + uint8_t nt = it->second.nt; + std::vector sq1 = it->second.sequence1; + std::vector sq2 = it->second.sequence2; } if (msg == 0) { return; } + std::vector sequence; + if (d_GST_Sf % 60 == 0) + { + sequence = sq1; + } + else if (d_GST_Sf % 60 == 30) + { + sequence = sq2; + } + else + { + std::cout << "Galileo OSNMA: Mismatch in the GST verification => should end in 30 or 60 seconds but it dit not." << std::endl; + } // compare ADKD of Mack tags with MACLT defined ADKDs - // TODO - "When it is equal to 2, the sequence starts with the MACK message transmitted in the first 30 seconds of a GST minute." - if(d_osnma_data.d_mack_message.tag_and_info.size() != sq1.size()) // TODO - which sequence is retrieved in this Mack? + if(d_osnma_data.d_mack_message.tag_and_info.size() != sq1.size()) { std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; return; } - bool allOk = true; - std::string selfAutenticated {}; + bool allOk = true; // one being invalid spoils the entire MACK + std::vector flxTags {}; + std::string tempADKD; for (uint8_t i = 0; i < d_osnma_data.d_mack_message.tag_and_info.size(); i++) { - if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(sq1[i])) // C: undefined if format is not "00S" + // TODO - logic for asserting if if sq[i] == "FLX" (string) or "00X" (int built with first two digits) + tempADKD = sequence[i]; + if(tempADKD == "FLX") + { + flxTags.push_back(i); // C: just need to save the index in the sequence + } + else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(sequence[i])) { allOk = false; - break; + std::cout << "Galileo OSNMA: Unsuccessful verification of received ADKD against MAC Look-up table. " << std::endl; + return; // C: suffices one incorrect to abort and not process the rest of the tags } - selfAutenticated = sq1[i][sq1[i].size()-1]; } + // MACSEQ verification - std::vector m(5); // C: ICD - Eq. 22 + // Case no tags defined as FLX in the MACLT + std::vector m(5 + flxTags.size()); // C: ICD - Eq. 22 m[0] = static_cast(osnma_msg->PRN); // PRN_A - m[1] = ((d_GST_Sf & 0xF000) >> 24); - m[2] = ((d_GST_Sf & 0x0F00) >> 16); - m[3] = ((d_GST_Sf & 0x00F0) >> 8); - m[4] = (d_GST_Sf & 0x000F); + m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); + m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); + m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); + m[4] = static_cast(d_GST_Sf & 0x000000FF); + // Case tags flexible + for (uint8_t i = 0; i < flxTags.size() ; i++) + { + m[i+5] = d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; + m[i+6] = d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; + } std::vector applicable_key; // if ADKD=12, pick d_old_mack_message.front() if d_old_mack_message[10] is full // otherwise pick d_old_mack_message.back() @@ -857,27 +888,29 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& { mac = d_crypto->computeCMAC_AES(applicable_key, m); } + + // Truncate the twelve MSBits and compare with received MACSEQ uint16_t mac_msb = 0; if (!mac.empty()) { mac_msb = (mac[0] << 8) + mac[1]; } - uint16_t computed_macseq = (mac_msb & 0x0FFF); + uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; // TODO - double check, it was 0x0FFF which presuposes little endian... int num_tags_added = 0; if (computed_macseq == d_osnma_data.d_mack_message.header.macseq) { + + // C: TODO - for each tag in tag_and_info[] && until l_t_verified <= L_t_min or tags of MACK are finished + // C: d_osnma_data.d_dsm_kroot_message.ts gives l_t of each tag for this mack + // C: tag = trunc(l_t, mac(applicable_key,m)) + // C: where m = (PRNd || PRNa || GSTsf || CTR || NMAS || NavData || P) + // C: si l_t_verified >= L_t_min d_new_data = true std::cout << "OSNMA: MACSEQ authenticated for PRN_A " << osnma_msg->PRN << " with WN=" << osnma_msg->WN_sf0 << ", TOW=" << osnma_msg->TOW_sf0 << ". Tags added: " << num_tags_added << std::endl; } - - // C: TODO - for each tag in tag_and_info[] && until l_t_verified <= L_t_min - // C: d_osnma_data.d_dsm_kroot_message.ts gives l_t of each tag for this mack - // C: tag = trunc(l_t, mac(applicable_key,m)) - // C: where m = (PRNd || PRNa || GSTsf || CTR || NMAS || NavData || P) - // C: si l_t_verified >= L_t_min d_new_data = true } bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index 8166b0e9f..57d950e44 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1430,6 +1430,9 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() TOW_sf0 += 604800; } nma_msg.TOW_sf0 = static_cast(TOW_sf0); + // TODO - draft for retrieving NavData for use during Tag verification. + nma_msg.t0e_1 = static_cast(t0e_1); + nma_msg.IOD_nav = static_cast(IOD_nav_1); return nma_msg; } diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 1ed9a8ae9..91b332ca3 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -49,6 +49,8 @@ public: uint32_t PRN{}; uint32_t WN_sf0{}; uint32_t TOW_sf0{}; + uint32_t t0e_1{}; + uint32_t IOD_nav{}; }; /*! diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index ffd459fab..a19666d5b 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -70,6 +70,7 @@ public: MACK_tag_and_info() = default; uint64_t tag; // C: 20-40 bits MACK_tag_info tag_info; + // TODO - std::vector with complete Tag }; class DSM_PKR_message From f7d7f5a78474949a6f3c494266260d4844ed9436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Mon, 8 Jan 2024 19:11:13 +0100 Subject: [PATCH 073/219] [TAS-116] tag verification for ADKD=0 --- src/core/libs/osnma_msg_receiver.cc | 103 ++++++++++++++++-- src/core/libs/osnma_msg_receiver.h | 1 + .../system_parameters/galileo_inav_message.h | 3 + 3 files changed, 97 insertions(+), 10 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 819f5d6a9..6bc8d487f 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -460,7 +460,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma } // compute time of subrame and kroot time of applicability, used in read_mack_body and process_mack_message // TODO - find a better placement - d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; + d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k; d_GST_Sf = d_GST_0 + 30 * std::floor((d_GST_SIS-d_GST_0)/30); // Eq. 3 R.G. if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts < ts < 10 @@ -888,7 +888,6 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& { mac = d_crypto->computeCMAC_AES(applicable_key, m); } - // Truncate the twelve MSBits and compare with received MACSEQ uint16_t mac_msb = 0; if (!mac.empty()) @@ -899,17 +898,101 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& int num_tags_added = 0; if (computed_macseq == d_osnma_data.d_mack_message.header.macseq) { - - // C: TODO - for each tag in tag_and_info[] && until l_t_verified <= L_t_min or tags of MACK are finished - // C: d_osnma_data.d_dsm_kroot_message.ts gives l_t of each tag for this mack - // C: tag = trunc(l_t, mac(applicable_key,m)) - // C: where m = (PRNd || PRNa || GSTsf || CTR || NMAS || NavData || P) - // C: si l_t_verified >= L_t_min d_new_data = true std::cout << "OSNMA: MACSEQ authenticated for PRN_A " << osnma_msg->PRN << " with WN=" << osnma_msg->WN_sf0 << ", TOW=" - << osnma_msg->TOW_sf0 << ". Tags added: " - << num_tags_added << std::endl; + << osnma_msg->TOW_sf0 << ". Verifying tags. " + << std::endl; + + uint8_t l_t_verified = 0; // tag bits verified + uint8_t i = 0; + // TODO - configuration file must define which tags shall be verified + // e.g. NavDataVerification: A == ALL, T == Timing Parameters, ECS == Ephemeris,Clock and Status. + std::string navDataToVerify = "EphemerisClockAndStatus"; // ADKD 0 + // Timing Parameters ADKD 4 + // EphemerisClockAndStatus ADKD 12 10+ Delay + m.clear(); + uint8_t lt_bits = 0; + const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); + if (it2 != OSNMA_TABLE_11.cend()) + { + lt_bits = it2->second; + } + if (lt_bits == 0) + { + return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. + } + while (i < d_osnma_data.d_mack_message.tag_and_info.size() && l_t_verified < d_Lt_min) + { + // compute m + m.push_back(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.PRN_d); + m.push_back(osnma_msg->PRN); + m.push_back(static_cast((d_GST_Sf & 0xFF000000) >> 24)); + m.push_back(static_cast((d_GST_Sf & 0x00FF0000) >> 16)); + m.push_back(static_cast((d_GST_Sf & 0x0000FF00) >> 8)); + m.push_back(static_cast(d_GST_Sf & 0x000000FF)); + m.push_back(i+1); // CTRauto + m.push_back(d_osnma_data.d_nma_header.nmas); + // TODO - other ADKD need different data. + // TODO - store buffer the NavData of 11 last subframes, ADKD 0 and 12 => NavData belongs to SF-1 + m.insert(m.end(),osnma_msg->EphemerisClockAndStatusData.begin(),osnma_msg->EphemerisClockAndStatusData.end()) ; + i = 0; + while (i<10/*TODO - number of padding zeroes to be computed*/) + { + m.push_back(0); + i++; + } + + // compute mac + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + { + mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + } + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + { + mac = d_crypto->computeCMAC_AES(applicable_key, m); + } + + // compute tag = trunc(l_t, mac(K,m)) Eq. 23 ICD + uint64_t computed_mac = static_cast(mac[0]) << (lt_bits - 8); + computed_mac += (static_cast(mac[1]) << (lt_bits - 16)); + if (lt_bits == 20) + { + computed_mac += (static_cast(mac[1] & 0xF0) >> 4); + } + else if (lt_bits == 24) + { + computed_mac += static_cast(mac[2]); + } + else if (lt_bits == 28) + { + computed_mac += (static_cast(mac[2]) << 4); + computed_mac += (static_cast(mac[3] & 0xF0) >> 4); + } + else if (lt_bits == 32) + { + computed_mac += (static_cast(mac[2]) << 8); + computed_mac += static_cast(mac[3]); + } + else if (lt_bits == 40) + { + computed_mac += (static_cast(mac[2]) << 16); + computed_mac += (static_cast(mac[3]) << 8); + computed_mac += static_cast(mac[4]); + } + + // Compare computed tag with received one truncated + if (d_osnma_data.d_mack_message.tag_and_info[i].tag == computed_mac) + { + std::cout << "Galileo OSNMA: Tag verification successful " << std::endl; + l_t_verified += lt_bits; + } + else + { + std::cout << "Galileo OSNMA: Tag verification failed " << std::endl; + } + + } } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 0ba9169ff..655f0dae5 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -85,6 +85,7 @@ private: bool d_public_key_verified{false}; bool d_kroot_verified{false}; uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification + uint8_t d_Lt_min {}; // minimum equivalent tag length uint32_t d_GST_0 {}; uint32_t d_GST_SIS {}; }; diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 91b332ca3..d6139c7e0 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -49,6 +49,9 @@ public: uint32_t PRN{}; uint32_t WN_sf0{}; uint32_t TOW_sf0{}; + // TODO - NavData to be retrieved correctly + std::vector EphemerisClockAndStatusData {}; + std::vector TimingData {}; uint32_t t0e_1{}; uint32_t IOD_nav{}; }; From 13cc59c5fa8130c8949e3622811358ada9ed4a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Thu, 18 Jan 2024 14:00:36 +0100 Subject: [PATCH 074/219] [TAS-117] implement first test --- src/core/libs/osnma_msg_receiver.cc | 17 +---------- .../osnma/osnma_sha2_test.cpp | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 src/tests/unit-tests/signal-processing-blocks/osnma/osnma_sha2_test.cpp diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 6bc8d487f..895a310aa 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -535,7 +535,6 @@ void osnma_msg_receiver::read_mack_header() void osnma_msg_receiver::read_mack_body() { - uint8_t lt_bits = 0; const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); if (it != OSNMA_TABLE_11.cend()) @@ -703,10 +702,6 @@ void osnma_msg_receiver::read_mack_body() d_osnma_data.d_mack_message.tag_and_info[k].tag_info.ADKD = ADKD; d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = cop; } - // TODO - [TAS-110] - // retrieve TESLA key: index i is [479-MH(l_t)-(nt-1)*(16+l_t), i+l_k] - // compute I (GST_SFi,GST_Kroot) - // perform recursive hash calls until base case: i = 10...1 // retrieve tesla key uint8_t start_index_bytes = ( 480 - (lt_bits + 16) - (nt - 1) * ( lt_bits + 16 ) - 1 ) / 8; // includes -1 to start at [i-1] @@ -798,12 +793,6 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // MACSEQ validation - case no FLX Tags - // C: TODO check ADKD-MACLT for match, also identify which tags are FLX - - - // d_osnma_data.d_dsm_kroot_message.maclt - // d_osnma_data.d_mack_message.tag_and_info[k].tag - // retrieve data to verify MACK tags uint8_t msg {0}; uint8_t nt {0}; @@ -840,21 +829,17 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; return; } - bool allOk = true; // one being invalid spoils the entire MACK std::vector flxTags {}; std::string tempADKD; for (uint8_t i = 0; i < d_osnma_data.d_mack_message.tag_and_info.size(); i++) { - // TODO - logic for asserting if if sq[i] == "FLX" (string) or "00X" (int built with first two digits) tempADKD = sequence[i]; if(tempADKD == "FLX") { flxTags.push_back(i); // C: just need to save the index in the sequence } else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(sequence[i])) - { - allOk = false; - std::cout << "Galileo OSNMA: Unsuccessful verification of received ADKD against MAC Look-up table. " << std::endl; + { std::cout << "Galileo OSNMA: Unsuccessful verification of received ADKD against MAC Look-up table. " << std::endl; return; // C: suffices one incorrect to abort and not process the rest of the tags } } diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_sha2_test.cpp b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_sha2_test.cpp new file mode 100644 index 000000000..4e04a837f --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_sha2_test.cpp @@ -0,0 +1,29 @@ +// +// Created by cghio on 17.01.24. +// +#include "gtest/gtest.h" +#include "gnss_crypto.h" +//#include "std" +#ifndef GNSS_SDR_GNSS_CRYPTO_SHA2_TEST_H +#define GNSS_SDR_GNSS_CRYPTO_SHA2_TEST_H + +class OsnmaCryptoTest : public :: testing ::Test{ +}; + +TEST_F(OsnmaCryptoTest, basicTest) +{ + std::unique_ptr d_crypto; + + auto str = "Hello World!"; + std::vector input (str, str + strlen(str)); + + auto expectedOutputStr = "86933b0b147ac4c010266b99004158fa17937db89a03dd7bb2ca5ef7f43c325a"; + std::vector expectedOutput(expectedOutputStr, expectedOutputStr + strlen(expectedOutputStr)); + + std::vector computedOutput = d_crypto->computeSHA256(input); + + ASSERT_TRUE(computedOutput == expectedOutput); + +} + +#endif // GNSS_SDR_GNSS_CRYPTO_SHA2_TEST_H From 50fbc3e9e5834ee299c60c507ad0652268b7f499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Sat, 20 Jan 2024 10:21:22 +0100 Subject: [PATCH 075/219] [TAS-111] time synch check: first draft --- .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 3 ++ src/core/libs/osnma_msg_receiver.cc | 48 +++++++++++++++---- src/core/libs/osnma_msg_receiver.h | 2 + 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index ec7db2067..298634dd1 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -188,6 +188,8 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, this->message_port_register_out(pmt::mp("pvt_to_trk")); // Send PVT status to gnss_flowgraph this->message_port_register_out(pmt::mp("status")); + // Send PVT time to OSNMA + this->message_port_register_out(pmt::mp("pvt_to_osnma")); // GPS Ephemeris data message port in this->message_port_register_in(pmt::mp("telemetry")); @@ -2139,6 +2141,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item // #### solve PVT and store the corrected observable set if (d_internal_pvt_solver->get_PVT(d_gnss_observables_map, d_observable_interval_ms / 1000.0)) { + this->message_port_pub(pmt::mp("pvt_to_osnma"), pmt::make_any(convert_to_time_t(d_internal_pvt_solver->get_position_UTC_time()))); d_pvt_errors_counter = 0; // Reset consecutive PVT error counter const double Rx_clock_offset_s = d_internal_pvt_solver->get_time_offset_s(); diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 895a310aa..68dec02e5 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -22,6 +22,7 @@ #include "gnss_crypto.h" #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader +#include "pvt_interface.h" #include // for DLOG #include // for gr::io_signature::make #include @@ -62,9 +63,6 @@ osnma_msg_receiver::osnma_msg_receiver( d_old_mack_message.set_capacity(10); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); - // register OSNMA output message port to PVT block - this->message_port_register_out(pmt::mp("OSNMA_to_PVT")); - this->set_msg_handler(pmt::mp("OSNMA_from_TLM"), #if HAS_GENERIC_LAMBDA [this](auto&& PH1) { msg_handler_osnma(PH1); }); @@ -75,9 +73,33 @@ osnma_msg_receiver::osnma_msg_receiver( boost::bind(&osnma_msg_receiver::msg_handler_osnma, this, _1)); #endif #endif + // register OSNMA input message port from PVT block + this->message_port_register_in(pmt::mp("pvt_to_osnma")); + this->set_msg_handler(pmt::mp("pvt_to_osnma"), +#if HAS_GENERIC_LAMBDA + [this](auto&& PH1) { msg_handler_pvt_to_osnma(PH1); }); +#else +#if USE_BOOST_BIND_PLACEHOLDERS + boost::bind(&osnma_msg_receiver::msg_handler_pvt_to_osnma, this, boost::placeholders::_1)); +#else + boost::bind(&osnma_msg_receiver::msg_handler_pvt_to_osnma, this, _1)); +#endif +#endif + // register OSNMA output message port to PVT block + this->message_port_register_out(pmt::mp("OSNMA_to_PVT")); } - +void osnma_msg_receiver::msg_handler_pvt_to_osnma(const pmt::pmt_t& msg) +{ + try + { + d_receiver_time = wht::any_cast(pmt::any_ref(msg)); // C: TODO - check if this is the correct way to get the time from the PVT block + } + catch (const pmt::exception& e) + { + LOG(WARNING) << "osnma_msg_receiver pmt exception: " << e.what(); + } +} void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) { // requires mutex with msg_handler_osnma function called by the scheduler @@ -97,7 +119,18 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) << ", from satellite " << sat << std::endl; - process_osnma_message(nma_msg); + + // compare local time with OSNMA subframe time + d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... + double_t T_L = 15; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time + if(abs(d_GST_SIS - d_receiver_time) <= T_L) + { + process_osnma_message(nma_msg); + } + else + { + LOG(WARNING) << "OSNMA: Subframe received with time difference greater than " << T_L << " seconds"; + } } else { @@ -432,7 +465,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_public_key_verified = true; d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk); } - } } @@ -446,7 +478,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } - +// reads Mack message void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma_msg) { uint32_t index = 0; @@ -789,6 +821,7 @@ void osnma_msg_receiver::read_mack_body() void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) { + // TODO - is it filled at this point always? d_old_mack_message.push_back(d_osnma_data.d_mack_message); // C: old mack message is needed for // MACSEQ validation - case no FLX Tags @@ -1018,7 +1051,6 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) { std::cout << "Galileo OSNMA: DSM-PKR verified successfully! " << std::endl; return true; - // C: NPK verification against Merkle tree root. } else { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 655f0dae5..b79719093 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -60,6 +60,7 @@ private: osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); + void msg_handler_pvt_to_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); @@ -88,6 +89,7 @@ private: uint8_t d_Lt_min {}; // minimum equivalent tag length uint32_t d_GST_0 {}; uint32_t d_GST_SIS {}; + std::time_t d_receiver_time {}; }; From 08bd1992af7730a7b66f46c75a0c33881ed54983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Mon, 22 Jan 2024 17:55:52 +0100 Subject: [PATCH 076/219] [TAS-125] NavData retrieval. * set osnma flags to true when new data * send them to osnma block if filled. --- .../galileo_telemetry_decoder_gs.cc | 10 +++++++++- .../gnuradio_blocks/galileo_telemetry_decoder_gs.h | 3 +++ src/core/system_parameters/galileo_inav_message.cc | 10 ++++++---- src/core/system_parameters/galileo_inav_message.h | 14 +++++++++----- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 80a94aab0..991fb6895 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -465,6 +465,8 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); d_first_eph_sent = true; // do not send reduced CED anymore, since we have the full ephemeris set + + d_flag_osnma_ephemeris = true; } else { @@ -514,6 +516,8 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in << d_satellite << " with CN0=" << std::setprecision(2) << cn0 << std::setprecision(default_precision) << " dB-Hz" << TEXT_RESET << std::endl; } + + d_flag_osnma_iono_and_time = true; } if (d_inav_nav.have_new_utc_model() == true) @@ -549,6 +553,8 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_delta_t = tmp_obj->A_0G + tmp_obj->A_1G * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - tmp_obj->t_0G + 604800 * (std::fmod(static_cast(d_inav_nav.get_Galileo_week() - tmp_obj->WN_0G), 64.0))); DLOG(INFO) << "delta_t=" << d_delta_t << "[s]"; + + d_flag_osnma_utc_model = true; } if (d_inav_nav.have_new_almanac() == true) @@ -584,7 +590,9 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in DLOG(INFO) << "d_nav.WN_0=" << d_inav_nav.get_Galileo_week(); } - if (d_band == '1' && d_inav_nav.have_new_nma() == true) + // get osnma message if the needed nav data is available + auto adkd_4_12_nav_data_available = d_flag_osnma_iono_and_time && d_flag_osnma_ephemeris; + if (d_band == '1' && d_inav_nav.have_new_nma() == true && adkd_4_12_nav_data_available == true && d_flag_osnma_utc_model == true) { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h index a6391a2e0..bad8c8fc5 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h @@ -155,6 +155,9 @@ private: bool d_there_are_e1_channels; bool d_there_are_e6_channels; bool d_use_ced; + bool d_flag_osnma_ephemeris; // flag to indicate if the ephemeris is complete for OSNMA processing + bool d_flag_osnma_utc_model; // flag to indicate if the GST conversion parameters are complete for OSNMA processing + bool d_flag_osnma_iono_and_time; // flag to indicate if the iono correction and time is complete for OSNMA processing }; diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index 565009dc7..7a500d788 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1387,15 +1387,17 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() nma_position_filled = std::array{}; // Fill TOW and WN nma_msg.WN_sf0 = WN_0; - int32_t TOW_sf0 = TOW_5 - 24; + int32_t TOW_sf0 = TOW_5 - 24; // TODO - why not TOW_0? if (TOW_sf0 < 0) { TOW_sf0 += 604800; } nma_msg.TOW_sf0 = static_cast(TOW_sf0); - // TODO - draft for retrieving NavData for use during Tag verification. - nma_msg.t0e_1 = static_cast(t0e_1); - nma_msg.IOD_nav = static_cast(IOD_nav_1); +// nma_msg.TOW_sf0 = static_cast(TOW_0); + // get ephemeris, clock and iono correction datn and GST-UTC and GST-GPS converstion parameters (may be incomplete) + nma_msg.EphemerisData = get_ephemeris(); + nma_msg.IonoData = get_iono(); + nma_msg.UtcModelData = get_utc_model(); return nma_msg; } diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index d6139c7e0..13db80706 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -39,7 +39,9 @@ class ReedSolomon; // Forward declaration of the ReedSolomon class * \{ */ /** \addtogroup System_Parameters * \{ */ - +/*! + * \brief This class fills the OSNMA_msg structure with the data received from the telemetry blocks. + */ class OSNMA_msg { public: @@ -47,13 +49,15 @@ public: std::array mack{}; std::array hkroot{}; uint32_t PRN{}; - uint32_t WN_sf0{}; + uint32_t WN_sf0{}; // TODO - this is present in UtcModelData already uint32_t TOW_sf0{}; - // TODO - NavData to be retrieved correctly std::vector EphemerisClockAndStatusData {}; std::vector TimingData {}; - uint32_t t0e_1{}; - uint32_t IOD_nav{}; + Galileo_Ephemeris EphemerisData {}; + Galileo_Iono IonoData {}; + Galileo_Utc_Model UtcModelData {}; + + }; /*! From 620249f9f2aab0e9741787d0bc64c2daea9723a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Thu, 25 Jan 2024 17:11:28 +0100 Subject: [PATCH 077/219] [TAS-126] [TAS-125] NavData storage of last 10 SFs / NavData retrieval: store needed NavData within osnma_data::NavData for the last 10 subframes * In osnma_msg_receiver: d_old_navdata_buffer to store last 10 NavData. * In osnma_msg_receiver::process_mack_message: pass needed data to the newly created structure osnma_data::NavData, generate needed vectors for tag verification. * In osnma_data.h/cc: Create NavData structure, Create osnma_data.cc source file, add to CMakeLists source file. --- src/core/libs/osnma_msg_receiver.cc | 13 +- src/core/libs/osnma_msg_receiver.h | 1 + src/core/system_parameters/CMakeLists.txt | 1 + .../system_parameters/galileo_inav_message.cc | 1 + src/core/system_parameters/osnma_data.cc | 185 ++++++++++++++++++ src/core/system_parameters/osnma_data.h | 22 +++ 6 files changed, 219 insertions(+), 4 deletions(-) create mode 100644 src/core/system_parameters/osnma_data.cc diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 68dec02e5..66099e054 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -145,7 +145,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // Send the resulting decoded NMA data (if available) to PVT if (d_new_data == true) // TODO where is it set to true? { - auto osnma_data_ptr = std::make_shared(d_osnma_data); // C: why create new object and pass it empty to Pvt? + auto osnma_data_ptr = std::make_shared(d_osnma_data); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); d_new_data = false; // d_osnma_data = OSNMA_data(); @@ -821,9 +821,14 @@ void osnma_msg_receiver::read_mack_body() void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) { - // TODO - is it filled at this point always? - d_old_mack_message.push_back(d_osnma_data.d_mack_message); // C: old mack message is needed for - + d_old_mack_message.push_back(d_osnma_data.d_mack_message); // last 10 MACKs are needed to be stored as per ICD + // populate d_nav_data with three classes of osnma_msg + d_osnma_data.d_nav_data.EphemerisData = osnma_msg->EphemerisData; + d_osnma_data.d_nav_data.IonoData = osnma_msg->IonoData; + d_osnma_data.d_nav_data.UtcData = osnma_msg->UtcModelData; + d_osnma_data.d_nav_data.generate_eph_iono_vector2(); + d_osnma_data.d_nav_data.generate_utc_vector(); + d_old_navdata_buffer.push_back(d_osnma_data.d_nav_data); // last 10 NavData messages are needed to be stored as per ICD // MACSEQ validation - case no FLX Tags // retrieve data to verify MACK tags diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index b79719093..6b694f32d 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -73,6 +73,7 @@ private: void process_mack_message(const std::shared_ptr& osnma_msg); boost::circular_buffer d_old_mack_message; + boost::circular_buffer d_old_navdata_buffer; // buffer that holds last 10 received navdata messages std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 9db20a317..dc78ae094 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -30,6 +30,7 @@ set(SYSTEM_PARAMETERS_SOURCES glonass_gnav_navigation_message.cc reed_solomon.cc osnma_dsm_reader.cc + osnma_data.cc ) set(SYSTEM_PARAMETERS_HEADERS diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index 7a500d788..869ba3c35 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1384,6 +1384,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) OSNMA_msg Galileo_Inav_Message::get_osnma_msg() { + // TODO - why PRN of word 4 is done separately? nma_position_filled = std::array{}; // Fill TOW and WN nma_msg.WN_sf0 = WN_0; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc new file mode 100644 index 000000000..db4b5c553 --- /dev/null +++ b/src/core/system_parameters/osnma_data.cc @@ -0,0 +1,185 @@ +/*! +* \file osnma_data.cc +* \brief Class for Galileo OSNMA data storage +* \author Carles Fernandez-Prades, 2020-2023 cfernandez(at)cttc.es +* +* ----------------------------------------------------------------------------- +* +* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +* This file is part of GNSS-SDR. +* +* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) +* SPDX-License-Identifier: GPL-3.0-or-later +* +* ----------------------------------------------------------------------------- +*/ + +#include "osnma_data.h" +#include + +void NavData::generate_eph_iono_vector() +{ + ephemeris_iono_vector.clear(); + ephemeris_iono_vector.push_back(static_cast((EphemerisData.IOD_nav & 0b0000'0000'0000'0000'0000'0011'1111'1100) >> 2)); + ephemeris_iono_vector.push_back(static_cast((EphemerisData.IOD_nav & 0b0000'0000'0000'0000'0000'0000'0000'0011) << 6 + | (EphemerisData.toe & 0b0000'0000'0000'0000'0011'1111'1111'1111) >> 8)); + ephemeris_iono_vector.push_back(static_cast(EphemerisData.toe)); + uint64_t binary_representation; + memcpy(&binary_representation, &EphemerisData.M_0, sizeof(EphemerisData.M_0)); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 8))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 16))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 24))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 32))); + memcpy(&binary_representation, &EphemerisData.ecc, sizeof(EphemerisData.ecc)); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 8))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 16))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 24))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 32))); + memcpy(&binary_representation, &EphemerisData.sqrtA, sizeof(EphemerisData.sqrtA)); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 8))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 16))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 24))); + ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 32))); + + // TODO: Implement the function to generate the rest of pages +} + +void NavData::generate_eph_iono_vector2() +{ + std::vector eph_iono_vector; + uint64_t bit_buffer = 0; // variable to store the bits to be extracted, it can contain bits from different variables + int bit_count = 0; // Number of bits in the buffer, i.e. to be extracted + + // create structure to hold the variables to store into the vector along with their bit size + std::vector> variables = { + // data from word type 1 + {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, + {static_cast(&EphemerisData.toe), sizeof(EphemerisData.toe) * 8}, + {static_cast(&EphemerisData.M_0), sizeof(EphemerisData.M_0) * 8}, + {static_cast(&EphemerisData.ecc), sizeof(EphemerisData.ecc) * 8}, + {static_cast(&EphemerisData.sqrtA), sizeof(EphemerisData.sqrtA) * 8}, + // data from word type 2 + {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, + {static_cast(&EphemerisData.OMEGA_0), sizeof(EphemerisData.OMEGA_0) * 8}, + {static_cast(&EphemerisData.i_0), sizeof(EphemerisData.i_0) * 8}, + {static_cast(&EphemerisData.omega), sizeof(EphemerisData.omega) * 8}, + {static_cast(&EphemerisData.idot), sizeof(EphemerisData.idot) * 8}, + {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, + // data from word type 3 + {static_cast(&EphemerisData.OMEGAdot), sizeof(EphemerisData.OMEGAdot) * 8}, + {static_cast(&EphemerisData.delta_n), sizeof(EphemerisData.delta_n) * 8}, + {static_cast(&EphemerisData.Cuc), sizeof(EphemerisData.Cuc) * 8}, + {static_cast(&EphemerisData.Cus), sizeof(EphemerisData.Cus) * 8}, + {static_cast(&EphemerisData.Crc), sizeof(EphemerisData.Crc) * 8}, + {static_cast(&EphemerisData.Crs), sizeof(EphemerisData.Crs) * 8}, + {static_cast(&EphemerisData.SISA), sizeof(EphemerisData.SISA) * 8}, + // data from word type 4 + {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, + {static_cast(&EphemerisData.PRN), sizeof(EphemerisData.PRN) * 8}, + {static_cast(&EphemerisData.Cic), sizeof(EphemerisData.Cic) * 8}, + {static_cast(&EphemerisData.Cis), sizeof(EphemerisData.Cis) * 8}, + {static_cast(&EphemerisData.toe), sizeof(EphemerisData.toe) * 8}, + {static_cast(&EphemerisData.af0), sizeof(EphemerisData.af0) * 8}, + {static_cast(&EphemerisData.af1), sizeof(EphemerisData.af1) * 8}, + {static_cast(&EphemerisData.af2), sizeof(EphemerisData.af2) * 8}, + // data from word type 5 + {static_cast(&IonoData.ai0), sizeof(IonoData.ai0) * 8}, + {static_cast(&IonoData.ai1), sizeof(IonoData.ai1) * 8}, + {static_cast(&IonoData.ai2), sizeof(IonoData.ai2) * 8}, + {static_cast(&IonoData.Region1_flag), sizeof(IonoData.Region1_flag) * 8}, + {static_cast(&IonoData.Region2_flag), sizeof(IonoData.Region2_flag) * 8}, + {static_cast(&IonoData.Region3_flag), sizeof(IonoData.Region3_flag) * 8}, + {static_cast(&IonoData.Region4_flag), sizeof(IonoData.Region4_flag) * 8}, + {static_cast(&IonoData.Region5_flag), sizeof(IonoData.Region5_flag) * 8}, + {static_cast(&EphemerisData.BGD_E1E5a), sizeof(EphemerisData.BGD_E1E5a) * 8}, + {static_cast(&EphemerisData.BGD_E1E5b), sizeof(EphemerisData.BGD_E1E5b) * 8}, + {static_cast(&EphemerisData.E5b_HS), sizeof(EphemerisData.E5b_HS) * 8}, + {static_cast(&EphemerisData.E1B_HS), sizeof(EphemerisData.E1B_HS) * 8}, + {static_cast(&EphemerisData.E5b_DVS), sizeof(EphemerisData.E5b_DVS) * 8}, + {static_cast(&EphemerisData.E1B_DVS), sizeof(EphemerisData.E1B_DVS) * 8}, + }; + + for (auto& var : variables) + { + // extract the bits from the variable + uint64_t binary_representation; + memcpy(&binary_representation, var.first, var.second / 8); + + // Append the bits to the buffer and update the bit count + bit_buffer = (bit_buffer << var.second) | binary_representation; + bit_count += var.second; + // While there are 8 or more bits in the buffer + while (bit_count >= 8) + { + // Extract the 8 bits starting from last bit position and add them to the vector + uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; + eph_iono_vector.push_back(extracted_bits); + + // Remove the extracted bits from the buffer + bit_count -= 8; + bit_buffer = bit_buffer & ~(0xFF << bit_count); + } + + } + + // If there are any bits left in the buffer, add them to the vector + if (bit_count > 0) + { + eph_iono_vector.push_back(static_cast(bit_buffer)); + } +} + +void NavData::generate_utc_vector() +{ + utc_vector.clear(); + uint64_t bit_buffer = 0; + int bit_count = 0; + + std::vector> variables = { + {static_cast(&UtcData.A0), sizeof(UtcData.A0) * 8}, + {static_cast(&UtcData.A1), sizeof(UtcData.A1) * 8}, + {static_cast(&UtcData.Delta_tLS), sizeof(UtcData.Delta_tLS) * 8}, + {static_cast(&UtcData.tot), sizeof(UtcData.tot) * 8}, + {static_cast(&UtcData.WNot), sizeof(UtcData.WNot) * 8}, + {static_cast(&UtcData.WN_LSF), sizeof(UtcData.WN_LSF) * 8}, + {static_cast(&UtcData.DN), sizeof(UtcData.DN) * 8}, + {static_cast(&UtcData.Delta_tLSF), sizeof(UtcData.Delta_tLSF) * 8}, + {static_cast(&UtcData.A_0G), sizeof(UtcData.A_0G) * 8}, + {static_cast(&UtcData.A_1G), sizeof(UtcData.A_1G) * 8}, + {static_cast(&UtcData.t_0G), sizeof(UtcData.t_0G) * 8}, + {static_cast(&UtcData.WN_0G), sizeof(UtcData.WN_0G) * 8}, + }; + + for (auto& var : variables) + { + uint64_t binary_representation; + memcpy(&binary_representation, var.first, var.second / 8); + + bit_buffer = (bit_buffer << var.second) | binary_representation; + bit_count += var.second; + + while (bit_count >= 8) + { + uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; + utc_vector.push_back(extracted_bits); + + bit_count -= 8; + bit_buffer = bit_buffer & ~(0xFF << bit_count); + } + } + + if (bit_count > 0) + { + utc_vector.push_back(static_cast(bit_buffer)); + } +} + +std::vector NavData::get_eph_iono_vector() +{ + return ephemeris_iono_vector; +} + +std::vector NavData::get_utc_vector() +{ + return utc_vector; +} diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index a19666d5b..941e7c8bc 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -18,6 +18,9 @@ #ifndef GNSS_SDR_OSNMA_DATA_H #define GNSS_SDR_OSNMA_DATA_H +#include "galileo_ephemeris.h" +#include "galileo_iono.h" +#include "galileo_utc_model.h" #include #include #include @@ -119,6 +122,24 @@ public: std::vector key; }; +class NavData +{ +public: + NavData() = default; + Galileo_Ephemeris EphemerisData; + Galileo_Iono IonoData; + Galileo_Utc_Model UtcData; + void generate_eph_iono_vector(); // TODO check with Carles procedure and compare with v2 + void generate_eph_iono_vector2(); + void generate_utc_vector(); // TODO + std::vector get_eph_iono_vector(); // TODO + std::vector get_utc_vector(); // TODO +private: + std::vector ephemeris_iono_vector; + std::vector utc_vector; + +}; + /*! * \brief This class handles ONSMA data * See https://www.gsc-europa.eu/sites/default/files/sites/all/files/Galileo_OSNMA_User_ICD_for_Test_Phase_v1.0.pdf @@ -132,6 +153,7 @@ public: DSM_PKR_message d_dsm_pkr_message; DSM_KROOT_message d_dsm_kroot_message; MACK_message d_mack_message; + NavData d_nav_data; }; From ba2e392a5d58a08b3b123baf6e1c836de49141a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Mon, 29 Jan 2024 17:05:47 +0100 Subject: [PATCH 078/219] [TAS-111] time synch check --- src/core/libs/osnma_msg_receiver.cc | 12 +++++++++--- src/core/libs/osnma_msg_receiver.h | 3 ++- src/core/system_parameters/galileo_utc_model.cc | 5 +++++ src/core/system_parameters/galileo_utc_model.h | 1 + src/core/system_parameters/osnma_data.cc | 2 +- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 66099e054..1f96afb61 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -23,6 +23,7 @@ #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "pvt_interface.h" +#include "galileo_utc_model.h" // for Galileo_Utc_Model #include // for DLOG #include // for gr::io_signature::make #include @@ -54,9 +55,11 @@ osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, osnma_msg_receiver::osnma_msg_receiver( const std::string& pemFilePath, - const std::string& merkleFilePath) : gr::block("osnma_msg_receiver", + const std::string& merkleFilePath, + const Galileo_Utc_Model &utc_model) : 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)), + galileo_utc_model(utc_model) { d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(pemFilePath, merkleFilePath); @@ -93,7 +96,9 @@ void osnma_msg_receiver::msg_handler_pvt_to_osnma(const pmt::pmt_t& msg) { try { - d_receiver_time = wht::any_cast(pmt::any_ref(msg)); // C: TODO - check if this is the correct way to get the time from the PVT block + // receive the UTC time + auto utc_time_from_pvt = wht::any_cast(pmt::any_ref(msg)); // C: TODO - check if this is the correct way to get the time from the PVT block + } catch (const pmt::exception& e) { @@ -122,6 +127,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // compare local time with OSNMA subframe time d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... + auto utc = galileo_utc_model.GST_to_UTC_time(d_GST_SIS, static_cast(nma_msg->WN_sf0)); double_t T_L = 15; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time if(abs(d_GST_SIS - d_receiver_time) <= T_L) { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 6b694f32d..27c07ae56 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -57,7 +57,7 @@ public: private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); - osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); + osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath, const Galileo_Utc_Model &galileo_utc_model); void msg_handler_osnma(const pmt::pmt_t& msg); void msg_handler_pvt_to_osnma(const pmt::pmt_t& msg); @@ -83,6 +83,7 @@ private: std::array d_mack_message{}; // C: 480 b OSNMA_data d_osnma_data{}; + Galileo_Utc_Model galileo_utc_model; bool d_new_data{false}; bool d_public_key_verified{false}; bool d_kroot_verified{false}; diff --git a/src/core/system_parameters/galileo_utc_model.cc b/src/core/system_parameters/galileo_utc_model.cc index 4f3a41df8..d14aa8c42 100644 --- a/src/core/system_parameters/galileo_utc_model.cc +++ b/src/core/system_parameters/galileo_utc_model.cc @@ -72,3 +72,8 @@ double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) const t_Utc = secondsOfWeekBeforeToday + t_Utc_daytime; return t_Utc; } + +double Galileo_Utc_Model::UTC_time_to_GST(double t_Utc, int32_t WN) const +{ + // TODO +} \ No newline at end of file diff --git a/src/core/system_parameters/galileo_utc_model.h b/src/core/system_parameters/galileo_utc_model.h index adb941daa..6024a41d0 100644 --- a/src/core/system_parameters/galileo_utc_model.h +++ b/src/core/system_parameters/galileo_utc_model.h @@ -43,6 +43,7 @@ public: // double TOW; double GST_to_UTC_time(double t_e, int32_t WN) const; //!< GST-UTC Conversion Algorithm and Parameters + double UTC_time_to_GST(double t_Utc, int32_t WN) const; // Word type 6: GST-UTC conversion parameters double A0{}; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index db4b5c553..110b85241 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -102,7 +102,7 @@ void NavData::generate_eph_iono_vector2() for (auto& var : variables) { // extract the bits from the variable - uint64_t binary_representation; + uint64_t binary_representation; // FIXME types have more bits than the specification size, e.g. 32 bits vs 10 bits memcpy(&binary_representation, var.first, var.second / 8); // Append the bits to the buffer and update the bit count From 51b4209535bdfc592e062896093871d65bb8b8b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cesare=20G=2E=20Mart=C3=ADnez?= Date: Mon, 29 Jan 2024 17:05:47 +0100 Subject: [PATCH 079/219] [TAS-111] Refactor Galileo_Utc_Model and time synchronization in osnma_msg_receiver In osnma_msg_receiver, the time synchronization between OSNMA subframes and local time has been updated. To facilitate this, the Galileo_Utc_Model has been refactored to be used statically, instead of being passed through the osnma_msg_receiver constructor. Additional changes include: adjusting variable declarations, adding an initialization method, altering the function GST_to_UTC_time to be static, and removing an unused instantiation of the model in osnma_msg_receiver. --- src/core/libs/osnma_msg_receiver.cc | 8 ++++-- src/core/libs/osnma_msg_receiver.h | 3 +- .../system_parameters/galileo_utc_model.cc | 14 +++++++++- .../system_parameters/galileo_utc_model.h | 28 +++++++++++++------ 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 1f96afb61..1131ffbc3 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -127,9 +127,11 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // compare local time with OSNMA subframe time d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... - auto utc = galileo_utc_model.GST_to_UTC_time(d_GST_SIS, static_cast(nma_msg->WN_sf0)); - double_t T_L = 15; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time - if(abs(d_GST_SIS - d_receiver_time) <= T_L) + // instantiate galileo_utc_model and call init function, then call GST_to_UTC_time + Galileo_Utc_Model::init(nma_msg->utc_data); + double_t utc = Galileo_Utc_Model::GST_to_UTC_time(static_cast(d_GST_SIS), static_cast(nma_msg->WN_sf0)); + double_t T_L = 15.0; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time + if(abs(utc - d_receiver_time) <= T_L) { process_osnma_message(nma_msg); } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 27c07ae56..efaadd6a2 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -72,6 +72,7 @@ private: void read_mack_body(); void process_mack_message(const std::shared_ptr& osnma_msg); +// Galileo_Utc_Model galileo_utc_model; boost::circular_buffer d_old_mack_message; boost::circular_buffer d_old_navdata_buffer; // buffer that holds last 10 received navdata messages std::unique_ptr d_dsm_reader; @@ -91,7 +92,7 @@ private: uint8_t d_Lt_min {}; // minimum equivalent tag length uint32_t d_GST_0 {}; uint32_t d_GST_SIS {}; - std::time_t d_receiver_time {}; + std::time_t d_receiver_time {}; // PVT time computed by the local receiver }; diff --git a/src/core/system_parameters/galileo_utc_model.cc b/src/core/system_parameters/galileo_utc_model.cc index d14aa8c42..74ea2ba43 100644 --- a/src/core/system_parameters/galileo_utc_model.cc +++ b/src/core/system_parameters/galileo_utc_model.cc @@ -17,8 +17,19 @@ #include "galileo_utc_model.h" #include +void Galileo_Utc_Model::init(const Galileo_Utc_Model& data) +{ + A0 = data.A0; + A1 = data.A1; + Delta_tLS = data.Delta_tLS; + Delta_tLSF = data.Delta_tLSF; + DN = data.DN; + tot = data.tot; + WNot = data.WNot; + WN_LSF = data.WN_LSF; -double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) const +} +double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) { double t_Utc; double t_Utc_daytime; @@ -76,4 +87,5 @@ double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) const double Galileo_Utc_Model::UTC_time_to_GST(double t_Utc, int32_t WN) const { // TODO + return 0; } \ No newline at end of file diff --git a/src/core/system_parameters/galileo_utc_model.h b/src/core/system_parameters/galileo_utc_model.h index 6024a41d0..c762c428f 100644 --- a/src/core/system_parameters/galileo_utc_model.h +++ b/src/core/system_parameters/galileo_utc_model.h @@ -41,19 +41,29 @@ public: */ Galileo_Utc_Model() = default; + /** + * @brief Initialize the Galileo_UTC_Model with the provided data. + * + * This function initializes the Galileo_UTC_Model object with the given data. + * + * @param data The Galileo_UTC_Model object containing the data. + */ + static void init(const Galileo_Utc_Model& data); + // double TOW; - double GST_to_UTC_time(double t_e, int32_t WN) const; //!< GST-UTC Conversion Algorithm and Parameters + static double GST_to_UTC_time(double t_e, int32_t WN); //!< GST-UTC Conversion Algorithm and Parameters double UTC_time_to_GST(double t_Utc, int32_t WN) const; + // TODO - make them private? // Word type 6: GST-UTC conversion parameters - double A0{}; - double A1{}; - int32_t Delta_tLS{}; - int32_t tot{}; //!< UTC data reference Time of Week [s] - int32_t WNot{}; //!< UTC data reference Week number [week] - int32_t WN_LSF{}; - int32_t DN{}; - int32_t Delta_tLSF{}; + static double A0; + static double A1; + static int32_t Delta_tLS; + static int32_t tot; //!< UTC data reference Time of Week [s] + static int32_t WNot; //!< UTC data reference Week number [week] + static int32_t WN_LSF; + static int32_t DN; + static int32_t Delta_tLSF; // GPS to Galileo GST conversion parameters double A_0G{}; From dafa7403dce9ff027b6e9bc89503c418a3623f10 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 1 Feb 2024 06:12:25 +0100 Subject: [PATCH 080/219] Revert "[TAS-111] Refactor Galileo_Utc_Model and time synchronization in osnma_msg_receiver" This reverts commit 51b4209535bdfc592e062896093871d65bb8b8b9. --- src/core/libs/osnma_msg_receiver.cc | 8 ++---- src/core/libs/osnma_msg_receiver.h | 3 +- .../system_parameters/galileo_utc_model.cc | 14 +--------- .../system_parameters/galileo_utc_model.h | 28 ++++++------------- 4 files changed, 14 insertions(+), 39 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 1131ffbc3..1f96afb61 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -127,11 +127,9 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // compare local time with OSNMA subframe time d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... - // instantiate galileo_utc_model and call init function, then call GST_to_UTC_time - Galileo_Utc_Model::init(nma_msg->utc_data); - double_t utc = Galileo_Utc_Model::GST_to_UTC_time(static_cast(d_GST_SIS), static_cast(nma_msg->WN_sf0)); - double_t T_L = 15.0; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time - if(abs(utc - d_receiver_time) <= T_L) + auto utc = galileo_utc_model.GST_to_UTC_time(d_GST_SIS, static_cast(nma_msg->WN_sf0)); + double_t T_L = 15; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time + if(abs(d_GST_SIS - d_receiver_time) <= T_L) { process_osnma_message(nma_msg); } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index efaadd6a2..27c07ae56 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -72,7 +72,6 @@ private: void read_mack_body(); void process_mack_message(const std::shared_ptr& osnma_msg); -// Galileo_Utc_Model galileo_utc_model; boost::circular_buffer d_old_mack_message; boost::circular_buffer d_old_navdata_buffer; // buffer that holds last 10 received navdata messages std::unique_ptr d_dsm_reader; @@ -92,7 +91,7 @@ private: uint8_t d_Lt_min {}; // minimum equivalent tag length uint32_t d_GST_0 {}; uint32_t d_GST_SIS {}; - std::time_t d_receiver_time {}; // PVT time computed by the local receiver + std::time_t d_receiver_time {}; }; diff --git a/src/core/system_parameters/galileo_utc_model.cc b/src/core/system_parameters/galileo_utc_model.cc index 74ea2ba43..d14aa8c42 100644 --- a/src/core/system_parameters/galileo_utc_model.cc +++ b/src/core/system_parameters/galileo_utc_model.cc @@ -17,19 +17,8 @@ #include "galileo_utc_model.h" #include -void Galileo_Utc_Model::init(const Galileo_Utc_Model& data) -{ - A0 = data.A0; - A1 = data.A1; - Delta_tLS = data.Delta_tLS; - Delta_tLSF = data.Delta_tLSF; - DN = data.DN; - tot = data.tot; - WNot = data.WNot; - WN_LSF = data.WN_LSF; -} -double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) +double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) const { double t_Utc; double t_Utc_daytime; @@ -87,5 +76,4 @@ double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) double Galileo_Utc_Model::UTC_time_to_GST(double t_Utc, int32_t WN) const { // TODO - return 0; } \ No newline at end of file diff --git a/src/core/system_parameters/galileo_utc_model.h b/src/core/system_parameters/galileo_utc_model.h index c762c428f..6024a41d0 100644 --- a/src/core/system_parameters/galileo_utc_model.h +++ b/src/core/system_parameters/galileo_utc_model.h @@ -41,29 +41,19 @@ public: */ Galileo_Utc_Model() = default; - /** - * @brief Initialize the Galileo_UTC_Model with the provided data. - * - * This function initializes the Galileo_UTC_Model object with the given data. - * - * @param data The Galileo_UTC_Model object containing the data. - */ - static void init(const Galileo_Utc_Model& data); - // double TOW; - static double GST_to_UTC_time(double t_e, int32_t WN); //!< GST-UTC Conversion Algorithm and Parameters + double GST_to_UTC_time(double t_e, int32_t WN) const; //!< GST-UTC Conversion Algorithm and Parameters double UTC_time_to_GST(double t_Utc, int32_t WN) const; - // TODO - make them private? // Word type 6: GST-UTC conversion parameters - static double A0; - static double A1; - static int32_t Delta_tLS; - static int32_t tot; //!< UTC data reference Time of Week [s] - static int32_t WNot; //!< UTC data reference Week number [week] - static int32_t WN_LSF; - static int32_t DN; - static int32_t Delta_tLSF; + double A0{}; + double A1{}; + int32_t Delta_tLS{}; + int32_t tot{}; //!< UTC data reference Time of Week [s] + int32_t WNot{}; //!< UTC data reference Week number [week] + int32_t WN_LSF{}; + int32_t DN{}; + int32_t Delta_tLSF{}; // GPS to Galileo GST conversion parameters double A_0G{}; From a32bdae396c4f0394d6abe2d4c4d9062a50f1dc0 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 1 Feb 2024 06:12:26 +0100 Subject: [PATCH 081/219] Revert "[TAS-111] time synch check" This reverts commit ba2e392a5d58a08b3b123baf6e1c836de49141a4. --- src/core/libs/osnma_msg_receiver.cc | 12 +++--------- src/core/libs/osnma_msg_receiver.h | 3 +-- src/core/system_parameters/galileo_utc_model.cc | 5 ----- src/core/system_parameters/galileo_utc_model.h | 1 - src/core/system_parameters/osnma_data.cc | 2 +- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 1f96afb61..66099e054 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -23,7 +23,6 @@ #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "pvt_interface.h" -#include "galileo_utc_model.h" // for Galileo_Utc_Model #include // for DLOG #include // for gr::io_signature::make #include @@ -55,11 +54,9 @@ osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, osnma_msg_receiver::osnma_msg_receiver( const std::string& pemFilePath, - const std::string& merkleFilePath, - const Galileo_Utc_Model &utc_model) : gr::block("osnma_msg_receiver", + const std::string& merkleFilePath) : gr::block("osnma_msg_receiver", gr::io_signature::make(0, 0, 0), - gr::io_signature::make(0, 0, 0)), - galileo_utc_model(utc_model) + gr::io_signature::make(0, 0, 0)) { d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(pemFilePath, merkleFilePath); @@ -96,9 +93,7 @@ void osnma_msg_receiver::msg_handler_pvt_to_osnma(const pmt::pmt_t& msg) { try { - // receive the UTC time - auto utc_time_from_pvt = wht::any_cast(pmt::any_ref(msg)); // C: TODO - check if this is the correct way to get the time from the PVT block - + d_receiver_time = wht::any_cast(pmt::any_ref(msg)); // C: TODO - check if this is the correct way to get the time from the PVT block } catch (const pmt::exception& e) { @@ -127,7 +122,6 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // compare local time with OSNMA subframe time d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... - auto utc = galileo_utc_model.GST_to_UTC_time(d_GST_SIS, static_cast(nma_msg->WN_sf0)); double_t T_L = 15; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time if(abs(d_GST_SIS - d_receiver_time) <= T_L) { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 27c07ae56..6b694f32d 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -57,7 +57,7 @@ public: private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); - osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath, const Galileo_Utc_Model &galileo_utc_model); + osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void msg_handler_pvt_to_osnma(const pmt::pmt_t& msg); @@ -83,7 +83,6 @@ private: std::array d_mack_message{}; // C: 480 b OSNMA_data d_osnma_data{}; - Galileo_Utc_Model galileo_utc_model; bool d_new_data{false}; bool d_public_key_verified{false}; bool d_kroot_verified{false}; diff --git a/src/core/system_parameters/galileo_utc_model.cc b/src/core/system_parameters/galileo_utc_model.cc index d14aa8c42..4f3a41df8 100644 --- a/src/core/system_parameters/galileo_utc_model.cc +++ b/src/core/system_parameters/galileo_utc_model.cc @@ -72,8 +72,3 @@ double Galileo_Utc_Model::GST_to_UTC_time(double t_e, int32_t WN) const t_Utc = secondsOfWeekBeforeToday + t_Utc_daytime; return t_Utc; } - -double Galileo_Utc_Model::UTC_time_to_GST(double t_Utc, int32_t WN) const -{ - // TODO -} \ No newline at end of file diff --git a/src/core/system_parameters/galileo_utc_model.h b/src/core/system_parameters/galileo_utc_model.h index 6024a41d0..adb941daa 100644 --- a/src/core/system_parameters/galileo_utc_model.h +++ b/src/core/system_parameters/galileo_utc_model.h @@ -43,7 +43,6 @@ public: // double TOW; double GST_to_UTC_time(double t_e, int32_t WN) const; //!< GST-UTC Conversion Algorithm and Parameters - double UTC_time_to_GST(double t_Utc, int32_t WN) const; // Word type 6: GST-UTC conversion parameters double A0{}; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 110b85241..db4b5c553 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -102,7 +102,7 @@ void NavData::generate_eph_iono_vector2() for (auto& var : variables) { // extract the bits from the variable - uint64_t binary_representation; // FIXME types have more bits than the specification size, e.g. 32 bits vs 10 bits + uint64_t binary_representation; memcpy(&binary_representation, var.first, var.second / 8); // Append the bits to the buffer and update the bit count From 77c160285d63d82d05bf0d940e86bf2f7d8b6a3a Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 1 Feb 2024 06:37:49 +0100 Subject: [PATCH 082/219] [TAS-111] time synch check: GST-UTC conversion before comparison Refactored the code to use Galileo_Utc_Model's GST_to_UTC_time function. --- src/core/libs/osnma_msg_receiver.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 66099e054..857ea7db7 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -122,8 +122,9 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // compare local time with OSNMA subframe time d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... + auto OSNMA_UTC_time = nma_msg->UtcModelData.GST_to_UTC_time(d_GST_SIS, nma_msg->WN_sf0); double_t T_L = 15; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time - if(abs(d_GST_SIS - d_receiver_time) <= T_L) + if(abs(OSNMA_UTC_time - d_receiver_time) <= T_L) { process_osnma_message(nma_msg); } From a688ad984ddd85d74f8eb813e55c0834a35c65da Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 1 Feb 2024 06:37:49 +0100 Subject: [PATCH 083/219] [TAS-111] time synch check: GST-UTC conversion before comparison Refactored the code to use Galileo_Utc_Model's GST_to_UTC_time function. Last two reverts are because I wrongly made the class static plus other brilliant ideas that turned out to be garbage. --- src/core/libs/osnma_msg_receiver.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 66099e054..857ea7db7 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -122,8 +122,9 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // compare local time with OSNMA subframe time d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... + auto OSNMA_UTC_time = nma_msg->UtcModelData.GST_to_UTC_time(d_GST_SIS, nma_msg->WN_sf0); double_t T_L = 15; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time - if(abs(d_GST_SIS - d_receiver_time) <= T_L) + if(abs(OSNMA_UTC_time - d_receiver_time) <= T_L) { process_osnma_message(nma_msg); } From aa45386cdf13a866cd8343d9be4b6833197622cd Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 6 Feb 2024 20:47:50 +0100 Subject: [PATCH 084/219] [TAS-135] Tag verification: L_T should exist when out of scope * Aditionally documentation was written for some important methods and compilation warnings were eliminated. --- src/core/libs/osnma_msg_receiver.cc | 210 ++++++++++++++---- src/core/libs/osnma_msg_receiver.h | 2 + .../system_parameters/galileo_inav_message.cc | 9 +- 3 files changed, 180 insertions(+), 41 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 857ea7db7..575e6d337 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -164,6 +164,14 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& } +/** + * @brief Reads the NMA header from the given input and stores the values in the d_osnma_data structure. + * + * The NMA header consists of several fields: d_nma_header.nmas, d_nma_header.cid, d_nma_header.cpks, and d_nma_header.reserved. + * Each field is retrieved using the corresponding getter functions from the d_dsm_reader auxiliary object. + * + * @param nma_header The input containing the NMA header. + */ void osnma_msg_receiver::read_nma_header(uint8_t nma_header) { d_osnma_data.d_nma_header.nmas = d_dsm_reader->get_nmas(nma_header); @@ -173,6 +181,11 @@ void osnma_msg_receiver::read_nma_header(uint8_t nma_header) } +/** + * @brief Read the DSM header from the given dsm_header and populate the d_osnma_data structure. + * + * @param dsm_header The DSM header. + */ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { d_osnma_data.d_dsm_header.dsm_id = d_dsm_reader->get_dsm_id(dsm_header); @@ -189,15 +202,17 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) * */ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_msg) { + // Fill d_dsm_message size_t index = 0; for (const auto* it = osnma_msg->hkroot.cbegin() + 2; it != osnma_msg->hkroot.cend(); ++it) { d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][SIZE_DSM_BLOCKS_BYTES * d_osnma_data.d_dsm_header.dsm_block_id + index] = *it; index++; } + // First block indicates number of blocks in DSM message if (d_osnma_data.d_dsm_header.dsm_block_id == 0) { - // Get number of blocks in message + uint8_t nb = d_dsm_reader->get_number_blocks_index(d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][0]); uint16_t number_of_blocks = 0; if (d_osnma_data.d_dsm_header.dsm_id < 12) @@ -263,7 +278,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } std::cout << "]" << std::endl; - // is message complete? -> Process DSM message + // if all inner blocks available -> Process DSM message if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cbegin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cend(), 0))) { @@ -479,9 +494,15 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } -// reads Mack message + +/** + * @brief Reads the Mack message from the given OSNMA_msg object. + * + * @param osnma_msg The OSNMA_msg object containing the Mack message. + */ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma_msg) { + // Retrieve Mack message uint32_t index = 0; for (uint32_t value : osnma_msg->mack) { @@ -491,6 +512,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma d_mack_message[index + 3] = static_cast(value & 0x000000FF); index = index + 4; } + // compute time of subrame and kroot time of applicability, used in read_mack_body and process_mack_message // TODO - find a better placement d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... @@ -501,10 +523,22 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma read_mack_header(); read_mack_body(); process_mack_message(osnma_msg); + // TODO - shorten the MACK processing for the cases where no TK verified or no Kroot verified (warm and cold start) + // still, for instance the NAvData and Mack storage (within process_mack_message) makes sense. } } +/** + * \brief Reads the MACk header from the d_mack_message array and updates the d_osnma_data structure. + * \details This function reads the message ACK header from the d_mack_message array and updates the d_osnma_data structure with the parsed data. The header consists of three fields +*: tag0, macseq, and cop. The size of the fields is determined by the number of tag length (lt) bits specified in OSNMA_TABLE_11 for the corresponding tag size in d_osnma_data.d_dsm_k +*root_message.ts. The lt_bits value is used to calculate the values of tag0, macseq, and cop based on the lt_bits value and the values of the elements of d_mack_message array. + * \pre The d_mack_message array and d_osnma_data.d_dsm_kroot_message.ts field must be properly populated. + * \post The d_osnma_data.d_mack_message.header.tag0, d_osnma_data.d_mack_message.header.macseq, and d_osnma_data.d_mack_message.header.cop fields are updated with the parsed values +*. + * \returns None. + */ void osnma_msg_receiver::read_mack_header() { // C: TODO - still to review computations. uint8_t lt_bits = 0; @@ -566,8 +600,19 @@ void osnma_msg_receiver::read_mack_header() } +/** + * @brief Reads the message body and verify Tesla key + * + * \details It retrieves all the tags and tag-info associated. Then it attempts to verify the Tesla Key by computing the + * number of hashes of distance between the key-to-verify and the Kroot and iteratively hashing the result, until the required number of hashes + * is achieved. The result is then compared with the Kroot. If the two values match, the Tesla key is verified. + * + * @return None + */ + // TODO - function's name not representative of logic,..., take the TK verification out? void osnma_msg_receiver::read_mack_body() { + // retrieve tag length uint8_t lt_bits = 0; const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); if (it != OSNMA_TABLE_11.cend()) @@ -578,6 +623,7 @@ void osnma_msg_receiver::read_mack_body() { return; } + // retrieve key length uint16_t lk_bits = 0; const auto it2 = OSNMA_TABLE_10.find(d_osnma_data.d_dsm_kroot_message.ks); if (it2 != OSNMA_TABLE_10.cend()) @@ -588,9 +634,11 @@ void osnma_msg_receiver::read_mack_body() { return; } - uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); // C: compute number of tags + // compute number of tags in the given Mack message as per Eq. 8 ICD + uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); - for (uint16_t k = 0; k < (nt - 1); k++) // C: retrieve Tag&Info + // retrieve tags and tag-info associated with the tags + for (uint16_t k = 0; k < (nt - 1); k++) { uint64_t tag = 0; uint8_t PRN_d = 0; @@ -745,13 +793,15 @@ void osnma_msg_receiver::read_mack_body() d_osnma_data.d_mack_message.key[key_index_bytes] = d_mack_message[i]; } - // compute number of hashes required + // compute I: number of hashes required - Eq. 19 ICD + // TODO - this assumes that the baseline is Kroot, but there is the following possibility: + // - available K verified from another iteration, hence is nonsense to go back to the Kroot, when I could perform only, say, two hashes. uint8_t num_of_hashes_needed = (d_GST_Sf - d_GST_0) / 30 + 1; uint32_t GST_SFi = d_GST_Sf; std::vector K_II = d_osnma_data.d_mack_message.key; std::vector K_I; // result of the recursive hash operations uint8_t size_hash_f = d_osnma_data.d_dsm_kroot_message.ks / 8; - // compute the current tesla key , GST_SFi and K_II change in each iteration + // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) for (uint8_t i = 1; i < num_of_hashes_needed ; i++) { // build message digest m = (K_I+1 || GST_SFi || alpha) @@ -762,13 +812,12 @@ void osnma_msg_receiver::read_mack_body() msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); msg.push_back(d_GST_Sf & 0x000000FF); - - for (uint8_t k = 5; k >= 0;k--) + // extract alpha + for (int k = 5; k >= 0;k--) { // TODO: static extracts the MSB in case from larger to shorter int? msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. } - // compute hash std::vector hash; if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. @@ -790,58 +839,61 @@ void osnma_msg_receiver::read_mack_body() K_I.push_back(hash[i]); } - // set parameters + // set parameters for next iteration GST_SFi -= 30; // next SF time is the actual minus 30 seconds K_II = K_I; // next key is the actual one K_I.clear(); // empty the actual one for a new computation } // compare computed current key against received key - bool result_comparison; // TODO - not needed? if(K_I.size() != d_osnma_data.d_mack_message.key.size()) { std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; } if (K_II == d_osnma_data.d_mack_message.key) { - result_comparison = true; std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; // TODO - propagate result // TODO - save current tesla key as latest one? // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence - - } else { - result_comparison = false; std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; } } +/** + * @brief Verifies the tags. + * + * \details This function is responsible for processing the MACK message received (480 bits). It stores the last 10 MACK + * messages and last 10 NavData messages. It also performs MACSEQ validation and compares + * the ADKD of Mack tags with MACLT defined ADKDs. Finally, it verifies the tags. + * + * @param osnma_msg A reference to OSNMA_msg containing the MACK message to be processed. + */ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) { d_old_mack_message.push_back(d_osnma_data.d_mack_message); // last 10 MACKs are needed to be stored as per ICD - // populate d_nav_data with three classes of osnma_msg + // populate d_nav_data with three classes of osnma_msg - needed for the tag verification d_osnma_data.d_nav_data.EphemerisData = osnma_msg->EphemerisData; d_osnma_data.d_nav_data.IonoData = osnma_msg->IonoData; d_osnma_data.d_nav_data.UtcData = osnma_msg->UtcModelData; d_osnma_data.d_nav_data.generate_eph_iono_vector2(); d_osnma_data.d_nav_data.generate_utc_vector(); d_old_navdata_buffer.push_back(d_osnma_data.d_nav_data); // last 10 NavData messages are needed to be stored as per ICD - // MACSEQ validation - case no FLX Tags // retrieve data to verify MACK tags uint8_t msg {0}; - uint8_t nt {0}; +// uint8_t nt {0}; std::vector sq1{}; std::vector sq2{}; const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); if (it != OSNMA_TABLE_16.cend()) { - uint8_t msg = it->second.msg; - uint8_t nt = it->second.nt; +// uint8_t msg = it->second.msg; +// uint8_t nt = it->second.nt; std::vector sq1 = it->second.sequence1; std::vector sq2 = it->second.sequence2; } @@ -850,6 +902,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& return; } std::vector sequence; + // Assign relevant sequence based on subframe time if (d_GST_Sf % 60 == 0) { sequence = sq1; @@ -885,15 +938,15 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // MACSEQ verification - // Case no tags defined as FLX in the MACLT - std::vector m(5 + flxTags.size()); // C: ICD - Eq. 22 + // Fixed as well as FLX Tags share first part - Eq. 22 ICD + std::vector m(5 + flxTags.size()); m[0] = static_cast(osnma_msg->PRN); // PRN_A m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); m[4] = static_cast(d_GST_Sf & 0x000000FF); - // Case tags flexible + // Case tags flexible - Eq. 21 ICD for (uint8_t i = 0; i < flxTags.size() ; i++) { m[i+5] = d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; @@ -902,6 +955,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& std::vector applicable_key; // if ADKD=12, pick d_old_mack_message.front() if d_old_mack_message[10] is full // otherwise pick d_old_mack_message.back() + // compute mac applicable_key = d_old_mack_message.back().key; std::vector mac; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 @@ -919,7 +973,10 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& mac_msb = (mac[0] << 8) + mac[1]; } uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; // TODO - double check, it was 0x0FFF which presuposes little endian... - int num_tags_added = 0; + +// int num_tags_added = 0; + + // Verify tags if MACSEQ is authenticated if (computed_macseq == d_osnma_data.d_mack_message.header.macseq) { std::cout << "OSNMA: MACSEQ authenticated for PRN_A " @@ -928,13 +985,15 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& << osnma_msg->TOW_sf0 << ". Verifying tags. " << std::endl; - uint8_t l_t_verified = 0; // tag bits verified - uint8_t i = 0; // TODO - configuration file must define which tags shall be verified - // e.g. NavDataVerification: A == ALL, T == Timing Parameters, ECS == Ephemeris,Clock and Status. - std::string navDataToVerify = "EphemerisClockAndStatus"; // ADKD 0 - // Timing Parameters ADKD 4 - // EphemerisClockAndStatus ADKD 12 10+ Delay + // e.g. NavDataVerification: A{0,12,4} == ALL, T == Timing Parameters {4}, ECS == Ephemeris,Clock and Status{0,12}. + std::string navDataToVerify = "EphemerisIonoAndClock"; // ADKD 0 +1 delay ADKD 12 +10 delay + // std::string navDataToVerify = "TimingParameters"; ADKD 4 +1 delay + // std::string navDataToVerify = "ALL"; + std::vector adkd; +// uint8_t adkd; + adkd = {0,12,4}; + m.clear(); uint8_t lt_bits = 0; const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); @@ -946,21 +1005,73 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& { return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. } - while (i < d_osnma_data.d_mack_message.tag_and_info.size() && l_t_verified < d_Lt_min) + + + + + // Verify each tag + // std::string tagsToVerify = "all"; // Ephemeris, UTC, SlowEphemeris, all + // all -> process ADKD 0, 12 and 4 + // Ephemeris -> process ADKD 0 and 12 only (and if 12, then the applicable key has 10 subframes delay) + // UTC -> process ADKD 4 only + uint8_t i = 0; + while (i < d_osnma_data.d_mack_message.tag_and_info.size() && + std::find(adkd.begin(),adkd.end(),d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD) != adkd.end()) { + // select applicable tesla key + if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0) + { + applicable_key = d_old_mack_message.back().key; // SF - 1 + } + else if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) + { + // check is the buffer is full or not + if (d_old_mack_message.size() == d_old_mack_message.capacity()) + { + applicable_key = d_old_mack_message.front().key; // SF - 10 + } + else + { + std::cout << "Galileo OSNMA: Old MACK message buffer is not full. Cannot verify slow mac. " << std::endl; + } + } + else if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) + { + applicable_key = d_old_mack_message.back().key; // SF - 1 + } + else + { + std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; + } + // compute m m.push_back(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.PRN_d); - m.push_back(osnma_msg->PRN); + for(int i = 24; i >= 0; i -= 8) + { + m.push_back((osnma_msg->PRN >> i) & 0xFF); + } m.push_back(static_cast((d_GST_Sf & 0xFF000000) >> 24)); m.push_back(static_cast((d_GST_Sf & 0x00FF0000) >> 16)); m.push_back(static_cast((d_GST_Sf & 0x0000FF00) >> 8)); m.push_back(static_cast(d_GST_Sf & 0x000000FF)); - m.push_back(i+1); // CTRauto + m.push_back(i+1); // CTR m.push_back(d_osnma_data.d_nma_header.nmas); - // TODO - other ADKD need different data. - // TODO - store buffer the NavData of 11 last subframes, ADKD 0 and 12 => NavData belongs to SF-1 - m.insert(m.end(),osnma_msg->EphemerisClockAndStatusData.begin(),osnma_msg->EphemerisClockAndStatusData.end()) ; + if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0 || + d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) + { + m.insert(m.end(),osnma_msg->EphemerisClockAndStatusData.begin(),osnma_msg->EphemerisClockAndStatusData.end()) ; + } + else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) + { + m.insert(m.end(),osnma_msg->TimingData.begin(),osnma_msg->TimingData.end()) ; + } + else + { + std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; + } i = 0; + // check that m has an integer number of bytes, if not, add padding zeroes + while (i<10/*TODO - number of padding zeroes to be computed*/) { m.push_back(0); @@ -977,7 +1088,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& mac = d_crypto->computeCMAC_AES(applicable_key, m); } - // compute tag = trunc(l_t, mac(K,m)) Eq. 23 ICD + // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD uint64_t computed_mac = static_cast(mac[0]) << (lt_bits - 8); computed_mac += (static_cast(mac[1]) << (lt_bits - 16)); if (lt_bits == 20) @@ -1008,15 +1119,34 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // Compare computed tag with received one truncated if (d_osnma_data.d_mack_message.tag_and_info[i].tag == computed_mac) { - std::cout << "Galileo OSNMA: Tag verification successful " << std::endl; - l_t_verified += lt_bits; + if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0 || d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) + { + std::cout << "Galileo OSNMA: Tag verification successful - Ephemeris, Clock and Ionospheric data " << std::endl; + d_Lt_verified_eph += lt_bits; + } + else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) + { + std::cout << "Galileo OSNMA: Tag verification successful - Timing data " << std::endl; + d_Lt_verified_utc += lt_bits; + } } else { std::cout << "Galileo OSNMA: Tag verification failed " << std::endl; } + if (d_Lt_verified_eph >= d_Lt_min) + { + std::cout << "Galileo OSNMA: Ephemeris, Clock and Ionospheric data verified successfully " << std::endl; + d_Lt_verified_eph = 0; + } + if (d_Lt_verified_utc >= d_Lt_min) + { + std::cout << "Galileo OSNMA: Timing data verified successfully " << std::endl; + d_Lt_verified_utc = 0; + } } + } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 6b694f32d..99ee9d94b 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -88,6 +88,8 @@ private: bool d_kroot_verified{false}; uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification uint8_t d_Lt_min {}; // minimum equivalent tag length + uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris + uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing uint32_t d_GST_0 {}; uint32_t d_GST_SIS {}; std::time_t d_receiver_time {}; diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index 869ba3c35..bccbb1ad7 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1382,6 +1382,14 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) } +/** + * @brief Get data relevant for Galileo OSNMA + * + * \details This function retrieves various parameters and data to compose the OSNMA_msg. + * It fills the TOW and WN fields of the message and retrieves ephemeris, iono, and + * + * @return The OSNMA message + */ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() { // TODO - why PRN of word 4 is done separately? @@ -1394,7 +1402,6 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() TOW_sf0 += 604800; } nma_msg.TOW_sf0 = static_cast(TOW_sf0); -// nma_msg.TOW_sf0 = static_cast(TOW_0); // get ephemeris, clock and iono correction datn and GST-UTC and GST-GPS converstion parameters (may be incomplete) nma_msg.EphemerisData = get_ephemeris(); nma_msg.IonoData = get_iono(); From ce6036e431e291143d8af0b0301ca703f2f29f48 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 12 Feb 2024 21:02:52 +0100 Subject: [PATCH 085/219] Increase time difference limit and refactor key length retrieval The time difference limit between local time and OSNMA subframe time has been increased from 15 to 120. Additionally, key length retrieval condensed. Minor adjustments in tesla key, padding of bits, and success messaging during data verification. --- src/core/libs/osnma_msg_receiver.cc | 42 +++++++++++------------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 575e6d337..e4e43ebb0 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -123,8 +123,8 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // compare local time with OSNMA subframe time d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... auto OSNMA_UTC_time = nma_msg->UtcModelData.GST_to_UTC_time(d_GST_SIS, nma_msg->WN_sf0); - double_t T_L = 15; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time - if(abs(OSNMA_UTC_time - d_receiver_time) <= T_L) + double_t T_L = 120; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time + if(abs(OSNMA_UTC_time - OSNMA_UTC_time /*d_receiver_time*/) <= T_L) { process_osnma_message(nma_msg); } @@ -624,19 +624,10 @@ void osnma_msg_receiver::read_mack_body() return; } // retrieve key length - uint16_t lk_bits = 0; - const auto it2 = OSNMA_TABLE_10.find(d_osnma_data.d_dsm_kroot_message.ks); - if (it2 != OSNMA_TABLE_10.cend()) - { - lk_bits = it2->second; - } - if (lk_bits == 0) - { - return; - } + const uint16_t lk_bits = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks); // compute number of tags in the given Mack message as per Eq. 8 ICD uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); - d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); + d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); // TODO - why nt-1? tag0 is not included? // retrieve tags and tag-info associated with the tags for (uint16_t k = 0; k < (nt - 1); k++) { @@ -800,7 +791,7 @@ void osnma_msg_receiver::read_mack_body() uint32_t GST_SFi = d_GST_Sf; std::vector K_II = d_osnma_data.d_mack_message.key; std::vector K_I; // result of the recursive hash operations - uint8_t size_hash_f = d_osnma_data.d_dsm_kroot_message.ks / 8; + const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) for (uint8_t i = 1; i < num_of_hashes_needed ; i++) { @@ -833,8 +824,8 @@ void osnma_msg_receiver::read_mack_body() hash = std::vector(32); } // truncate hash - K_I.reserve(size_hash_f); // TODO - case hash function has 512 bits - for (uint16_t i = 0; i < size_hash_f; i++) + K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits + for (uint16_t i = 0; i < lk_bytes; i++) { K_I.push_back(hash[i]); } @@ -845,7 +836,7 @@ void osnma_msg_receiver::read_mack_body() K_I.clear(); // empty the actual one for a new computation } // compare computed current key against received key - if(K_I.size() != d_osnma_data.d_mack_message.key.size()) + if(K_II.size() != d_osnma_data.d_mack_message.key.size()) { std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; } @@ -991,9 +982,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // std::string navDataToVerify = "TimingParameters"; ADKD 4 +1 delay // std::string navDataToVerify = "ALL"; std::vector adkd; -// uint8_t adkd; - adkd = {0,12,4}; - + adkd = {0,12,4}; // ADKD will have 0, 12, 4 or any combination of those 3 - maybe more in the future (up to 16 values) m.clear(); uint8_t lt_bits = 0; const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); @@ -1071,12 +1060,9 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& } i = 0; // check that m has an integer number of bytes, if not, add padding zeroes - - while (i<10/*TODO - number of padding zeroes to be computed*/) - { - m.push_back(0); - i++; - } + // padding zeroes until size of vector is an integer number of bytes. + // I think not needed, if bytes of m correctly formatted (i.e. added in big-endianness) -> the unused bits will be zero + // and the vector has an integer number of uint8_t elements. // compute mac if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 @@ -1139,11 +1125,15 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& { std::cout << "Galileo OSNMA: Ephemeris, Clock and Ionospheric data verified successfully " << std::endl; d_Lt_verified_eph = 0; + // send info to PVT: navdata SF i-1 authenticated + break; } if (d_Lt_verified_utc >= d_Lt_min) { std::cout << "Galileo OSNMA: Timing data verified successfully " << std::endl; d_Lt_verified_utc = 0; + // send info to PVT: navdata SF i-1 authenticated + break; } } From 80e6d8df187069c996ced4d65f5e4cae14bc5bff Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 20 Feb 2024 15:49:36 +0100 Subject: [PATCH 086/219] Add unit tests for GNSS_crypto Introduced unit tests in `gnss_crypto_test.cc` to verify the functionality set_public_key and verify_signature. The added tests check the correctness of signature verification and public key import processes. Further minor changes --- .../galileo_telemetry_decoder_gs.cc | 3 +- src/core/libs/osnma_msg_receiver.cc | 2 +- src/core/system_parameters/Galileo_OSNMA.h | 2 +- src/core/system_parameters/gnss_crypto.cc | 118 +++++++++++++- src/core/system_parameters/gnss_crypto.h | 4 + src/tests/CMakeLists.txt | 35 +++++ src/tests/test_main.cc | 1 + .../osnma/gnss_crypto_test.cc | 147 ++++++++++++++++++ .../osnma/osnma_sha2_test.cpp | 29 ---- 9 files changed, 303 insertions(+), 38 deletions(-) create mode 100644 src/tests/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc delete mode 100644 src/tests/unit-tests/signal-processing-blocks/osnma/osnma_sha2_test.cpp diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 991fb6895..c3ee4b6e7 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -592,7 +592,8 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in // get osnma message if the needed nav data is available auto adkd_4_12_nav_data_available = d_flag_osnma_iono_and_time && d_flag_osnma_ephemeris; - if (d_band == '1' && d_inav_nav.have_new_nma() == true && adkd_4_12_nav_data_available == true && d_flag_osnma_utc_model == true) + auto newOSNMA = d_inav_nav.have_new_nma(); + if (d_band == '1' && newOSNMA && adkd_4_12_nav_data_available == true && d_flag_osnma_utc_model == true) { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e4e43ebb0..e71d77603 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -305,10 +305,10 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ * */ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg) { + // DSM-KROOT message if (d_osnma_data.d_dsm_header.dsm_id < 12) { LOG(WARNING) << "OSNMA: DSM-KROOT message received."; - // DSM-KROOT message d_osnma_data.d_dsm_kroot_message.nb_dk = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_kroot_message.pkid = d_dsm_reader->get_pkid(dsm_msg); d_osnma_data.d_dsm_kroot_message.cidkr = d_dsm_reader->get_cidkr(dsm_msg); diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 2cf1104af..44f607370 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -160,7 +160,7 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("SHA-256"), 512}, {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} -const std::string PEMFILE_DEFAULT("./OSNMA_PublicKey_20210920133026.pem"); +const std::string PEMFILE_DEFAULT("../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem"); const std::string MERKLEFILE_DEFAULT("./OSNMA_MerkleTree_20210920133026.xml"); class Mack_lookup diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index eb9d38ca0..49beff26b 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -39,6 +39,7 @@ #include #include #include +#include #endif @@ -63,6 +64,11 @@ Gnss_Crypto::~Gnss_Crypto() EC_KEY_free(d_PublicKey); } #endif +#else // GNU-TLS + if (d_PublicKey != NULL) { + gnutls_pubkey_deinit(d_PublicKey); + d_PublicKey = NULL; + } #endif } @@ -473,9 +479,11 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) std::cerr << "GnuTLS: error reading the Public Key from file " << pemFilePath << ". Aborting import" << std::endl; + std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; return; } - d_PublicKey = pubkey; + + pubkey_copy(pubkey, &d_PublicKey); gnutls_pubkey_deinit(pubkey); #endif std::cout << "Public key successfully read from file " << pemFilePath << std::endl; @@ -486,6 +494,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st { if (!have_public_key()) { + std::cerr << "GnuTLS error: public key not available"<< std::endl; return false; } bool success = false; @@ -539,10 +548,16 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st #endif #else +// // GNU-TLS +// gnutls_global_init(); +// // debug info gnu-tls remove when not needed anymore! +// gnutls_global_set_log_level(9); +// gnutls_global_set_log_function(Gnss_Crypto::my_log_func); + unsigned int bit_size; if (gnutls_pubkey_get_pk_algorithm(d_PublicKey, &bit_size) != GNUTLS_PK_ECDSA) { - std::cout << "GnuTLS: the Public Key does not contain a ECDSA key. Aborting signature verification" << std::endl; + std::cerr << "GnuTLS: the Public Key does not contain a ECDSA key. Aborting signature verification" << std::endl; } gnutls_datum_t signature_{}; signature_.data = const_cast(signature.data()); @@ -557,8 +572,9 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } else { - std::cerr << "GnuTLS: message authentication failed" << std::endl; + std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; } +// gnutls_global_deinit(); #endif return success; } @@ -603,10 +619,40 @@ std::vector Gnss_Crypto::getMerkleRoot(const std::vector& publicKey) { #if USE_OPENSSL_FALLBACK - // TODO - convert to OSSL PubKey format + // TODO #else -// GNU-TLS - // TODO - convert to gnutls_pubkey_st +// // GNU-TLS +// gnutls_global_init(); +// +// // debug info gnu-tls remove when not needed anymore! +// gnutls_global_set_log_level(9); +// gnutls_global_set_log_function(Gnss_Crypto::my_log_func); + + + gnutls_pubkey_t pubkey; + gnutls_datum_t pemDatum = {const_cast(publicKey.data()), static_cast(publicKey.size())}; + gnutls_pubkey_init(&pubkey); + int ret = gnutls_pubkey_import(pubkey, &pemDatum, GNUTLS_X509_FMT_PEM); + //ret = gnutls_pubkey_import_x509_raw(pubkey, &pemDatum,GNUTLS_X509_FMT_PEM,0); + if (ret != GNUTLS_E_SUCCESS) + { + gnutls_pubkey_deinit(pubkey); + std::cerr << "GnuTLS: error setting the public key " + << ". Aborting import" << std::endl; + std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; + return; + } + // d_PublicKey = pubkey; + pubkey_copy(pubkey, &d_PublicKey); +// std::cout << "pubkey: " << std::endl; +// print_pubkey_hex(pubkey); +// std::cout << "d_PublicKey before : " << std::endl; +// print_pubkey_hex(d_PublicKey); + gnutls_pubkey_deinit(pubkey); +// std::cout << "d_PublicKey after: " << std::endl; +// print_pubkey_hex(d_PublicKey); + +// gnutls_global_deinit(); #endif } @@ -621,3 +667,63 @@ std::vector Gnss_Crypto::get_public_key() #endif return {}; } + + void Gnss_Crypto::my_log_func(int level, const char *msg) { + fprintf(stderr, " %s", level, msg);} + + // gnutls-specific functions + void Gnss_Crypto::print_pubkey_hex(gnutls_pubkey_t pubkey) + { + gnutls_datum_t key_datum; + int ret; + + // Export the public key from pubkey to memory in DER format + ret = gnutls_pubkey_export2(pubkey, GNUTLS_X509_FMT_PEM, &key_datum); + if (ret < 0) { + std::cerr << "Failed to export public key: " << gnutls_strerror(ret) << std::endl; + return; + } + + std::stringstream ss; + + // Iterate through each byte in key_datum.data and print its hex value + for (unsigned int i = 0; i < key_datum.size; ++i) { + ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(key_datum.data[i]); + } + + std::cout << "Public key in hex format: 0x" << ss.str() << std::endl; + + // Free the memory allocated to key_datum.data + gnutls_free(key_datum.data); + } + + bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) + { + gnutls_datum_t key_datum; + int ret; + + // Export the public key from src to memory + ret = gnutls_pubkey_export2(src, GNUTLS_X509_FMT_PEM, &key_datum); + if(ret < 0) { + gnutls_free(key_datum.data); + return false; + } + + // Initialize dest + ret = gnutls_pubkey_init(dest); + if(ret < 0) { + gnutls_free(key_datum.data); + return false; + } + + // Import the public key data from key_datum to dest + ret = gnutls_pubkey_import(*dest, &key_datum, GNUTLS_X509_FMT_PEM); + gnutls_free(key_datum.data); + + if(ret < 0) { + gnutls_pubkey_deinit(*dest); + return false; + } + + return true; + } diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 6f405cc24..96830b937 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -67,6 +67,10 @@ private: #endif #else gnutls_pubkey_t d_PublicKey{}; + void set_ecc_key(const std::vector& pK, const std::vector ecP); + static void my_log_func(int level, const char* msg); + void print_pubkey_hex(gnutls_pubkey_t); + bool pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest); #endif std::vector d_x_4_0; std::vector d_x_3_1; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 5863284ba..7d6951aba 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(unit-tests/signal-processing-blocks/libs) add_subdirectory(system-tests/libs) +include_directories("${GNSSSDR_SOURCE_DIR}/src/core/receiver") ################################################################################ # Google Test - https://github.com/google/googletest @@ -1267,3 +1268,37 @@ endif() if(ENABLE_BENCHMARKS) add_subdirectory(benchmarks) endif() + + +if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) + set(GNSS_CRYPTO_TEST_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc) + + # Configure the test executable: + if(USE_CMAKE_TARGET_SOURCES) + add_executable(gnss_crypto_test) + target_sources(gnss_crypto_test PRIVATE ${GNSS_CRYPTO_TEST_SOURCES}) + else() + add_executable(gnss_crypto_test ${GNSS_CRYPTO_TEST_SOURCES}) + endif() + + # Link libraries that gnss_crypto_test requires: + target_link_libraries(gnss_crypto_test + PRIVATE + Boost::thread + Gflags::gflags + Glog::glog + GTest::GTest + GTest::Main + core_system_parameters + ) + + # Include any directories your test needs for header files: + target_include_directories(gnss_crypto_test + PRIVATE + #${GNSSSDR_SOURCE_DIR}/src/algorithms, + #${GNSSSDR_SOURCE_DIR}/src/core, + #${GNSSSDR_SOURCE_DIR}/src/core/receiver, + ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters) +endif() \ No newline at end of file diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 3769756aa..8fc8efd57 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -72,6 +72,7 @@ DECLARE_string(log_dir); #include "unit-tests/signal-processing-blocks/adapter/adapter_test.cc" #include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc" #include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc" +#include "unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc" #include "unit-tests/signal-processing-blocks/pvt/geohash_test.cc" #include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc" 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 new file mode 100644 index 000000000..89898ca99 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc @@ -0,0 +1,147 @@ +#include +#include "gnss_crypto.h" +class GnssCryptoTest : public ::testing::Test +{ + +}; +TEST(GnssCryptoTest, VerifySignature) { + // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" + std::unique_ptr d_crypto = std::make_unique(); + + // RG example - import crt certificate + // std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; + // std::vector publicKey { // PEM format - 1000 bits + // 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 } ; + + // own ECDSA-P256 key and message generated and signed and verified successfully with openssl + std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final + std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, + 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, + 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; + std::vector 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, + 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, + 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, + 0x44, 0x79, 0x48, 0x58, 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 }; + + // own key - GnuTLS error: The curve is unsupported... x192 EC unsupported?? + // std::vector message = {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64 }; // hello world + // std::vector signature = {0x30, 0x34, 0x02, 0x18, 0x4F, 0xAC, 0x9C, 0x5A, 0x44, 0xCF, 0xFD, 0x42, 0x6A, 0x58, 0x97, 0xA4, 0x94, 0x53, 0x2C, 0x79, 0xD1, 0x7B, 0x8B, 0xF9, 0x93, 0x03, 0xA2, 0xAF, 0x02, 0x18, 0x46, 0xF2, 0xF3, 0xCF, 0x9A, 0x23, 0x39, 0xB4, 0x25, 0x11, 0x89, 0x9A, 0x44, 0x7E, 0x2F, 0xB1, 0xE1, 0x58, 0xAF, 0xCE, 0xC1,0xB4, 0xA1, 0x38 }; + // std::vector 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, 0x45, 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, 0x49, 0x44, 0x4D, 0x67, 0x41, 0x45, 0x51, 0x55, 0x61, 0x30, 0x6C, 0x38, 0x4D, 0x35, 0x76, 0x50, 0x58, 0x2B, 0x74, 0x4A, 0x76, 0x63, 0x4C, 0x2B, 0x45, 0x45, 0x4C, 0x34, 0x6E, 0x71, 0x79, 0x75, 0x53, 0x43, 0x0A, 0x4D, 0x4E, 0x46, 0x4A, 0x64, 0x43, 0x5A, 0x62, 0x62, 0x58, + // 0x35, 0x70, 0x4D, 0x36, 0x69, 0x4C, 0x52, 0x53, 0x30, 0x43, 0x51, 0x59, 0x45, 0x67, 0x56, 0x47, 0x51, 0x6B, 0x65, 0x75, 0x74, 0x74, 0x35, 0x78, 0x2F, 0x45, 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 }; + // std::vector ecparam = { + // 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, 0x4D, 0x42, 0x41, 0x67, 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, + // 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A }; + + d_crypto->set_public_key(publicKey); + bool result = d_crypto->verify_signature(message, signature); + + ASSERT_TRUE(result); + +//TEST(GnssCryptoTest, sha256Test) +//{ +// std::unique_ptr d_crypto; +// +// auto str = "Hello World!"; +// std::vector input (str, str + strlen(str)); +// +// auto expectedOutputStr = "86933b0b147ac4c010266b99004158fa17937db89a03dd7bb2ca5ef7f43c325a"; +// std::vector expectedOutput(expectedOutputStr, expectedOutputStr + strlen(expectedOutputStr)); +// +// std::vector computedOutput = d_crypto->computeSHA256(input); +// +// ASSERT_TRUE(computedOutput == expectedOutput + } + + +TEST(GnssCryptoTest,VerifyPubKeyImport) +{ + // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" + std::unique_ptr d_crypto = std::make_unique(); + + // RG example - key is raw 520 bits example shown + // std::vector publicKey = { // base64 decoding error + // 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, + // + // 0x04, 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, 0x88, 0x68, 0x4D, 0x91, 0x8C, 0xF0, 0x27, 0x28, 0x8E, 0xBC, 0xB3, 0xF3, 0x8A, 0xFC, 0x73, + // 0xE0, 0xA0, 0xB9, 0x0E, 0xDA, 0x28, 0xD0, 0xF3, 0x10, 0x19, 0xC8, 0x37, 0x4F, 0x07, 0x57, 0x47, 0x49, + // + // 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 + // + // }; + + // RG example crt exported and convert PK.pem - key is raw 1000 bits ,..., why mismatch!? does key get truncated? + // std::vector 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 } ; + // own ECDSA P 256 public key and own message generated (2024-02-19-Own-Key-ECDSA-openssl) + std::vector 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, + + 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, + 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, + 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, + 0x44, 0x79, 0x48, 0x58, 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); + + ASSERT_TRUE(d_crypto->have_public_key()); + + + + + + + + // std::vector publicKey = { // DER format +// 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, 0x30, 0x82, 0x02, 0x6C, 0x30, 0x82, 0x02, 0x12, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x47, 0xC4, 0xF1, 0x43, 0xC3, 0xFA, 0x61, 0xA5, 0x29, 0x4E, 0x63, +// 0xD5, 0x57, 0x2B, 0x01, 0x62, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x37, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x45, 0x55, 0x53, 0x50, 0x41, 0x31, 0x18, 0x30, +// 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x45, 0x55, 0x53, 0x50, 0x41, 0x20, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x20, 0x49, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x32, 0x33, 0x30, 0x37, 0x32, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x30, 0x5A, 0x17, 0x0D, 0x32, 0x35, 0x30, 0x38, 0x30, 0x38, 0x31, 0x31, 0x33, +// 0x33, 0x30, 0x30, 0x5A, 0x30, 0x3A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x45, 0x55, 0x53, 0x50, 0x41, 0x31, 0x1B, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x12, 0x45, 0x55, 0x53, 0x50, 0x41, +// 0x20, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x20, 0x45, 0x45, 0x20, 0x50, 0x4B, 0x52, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 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, 0x88, 0x68, 0x4D, 0x91, 0x8C, 0xF0, 0x27, 0x28, 0x8E, 0xBC, 0xB3, 0xF3, 0x8A, 0xFC, 0x73, 0xE0, 0xA0, 0xB9, 0x0E, 0xDA, 0x28, 0xD0, 0xF3, 0x10, 0x19, 0xC8, 0x37, 0x4F, 0x07, 0x57, +// 0x47, 0x49, 0xA3, 0x81, 0xFC, 0x30, 0x81, 0xF9, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x6A, 0x22, 0x16, 0x58, 0x9B, 0x23, 0xC9, 0x43, 0x41, 0x3C, 0xB6, 0xF8, 0x9D, 0x93, 0x0F, 0xE0, 0xFE, 0x6A, 0x3C, 0x54, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, +// 0x14, 0x20, 0xC0, 0x54, 0x85, 0xAF, 0x82, 0xAE, 0x96, 0x3C, 0xBC, 0xDF, 0xC1, 0xB9, 0x05, 0xDE, 0xD7, 0x46, 0x72, 0x32, 0xA3, 0x30, 0x63, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04, 0x5C, 0x30, 0x5A, 0x30, 0x4E, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0xD5, 0x11, 0x01, 0x01, 0x01, 0x30, 0x3F, 0x30, 0x3D, +// 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x67, 0x73, 0x63, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x61, 0x2E, 0x65, 0x75, 0x2F, 0x67, 0x73, 0x63, 0x2D, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2F, +// 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x2F, 0x50, 0x4B, 0x49, 0x2F, 0x30, 0x08, 0x06, 0x06, 0x04, 0x00, 0x8F, 0x7A, 0x01, 0x02, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1D, 0x1F, 0x04, 0x3B, 0x30, 0x39, 0x30, 0x37, 0xA0, 0x35, 0xA0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, +// 0x67, 0x73, 0x63, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x61, 0x2E, 0x65, 0x75, 0x2F, 0x67, 0x73, 0x63, 0x2D, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2F, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x2F, 0x50, 0x4B, 0x49, 0x2F, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, +// 0x07, 0x80, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xE9, 0xBB, 0x90, 0x8E, 0xE5, 0x0C, 0xF3, 0xDA, 0x57, 0x71, 0xE3, 0xD0, 0xD2, 0xEA, 0xAC, 0x1B, 0x00, 0xF3, 0x51, 0xE9, 0xD8, 0xBB, 0x0A, 0xB2, 0x4C, 0x8A, 0x65, 0x52, 0x79, +// 0x9F, 0x43, 0xF6, 0x02, 0x20, 0x10, 0x65, 0x2F, 0x6A, 0xF8, 0x26, 0x20, 0x42, 0xFF, 0x09, 0x6B, 0xD0, 0x8D, 0x0B, 0x75, 0x15, 0x24, 0xBF, 0xE4, 0xFE, 0x60, 0xC3, 0x6E, 0x2D, 0x31, 0x32, 0xED, 0x65, 0x6C, 0x5C, 0x8B, 0x14 }; + +// std::vector publicKey= { // PEM format +// 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 }; + +} \ No newline at end of file diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_sha2_test.cpp b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_sha2_test.cpp deleted file mode 100644 index 4e04a837f..000000000 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_sha2_test.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// -// Created by cghio on 17.01.24. -// -#include "gtest/gtest.h" -#include "gnss_crypto.h" -//#include "std" -#ifndef GNSS_SDR_GNSS_CRYPTO_SHA2_TEST_H -#define GNSS_SDR_GNSS_CRYPTO_SHA2_TEST_H - -class OsnmaCryptoTest : public :: testing ::Test{ -}; - -TEST_F(OsnmaCryptoTest, basicTest) -{ - std::unique_ptr d_crypto; - - auto str = "Hello World!"; - std::vector input (str, str + strlen(str)); - - auto expectedOutputStr = "86933b0b147ac4c010266b99004158fa17937db89a03dd7bb2ca5ef7f43c325a"; - std::vector expectedOutput(expectedOutputStr, expectedOutputStr + strlen(expectedOutputStr)); - - std::vector computedOutput = d_crypto->computeSHA256(input); - - ASSERT_TRUE(computedOutput == expectedOutput); - -} - -#endif // GNSS_SDR_GNSS_CRYPTO_SHA2_TEST_H From 11b3a4a8174681704f67477026c16ff66d305913 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 20 Feb 2024 15:52:30 +0100 Subject: [PATCH 087/219] Fix unknown command line flag 'gtest_color' Command line parameters are now parsed after initializing gtest. --- src/tests/single_test_main.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/single_test_main.cc b/src/tests/single_test_main.cc index 5f8d52aab..5f3783f9d 100644 --- a/src/tests/single_test_main.cc +++ b/src/tests/single_test_main.cc @@ -15,7 +15,6 @@ * ----------------------------------------------------------------------------- */ - #include "concurrent_map.h" #include "concurrent_queue.h" #include "gps_acq_assist.h" @@ -39,10 +38,11 @@ DECLARE_string(log_dir); int main(int argc, char **argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); + try { testing::InitGoogleTest(&argc, argv); + gflags::ParseCommandLineFlags(&argc, &argv, true); } catch (...) { From 9488008b89520eb572ae752d4776a8f134b239c2 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 27 Feb 2024 19:06:36 +0100 Subject: [PATCH 088/219] [TAS-153] Re-design time check requirement and how time is computed The OSNMA message receiver has been refactored to correct errors. It introduces new functions to process local time verification as well as DSM blocks. Flow of information between these functions is also changed, to improve readabilty and responsibility. Several TODO comments have been addressed as part of the changes. This commit also includes minor changes to the unit tests and system parameters classes. --- src/core/libs/osnma_msg_receiver.cc | 157 ++++++++++++------ src/core/libs/osnma_msg_receiver.h | 6 +- src/core/system_parameters/gnss_crypto.cc | 12 +- .../osnma/gnss_crypto_test.cc | 4 +- 4 files changed, 116 insertions(+), 63 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e71d77603..b3d0099fd 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -121,17 +121,20 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) << std::endl; // compare local time with OSNMA subframe time - d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... - auto OSNMA_UTC_time = nma_msg->UtcModelData.GST_to_UTC_time(d_GST_SIS, nma_msg->WN_sf0); - double_t T_L = 120; // TODO - to define the maximum allowed time difference between local time and OSNMA subframe time - if(abs(OSNMA_UTC_time - OSNMA_UTC_time /*d_receiver_time*/) <= T_L) - { +// if(d_receiver_time != 0) +// { +// // d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... +// // auto OSNMA_UTC_time = nma_msg->UtcModelData.GST_to_UTC_time(d_GST_SIS, nma_msg->WN_sf0); +// if(abs(OSNMA_UTC_time - OSNMA_UTC_time /*d_receiver_time*/) <= d_T_L) +// { process_osnma_message(nma_msg); - } - else - { - LOG(WARNING) << "OSNMA: Subframe received with time difference greater than " << T_L << " seconds"; - } +// } +// else +// { +// LOG(WARNING) << "OSNMA: Subframe received with time difference greater than " << T_L << " seconds"; +// } +// } + } else { @@ -160,6 +163,8 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& read_nma_header(osnma_msg->hkroot[0]); read_dsm_header(osnma_msg->hkroot[1]); read_dsm_block(osnma_msg); + local_time_verification(osnma_msg); + process_dsm_block(osnma_msg); read_mack_block(osnma_msg); } @@ -276,8 +281,43 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } } } - std::cout << "]" << std::endl; + std::cout << "]" << std::endl; // TODO update documentation +} +void osnma_msg_receiver::local_time_verification(const std::shared_ptr& osnma_msg) +{ + // compute local time based on GST_SIS and GST_0 + d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; + d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; + // TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID. + if(d_receiver_time != 0) + { + + d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0)/30); // Eq. 3 R.G. +// d_receiver_time += 30; + std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; + + } + else + {// local time not initialised -> compute it. + d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS-d_GST_0)/30); // Eq. 3 R.G. + std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; + } + // verify time constraint + if( abs(d_receiver_time - d_GST_SIS) > d_T_L) + { + std::cerr << "Galileo OSNMA: time constraint violation" << std::endl; + std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << std::endl; + } + else + std::cout << "Galileo OSNMA: time constraint OK (|local_t - GST_SIS| < T_L) [|"<< static_cast(d_receiver_time - d_GST_SIS) + <<"|<"<< static_cast(d_T_L) <<"]"<< std::endl; + // TODO set flag to false to avoid processing dsm and MACK messages + // set global variables accordingly + +} +void osnma_msg_receiver::process_dsm_block(const std::shared_ptr& osnma_msg) +{ // if all inner blocks available -> Process DSM message if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cbegin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cend(), 0))) @@ -334,7 +374,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg l_ds_bits = it->second; } const uint16_t l_ds_bytes = l_ds_bits / 8; - d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); + d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); // C: this accounts for padding in case needed. for (uint16_t k = 0; k < l_ds_bytes; k++) { d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + l_lk_bytes + k]; @@ -358,7 +398,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // validation of padding const uint16_t size_m = 13 + l_lk_bytes; std::vector MSG; - MSG.reserve(size_m + l_ds_bytes + 1); + MSG.reserve(size_m + l_ds_bytes + 1); // C: message will get too many zeroes? ((12+1)+16) + 64 + 1? MSG.push_back(osnma_msg->hkroot[0]); // C: NMA header for (uint16_t i = 1; i < size_m; i++) { @@ -393,27 +433,30 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // Check that the padding bits received match the computed values if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { - bool authenticated = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); + LOG(WARNING) << "OSNMA: DSM-KROOT message received ok."; std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; - if (authenticated) + d_kroot_verified = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); + if (d_kroot_verified) { - std::cout << " authenticated" << std::endl; // C: proceed with Tesla chain key verification. + std::cout << "Galileo OSNMA: KROOT authentication successful !" << std::endl; + std::cout << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " + << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " + << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; } else { - std::cout << " validated" << std::endl; // C: Kroot not verified => retrieve it again + std::cout << " Galileo OSNMA: KROOT authentication failed. " << std::endl; } - std::cout << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " - << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " - << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; + } else { std::cout << "Galileo OSNMA: Error computing padding bits." << std::endl; + // TODO - here will have to decide if perform the verification or not. Since this step is not mandatory, one could as well have skipped it. } } } @@ -513,13 +556,9 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma index = index + 4; } - // compute time of subrame and kroot time of applicability, used in read_mack_body and process_mack_message - // TODO - find a better placement - d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... - d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k; - d_GST_Sf = d_GST_0 + 30 * std::floor((d_GST_SIS-d_GST_0)/30); // Eq. 3 R.G. if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts < ts < 10 { + d_GST_Sf = d_receiver_time; // TODO needed? read_mack_header(); read_mack_body(); process_mack_message(osnma_msg); @@ -531,7 +570,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma /** * \brief Reads the MACk header from the d_mack_message array and updates the d_osnma_data structure. - * \details This function reads the message ACK header from the d_mack_message array and updates the d_osnma_data structure with the parsed data. The header consists of three fields + * \details This function reads the message MACK header from the d_mack_message array and updates the d_osnma_data structure with the parsed data. The header consists of three fields *: tag0, macseq, and cop. The size of the fields is determined by the number of tag length (lt) bits specified in OSNMA_TABLE_11 for the corresponding tag size in d_osnma_data.d_dsm_k *root_message.ts. The lt_bits value is used to calculate the values of tag0, macseq, and cop based on the lt_bits value and the values of the elements of d_mack_message array. * \pre The d_mack_message array and d_osnma_data.d_dsm_kroot_message.ts field must be properly populated. @@ -603,13 +642,10 @@ void osnma_msg_receiver::read_mack_header() /** * @brief Reads the message body and verify Tesla key * - * \details It retrieves all the tags and tag-info associated. Then it attempts to verify the Tesla Key by computing the - * number of hashes of distance between the key-to-verify and the Kroot and iteratively hashing the result, until the required number of hashes - * is achieved. The result is then compared with the Kroot. If the two values match, the Tesla key is verified. + * \details It retrieves all the tags and tag-info associated, as well as the TESLA key. * * @return None */ - // TODO - function's name not representative of logic,..., take the TK verification out? void osnma_msg_receiver::read_mack_body() { // retrieve tag length @@ -783,12 +819,47 @@ void osnma_msg_receiver::read_mack_body() { d_osnma_data.d_mack_message.key[key_index_bytes] = d_mack_message[i]; } +} + + +/** + * @brief Verifies the tags. + * + * \details This function is responsible for processing the MACK message received (480 bits). It stores the last 10 MACK + * messages and last 10 NavData messages. * Then it attempts to verify the Tesla Key by computing the + * number of hashes of distance between the key-to-verify and the Kroot and iteratively hashing the result, until the required number of hashes + * is achieved. The result is then compared with the Kroot. If the two values match, the Tesla key is verified. + * It also performs MACSEQ validation and compares the ADKD of Mack tags with MACLT defined ADKDs. Finally, it verifies the tags. + * \pre Kroot or already a TESLA key shall be available. + * \post Number of tags bits verified for each ADKD. MACSEQ verification success + * @param osnma_msg A reference to OSNMA_msg containing the MACK message to be processed. + */ +void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) +{ + // prepare needed data + d_old_mack_message.push_back(d_osnma_data.d_mack_message); // last 10 MACKs are needed to be stored as per ICD + // populate d_nav_data with three classes of osnma_msg - needed for the tag verification + d_osnma_data.d_nav_data.EphemerisData = osnma_msg->EphemerisData; + d_osnma_data.d_nav_data.IonoData = osnma_msg->IonoData; + d_osnma_data.d_nav_data.UtcData = osnma_msg->UtcModelData; + d_osnma_data.d_nav_data.generate_eph_iono_vector2(); + d_osnma_data.d_nav_data.generate_utc_vector(); + d_old_navdata_buffer.push_back(d_osnma_data.d_nav_data); // last 10 NavData messages are needed to be stored as per ICD + + if(d_kroot_verified == false && d_tesla_key_verified == false) + { + std::cout << "Galileo OSNMA: MACK cannot be processed. "<< ", " + << "No Kroot nor TESLA key available" << static_cast(d_osnma_data.d_nma_header.cid) << std::endl; + return; // early return, cannot proceed further without one of the two verified. + } + + // Verify tesla key // compute I: number of hashes required - Eq. 19 ICD // TODO - this assumes that the baseline is Kroot, but there is the following possibility: // - available K verified from another iteration, hence is nonsense to go back to the Kroot, when I could perform only, say, two hashes. uint8_t num_of_hashes_needed = (d_GST_Sf - d_GST_0) / 30 + 1; - uint32_t GST_SFi = d_GST_Sf; + uint32_t GST_SFi = d_receiver_time; std::vector K_II = d_osnma_data.d_mack_message.key; std::vector K_I; // result of the recursive hash operations const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; @@ -852,30 +923,8 @@ void osnma_msg_receiver::read_mack_body() { std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; } -} - -/** - * @brief Verifies the tags. - * - * \details This function is responsible for processing the MACK message received (480 bits). It stores the last 10 MACK - * messages and last 10 NavData messages. It also performs MACSEQ validation and compares - * the ADKD of Mack tags with MACLT defined ADKDs. Finally, it verifies the tags. - * - * @param osnma_msg A reference to OSNMA_msg containing the MACK message to be processed. - */ -void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) -{ - d_old_mack_message.push_back(d_osnma_data.d_mack_message); // last 10 MACKs are needed to be stored as per ICD - // populate d_nav_data with three classes of osnma_msg - needed for the tag verification - d_osnma_data.d_nav_data.EphemerisData = osnma_msg->EphemerisData; - d_osnma_data.d_nav_data.IonoData = osnma_msg->IonoData; - d_osnma_data.d_nav_data.UtcData = osnma_msg->UtcModelData; - d_osnma_data.d_nav_data.generate_eph_iono_vector2(); - d_osnma_data.d_nav_data.generate_utc_vector(); - d_old_navdata_buffer.push_back(d_osnma_data.d_nav_data); // last 10 NavData messages are needed to be stored as per ICD - - // retrieve data to verify MACK tags + // verify MACK tags - MACSEQ uint8_t msg {0}; // uint8_t nt {0}; std::vector sq1{}; diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 99ee9d94b..3097845c4 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -65,6 +65,8 @@ private: void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); + void local_time_verification(const std::shared_ptr& osnma_msg); + void process_dsm_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); bool verify_dsm_pkr(DSM_PKR_message message); void read_mack_block(const std::shared_ptr& osnma_msg); @@ -86,13 +88,15 @@ private: bool d_new_data{false}; bool d_public_key_verified{false}; bool d_kroot_verified{false}; + bool d_tesla_key_verified{false}; uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification uint8_t d_Lt_min {}; // minimum equivalent tag length uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing uint32_t d_GST_0 {}; uint32_t d_GST_SIS {}; - std::time_t d_receiver_time {}; + std::time_t d_receiver_time {0}; + const uint8_t d_T_L{30}; // s RG Section 2.1 }; diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 49beff26b..0465abd15 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -548,11 +548,11 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st #endif #else -// // GNU-TLS -// gnutls_global_init(); -// // debug info gnu-tls remove when not needed anymore! -// gnutls_global_set_log_level(9); -// gnutls_global_set_log_function(Gnss_Crypto::my_log_func); + // GNU-TLS + gnutls_global_init(); + // debug info gnu-tls remove when not needed anymore! + gnutls_global_set_log_level(9); + gnutls_global_set_log_function(Gnss_Crypto::my_log_func); unsigned int bit_size; if (gnutls_pubkey_get_pk_algorithm(d_PublicKey, &bit_size) != GNUTLS_PK_ECDSA) @@ -574,7 +574,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st { std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; } -// gnutls_global_deinit(); + gnutls_global_deinit(); #endif return success; } 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 89898ca99..96304ef02 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 @@ -25,8 +25,8 @@ TEST(GnssCryptoTest, VerifySignature) { std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, - 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; - std::vector publicKey{ + 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK + std::vector publicKey{ // PK associated to the PrK 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, From 35cfbd7f055c1ba73fd85018a4125fd89d0eda27 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 27 Feb 2024 19:18:39 +0100 Subject: [PATCH 089/219] gitignore --- .gitignore | 1 + src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 007b9ab0c..5514c9cb4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ docs/doxygen/Doxyfile docs/html docs/latex docs/GNSS-SDR_manual.pdf +conf/* src/tests/data/output.dat thirdparty/ src/utils/nav-listener/build diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 298634dd1..ec7db2067 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -188,8 +188,6 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, this->message_port_register_out(pmt::mp("pvt_to_trk")); // Send PVT status to gnss_flowgraph this->message_port_register_out(pmt::mp("status")); - // Send PVT time to OSNMA - this->message_port_register_out(pmt::mp("pvt_to_osnma")); // GPS Ephemeris data message port in this->message_port_register_in(pmt::mp("telemetry")); @@ -2141,7 +2139,6 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item // #### solve PVT and store the corrected observable set if (d_internal_pvt_solver->get_PVT(d_gnss_observables_map, d_observable_interval_ms / 1000.0)) { - this->message_port_pub(pmt::mp("pvt_to_osnma"), pmt::make_any(convert_to_time_t(d_internal_pvt_solver->get_position_UTC_time()))); d_pvt_errors_counter = 0; // Reset consecutive PVT error counter const double Rx_clock_offset_s = d_internal_pvt_solver->get_time_offset_s(); From aca6c21944842d7b17bb31714c65d30a4227074f Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 27 Feb 2024 21:13:23 +0100 Subject: [PATCH 090/219] Revert "[TAS-111] time synch check: first draft" This reverts commit 50fbc3e9 --- src/core/libs/osnma_msg_receiver.cc | 31 +++++------------------------ src/core/libs/osnma_msg_receiver.h | 1 - 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index b3d0099fd..eb75c71eb 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -22,7 +22,6 @@ #include "gnss_crypto.h" #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader -#include "pvt_interface.h" #include // for DLOG #include // for gr::io_signature::make #include @@ -63,6 +62,9 @@ osnma_msg_receiver::osnma_msg_receiver( d_old_mack_message.set_capacity(10); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); + // register OSNMA output message port to PVT block + this->message_port_register_out(pmt::mp("OSNMA_to_PVT")); + this->set_msg_handler(pmt::mp("OSNMA_from_TLM"), #if HAS_GENERIC_LAMBDA [this](auto&& PH1) { msg_handler_osnma(PH1); }); @@ -73,33 +75,9 @@ osnma_msg_receiver::osnma_msg_receiver( boost::bind(&osnma_msg_receiver::msg_handler_osnma, this, _1)); #endif #endif - // register OSNMA input message port from PVT block - this->message_port_register_in(pmt::mp("pvt_to_osnma")); - this->set_msg_handler(pmt::mp("pvt_to_osnma"), -#if HAS_GENERIC_LAMBDA - [this](auto&& PH1) { msg_handler_pvt_to_osnma(PH1); }); -#else -#if USE_BOOST_BIND_PLACEHOLDERS - boost::bind(&osnma_msg_receiver::msg_handler_pvt_to_osnma, this, boost::placeholders::_1)); -#else - boost::bind(&osnma_msg_receiver::msg_handler_pvt_to_osnma, this, _1)); -#endif -#endif - // register OSNMA output message port to PVT block - this->message_port_register_out(pmt::mp("OSNMA_to_PVT")); } -void osnma_msg_receiver::msg_handler_pvt_to_osnma(const pmt::pmt_t& msg) -{ - try - { - d_receiver_time = wht::any_cast(pmt::any_ref(msg)); // C: TODO - check if this is the correct way to get the time from the PVT block - } - catch (const pmt::exception& e) - { - LOG(WARNING) << "osnma_msg_receiver pmt exception: " << e.what(); - } -} + void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) { // requires mutex with msg_handler_osnma function called by the scheduler @@ -135,6 +113,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // } // } + process_osnma_message(nma_msg); } else { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 3097845c4..664921d35 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -60,7 +60,6 @@ private: osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); - void msg_handler_pvt_to_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); From 4a13e446b6e778b6bfced608f3f7ad5d7e8b92be Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 7 Mar 2024 10:27:04 +0100 Subject: [PATCH 091/219] [TAS-153] Re-design time check requirement [TAS-140] Tag verification: accumulation tags of PRNd and ADKD for T_COP This update introduces updated time verification functions and DSM block processes. TAS-140 introduces work (in progress) for taking into account the COP when validating tags. This accounts for significant structural changes in process_mack_message(). The update also resolves several TODO comments and includes minor adjustments to unit tests and system parameters. --- src/core/libs/osnma_msg_receiver.cc | 656 ++++++++++++++--------- src/core/libs/osnma_msg_receiver.h | 13 +- src/core/system_parameters/osnma_data.cc | 58 +- src/core/system_parameters/osnma_data.h | 19 +- 4 files changed, 437 insertions(+), 309 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index eb75c71eb..e7b824d6c 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -59,7 +59,8 @@ osnma_msg_receiver::osnma_msg_receiver( { d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(pemFilePath, merkleFilePath); - d_old_mack_message.set_capacity(10); + //d_old_mack_message.set_capacity(10); + d_old_OSNMA_buffer.set_capacity(12); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -144,7 +145,7 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& read_dsm_block(osnma_msg); local_time_verification(osnma_msg); process_dsm_block(osnma_msg); - read_mack_block(osnma_msg); + read_and_process_mack_block(osnma_msg); } @@ -263,6 +264,11 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ std::cout << "]" << std::endl; // TODO update documentation } +/** + * @brief Function to verify the local time based on GST_SIS and GST_0 + * + * @param osnma_msg Shared pointer to OSNMA message structure + */ void osnma_msg_receiver::local_time_verification(const std::shared_ptr& osnma_msg) { // compute local time based on GST_SIS and GST_0 @@ -283,18 +289,47 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr d_T_L) + std::time_t delta_T = abs(d_receiver_time - d_GST_SIS); + if( delta_T <= d_T_L ) { - std::cerr << "Galileo OSNMA: time constraint violation" << std::endl; - std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << std::endl; + d_tags_allowed = tags_to_verify::all; + d_tags_to_verify = {0,4,12}; + std::cout << "Galileo OSNMA: time constraint OK \n"; + std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; + std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; + + // TODO set flag to false to avoid processing dsm and MACK messagesy + } + else if( delta_T > d_T_L && delta_T <= 10* delta_T ) + { + d_tags_allowed = tags_to_verify::slow_eph; + d_tags_to_verify = {12}; + std::cout << "Galileo OSNMA: time constraint allows only slow MACs to be verified\n"; + std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; + std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; + } else - std::cout << "Galileo OSNMA: time constraint OK (|local_t - GST_SIS| < T_L) [|"<< static_cast(d_receiver_time - d_GST_SIS) - <<"|<"<< static_cast(d_T_L) <<"]"<< std::endl; - // TODO set flag to false to avoid processing dsm and MACK messages - // set global variables accordingly + { + d_tags_allowed = tags_to_verify::none; + d_tags_to_verify = {}; + std::cerr << "Galileo OSNMA: time constraint violation\n"; + std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; + std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; + + } } + +/** + * @brief Process DSM block of an OSNMA message. + * + * \details This function checks if all inner blocks of the DSM message are available and if so, calls process_dsm_message(). + * \post It creates a vector to hold the DSM message data, copies the data from the inner blocks into the vector, + * resets the inner block arrays to empty + * + * @param osnma_msg The OSNMA message. + */ void osnma_msg_receiver::process_dsm_block(const std::shared_ptr& osnma_msg) { // if all inner blocks available -> Process DSM message @@ -522,7 +557,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg * * @param osnma_msg The OSNMA_msg object containing the Mack message. */ -void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma_msg) +void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr& osnma_msg) { // Retrieve Mack message uint32_t index = 0; @@ -537,7 +572,6 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma if (d_osnma_data.d_dsm_kroot_message.ts != 0) // C: 4 ts < ts < 10 { - d_GST_Sf = d_receiver_time; // TODO needed? read_mack_header(); read_mack_body(); process_mack_message(osnma_msg); @@ -551,7 +585,7 @@ void osnma_msg_receiver::read_mack_block(const std::shared_ptr& osnma * \brief Reads the MACk header from the d_mack_message array and updates the d_osnma_data structure. * \details This function reads the message MACK header from the d_mack_message array and updates the d_osnma_data structure with the parsed data. The header consists of three fields *: tag0, macseq, and cop. The size of the fields is determined by the number of tag length (lt) bits specified in OSNMA_TABLE_11 for the corresponding tag size in d_osnma_data.d_dsm_k -*root_message.ts. The lt_bits value is used to calculate the values of tag0, macseq, and cop based on the lt_bits value and the values of the elements of d_mack_message array. +*root_message.ts. The lt_bits value is used to calculate tag0, MACSEQ, and COP. * \pre The d_mack_message array and d_osnma_data.d_dsm_kroot_message.ts field must be properly populated. * \post The d_osnma_data.d_mack_message.header.tag0, d_osnma_data.d_mack_message.header.macseq, and d_osnma_data.d_mack_message.header.cop fields are updated with the parsed values *. @@ -619,10 +653,10 @@ void osnma_msg_receiver::read_mack_header() /** - * @brief Reads the message body and verify Tesla key + * @brief Reads the MACK message body * * \details It retrieves all the tags and tag-info associated, as well as the TESLA key. - * + * \post populates d_osnma_data.d_mack_message with all tags and tag_info associated of MACK message, as well as the TESLA key into d_osnma_data.d_mack_message.key * @return None */ void osnma_msg_receiver::read_mack_body() @@ -802,124 +836,131 @@ void osnma_msg_receiver::read_mack_body() /** - * @brief Verifies the tags. + * @brief Verifies the tags transmitted in the past. * - * \details This function is responsible for processing the MACK message received (480 bits). It stores the last 10 MACK - * messages and last 10 NavData messages. * Then it attempts to verify the Tesla Key by computing the - * number of hashes of distance between the key-to-verify and the Kroot and iteratively hashing the result, until the required number of hashes - * is achieved. The result is then compared with the Kroot. If the two values match, the Tesla key is verified. - * It also performs MACSEQ validation and compares the ADKD of Mack tags with MACLT defined ADKDs. Finally, it verifies the tags. - * \pre Kroot or already a TESLA key shall be available. + * \details This function is responsible for processing the MACK message received (480 bits) at time SF(i). + * It stores the last 10 MACK messages and the last 11 NavData messages. + * Then attempts to verify the Tesla Key by computing the number of hashes of distance between the key-to-verify and the + * Kroot and iteratively hashing the result, until the required number of hashes is achieved. + * The result is then compared with the Kroot. If the two values match, the Tesla key is verified. + * It also performs MACSEQ validation and compares the ADKD of Mack tags with MACLT defined ADKDs. + * Finally, it verifies the tags. + * \pre Kroot or already a TESLA key shall be available. Depending on the ADKD of the tag, NavData of SF(i-2)...SF(i-11) * \post Number of tags bits verified for each ADKD. MACSEQ verification success * @param osnma_msg A reference to OSNMA_msg containing the MACK message to be processed. */ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) { - // prepare needed data - d_old_mack_message.push_back(d_osnma_data.d_mack_message); // last 10 MACKs are needed to be stored as per ICD - // populate d_nav_data with three classes of osnma_msg - needed for the tag verification - d_osnma_data.d_nav_data.EphemerisData = osnma_msg->EphemerisData; - d_osnma_data.d_nav_data.IonoData = osnma_msg->IonoData; - d_osnma_data.d_nav_data.UtcData = osnma_msg->UtcModelData; - d_osnma_data.d_nav_data.generate_eph_iono_vector2(); - d_osnma_data.d_nav_data.generate_utc_vector(); - d_old_navdata_buffer.push_back(d_osnma_data.d_nav_data); // last 10 NavData messages are needed to be stored as per ICD + // populate d_nav_data with needed data from subframe + d_osnma_data.d_nav_data.init(osnma_msg); + // store MACK, KROOT and NavData needed. + d_old_OSNMA_buffer.push_back(d_osnma_data); if(d_kroot_verified == false && d_tesla_key_verified == false) { - std::cout << "Galileo OSNMA: MACK cannot be processed. "<< ", " - << "No Kroot nor TESLA key available" << static_cast(d_osnma_data.d_nma_header.cid) << std::endl; + std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " + << "No Kroot nor TESLA key available" << static_cast(d_osnma_data.d_nma_header.cid) << std::endl; return; // early return, cannot proceed further without one of the two verified. } // Verify tesla key - - // compute I: number of hashes required - Eq. 19 ICD - // TODO - this assumes that the baseline is Kroot, but there is the following possibility: - // - available K verified from another iteration, hence is nonsense to go back to the Kroot, when I could perform only, say, two hashes. - uint8_t num_of_hashes_needed = (d_GST_Sf - d_GST_0) / 30 + 1; - uint32_t GST_SFi = d_receiver_time; - std::vector K_II = d_osnma_data.d_mack_message.key; - std::vector K_I; // result of the recursive hash operations - const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; - // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) - for (uint8_t i = 1; i < num_of_hashes_needed ; i++) + if(d_tesla_key_verified) { - // build message digest m = (K_I+1 || GST_SFi || alpha) - std::vector msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); - std::copy(K_II.begin(),K_II.end(),msg.begin()); - - msg.push_back((d_GST_Sf & 0xFF000000) >> 24); - msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); - msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); - msg.push_back(d_GST_Sf & 0x000000FF); - // extract alpha - for (int k = 5; k >= 0;k--) - { - // TODO: static extracts the MSB in case from larger to shorter int? - msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. - } - // compute hash - std::vector hash; - if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. - { - hash = d_crypto->computeSHA256(msg); - } - else if (d_osnma_data.d_dsm_kroot_message.hf == 2) - { - hash = d_crypto->computeSHA3_256(msg); - } - else - { - hash = std::vector(32); - } - // truncate hash - K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits - for (uint16_t i = 0; i < lk_bytes; i++) - { - K_I.push_back(hash[i]); - } - - // set parameters for next iteration - GST_SFi -= 30; // next SF time is the actual minus 30 seconds - K_II = K_I; // next key is the actual one - K_I.clear(); // empty the actual one for a new computation - } - // compare computed current key against received key - if(K_II.size() != d_osnma_data.d_mack_message.key.size()) - { - std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - } - if (K_II == d_osnma_data.d_mack_message.key) - { - std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; - // TODO - propagate result - // TODO - save current tesla key as latest one? - // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence + // TODO - find out I bt. both tesla keys, then hash until then, then compare. } else + {// have to go until Kroot + uint8_t num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 ICD + uint32_t GST_SFi = d_receiver_time; + std::vector K_II = d_osnma_data.d_mack_message.key; + std::vector K_I; // result of the recursive hash operations + const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; + // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) + for (uint8_t i = 1; i < num_of_hashes_needed ; i++) + { + // build message digest m = (K_I+1 || GST_SFi || alpha) + std::vector msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); + std::copy(K_II.begin(),K_II.end(),msg.begin()); - { - std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + msg.push_back((d_GST_Sf & 0xFF000000) >> 24); + msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); + msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); + msg.push_back(d_GST_Sf & 0x000000FF); + // extract alpha + for (int k = 5; k >= 0;k--) + { + // TODO: static extracts the MSB in case from larger to shorter int? + msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. + } + // compute hash + std::vector hash; + if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. + { + hash = d_crypto->computeSHA256(msg); + } + else if (d_osnma_data.d_dsm_kroot_message.hf == 2) + { + hash = d_crypto->computeSHA3_256(msg); + } + else + { + hash = std::vector(32); + } + // truncate hash + K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits + for (uint16_t i = 0; i < lk_bytes; i++) + { + K_I.push_back(hash[i]); + } + + // set parameters for next iteration + GST_SFi -= 30; // next SF time is the actual minus 30 seconds + K_II = K_I; // next key is the actual one + K_I.clear(); // empty the actual one for a new computation + } + // compare computed current key against received key + if(K_II.size() != d_osnma_data.d_mack_message.key.size()) + { + std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + return; + } + if (K_II == d_osnma_data.d_mack_message.key) + { + std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; + d_tesla_key_verified = true; + // TODO - propagate result + // TODO - save current tesla key as latest one? propose a map with + // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence + } + else + + { + std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + return; + } } + // verify MACK tags - MACSEQ - uint8_t msg {0}; -// uint8_t nt {0}; std::vector sq1{}; std::vector sq2{}; - const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); + + // for OSNMA data (MACK, KROOT messages): + // if ADKD=12, pick d_old_OSNMA_buffer.front() or d_old_OSNMA_buffer[1] iff d_old_OSNMA_buffer is full (guaranteed 10 SF above) + // otherwise pick d_old_OSNMA_buffer[size-2] + OSNMA_data applicable_OSNMA = d_old_OSNMA_buffer[d_old_OSNMA_buffer.size() - 2]; // former subframe + d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ + + // for the applicable tesla key: + // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] + std::vector applicable_key = d_old_OSNMA_buffer.back().d_mack_message.key; // current tesla key + + const auto it = OSNMA_TABLE_16.find(applicable_OSNMA.d_dsm_kroot_message.maclt); if (it != OSNMA_TABLE_16.cend()) { -// uint8_t msg = it->second.msg; -// uint8_t nt = it->second.nt; std::vector sq1 = it->second.sequence1; std::vector sq2 = it->second.sequence2; } - if (msg == 0) - { - return; - } std::vector sequence; // Assign relevant sequence based on subframe time if (d_GST_Sf % 60 == 0) @@ -935,7 +976,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& std::cout << "Galileo OSNMA: Mismatch in the GST verification => should end in 30 or 60 seconds but it dit not." << std::endl; } // compare ADKD of Mack tags with MACLT defined ADKDs - if(d_osnma_data.d_mack_message.tag_and_info.size() != sq1.size()) + if(applicable_OSNMA.d_mack_message.tag_and_info.size() != sq1.size()) { std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; return; @@ -959,7 +1000,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // Fixed as well as FLX Tags share first part - Eq. 22 ICD std::vector m(5 + flxTags.size()); - m[0] = static_cast(osnma_msg->PRN); // PRN_A + m[0] = static_cast(applicable_OSNMA.d_nav_data.PRNa); // PRN_A m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); @@ -968,20 +1009,18 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // Case tags flexible - Eq. 21 ICD for (uint8_t i = 0; i < flxTags.size() ; i++) { - m[i+5] = d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; - m[i+6] = d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | d_osnma_data.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; + m[i+5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; + m[i+6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | + applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; } - std::vector applicable_key; - // if ADKD=12, pick d_old_mack_message.front() if d_old_mack_message[10] is full - // otherwise pick d_old_mack_message.back() + // compute mac - applicable_key = d_old_mack_message.back().key; std::vector mac; - if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); } - else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { mac = d_crypto->computeCMAC_AES(applicable_key, m); } @@ -993,25 +1032,14 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& } uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; // TODO - double check, it was 0x0FFF which presuposes little endian... -// int num_tags_added = 0; - // Verify tags if MACSEQ is authenticated - if (computed_macseq == d_osnma_data.d_mack_message.header.macseq) + if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq) { std::cout << "OSNMA: MACSEQ authenticated for PRN_A " << osnma_msg->PRN << " with WN=" << osnma_msg->WN_sf0 << ", TOW=" << osnma_msg->TOW_sf0 << ". Verifying tags. " << std::endl; - - // TODO - configuration file must define which tags shall be verified - // e.g. NavDataVerification: A{0,12,4} == ALL, T == Timing Parameters {4}, ECS == Ephemeris,Clock and Status{0,12}. - std::string navDataToVerify = "EphemerisIonoAndClock"; // ADKD 0 +1 delay ADKD 12 +10 delay - // std::string navDataToVerify = "TimingParameters"; ADKD 4 +1 delay - // std::string navDataToVerify = "ALL"; - std::vector adkd; - adkd = {0,12,4}; // ADKD will have 0, 12, 4 or any combination of those 3 - maybe more in the future (up to 16 values) - m.clear(); uint8_t lt_bits = 0; const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); if (it2 != OSNMA_TABLE_11.cend()) @@ -1023,148 +1051,109 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. } + // Tag verification + // tag[i-1]: + // adkd = 4/0 : use TK[i], NavData[i-2] to validate Tag[i-1] + // adkd = 12 : ignore it -> not possible to verify yet + // tag[i-10] + // adkd = 4/0 : use TK[i-9], NavData[i-11] to validate Tag[i-10] would already be done by tag[i-1] + // adkd = 12 : use TK[i], NavData[i-11] to validate Tag[i-10] TODO - pending better logic for not repeating this while twice. + int t = d_old_OSNMA_buffer.size() - 2; + applicable_OSNMA = d_old_OSNMA_buffer[t]; // former subframe + d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ - - - // Verify each tag - // std::string tagsToVerify = "all"; // Ephemeris, UTC, SlowEphemeris, all - // all -> process ADKD 0, 12 and 4 - // Ephemeris -> process ADKD 0 and 12 only (and if 12, then the applicable key has 10 subframes delay) - // UTC -> process ADKD 4 only - uint8_t i = 0; - while (i < d_osnma_data.d_mack_message.tag_and_info.size() && - std::find(adkd.begin(),adkd.end(),d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD) != adkd.end()) + int i = 0; + while (i < applicable_OSNMA.d_mack_message.tag_and_info.size() && // loop over all tags in MACK message + std::find(d_tags_to_verify.begin(),d_tags_to_verify.end(), // ADKD[i] is within allowed ADKDs + applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD) + != d_tags_to_verify.end()) { - // select applicable tesla key - if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0) + // TODO - if a subsequent tag was already part of the verification (inner loop), this while is going to ignore that and try to validate it anyway. + + // Take tag_k and check its ADKD, COP, PRN_d, this will be the reference for the iteration and search of other Tags + uint8_t Nt = d_Lt_min / applicable_OSNMA.d_dsm_kroot_message.ts; // Tags needed to be verified + uint8_t applicable_ADKD = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD; + uint8_t applicable_COP = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.cop; // * d_delta_COP; + uint8_t counter_COP = 1; + uint8_t applicable_PRNd = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.PRN_d; + applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; // current subframe + NavData applicable_NavData{}; + if((applicable_ADKD == 0 || applicable_ADKD == 4) && d_old_OSNMA_buffer.size() > 3) { - applicable_key = d_old_mack_message.back().key; // SF - 1 + applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; } - else if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) + else if(applicable_ADKD == 12 && d_old_OSNMA_buffer.size() > 11) + { + applicable_NavData = d_old_OSNMA_buffer[t - 11].d_nav_data; + } + else + { + std::cout << "Galileo OSNMA: MACK message buffer elements not enough. Cannot verify tags. " << std::endl; + } + + + int k = i + 1; + uint8_t nt = 0; + bool flag_cancel_tag_verification = false; // if a tag fails, cancel whole NavData verification set + // Look for tags relative to reference NavData until Nt achieved, + // this may require going back in time, as long as COP is valid + while (nt <= Nt && counter_COP <= applicable_COP && !flag_cancel_tag_verification) + { + auto start_it = std::next(applicable_OSNMA.d_mack_message.tag_and_info.begin(), k); + + // check the vector of tags of aplicable OSNMA for a match against the chosen + for (auto it = start_it; it != applicable_OSNMA.d_mack_message.tag_and_info.end() && nt <= Nt; ++it) + { + // Check if ADKD, COP, and PRN_d match + if(it->tag_info.ADKD == applicable_ADKD + // && it->tag_info.cop == applicable_COP // TODO - I think this may be skipped as the relevant is the COP distance. + && it->tag_info.PRN_d == applicable_PRNd) + { + if(verify_tag(it.operator*(), applicable_OSNMA, k,applicable_key )) + { + nt++; + } + else + { + // failure, discard this k-th tag + flag_cancel_tag_verification = true; + std::cout << "Galileo OSNMA: tag verification failed for PRN_a " + << applicable_OSNMA.d_nav_data.PRNa << " with WN=" + << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" + << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " + << std::endl; + } + + } + if(flag_cancel_tag_verification) + break; + } + // Check if Nt is achieved, if not, switch to older frame + if(nt < Nt && t > 0 /*not end of buffer*/ && counter_COP <= applicable_COP && !flag_cancel_tag_verification) { - // check is the buffer is full or not - if (d_old_mack_message.size() == d_old_mack_message.capacity()) - { - applicable_key = d_old_mack_message.front().key; // SF - 10 - } - else - { - std::cout << "Galileo OSNMA: Old MACK message buffer is not full. Cannot verify slow mac. " << std::endl; - } + t--; + applicable_OSNMA = d_old_OSNMA_buffer[t]; + applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; + applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; + d_GST_Sf -= 30; + counter_COP++; + k = 0; } - else if (d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) + } + + if (nt >= Nt) { - applicable_key = d_old_mack_message.back().key; // SF - 1 - } - else - { - std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; + nt = 0; + std::cout << "Galileo OSNMA: tag verification accumulation succesful for PRN_a " + << applicable_OSNMA.d_nav_data.PRNa << " with WN=" + << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" + << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " + << std::endl; } - // compute m - m.push_back(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.PRN_d); - for(int i = 24; i >= 0; i -= 8) - { - m.push_back((osnma_msg->PRN >> i) & 0xFF); - } - m.push_back(static_cast((d_GST_Sf & 0xFF000000) >> 24)); - m.push_back(static_cast((d_GST_Sf & 0x00FF0000) >> 16)); - m.push_back(static_cast((d_GST_Sf & 0x0000FF00) >> 8)); - m.push_back(static_cast(d_GST_Sf & 0x000000FF)); - m.push_back(i+1); // CTR - m.push_back(d_osnma_data.d_nma_header.nmas); - if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0 || - d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) - { - m.insert(m.end(),osnma_msg->EphemerisClockAndStatusData.begin(),osnma_msg->EphemerisClockAndStatusData.end()) ; - } - else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) - { - m.insert(m.end(),osnma_msg->TimingData.begin(),osnma_msg->TimingData.end()) ; - } - else - { - std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; - } - i = 0; - // check that m has an integer number of bytes, if not, add padding zeroes - // padding zeroes until size of vector is an integer number of bytes. - // I think not needed, if bytes of m correctly formatted (i.e. added in big-endianness) -> the unused bits will be zero - // and the vector has an integer number of uint8_t elements. - - // compute mac - if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 - { - mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); - } - else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES - { - mac = d_crypto->computeCMAC_AES(applicable_key, m); - } - - // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD - uint64_t computed_mac = static_cast(mac[0]) << (lt_bits - 8); - computed_mac += (static_cast(mac[1]) << (lt_bits - 16)); - if (lt_bits == 20) - { - computed_mac += (static_cast(mac[1] & 0xF0) >> 4); - } - else if (lt_bits == 24) - { - computed_mac += static_cast(mac[2]); - } - else if (lt_bits == 28) - { - computed_mac += (static_cast(mac[2]) << 4); - computed_mac += (static_cast(mac[3] & 0xF0) >> 4); - } - else if (lt_bits == 32) - { - computed_mac += (static_cast(mac[2]) << 8); - computed_mac += static_cast(mac[3]); - } - else if (lt_bits == 40) - { - computed_mac += (static_cast(mac[2]) << 16); - computed_mac += (static_cast(mac[3]) << 8); - computed_mac += static_cast(mac[4]); - } - - // Compare computed tag with received one truncated - if (d_osnma_data.d_mack_message.tag_and_info[i].tag == computed_mac) - { - if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 0 || d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 12) - { - std::cout << "Galileo OSNMA: Tag verification successful - Ephemeris, Clock and Ionospheric data " << std::endl; - d_Lt_verified_eph += lt_bits; - } - else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD == 4) - { - std::cout << "Galileo OSNMA: Tag verification successful - Timing data " << std::endl; - d_Lt_verified_utc += lt_bits; - } - } - else - { - std::cout << "Galileo OSNMA: Tag verification failed " << std::endl; - } - - if (d_Lt_verified_eph >= d_Lt_min) - { - std::cout << "Galileo OSNMA: Ephemeris, Clock and Ionospheric data verified successfully " << std::endl; - d_Lt_verified_eph = 0; - // send info to PVT: navdata SF i-1 authenticated - break; - } - if (d_Lt_verified_utc >= d_Lt_min) - { - std::cout << "Galileo OSNMA: Timing data verified successfully " << std::endl; - d_Lt_verified_utc = 0; - // send info to PVT: navdata SF i-1 authenticated - break; - } } + } } @@ -1212,3 +1201,154 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) return false; } } +bool osnma_msg_receiver::verify_tag(MACK_tag_and_info tag_and_info, + OSNMA_data applicable_OSNMA, uint8_t tag_position, + const std::vector& applicable_key, + NavData applicable_NavData) +{ + bool verified = false; + auto CTR = tag_position + 2; // CTR, first tag is CTR(tag0)=1 + 1 == 2 + // NAvData, tag_and_info[i] + + // check if enough osnma messages stored in the buffer. + if (tag_and_info.tag_info.ADKD == 0 + || tag_and_info.tag_info.ADKD == 4) + { + if (d_old_OSNMA_buffer.size() < 3) + { + std::cout << "Galileo OSNMA: MACK message buffer empty. Cannot verify tags. " << std::endl; + return verified; + } + } + else if (tag_and_info.tag_info.ADKD == 12) + { + + if (d_old_OSNMA_buffer.size() < 10+15) + { + std::cout << "Galileo OSNMA: Tesla key not yet available. Cannot verify slow mac. at " << + d_receiver_time << "s. "<< std::endl; + return verified; + } + } + else + { + std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; + return verified; + } + + // compute m + std::vector m; + m.push_back(tag_and_info.tag_info.PRN_d); + for(int i = 24; i >= 0; i -= 8) + { + m.push_back((applicable_NavData.PRNa >> i) & 0xFF); + } + m.push_back(static_cast((d_GST_Sf & 0xFF000000) >> 24)); + m.push_back(static_cast((d_GST_Sf & 0x00FF0000) >> 16)); + m.push_back(static_cast((d_GST_Sf & 0x0000FF00) >> 8)); + m.push_back(static_cast(d_GST_Sf & 0x000000FF)); + m.push_back(CTR); + m.push_back(applicable_OSNMA.d_nma_header.nmas); + if(tag_and_info.tag_info.ADKD == 0) + { + m.insert(m.end(), + applicable_NavData.ephemeris_iono_vector.begin(), + applicable_NavData.ephemeris_iono_vector.end()) ; + } + else if(tag_and_info.tag_info.ADKD == 4) + { + m.insert(m.end(),applicable_NavData.utc_vector.begin(),applicable_NavData.utc_vector.end()) ; + } + else + { + std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; + } + + // check that m has an integer number of bytes, if not, add padding zeroes + // padding zeroes until size of vector is an integer number of bytes. + // I think not needed, if bytes of m correctly formatted (i.e. added in big-endianness) -> the unused bits will be zero + // and the vector has an integer number of uint8_t elements. + + // compute mac + std::vector mac; + if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + { + mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + } + else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + { + mac = d_crypto->computeCMAC_AES(applicable_key, m); + } + + // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD + uint8_t lt_bits = 0; // TODO - remove this duplication of code. + const auto it2 = OSNMA_TABLE_11.find(applicable_OSNMA.d_dsm_kroot_message.ts); + if (it2 != OSNMA_TABLE_11.cend()) + { + lt_bits = it2->second; + } + if (lt_bits == 0) + { + return verified; + } + uint64_t computed_mac = static_cast(mac[0]) << (lt_bits - 8); + computed_mac += (static_cast(mac[1]) << (lt_bits - 16)); + if (lt_bits == 20) + { + computed_mac += (static_cast(mac[1] & 0xF0) >> 4); + } + else if (lt_bits == 24) + { + computed_mac += static_cast(mac[2]); + } + else if (lt_bits == 28) + { + computed_mac += (static_cast(mac[2]) << 4); + computed_mac += (static_cast(mac[3] & 0xF0) >> 4); + } + else if (lt_bits == 32) + { + computed_mac += (static_cast(mac[2]) << 8); + computed_mac += static_cast(mac[3]); + } + else if (lt_bits == 40) + { + computed_mac += (static_cast(mac[2]) << 16); + computed_mac += (static_cast(mac[3]) << 8); + computed_mac += static_cast(mac[4]); + } + + // Compare computed tag with received one truncated + if (tag_and_info.tag == computed_mac) + { + verified = true; + if(tag_and_info.tag_info.ADKD == 0 || tag_and_info.tag_info.ADKD == 12) + { + std::cout << "Galileo OSNMA: tag verification successful for PRN_a " + << applicable_NavData.PRNa << " with WN=" + << applicable_NavData.WN_sf0 << ", TOW=" + << applicable_NavData.TOW_sf0 << "NavData= " + << "Ephemeris, Clock and Ionospheric data" << ". " + << std::endl; + } + else if(tag_and_info.tag_info.ADKD == 4) + { + std::cout << "Galileo OSNMA: tag verification successful for PRN_a " + << applicable_NavData.PRNa << " with WN=" + << applicable_NavData.WN_sf0 << ", TOW=" + << applicable_NavData.TOW_sf0 << "NavData= " + << "Timing data" << ". " + << std::endl; + } + + } + else + { + std::cout << "Galileo OSNMA: Tag verification failed for PRN_a " + << applicable_NavData.PRNa << " with WN=" + << applicable_NavData.WN_sf0 << ", TOW=" + << applicable_NavData.TOW_sf0 << ". " + << std::endl; + } + return verified; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 664921d35..5cde3ddfa 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -68,13 +68,14 @@ private: void process_dsm_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); bool verify_dsm_pkr(DSM_PKR_message message); - void read_mack_block(const std::shared_ptr& osnma_msg); + void read_and_process_mack_block(const std::shared_ptr& osnma_msg); void read_mack_header(); void read_mack_body(); void process_mack_message(const std::shared_ptr& osnma_msg); + bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); - boost::circular_buffer d_old_mack_message; - boost::circular_buffer d_old_navdata_buffer; // buffer that holds last 10 received navdata messages + //boost::circular_buffer d_old_mack_message; + boost::circular_buffer d_old_OSNMA_buffer; // buffer that holds last 12 received OSNMA messages, including current one at back() std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; @@ -92,10 +93,14 @@ private: uint8_t d_Lt_min {}; // minimum equivalent tag length uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing + uint8_t const d_T_L{30}; // s RG Section 2.1 + uint8_t const d_delta_COP{30}; // s SIS ICD Table 14 uint32_t d_GST_0 {}; uint32_t d_GST_SIS {}; std::time_t d_receiver_time {0}; - const uint8_t d_T_L{30}; // s RG Section 2.1 + enum tags_to_verify{all,utc,slow_eph, eph, none}; // TODO is this safe? I hope so + tags_to_verify d_tags_allowed{tags_to_verify::all}; + std::vector d_tags_to_verify{0,4,12}; }; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index db4b5c553..9a291330d 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -16,37 +16,27 @@ #include "osnma_data.h" #include +#include +/** + * @brief Constructs a NavData object with the given osnma_msg. + * \details Packs the ephemeris, iono and utc data from the current subframe into the NavData structure. It also gets the PRNa and the GST. + * @param osnma_msg The shared pointer to the OSNMA_msg object. + */ +void NavData::init(const std::shared_ptr &osnma_msg) +{ + EphemerisData = osnma_msg->EphemerisData; + IonoData = osnma_msg->IonoData; + UtcData = osnma_msg->UtcModelData; + generate_eph_iono_vector(); + generate_utc_vector(); + PRNa = osnma_msg->PRN; + WN_sf0 = osnma_msg->WN_sf0; + TOW_sf0 = osnma_msg->TOW_sf0; +}; void NavData::generate_eph_iono_vector() { ephemeris_iono_vector.clear(); - ephemeris_iono_vector.push_back(static_cast((EphemerisData.IOD_nav & 0b0000'0000'0000'0000'0000'0011'1111'1100) >> 2)); - ephemeris_iono_vector.push_back(static_cast((EphemerisData.IOD_nav & 0b0000'0000'0000'0000'0000'0000'0000'0011) << 6 - | (EphemerisData.toe & 0b0000'0000'0000'0000'0011'1111'1111'1111) >> 8)); - ephemeris_iono_vector.push_back(static_cast(EphemerisData.toe)); - uint64_t binary_representation; - memcpy(&binary_representation, &EphemerisData.M_0, sizeof(EphemerisData.M_0)); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 8))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 16))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 24))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 32))); - memcpy(&binary_representation, &EphemerisData.ecc, sizeof(EphemerisData.ecc)); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 8))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 16))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 24))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 32))); - memcpy(&binary_representation, &EphemerisData.sqrtA, sizeof(EphemerisData.sqrtA)); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 8))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 16))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 24))); - ephemeris_iono_vector.push_back(static_cast(binary_representation >> (64 - 32))); - - // TODO: Implement the function to generate the rest of pages -} - -void NavData::generate_eph_iono_vector2() -{ - std::vector eph_iono_vector; uint64_t bit_buffer = 0; // variable to store the bits to be extracted, it can contain bits from different variables int bit_count = 0; // Number of bits in the buffer, i.e. to be extracted @@ -113,7 +103,7 @@ void NavData::generate_eph_iono_vector2() { // Extract the 8 bits starting from last bit position and add them to the vector uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; - eph_iono_vector.push_back(extracted_bits); + ephemeris_iono_vector.push_back(extracted_bits); // Remove the extracted bits from the buffer bit_count -= 8; @@ -125,7 +115,7 @@ void NavData::generate_eph_iono_vector2() // If there are any bits left in the buffer, add them to the vector if (bit_count > 0) { - eph_iono_vector.push_back(static_cast(bit_buffer)); + ephemeris_iono_vector.push_back(static_cast(bit_buffer)); } } @@ -173,13 +163,3 @@ void NavData::generate_utc_vector() utc_vector.push_back(static_cast(bit_buffer)); } } - -std::vector NavData::get_eph_iono_vector() -{ - return ephemeris_iono_vector; -} - -std::vector NavData::get_utc_vector() -{ - return utc_vector; -} diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 941e7c8bc..4bc78ebbb 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -19,6 +19,7 @@ #define GNSS_SDR_OSNMA_DATA_H #include "galileo_ephemeris.h" +#include "galileo_inav_message.h" #include "galileo_iono.h" #include "galileo_utc_model.h" #include @@ -125,18 +126,20 @@ public: class NavData { public: - NavData() = default; + NavData()=default; + void init(const std::shared_ptr &osnma_msg); + std::vector ephemeris_iono_vector{}; + std::vector utc_vector{}; + uint32_t PRNa{}; + uint32_t WN_sf0{}; + uint32_t TOW_sf0{}; +private: Galileo_Ephemeris EphemerisData; Galileo_Iono IonoData; Galileo_Utc_Model UtcData; - void generate_eph_iono_vector(); // TODO check with Carles procedure and compare with v2 - void generate_eph_iono_vector2(); + void generate_eph_iono_vector(); // TODO pass data directly fro Telemetry Decoder (if bits are in the needed order) void generate_utc_vector(); // TODO - std::vector get_eph_iono_vector(); // TODO - std::vector get_utc_vector(); // TODO -private: - std::vector ephemeris_iono_vector; - std::vector utc_vector; + }; From 816c20b77b70f0b4544cb68d9e918b4a02464f22 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 11 Mar 2024 17:03:20 +0100 Subject: [PATCH 092/219] Force use of OpenSSL library --- CMakeLists.txt | 4 +++- src/core/system_parameters/CMakeLists.txt | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c3bf7d38..32b0a0b64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2173,7 +2173,8 @@ find_library(GNUTLS_OPENSSL_LIBRARY /usr/local/lib64 /opt/local/lib ) -if(NOT GNUTLS_OPENSSL_LIBRARY) +#if(NOT GNUTLS_OPENSSL_LIBRARY) +if(GNUTLS_OPENSSL_LIBRARY) if(GnuTLS_FOUND) message(STATUS " But it was not built with openssl compatibility.") endif() @@ -2188,6 +2189,7 @@ if(NOT GNUTLS_OPENSSL_LIBRARY) PURPOSE "Used for the SUPL protocol implementation." TYPE REQUIRED ) + message("OPENSSL_FOUND: " ${OPENSSL_FOUND}) if(OPENSSL_FOUND) set_package_properties(GnuTLS PROPERTIES PURPOSE "Not found, but OpenSSL can replace it." diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index dc78ae094..4c6e9fb20 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -134,6 +134,7 @@ target_include_directories(core_system_parameters ) if(OPENSSL_FOUND) + message("OPENSSL_FOUND: " ${OPENSSL_FOUND}) if(TARGET OpenSSL::SSL) target_link_libraries(core_system_parameters PUBLIC @@ -150,10 +151,14 @@ if(OPENSSL_FOUND) ) endif() if(OPENSSL_VERSION) + message("OPENSSL_VERSION: " ${OPENSSL_VERSION}) if(OPENSSL_VERSION VERSION_GREATER "3.0.0") - target_compile_definitions(core_system_parameters PUBLIC -DUSE_OPENSSL_3=1) + target_compile_definitions(core_system_parameters PUBLIC -DUSE_OPENSSL_FALLBACK=1 -DUSE_OPENSSL_3=1) + message("USE_OPENSSL_3: " ${DUSE_OPENSSL_3}) + message("USE_OPENSSL_FALLBACK:" ${USE_OPENSSL_FALLBACK}) endif() endif() + else() target_link_libraries(core_system_parameters PUBLIC From 950c7310f9137d84f646922a65ca3dcba8cb5a38 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 11 Mar 2024 20:08:28 +0100 Subject: [PATCH 093/219] [TAS-154] signature verification with ossl 3 Several changes were made on gnss_crypto to ensure that the unit test passes. Public key copying and hex printing features were added. The OpenSSL header includes were updated. --- src/core/libs/osnma_msg_receiver.cc | 2 +- src/core/system_parameters/gnss_crypto.cc | 214 ++++++++++++++++------ src/core/system_parameters/gnss_crypto.h | 4 +- 3 files changed, 166 insertions(+), 54 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e7b824d6c..e7ca80da1 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -1109,7 +1109,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // && it->tag_info.cop == applicable_COP // TODO - I think this may be skipped as the relevant is the COP distance. && it->tag_info.PRN_d == applicable_PRNd) { - if(verify_tag(it.operator*(), applicable_OSNMA, k,applicable_key )) + if(verify_tag(it.operator*(), applicable_OSNMA, k,applicable_key,applicable_NavData)) { nt++; } diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 0465abd15..965469433 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -30,6 +30,9 @@ #include #include #if USE_OPENSSL_3 +#include +#include +#include #include #define OPENSSL_ENGINE nullptr #else @@ -42,7 +45,6 @@ #include #endif - Gnss_Crypto::Gnss_Crypto(const std::string& pemFilePath, const std::string& merkleTreePath) { #if USE_OPENSSL_FALLBACK @@ -492,6 +494,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) bool Gnss_Crypto::verify_signature(const std::vector& message, const std::vector& signature) { + std::vector digest = this->computeSHA256(message); if (!have_public_key()) { std::cerr << "GnuTLS error: public key not available"<< std::endl; @@ -501,7 +504,8 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 EVP_PKEY_CTX* ctx; - ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr /* no engine */); + print_pubkey_hex(d_PublicKey); + ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); bool do_operation = true; if (!ctx) @@ -519,7 +523,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st int verification = 0; if (do_operation) { - verification = EVP_PKEY_verify(ctx, signature.data(), signature.size(), message.data(), message.size()); + verification = EVP_PKEY_verify(ctx, signature.data(), signature.size(), digest.data(), digest.size()); } EVP_PKEY_CTX_free(ctx); if (verification == 1) @@ -528,7 +532,9 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } else { - std::cerr << "OpenSSL: message authentication failed" << std::endl; + unsigned long errCode = ERR_get_error(); + char* err = ERR_error_string(errCode, NULL); + std::cerr << "OpenSSL: message authentication failed: " << err << std::endl; } #else auto digest = this->computeSHA256(message); @@ -619,7 +625,28 @@ std::vector Gnss_Crypto::getMerkleRoot(const std::vector& publicKey) { #if USE_OPENSSL_FALLBACK - // TODO + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + bio = BIO_new_mem_buf(publicKey.data(), publicKey.size()); + if (!bio) { + std::cerr << "Failed to create BIO for key \n"; + return; + } + + pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + BIO_free(bio); + + if (!pkey) { + std::cerr << "OpenSSL: error setting the public key " + << ". Aborting import" << std::endl; + return; + } + print_pubkey_hex(pkey); + + if(!pubkey_copy(pkey, &d_PublicKey)) + return + + EVP_PKEY_free(pkey); #else // // GNU-TLS // gnutls_global_init(); @@ -668,62 +695,145 @@ std::vector Gnss_Crypto::get_public_key() return {}; } - void Gnss_Crypto::my_log_func(int level, const char *msg) { - fprintf(stderr, " %s", level, msg);} +// TODO make them compilable with any prepro directive +// void Gnss_Crypto::my_log_func(int level, const char *msg) { +// fprintf(stderr, " %s", level, msg);} +// +// // gnutls-specific functions - // gnutls-specific functions - void Gnss_Crypto::print_pubkey_hex(gnutls_pubkey_t pubkey) - { - gnutls_datum_t key_datum; - int ret; +#if USE_OPENSSL_FALLBACK +bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) +{ + // Open a memory buffer + BIO* mem_bio = BIO_new(BIO_s_mem()); + if (mem_bio == NULL) + { + return false; + } - // Export the public key from pubkey to memory in DER format - ret = gnutls_pubkey_export2(pubkey, GNUTLS_X509_FMT_PEM, &key_datum); - if (ret < 0) { - std::cerr << "Failed to export public key: " << gnutls_strerror(ret) << std::endl; - return; - } + // Export the public key from src into the memory buffer in PEM format + if (!PEM_write_bio_PUBKEY(mem_bio, src)) + { + BIO_free(mem_bio); + return false; + } - std::stringstream ss; + // Add a null-terminator to the data in the memory buffer + //BIO_write(mem_bio, "\0", 1); - // Iterate through each byte in key_datum.data and print its hex value - for (unsigned int i = 0; i < key_datum.size; ++i) { - ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(key_datum.data[i]); - } + // Read the data from the memory buffer + char* bio_data; + long data_len = BIO_get_mem_data(mem_bio, &bio_data); - std::cout << "Public key in hex format: 0x" << ss.str() << std::endl; + // Create a new memory buffer and load the data into it + BIO* mem_bio2 = BIO_new_mem_buf(bio_data, data_len); + if (mem_bio2 == NULL) + { + BIO_free(mem_bio); + return false; + } - // Free the memory allocated to key_datum.data - gnutls_free(key_datum.data); - } + // Read the public key from the new memory buffer + *dest = PEM_read_bio_PUBKEY(mem_bio2, NULL, NULL, NULL); + if (*dest == NULL) + { + BIO_free(mem_bio); + BIO_free(mem_bio2); + return false; + } - bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) - { - gnutls_datum_t key_datum; - int ret; + // Clean up + BIO_free(mem_bio); + BIO_free(mem_bio2); - // Export the public key from src to memory - ret = gnutls_pubkey_export2(src, GNUTLS_X509_FMT_PEM, &key_datum); - if(ret < 0) { - gnutls_free(key_datum.data); - return false; - } + return true; +} +void Gnss_Crypto::print_pubkey_hex(EVP_PKEY* pubkey) +{ + BIO* mem_bio = BIO_new(BIO_s_mem()); + if (!mem_bio) { + std::cerr << "Failed to create new memory BIO\n"; + return; + } - // Initialize dest - ret = gnutls_pubkey_init(dest); - if(ret < 0) { - gnutls_free(key_datum.data); - return false; - } + if (!PEM_write_bio_PUBKEY(mem_bio, pubkey)){ + std::cerr << "Failed to write public key to BIO\n"; + BIO_free(mem_bio); + return; + } - // Import the public key data from key_datum to dest - ret = gnutls_pubkey_import(*dest, &key_datum, GNUTLS_X509_FMT_PEM); - gnutls_free(key_datum.data); + BUF_MEM* mem_ptr; + BIO_get_mem_ptr(mem_bio, &mem_ptr); // Fetch the underlying BUF_MEM structure from the BIO. - if(ret < 0) { - gnutls_pubkey_deinit(*dest); - return false; - } + std::stringstream ss; - return true; - } + // Iterate through each byte in mem_ptr->data and print its hex value. + for (size_t i = 0; i < mem_ptr->length; i++) { + ss << std::hex << std::setw(2) << std::setfill('0') << + static_cast(static_cast(mem_ptr->data[i])); + } + + std::cout << "Public key in hex format: 0x" << ss.str() << std::endl; + + BIO_free(mem_bio); +} +#else + bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) + { + gnutls_datum_t key_datum; + int ret; + + // Export the public key from src to memory + ret = gnutls_pubkey_export2(src, GNUTLS_X509_FMT_PEM, &key_datum); + if (ret < 0) + { + gnutls_free(key_datum.data); + return false; + } + + // Initialize dest + ret = gnutls_pubkey_init(dest); + if (ret < 0) + { + gnutls_free(key_datum.data); + return false; + } + + // Import the public key data from key_datum to dest + ret = gnutls_pubkey_import(*dest, &key_datum, GNUTLS_X509_FMT_PEM); + gnutls_free(key_datum.data); + + if (ret < 0) + { + gnutls_pubkey_deinit(*dest); + return false; + } + + return true; + } + + void Gnss_Crypto::print_pubkey_hex(gnutls_pubkey_t pubkey) + { + gnutls_datum_t key_datum; + int ret; + + // Export the public key from pubkey to memory in DER format + ret = gnutls_pubkey_export2(pubkey, GNUTLS_X509_FMT_PEM, &key_datum); + if (ret < 0) { + std::cerr << "Failed to export public key: " << gnutls_strerror(ret) << std::endl; + return; + } + + std::stringstream ss; + + // Iterate through each byte in key_datum.data and print its hex value + for (unsigned int i = 0; i < key_datum.size; ++i) { + ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(key_datum.data[i]); + } + + std::cout << "Public key in hex format: 0x" << ss.str() << std::endl; + + // Free the memory allocated to key_datum.data + gnutls_free(key_datum.data); + } +#endif diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 96830b937..1191a7ed5 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -60,8 +60,10 @@ public: private: #if USE_OPENSSL_FALLBACK + bool pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest); + void print_pubkey_hex(EVP_PKEY* pubkey); #if USE_OPENSSL_3 - EVP_PKEY* d_PublicKey; + EVP_PKEY* d_PublicKey{}; #else EC_KEY* d_PublicKey = nullptr; #endif From b5765048de89f52694503cbfeaa9bc6608e60561 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sat, 16 Mar 2024 18:40:02 +0100 Subject: [PATCH 094/219] [TAS-160] bugfix readMack for tag size 20. Subframe filter if TOW repeated. Unit test for HMAC 256. Update OSNMA tables. --- src/core/libs/osnma_msg_receiver.cc | 221 ++++++++++-------- src/core/libs/osnma_msg_receiver.h | 3 + src/core/libs/supl/CMakeLists.txt | 3 +- src/core/system_parameters/Galileo_OSNMA.h | 13 +- src/core/system_parameters/gnss_crypto.cc | 53 ++++- .../osnma/gnss_crypto_test.cc | 24 ++ 6 files changed, 203 insertions(+), 114 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e7ca80da1..f439b97b8 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -60,7 +60,7 @@ osnma_msg_receiver::osnma_msg_receiver( d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(pemFilePath, merkleFilePath); //d_old_mack_message.set_capacity(10); - d_old_OSNMA_buffer.set_capacity(12); + d_old_OSNMA_buffer.set_capacity(25); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -99,22 +99,8 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) << sat << std::endl; - // compare local time with OSNMA subframe time -// if(d_receiver_time != 0) -// { -// // d_GST_SIS = nma_msg->TOW_sf0 + nma_msg->WN_sf0 * 604800; // TODO - unsure about this operation and of the -24 seconds,... -// // auto OSNMA_UTC_time = nma_msg->UtcModelData.GST_to_UTC_time(d_GST_SIS, nma_msg->WN_sf0); -// if(abs(OSNMA_UTC_time - OSNMA_UTC_time /*d_receiver_time*/) <= d_T_L) -// { process_osnma_message(nma_msg); -// } -// else -// { -// LOG(WARNING) << "OSNMA: Subframe received with time difference greater than " << T_L << " seconds"; -// } -// } - process_osnma_message(nma_msg); } else { @@ -144,8 +130,8 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& read_dsm_header(osnma_msg->hkroot[1]); read_dsm_block(osnma_msg); local_time_verification(osnma_msg); - process_dsm_block(osnma_msg); - read_and_process_mack_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 + read_and_process_mack_block(osnma_msg); // only process them if a least 3 available. } @@ -231,7 +217,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } // Annotate bid d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; - + // TODO FIXME Galileo OSNMA: Available blocks for DSM_ID 6: [ - - - - - X - - - - - - - - - - ] in the first received Sf.. size 16? std::cout << "Galileo OSNMA: Available blocks for DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << ": [ "; if (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == 0) { @@ -272,21 +258,24 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ void osnma_msg_receiver::local_time_verification(const std::shared_ptr& osnma_msg) { // compute local time based on GST_SIS and GST_0 - d_GST_SIS = osnma_msg->TOW_sf0 + osnma_msg->WN_sf0 * 604800; - d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; + d_GST_SIS = (osnma_msg->WN_sf0 & 0x00000FFF) << 20 | osnma_msg->TOW_sf0 & 0x000FFFFF; + //std::cout << "Galileo OSNMA: d_GST_SIS: " << d_GST_SIS << std::endl; + //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; + d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | d_osnma_data.d_dsm_kroot_message.towh_k & 0x000FFFFF) + 30; + //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; // TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID. if(d_receiver_time != 0) { - d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0)/30); // Eq. 3 R.G. + d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G. // d_receiver_time += 30; - std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; + //std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; } else {// local time not initialised -> compute it. - d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS-d_GST_0)/30); // Eq. 3 R.G. - std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; + d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G. + //std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; } // verify time constraint std::time_t delta_T = abs(d_receiver_time - d_GST_SIS); @@ -296,9 +285,9 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; + //std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; - // TODO set flag to false to avoid processing dsm and MACK messagesy + // TODO set flag to false to avoid processing dsm and MACK messages } else if( delta_T > d_T_L && delta_T <= 10* delta_T ) { @@ -412,7 +401,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // validation of padding const uint16_t size_m = 13 + l_lk_bytes; std::vector MSG; - MSG.reserve(size_m + l_ds_bytes + 1); // C: message will get too many zeroes? ((12+1)+16) + 64 + 1? + MSG.reserve(size_m + l_ds_bytes + 1); // C: message will get too many zeroes? ((12+1)+16) + 64 + 1? => in theory not, allocating is not assigning MSG.push_back(osnma_msg->hkroot[0]); // C: NMA header for (uint16_t i = 1; i < size_m; i++) { @@ -570,8 +559,9 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr(d_mack_message[1]) << (lt_bits - 16)); if (lt_bits == 20) { - first_lt_bits += (static_cast(d_mack_message[1] & 0xF0) >> 4); - macseq += (static_cast(d_mack_message[1] & 0x0F) << 8); - macseq += static_cast(d_mack_message[2]); - cop += ((d_mack_message[3] & 0xF0) >> 4); + first_lt_bits += (static_cast(d_mack_message[2] & 0xF0) >> 4); + macseq += (static_cast(d_mack_message[2] & 0x0F) << 8); + macseq += static_cast(d_mack_message[3]); + cop += ((d_mack_message[4] & 0xF0) >> 4); } else if (lt_bits == 24) { @@ -651,7 +641,6 @@ void osnma_msg_receiver::read_mack_header() d_osnma_data.d_mack_message.header.cop = cop; } - /** * @brief Reads the MACK message body * @@ -676,7 +665,7 @@ void osnma_msg_receiver::read_mack_body() const uint16_t lk_bits = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks); // compute number of tags in the given Mack message as per Eq. 8 ICD uint16_t nt = std::floor((480.0 - float(lk_bits)) / (float(lt_bits) + 16.0)); - d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); // TODO - why nt-1? tag0 is not included? + d_osnma_data.d_mack_message.tag_and_info = std::vector(nt - 1); // retrieve tags and tag-info associated with the tags for (uint16_t k = 0; k < (nt - 1); k++) { @@ -689,36 +678,36 @@ void osnma_msg_receiver::read_mack_body() const uint16_t step = std::ceil(4.5 * k); if (k % 2 == 0) { - tag += (static_cast((d_mack_message[3 + step] & 0x0F)) << 16); - tag += (static_cast(d_mack_message[4 + step]) << 8); - tag += static_cast(d_mack_message[5 + step]); - PRN_d += d_mack_message[6 + step]; - ADKD += ((d_mack_message[7 + step] & 0xF0) >> 4); - cop += (d_mack_message[7 + step] & 0x0F); + tag += (static_cast((d_mack_message[4 + step] & 0x0F)) << 16); + tag += (static_cast(d_mack_message[5 + step]) << 8); + tag += static_cast(d_mack_message[6 + step]); + PRN_d += d_mack_message[7 + step]; + ADKD += ((d_mack_message[8 + step] & 0xF0) >> 4); + cop += (d_mack_message[8 + step] & 0x0F); if (k == (nt - 2)) { d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) { - d_osnma_data.d_mack_message.key[j] = d_mack_message[8 + step + j]; + d_osnma_data.d_mack_message.key[j] = d_mack_message[9 + step + j]; } } } else { - tag += (static_cast(d_mack_message[3 + step]) << 12); - tag += (static_cast(d_mack_message[4 + step]) << 4); - tag += (static_cast((d_mack_message[5 + step] & 0xF0)) >> 4); - PRN_d += (d_mack_message[5 + step] & 0x0F) << 4; - PRN_d += (d_mack_message[6 + step] & 0xF0) >> 4; - ADKD += (d_mack_message[6 + step] & 0x0F); - cop += (d_mack_message[7 + step] & 0xF0) >> 4; + tag += (static_cast(d_mack_message[4 + step]) << 12); + tag += (static_cast(d_mack_message[5 + step]) << 4); + tag += (static_cast((d_mack_message[6 + step] & 0xF0)) >> 4); + PRN_d += (d_mack_message[6 + step] & 0x0F) << 4; + PRN_d += (d_mack_message[7 + step] & 0xF0) >> 4; + ADKD += (d_mack_message[7 + step] & 0x0F); + cop += (d_mack_message[8 + step] & 0xF0) >> 4; if (k == (nt - 2)) { d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) { - d_osnma_data.d_mack_message.key[j] = ((d_mack_message[7 + step + j] & 0x0F) << 4) + ((d_mack_message[8 + step + j] & 0xF0) >> 4); + d_osnma_data.d_mack_message.key[j] = ((d_mack_message[8 + step + j] & 0x0F) << 4) + ((d_mack_message[9 + step + j] & 0xF0) >> 4); } } } @@ -801,7 +790,7 @@ void osnma_msg_receiver::read_mack_body() } else if (lt_bits == 40) { - tag += (static_cast((d_mack_message[7 + k * 7])) << 32); + tag += (static_cast((d_mack_message[7/* bytes of MACK header */ + k * 7 /* offset of k-th tag */])) << 32); tag += (static_cast((d_mack_message[8 + k * 7])) << 24); tag += (static_cast((d_mack_message[9 + k * 7])) << 16); tag += (static_cast((d_mack_message[10 + k * 7])) << 8); @@ -809,7 +798,7 @@ void osnma_msg_receiver::read_mack_body() PRN_d += d_mack_message[12 + k * 7]; ADKD += ((d_mack_message[13 + k * 7] & 0xF0) >> 4); cop += (d_mack_message[13 + k * 7] & 0x0F); - if (k == (nt - 2)) + if (k == (nt - 2)) // end of Tag&Info { d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) @@ -823,15 +812,7 @@ void osnma_msg_receiver::read_mack_body() d_osnma_data.d_mack_message.tag_and_info[k].tag_info.ADKD = ADKD; d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = cop; } - - // retrieve tesla key - uint8_t start_index_bytes = ( 480 - (lt_bits + 16) - (nt - 1) * ( lt_bits + 16 ) - 1 ) / 8; // includes -1 to start at [i-1] - uint8_t last_index_bytes = ( start_index_bytes * 8 + lk_bits ) / 8; - uint8_t key_index_bytes = 0; - for (uint8_t i = start_index_bytes; i < last_index_bytes ; i++, key_index_bytes++) - { - d_osnma_data.d_mack_message.key[key_index_bytes] = d_mack_message[i]; - } + // rest are padding bits, used for anything ? } @@ -851,34 +832,48 @@ void osnma_msg_receiver::read_mack_body() */ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& osnma_msg) { + d_flag_debug = true; // populate d_nav_data with needed data from subframe d_osnma_data.d_nav_data.init(osnma_msg); // store MACK, KROOT and NavData needed. d_old_OSNMA_buffer.push_back(d_osnma_data); - + if(d_old_OSNMA_buffer.size() < 3) + { + std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " + << "Not enough OSNMA messages available" + << "buffer size: "<< d_old_OSNMA_buffer.size() << std::endl; + return; + } if(d_kroot_verified == false && d_tesla_key_verified == false) { std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " - << "No Kroot nor TESLA key available" << static_cast(d_osnma_data.d_nma_header.cid) << std::endl; - return; // early return, cannot proceed further without one of the two verified. + << "No Kroot nor TESLA key available" << std::endl; + if(!d_flag_debug) + return; // early return, cannot proceed further without one of the two verified. } // Verify tesla key - if(d_tesla_key_verified) + if(d_tesla_key_verified || d_flag_debug) { // TODO - find out I bt. both tesla keys, then hash until then, then compare. + // retrieve latest tesla key + // compute hashes needed + // hash current key until num_hashes and compare } else {// have to go until Kroot - uint8_t num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 ICD + uint32_t num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 ICD + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; + auto start = std::chrono::high_resolution_clock::now(); uint32_t GST_SFi = d_receiver_time; std::vector K_II = d_osnma_data.d_mack_message.key; std::vector K_I; // result of the recursive hash operations const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) - for (uint8_t i = 1; i < num_of_hashes_needed ; i++) + for (uint32_t i = 1; i < num_of_hashes_needed ; i++) { // build message digest m = (K_I+1 || GST_SFi || alpha) + // TODO sizeof() wrong. std::vector msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); std::copy(K_II.begin(),K_II.end(),msg.begin()); @@ -919,6 +914,10 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& K_I.clear(); // empty the actual one for a new computation } // compare computed current key against received key + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; + if(K_II.size() != d_osnma_data.d_mack_message.key.size()) { std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; @@ -936,62 +935,56 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& { std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - return; + if(!d_flag_debug) + return; } } - // verify MACK tags - MACSEQ + OSNMA_data applicable_OSNMA = d_old_OSNMA_buffer[d_old_OSNMA_buffer.size() - 2]; // former subframe + d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. + std::vector applicable_key = d_old_OSNMA_buffer.back().d_mack_message.key; // current tesla key ie transmitted in the next subframe std::vector sq1{}; std::vector sq2{}; - - // for OSNMA data (MACK, KROOT messages): - // if ADKD=12, pick d_old_OSNMA_buffer.front() or d_old_OSNMA_buffer[1] iff d_old_OSNMA_buffer is full (guaranteed 10 SF above) - // otherwise pick d_old_OSNMA_buffer[size-2] - OSNMA_data applicable_OSNMA = d_old_OSNMA_buffer[d_old_OSNMA_buffer.size() - 2]; // former subframe - d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ - - // for the applicable tesla key: - // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] - std::vector applicable_key = d_old_OSNMA_buffer.back().d_mack_message.key; // current tesla key - + std::vector applicable_sequence; const auto it = OSNMA_TABLE_16.find(applicable_OSNMA.d_dsm_kroot_message.maclt); + // TODO as per RG example appears that the seq. q shall also be validated ageints either next or former Sf (depending on GST) if (it != OSNMA_TABLE_16.cend()) { - std::vector sq1 = it->second.sequence1; - std::vector sq2 = it->second.sequence2; + sq1 = it->second.sequence1; + sq2 = it->second.sequence2; } - std::vector sequence; + // Assign relevant sequence based on subframe time - if (d_GST_Sf % 60 == 0) + if (applicable_OSNMA.d_nav_data.TOW_sf0 % 60 < 30) // tried GST_Sf and it does not support the data present. { - sequence = sq1; + applicable_sequence = sq1; } - else if (d_GST_Sf % 60 == 30) + else if (applicable_OSNMA.d_nav_data.TOW_sf0 % 60 >= 30) { - sequence = sq2; + applicable_sequence = sq2; } else { - std::cout << "Galileo OSNMA: Mismatch in the GST verification => should end in 30 or 60 seconds but it dit not." << std::endl; + std::cout << "Galileo OSNMA: Mismatch in the GST verification. " << std::endl; } // compare ADKD of Mack tags with MACLT defined ADKDs - if(applicable_OSNMA.d_mack_message.tag_and_info.size() != sq1.size()) + if(applicable_OSNMA.d_mack_message.tag_and_info.size() != applicable_sequence.size()-1) { std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; return; } std::vector flxTags {}; std::string tempADKD; - for (uint8_t i = 0; i < d_osnma_data.d_mack_message.tag_and_info.size(); i++) + for (uint8_t i = 0; i < applicable_OSNMA.d_mack_message.tag_and_info.size(); i++) { - tempADKD = sequence[i]; + tempADKD = applicable_sequence[i+1]; if(tempADKD == "FLX") { flxTags.push_back(i); // C: just need to save the index in the sequence } - else if(d_osnma_data.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(sequence[i])) - { std::cout << "Galileo OSNMA: Unsuccessful verification of received ADKD against MAC Look-up table. " << std::endl; + else if(applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i+1])) + { std::cout << "Galileo OSNMA: Unsuccessful verification of MACSEQ - received ADKD against MAC Look-up table. " << std::endl; return; // C: suffices one incorrect to abort and not process the rest of the tags } } @@ -999,8 +992,8 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // MACSEQ verification // Fixed as well as FLX Tags share first part - Eq. 22 ICD - std::vector m(5 + flxTags.size()); - m[0] = static_cast(applicable_OSNMA.d_nav_data.PRNa); // PRN_A + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + m[0] = static_cast(applicable_OSNMA.d_nav_data.PRNa); // PRN_A - SVID of the satellite transmiting the tag m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); @@ -1009,11 +1002,14 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& // Case tags flexible - Eq. 21 ICD for (uint8_t i = 0; i < flxTags.size() ; i++) { - m[i+5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; - m[i+6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | + m[2*i + 5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; + m[2*i + 6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; } - +// m = {0x18, 0x4f, 0x93, 0x53, 0x04, 0x05, 0x0f, 0x1f, 0x0f}; +// applicable_key = {0x11, 0x26, 0x47, 0x3b, 0x0e, 0x05, 0x05, 0x35, +// 0xb0, 0xf2, 0xa7, 0x24, 0x00, 0x22, 0xba, 0x8f}; +// applicable_OSNMA.d_mack_message.header.macseq = 0xbb8; // compute mac std::vector mac; if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 @@ -1030,11 +1026,10 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& { mac_msb = (mac[0] << 8) + mac[1]; } - uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; // TODO - double check, it was 0x0FFF which presuposes little endian... - + uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; // Verify tags if MACSEQ is authenticated if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq) - { + { // TODO this shall affect only flx tags verification - and currently all tags of a MACK are affected which is undesired std::cout << "OSNMA: MACSEQ authenticated for PRN_A " << osnma_msg->PRN << " with WN=" << osnma_msg->WN_sf0 << ", TOW=" @@ -1062,7 +1057,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& applicable_OSNMA = d_old_OSNMA_buffer[t]; // former subframe d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ - int i = 0; + size_t i = 0; while (i < applicable_OSNMA.d_mack_message.tag_and_info.size() && // loop over all tags in MACK message std::find(d_tags_to_verify.begin(),d_tags_to_verify.end(), // ADKD[i] is within allowed ADKDs applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD) @@ -1076,6 +1071,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& uint8_t applicable_COP = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.cop; // * d_delta_COP; uint8_t counter_COP = 1; uint8_t applicable_PRNd = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.PRN_d; + // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; // current subframe NavData applicable_NavData{}; if((applicable_ADKD == 0 || applicable_ADKD == 4) && d_old_OSNMA_buffer.size() > 3) @@ -1352,3 +1348,22 @@ bool osnma_msg_receiver::verify_tag(MACK_tag_and_info tag_and_info, } return verified; } +/** + * @brief Checks if the current subframe time is bigger than last one received. + * + * \details It compares the current GST value with the previous one and updates the old value with the new one. + * + * @param sharedPtr A shared pointer to an instance of OSNMA_msg. + * @return True if the current subframe is the next subframe, False otherwise. + */ +bool osnma_msg_receiver::is_next_subframe() +{ + bool is_bigger = d_GST_SIS > d_old_GST_SIS; + if(d_GST_SIS != d_old_GST_SIS + 30 && d_old_GST_SIS != 0){ + std::cout << "Galileo OSNMA:: Mack processing - skip " << std::endl; + } + + d_old_GST_SIS = d_GST_SIS; + + return is_bigger; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 5cde3ddfa..b6a7bb812 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -89,7 +89,9 @@ private: bool d_public_key_verified{false}; bool d_kroot_verified{false}; bool d_tesla_key_verified{false}; + bool d_flag_debug{false}; uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification + uint32_t d_old_GST_SIS{0}; uint8_t d_Lt_min {}; // minimum equivalent tag length uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing @@ -101,6 +103,7 @@ private: enum tags_to_verify{all,utc,slow_eph, eph, none}; // TODO is this safe? I hope so tags_to_verify d_tags_allowed{tags_to_verify::all}; std::vector d_tags_to_verify{0,4,12}; + bool is_next_subframe(); }; diff --git a/src/core/libs/supl/CMakeLists.txt b/src/core/libs/supl/CMakeLists.txt index a08631e91..743852047 100644 --- a/src/core/libs/supl/CMakeLists.txt +++ b/src/core/libs/supl/CMakeLists.txt @@ -49,7 +49,8 @@ endif() if(OPENSSL_FOUND) target_compile_definitions(core_libs_supl PUBLIC -DUSE_OPENSSL_FALLBACK=1) endif() - +message("OPENSSL_FOUND: " ${OPENSSL_FOUND}) +message("USE_OPENSSL_FALLBACK:" ${USE_OPENSSL_FALLBACK}) target_link_libraries(core_libs_supl PUBLIC ${GNUTLS_LIBRARIES} diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 44f607370..e6530b610 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -143,7 +143,7 @@ const std::unordered_map OSNMA_TABLE_11 = { {4, 0}, {5, 20}, {6, 24}, - {7, 26}, + {7, 28}, {8, 32}, {9, 40}, {10, 0}, @@ -184,7 +184,16 @@ const std::unordered_map OSNMA_TABLE_16 = { {27, {2, 6, {"00S", "00E", "00E", "00E", "12S", "00E"}, {"00S ", "00E", "00E", "04S", "12S", "00E"}}}, {28, {2, 10, {"00S", "00E", "00E", "00E", "00S", "00E", "00E", "12S", "00E", "00E"}, {"00S", "00E", "00E", "00S", "00E", "00E", "04S", "12S", "00E", "00E"}}}, {31, {2, 5, {"00S", "00E", "00E", "12S", "00E"}, {"00S", "00E", "00E", "12S", "04S"}}}, - {33, {2, 6, {"00S", "00E", "04S", "00E", "12S", "00E"}, {"00S", "00E", "00E", "12S", "00E", "12E"}}}}; + {33, {2, 6, {"00S", "00E", "04S", "00E", "12S", "00E"}, {"00S", "00E", "00E", "12S", "00E", "12E"}}}, + {34, {2, 6, {"00S", "FLX", "04S", "FLX", "12S", "00E"}, {"00S", "FLX", "00E", "12S", "00E", "12E"}}}, + {35, {2, 6, {"00S", "FLX", "04S", "FLX", "12S", "FLX"}, {"00S", "FLX", "FLX", "12S", "FLX", "FLX"}}}, + {36, {2, 5, {"00S", "FLX", "04S", "FLX", "12S"}, {"00S", "FLX", "00E", "12S", "12E"}}}, + {37, {2, 5, {"00S", "00E", "04S", "00E", "12S"}, {"00S", "00E", "00E", "12S", "12E"}}}, + {38, {2, 5, {"00S", "FLX", "04S", "FLX", "12S"}, {"00S", "FLX", "FLX", "12S", "FLX"}}}, + {39, {2, 4, {"00S", "FLX", "04S", "FLX"}, {"00S", "FLX", "00E", "12S"}}}, + {40, {2, 4, {"00S", "00E", "04S", "12S"}, {"00S", "00E", "00E", "12E"}}}, + {41, {2, 4, {"00S", "FLX", "04S", "FLX"}, {"00S", "FLX", "FLX", "12S"}}} +}; /** \} */ /** \} */ diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 965469433..af7df7899 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -502,6 +502,45 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } bool success = false; #if USE_OPENSSL_FALLBACK + + EVP_MD_CTX *mdctx = NULL; // verification context; a struct that wraps the message to be verified. + int ret = 0; // error + + /* Create the Message Digest Context */ + if(!(mdctx = EVP_MD_CTX_new())) goto err; // Allocates and returns a digest context. + + /* Initialize `key` with a public key */ + // hashes cnt bytes of data at d into the verification context ctx + if(1 != EVP_DigestVerifyInit(mdctx, NULL /*TODO null?*/, EVP_sha256(), NULL, d_PublicKey)) goto err; + + /* Initialize `key` with a public key */ + if(1 != EVP_DigestVerifyUpdate(mdctx, message.data(), message.size())) goto err; + + + if( 1== EVP_DigestVerifyFinal(mdctx, signature.data(), signature.size())) + { + return true; + } + else + { + unsigned long errCode = ERR_get_error(); + int lib_code = ERR_GET_LIB(errCode); + char* err = ERR_error_string(errCode, NULL); + const char* error_string = ERR_error_string(errCode, NULL); + std::cerr << "OpenSSL: message authentication failed: " << err /*<< + "from library with code " << lib_code << + " error string: " << error_string */<< std::endl; + } +err: + if(ret != 1) + { + /* Do some error handling */ + // notify other blocks + std::cout << "ECDSA_Verify_OSSL()::error " << ret << std::endl; + + } + + #if USE_OPENSSL_3 EVP_PKEY_CTX* ctx; print_pubkey_hex(d_PublicKey); @@ -695,11 +734,6 @@ std::vector Gnss_Crypto::get_public_key() return {}; } -// TODO make them compilable with any prepro directive -// void Gnss_Crypto::my_log_func(int level, const char *msg) { -// fprintf(stderr, " %s", level, msg);} -// -// // gnutls-specific functions #if USE_OPENSSL_FALLBACK bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) @@ -777,8 +811,11 @@ void Gnss_Crypto::print_pubkey_hex(EVP_PKEY* pubkey) BIO_free(mem_bio); } -#else - bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) +#else // gnutls-specific functions + void Gnss_Crypto::my_log_func(int level, const char *msg){ + fprintf(stderr, " %s", level, msg);} + + bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) { gnutls_datum_t key_datum; int ret; @@ -812,7 +849,7 @@ void Gnss_Crypto::print_pubkey_hex(EVP_PKEY* pubkey) return true; } - void Gnss_Crypto::print_pubkey_hex(gnutls_pubkey_t pubkey) + void Gnss_Crypto::print_pubkey_hex(gnutls_pubkey_t pubkey) { gnutls_datum_t key_datum; int ret; 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 96304ef02..4f57162fa 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 @@ -144,4 +144,28 @@ TEST(GnssCryptoTest,VerifyPubKeyImport) // 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 }; +} + +// Unit test for computeHMAC_SHA_256 function. +TEST(GnssCryptoTest, TestComputeHMACSHA256) { + std::unique_ptr d_crypto = std::make_unique(); + std::vector key = { + 0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7, + 0x7D, 0x48, 0xE7, 0xF1, 0x48, 0x0C, 0xC2, 0x98, + 0xEB, 0x62, 0x3E, 0x95, 0x6B, 0x2B, 0xCE, 0xA3, + 0xB4, 0xD4, 0xDB, 0x31, 0xEE, 0x96, 0xAB, 0xFA }; + + std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A + std::vector expected_output = { + 0xC3, 0x51, 0xF6, 0xFD, 0xDD, 0xC9, 0x8B, 0x41, + 0xD6, 0xF4, 0x77, 0x6D, 0xAC, 0xE8, 0xE0, 0x14, + 0xB2, 0x7A, 0xCC, 0x22, 0x00, 0xAA, 0xD2, 0x37, + 0xD0, 0x79, 0x06, 0x12, 0x83, 0x40, 0xB7, 0xA6 }; + + + std::vector output = d_crypto->computeHMAC_SHA_256(key, message); + + ASSERT_EQ(expected_output, output); + + } \ No newline at end of file From 37b343391c13db4ad062f891f497c520479139e9 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sat, 16 Mar 2024 19:05:01 +0100 Subject: [PATCH 095/219] Refactor tag verification logic WIP --- src/core/libs/osnma_msg_receiver.cc | 614 ++++++++++++++--------- src/core/libs/osnma_msg_receiver.h | 17 +- src/core/system_parameters/osnma_data.cc | 1 + src/core/system_parameters/osnma_data.h | 41 ++ 4 files changed, 439 insertions(+), 234 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index f439b97b8..21fe08b1e 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -38,6 +38,7 @@ #if PMT_USES_BOOST_ANY #include +#include namespace wht = boost; #else #include @@ -169,7 +170,7 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) } /* - * accumulates dsm messages until completeness, then calls process_dsm_message + * accumulates dsm messages * */ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_msg) { @@ -559,9 +560,12 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr& osnma_msg) { d_flag_debug = true; - // populate d_nav_data with needed data from subframe - d_osnma_data.d_nav_data.init(osnma_msg); - // store MACK, KROOT and NavData needed. - d_old_OSNMA_buffer.push_back(d_osnma_data); - if(d_old_OSNMA_buffer.size() < 3) - { - std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " - << "Not enough OSNMA messages available" - << "buffer size: "<< d_old_OSNMA_buffer.size() << std::endl; - return; - } + if(d_kroot_verified == false && d_tesla_key_verified == false) { std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " - << "No Kroot nor TESLA key available" << std::endl; + << "No Kroot nor TESLA key available" << std::endl; if(!d_flag_debug) return; // early return, cannot proceed further without one of the two verified. } - - // Verify tesla key - if(d_tesla_key_verified || d_flag_debug) - { - // TODO - find out I bt. both tesla keys, then hash until then, then compare. - // retrieve latest tesla key - // compute hashes needed - // hash current key until num_hashes and compare + // verify tesla key and add it to the container of verified keys if successful + bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key); + if(retV){ + d_tesla_keys.insert(std::pair(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); } - else - {// have to go until Kroot - uint32_t num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 ICD - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; - auto start = std::chrono::high_resolution_clock::now(); - uint32_t GST_SFi = d_receiver_time; - std::vector K_II = d_osnma_data.d_mack_message.key; - std::vector K_I; // result of the recursive hash operations - const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; - // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) - for (uint32_t i = 1; i < num_of_hashes_needed ; i++) - { - // build message digest m = (K_I+1 || GST_SFi || alpha) - // TODO sizeof() wrong. - std::vector msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); - std::copy(K_II.begin(),K_II.end(),msg.begin()); - msg.push_back((d_GST_Sf & 0xFF000000) >> 24); - msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); - msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); - msg.push_back(d_GST_Sf & 0x000000FF); - // extract alpha - for (int k = 5; k >= 0;k--) - { - // TODO: static extracts the MSB in case from larger to shorter int? - msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. - } - // compute hash - std::vector hash; - if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. - { - hash = d_crypto->computeSHA256(msg); - } - else if (d_osnma_data.d_dsm_kroot_message.hf == 2) - { - hash = d_crypto->computeSHA3_256(msg); - } + // MACSEQ - verify current macks, then add current retrieved mack to the end. + for (auto& mack : d_macks_awating_MACSEQ_verification){ + if(d_tesla_keys.find(mack.TOW) != d_tesla_keys.end()){ + bool ret = verify_macseq(mack); + + } + + } + // TODO verify MACSEQ of FLX tags + // add newly retrieved tags to the container + for (const auto& MTI: d_osnma_data.d_mack_message.tag_and_info){ + Tag tag(MTI, d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_nav_data.PRNa); + d_tags_awaiting_verify.insert({tag.TOW, tag}); + } + + // d_satellite_data already updated from a msg_handler coming from TD. TODO + +// d_old_OSNMA_buffer.push_back(d_osnma_data); // TODO deprecate +// if(d_keys.size() < 2) +// { +// std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " +// << "Not enough OSNMA messages available" +// << "buffer size: "<< d_old_OSNMA_buffer.size() << std::endl; +// return; +// } + + // verify tags + for (auto it = d_tags_awaiting_verify.begin(); it != d_tags_awaiting_verify.end(); ++it){ + bool ret; + if(d_tesla_keys.find(it->first) != d_tesla_keys.end() && nav_data_available(it->second)){ + ret = verify_tag(it->second); + if(ret) + int a; + // TODO notify PVT via pmt else - { - hash = std::vector(32); - } - // truncate hash - K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits - for (uint16_t i = 0; i < lk_bytes; i++) - { - K_I.push_back(hash[i]); - } - - // set parameters for next iteration - GST_SFi -= 30; // next SF time is the actual minus 30 seconds - K_II = K_I; // next key is the actual one - K_I.clear(); // empty the actual one for a new computation - } - // compare computed current key against received key - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; - - if(K_II.size() != d_osnma_data.d_mack_message.key.size()) - { - std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - return; - } - if (K_II == d_osnma_data.d_mack_message.key) - { - std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; - d_tesla_key_verified = true; - // TODO - propagate result - // TODO - save current tesla key as latest one? propose a map with - // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence - } - else - - { - std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - if(!d_flag_debug) - return; + int a; + // also } } + remove_verified_tags(); + + control_tags_awaiting_verify_size(); // remove oldest tags if size is too big. + + + + + + + + + + + + // verify MACK tags - MACSEQ OSNMA_data applicable_OSNMA = d_old_OSNMA_buffer[d_old_OSNMA_buffer.size() - 2]; // former subframe - d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. + + //d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. std::vector applicable_key = d_old_OSNMA_buffer.back().d_mack_message.key; // current tesla key ie transmitted in the next subframe std::vector sq1{}; std::vector sq2{}; @@ -968,7 +935,6 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& { std::cout << "Galileo OSNMA: Mismatch in the GST verification. " << std::endl; } - // compare ADKD of Mack tags with MACLT defined ADKDs if(applicable_OSNMA.d_mack_message.tag_and_info.size() != applicable_sequence.size()-1) { std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; @@ -976,6 +942,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& } std::vector flxTags {}; std::string tempADKD; + // MACLT verification for (uint8_t i = 0; i < applicable_OSNMA.d_mack_message.tag_and_info.size(); i++) { tempADKD = applicable_sequence[i+1]; @@ -989,121 +956,96 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& } } - // MACSEQ verification - // Fixed as well as FLX Tags share first part - Eq. 22 ICD - std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes - m[0] = static_cast(applicable_OSNMA.d_nav_data.PRNa); // PRN_A - SVID of the satellite transmiting the tag - m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); - m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); - m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); - m[4] = static_cast(d_GST_Sf & 0x000000FF); - - // Case tags flexible - Eq. 21 ICD - for (uint8_t i = 0; i < flxTags.size() ; i++) - { - m[2*i + 5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; - m[2*i + 6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | - applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; - } -// m = {0x18, 0x4f, 0x93, 0x53, 0x04, 0x05, 0x0f, 0x1f, 0x0f}; -// applicable_key = {0x11, 0x26, 0x47, 0x3b, 0x0e, 0x05, 0x05, 0x35, -// 0xb0, 0xf2, 0xa7, 0x24, 0x00, 0x22, 0xba, 0x8f}; -// applicable_OSNMA.d_mack_message.header.macseq = 0xbb8; - // compute mac - std::vector mac; - if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 - { - mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); - } - else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES - { - mac = d_crypto->computeCMAC_AES(applicable_key, m); - } - // Truncate the twelve MSBits and compare with received MACSEQ - uint16_t mac_msb = 0; - if (!mac.empty()) - { - mac_msb = (mac[0] << 8) + mac[1]; - } - uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; // Verify tags if MACSEQ is authenticated - if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq) - { // TODO this shall affect only flx tags verification - and currently all tags of a MACK are affected which is undesired - std::cout << "OSNMA: MACSEQ authenticated for PRN_A " + bool flxTagsV = false; + if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq && flxTags.size() > 0) + { + std::cout << "Galileo OSNMA: FLX tags authenticated for PRN_A " << osnma_msg->PRN << " with WN=" << osnma_msg->WN_sf0 << ", TOW=" << osnma_msg->TOW_sf0 << ". Verifying tags. " << std::endl; - uint8_t lt_bits = 0; - const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); - if (it2 != OSNMA_TABLE_11.cend()) - { - lt_bits = it2->second; - } - if (lt_bits == 0) - { - return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. + flxTagsV = true; + } + + uint8_t lt_bits = 0; + const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); + if (it2 != OSNMA_TABLE_11.cend()) + { + lt_bits = it2->second; + } + if (lt_bits == 0) + { + return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. + } + + // Tag verification + // tag[i-1]: + // adkd = 4/0 : use TK[i], NavData[i-2] to validate Tag[i-1] + // adkd = 12 : ignore it -> not possible to verify yet + // tag[i-10] + // adkd = 4/0 : use TK[i-9], NavData[i-11] to validate Tag[i-10] would already be done by tag[i-1] + // adkd = 12 : use TK[i], NavData[i-11] to validate Tag[i-10] TODO - pending better logic for not repeating this while twice. + int t = d_old_OSNMA_buffer.size() - 2; + applicable_OSNMA = d_old_OSNMA_buffer[t]; // former subframe + d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ + + size_t i = 0; + while (i < applicable_OSNMA.d_mack_message.tag_and_info.size() && // loop over all tags in MACK message + std::find(d_tags_to_verify.begin(),d_tags_to_verify.end(), // ADKD[i] is within allowed ADKDs + applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD) + != d_tags_to_verify.end()) + { + // TODO - if a subsequent tag was already part of the verification (inner loop), this while is going to ignore that and try to validate it anyway. + + // check if tag is flx + bool is_flexible_tag = std::find(flxTags.begin(),flxTags.end(), i) != flxTags.end(); + if(is_flexible_tag && flxTagsV == false){ + //std::cout << "Galileo OSNMA: cannot verify flx tag. " << std::endl; + continue; } - // Tag verification - // tag[i-1]: - // adkd = 4/0 : use TK[i], NavData[i-2] to validate Tag[i-1] - // adkd = 12 : ignore it -> not possible to verify yet - // tag[i-10] - // adkd = 4/0 : use TK[i-9], NavData[i-11] to validate Tag[i-10] would already be done by tag[i-1] - // adkd = 12 : use TK[i], NavData[i-11] to validate Tag[i-10] TODO - pending better logic for not repeating this while twice. - int t = d_old_OSNMA_buffer.size() - 2; - applicable_OSNMA = d_old_OSNMA_buffer[t]; // former subframe - d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ - size_t i = 0; - while (i < applicable_OSNMA.d_mack_message.tag_and_info.size() && // loop over all tags in MACK message - std::find(d_tags_to_verify.begin(),d_tags_to_verify.end(), // ADKD[i] is within allowed ADKDs - applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD) - != d_tags_to_verify.end()) + // Take tag_k and check its ADKD, COP, PRN_d, this will be the reference for the iteration and search of other Tags + uint8_t Nt = d_Lt_min / applicable_OSNMA.d_dsm_kroot_message.ts; // Tags needed to be verified + uint8_t applicable_ADKD = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD; + uint8_t applicable_COP = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.cop; // * d_delta_COP; + uint8_t counter_COP = 1; + uint8_t applicable_PRNd = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.PRN_d; + // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] + applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; // current subframe + NavData applicable_NavData{}; + if((applicable_ADKD == 0 || applicable_ADKD == 4) && d_old_OSNMA_buffer.size() > 3) { - // TODO - if a subsequent tag was already part of the verification (inner loop), this while is going to ignore that and try to validate it anyway. - - // Take tag_k and check its ADKD, COP, PRN_d, this will be the reference for the iteration and search of other Tags - uint8_t Nt = d_Lt_min / applicable_OSNMA.d_dsm_kroot_message.ts; // Tags needed to be verified - uint8_t applicable_ADKD = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD; - uint8_t applicable_COP = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.cop; // * d_delta_COP; - uint8_t counter_COP = 1; - uint8_t applicable_PRNd = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.PRN_d; - // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] - applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; // current subframe - NavData applicable_NavData{}; - if((applicable_ADKD == 0 || applicable_ADKD == 4) && d_old_OSNMA_buffer.size() > 3) - { - applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; - } - else if(applicable_ADKD == 12 && d_old_OSNMA_buffer.size() > 11) - { - applicable_NavData = d_old_OSNMA_buffer[t - 11].d_nav_data; - } - else - { - std::cout << "Galileo OSNMA: MACK message buffer elements not enough. Cannot verify tags. " << std::endl; - } + applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; + } + else if(applicable_ADKD == 12 && d_old_OSNMA_buffer.size() > 11) + { + applicable_NavData = d_old_OSNMA_buffer[t - 11].d_nav_data; + } + else + { + std::cout << "Galileo OSNMA: MACK message buffer elements not enough. Cannot verify tags. " << std::endl; + } - int k = i + 1; - uint8_t nt = 0; - bool flag_cancel_tag_verification = false; // if a tag fails, cancel whole NavData verification set - // Look for tags relative to reference NavData until Nt achieved, - // this may require going back in time, as long as COP is valid - while (nt <= Nt && counter_COP <= applicable_COP && !flag_cancel_tag_verification) - { - auto start_it = std::next(applicable_OSNMA.d_mack_message.tag_and_info.begin(), k); + int k = i + 1; + uint8_t nt = 0; + bool flag_cancel_tag_verification = false; // if a tag fails, cancel whole NavData verification set + // Look for tags relative to reference NavData until Nt achieved, + // this may require going back in time, as long as COP is valid + while (nt <= Nt && counter_COP <= applicable_COP && !flag_cancel_tag_verification) + { + auto start_it = std::next(applicable_OSNMA.d_mack_message.tag_and_info.begin(), k); - // check the vector of tags of aplicable OSNMA for a match against the chosen - for (auto it = start_it; it != applicable_OSNMA.d_mack_message.tag_and_info.end() && nt <= Nt; ++it) + // check the vector of tags of aplicable OSNMA for a match against the chosen + for (auto it = start_it; it != applicable_OSNMA.d_mack_message.tag_and_info.end() && nt <= Nt; ++it) { - // Check if ADKD, COP, and PRN_d match - if(it->tag_info.ADKD == applicable_ADKD - // && it->tag_info.cop == applicable_COP // TODO - I think this may be skipped as the relevant is the COP distance. - && it->tag_info.PRN_d == applicable_PRNd) + // Check if ADKD, COP, and PRN_d match + if(it->tag_info.ADKD == applicable_ADKD + // && it->tag_info.cop == applicable_COP // TODO - I think this may be skipped as the relevant is the COP distance. + && it->tag_info.PRN_d == applicable_PRNd) { if(verify_tag(it.operator*(), applicable_OSNMA, k,applicable_key,applicable_NavData)) { @@ -1111,46 +1053,44 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& } else { - // failure, discard this k-th tag - flag_cancel_tag_verification = true; - std::cout << "Galileo OSNMA: tag verification failed for PRN_a " - << applicable_OSNMA.d_nav_data.PRNa << " with WN=" - << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" - << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " - << std::endl; + // failure, discard this k-th tag + flag_cancel_tag_verification = true; + std::cout << "Galileo OSNMA: tag verification failed for PRN_a " + << applicable_OSNMA.d_nav_data.PRNa << " with WN=" + << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" + << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " + << std::endl; } } - if(flag_cancel_tag_verification) - break; + if(flag_cancel_tag_verification) + break; } - // Check if Nt is achieved, if not, switch to older frame - if(nt < Nt && t > 0 /*not end of buffer*/ && counter_COP <= applicable_COP && !flag_cancel_tag_verification) - { - t--; - applicable_OSNMA = d_old_OSNMA_buffer[t]; - applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; - applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; - d_GST_Sf -= 30; - counter_COP++; - k = 0; - } - } - - if (nt >= Nt) + // Check if Nt is achieved, if not, switch to older frame + if(nt < Nt && t > 0 /*not end of buffer*/ && counter_COP <= applicable_COP && !flag_cancel_tag_verification) { - nt = 0; - std::cout << "Galileo OSNMA: tag verification accumulation succesful for PRN_a " - << applicable_OSNMA.d_nav_data.PRNa << " with WN=" - << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" - << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " - << std::endl; + t--; + applicable_OSNMA = d_old_OSNMA_buffer[t]; + applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; + applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; + d_GST_Sf -= 30; + counter_COP++; + k = 0; } - } + if (nt >= Nt) + { + nt = 0; + std::cout << "Galileo OSNMA: tag verification accumulation succesful for PRN_a " + << applicable_OSNMA.d_nav_data.PRNa << " with WN=" + << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" + << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " + << std::endl; + } } + } bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) @@ -1348,6 +1288,27 @@ bool osnma_msg_receiver::verify_tag(MACK_tag_and_info tag_and_info, } return verified; } +bool osnma_msg_receiver::verify_tag(Tag& tag) +{ + // TODO +// m = t.build_message(t) // **needs d_nav_data[t.PRNd][t.TOW-30]** +// +// t.hasKey()?: k = t.**getKey**() +// +// computed_tag = d_crypto→hmac(m,k) +// +// if t.tag == computed_tag +// +// t.verified::true; +// +// return true +// +// else +// +// t.verified::false +// +// return false; +} /** * @brief Checks if the current subframe time is bigger than last one received. * @@ -1367,3 +1328,194 @@ bool osnma_msg_receiver::is_next_subframe() return is_bigger; } +void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) +{ + while (d_satellite_data[SV_ID].size() >= 25) { + d_satellite_data[SV_ID].erase(d_satellite_data[SV_ID].begin()); + } + d_osnma_data[TOW] = crypto; // crypto + d_satellite_data[SV_ID][TOW] = data; // nav + std::cout << "Galileo OSNMA: added element, size is " << d_satellite_data[SV_ID].size() << std::endl; +} +void osnma_msg_receiver::display_data() +{ + if(d_satellite_data.empty()) + return; + + for(const auto& satellite : d_satellite_data) { + std::cout << "SV_ID: " << satellite.first << std::endl; + for(const auto& towData : satellite.second) { + std::cout << "\tTOW: " << towData.first << " key: "; + for(size_t i = 0; i < towData.second.d_mack_message.key.size(); i++) { + std::cout << std::hex << std::setfill('0') << std::setw(2) + << static_cast(towData.second.d_mack_message.key[i]) << " "; + } + } + } +} +bool osnma_msg_receiver::verify_tesla_key(std::vector& key) +{ + if(d_tesla_key_verified || d_flag_debug) + { + // TODO - find out I bt. both tesla keys, then hash until then, then compare. + // retrieve latest tesla key + // compute hashes needed + // hash current key until num_hashes and compare + } + else + {// have to go until Kroot + uint32_t num_of_hashes_needed = (d_GST_SIS - d_GST_0) / 30 + 1; // Eq. 19 ICD + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; + auto start = std::chrono::high_resolution_clock::now(); + uint32_t GST_SFi = d_GST_SIS; + std::vector K_II = applicable_MACK.key; + std::vector K_I; // result of the recursive hash operations + const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; + // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) + for (uint32_t i = 1; i < num_of_hashes_needed ; i++) + { + // build message digest m = (K_I+1 || GST_SFi || alpha) + std::vector msg(K_II.size() + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); + std::copy(K_II.begin(),K_II.end(),msg.begin()); + + msg.push_back((d_GST_Sf & 0xFF000000) >> 24); + msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); + msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); + msg.push_back(d_GST_Sf & 0x000000FF); + // extract alpha + for (int k = 5; k >= 0;k--) + { + // TODO: static extracts the MSB in case from larger to shorter int? + msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. + } + // compute hash + std::vector hash; + if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. + { + hash = d_crypto->computeSHA256(msg); + } + else if (d_osnma_data.d_dsm_kroot_message.hf == 2) + { + hash = d_crypto->computeSHA3_256(msg); + } + else + { + hash = std::vector(32); + } + // truncate hash + K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits + for (uint16_t i = 0; i < lk_bytes; i++) + { + K_I.push_back(hash[i]); + } + + // set parameters for next iteration + GST_SFi -= 30; // next SF time is the actual minus 30 seconds + K_II = K_I; // next key is the actual one + K_I.clear(); // empty the actual one for a new computation + } + // compare computed current key against received key + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; + + if(K_II.size() != applicable_MACK.key.size()) + { + std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + return; + } + if (K_II == applicable_MACK.key) + { + std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; + d_keys.insert(std::pair(applicable_MACK.TOW,applicable_MACK.key)); + d_tesla_key_verified = true; + // TODO - propagate result + // TODO - save current tesla key as latest one? propose a map with + // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence + } + else + + { + std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + if(!d_flag_debug) + return; + } + } + +} +void osnma_msg_receiver::remove_verified_tags() +{ + for (auto it = d_tags_awaiting_verify.begin(); it != d_tags_awaiting_verify.end() ; ){ + if (it->second.status == Tag::SUCCESS || it->second.status == Tag::FAIL) + it = d_tags_awaiting_verify.erase(it); + else + ++it; + } +} +void osnma_msg_receiver::control_tags_awaiting_verify_size() +{ + // TODO +} +bool osnma_msg_receiver::verify_macseq(MACK_message& message) +{ + // MACSEQ verification + + // Fixed as well as FLX Tags share first part - Eq. 22 ICD + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + m[0] = static_cast(applicable_OSNMA.d_nav_data.PRNa); // PRN_A - SVID of the satellite transmiting the tag + m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); + m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); + m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); + m[4] = static_cast(d_GST_Sf & 0x000000FF); + // Case tags flexible - Eq. 21 ICD + for (uint8_t i = 0; i < flxTags.size() ; i++) + { + m[2*i + 5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; + m[2*i + 6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | + applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; + } + // m = {0x18, 0x4f, 0x93, 0x53, 0x04, 0x05, 0x0f, 0x1f, 0x0f}; + // applicable_key = {0x11, 0x26, 0x47, 0x3b, 0x0e, 0x05, 0x05, 0x35, + // 0xb0, 0xf2, 0xa7, 0x24, 0x00, 0x22, 0xba, 0x8f}; + // applicable_OSNMA.d_mack_message.header.macseq = 0xbb8; + // compute mac + std::vector mac; + if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + { + mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + } + else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + { + mac = d_crypto->computeCMAC_AES(applicable_key, m); + } + // Truncate the twelve MSBits and compare with received MACSEQ + uint16_t mac_msb = 0; + if (!mac.empty()) + { + mac_msb = (mac[0] << 8) + mac[1]; + } + uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; + if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq && flxTags.size() > 0) + return true; + else + return false; +} +bool osnma_msg_receiver::nav_data_available(Tag t) +{ + auto prn_it = d_satellite_nav_data.find(t.PRNa); + if (prn_it != d_satellite_nav_data.end()) { + // PRN was found, check if TOW exists in inner map + std::map& tow_map = prn_it->second; + auto tow_it = tow_map.find(t.TOW); + if (tow_it != tow_map.end()) { + return true; + } else { + // TOW not found + return false; + } + } else { + // PRN was not found + return false; + } + return false; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index b6a7bb812..1a2703bcd 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -72,14 +72,23 @@ private: void read_mack_header(); void read_mack_body(); void process_mack_message(const std::shared_ptr& osnma_msg); + void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData &data); + bool verify_tesla_key(std::vector& key); + void const display_data(); bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); + bool verify_tag(Tag& tag); + bool is_next_subframe(); + bool nav_data_available(Tag& t); - //boost::circular_buffer d_old_mack_message; + std::map> d_satellite_nav_data; // map holding NavData sorted by SVID and TOW. boost::circular_buffer d_old_OSNMA_buffer; // buffer that holds last 12 received OSNMA messages, including current one at back() + std::map> d_tesla_keys; // tesla keys over time, sorted by TOW + std::vector d_macks_awating_MACSEQ_verification; + std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; - std::array, 16> d_dsm_message{}; // C: each dsm[0-15] has 2048 bits + std::array, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself. std::array, 16> d_dsm_id_received{}; std::array d_number_of_blocks{}; std::array d_mack_message{}; // C: 480 b @@ -103,7 +112,9 @@ private: enum tags_to_verify{all,utc,slow_eph, eph, none}; // TODO is this safe? I hope so tags_to_verify d_tags_allowed{tags_to_verify::all}; std::vector d_tags_to_verify{0,4,12}; - bool is_next_subframe(); + void remove_verified_tags(); + void control_tags_awaiting_verify_size(); + bool verify_macseq(MACK_message& message); }; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 9a291330d..44f343286 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -163,3 +163,4 @@ void NavData::generate_utc_vector() utc_vector.push_back(static_cast(bit_buffer)); } } + diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 4bc78ebbb..4a05ddabb 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -121,6 +121,7 @@ public: MACK_header header; std::vector tag_and_info; std::vector key; + uint32_t TOW; // TODO duplicated variable }; class NavData @@ -157,9 +158,49 @@ public: DSM_KROOT_message d_dsm_kroot_message; MACK_message d_mack_message; NavData d_nav_data; + }; +class Tag +{ +public: + enum e_verification_status{ + SUCCESS, + FAIL, + UNVERIFIED}; + Tag(const MACK_tag_and_info& MTI, uint32_t TOW, uint32_t PRNa) + : tag_id(id_counter++), + received_tag(MTI.tag), + computed_tag(0), + PRN_d(MTI.tag_info.PRN_d), + ADKD(MTI.tag_info.ADKD), + cop(MTI.tag_info.cop), + TOW(TOW), + PRNa(PRNa), + status(UNVERIFIED) + { + } + const uint32_t tag_id; + uint32_t TOW; + uint32_t PRNa; + std::vector build_message(); + e_verification_status status; + +private: + uint32_t static id_counter; + uint64_t received_tag; + uint64_t computed_tag; + + + uint8_t PRN_d; + uint8_t ADKD; + uint8_t cop; + + + +; +}; /** \} */ /** \} */ #endif // GNSS_SDR_OSNMA_DATA_H From 9120f5e59a1f9d0bab01f9ed0ff1082fc49c049e Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sat, 16 Mar 2024 19:05:01 +0100 Subject: [PATCH 096/219] Refactor tag verification logic WIP --- src/core/libs/osnma_msg_receiver.cc | 837 ++++++++++++++--------- src/core/libs/osnma_msg_receiver.h | 17 +- src/core/system_parameters/osnma_data.cc | 6 + src/core/system_parameters/osnma_data.h | 37 + 4 files changed, 588 insertions(+), 309 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index f439b97b8..21321e685 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -38,6 +38,7 @@ #if PMT_USES_BOOST_ANY #include +#include namespace wht = boost; #else #include @@ -169,7 +170,7 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) } /* - * accumulates dsm messages until completeness, then calls process_dsm_message + * accumulates dsm messages * */ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_msg) { @@ -559,9 +560,12 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr& osnma_msg) { d_flag_debug = true; - // populate d_nav_data with needed data from subframe - d_osnma_data.d_nav_data.init(osnma_msg); - // store MACK, KROOT and NavData needed. - d_old_OSNMA_buffer.push_back(d_osnma_data); - if(d_old_OSNMA_buffer.size() < 3) - { - std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " - << "Not enough OSNMA messages available" - << "buffer size: "<< d_old_OSNMA_buffer.size() << std::endl; - return; - } + if(d_kroot_verified == false && d_tesla_key_verified == false) { std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " - << "No Kroot nor TESLA key available" << std::endl; + << "No Kroot nor TESLA key available" << std::endl; if(!d_flag_debug) return; // early return, cannot proceed further without one of the two verified. } - - // Verify tesla key - if(d_tesla_key_verified || d_flag_debug) - { - // TODO - find out I bt. both tesla keys, then hash until then, then compare. - // retrieve latest tesla key - // compute hashes needed - // hash current key until num_hashes and compare - } - else - {// have to go until Kroot - uint32_t num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 ICD - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; - auto start = std::chrono::high_resolution_clock::now(); - uint32_t GST_SFi = d_receiver_time; - std::vector K_II = d_osnma_data.d_mack_message.key; - std::vector K_I; // result of the recursive hash operations - const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; - // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) - for (uint32_t i = 1; i < num_of_hashes_needed ; i++) - { - // build message digest m = (K_I+1 || GST_SFi || alpha) - // TODO sizeof() wrong. - std::vector msg(sizeof(K_II) + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); - std::copy(K_II.begin(),K_II.end(),msg.begin()); - - msg.push_back((d_GST_Sf & 0xFF000000) >> 24); - msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); - msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); - msg.push_back(d_GST_Sf & 0x000000FF); - // extract alpha - for (int k = 5; k >= 0;k--) - { - // TODO: static extracts the MSB in case from larger to shorter int? - msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. - } - // compute hash - std::vector hash; - if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. - { - hash = d_crypto->computeSHA256(msg); - } - else if (d_osnma_data.d_dsm_kroot_message.hf == 2) - { - hash = d_crypto->computeSHA3_256(msg); - } - else - { - hash = std::vector(32); - } - // truncate hash - K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits - for (uint16_t i = 0; i < lk_bytes; i++) - { - K_I.push_back(hash[i]); - } - - // set parameters for next iteration - GST_SFi -= 30; // next SF time is the actual minus 30 seconds - K_II = K_I; // next key is the actual one - K_I.clear(); // empty the actual one for a new computation - } - // compare computed current key against received key - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; - - if(K_II.size() != d_osnma_data.d_mack_message.key.size()) - { - std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - return; - } - if (K_II == d_osnma_data.d_mack_message.key) - { - std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; - d_tesla_key_verified = true; - // TODO - propagate result - // TODO - save current tesla key as latest one? propose a map with - // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence - } - else - - { - std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - if(!d_flag_debug) - return; - } + // verify tesla key and add it to the container of verified keys if successful + bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key); + if(retV){ + d_tesla_keys.insert(std::pair(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); } - // verify MACK tags - MACSEQ - OSNMA_data applicable_OSNMA = d_old_OSNMA_buffer[d_old_OSNMA_buffer.size() - 2]; // former subframe - d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. - std::vector applicable_key = d_old_OSNMA_buffer.back().d_mack_message.key; // current tesla key ie transmitted in the next subframe - std::vector sq1{}; - std::vector sq2{}; - std::vector applicable_sequence; - const auto it = OSNMA_TABLE_16.find(applicable_OSNMA.d_dsm_kroot_message.maclt); - // TODO as per RG example appears that the seq. q shall also be validated ageints either next or former Sf (depending on GST) - if (it != OSNMA_TABLE_16.cend()) - { - sq1 = it->second.sequence1; - sq2 = it->second.sequence2; - } - - // Assign relevant sequence based on subframe time - if (applicable_OSNMA.d_nav_data.TOW_sf0 % 60 < 30) // tried GST_Sf and it does not support the data present. - { - applicable_sequence = sq1; - } - else if (applicable_OSNMA.d_nav_data.TOW_sf0 % 60 >= 30) - { - applicable_sequence = sq2; - } - else - { - std::cout << "Galileo OSNMA: Mismatch in the GST verification. " << std::endl; - } - // compare ADKD of Mack tags with MACLT defined ADKDs - if(applicable_OSNMA.d_mack_message.tag_and_info.size() != applicable_sequence.size()-1) - { - std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; - return; - } - std::vector flxTags {}; - std::string tempADKD; - for (uint8_t i = 0; i < applicable_OSNMA.d_mack_message.tag_and_info.size(); i++) - { - tempADKD = applicable_sequence[i+1]; - if(tempADKD == "FLX") - { - flxTags.push_back(i); // C: just need to save the index in the sequence - } - else if(applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i+1])) - { std::cout << "Galileo OSNMA: Unsuccessful verification of MACSEQ - received ADKD against MAC Look-up table. " << std::endl; - return; // C: suffices one incorrect to abort and not process the rest of the tags - } - } - - // MACSEQ verification - - // Fixed as well as FLX Tags share first part - Eq. 22 ICD - std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes - m[0] = static_cast(applicable_OSNMA.d_nav_data.PRNa); // PRN_A - SVID of the satellite transmiting the tag - m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); - m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); - m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); - m[4] = static_cast(d_GST_Sf & 0x000000FF); - - // Case tags flexible - Eq. 21 ICD - for (uint8_t i = 0; i < flxTags.size() ; i++) - { - m[2*i + 5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; - m[2*i + 6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | - applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; - } -// m = {0x18, 0x4f, 0x93, 0x53, 0x04, 0x05, 0x0f, 0x1f, 0x0f}; -// applicable_key = {0x11, 0x26, 0x47, 0x3b, 0x0e, 0x05, 0x05, 0x35, -// 0xb0, 0xf2, 0xa7, 0x24, 0x00, 0x22, 0xba, 0x8f}; -// applicable_OSNMA.d_mack_message.header.macseq = 0xbb8; - // compute mac - std::vector mac; - if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 - { - mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); - } - else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES - { - mac = d_crypto->computeCMAC_AES(applicable_key, m); - } - // Truncate the twelve MSBits and compare with received MACSEQ - uint16_t mac_msb = 0; - if (!mac.empty()) - { - mac_msb = (mac[0] << 8) + mac[1]; - } - uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; - // Verify tags if MACSEQ is authenticated - if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq) - { // TODO this shall affect only flx tags verification - and currently all tags of a MACK are affected which is undesired - std::cout << "OSNMA: MACSEQ authenticated for PRN_A " - << osnma_msg->PRN << " with WN=" - << osnma_msg->WN_sf0 << ", TOW=" - << osnma_msg->TOW_sf0 << ". Verifying tags. " - << std::endl; - uint8_t lt_bits = 0; - const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); - if (it2 != OSNMA_TABLE_11.cend()) - { - lt_bits = it2->second; - } - if (lt_bits == 0) - { - return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. - } - - // Tag verification - // tag[i-1]: - // adkd = 4/0 : use TK[i], NavData[i-2] to validate Tag[i-1] - // adkd = 12 : ignore it -> not possible to verify yet - // tag[i-10] - // adkd = 4/0 : use TK[i-9], NavData[i-11] to validate Tag[i-10] would already be done by tag[i-1] - // adkd = 12 : use TK[i], NavData[i-11] to validate Tag[i-10] TODO - pending better logic for not repeating this while twice. - int t = d_old_OSNMA_buffer.size() - 2; - applicable_OSNMA = d_old_OSNMA_buffer[t]; // former subframe - d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ - - size_t i = 0; - while (i < applicable_OSNMA.d_mack_message.tag_and_info.size() && // loop over all tags in MACK message - std::find(d_tags_to_verify.begin(),d_tags_to_verify.end(), // ADKD[i] is within allowed ADKDs - applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD) - != d_tags_to_verify.end()) - { - // TODO - if a subsequent tag was already part of the verification (inner loop), this while is going to ignore that and try to validate it anyway. - - // Take tag_k and check its ADKD, COP, PRN_d, this will be the reference for the iteration and search of other Tags - uint8_t Nt = d_Lt_min / applicable_OSNMA.d_dsm_kroot_message.ts; // Tags needed to be verified - uint8_t applicable_ADKD = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD; - uint8_t applicable_COP = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.cop; // * d_delta_COP; - uint8_t counter_COP = 1; - uint8_t applicable_PRNd = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.PRN_d; - // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] - applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; // current subframe - NavData applicable_NavData{}; - if((applicable_ADKD == 0 || applicable_ADKD == 4) && d_old_OSNMA_buffer.size() > 3) - { - applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; - } - else if(applicable_ADKD == 12 && d_old_OSNMA_buffer.size() > 11) - { - applicable_NavData = d_old_OSNMA_buffer[t - 11].d_nav_data; - } - else - { - std::cout << "Galileo OSNMA: MACK message buffer elements not enough. Cannot verify tags. " << std::endl; - } - - - int k = i + 1; - uint8_t nt = 0; - bool flag_cancel_tag_verification = false; // if a tag fails, cancel whole NavData verification set - // Look for tags relative to reference NavData until Nt achieved, - // this may require going back in time, as long as COP is valid - while (nt <= Nt && counter_COP <= applicable_COP && !flag_cancel_tag_verification) - { - auto start_it = std::next(applicable_OSNMA.d_mack_message.tag_and_info.begin(), k); - - // check the vector of tags of aplicable OSNMA for a match against the chosen - for (auto it = start_it; it != applicable_OSNMA.d_mack_message.tag_and_info.end() && nt <= Nt; ++it) - { - // Check if ADKD, COP, and PRN_d match - if(it->tag_info.ADKD == applicable_ADKD - // && it->tag_info.cop == applicable_COP // TODO - I think this may be skipped as the relevant is the COP distance. - && it->tag_info.PRN_d == applicable_PRNd) + // MACSEQ - verify current macks, then add current retrieved mack to the end. + auto mack = d_macks_awaiting_MACSEQ_verification.begin(); + while (mack != d_macks_awaiting_MACSEQ_verification.end()){ + if(d_tesla_keys.find(mack->TOW) != d_tesla_keys.end()){ + bool ret = verify_macseq(*mack); + if (ret || d_flag_debug){ + for(auto& tag:mack->tag_and_info) { - if(verify_tag(it.operator*(), applicable_OSNMA, k,applicable_key,applicable_NavData)) - { - nt++; - } - else - { - // failure, discard this k-th tag - flag_cancel_tag_verification = true; - std::cout << "Galileo OSNMA: tag verification failed for PRN_a " - << applicable_OSNMA.d_nav_data.PRNa << " with WN=" - << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" - << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " - << std::endl; - } - + Tag t(tag, mack->TOW, mack->PRNa); + d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); } - if(flag_cancel_tag_verification) - break; + mack = d_macks_awaiting_MACSEQ_verification.erase(mack); } - // Check if Nt is achieved, if not, switch to older frame - if(nt < Nt && t > 0 /*not end of buffer*/ && counter_COP <= applicable_COP && !flag_cancel_tag_verification) - { - t--; - applicable_OSNMA = d_old_OSNMA_buffer[t]; - applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; - applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; - d_GST_Sf -= 30; - counter_COP++; - k = 0; - } - } - - if (nt >= Nt) + else { - nt = 0; - std::cout << "Galileo OSNMA: tag verification accumulation succesful for PRN_a " - << applicable_OSNMA.d_nav_data.PRNa << " with WN=" - << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" - << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " - << std::endl; + mack = d_macks_awaiting_MACSEQ_verification.erase(mack); } - } - - + else { // key not yet available - keep in container until then -- might be deleted if container size exceeds max allowed + ++mack; + } } + // add current received MACK to the container to be verified in the next iteration (on this one no key available) + d_macks_awaiting_MACSEQ_verification.push_back(d_osnma_data.d_mack_message); + + + // d_satellite_data already updated from a msg_handler coming from TD. TODO + +// d_old_OSNMA_buffer.push_back(d_osnma_data); // TODO deprecate +// if(d_keys.size() < 2) +// { +// std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " +// << "Not enough OSNMA messages available" +// << "buffer size: "<< d_old_OSNMA_buffer.size() << std::endl; +// return; +// } + + // verify tags + for (auto & it : d_tags_awaiting_verify){ + bool ret; + if(d_tesla_keys.find(it.first) != d_tesla_keys.end() && nav_data_available(it.second)){ + ret = verify_tag(it.second); + /* TODO - take into account: + * - COP: if + * - ADKD type + * - NavData the tag verifies (min. number of bits verified to consider NavData OK) + * */ + if(ret) + int a; + /* TODO notify PVT via pmt + * have_new_data() true + * signal which one is verified + * communicate to PVT*/ + else + int a; + // also + } + } + + remove_verified_tags(); + + control_tags_awaiting_verify_size(); // remove oldest tags if size is too big. + + // deprecated tag verification - it includes steps not yet present on verify_tag, so keep it until then. + // Tag verification + // tag[i-1]: + // adkd = 4/0 : use TK[i], NavData[i-2] to validate Tag[i-1] + // adkd = 12 : ignore it -> not possible to verify yet + // tag[i-10] + // adkd = 4/0 : use TK[i-9], NavData[i-11] to validate Tag[i-10] would already be done by tag[i-1] + // adkd = 12 : use TK[i], NavData[i-11] to validate Tag[i-10] TODO - pending better logic for not repeating this while twice. +// int t = d_old_OSNMA_buffer.size() - 2; +// applicable_OSNMA = d_old_OSNMA_buffer[t]; // former subframe +// d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ +// +// size_t i = 0; +// while (i < applicable_OSNMA.d_mack_message.tag_and_info.size() && // loop over all tags in MACK message +// std::find(d_tags_to_verify.begin(),d_tags_to_verify.end(), // ADKD[i] is within allowed ADKDs +// applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD) +// != d_tags_to_verify.end()) +// { +// // TODO - if a subsequent tag was already part of the verification (inner loop), this while is going to ignore that and try to validate it anyway. +// +// // check if tag is flx +// bool is_flexible_tag = std::find(flxTags.begin(),flxTags.end(), i) != flxTags.end(); +// if(is_flexible_tag && flxTagsV == false){ +// //std::cout << "Galileo OSNMA: cannot verify flx tag. " << std::endl; +// continue; +// } +// +// +// // Take tag_k and check its ADKD, COP, PRN_d, this will be the reference for the iteration and search of other Tags +// uint8_t Nt = d_Lt_min / applicable_OSNMA.d_dsm_kroot_message.ts; // Tags needed to be verified +// uint8_t applicable_ADKD = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD; +// uint8_t applicable_COP = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.cop; // * d_delta_COP; +// uint8_t counter_COP = 1; +// uint8_t applicable_PRNd = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.PRN_d; +// // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] +// applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; // current subframe +// NavData applicable_NavData{}; +// if((applicable_ADKD == 0 || applicable_ADKD == 4) && d_old_OSNMA_buffer.size() > 3) +// { +// applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; +// } +// else if(applicable_ADKD == 12 && d_old_OSNMA_buffer.size() > 11) +// { +// applicable_NavData = d_old_OSNMA_buffer[t - 11].d_nav_data; +// } +// else +// { +// std::cout << "Galileo OSNMA: MACK message buffer elements not enough. Cannot verify tags. " << std::endl; +// } +// +// +// int k = i + 1; +// uint8_t nt = 0; +// bool flag_cancel_tag_verification = false; // if a tag fails, cancel whole NavData verification set +// // Look for tags relative to reference NavData until Nt achieved, +// // this may require going back in time, as long as COP is valid +// while (nt <= Nt && counter_COP <= applicable_COP && !flag_cancel_tag_verification) +// { +// auto start_it = std::next(applicable_OSNMA.d_mack_message.tag_and_info.begin(), k); +// +// // check the vector of tags of aplicable OSNMA for a match against the chosen +// for (auto it = start_it; it != applicable_OSNMA.d_mack_message.tag_and_info.end() && nt <= Nt; ++it) +// { +// // Check if ADKD, COP, and PRN_d match +// if(it->tag_info.ADKD == applicable_ADKD +// // && it->tag_info.cop == applicable_COP // TODO - I think this may be skipped as the relevant is the COP distance. +// && it->tag_info.PRN_d == applicable_PRNd) +// { +// if(verify_tag(it.operator*(), applicable_OSNMA, k,applicable_key,applicable_NavData)) +// { +// nt++; +// } +// else +// { +// // failure, discard this k-th tag +// flag_cancel_tag_verification = true; +// std::cout << "Galileo OSNMA: tag verification failed for PRN_a " +// << applicable_OSNMA.d_nav_data.PRNa << " with WN=" +// << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" +// << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " +// << std::endl; +// } +// +// } +// if(flag_cancel_tag_verification) +// break; +// } +// // Check if Nt is achieved, if not, switch to older frame +// if(nt < Nt && t > 0 /*not end of buffer*/ && counter_COP <= applicable_COP && !flag_cancel_tag_verification) +// { +// t--; +// applicable_OSNMA = d_old_OSNMA_buffer[t]; +// applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; +// applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; +// d_GST_Sf -= 30; +// counter_COP++; +// k = 0; +// } +// } +// +// if (nt >= Nt) +// { +// nt = 0; +// std::cout << "Galileo OSNMA: tag verification accumulation succesful for PRN_a " +// << applicable_OSNMA.d_nav_data.PRNa << " with WN=" +// << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" +// << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " +// << std::endl; +// } +// +// } + } bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) @@ -1348,6 +1223,91 @@ bool osnma_msg_receiver::verify_tag(MACK_tag_and_info tag_and_info, } return verified; } +bool osnma_msg_receiver::verify_tag(Tag& tag) +{ + std::vector m = tag.build_message(); + + std::vector mac; + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + { + mac = d_crypto->computeHMAC_SHA_256(d_tesla_keys[tag.TOW], m); + } + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + { + mac = d_crypto->computeCMAC_AES(d_tesla_keys[tag.TOW], m); + } + + // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD + uint8_t lt_bits = 0; // TODO - remove this duplication of code. + const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); + if (it2 != OSNMA_TABLE_11.cend()) + { + lt_bits = it2->second; + } + if (lt_bits == 0) + { + return false; + } + uint64_t computed_mac = static_cast(mac[0]) << (lt_bits - 8); + computed_mac += (static_cast(mac[1]) << (lt_bits - 16)); + if (lt_bits == 20) + { + computed_mac += (static_cast(mac[1] & 0xF0) >> 4); + } + else if (lt_bits == 24) + { + computed_mac += static_cast(mac[2]); + } + else if (lt_bits == 28) + { + computed_mac += (static_cast(mac[2]) << 4); + computed_mac += (static_cast(mac[3] & 0xF0) >> 4); + } + else if (lt_bits == 32) + { + computed_mac += (static_cast(mac[2]) << 8); + computed_mac += static_cast(mac[3]); + } + else if (lt_bits == 40) + { + computed_mac += (static_cast(mac[2]) << 16); + computed_mac += (static_cast(mac[3]) << 8); + computed_mac += static_cast(mac[4]); + } + + // Compare computed tag with received one truncated + if (tag.received_tag == computed_mac) + { + if(tag.ADKD == 0 || tag.ADKD == 12) + { + std::cout << "Galileo OSNMA: tag verification successful for PRN_a " + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " + << "Ephemeris, Clock and Ionospheric data" << ". " + << std::endl; + } + else if(tag.ADKD == 4) + { + std::cout << "Galileo OSNMA: tag verification successful for PRN_a " + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " + << "Timing data" << ". " + << std::endl; + } + return true; + + } + else + { + std::cout << "Galileo OSNMA: Tag verification failed for PRN_a " + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" + << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << std::endl; + return false; + } +} /** * @brief Checks if the current subframe time is bigger than last one received. * @@ -1367,3 +1327,268 @@ bool osnma_msg_receiver::is_next_subframe() return is_bigger; } +void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) +{ + while (d_satellite_data[SV_ID].size() >= 25) { + d_satellite_data[SV_ID].erase(d_satellite_data[SV_ID].begin()); + } + d_osnma_data[TOW] = crypto; // crypto + d_satellite_data[SV_ID][TOW] = data; // nav + std::cout << "Galileo OSNMA: added element, size is " << d_satellite_data[SV_ID].size() << std::endl; +} +void osnma_msg_receiver::display_data() +{ + if(d_satellite_data.empty()) + return; + + for(const auto& satellite : d_satellite_data) { + std::cout << "SV_ID: " << satellite.first << std::endl; + for(const auto& towData : satellite.second) { + std::cout << "\tTOW: " << towData.first << " key: "; + for(size_t i = 0; i < towData.second.d_mack_message.key.size(); i++) { + std::cout << std::hex << std::setfill('0') << std::setw(2) + << static_cast(towData.second.d_mack_message.key[i]) << " "; + } + } + } +} +bool osnma_msg_receiver::verify_tesla_key(std::vector& key) +{ + if(d_tesla_key_verified || d_flag_debug) + { + // TODO - find out I bt. both tesla keys, then hash until then, then compare. + // retrieve latest tesla key + // compute hashes needed + // hash current key until num_hashes and compare + } + else + {// have to go until Kroot + uint32_t num_of_hashes_needed = (d_GST_SIS - d_GST_0) / 30 + 1; // Eq. 19 ICD + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; + auto start = std::chrono::high_resolution_clock::now(); + uint32_t GST_SFi = d_GST_SIS; + std::vector K_II = applicable_MACK.key; + std::vector K_I; // result of the recursive hash operations + const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; + // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) + for (uint32_t i = 1; i < num_of_hashes_needed ; i++) + { + // build message digest m = (K_I+1 || GST_SFi || alpha) + std::vector msg(K_II.size() + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); + std::copy(K_II.begin(),K_II.end(),msg.begin()); + + msg.push_back((d_GST_Sf & 0xFF000000) >> 24); + msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); + msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); + msg.push_back(d_GST_Sf & 0x000000FF); + // extract alpha + for (int k = 5; k >= 0;k--) + { + // TODO: static extracts the MSB in case from larger to shorter int? + msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. + } + // compute hash + std::vector hash; + if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. + { + hash = d_crypto->computeSHA256(msg); + } + else if (d_osnma_data.d_dsm_kroot_message.hf == 2) + { + hash = d_crypto->computeSHA3_256(msg); + } + else + { + hash = std::vector(32); + } + // truncate hash + K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits + for (uint16_t i = 0; i < lk_bytes; i++) + { + K_I.push_back(hash[i]); + } + + // set parameters for next iteration + GST_SFi -= 30; // next SF time is the actual minus 30 seconds + K_II = K_I; // next key is the actual one + K_I.clear(); // empty the actual one for a new computation + } + // compare computed current key against received key + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; + + if(K_II.size() != applicable_MACK.key.size()) + { + std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + return; + } + if (K_II == applicable_MACK.key) + { + std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; + d_keys.insert(std::pair(applicable_MACK.TOW,applicable_MACK.key)); + d_tesla_key_verified = true; + // TODO - propagate result + // TODO - save current tesla key as latest one? propose a map with + // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence + } + else + + { + std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + if(!d_flag_debug) + return; + } + } + +} +/** + * @brief Removes the tags that have been verified from the multimap d_tags_awaiting_verify. + * + * This function iterates through the multimap d_tags_awaiting_verify, and removes the tags that have a status of SUCCESS or FAIL. + */ +void osnma_msg_receiver::remove_verified_tags() +{ + for (auto it = d_tags_awaiting_verify.begin(); it != d_tags_awaiting_verify.end() ; ){ + if (it->second.status == Tag::SUCCESS || it->second.status == Tag::FAIL) + it = d_tags_awaiting_verify.erase(it); + else + ++it; + } +} +/** + * @brief Control the size of the tags awaiting verification multimap. + * + * This function checks the size of the multimap `d_tags_awaiting_verify` and removes + * elements from the beginning until the size is no longer greater than 60. + * The purpose is to limit the size of the multimap and prevent it from consuming + * excessive memory. + */ +void osnma_msg_receiver::control_tags_awaiting_verify_size() +{ + while(d_tags_awaiting_verify.size() > 60) + { + d_tags_awaiting_verify.erase(d_tags_awaiting_verify.begin()); + } +} + +/** + * @brief Verifies the MACSEQ of a received MACK_message. + * + * \details checks for each tag in the retrieved mack message if its flexible (MACSEQ) or not (MACSEQ/MACLT depending on configuration param. (TODO) + * @param message The MACK_message to verify. + * @return True if the MACSEQ is valid, false otherwise. + */ +bool osnma_msg_receiver::verify_macseq(MACK_message& message) +{ + // MACSEQ verification + + // verify MACK tags - MACSEQ + OSNMA_data applicable_OSNMA = d_old_OSNMA_buffer[d_old_OSNMA_buffer.size() - 2]; // former subframe + + //d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. + std::vector applicable_key = d_old_OSNMA_buffer.back().d_mack_message.key; // current tesla key ie transmitted in the next subframe + std::vector sq1{}; + std::vector sq2{}; + std::vector applicable_sequence; + const auto it = OSNMA_TABLE_16.find(applicable_OSNMA.d_dsm_kroot_message.maclt); + // TODO as per RG example appears that the seq. q shall also be validated ageints either next or former Sf (depending on GST) + if (it != OSNMA_TABLE_16.cend()) + { + sq1 = it->second.sequence1; + sq2 = it->second.sequence2; + } + + // Assign relevant sequence based on subframe time + if (applicable_OSNMA.d_nav_data.TOW_sf0 % 60 < 30) // tried GST_Sf and it does not support the data present. + { + applicable_sequence = sq1; + } + else if (applicable_OSNMA.d_nav_data.TOW_sf0 % 60 >= 30) + { + applicable_sequence = sq2; + } + else + { + std::cout << "Galileo OSNMA: Mismatch in the GST verification. " << std::endl; + } + if(applicable_OSNMA.d_mack_message.tag_and_info.size() != applicable_sequence.size()-1) + { + std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; + return; + } + std::vector flxTags {}; + std::string tempADKD; + // MACLT verification + for (uint8_t i = 0; i < applicable_OSNMA.d_mack_message.tag_and_info.size(); i++) + { + tempADKD = applicable_sequence[i+1]; + if(tempADKD == "FLX") + { + flxTags.push_back(i); // C: just need to save the index in the sequence + } + else if(applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i+1])) + { std::cout << "Galileo OSNMA: Unsuccessful verification of MACSEQ - received ADKD against MAC Look-up table. " << std::endl; + return; // C: suffices one incorrect to abort and not process the rest of the tags + } + } + + // Fixed as well as FLX Tags share first part - Eq. 22 ICD + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + m[0] = static_cast(applicable_OSNMA.d_nav_data.PRNa); // PRN_A - SVID of the satellite transmiting the tag + m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); + m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); + m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); + m[4] = static_cast(d_GST_Sf & 0x000000FF); + // Case tags flexible - Eq. 21 ICD + for (uint8_t i = 0; i < flxTags.size() ; i++) + { + m[2*i + 5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; + m[2*i + 6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | + applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; + } + // m = {0x18, 0x4f, 0x93, 0x53, 0x04, 0x05, 0x0f, 0x1f, 0x0f}; + // applicable_key = {0x11, 0x26, 0x47, 0x3b, 0x0e, 0x05, 0x05, 0x35, + // 0xb0, 0xf2, 0xa7, 0x24, 0x00, 0x22, 0xba, 0x8f}; + // applicable_OSNMA.d_mack_message.header.macseq = 0xbb8; + // compute mac + std::vector mac; + if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + { + mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + } + else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + { + mac = d_crypto->computeCMAC_AES(applicable_key, m); + } + // Truncate the twelve MSBits and compare with received MACSEQ + uint16_t mac_msb = 0; + if (!mac.empty()) + { + mac_msb = (mac[0] << 8) + mac[1]; + } + uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; + if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq && !flxTags.empty()) + return true; + else + return false; +} +bool osnma_msg_receiver::nav_data_available(Tag t) +{ + auto prn_it = d_satellite_nav_data.find(t.PRNa); + if (prn_it != d_satellite_nav_data.end()) { + // PRN was found, check if TOW exists in inner map + std::map& tow_map = prn_it->second; + auto tow_it = tow_map.find(t.TOW); + if (tow_it != tow_map.end()) { + return true; + } else { + // TOW not found + return false; + } + } else { + // PRN was not found + return false; + } + return false; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index b6a7bb812..9fde2d386 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -72,14 +72,23 @@ private: void read_mack_header(); void read_mack_body(); void process_mack_message(const std::shared_ptr& osnma_msg); + void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData &data); + bool verify_tesla_key(std::vector& key); + void const display_data(); bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); + bool verify_tag(Tag& tag); + bool is_next_subframe(); + bool nav_data_available(Tag& t); - //boost::circular_buffer d_old_mack_message; + std::map> d_satellite_nav_data; // map holding NavData sorted by SVID and TOW. boost::circular_buffer d_old_OSNMA_buffer; // buffer that holds last 12 received OSNMA messages, including current one at back() + std::map> d_tesla_keys; // tesla keys over time, sorted by TOW + std::vector d_macks_awaiting_MACSEQ_verification; + std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; - std::array, 16> d_dsm_message{}; // C: each dsm[0-15] has 2048 bits + std::array, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself. std::array, 16> d_dsm_id_received{}; std::array d_number_of_blocks{}; std::array d_mack_message{}; // C: 480 b @@ -103,7 +112,9 @@ private: enum tags_to_verify{all,utc,slow_eph, eph, none}; // TODO is this safe? I hope so tags_to_verify d_tags_allowed{tags_to_verify::all}; std::vector d_tags_to_verify{0,4,12}; - bool is_next_subframe(); + void remove_verified_tags(); + void control_tags_awaiting_verify_size(); + bool verify_macseq(MACK_message& message); }; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 9a291330d..cb76b9107 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -163,3 +163,9 @@ void NavData::generate_utc_vector() utc_vector.push_back(static_cast(bit_buffer)); } } + +std::vector Tag::build_message() +{ + // TODO + return std::vector(); +} diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 4bc78ebbb..c9598e396 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -121,6 +121,8 @@ public: MACK_header header; std::vector tag_and_info; std::vector key; + uint32_t TOW; // TODO duplicated variable + uint32_t PRNa; }; class NavData @@ -157,9 +159,44 @@ public: DSM_KROOT_message d_dsm_kroot_message; MACK_message d_mack_message; NavData d_nav_data; + }; +class Tag +{ +public: + enum e_verification_status{ + SUCCESS, + FAIL, + UNVERIFIED}; + Tag(const MACK_tag_and_info& MTI, uint32_t TOW, uint32_t PRNa) + : tag_id(id_counter++), + TOW(TOW), + PRNa(PRNa), + status(UNVERIFIED), + received_tag(MTI.tag), + computed_tag(0), + PRN_d(MTI.tag_info.PRN_d), + ADKD(MTI.tag_info.ADKD), + cop(MTI.tag_info.cop) + { + } + + const uint32_t tag_id; + uint32_t TOW; + uint32_t PRNa; + e_verification_status status; + uint64_t received_tag; + std::vector build_message(); + + uint32_t static id_counter; + uint64_t computed_tag; + + uint8_t PRN_d; + uint8_t ADKD; + uint8_t cop; +}; /** \} */ /** \} */ #endif // GNSS_SDR_OSNMA_DATA_H From 8fa1a86f242a800b2578b08f601fc4cb867b6395 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 2 Apr 2024 18:04:19 +0200 Subject: [PATCH 097/219] Refactor tag verification logic - solve build errors --- src/core/libs/osnma_msg_receiver.cc | 116 +++++++++++++---------- src/core/libs/osnma_msg_receiver.h | 8 +- src/core/system_parameters/osnma_data.cc | 2 + 3 files changed, 72 insertions(+), 54 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 21321e685..a62f03dd6 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -259,10 +259,10 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ void osnma_msg_receiver::local_time_verification(const std::shared_ptr& osnma_msg) { // compute local time based on GST_SIS and GST_0 - d_GST_SIS = (osnma_msg->WN_sf0 & 0x00000FFF) << 20 | osnma_msg->TOW_sf0 & 0x000FFFFF; + d_GST_SIS = (osnma_msg->WN_sf0 & 0x00000FFF) << 20 | (osnma_msg->TOW_sf0 & 0x000FFFFF); //std::cout << "Galileo OSNMA: d_GST_SIS: " << d_GST_SIS << std::endl; //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; - d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | d_osnma_data.d_dsm_kroot_message.towh_k & 0x000FFFFF) + 30; + d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k & 0x000FFFFF)) + 30; //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; // TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID. if(d_receiver_time != 0) @@ -568,7 +568,7 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr& osnma_msg) +void osnma_msg_receiver::process_mack_message() { d_flag_debug = true; @@ -846,7 +846,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& return; // early return, cannot proceed further without one of the two verified. } // verify tesla key and add it to the container of verified keys if successful - bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key); + bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key, d_osnma_data.d_mack_message.TOW); if(retV){ d_tesla_keys.insert(std::pair(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); } @@ -855,7 +855,7 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& auto mack = d_macks_awaiting_MACSEQ_verification.begin(); while (mack != d_macks_awaiting_MACSEQ_verification.end()){ if(d_tesla_keys.find(mack->TOW) != d_tesla_keys.end()){ - bool ret = verify_macseq(*mack); + bool ret = verify_macseq(); if (ret || d_flag_debug){ for(auto& tag:mack->tag_and_info) { @@ -899,14 +899,27 @@ void osnma_msg_receiver::process_mack_message(const std::shared_ptr& * - NavData the tag verifies (min. number of bits verified to consider NavData OK) * */ if(ret) - int a; + std::cout << "Galileo OSNMA: Tag verification failure at " + << "TOW=" + << it.second.TOW + << ", ADKD=" + << it.second.ADKD + << ", from satellite " + << it.second.PRN_d + << std::endl; /* TODO notify PVT via pmt * have_new_data() true * signal which one is verified * communicate to PVT*/ else - int a; - // also + std::cout << "Galileo OSNMA: Tag verification failure at " + << "TOW=" + << it.second.TOW + << ", ADKD=" + << it.second.ADKD + << ", from satellite " + << it.second.PRN_d + << std::endl; } } @@ -1316,43 +1329,44 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) * @param sharedPtr A shared pointer to an instance of OSNMA_msg. * @return True if the current subframe is the next subframe, False otherwise. */ -bool osnma_msg_receiver::is_next_subframe() -{ - bool is_bigger = d_GST_SIS > d_old_GST_SIS; - if(d_GST_SIS != d_old_GST_SIS + 30 && d_old_GST_SIS != 0){ - std::cout << "Galileo OSNMA:: Mack processing - skip " << std::endl; - } - - d_old_GST_SIS = d_GST_SIS; - - return is_bigger; -} +//bool osnma_msg_receiver::is_next_subframe() +//{ +// bool is_bigger = d_GST_SIS > d_old_GST_SIS; +// if(d_GST_SIS != d_old_GST_SIS + 30 && d_old_GST_SIS != 0){ +// std::cout << "Galileo OSNMA:: Mack processing - skip " << std::endl; +// } +// +// d_old_GST_SIS = d_GST_SIS; +// +// return is_bigger; +//} void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) { - while (d_satellite_data[SV_ID].size() >= 25) { - d_satellite_data[SV_ID].erase(d_satellite_data[SV_ID].begin()); + // control size of container + while (d_satellite_nav_data[SV_ID].size() >= 25) { + d_satellite_nav_data[SV_ID].erase(d_satellite_nav_data[SV_ID].begin()); } - d_osnma_data[TOW] = crypto; // crypto - d_satellite_data[SV_ID][TOW] = data; // nav - std::cout << "Galileo OSNMA: added element, size is " << d_satellite_data[SV_ID].size() << std::endl; + //d_osnma_data[TOW] = crypto; // crypto + d_satellite_nav_data[SV_ID][TOW] = data; // nav + std::cout << "Galileo OSNMA: added element, size is " << d_satellite_nav_data[SV_ID].size() << std::endl; } void osnma_msg_receiver::display_data() { - if(d_satellite_data.empty()) - return; - - for(const auto& satellite : d_satellite_data) { - std::cout << "SV_ID: " << satellite.first << std::endl; - for(const auto& towData : satellite.second) { - std::cout << "\tTOW: " << towData.first << " key: "; - for(size_t i = 0; i < towData.second.d_mack_message.key.size(); i++) { - std::cout << std::hex << std::setfill('0') << std::setw(2) - << static_cast(towData.second.d_mack_message.key[i]) << " "; - } - } - } +// if(d_satellite_nav_data.empty()) +// return; +// +// for(const auto& satellite : d_satellite_nav_data) { +// std::cout << "SV_ID: " << satellite.first << std::endl; +// for(const auto& towData : satellite.second) { +// std::cout << "\tTOW: " << towData.first << " key: "; +// for(size_t i = 0; i < towData.second.d_mack_message.key.size(); i++) { +// std::cout << std::hex << std::setfill('0') << std::setw(2) +// << static_cast(towData.second.d_mack_message.key[i]) << " "; +// } +// } +// } } -bool osnma_msg_receiver::verify_tesla_key(std::vector& key) +bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TOW) { if(d_tesla_key_verified || d_flag_debug) { @@ -1360,6 +1374,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key) // retrieve latest tesla key // compute hashes needed // hash current key until num_hashes and compare + return false; } else {// have to go until Kroot @@ -1367,7 +1382,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key) std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; auto start = std::chrono::high_resolution_clock::now(); uint32_t GST_SFi = d_GST_SIS; - std::vector K_II = applicable_MACK.key; + std::vector K_II = key; std::vector K_I; // result of the recursive hash operations const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) @@ -1418,15 +1433,15 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key) std::chrono::duration elapsed = end - start; std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; - if(K_II.size() != applicable_MACK.key.size()) + if(K_II.size() != key.size()) { std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - return; + return false; } - if (K_II == applicable_MACK.key) + if (K_II == key) { std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; - d_keys.insert(std::pair(applicable_MACK.TOW,applicable_MACK.key)); + d_tesla_keys.insert(std::pair(TOW,key)); d_tesla_key_verified = true; // TODO - propagate result // TODO - save current tesla key as latest one? propose a map with @@ -1436,9 +1451,10 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key) { std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - if(!d_flag_debug) - return; + if(d_flag_debug) + d_tesla_key_verified = true; } + return d_tesla_key_verified; } } @@ -1479,7 +1495,7 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() * @param message The MACK_message to verify. * @return True if the MACSEQ is valid, false otherwise. */ -bool osnma_msg_receiver::verify_macseq(MACK_message& message) +bool osnma_msg_receiver::verify_macseq() { // MACSEQ verification @@ -1515,7 +1531,7 @@ bool osnma_msg_receiver::verify_macseq(MACK_message& message) if(applicable_OSNMA.d_mack_message.tag_and_info.size() != applicable_sequence.size()-1) { std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; - return; + return false; } std::vector flxTags {}; std::string tempADKD; @@ -1529,7 +1545,7 @@ bool osnma_msg_receiver::verify_macseq(MACK_message& message) } else if(applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i+1])) { std::cout << "Galileo OSNMA: Unsuccessful verification of MACSEQ - received ADKD against MAC Look-up table. " << std::endl; - return; // C: suffices one incorrect to abort and not process the rest of the tags + return false; // C: suffices one incorrect to abort and not process the rest of the tags } } @@ -1573,7 +1589,7 @@ bool osnma_msg_receiver::verify_macseq(MACK_message& message) else return false; } -bool osnma_msg_receiver::nav_data_available(Tag t) +bool osnma_msg_receiver::nav_data_available(Tag& t) { auto prn_it = d_satellite_nav_data.find(t.PRNa); if (prn_it != d_satellite_nav_data.end()) { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 9fde2d386..7915d408e 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -71,10 +71,10 @@ private: void read_and_process_mack_block(const std::shared_ptr& osnma_msg); void read_mack_header(); void read_mack_body(); - void process_mack_message(const std::shared_ptr& osnma_msg); + void process_mack_message(); void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData &data); - bool verify_tesla_key(std::vector& key); - void const display_data(); + bool verify_tesla_key(std::vector& key, uint32_t TOW); + void display_data(); bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); bool verify_tag(Tag& tag); bool is_next_subframe(); @@ -114,7 +114,7 @@ private: std::vector d_tags_to_verify{0,4,12}; void remove_verified_tags(); void control_tags_awaiting_verify_size(); - bool verify_macseq(MACK_message& message); + bool verify_macseq(); }; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index cb76b9107..65145ae16 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -23,6 +23,8 @@ * \details Packs the ephemeris, iono and utc data from the current subframe into the NavData structure. It also gets the PRNa and the GST. * @param osnma_msg The shared pointer to the OSNMA_msg object. */ + +uint32_t Tag::id_counter = 0; void NavData::init(const std::shared_ptr &osnma_msg) { EphemerisData = osnma_msg->EphemerisData; From a17b04cb22d10d9ec10986de55aa374c7e367226 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sun, 7 Apr 2024 14:27:14 +0200 Subject: [PATCH 098/219] [TAS-159 ] d_tesla_key_verified => do not hash until Kroot(every time) - improve efficiency of verify_tesla_key by computing only the needed hashes until chronologically closest key, instead of going back to Kroot. Aditional chanches are: * rename unused variable d_old_GST_SISto d_last_verified_key_GST and use it for tesla key verification * fix bug on verify_tesla_key during the comparison of computed and received key * deleted d_old_OSNMA_buffer * fill PRNa and TOW for MACK message when parsing it * fix parameter bug for verify_macseq() * immplement tag_has_key_available * delete old verify_tag implementation --- src/core/libs/osnma_msg_receiver.cc | 571 ++++++++++------------------ src/core/libs/osnma_msg_receiver.h | 11 +- 2 files changed, 211 insertions(+), 371 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index a62f03dd6..f5e084ffe 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -60,8 +60,6 @@ osnma_msg_receiver::osnma_msg_receiver( { d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(pemFilePath, merkleFilePath); - //d_old_mack_message.set_capacity(10); - d_old_OSNMA_buffer.set_capacity(25); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -541,7 +539,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } - /** * @brief Reads the Mack message from the given OSNMA_msg object. * @@ -574,7 +571,6 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrTOW) != d_tesla_keys.end()){ - bool ret = verify_macseq(); + if(d_tesla_keys.find(mack->TOW + 30) != d_tesla_keys.end()){ + bool ret = verify_macseq(*mack); if (ret || d_flag_debug){ for(auto& tag:mack->tag_and_info) { @@ -877,21 +875,10 @@ void osnma_msg_receiver::process_mack_message() d_macks_awaiting_MACSEQ_verification.push_back(d_osnma_data.d_mack_message); - // d_satellite_data already updated from a msg_handler coming from TD. TODO - -// d_old_OSNMA_buffer.push_back(d_osnma_data); // TODO deprecate -// if(d_keys.size() < 2) -// { -// std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " -// << "Not enough OSNMA messages available" -// << "buffer size: "<< d_old_OSNMA_buffer.size() << std::endl; -// return; -// } - - // verify tags + // Tag verification for (auto & it : d_tags_awaiting_verify){ bool ret; - if(d_tesla_keys.find(it.first) != d_tesla_keys.end() && nav_data_available(it.second)){ + if(tag_has_key_available(it.second) && tag_has_nav_data_available(it.second)){ ret = verify_tag(it.second); /* TODO - take into account: * - COP: if @@ -899,146 +886,52 @@ void osnma_msg_receiver::process_mack_message() * - NavData the tag verifies (min. number of bits verified to consider NavData OK) * */ if(ret) - std::cout << "Galileo OSNMA: Tag verification failure at " - << "TOW=" - << it.second.TOW - << ", ADKD=" - << it.second.ADKD - << ", from satellite " - << it.second.PRN_d - << std::endl; + { + it.second.status = Tag::SUCCESS; + std::cout << "Galileo OSNMA: Tag verification failure for tag Id= " + << it.second.tag_id + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", from satellite " + << it.second.PRNa + << std::endl; + } /* TODO notify PVT via pmt * have_new_data() true * signal which one is verified * communicate to PVT*/ else - std::cout << "Galileo OSNMA: Tag verification failure at " - << "TOW=" + { + it.second.status = Tag::FAIL; + std::cout << "Galileo OSNMA: Tag verification failure for tag Id= " + << it.second.tag_id + << ", TOW=" << it.second.TOW << ", ADKD=" - << it.second.ADKD + << static_cast(it.second.ADKD) << ", from satellite " - << it.second.PRN_d + << it.second.PRNa << std::endl; + } + } + else { + std::cout << "Galileo OSNMA: Tag verification skipped for Tag Id= " + << it.second.tag_id + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", from satellite " + << it.second.PRNa + << std::endl; } } remove_verified_tags(); - control_tags_awaiting_verify_size(); // remove oldest tags if size is too big. - - // deprecated tag verification - it includes steps not yet present on verify_tag, so keep it until then. - // Tag verification - // tag[i-1]: - // adkd = 4/0 : use TK[i], NavData[i-2] to validate Tag[i-1] - // adkd = 12 : ignore it -> not possible to verify yet - // tag[i-10] - // adkd = 4/0 : use TK[i-9], NavData[i-11] to validate Tag[i-10] would already be done by tag[i-1] - // adkd = 12 : use TK[i], NavData[i-11] to validate Tag[i-10] TODO - pending better logic for not repeating this while twice. -// int t = d_old_OSNMA_buffer.size() - 2; -// applicable_OSNMA = d_old_OSNMA_buffer[t]; // former subframe -// d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ -// -// size_t i = 0; -// while (i < applicable_OSNMA.d_mack_message.tag_and_info.size() && // loop over all tags in MACK message -// std::find(d_tags_to_verify.begin(),d_tags_to_verify.end(), // ADKD[i] is within allowed ADKDs -// applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD) -// != d_tags_to_verify.end()) -// { -// // TODO - if a subsequent tag was already part of the verification (inner loop), this while is going to ignore that and try to validate it anyway. -// -// // check if tag is flx -// bool is_flexible_tag = std::find(flxTags.begin(),flxTags.end(), i) != flxTags.end(); -// if(is_flexible_tag && flxTagsV == false){ -// //std::cout << "Galileo OSNMA: cannot verify flx tag. " << std::endl; -// continue; -// } -// -// -// // Take tag_k and check its ADKD, COP, PRN_d, this will be the reference for the iteration and search of other Tags -// uint8_t Nt = d_Lt_min / applicable_OSNMA.d_dsm_kroot_message.ts; // Tags needed to be verified -// uint8_t applicable_ADKD = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD; -// uint8_t applicable_COP = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.cop; // * d_delta_COP; -// uint8_t counter_COP = 1; -// uint8_t applicable_PRNd = applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.PRN_d; -// // ADKD=12 or ADKD = 4/0 => pick d_old_OSNMA_buffer.back() or [size-1] -// applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; // current subframe -// NavData applicable_NavData{}; -// if((applicable_ADKD == 0 || applicable_ADKD == 4) && d_old_OSNMA_buffer.size() > 3) -// { -// applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; -// } -// else if(applicable_ADKD == 12 && d_old_OSNMA_buffer.size() > 11) -// { -// applicable_NavData = d_old_OSNMA_buffer[t - 11].d_nav_data; -// } -// else -// { -// std::cout << "Galileo OSNMA: MACK message buffer elements not enough. Cannot verify tags. " << std::endl; -// } -// -// -// int k = i + 1; -// uint8_t nt = 0; -// bool flag_cancel_tag_verification = false; // if a tag fails, cancel whole NavData verification set -// // Look for tags relative to reference NavData until Nt achieved, -// // this may require going back in time, as long as COP is valid -// while (nt <= Nt && counter_COP <= applicable_COP && !flag_cancel_tag_verification) -// { -// auto start_it = std::next(applicable_OSNMA.d_mack_message.tag_and_info.begin(), k); -// -// // check the vector of tags of aplicable OSNMA for a match against the chosen -// for (auto it = start_it; it != applicable_OSNMA.d_mack_message.tag_and_info.end() && nt <= Nt; ++it) -// { -// // Check if ADKD, COP, and PRN_d match -// if(it->tag_info.ADKD == applicable_ADKD -// // && it->tag_info.cop == applicable_COP // TODO - I think this may be skipped as the relevant is the COP distance. -// && it->tag_info.PRN_d == applicable_PRNd) -// { -// if(verify_tag(it.operator*(), applicable_OSNMA, k,applicable_key,applicable_NavData)) -// { -// nt++; -// } -// else -// { -// // failure, discard this k-th tag -// flag_cancel_tag_verification = true; -// std::cout << "Galileo OSNMA: tag verification failed for PRN_a " -// << applicable_OSNMA.d_nav_data.PRNa << " with WN=" -// << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" -// << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " -// << std::endl; -// } -// -// } -// if(flag_cancel_tag_verification) -// break; -// } -// // Check if Nt is achieved, if not, switch to older frame -// if(nt < Nt && t > 0 /*not end of buffer*/ && counter_COP <= applicable_COP && !flag_cancel_tag_verification) -// { -// t--; -// applicable_OSNMA = d_old_OSNMA_buffer[t]; -// applicable_key = d_old_OSNMA_buffer[t+1].d_mack_message.key; -// applicable_NavData = d_old_OSNMA_buffer[t-1].d_nav_data; -// d_GST_Sf -= 30; -// counter_COP++; -// k = 0; -// } -// } -// -// if (nt >= Nt) -// { -// nt = 0; -// std::cout << "Galileo OSNMA: tag verification accumulation succesful for PRN_a " -// << applicable_OSNMA.d_nav_data.PRNa << " with WN=" -// << applicable_OSNMA.d_nav_data.WN_sf0 << ", TOW=" -// << applicable_OSNMA.d_nav_data.TOW_sf0 << ". " -// << std::endl; -// } -// -// } - + control_tags_awaiting_verify_size(); // remove the oldest tags if size is too big. } bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) @@ -1085,157 +978,6 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) return false; } } -bool osnma_msg_receiver::verify_tag(MACK_tag_and_info tag_and_info, - OSNMA_data applicable_OSNMA, uint8_t tag_position, - const std::vector& applicable_key, - NavData applicable_NavData) -{ - bool verified = false; - auto CTR = tag_position + 2; // CTR, first tag is CTR(tag0)=1 + 1 == 2 - // NAvData, tag_and_info[i] - - // check if enough osnma messages stored in the buffer. - if (tag_and_info.tag_info.ADKD == 0 - || tag_and_info.tag_info.ADKD == 4) - { - if (d_old_OSNMA_buffer.size() < 3) - { - std::cout << "Galileo OSNMA: MACK message buffer empty. Cannot verify tags. " << std::endl; - return verified; - } - } - else if (tag_and_info.tag_info.ADKD == 12) - { - - if (d_old_OSNMA_buffer.size() < 10+15) - { - std::cout << "Galileo OSNMA: Tesla key not yet available. Cannot verify slow mac. at " << - d_receiver_time << "s. "<< std::endl; - return verified; - } - } - else - { - std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; - return verified; - } - - // compute m - std::vector m; - m.push_back(tag_and_info.tag_info.PRN_d); - for(int i = 24; i >= 0; i -= 8) - { - m.push_back((applicable_NavData.PRNa >> i) & 0xFF); - } - m.push_back(static_cast((d_GST_Sf & 0xFF000000) >> 24)); - m.push_back(static_cast((d_GST_Sf & 0x00FF0000) >> 16)); - m.push_back(static_cast((d_GST_Sf & 0x0000FF00) >> 8)); - m.push_back(static_cast(d_GST_Sf & 0x000000FF)); - m.push_back(CTR); - m.push_back(applicable_OSNMA.d_nma_header.nmas); - if(tag_and_info.tag_info.ADKD == 0) - { - m.insert(m.end(), - applicable_NavData.ephemeris_iono_vector.begin(), - applicable_NavData.ephemeris_iono_vector.end()) ; - } - else if(tag_and_info.tag_info.ADKD == 4) - { - m.insert(m.end(),applicable_NavData.utc_vector.begin(),applicable_NavData.utc_vector.end()) ; - } - else - { - std::cout << "Galileo OSNMA: Unknown ADKD. " << std::endl; - } - - // check that m has an integer number of bytes, if not, add padding zeroes - // padding zeroes until size of vector is an integer number of bytes. - // I think not needed, if bytes of m correctly formatted (i.e. added in big-endianness) -> the unused bits will be zero - // and the vector has an integer number of uint8_t elements. - - // compute mac - std::vector mac; - if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 - { - mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); - } - else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES - { - mac = d_crypto->computeCMAC_AES(applicable_key, m); - } - - // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD - uint8_t lt_bits = 0; // TODO - remove this duplication of code. - const auto it2 = OSNMA_TABLE_11.find(applicable_OSNMA.d_dsm_kroot_message.ts); - if (it2 != OSNMA_TABLE_11.cend()) - { - lt_bits = it2->second; - } - if (lt_bits == 0) - { - return verified; - } - uint64_t computed_mac = static_cast(mac[0]) << (lt_bits - 8); - computed_mac += (static_cast(mac[1]) << (lt_bits - 16)); - if (lt_bits == 20) - { - computed_mac += (static_cast(mac[1] & 0xF0) >> 4); - } - else if (lt_bits == 24) - { - computed_mac += static_cast(mac[2]); - } - else if (lt_bits == 28) - { - computed_mac += (static_cast(mac[2]) << 4); - computed_mac += (static_cast(mac[3] & 0xF0) >> 4); - } - else if (lt_bits == 32) - { - computed_mac += (static_cast(mac[2]) << 8); - computed_mac += static_cast(mac[3]); - } - else if (lt_bits == 40) - { - computed_mac += (static_cast(mac[2]) << 16); - computed_mac += (static_cast(mac[3]) << 8); - computed_mac += static_cast(mac[4]); - } - - // Compare computed tag with received one truncated - if (tag_and_info.tag == computed_mac) - { - verified = true; - if(tag_and_info.tag_info.ADKD == 0 || tag_and_info.tag_info.ADKD == 12) - { - std::cout << "Galileo OSNMA: tag verification successful for PRN_a " - << applicable_NavData.PRNa << " with WN=" - << applicable_NavData.WN_sf0 << ", TOW=" - << applicable_NavData.TOW_sf0 << "NavData= " - << "Ephemeris, Clock and Ionospheric data" << ". " - << std::endl; - } - else if(tag_and_info.tag_info.ADKD == 4) - { - std::cout << "Galileo OSNMA: tag verification successful for PRN_a " - << applicable_NavData.PRNa << " with WN=" - << applicable_NavData.WN_sf0 << ", TOW=" - << applicable_NavData.TOW_sf0 << "NavData= " - << "Timing data" << ". " - << std::endl; - } - - } - else - { - std::cout << "Galileo OSNMA: Tag verification failed for PRN_a " - << applicable_NavData.PRNa << " with WN=" - << applicable_NavData.WN_sf0 << ", TOW=" - << applicable_NavData.TOW_sf0 << ". " - << std::endl; - } - return verified; -} bool osnma_msg_receiver::verify_tag(Tag& tag) { std::vector m = tag.build_message(); @@ -1291,55 +1033,36 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) // Compare computed tag with received one truncated if (tag.received_tag == computed_mac) { - if(tag.ADKD == 0 || tag.ADKD == 12) - { - std::cout << "Galileo OSNMA: tag verification successful for PRN_a " - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " - << "Ephemeris, Clock and Ionospheric data" << ". " - << std::endl; - } - else if(tag.ADKD == 4) - { - std::cout << "Galileo OSNMA: tag verification successful for PRN_a " - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " - << "Timing data" << ". " - << std::endl; - } +// if(tag.ADKD == 0 || tag.ADKD == 12) +// { +// std::cout << "Galileo OSNMA: tag verification successful for PRN_a " +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " +// << "Ephemeris, Clock and Ionospheric data" << ". " +// << std::endl; +// } +// else if(tag.ADKD == 4) +// { +// std::cout << "Galileo OSNMA: tag verification successful for PRN_a " +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " +// << "Timing data" << ". " +// << std::endl; +// } return true; } else { - std::cout << "Galileo OSNMA: Tag verification failed for PRN_a " - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" - << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << std::endl; +// std::cout << "Galileo OSNMA: Tag verification failed for PRN_a " +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" +// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << std::endl; return false; } } -/** - * @brief Checks if the current subframe time is bigger than last one received. - * - * \details It compares the current GST value with the previous one and updates the old value with the new one. - * - * @param sharedPtr A shared pointer to an instance of OSNMA_msg. - * @return True if the current subframe is the next subframe, False otherwise. - */ -//bool osnma_msg_receiver::is_next_subframe() -//{ -// bool is_bigger = d_GST_SIS > d_old_GST_SIS; -// if(d_GST_SIS != d_old_GST_SIS + 30 && d_old_GST_SIS != 0){ -// std::cout << "Galileo OSNMA:: Mack processing - skip " << std::endl; -// } -// -// d_old_GST_SIS = d_GST_SIS; -// -// return is_bigger; -//} void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) { // control size of container @@ -1368,13 +1091,95 @@ void osnma_msg_receiver::display_data() } bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TOW) { - if(d_tesla_key_verified || d_flag_debug) + if(d_tesla_key_verified) { // TODO - find out I bt. both tesla keys, then hash until then, then compare. - // retrieve latest tesla key + // retrieve latest tesla key from d_tesla_keys + std::vector validated_key = d_tesla_keys.rbegin()->second; // compute hashes needed + uint32_t num_of_hashes_needed = (d_GST_SIS - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; // hash current key until num_hashes and compare - return false; + auto start = std::chrono::high_resolution_clock::now(); + uint32_t GST_SFi = d_GST_SIS; // TODO + std::vector K_II = key; + std::vector K_I; // result of the recursive hash operations + const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; + // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) + for (uint32_t i = 1; i < num_of_hashes_needed ; i++) + { + // build message digest m = (K_I+1 || GST_SFi || alpha) + std::vector msg(K_II.size() + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); + std::copy(K_II.begin(),K_II.end(),msg.begin()); + + msg.push_back((d_GST_Sf & 0xFF000000) >> 24); + msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); + msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); + msg.push_back(d_GST_Sf & 0x000000FF); + // extract alpha + for (int k = 5; k >= 0;k--) + { + // TODO: static extracts the MSB in case from larger to shorter int? + msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. + } + // compute hash + std::vector hash; + if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. + { + hash = d_crypto->computeSHA256(msg); + } + else if (d_osnma_data.d_dsm_kroot_message.hf == 2) + { + hash = d_crypto->computeSHA3_256(msg); + } + else + { + hash = std::vector(32); + } + // truncate hash + K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits + for (uint16_t i = 0; i < lk_bytes; i++) + { + K_I.push_back(hash[i]); + } + + // set parameters for next iteration + GST_SFi -= 30; // next SF time is the actual minus 30 seconds + K_II = K_I; // next key is the actual one + K_I.clear(); // empty the actual one for a new computation + } + // compare computed current key against received key + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; + + if(K_II.size() != key.size()) + { + std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + return false; + } + if (K_II == validated_key) + { + std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; + d_tesla_keys.insert(std::pair(TOW,key)); + d_last_verified_key_GST = d_GST_SIS; + d_tesla_key_verified = true; // TODO this boolean only shows that a tesla key is verified, re-setting it all the time is not beautiful + // case one verified and after a time another one not, what would happen in the next MAck processed is that because false + // it would try to verifiy against kroot, but it could as well try against last validated key. This needs to be adressed in the future. + } + else + + { + std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + if(d_flag_debug){ + d_last_verified_key_GST = d_GST_SIS; + d_tesla_key_verified = true; + } + + else + d_tesla_key_verified = false; + } + return d_tesla_key_verified; } else {// have to go until Kroot @@ -1438,11 +1243,12 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; return false; } - if (K_II == key) + if (K_II == d_osnma_data.d_dsm_kroot_message.kroot) { std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; d_tesla_keys.insert(std::pair(TOW,key)); d_tesla_key_verified = true; + d_last_verified_key_GST = d_GST_SIS; // TODO - propagate result // TODO - save current tesla key as latest one? propose a map with // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence @@ -1451,8 +1257,10 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO { std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - if(d_flag_debug) + if(d_flag_debug){ + d_last_verified_key_GST = d_GST_SIS; d_tesla_key_verified = true; + } } return d_tesla_key_verified; } @@ -1467,7 +1275,15 @@ void osnma_msg_receiver::remove_verified_tags() { for (auto it = d_tags_awaiting_verify.begin(); it != d_tags_awaiting_verify.end() ; ){ if (it->second.status == Tag::SUCCESS || it->second.status == Tag::FAIL) - it = d_tags_awaiting_verify.erase(it); + { + std::cout << "Galileo OSNMA: delete tag for tag Id= " + << it->second.tag_id << ", PRN_a= " + << it->second.PRNa << ", TOW=" + << it->second.TOW << ", ADKD= " + << static_cast(it->second.ADKD) << ", status= " + << it->second.status << std::endl; + it = d_tags_awaiting_verify.erase(it); + } else ++it; } @@ -1495,19 +1311,15 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() * @param message The MACK_message to verify. * @return True if the MACSEQ is valid, false otherwise. */ -bool osnma_msg_receiver::verify_macseq() +bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) { // MACSEQ verification - - // verify MACK tags - MACSEQ - OSNMA_data applicable_OSNMA = d_old_OSNMA_buffer[d_old_OSNMA_buffer.size() - 2]; // former subframe - //d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. - std::vector applicable_key = d_old_OSNMA_buffer.back().d_mack_message.key; // current tesla key ie transmitted in the next subframe + std::vector applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe std::vector sq1{}; std::vector sq2{}; std::vector applicable_sequence; - const auto it = OSNMA_TABLE_16.find(applicable_OSNMA.d_dsm_kroot_message.maclt); + const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); // TODO as per RG example appears that the seq. q shall also be validated ageints either next or former Sf (depending on GST) if (it != OSNMA_TABLE_16.cend()) { @@ -1516,11 +1328,11 @@ bool osnma_msg_receiver::verify_macseq() } // Assign relevant sequence based on subframe time - if (applicable_OSNMA.d_nav_data.TOW_sf0 % 60 < 30) // tried GST_Sf and it does not support the data present. + if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present. { applicable_sequence = sq1; } - else if (applicable_OSNMA.d_nav_data.TOW_sf0 % 60 >= 30) + else if (mack.TOW % 60 >= 30) { applicable_sequence = sq2; } @@ -1528,7 +1340,7 @@ bool osnma_msg_receiver::verify_macseq() { std::cout << "Galileo OSNMA: Mismatch in the GST verification. " << std::endl; } - if(applicable_OSNMA.d_mack_message.tag_and_info.size() != applicable_sequence.size()-1) + if(mack.tag_and_info.size() != applicable_sequence.size() - 1) { std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; return false; @@ -1536,14 +1348,14 @@ bool osnma_msg_receiver::verify_macseq() std::vector flxTags {}; std::string tempADKD; // MACLT verification - for (uint8_t i = 0; i < applicable_OSNMA.d_mack_message.tag_and_info.size(); i++) + for (uint8_t i = 0; i < mack.tag_and_info.size(); i++) { tempADKD = applicable_sequence[i+1]; if(tempADKD == "FLX") { flxTags.push_back(i); // C: just need to save the index in the sequence } - else if(applicable_OSNMA.d_mack_message.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i+1])) + else if(mack.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i+1])) { std::cout << "Galileo OSNMA: Unsuccessful verification of MACSEQ - received ADKD against MAC Look-up table. " << std::endl; return false; // C: suffices one incorrect to abort and not process the rest of the tags } @@ -1551,7 +1363,7 @@ bool osnma_msg_receiver::verify_macseq() // Fixed as well as FLX Tags share first part - Eq. 22 ICD std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes - m[0] = static_cast(applicable_OSNMA.d_nav_data.PRNa); // PRN_A - SVID of the satellite transmiting the tag + m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); @@ -1559,9 +1371,9 @@ bool osnma_msg_receiver::verify_macseq() // Case tags flexible - Eq. 21 ICD for (uint8_t i = 0; i < flxTags.size() ; i++) { - m[2*i + 5] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.PRN_d; - m[2*i + 6] = applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | - applicable_OSNMA.d_mack_message.tag_and_info[flxTags[i]].tag_info.cop; + m[2*i + 5] = mack.tag_and_info[flxTags[i]].tag_info.PRN_d; + m[2*i + 6] = mack.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | + mack.tag_and_info[flxTags[i]].tag_info.cop; } // m = {0x18, 0x4f, 0x93, 0x53, 0x04, 0x05, 0x0f, 0x1f, 0x0f}; // applicable_key = {0x11, 0x26, 0x47, 0x3b, 0x0e, 0x05, 0x05, 0x35, @@ -1569,11 +1381,11 @@ bool osnma_msg_receiver::verify_macseq() // applicable_OSNMA.d_mack_message.header.macseq = 0xbb8; // compute mac std::vector mac; - if (applicable_OSNMA.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); } - else if (applicable_OSNMA.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { mac = d_crypto->computeCMAC_AES(applicable_key, m); } @@ -1584,16 +1396,17 @@ bool osnma_msg_receiver::verify_macseq() mac_msb = (mac[0] << 8) + mac[1]; } uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; - if (computed_macseq == applicable_OSNMA.d_mack_message.header.macseq && !flxTags.empty()) + if (computed_macseq == mack.header.macseq && !flxTags.empty()) return true; else return false; } -bool osnma_msg_receiver::nav_data_available(Tag& t) +bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) { auto prn_it = d_satellite_nav_data.find(t.PRNa); if (prn_it != d_satellite_nav_data.end()) { // PRN was found, check if TOW exists in inner map + std::cout << "Galileo OSNMA: hasData = true " << std::endl; std::map& tow_map = prn_it->second; auto tow_it = tow_map.find(t.TOW); if (tow_it != tow_map.end()) { @@ -1604,7 +1417,35 @@ bool osnma_msg_receiver::nav_data_available(Tag& t) } } else { // PRN was not found + std::cout << "Galileo OSNMA: hasData = false " << std::endl; return false; } return false; } +bool osnma_msg_receiver::tag_has_key_available(Tag& t){ + // check adkd of tag + // if adkd = 0 or 4 => look for d_tesla_keys[t.TOW+30] + // if adkd = 12 => look for d_tesla_keys[t.TOW+300] + // return true if available, otherwise false + + if (t.ADKD == 0 || t.ADKD == 4) + { + auto it = d_tesla_keys.find(t.TOW + 30); + if (it != d_tesla_keys.end()) + { + std::cout << "Galileo OSNMA: hasKey = true " << std::endl; + return true; + } + } + else if (t.ADKD == 12) + { + auto it = d_tesla_keys.find(t.TOW + 300); + if (it != d_tesla_keys.end()) + { + std::cout << "Galileo OSNMA: hasKey = true " << std::endl; + return true; + } + } + std::cout << "Galileo OSNMA: hasKey = false " << std::endl; + return false; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 7915d408e..c921fd62d 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -74,14 +74,13 @@ private: void process_mack_message(); void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData &data); bool verify_tesla_key(std::vector& key, uint32_t TOW); - void display_data(); - bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); + void display_data();bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); bool verify_tag(Tag& tag); bool is_next_subframe(); - bool nav_data_available(Tag& t); + bool tag_has_nav_data_available(Tag& t); + bool tag_has_key_available(Tag& t); std::map> d_satellite_nav_data; // map holding NavData sorted by SVID and TOW. - boost::circular_buffer d_old_OSNMA_buffer; // buffer that holds last 12 received OSNMA messages, including current one at back() std::map> d_tesla_keys; // tesla keys over time, sorted by TOW std::vector d_macks_awaiting_MACSEQ_verification; std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW @@ -100,7 +99,7 @@ private: bool d_tesla_key_verified{false}; bool d_flag_debug{false}; uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification - uint32_t d_old_GST_SIS{0}; + uint32_t d_last_verified_key_GST{0}; uint8_t d_Lt_min {}; // minimum equivalent tag length uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing @@ -114,7 +113,7 @@ private: std::vector d_tags_to_verify{0,4,12}; void remove_verified_tags(); void control_tags_awaiting_verify_size(); - bool verify_macseq(); + bool verify_macseq(const MACK_message& mack); }; From ff5118db5451bbdfeeef6b6dbce2aff698c2db6e Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Wed, 10 Apr 2024 17:51:43 +0200 Subject: [PATCH 099/219] [TAS-156] debug verify_tesla_key various bugfixes plus refactor recursive hash computation --- src/core/libs/osnma_msg_receiver.cc | 284 +++++++----------- src/core/libs/osnma_msg_receiver.h | 3 +- src/core/system_parameters/gnss_crypto.cc | 78 ++--- .../osnma/gnss_crypto_test.cc | 9 +- 4 files changed, 158 insertions(+), 216 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index f5e084ffe..d058f92a6 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -128,9 +128,10 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& read_nma_header(osnma_msg->hkroot[0]); read_dsm_header(osnma_msg->hkroot[1]); read_dsm_block(osnma_msg); - local_time_verification(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 - read_and_process_mack_block(osnma_msg); // only process them if a least 3 available. + if(d_osnma_data.d_dsm_kroot_message.towh_k != 0) + local_time_verification(osnma_msg); + read_and_process_mack_block(osnma_msg); // only process them if at least 3 available. } @@ -260,7 +261,7 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptrWN_sf0 & 0x00000FFF) << 20 | (osnma_msg->TOW_sf0 & 0x000FFFFF); //std::cout << "Galileo OSNMA: d_GST_SIS: " << d_GST_SIS << std::endl; //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; - d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k & 0x000FFFFF)) + 30; + d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k & 0x000FFFFF)) + 30; // applicable time (GST_Kroot + 30) //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; // TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID. if(d_receiver_time != 0) @@ -350,6 +351,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // DSM-KROOT message if (d_osnma_data.d_dsm_header.dsm_id < 12) { + // Parse Kroot message LOG(WARNING) << "OSNMA: DSM-KROOT message received."; d_osnma_data.d_dsm_kroot_message.nb_dk = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_kroot_message.pkid = d_dsm_reader->get_pkid(dsm_msg); @@ -364,10 +366,10 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_kroot_message.wn_k = d_dsm_reader->get_wn_k(dsm_msg); d_osnma_data.d_dsm_kroot_message.towh_k = d_dsm_reader->get_towh_k(dsm_msg); d_osnma_data.d_dsm_kroot_message.alpha = d_dsm_reader->get_alpha(dsm_msg); - + // Kroot field const uint16_t l_lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; d_osnma_data.d_dsm_kroot_message.kroot = d_dsm_reader->get_kroot(dsm_msg, l_lk_bytes); - + // DS field std::string hash_function = d_dsm_reader->get_hash_function(d_osnma_data.d_dsm_kroot_message.hf); uint16_t l_ds_bits = 0; const auto it = OSNMA_TABLE_15.find(hash_function); @@ -381,6 +383,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + l_lk_bytes + k]; } + // Padding const uint16_t l_dk_bits = d_dsm_reader->get_l_dk_bits(d_osnma_data.d_dsm_kroot_message.nb_dk); const uint16_t l_dk_bytes = l_dk_bits / 8; const uint16_t l_pdk_bytes = (l_dk_bytes - 13 - l_lk_bytes - l_ds_bytes); @@ -406,7 +409,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { MSG.push_back(dsm_msg[i]); } - std::vector message = MSG; // C: MSG == M || DS from ICD. Eq. 7 + std::vector 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]); @@ -435,12 +438,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // Check that the padding bits received match the computed values if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { - LOG(WARNING) << "OSNMA: DSM-KROOT message received ok."; std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) - << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; + << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 << std::endl; + local_time_verification(osnma_msg); d_kroot_verified = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); if (d_kroot_verified) { @@ -1091,179 +1094,51 @@ void osnma_msg_receiver::display_data() } bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TOW) { - if(d_tesla_key_verified) + uint32_t num_of_hashes_needed; + uint32_t GST_SFi = d_receiver_time - 30; + std::vector hash; + const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; + std::vector validated_key; + if(d_tesla_key_verified){ // have to go up to last verified key + validated_key = d_tesla_keys.rbegin()->second; + num_of_hashes_needed = (d_receiver_time - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key " << std::endl; + + hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); + } + else{// have to go until Kroot + validated_key = d_osnma_data.d_dsm_kroot_message.kroot; + num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 ICD + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed up to Kroot " << std::endl; + + hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); + } + + if(hash.size() != key.size()) { - // TODO - find out I bt. both tesla keys, then hash until then, then compare. - // retrieve latest tesla key from d_tesla_keys - std::vector validated_key = d_tesla_keys.rbegin()->second; - // compute hashes needed - uint32_t num_of_hashes_needed = (d_GST_SIS - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; - // hash current key until num_hashes and compare - auto start = std::chrono::high_resolution_clock::now(); - uint32_t GST_SFi = d_GST_SIS; // TODO - std::vector K_II = key; - std::vector K_I; // result of the recursive hash operations - const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; - // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) - for (uint32_t i = 1; i < num_of_hashes_needed ; i++) - { - // build message digest m = (K_I+1 || GST_SFi || alpha) - std::vector msg(K_II.size() + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); - std::copy(K_II.begin(),K_II.end(),msg.begin()); - - msg.push_back((d_GST_Sf & 0xFF000000) >> 24); - msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); - msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); - msg.push_back(d_GST_Sf & 0x000000FF); - // extract alpha - for (int k = 5; k >= 0;k--) - { - // TODO: static extracts the MSB in case from larger to shorter int? - msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. - } - // compute hash - std::vector hash; - if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. - { - hash = d_crypto->computeSHA256(msg); - } - else if (d_osnma_data.d_dsm_kroot_message.hf == 2) - { - hash = d_crypto->computeSHA3_256(msg); - } - else - { - hash = std::vector(32); - } - // truncate hash - K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits - for (uint16_t i = 0; i < lk_bytes; i++) - { - K_I.push_back(hash[i]); - } - - // set parameters for next iteration - GST_SFi -= 30; // next SF time is the actual minus 30 seconds - K_II = K_I; // next key is the actual one - K_I.clear(); // empty the actual one for a new computation - } - // compare computed current key against received key - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; - - if(K_II.size() != key.size()) - { - std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - return false; - } - if (K_II == validated_key) - { - std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; - d_tesla_keys.insert(std::pair(TOW,key)); - d_last_verified_key_GST = d_GST_SIS; - d_tesla_key_verified = true; // TODO this boolean only shows that a tesla key is verified, re-setting it all the time is not beautiful - // case one verified and after a time another one not, what would happen in the next MAck processed is that because false - // it would try to verifiy against kroot, but it could as well try against last validated key. This needs to be adressed in the future. - } - else - - { - std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - if(d_flag_debug){ - d_last_verified_key_GST = d_GST_SIS; - d_tesla_key_verified = true; - } - - else - d_tesla_key_verified = false; - } - return d_tesla_key_verified; + std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + return false; } - else - {// have to go until Kroot - uint32_t num_of_hashes_needed = (d_GST_SIS - d_GST_0) / 30 + 1; // Eq. 19 ICD - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed. " << std::endl; - auto start = std::chrono::high_resolution_clock::now(); - uint32_t GST_SFi = d_GST_SIS; - std::vector K_II = key; - std::vector K_I; // result of the recursive hash operations - const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; - // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) - for (uint32_t i = 1; i < num_of_hashes_needed ; i++) - { - // build message digest m = (K_I+1 || GST_SFi || alpha) - std::vector msg(K_II.size() + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); - std::copy(K_II.begin(),K_II.end(),msg.begin()); - - msg.push_back((d_GST_Sf & 0xFF000000) >> 24); - msg.push_back((d_GST_Sf & 0x00FF0000) >> 16); - msg.push_back((d_GST_Sf & 0x0000FF00) >> 8); - msg.push_back(d_GST_Sf & 0x000000FF); - // extract alpha - for (int k = 5; k >= 0;k--) - { - // TODO: static extracts the MSB in case from larger to shorter int? - msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (i * 8)) & 0xFF)); // extract first 6 bytes of alpha. - } - // compute hash - std::vector hash; - if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. - { - hash = d_crypto->computeSHA256(msg); - } - else if (d_osnma_data.d_dsm_kroot_message.hf == 2) - { - hash = d_crypto->computeSHA3_256(msg); - } - else - { - hash = std::vector(32); - } - // truncate hash - K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits - for (uint16_t i = 0; i < lk_bytes; i++) - { - K_I.push_back(hash[i]); - } - - // set parameters for next iteration - GST_SFi -= 30; // next SF time is the actual minus 30 seconds - K_II = K_I; // next key is the actual one - K_I.clear(); // empty the actual one for a new computation - } - // compare computed current key against received key - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; - - if(K_II.size() != key.size()) - { - std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - return false; - } - if (K_II == d_osnma_data.d_dsm_kroot_message.kroot) - { - std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; + if (hash == validated_key) + { + std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; + d_tesla_keys.insert(std::pair(TOW,key)); + d_tesla_key_verified = true; + d_last_verified_key_GST = d_receiver_time; + // TODO - propagate result + // TODO - save current tesla key as latest one? propose a map with + // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence + } + else{ + std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + if(d_flag_debug){ d_tesla_keys.insert(std::pair(TOW,key)); + d_last_verified_key_GST = d_receiver_time; d_tesla_key_verified = true; - d_last_verified_key_GST = d_GST_SIS; - // TODO - propagate result - // TODO - save current tesla key as latest one? propose a map with - // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence + // TODO - if intermediate verification fails, can one still use the former verified tesla key or should go to Kroot or even retrieve new Kroot? } - else - - { - std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - if(d_flag_debug){ - d_last_verified_key_GST = d_GST_SIS; - d_tesla_key_verified = true; - } - } - return d_tesla_key_verified; } + return d_tesla_key_verified; } /** @@ -1449,3 +1324,62 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t){ std::cout << "Galileo OSNMA: hasKey = false " << std::endl; return false; } +std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes) +{ + auto start = std::chrono::high_resolution_clock::now(); + std::vector K_II = {0x2D,0xC3,0xA3,0xCD,0xB1,0x17,0xFA,0xAD,0xB8,0x3B,0x5F,0x0B,0x6F,0xEA,0x88,0xEB};//key; + std::vector K_I; // result of the recursive hash operations + GST_SFi = 0x4E054600; + std::vector msg; + // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) + for (uint32_t i = 1; i <= num_of_hashes_needed ; i++) + { + // build message digest m = (K_I+1 || GST_SFi || alpha) + msg.reserve(K_II.size() + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); + std::copy(K_II.begin(),K_II.end(),std::back_inserter(msg)); + + msg.push_back((GST_SFi & 0xFF000000) >> 24); + msg.push_back((GST_SFi & 0x00FF0000) >> 16); + msg.push_back((GST_SFi & 0x0000FF00) >> 8); + msg.push_back(GST_SFi & 0x000000FF); + // extract alpha + d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; + for (int k = 5; k >= 0;k--) + { + // TODO: static extracts the MSB in case from larger to shorter int? + msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (k * 8)) & 0xFF)); // extract first 6 bytes of alpha. + } + // compute hash + std::vector hash; + if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. + { + hash = d_crypto->computeSHA256(msg); + } + else if (d_osnma_data.d_dsm_kroot_message.hf == 2) + { + hash = d_crypto->computeSHA3_256(msg); + } + else + { + hash = std::vector(32); + } + // truncate hash + K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits + for (int k = 0; k < lk_bytes; k++) + { + K_I.push_back(hash[k]); + } + // set parameters for next iteration + GST_SFi -= 30; // next SF time is the actual minus 30 seconds + K_II = K_I; // next key is the actual one + K_I.clear(); // empty the actual one for a new computation + msg.clear(); + } + if(GST_SFi + 30 != d_GST_0 - 30 && d_tesla_key_verified == false) + std::cout << "Galileo OSNMA: TESLA verification error. Kroot time mismatch! \n"; // ICD. Eq. 18 + // compare computed current key against received key + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = end - start; + std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; + return K_II; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index c921fd62d..a443850ac 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -74,6 +74,7 @@ private: void process_mack_message(); void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData &data); bool verify_tesla_key(std::vector& key, uint32_t TOW); + std::vector hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes); void display_data();bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); bool verify_tag(Tag& tag); bool is_next_subframe(); @@ -98,7 +99,7 @@ private: bool d_kroot_verified{false}; bool d_tesla_key_verified{false}; bool d_flag_debug{false}; - uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification + uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification TODO need really to be global var? uint32_t d_last_verified_key_GST{0}; uint8_t d_Lt_min {}; // minimum equivalent tag length uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index af7df7899..f55b5f609 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -468,6 +468,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) std::cerr << "OpenSSL: error reading the Public Key from file " << pemFilePath << ". Aborting import" << std::endl; return; } + #else // Import the PEM data gnutls_datum_t pemDatum = {const_cast(reinterpret_cast(pemContent.data())), static_cast(pemContent.size())}; @@ -489,6 +490,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) gnutls_pubkey_deinit(pubkey); #endif std::cout << "Public key successfully read from file " << pemFilePath << std::endl; + print_pubkey_hex(d_PublicKey); } @@ -497,48 +499,48 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st std::vector digest = this->computeSHA256(message); if (!have_public_key()) { - std::cerr << "GnuTLS error: public key not available"<< std::endl; + std::cerr << "Galileo OSNMA::Kroot verification error::Public key not available"<< std::endl; return false; } bool success = false; #if USE_OPENSSL_FALLBACK - - EVP_MD_CTX *mdctx = NULL; // verification context; a struct that wraps the message to be verified. - int ret = 0; // error - - /* Create the Message Digest Context */ - if(!(mdctx = EVP_MD_CTX_new())) goto err; // Allocates and returns a digest context. - - /* Initialize `key` with a public key */ - // hashes cnt bytes of data at d into the verification context ctx - if(1 != EVP_DigestVerifyInit(mdctx, NULL /*TODO null?*/, EVP_sha256(), NULL, d_PublicKey)) goto err; - - /* Initialize `key` with a public key */ - if(1 != EVP_DigestVerifyUpdate(mdctx, message.data(), message.size())) goto err; - - - if( 1== EVP_DigestVerifyFinal(mdctx, signature.data(), signature.size())) - { - return true; - } - else - { - unsigned long errCode = ERR_get_error(); - int lib_code = ERR_GET_LIB(errCode); - char* err = ERR_error_string(errCode, NULL); - const char* error_string = ERR_error_string(errCode, NULL); - std::cerr << "OpenSSL: message authentication failed: " << err /*<< - "from library with code " << lib_code << - " error string: " << error_string */<< std::endl; - } -err: - if(ret != 1) - { - /* Do some error handling */ - // notify other blocks - std::cout << "ECDSA_Verify_OSSL()::error " << ret << std::endl; - - } +// using low-level API to test function -- it works in unit tests, not in real bytes. +// EVP_MD_CTX *mdctx = NULL; // verification context; a struct that wraps the message to be verified. +// int ret = 0; // error +// +// /* Create the Message Digest Context */ +// if(!(mdctx = EVP_MD_CTX_new())) goto err; // Allocates and returns a digest context. +// +// /* Initialize `key` with a public key */ +// // hashes cnt bytes of data at d into the verification context ctx +// if(1 != EVP_DigestVerifyInit(mdctx, NULL /*TODO null?*/, EVP_sha256(), NULL, d_PublicKey)) goto err; +// +// /* Initialize `key` with a public key */ +// if(1 != EVP_DigestVerifyUpdate(mdctx, message.data(), message.size())) goto err; +// +// +// if( 1 == EVP_DigestVerifyFinal(mdctx, signature.data(), signature.size())) +// { +// return true; +// } +// else +// { +// unsigned long errCode = ERR_get_error(); +// int lib_code = ERR_GET_LIB(errCode); +// char* err = ERR_error_string(errCode, NULL); +// const char* error_string = ERR_error_string(errCode, NULL); +// std::cerr << "OpenSSL: message authentication failed: " << err /*<< +// "from library with code " << lib_code << +// " error string: " << error_string */<< std::endl; +// } +//err: +// if(ret != 1) +// { +// /* Do some error handling */ +// // notify other blocks +// std::cout << "ECDSA_Verify_OSSL()::error " << ret << std::endl; +// +// } #if USE_OPENSSL_3 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 4f57162fa..563cf5a46 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 @@ -22,11 +22,16 @@ TEST(GnssCryptoTest, VerifySignature) { // 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 } ; // own ECDSA-P256 key and message generated and signed and verified successfully with openssl - std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final + std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK - std::vector publicKey{ // PK associated to the PrK +// std::vector publicKey{// PK associated to the PrK, in der format ---test +// 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4A, 0xF3, +// 0xEE, 0x3A, 0x94, 0x25, 0x25, 0x3D, 0x55, 0xC2, 0x5A, 0xC2, 0x2D, 0xCF, 0x14, 0x4D, 0x39, 0x0D, 0xB1, 0xFC, 0x7F, 0x31, 0x5A, 0x2A, 0x19, 0xAE, 0x4E, 0xD6, 0xCB, 0xA6, 0x59, +// 0xD6, 0x99, 0x7C, 0xE8, 0xBD, 0x1F, 0x43, 0x34, 0x1C, 0x59, 0xD9, 0xD9, 0xCA, 0xC3, 0xEE, 0x58, 0xE5, 0xEA, 0xD3, 0x55, 0x44, 0xEA, 0x89, 0x71, 0x65, 0xD0, 0x92, 0x72, 0xA2, +// 0xC8, 0x3C, 0x87, 0x5D }; + std::vector publicKey{ // PK associated to the PrK, in pem format 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, From e13fc392149437b07c5c2e45693015d59928262f Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Fri, 19 Apr 2024 00:47:31 +0200 Subject: [PATCH 100/219] [TAS-177] implement OsnmaTestVectorsSimulation This commit introduces two new unit tests for the osnma_msg_receiver class: 'TeslaKeyVerification' and 'OsnmaTestVectorsSimulation'. The first test verifies the Tesla key handling within the class. The second test uses real-world test vectors to simulate osnma message receiving and verifies correct parsing and processing of messages. --- src/core/libs/osnma_msg_receiver.cc | 3 +- src/core/libs/osnma_msg_receiver.h | 6 +- src/tests/CMakeLists.txt | 34 +++ src/tests/test_main.cc | 1 + .../osnma/gnss_crypto_test.cc | 28 +- .../osnma/osnma_msg_receiver_test.cc | 265 ++++++++++++++++++ 6 files changed, 322 insertions(+), 15 deletions(-) create mode 100644 src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index d058f92a6..9b546366e 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -149,6 +149,7 @@ void osnma_msg_receiver::read_nma_header(uint8_t nma_header) d_osnma_data.d_nma_header.cid = d_dsm_reader->get_cid(nma_header); d_osnma_data.d_nma_header.cpks = d_dsm_reader->get_cpks(nma_header); d_osnma_data.d_nma_header.reserved = d_dsm_reader->get_nma_header_reserved(nma_header); + std::cout<< "NMAS: " << static_cast(d_osnma_data.d_nma_header.nmas) << " CPKS: " << static_cast(d_osnma_data.d_nma_header.cpks) << std::endl; } @@ -438,7 +439,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // Check that the padding bits received match the computed values if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { - LOG(WARNING) << "OSNMA: DSM-KROOT message received ok."; + LOG(WARNING) << "Galileo OSNMA: DSM-KROOT message received ok."; std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index a443850ac..9f3c76fec 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -18,6 +18,8 @@ #ifndef GNSS_SDR_OSNMA_MSG_RECEIVER_H #define GNSS_SDR_OSNMA_MSG_RECEIVER_H +#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 @@ -54,7 +56,6 @@ class osnma_msg_receiver : public gr::block { public: ~osnma_msg_receiver() = default; //!< Default destructor - private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); @@ -115,6 +116,9 @@ private: void remove_verified_tags(); void control_tags_awaiting_verify_size(); bool verify_macseq(const MACK_message& mack); + + FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); + FRIEND_TEST(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation); }; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 7d6951aba..72b12bc9e 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1301,4 +1301,38 @@ if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) #${GNSSSDR_SOURCE_DIR}/src/core, #${GNSSSDR_SOURCE_DIR}/src/core/receiver, ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters) +endif() + + +if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) + set(OSNMA_MSG_RECEIVER_TEST_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc) + + # Configure the test executable: + if(USE_CMAKE_TARGET_SOURCES) + add_executable(osnma_msg_receiver_test) + target_sources(osnma_msg_receiver_test PRIVATE ${OSNMA_MSG_RECEIVER_TEST_SOURCES}) + else() + add_executable(osnma_msg_receiver_test ${OSNMA_MSG_RECEIVER_TEST_SOURCES}) + endif() + + # Link libraries that gnss_crypto_test requires: + target_link_libraries(osnma_msg_receiver_test + PRIVATE + Boost::thread + Gflags::gflags + Glog::glog + GTest::GTest + GTest::Main + core_libs + ) + + # Include any directories your test needs for header files: + target_include_directories(osnma_msg_receiver_test + PRIVATE + #${GNSSSDR_SOURCE_DIR}/src/algorithms, + #${GNSSSDR_SOURCE_DIR}/src/core, + #${GNSSSDR_SOURCE_DIR}/src/core/receiver, + ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters) endif() \ No newline at end of file diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 8fc8efd57..e589fb972 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -73,6 +73,7 @@ DECLARE_string(log_dir); #include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc" #include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc" #include "unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc" +#include "unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc" #include "unit-tests/signal-processing-blocks/pvt/geohash_test.cc" #include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc" 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 563cf5a46..b0ecaf2cc 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 @@ -8,21 +8,21 @@ TEST(GnssCryptoTest, VerifySignature) { // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" std::unique_ptr d_crypto = std::make_unique(); - // RG example - import crt certificate - // std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; - // std::vector publicKey { // PEM format - 1000 bits - // 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 } ; +// RG example - import crt certificate - result: FAIL +//std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; +//std::vector publicKey { // PEM format - 1000 bits +// 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 } ; // own ECDSA-P256 key and message generated and signed and verified successfully with openssl - std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message + std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message (unhashed) std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK @@ -56,6 +56,8 @@ TEST(GnssCryptoTest, VerifySignature) { // 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, 0x4D, 0x42, 0x41, 0x67, 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, // 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A }; + + d_crypto->set_public_key(publicKey); bool result = d_crypto->verify_signature(message, signature); diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc new file mode 100644 index 000000000..047832490 --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include + + +struct TestVector +{ + int svId; + int numNavBits; + std::vector navBits; +}; + +class OsnmaMsgReceiverTest : public ::testing::Test +{ +protected: + osnma_msg_receiver_sptr osnma; + Galileo_Inav_Message galileo_message; + uint8_t page_position_in_inav_subframe; + bool flag_CRC_test; + std::string page_even; + OSNMA_msg osnma_msg{}; + std::array nma_position_filled; + uint32_t d_GST_SIS{}; // 16 AUG 2023 05 00 01 + int T {}; + uint32_t TOW{}; + uint32_t WN{}; + void set_time(std::tm& input); + + void SetUp() override + { + flag_CRC_test = false; + page_even = ""; + + std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; + set_time(input_time); + std::string pemFilePath = "OSNMA_PublicKey_20230803105952_newPKID_1.pem"; + std::string merkleFilePath = "OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; + osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); + } + +public: + static std::vector parseNavBits(const std::string& hex); + static std::vector readTestVectorsFromFile(const std::string& filename); + std::string bytes_to_str(const std::vector& bytes); + std::vector extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes); +}; + + +TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { + // Arrange + osnma->d_tesla_key_verified = false; + osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; + osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits + osnma->d_receiver_time = 345630; + osnma->d_GST_0 = 345600; + osnma->d_tesla_keys.insert((std::pair>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); + std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; + uint32_t TOW = 345630; + + + + // Act + bool result = osnma->verify_tesla_key(key, TOW); + + // Assert + ASSERT_TRUE(result); // Adjust this according to what you expect + +} + +TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) +{ + // Arrange + std::vector testVectors = readTestVectorsFromFile(/*"/home/cgm/CLionProjects/osnma/src/tests/data/*/"16_AUG_2023_GST_05_00_01.csv"); + bool end_of_hex_stream{false}; + int offset_byte{0}; + int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size + const int SIZE_PAGE_BYTES{240/8}; + const int SIZE_SUBFRAME_PAGES{15}; + const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; + const int DURATION_SUBFRAME{30}; + + std::cout << "OsnmaTestVectorsSimulation:" << std::endl; + std::cout << "d_GST_SIS: " << d_GST_SIS << std::endl; + std::cout << "T: " << T << std::endl; + std::cout << "TOW: " << TOW << std::endl; + std::cout << "WN: " << WN << std::endl; + + + // Act + while (end_of_hex_stream == false){ // loop over all bytes of data. Note all TestVectors have same amount of data. + for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe + auto osnmaMsg_sptr = std::make_shared(); + std::array hkroot{}; + std::array mack{}; + byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) + for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe + { + // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index + std::vector page_bytes = extract_page_bytes(tv,byte_index,SIZE_PAGE_BYTES); + if(page_bytes.empty()){ + std::cout<< "OsnmaTestVectorsSimulation: end of TestVectors \n" << "byte_index="< osnmaBits(odd_page.substr(18, 40)); + // Extract bits for hkroot and mack + std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8)); + std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32)); + hkroot[idx] = static_cast(hkrootBits.to_ulong()); + mack[idx] = static_cast(mackBits.to_ulong()); + + byte_index += SIZE_PAGE_BYTES; + } + if(end_of_hex_stream) + break; + osnmaMsg_sptr->hkroot = hkroot; + osnmaMsg_sptr->mack = mack; + + osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; + osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ; + osnmaMsg_sptr->PRN = tv.svId; + + auto temp_obj = pmt::make_any(osnmaMsg_sptr); + + osnma->msg_handler_osnma(temp_obj); // osnma entry point + } + + + if(!end_of_hex_stream){ + offset_byte = byte_index; // update offset for the next subframe + d_GST_SIS += DURATION_SUBFRAME; + T = d_GST_SIS % 30; + TOW = d_GST_SIS & 0x000FFFFF; + WN = (d_GST_SIS & 0xFFF00000) >> 20 ; + std::cout << "OsnmaTestVectorsSimulation:" << std::endl; + std::cout << "d_GST_SIS: " << d_GST_SIS << std::endl; + std::cout << "T: " << T << std::endl; + std::cout << "TOW: " << TOW << std::endl; + std::cout << "WN: " << WN << std::endl; + } + + + } + + + + // Assert + // TODO +} + +std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std::string& filename) +{ + std::ifstream file(filename); + std::vector testVectors; + if (!file.is_open()) { + std::cerr<<"Error reading the file \"" << filename <<"\" \n"; + return testVectors; + } + + std::string line; + std::getline(file, line); + if (line != "SVID,NumNavBits,NavBitsHEX\r" ){ + std::cerr<<"Error parsing first line" <<"\n"; + } + + while (std::getline(file, line)) + { + std::stringstream ss(line); + TestVector tv; + + std::string val; + + std::getline(ss, val, ','); + tv.svId = std::stoi(val); + + std::getline(ss, val, ','); + tv.numNavBits = std::stoi(val); + + std::getline(ss, val, ','); + tv.navBits = OsnmaMsgReceiverTest::parseNavBits(val); + + testVectors.push_back(tv); + } + + return testVectors; +} +std::vector OsnmaMsgReceiverTest::parseNavBits(const std::string& hex) +{ + std::vector bytes; + + for (unsigned int i = 0; i < hex.length()-1; i += 2) + { + std::string byteString = hex.substr(i, 2); + uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16); + bytes.push_back(byte); + } + return bytes; +} +std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector& bytes) +{ + std::string bit_string; + bit_string.reserve(bytes.size() * 8); + for(const auto& byte : bytes) + { + std::bitset<8> bits(byte); + bit_string += bits.to_string(); + } + return bit_string; +} +std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes) +{ + // Ensure we don't go beyond the end of tv.navBits + int num_bytes_to_extract = std::min(num_bytes, static_cast(tv.navBits.size() - byte_index)); + + // If byte_index is beyond the end of tv.navBits, return an empty vector + if (num_bytes_to_extract <= 0) + { + return std::vector(); + } + + // Use std::next to get an iterator to the range to extract + std::vector extracted_bytes(tv.navBits.begin() + byte_index, tv.navBits.begin() + byte_index + num_bytes_to_extract); + + return extracted_bytes; +} + +void OsnmaMsgReceiverTest::set_time(std::tm& input) +{ + // GST epoch (start of GST time) + std::tm tm_epoch = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; + + auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&tm_epoch)); + auto input_time_point = std::chrono::system_clock::from_time_t(mktime(&input)); + + // Get the duration from epoch in seconds + auto duration_sec = std::chrono::duration_cast(input_time_point - epoch_time_point); + + // Calculate the week number (WN) and time of week (TOW) + uint32_t sec_in_week = 7 * 24 * 60 * 60; + uint32_t week_number = duration_sec.count() / sec_in_week; + uint32_t time_of_week = duration_sec.count() % sec_in_week; + this->WN = week_number; + this->TOW = time_of_week; + // Return the week number and time of week as a pair + + this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); + this->T = d_GST_SIS % 30; + + +} From 359631b534a56a45035dcc9b5c5439273c70119f Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 6 May 2024 17:46:33 +0200 Subject: [PATCH 101/219] Improve logging in OSNMA receiver * substitute std::cout with google log outputs, blend out some couts * add check that the final time matches the Kroot time during tesla key verification * introduce variable 'd_validated_key' --- src/core/libs/osnma_msg_receiver.cc | 196 ++++++++++++++++------------ src/core/libs/osnma_msg_receiver.h | 1 + 2 files changed, 112 insertions(+), 85 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 9b546366e..1c1da25a9 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -89,7 +89,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) { const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); - std::cout << "Galileo OSNMA: Subframe received starting at " + LOG(INFO) << "Galileo OSNMA: Subframe received starting at " << "WN=" << nma_msg->WN_sf0 << ", TOW=" @@ -126,6 +126,8 @@ 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) { read_nma_header(osnma_msg->hkroot[0]); + if(d_osnma_data.d_nma_header.nmas == 0 || d_osnma_data.d_nma_header.nmas == 3 /*&& d_kroot_verified*/) + return; 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 @@ -149,7 +151,6 @@ void osnma_msg_receiver::read_nma_header(uint8_t nma_header) d_osnma_data.d_nma_header.cid = d_dsm_reader->get_cid(nma_header); d_osnma_data.d_nma_header.cpks = d_dsm_reader->get_cpks(nma_header); d_osnma_data.d_nma_header.reserved = d_dsm_reader->get_nma_header_reserved(nma_header); - std::cout<< "NMAS: " << static_cast(d_osnma_data.d_nma_header.nmas) << " CPKS: " << static_cast(d_osnma_data.d_nma_header.cpks) << std::endl; } @@ -162,9 +163,9 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { d_osnma_data.d_dsm_header.dsm_id = d_dsm_reader->get_dsm_id(dsm_header); d_osnma_data.d_dsm_header.dsm_block_id = d_dsm_reader->get_dsm_block_id(dsm_header); // BID - LOG(WARNING) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); - LOG(WARNING) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); - std::cout << "Galileo OSNMA: Received block " << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) + LOG(INFO) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); + LOG(INFO) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); + LOG(INFO)<< "Galileo OSNMA: Received block " << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) << " from DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << std::endl; } @@ -174,7 +175,7 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) * */ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_msg) { - // Fill d_dsm_message + // Fill d_dsm_message. dsm_block_id provides the offset within the dsm message. size_t index = 0; for (const auto* it = osnma_msg->hkroot.cbegin() + 2; it != osnma_msg->hkroot.cend(); ++it) { @@ -207,7 +208,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = number_of_blocks; - LOG(WARNING) << "OSNMA: number_of_blocks=" << static_cast(number_of_blocks); + LOG(INFO) << "OSNMA: number_of_blocks=" << static_cast(number_of_blocks); if (number_of_blocks == 0) { // Something is wrong, start over @@ -219,18 +220,18 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ // Annotate bid d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; // TODO FIXME Galileo OSNMA: Available blocks for DSM_ID 6: [ - - - - - X - - - - - - - - - - ] in the first received Sf.. size 16? - std::cout << "Galileo OSNMA: Available blocks for DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << ": [ "; - if (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == 0) + LOG(INFO) << "Galileo OSNMA: Available blocks for DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << ": [ "; + if (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == 0) // block 0 not received yet { for (auto id_received : d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id]) { if (id_received == 0) { - std::cout << "- "; + LOG(INFO) << "- "; } else { - std::cout << "X "; + LOG(INFO) << "X "; } } } @@ -240,15 +241,15 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ { if (d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][k] == 0) { - std::cout << "- "; + LOG(INFO) << "- "; } else { - std::cout << "X "; + LOG(INFO) << "X "; } } } - std::cout << "]" << std::endl; // TODO update documentation + LOG(INFO) << "]" << std::endl; } /** @@ -262,7 +263,7 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptrWN_sf0 & 0x00000FFF) << 20 | (osnma_msg->TOW_sf0 & 0x000FFFFF); //std::cout << "Galileo OSNMA: d_GST_SIS: " << d_GST_SIS << std::endl; //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; - d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k & 0x000FFFFF)) + 30; // applicable time (GST_Kroot + 30) + d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k * 3600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; // TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID. if(d_receiver_time != 0) @@ -284,8 +285,8 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; // TODO set flag to false to avoid processing dsm and MACK messages @@ -294,18 +295,18 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; + LOG(WARNING) << "Galileo OSNMA: time constraint allows only slow MACs to be verified\n"; + LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; + LOG(WARNING)<< "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; } else { d_tags_allowed = tags_to_verify::none; d_tags_to_verify = {}; - std::cerr << "Galileo OSNMA: time constraint violation\n"; - std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; - std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; + LOG(ERROR) << "Galileo OSNMA: time constraint violation\n"; + LOG(ERROR) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; + LOG(ERROR) << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; } @@ -353,7 +354,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg if (d_osnma_data.d_dsm_header.dsm_id < 12) { // Parse Kroot message - LOG(WARNING) << "OSNMA: DSM-KROOT message received."; + LOG(INFO) << "OSNMA: DSM-KROOT message received."; d_osnma_data.d_dsm_kroot_message.nb_dk = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_kroot_message.pkid = d_dsm_reader->get_pkid(dsm_msg); d_osnma_data.d_dsm_kroot_message.cidkr = d_dsm_reader->get_cidkr(dsm_msg); @@ -397,7 +398,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg const uint16_t check_l_dk = 104 * std::ceil(1.0 + static_cast((l_lk_bytes * 8.0) + l_ds_bits) / 104.0); if (l_dk_bits != check_l_dk) { - std::cout << "Galileo OSNMA: Failed length reading" << std::endl; + LOG(ERROR) << "Galileo OSNMA: Failed length reading" << std::endl; } else { @@ -439,8 +440,8 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // Check that the padding bits received match the computed values if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { - LOG(WARNING) << "Galileo OSNMA: DSM-KROOT message received ok."; - std::cout << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) + LOG(INFO) << "Galileo OSNMA: DSM-KROOT message received ok."; + LOG(INFO) << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 << std::endl; @@ -448,20 +449,22 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_kroot_verified = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); if (d_kroot_verified) { - std::cout << "Galileo OSNMA: KROOT authentication successful !" << std::endl; - std::cout << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " + LOG(INFO) << "Galileo OSNMA: KROOT authentication successful !" << std::endl; + LOG(INFO) << "Galileo OSNMA: KROOT authentication successful !" << std::endl; + LOG(INFO) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; } else { - std::cout << " Galileo OSNMA: KROOT authentication failed. " << std::endl; + LOG(ERROR) << "Galileo OSNMA: KROOT authentication failed. " << std::endl; + LOG(INFO) << "Galileo OSNMA: KROOT authentication failed. " << std::endl; } } else { - std::cout << "Galileo OSNMA: Error computing padding bits." << std::endl; + LOG(ERROR) << "Galileo OSNMA: Error computing padding bits." << std::endl; // TODO - here will have to decide if perform the verification or not. Since this step is not mandatory, one could as well have skipped it. } } @@ -506,7 +509,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg uint32_t check_l_dp = 104 * std::ceil(static_cast(1040.0 + l_npk * 8.0) / 104.0); if (l_dp != check_l_dp) { - std::cout << "Galileo OSNMA: Failed length reading" << std::endl; + LOG(ERROR) << "Galileo OSNMA: Failed length reading" << std::endl; } else { @@ -516,7 +519,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; } // std::vector mi; // (NPKT + NPKID + NPK) - std::cout << "Galileo OSNMA: DSM-PKR with CID=" << static_cast(d_osnma_data.d_nma_header.cid) + LOG(INFO) << "Galileo OSNMA: DSM-PKR with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 @@ -564,8 +567,11 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr(16); + if (d_kroot_verified || d_tesla_key_verified || d_osnma_data.d_dsm_kroot_message.ts != 0 /*mack parser needs to know the tag size, otherwise cannot parse mack messages*/) // C: 4 ts < ts < 10 { // TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future read_mack_header(); read_mack_body(); @@ -838,14 +844,15 @@ void osnma_msg_receiver::read_mack_body() */ void osnma_msg_receiver::process_mack_message() { - d_flag_debug = true; - if(d_kroot_verified == false && d_tesla_key_verified == false) { - std::cerr << "Galileo OSNMA: MACK cannot be processed. "<< ", " + LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed. "<< ", " << "No Kroot nor TESLA key available" << std::endl; - if(!d_flag_debug) - return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. + if(!d_flag_debug){ + return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. + } + else + LOG(WARNING) << "But it will be processed for debugging purposes."; } // verify tesla key and add it to the container of verified keys if successful bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key, d_osnma_data.d_nav_data.TOW_sf0); @@ -863,6 +870,7 @@ void osnma_msg_receiver::process_mack_message() { Tag t(tag, mack->TOW, mack->PRNa); d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; } mack = d_macks_awaiting_MACSEQ_verification.erase(mack); } @@ -892,7 +900,7 @@ void osnma_msg_receiver::process_mack_message() if(ret) { it.second.status = Tag::SUCCESS; - std::cout << "Galileo OSNMA: Tag verification failure for tag Id= " + LOG(WARNING) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id= " << it.second.tag_id << ", TOW=" << it.second.TOW @@ -909,7 +917,7 @@ void osnma_msg_receiver::process_mack_message() else { it.second.status = Tag::FAIL; - std::cout << "Galileo OSNMA: Tag verification failure for tag Id= " + LOG(ERROR) << "Galileo OSNMA: Tag verification failure for tag Id= " << it.second.tag_id << ", TOW=" << it.second.TOW @@ -921,7 +929,7 @@ void osnma_msg_receiver::process_mack_message() } } else { - std::cout << "Galileo OSNMA: Tag verification skipped for Tag Id= " + LOG(INFO) << "Galileo OSNMA: Tag verification skipped for Tag Id= " << it.second.tag_id << ", TOW=" << it.second.TOW @@ -929,7 +937,7 @@ void osnma_msg_receiver::process_mack_message() << static_cast(it.second.ADKD) << ", from satellite " << it.second.PRNa - << std::endl; + << " due to missing key or navData. "; } } @@ -973,12 +981,12 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) if(x_4 == d_crypto->getMerkleRoot()) { - std::cout << "Galileo OSNMA: DSM-PKR verified successfully! " << std::endl; + LOG(INFO) << "Galileo OSNMA: DSM-PKR verified successfully! " << std::endl; return true; } else { - std::cout << "Galileo OSNMA: DSM-PKR verification unsuccessful !" << std::endl; + LOG(INFO) << "Galileo OSNMA: DSM-PKR verification unsuccessful !" << std::endl; return false; } } @@ -1075,7 +1083,7 @@ void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const } //d_osnma_data[TOW] = crypto; // crypto d_satellite_nav_data[SV_ID][TOW] = data; // nav - std::cout << "Galileo OSNMA: added element, size is " << d_satellite_nav_data[SV_ID].size() << std::endl; + //std::cout << "Galileo OSNMA: added element, size is " << d_satellite_nav_data[SV_ID].size() << std::endl; } void osnma_msg_receiver::display_data() { @@ -1096,42 +1104,40 @@ void osnma_msg_receiver::display_data() bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TOW) { uint32_t num_of_hashes_needed; - uint32_t GST_SFi = d_receiver_time - 30; + uint32_t GST_SFi = d_receiver_time - 30; // GST of target key is to be used. std::vector hash; const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; - std::vector validated_key; + //std::vector validated_key; if(d_tesla_key_verified){ // have to go up to last verified key - validated_key = d_tesla_keys.rbegin()->second; + d_validated_key = d_tesla_keys.rbegin()->second; num_of_hashes_needed = (d_receiver_time - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key " << std::endl; + LOG(INFO) << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key " << std::endl; hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); } else{// have to go until Kroot - validated_key = d_osnma_data.d_dsm_kroot_message.kroot; - num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 ICD - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed up to Kroot " << std::endl; + d_validated_key = d_osnma_data.d_dsm_kroot_message.kroot; + num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 IC + LOG(INFO) << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed up to Kroot " << std::endl; hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); } - - if(hash.size() != key.size()) + // truncate hash + std::vector computed_key; + computed_key.reserve(key.size()); + for (uint16_t i = 0; i < key.size(); i++) { - std::cout << "Galileo OSNMA: Error during tesla key verification. " << std::endl; - return false; + computed_key.push_back(hash[i]); } - if (hash == validated_key) + if (computed_key == d_validated_key && num_of_hashes_needed > 0) { - std::cout << "Galileo OSNMA: tesla key verified successfully " << std::endl; + LOG(WARNING) << "Galileo OSNMA:: TESLA key verification :: SUCCESS! " << std::endl; d_tesla_keys.insert(std::pair(TOW,key)); d_tesla_key_verified = true; d_last_verified_key_GST = d_receiver_time; - // TODO - propagate result - // TODO - save current tesla key as latest one? propose a map with - // TODO - Tags Sequence Verification: check ADKD[i] follows MACLT sequence } - else{ - std::cerr << "Galileo OSNMA: Error during tesla key verification. " << std::endl; + else if(num_of_hashes_needed > 0){ + LOG(ERROR) << "Galileo OSNMA:: TESLA key verification :: FAILED " << std::endl; if(d_flag_debug){ d_tesla_keys.insert(std::pair(TOW,key)); d_last_verified_key_GST = d_receiver_time; @@ -1152,7 +1158,7 @@ void osnma_msg_receiver::remove_verified_tags() for (auto it = d_tags_awaiting_verify.begin(); it != d_tags_awaiting_verify.end() ; ){ if (it->second.status == Tag::SUCCESS || it->second.status == Tag::FAIL) { - std::cout << "Galileo OSNMA: delete tag for tag Id= " + LOG(INFO) << "Galileo OSNMA: delete tag for tag Id= " << it->second.tag_id << ", PRN_a= " << it->second.PRNa << ", TOW=" << it->second.TOW << ", ADKD= " @@ -1176,6 +1182,7 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() { while(d_tags_awaiting_verify.size() > 60) { + LOG(WARNING) << "Galileo OSNMA: delete tag due to exceeding buffer size. "; d_tags_awaiting_verify.erase(d_tags_awaiting_verify.begin()); } } @@ -1214,11 +1221,11 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) } else { - std::cout << "Galileo OSNMA: Mismatch in the GST verification. " << std::endl; + LOG(ERROR) << "Galileo OSNMA: Mismatch in the GST verification. " << std::endl; } if(mack.tag_and_info.size() != applicable_sequence.size() - 1) { - std::cout << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; + LOG(ERROR) << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; return false; } std::vector flxTags {}; @@ -1232,11 +1239,16 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) flxTags.push_back(i); // C: just need to save the index in the sequence } else if(mack.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i+1])) - { std::cout << "Galileo OSNMA: Unsuccessful verification of MACSEQ - received ADKD against MAC Look-up table. " << std::endl; + { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: ADKD mismatch against MAC Look-up table. " << std::endl; return false; // C: suffices one incorrect to abort and not process the rest of the tags } } + if(flxTags.empty()){ + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: ADKD matches MAC Look-up table. " << std::endl; + return true; + } // Fixed as well as FLX Tags share first part - Eq. 22 ICD std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag @@ -1272,17 +1284,23 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) mac_msb = (mac[0] << 8) + mac[1]; } uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; - if (computed_macseq == mack.header.macseq && !flxTags.empty()) - return true; - else - return false; + if (computed_macseq == mack.header.macseq){ + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK " << std::endl; + return true; + } + + else{ + LOG(ERROR) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: FLX tags verification failed " << std::endl; + return false; + } + } bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) { auto prn_it = d_satellite_nav_data.find(t.PRNa); if (prn_it != d_satellite_nav_data.end()) { // PRN was found, check if TOW exists in inner map - std::cout << "Galileo OSNMA: hasData = true " << std::endl; + LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; std::map& tow_map = prn_it->second; auto tow_it = tow_map.find(t.TOW); if (tow_it != tow_map.end()) { @@ -1293,7 +1311,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) } } else { // PRN was not found - std::cout << "Galileo OSNMA: hasData = false " << std::endl; + LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; return false; } return false; @@ -1309,7 +1327,7 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t){ auto it = d_tesla_keys.find(t.TOW + 30); if (it != d_tesla_keys.end()) { - std::cout << "Galileo OSNMA: hasKey = true " << std::endl; + LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; return true; } } @@ -1318,19 +1336,18 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t){ auto it = d_tesla_keys.find(t.TOW + 300); if (it != d_tesla_keys.end()) { - std::cout << "Galileo OSNMA: hasKey = true " << std::endl; + LOG(INFO)<< "Galileo OSNMA: hasKey = true " << std::endl; return true; } } - std::cout << "Galileo OSNMA: hasKey = false " << std::endl; + LOG(INFO) << "Galileo OSNMA: hasKey = false " << std::endl; return false; } std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes) { auto start = std::chrono::high_resolution_clock::now(); - std::vector K_II = {0x2D,0xC3,0xA3,0xCD,0xB1,0x17,0xFA,0xAD,0xB8,0x3B,0x5F,0x0B,0x6F,0xEA,0x88,0xEB};//key; + std::vector K_II = key; std::vector K_I; // result of the recursive hash operations - GST_SFi = 0x4E054600; std::vector msg; // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) for (uint32_t i = 1; i <= num_of_hashes_needed ; i++) @@ -1343,8 +1360,8 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede msg.push_back((GST_SFi & 0x00FF0000) >> 16); msg.push_back((GST_SFi & 0x0000FF00) >> 8); msg.push_back(GST_SFi & 0x000000FF); - // extract alpha - d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; + // extract alpha +// d_osnma_data.d_dsm_kroot_message.alpha = 0xa06221261ad9; for (int k = 5; k >= 0;k--) { // TODO: static extracts the MSB in case from larger to shorter int? @@ -1376,11 +1393,20 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede K_I.clear(); // empty the actual one for a new computation msg.clear(); } - if(GST_SFi + 30 != d_GST_0 - 30 && d_tesla_key_verified == false) - std::cout << "Galileo OSNMA: TESLA verification error. Kroot time mismatch! \n"; // ICD. Eq. 18 + + // check that the final time matches the Kroot time + bool check; + if(!d_tesla_key_verified) + check = GST_SFi + 30 == d_GST_0 - 30; + else + check = GST_SFi + 30 == d_last_verified_key_GST; + if(!check) + LOG(ERROR) << "Galileo OSNMA: TESLA verification error. Kroot time mismatch! \n"; // ICD. Eq. 18 + else + LOG(INFO) << "Galileo OSNMA: TESLA verification. Kroot time matches! \n"; // ICD. Eq. 18 // compare computed current key against received key auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = end - start; - std::cout << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; + LOG(INFO) << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; return K_II; } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 9f3c76fec..157c78750 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -113,6 +113,7 @@ private: enum tags_to_verify{all,utc,slow_eph, eph, none}; // TODO is this safe? I hope so tags_to_verify d_tags_allowed{tags_to_verify::all}; std::vector d_tags_to_verify{0,4,12}; + std::vector d_validated_key{}; void remove_verified_tags(); void control_tags_awaiting_verify_size(); bool verify_macseq(const MACK_message& mack); From b687d4cafe82957ceec56bfe9bb8366bc38d1153 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 6 May 2024 17:52:07 +0200 Subject: [PATCH 102/219] Bugfix for Gnss_Crypto::verify_signature The commit introduces conversion from raw signature (r, s values) into DER format for the ossl3 region, after realising that that was making the verification fail. --- src/core/system_parameters/gnss_crypto.cc | 52 ++++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index f55b5f609..d3cd11380 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include #define OPENSSL_ENGINE nullptr #else #include @@ -490,7 +493,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) gnutls_pubkey_deinit(pubkey); #endif std::cout << "Public key successfully read from file " << pemFilePath << std::endl; - print_pubkey_hex(d_PublicKey); + //print_pubkey_hex(d_PublicKey); } @@ -545,7 +548,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st #if USE_OPENSSL_3 EVP_PKEY_CTX* ctx; - print_pubkey_hex(d_PublicKey); + //print_pubkey_hex(d_PublicKey); ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); bool do_operation = true; @@ -553,6 +556,42 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st { do_operation = false; } + // convert raw signature into DER format, needed for verify_signature + size_t half_size = signature.size() / 2; + std::vector raw_r(signature.begin(), signature.begin() + half_size); + std::vector raw_s(signature.begin() + half_size, signature.end()); + + // Convert raw R and S to BIGNUMs + BIGNUM* r = BN_bin2bn(raw_r.data(), raw_r.size(), nullptr); + BIGNUM* s = BN_bin2bn(raw_s.data(), raw_s.size(), nullptr); + + ECDSA_SIG* sig = ECDSA_SIG_new(); + if (r == nullptr || s == nullptr || sig == nullptr) + { + std::cerr << "Failed to allocate memory for BIGNUMs or ECDSA_SIG" << std::endl; + return false; + } + + if (ECDSA_SIG_set0(sig, r, s) != 1) + { + std::cerr << "Failed to set R and S values in ECDSA_SIG" << std::endl; + ECDSA_SIG_free(sig); // Free the ECDSA_SIG struct as it's no longer needed + return false; + } + + std::vector derSignature; + unsigned char *derSig = nullptr; + int derSigLength = i2d_ECDSA_SIG(sig, &derSig); + + if (derSigLength <= 0) + { + std::cerr << "Failed to convert ECDSA_SIG to DER format" << std::endl; + return false; + } + + derSignature.assign(derSig, derSig + derSigLength); + + if (EVP_PKEY_verify_init(ctx) <= 0) { do_operation = false; @@ -564,9 +603,11 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st int verification = 0; if (do_operation) { - verification = EVP_PKEY_verify(ctx, signature.data(), signature.size(), digest.data(), digest.size()); + verification = EVP_PKEY_verify(ctx, derSignature.data(), derSignature.size(), digest.data(), digest.size()); } EVP_PKEY_CTX_free(ctx); + OPENSSL_free(derSig); + ECDSA_SIG_free(sig); if (verification == 1) { success = true; @@ -682,7 +723,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) << ". Aborting import" << std::endl; return; } - print_pubkey_hex(pkey); + //print_pubkey_hex(pkey); if(!pubkey_copy(pkey, &d_PublicKey)) return @@ -736,7 +777,6 @@ std::vector Gnss_Crypto::get_public_key() return {}; } - #if USE_OPENSSL_FALLBACK bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) { @@ -809,7 +849,7 @@ void Gnss_Crypto::print_pubkey_hex(EVP_PKEY* pubkey) static_cast(static_cast(mem_ptr->data[i])); } - std::cout << "Public key in hex format: 0x" << ss.str() << std::endl; + //std::cout << "Public key in hex format: 0x" << ss.str() << std::endl; BIO_free(mem_bio); } From dd2f15302392f7800dcb34530c6f41fe081e5686 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 6 May 2024 17:53:13 +0200 Subject: [PATCH 103/219] Bugfix for OSNMA_DSM_Reader::get_alpha This commit fixes a bug in the parsing of the DSM-Kroot alpha parameter. --- src/core/system_parameters/osnma_dsm_reader.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/system_parameters/osnma_dsm_reader.cc b/src/core/system_parameters/osnma_dsm_reader.cc index 8a2a061d9..65caddd51 100644 --- a/src/core/system_parameters/osnma_dsm_reader.cc +++ b/src/core/system_parameters/osnma_dsm_reader.cc @@ -128,12 +128,12 @@ uint8_t OSNMA_DSM_Reader::get_towh_k(const std::vector& dsm_msg) const uint64_t OSNMA_DSM_Reader::get_alpha(const std::vector& dsm_msg) const { - uint64_t alpha = (static_cast(dsm_msg[8]) << 40) + - (static_cast(dsm_msg[9]) << 32) + - (static_cast(dsm_msg[10]) << 24) + - (static_cast(dsm_msg[11]) << 16) + - (static_cast(dsm_msg[12]) << 8) + - (static_cast(dsm_msg[13])); + uint64_t alpha = (static_cast(dsm_msg[7]) << 40) + + (static_cast(dsm_msg[8]) << 32) + + (static_cast(dsm_msg[9]) << 24) + + (static_cast(dsm_msg[10]) << 16) + + (static_cast(dsm_msg[11]) << 8) + + (static_cast(dsm_msg[12])); return alpha; } From 38829adaafff07a10fdbfba9cf4e1d9fc509cef0 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 6 May 2024 17:55:11 +0200 Subject: [PATCH 104/219] GnssCryptoTest :: introduce raw r and s values signature. This was done after bugfix for verify_signature. --- .../osnma/gnss_crypto_test.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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 b0ecaf2cc..d78c8d688 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 @@ -23,10 +23,17 @@ TEST(GnssCryptoTest, VerifySignature) { // own ECDSA-P256 key and message generated and signed and verified successfully with openssl std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message (unhashed) - std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, - 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, - 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK -// std::vector publicKey{// PK associated to the PrK, in der format ---test +// std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, +// 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, +// 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK + // raw r and s values + std::vector signature = { + 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, + 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, + 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, + 0xA5, 0xB9, 0xB2, 0x56 }; + + // std::vector publicKey{// PK associated to the PrK, in der format ---test // 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4A, 0xF3, // 0xEE, 0x3A, 0x94, 0x25, 0x25, 0x3D, 0x55, 0xC2, 0x5A, 0xC2, 0x2D, 0xCF, 0x14, 0x4D, 0x39, 0x0D, 0xB1, 0xFC, 0x7F, 0x31, 0x5A, 0x2A, 0x19, 0xAE, 0x4E, 0xD6, 0xCB, 0xA6, 0x59, // 0xD6, 0x99, 0x7C, 0xE8, 0xBD, 0x1F, 0x43, 0x34, 0x1C, 0x59, 0xD9, 0xD9, 0xCA, 0xC3, 0xEE, 0x58, 0xE5, 0xEA, 0xD3, 0x55, 0x44, 0xEA, 0x89, 0x71, 0x65, 0xD0, 0x92, 0x72, 0xA2, From c9259d87db63e936ae5bcb472ce2c29b043578e9 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 6 May 2024 17:58:56 +0200 Subject: [PATCH 105/219] Refactored and improved OsnmaMsgReceiverTest Changes in the osnma receiver initialisation for time synchronisation with the configuration 1. OsnmaMsgReceiverTest::initializeGoogleLog() implemented recycling code, in the same way as the gnss-sdr receiver upon start. --- .../osnma/osnma_msg_receiver_test.cc | 111 ++++++++++++++---- 1 file changed, 87 insertions(+), 24 deletions(-) diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 047832490..65dd98006 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -1,8 +1,10 @@ #include +#include +#include #include +#include #include #include -#include struct TestVector @@ -23,10 +25,13 @@ protected: OSNMA_msg osnma_msg{}; std::array nma_position_filled; uint32_t d_GST_SIS{}; // 16 AUG 2023 05 00 01 - int T {}; uint32_t TOW{}; uint32_t WN{}; + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm + const uint32_t LEAP_SECONDS = 0;//13 + 5; void set_time(std::tm& input); + std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; + void initializeGoogleLog(); void SetUp() override { @@ -39,6 +44,9 @@ protected: std::string merkleFilePath = "OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); } + void TearDown() override{ + google::ShutdownGoogleLogging(); + } public: static std::vector parseNavBits(const std::string& hex); @@ -51,19 +59,28 @@ public: TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Arrange osnma->d_tesla_key_verified = false; - osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; + osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits - osnma->d_receiver_time = 345630; - osnma->d_GST_0 = 345600; - osnma->d_tesla_keys.insert((std::pair>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); - std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; + osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; + // local_time_verification would do this operation. TODO - eliminate duplication. + osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); + osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; + + osnma->d_tesla_keys.insert((std::pair>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. + std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 uint32_t TOW = 345630; + // Act bool result = osnma->verify_tesla_key(key, TOW); + + + + // Assert ASSERT_TRUE(result); // Adjust this according to what you expect @@ -71,6 +88,7 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) { + initializeGoogleLog(); // Arrange std::vector testVectors = readTestVectorsFromFile(/*"/home/cgm/CLionProjects/osnma/src/tests/data/*/"16_AUG_2023_GST_05_00_01.csv"); bool end_of_hex_stream{false}; @@ -81,11 +99,9 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; const int DURATION_SUBFRAME{30}; - std::cout << "OsnmaTestVectorsSimulation:" << std::endl; - std::cout << "d_GST_SIS: " << d_GST_SIS << std::endl; - std::cout << "T: " << T << std::endl; - std::cout << "TOW: " << TOW << std::endl; - std::cout << "WN: " << WN << std::endl; + std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; // Act @@ -144,14 +160,11 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) if(!end_of_hex_stream){ offset_byte = byte_index; // update offset for the next subframe d_GST_SIS += DURATION_SUBFRAME; - T = d_GST_SIS % 30; TOW = d_GST_SIS & 0x000FFFFF; WN = (d_GST_SIS & 0xFFF00000) >> 20 ; - std::cout << "OsnmaTestVectorsSimulation:" << std::endl; - std::cout << "d_GST_SIS: " << d_GST_SIS << std::endl; - std::cout << "T: " << T << std::endl; - std::cout << "TOW: " << TOW << std::endl; - std::cout << "WN: " << WN << std::endl; + std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; } @@ -239,12 +252,20 @@ std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& return extracted_bytes; } +/** + * @brief Sets the time based on the given input. + * + * This function calculates the week number (WN) and time of week (TOW) + * based on the input time and the GST_START_EPOCH. It then stores the + * calculated values in the WN and TOW member variables. Finally, it + * combines the WN and TOW into a single 32-bit value and stores it in + * the d_GST_SIS member variable. + * + * @param input The input time as a tm struct. + */ void OsnmaMsgReceiverTest::set_time(std::tm& input) { - // GST epoch (start of GST time) - std::tm tm_epoch = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; - - auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&tm_epoch)); + auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH)); auto input_time_point = std::chrono::system_clock::from_time_t(mktime(&input)); // Get the duration from epoch in seconds @@ -255,11 +276,53 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) uint32_t week_number = duration_sec.count() / sec_in_week; uint32_t time_of_week = duration_sec.count() % sec_in_week; this->WN = week_number; - this->TOW = time_of_week; + this->TOW = time_of_week + LEAP_SECONDS; // Return the week number and time of week as a pair this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); - this->T = d_GST_SIS % 30; } + +void OsnmaMsgReceiverTest::initializeGoogleLog() +{ + google::InitGoogleLogging(log_name.c_str()); + FLAGS_minloglevel = 1; + FLAGS_logtostderr = 0; // add this line + FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; + if (FLAGS_log_dir.empty()) + { + std::cout << "Logging will be written at " + << std::filesystem::temp_directory_path() + << '\n' + << "Use gnss-sdr --log_dir=/path/to/log to change that.\n"; + } + else + { + try + { + const std::filesystem::path p(FLAGS_log_dir); + if (!std::filesystem::exists(p)) + { + std::cout << "The path " + << FLAGS_log_dir + << " does not exist, attempting to create it.\n"; + std::error_code ec; + if (!std::filesystem::create_directory(p, ec)) + { + std::cout << "Could not create the " << FLAGS_log_dir << " folder.\n"; + gflags::ShutDownCommandLineFlags(); + throw std::runtime_error("Could not create folder for logs"); + } + } + std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; + } + catch (const std::exception& e) + { + std::cerr << e.what() << '\n'; + std::cerr << "Could not create the " << FLAGS_log_dir << " folder.\n"; + gflags::ShutDownCommandLineFlags(); + throw; + } + } +} \ No newline at end of file From f3a204fec69c9c93873772dcd449ce28c796acdf Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sun, 12 May 2024 11:05:20 +0200 Subject: [PATCH 106/219] =?UTF-8?q?[TAS-174]=20retrieve=20NavData=20(W1?= =?UTF-8?q?=E2=86=92W5)=20directly=20from=20osnma=20test=20vector=20file.?= =?UTF-8?q?=20Add=20Osnma=5FHelper=20class.=20remove=20tag.build=5Fmessage?= =?UTF-8?q?.=20Ignore=20W33.=20Reporting=20changes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/libs/osnma_msg_receiver.cc | 87 +++++++++++-------- src/core/libs/osnma_msg_receiver.h | 2 + src/core/system_parameters/CMakeLists.txt | 2 + .../system_parameters/galileo_inav_message.h | 3 +- src/core/system_parameters/osnma_data.cc | 8 +- src/core/system_parameters/osnma_data.h | 13 ++- src/core/system_parameters/osnma_helper.cc | 34 ++++++++ src/core/system_parameters/osnma_helper.h | 33 +++++++ 8 files changed, 136 insertions(+), 46 deletions(-) create mode 100644 src/core/system_parameters/osnma_helper.cc create mode 100644 src/core/system_parameters/osnma_helper.h diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 1c1da25a9..29f896f8b 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -22,6 +22,7 @@ #include "gnss_crypto.h" #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader +#include "osnma_helper.h" #include // for DLOG #include // for gr::io_signature::make #include @@ -60,6 +61,7 @@ osnma_msg_receiver::osnma_msg_receiver( { d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(pemFilePath, merkleFilePath); + d_helper = std::make_unique(); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -89,14 +91,13 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) { const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); - LOG(INFO) << "Galileo OSNMA: Subframe received starting at " + LOG(WARNING) << "Galileo OSNMA: Subframe received starting at " << "WN=" << nma_msg->WN_sf0 << ", TOW=" << nma_msg->TOW_sf0 << ", from satellite " - << sat - << std::endl; + << sat; process_osnma_message(nma_msg); @@ -127,7 +128,10 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& { read_nma_header(osnma_msg->hkroot[0]); if(d_osnma_data.d_nma_header.nmas == 0 || d_osnma_data.d_nma_header.nmas == 3 /*&& d_kroot_verified*/) - return; + { + LOG(ERROR) << "Galileo OSNMA: NMAS invalid, skipping osnma message\n"; + return; + } 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 @@ -574,6 +578,9 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrPRN; // FIXME this is ugly. + d_osnma_data.d_mack_message.TOW = osnma_msg->TOW_sf0; + d_osnma_data.d_mack_message.WN = osnma_msg->WN_sf0; read_mack_body(); process_mack_message(); // TODO - shorten the MACK processing for the cases where no TK verified or no Kroot verified (warm and cold start) @@ -649,8 +656,6 @@ void osnma_msg_receiver::read_mack_header() d_osnma_data.d_mack_message.header.tag0 = first_lt_bits; d_osnma_data.d_mack_message.header.macseq = macseq; d_osnma_data.d_mack_message.header.cop = cop; - d_osnma_data.d_mack_message.PRNa = d_osnma_data.d_nav_data.PRNa; // FIXME this is ugly. - d_osnma_data.d_mack_message.TOW = d_osnma_data.d_nav_data.TOW_sf0; } /** @@ -866,9 +871,10 @@ void osnma_msg_receiver::process_mack_message() if(d_tesla_keys.find(mack->TOW + 30) != d_tesla_keys.end()){ bool ret = verify_macseq(*mack); if (ret || d_flag_debug){ - for(auto& tag:mack->tag_and_info) + for(std::size_t i = 0; i < mack->tag_and_info.size(); ++i) { - Tag t(tag, mack->TOW, mack->PRNa); + auto& tag = mack->tag_and_info[i]; + Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; } @@ -992,7 +998,43 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) } bool osnma_msg_receiver::verify_tag(Tag& tag) { - std::vector m = tag.build_message(); + // build message + std::vector m; + m.push_back(static_cast(tag.PRN_d)); + m.push_back(static_cast(tag.PRNa)); + uint32_t GST = d_helper->compute_gst(tag.TOW, tag.WN); + std::vector GST_uint8 = d_helper->gst_to_uint8(GST); + m.insert(m.end(),GST_uint8.begin(),GST_uint8.end()); + m.push_back(tag.CTR); + // Extracts only two bits from d_osnma_data.d_nma_header.nmas + uint8_t two_bits_nmas = d_osnma_data.d_nma_header.nmas & 0b00000011; + two_bits_nmas = two_bits_nmas << 6; + m.push_back(two_bits_nmas); + + // convert std::string to vector + std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.TOW][tag.PRNa].ephemeris_iono_vector_2; + std::vector ephemeris_iono_vector_2_bytes(ephemeris_iono_vector_2.begin(), ephemeris_iono_vector_2.end()); + + // Convert and add ephemeris_iono_vector_2 into the vector + for (uint8_t byte : ephemeris_iono_vector_2_bytes) { + m.back() |= (byte >> 2); // First take the 6 MSB bits of byte and add to m + m.push_back(byte << 6); // Then take the last 2 bits of byte, shift them to MSB position and insert the new element into m + } + if(m.back() == 0) { + m.pop_back(); // Remove the last element if its value is 0 (only padding was added) + } + else { + // Pad with zeros if the last element wasn't full + for (int bits = 2; bits < 8; bits += 2) { + // Check if the last element in the vector has 2 '00' bits in its LSB position + if((m.back() & 0b00000011) == 0) { + m.back() <<= 2; // Shift the existing bits to make room for new 2 bits + } + else { + break; // If it does not have 2 '00' bits in its LSB position, then the padding is complete + } + } + } std::vector mac; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 @@ -1044,36 +1086,9 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) // Compare computed tag with received one truncated if (tag.received_tag == computed_mac) - { -// if(tag.ADKD == 0 || tag.ADKD == 12) -// { -// std::cout << "Galileo OSNMA: tag verification successful for PRN_a " -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " -// << "Ephemeris, Clock and Ionospheric data" << ". " -// << std::endl; -// } -// else if(tag.ADKD == 4) -// { -// std::cout << "Galileo OSNMA: tag verification successful for PRN_a " -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " -// << "Timing data" << ". " -// << std::endl; -// } return true; - - } else - { -// std::cout << "Galileo OSNMA: Tag verification failed for PRN_a " -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << std::endl; return false; - } } void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 157c78750..8137c9824 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -40,6 +40,7 @@ friend class test_case_name##_##test_name##_Test class OSNMA_DSM_Reader; class Gnss_Crypto; +class Osnma_Helper; class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; @@ -88,6 +89,7 @@ private: std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; + std::unique_ptr d_helper; std::array, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself. std::array, 16> d_dsm_id_received{}; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 4c6e9fb20..46c5fb4b7 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -96,6 +96,8 @@ set(SYSTEM_PARAMETERS_HEADERS Galileo_OSNMA.h osnma_data.h osnma_dsm_reader.h + osnma_helper.cc + osnma_helper.h ) list(SORT SYSTEM_PARAMETERS_HEADERS) diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 13db80706..0e9c15b25 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -51,7 +51,8 @@ public: uint32_t PRN{}; uint32_t WN_sf0{}; // TODO - this is present in UtcModelData already uint32_t TOW_sf0{}; - std::vector EphemerisClockAndStatusData {}; + std::vector EphemerisClockAndStatusData {}; // TODO _2 rename and substitute this + std::string EphemerisClockAndStatusData_2{}; std::vector TimingData {}; Galileo_Ephemeris EphemerisData {}; Galileo_Iono IonoData {}; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 65145ae16..25124bb81 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -35,6 +35,9 @@ void NavData::init(const std::shared_ptr &osnma_msg) PRNa = osnma_msg->PRN; WN_sf0 = osnma_msg->WN_sf0; TOW_sf0 = osnma_msg->TOW_sf0; + + // new parsing, directly parsing bits + ephemeris_iono_vector_2 = osnma_msg->EphemerisClockAndStatusData_2; }; void NavData::generate_eph_iono_vector() { @@ -166,8 +169,3 @@ void NavData::generate_utc_vector() } } -std::vector Tag::build_message() -{ - // TODO - return std::vector(); -} diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 121853d2a..6e3439a4c 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -121,7 +121,8 @@ public: MACK_header header; std::vector tag_and_info; std::vector key; - uint32_t TOW; // TODO duplicated variable + uint32_t TOW; // TODO duplicated variable, also in NavData + uint32_t WN; uint32_t PRNa; }; @@ -131,6 +132,7 @@ public: NavData()=default; void init(const std::shared_ptr &osnma_msg); std::vector ephemeris_iono_vector{}; + std::string ephemeris_iono_vector_2{}; std::vector utc_vector{}; uint32_t PRNa{}; uint32_t WN_sf0{}; @@ -168,10 +170,12 @@ public: SUCCESS, FAIL, UNVERIFIED}; - Tag(const MACK_tag_and_info& MTI, uint32_t TOW, uint32_t PRNa) + Tag(const MACK_tag_and_info& MTI, uint32_t TOW,uint32_t WN, uint32_t PRNa,uint8_t CTR) : tag_id(id_counter++), - TOW(TOW), + TOW(TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, NavData missing + WN(WN), PRNa(PRNa), + CTR(CTR), status(UNVERIFIED), received_tag(MTI.tag), computed_tag(0), @@ -184,10 +188,11 @@ public: const uint32_t tag_id; uint32_t TOW; + uint32_t WN; uint32_t PRNa; + uint8_t CTR; e_verification_status status; uint64_t received_tag; - std::vector build_message(); uint32_t static id_counter; uint64_t computed_tag; diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc new file mode 100644 index 000000000..462fd5d34 --- /dev/null +++ b/src/core/system_parameters/osnma_helper.cc @@ -0,0 +1,34 @@ +/*! +* \file osnma_helper.h +* \brief Class for auxiliary osnma functions +* \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es +* +* ----------------------------------------------------------------------------- +* +* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +* This file is part of GNSS-SDR. +* +* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) +* SPDX-License-Identifier: GPL-3.0-or-later +* +* ----------------------------------------------------------------------------- + */ + +#include "osnma_helper.h" + +uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const +{ + uint32_t GST = (WN & 0x00000FFF) << 20 | (TOW & 0x000FFFFF); + return GST; +} + +std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const +{ + std::vector res(4); + + res[1] = static_cast((GST & 0xFF000000) >> 24); + res[2] = static_cast((GST & 0x00FF0000) >> 16); + res[3] = static_cast((GST & 0x0000FF00) >> 8); + res[4] = static_cast(GST & 0x000000FF); + return res; +} diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h new file mode 100644 index 000000000..0a1b72270 --- /dev/null +++ b/src/core/system_parameters/osnma_helper.h @@ -0,0 +1,33 @@ +/*! +* \file osnma_helper.h +* \brief Class for auxiliary osnma functions +* \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es +* +* ----------------------------------------------------------------------------- +* +* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +* This file is part of GNSS-SDR. +* +* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) +* SPDX-License-Identifier: GPL-3.0-or-later +* +* ----------------------------------------------------------------------------- +*/ + +#ifndef GNSS_SDR_OSNMA_HELPER_H +#define GNSS_SDR_OSNMA_HELPER_H + + +#include +#include +class Osnma_Helper +{ +public: + Osnma_Helper() = default; + ~Osnma_Helper() = default; + uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; + std::vector gst_to_uint8(uint32_t GST) const; +}; + + +#endif // GNSS_SDR_OSNMA_HELPER_H From a3a5f28e7f27826edea9b83f84e412967915eacc Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sun, 12 May 2024 11:05:20 +0200 Subject: [PATCH 107/219] =?UTF-8?q?[TAS-174]=20retrieve=20NavData=20(W1?= =?UTF-8?q?=E2=86=92W5)=20directly=20from=20osnma=20test=20vector=20file.?= =?UTF-8?q?=20Add=20Osnma=5FHelper=20class.=20remove=20tag.build=5Fmessage?= =?UTF-8?q?.=20Ignore=20W33.=20Reporting=20changes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/libs/osnma_msg_receiver.cc | 87 ++++++++++------- src/core/libs/osnma_msg_receiver.h | 2 + src/core/system_parameters/CMakeLists.txt | 2 + .../system_parameters/galileo_inav_message.h | 3 +- src/core/system_parameters/osnma_data.cc | 8 +- src/core/system_parameters/osnma_data.h | 13 ++- src/core/system_parameters/osnma_helper.cc | 34 +++++++ src/core/system_parameters/osnma_helper.h | 33 +++++++ .../osnma/osnma_msg_receiver_test.cc | 97 ++++++++++++++++++- 9 files changed, 230 insertions(+), 49 deletions(-) create mode 100644 src/core/system_parameters/osnma_helper.cc create mode 100644 src/core/system_parameters/osnma_helper.h diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 1c1da25a9..29f896f8b 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -22,6 +22,7 @@ #include "gnss_crypto.h" #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader +#include "osnma_helper.h" #include // for DLOG #include // for gr::io_signature::make #include @@ -60,6 +61,7 @@ osnma_msg_receiver::osnma_msg_receiver( { d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(pemFilePath, merkleFilePath); + d_helper = std::make_unique(); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -89,14 +91,13 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) { const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); - LOG(INFO) << "Galileo OSNMA: Subframe received starting at " + LOG(WARNING) << "Galileo OSNMA: Subframe received starting at " << "WN=" << nma_msg->WN_sf0 << ", TOW=" << nma_msg->TOW_sf0 << ", from satellite " - << sat - << std::endl; + << sat; process_osnma_message(nma_msg); @@ -127,7 +128,10 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& { read_nma_header(osnma_msg->hkroot[0]); if(d_osnma_data.d_nma_header.nmas == 0 || d_osnma_data.d_nma_header.nmas == 3 /*&& d_kroot_verified*/) - return; + { + LOG(ERROR) << "Galileo OSNMA: NMAS invalid, skipping osnma message\n"; + return; + } 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 @@ -574,6 +578,9 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrPRN; // FIXME this is ugly. + d_osnma_data.d_mack_message.TOW = osnma_msg->TOW_sf0; + d_osnma_data.d_mack_message.WN = osnma_msg->WN_sf0; read_mack_body(); process_mack_message(); // TODO - shorten the MACK processing for the cases where no TK verified or no Kroot verified (warm and cold start) @@ -649,8 +656,6 @@ void osnma_msg_receiver::read_mack_header() d_osnma_data.d_mack_message.header.tag0 = first_lt_bits; d_osnma_data.d_mack_message.header.macseq = macseq; d_osnma_data.d_mack_message.header.cop = cop; - d_osnma_data.d_mack_message.PRNa = d_osnma_data.d_nav_data.PRNa; // FIXME this is ugly. - d_osnma_data.d_mack_message.TOW = d_osnma_data.d_nav_data.TOW_sf0; } /** @@ -866,9 +871,10 @@ void osnma_msg_receiver::process_mack_message() if(d_tesla_keys.find(mack->TOW + 30) != d_tesla_keys.end()){ bool ret = verify_macseq(*mack); if (ret || d_flag_debug){ - for(auto& tag:mack->tag_and_info) + for(std::size_t i = 0; i < mack->tag_and_info.size(); ++i) { - Tag t(tag, mack->TOW, mack->PRNa); + auto& tag = mack->tag_and_info[i]; + Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; } @@ -992,7 +998,43 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) } bool osnma_msg_receiver::verify_tag(Tag& tag) { - std::vector m = tag.build_message(); + // build message + std::vector m; + m.push_back(static_cast(tag.PRN_d)); + m.push_back(static_cast(tag.PRNa)); + uint32_t GST = d_helper->compute_gst(tag.TOW, tag.WN); + std::vector GST_uint8 = d_helper->gst_to_uint8(GST); + m.insert(m.end(),GST_uint8.begin(),GST_uint8.end()); + m.push_back(tag.CTR); + // Extracts only two bits from d_osnma_data.d_nma_header.nmas + uint8_t two_bits_nmas = d_osnma_data.d_nma_header.nmas & 0b00000011; + two_bits_nmas = two_bits_nmas << 6; + m.push_back(two_bits_nmas); + + // convert std::string to vector + std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.TOW][tag.PRNa].ephemeris_iono_vector_2; + std::vector ephemeris_iono_vector_2_bytes(ephemeris_iono_vector_2.begin(), ephemeris_iono_vector_2.end()); + + // Convert and add ephemeris_iono_vector_2 into the vector + for (uint8_t byte : ephemeris_iono_vector_2_bytes) { + m.back() |= (byte >> 2); // First take the 6 MSB bits of byte and add to m + m.push_back(byte << 6); // Then take the last 2 bits of byte, shift them to MSB position and insert the new element into m + } + if(m.back() == 0) { + m.pop_back(); // Remove the last element if its value is 0 (only padding was added) + } + else { + // Pad with zeros if the last element wasn't full + for (int bits = 2; bits < 8; bits += 2) { + // Check if the last element in the vector has 2 '00' bits in its LSB position + if((m.back() & 0b00000011) == 0) { + m.back() <<= 2; // Shift the existing bits to make room for new 2 bits + } + else { + break; // If it does not have 2 '00' bits in its LSB position, then the padding is complete + } + } + } std::vector mac; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 @@ -1044,36 +1086,9 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) // Compare computed tag with received one truncated if (tag.received_tag == computed_mac) - { -// if(tag.ADKD == 0 || tag.ADKD == 12) -// { -// std::cout << "Galileo OSNMA: tag verification successful for PRN_a " -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " -// << "Ephemeris, Clock and Ionospheric data" << ". " -// << std::endl; -// } -// else if(tag.ADKD == 4) -// { -// std::cout << "Galileo OSNMA: tag verification successful for PRN_a " -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << "NavData= " -// << "Timing data" << ". " -// << std::endl; -// } return true; - - } else - { -// std::cout << "Galileo OSNMA: Tag verification failed for PRN_a " -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].PRNa << " with WN=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].WN_sf0 << ", TOW=" -// << d_satellite_nav_data[tag.PRN_d][tag.TOW-30].TOW_sf0 << std::endl; return false; - } } void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 157c78750..8137c9824 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -40,6 +40,7 @@ friend class test_case_name##_##test_name##_Test class OSNMA_DSM_Reader; class Gnss_Crypto; +class Osnma_Helper; class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; @@ -88,6 +89,7 @@ private: std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW std::unique_ptr d_dsm_reader; std::unique_ptr d_crypto; + std::unique_ptr d_helper; std::array, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself. std::array, 16> d_dsm_id_received{}; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 4c6e9fb20..46c5fb4b7 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -96,6 +96,8 @@ set(SYSTEM_PARAMETERS_HEADERS Galileo_OSNMA.h osnma_data.h osnma_dsm_reader.h + osnma_helper.cc + osnma_helper.h ) list(SORT SYSTEM_PARAMETERS_HEADERS) diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 13db80706..0e9c15b25 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -51,7 +51,8 @@ public: uint32_t PRN{}; uint32_t WN_sf0{}; // TODO - this is present in UtcModelData already uint32_t TOW_sf0{}; - std::vector EphemerisClockAndStatusData {}; + std::vector EphemerisClockAndStatusData {}; // TODO _2 rename and substitute this + std::string EphemerisClockAndStatusData_2{}; std::vector TimingData {}; Galileo_Ephemeris EphemerisData {}; Galileo_Iono IonoData {}; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 65145ae16..25124bb81 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -35,6 +35,9 @@ void NavData::init(const std::shared_ptr &osnma_msg) PRNa = osnma_msg->PRN; WN_sf0 = osnma_msg->WN_sf0; TOW_sf0 = osnma_msg->TOW_sf0; + + // new parsing, directly parsing bits + ephemeris_iono_vector_2 = osnma_msg->EphemerisClockAndStatusData_2; }; void NavData::generate_eph_iono_vector() { @@ -166,8 +169,3 @@ void NavData::generate_utc_vector() } } -std::vector Tag::build_message() -{ - // TODO - return std::vector(); -} diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 121853d2a..6e3439a4c 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -121,7 +121,8 @@ public: MACK_header header; std::vector tag_and_info; std::vector key; - uint32_t TOW; // TODO duplicated variable + uint32_t TOW; // TODO duplicated variable, also in NavData + uint32_t WN; uint32_t PRNa; }; @@ -131,6 +132,7 @@ public: NavData()=default; void init(const std::shared_ptr &osnma_msg); std::vector ephemeris_iono_vector{}; + std::string ephemeris_iono_vector_2{}; std::vector utc_vector{}; uint32_t PRNa{}; uint32_t WN_sf0{}; @@ -168,10 +170,12 @@ public: SUCCESS, FAIL, UNVERIFIED}; - Tag(const MACK_tag_and_info& MTI, uint32_t TOW, uint32_t PRNa) + Tag(const MACK_tag_and_info& MTI, uint32_t TOW,uint32_t WN, uint32_t PRNa,uint8_t CTR) : tag_id(id_counter++), - TOW(TOW), + TOW(TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, NavData missing + WN(WN), PRNa(PRNa), + CTR(CTR), status(UNVERIFIED), received_tag(MTI.tag), computed_tag(0), @@ -184,10 +188,11 @@ public: const uint32_t tag_id; uint32_t TOW; + uint32_t WN; uint32_t PRNa; + uint8_t CTR; e_verification_status status; uint64_t received_tag; - std::vector build_message(); uint32_t static id_counter; uint64_t computed_tag; diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc new file mode 100644 index 000000000..462fd5d34 --- /dev/null +++ b/src/core/system_parameters/osnma_helper.cc @@ -0,0 +1,34 @@ +/*! +* \file osnma_helper.h +* \brief Class for auxiliary osnma functions +* \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es +* +* ----------------------------------------------------------------------------- +* +* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +* This file is part of GNSS-SDR. +* +* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) +* SPDX-License-Identifier: GPL-3.0-or-later +* +* ----------------------------------------------------------------------------- + */ + +#include "osnma_helper.h" + +uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const +{ + uint32_t GST = (WN & 0x00000FFF) << 20 | (TOW & 0x000FFFFF); + return GST; +} + +std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const +{ + std::vector res(4); + + res[1] = static_cast((GST & 0xFF000000) >> 24); + res[2] = static_cast((GST & 0x00FF0000) >> 16); + res[3] = static_cast((GST & 0x0000FF00) >> 8); + res[4] = static_cast(GST & 0x000000FF); + return res; +} diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h new file mode 100644 index 000000000..0a1b72270 --- /dev/null +++ b/src/core/system_parameters/osnma_helper.h @@ -0,0 +1,33 @@ +/*! +* \file osnma_helper.h +* \brief Class for auxiliary osnma functions +* \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es +* +* ----------------------------------------------------------------------------- +* +* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +* This file is part of GNSS-SDR. +* +* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) +* SPDX-License-Identifier: GPL-3.0-or-later +* +* ----------------------------------------------------------------------------- +*/ + +#ifndef GNSS_SDR_OSNMA_HELPER_H +#define GNSS_SDR_OSNMA_HELPER_H + + +#include +#include +class Osnma_Helper +{ +public: + Osnma_Helper() = default; + ~Osnma_Helper() = default; + uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; + std::vector gst_to_uint8(uint32_t GST) const; +}; + + +#endif // GNSS_SDR_OSNMA_HELPER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 65dd98006..f251756e8 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -99,6 +99,8 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; const int DURATION_SUBFRAME{30}; + const int DUMMY_PAGE{63}; + bool flag_dummy_page{false}; std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS << ", TOW=" << TOW << ", WN=" << WN << std::endl; @@ -107,10 +109,12 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // Act while (end_of_hex_stream == false){ // loop over all bytes of data. Note all TestVectors have same amount of data. for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe + std::cout << "OsnmaTestVectorsSimulation: SVID "<< tv.svId << std::endl; auto osnmaMsg_sptr = std::make_shared(); std::array hkroot{}; std::array mack{}; byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) + std::map> words; for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe { // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index @@ -133,6 +137,34 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) bool tail_bits_OK = even_page.substr(even_page.size() - 6) == "000000" && odd_page.substr(odd_page.size() - 6) == "000000"; if(!even_odd_OK || !page_type_OK || !tail_bits_OK) std::cerr<< "OsnmaTestVectorsSimulation: error parsing pages." << std::endl; + + std::bitset<112> data_k(even_page.substr(2,112)); + std::bitset<16> data_j(odd_page.substr(2,16)); + std::bitset<112> shifted_data_k = data_k; +// uint8_t word_type = 0; +// for(int i = 0; i < 6; ++i) { +// word_type |= (data_k[104 + i] << i); +// } + uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word + std::cout<< "OsnmaTestVectorsSimulation: received Word "<< static_cast(word_type) << std::endl; + if( (word_type >= 1 && word_type <=5) || word_type == 6 || word_type == 10) + { + // store raw word + std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); + words[word_type] = data_combined; +// std::vector concatenatedData; +// for (std::size_t i = 0; i < data_k.size(); i += 8) { +// std::bitset<8> byte(data_k.to_string().substr(i, 8)); +// concatenatedData.push_back(static_cast(byte.to_ulong())); +// } +// for (std::size_t i = 0; i < data_j.size(); i += 8) { +// std::bitset<8> byte(data_j.to_string().substr(i, 8)); +// concatenatedData.push_back(static_cast(byte.to_ulong())); +// } + } + if(word_type == DUMMY_PAGE) + flag_dummy_page = true; + // place it into osnma object. std::bitset<40> osnmaBits(odd_page.substr(18, 40)); // Extract bits for hkroot and mack std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8)); @@ -142,8 +174,13 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) byte_index += SIZE_PAGE_BYTES; } + std::cout<< "----------" << std::endl; if(end_of_hex_stream) break; + if(flag_dummy_page){ + flag_dummy_page = false; + continue; // skip this SV + } osnmaMsg_sptr->hkroot = hkroot; osnmaMsg_sptr->mack = mack; @@ -151,6 +188,63 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ; osnmaMsg_sptr->PRN = tv.svId; + bool allWordsReceived = true; + for (int i = 1; i <= 5; ++i) + { + if (words.find(i) == words.end() && flag_dummy_page == false) + { + allWordsReceived = false; + std::cerr<< "OsnmaTestVectorsSimulation: error parsing words 1->5. " + "Word "<< i << " should be received for each subframe but was not." << std::endl; + } + } + if(allWordsReceived) + { + + // Define the starting position and length of bits to extract for each word + std::map> extractionParams = { + {1, {6, 120}}, + {2, {6, 120}}, + {3, {6, 122}}, + {4, {6, 120}}, + {5, {6, 67}}, + // TODO words 6 and 10 for TimingData + }; + + // Iterate over the extraction parameters + for (const auto& param : extractionParams) { + uint8_t wordKey = param.first; + uint8_t start = param.second.first; + uint8_t length = param.second.second; + + // Extract the required bits + std::bitset<128> word = words[wordKey]; + + osnmaMsg_sptr->EphemerisClockAndStatusData_2 += words[wordKey]. + to_string().substr( + start, length); + +// std::bitset<8> byte; +// int byteIndex = 0; +// for (uint8_t i = start; i < start + length; ++i) { +// byte[byteIndex] = word[i]; +// byteIndex++; +// +// // Once we have collected 8 bits, we can add them as an uint8_t to the vector +// if (byteIndex == 8) { +// osnmaMsg_sptr->EphemerisClockAndStatusData.push_back(static_cast(byte.to_ulong())); +// byte.reset(); +// byteIndex = 0; +// } +// } +// +// // Push remaining bits if it didn't reach 8 bits +// if (byteIndex > 0) { +// osnmaMsg_sptr->EphemerisClockAndStatusData.push_back(static_cast(byte.to_ulong())); +// } + } + } + auto temp_obj = pmt::make_any(osnmaMsg_sptr); osnma->msg_handler_osnma(temp_obj); // osnma entry point @@ -169,9 +263,6 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) } - - - // Assert // TODO } From f11eb5b421ed1025ea1afafe3bc361798abfc77a Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 14 May 2024 16:15:17 +0200 Subject: [PATCH 108/219] [TAS-199] Add TagVerification test. Bugfix for verify_tag and osnma_helper. --- src/core/libs/osnma_msg_receiver.cc | 12 ++-- src/core/libs/osnma_msg_receiver.h | 1 + src/core/system_parameters/osnma_helper.cc | 32 ++++++++-- src/core/system_parameters/osnma_helper.h | 2 + src/tests/single_test_main.cc | 1 - .../osnma/osnma_msg_receiver_test.cc | 58 +++++++++++++++++-- 6 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 29f896f8b..024455597 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -873,6 +873,7 @@ void osnma_msg_receiver::process_mack_message() if (ret || d_flag_debug){ for(std::size_t i = 0; i < mack->tag_and_info.size(); ++i) { + // add tags of current mack to the verification queue auto& tag = mack->tag_and_info[i]; Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); @@ -1002,7 +1003,7 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) std::vector m; m.push_back(static_cast(tag.PRN_d)); m.push_back(static_cast(tag.PRNa)); - uint32_t GST = d_helper->compute_gst(tag.TOW, tag.WN); + uint32_t GST = d_helper->compute_gst( tag.WN,tag.TOW); std::vector GST_uint8 = d_helper->gst_to_uint8(GST); m.insert(m.end(),GST_uint8.begin(),GST_uint8.end()); m.push_back(tag.CTR); @@ -1012,8 +1013,8 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) m.push_back(two_bits_nmas); // convert std::string to vector - std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.TOW][tag.PRNa].ephemeris_iono_vector_2; - std::vector ephemeris_iono_vector_2_bytes(ephemeris_iono_vector_2.begin(), ephemeris_iono_vector_2.end()); + std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRNa][tag.TOW].ephemeris_iono_vector_2; + std::vector ephemeris_iono_vector_2_bytes = d_helper->bytes(ephemeris_iono_vector_2); // Convert and add ephemeris_iono_vector_2 into the vector for (uint8_t byte : ephemeris_iono_vector_2_bytes) { @@ -1205,7 +1206,8 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() /** * @brief Verifies the MACSEQ of a received MACK_message. * - * \details checks for each tag in the retrieved mack message if its flexible (MACSEQ) or not (MACSEQ/MACLT depending on configuration param. (TODO) + * \details checks for each tag in the retrieved mack message if its flexible (MACSEQ) or not (MACSEQ/MACLT depending on configuration param, and + * verifies according to Eqs. 20, 21 SIS ICD. * @param message The MACK_message to verify. * @return True if the MACSEQ is valid, false otherwise. */ @@ -1218,7 +1220,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) std::vector sq2{}; std::vector applicable_sequence; const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); - // TODO as per RG example appears that the seq. q shall also be validated ageints either next or former Sf (depending on GST) + // TODO as per RG example appears that the seq. q shall also be validated against either next or former Sf (depending on GST) if (it != OSNMA_TABLE_16.cend()) { sq1 = it->second.sequence1; diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 8137c9824..b655094df 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -122,6 +122,7 @@ private: FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); FRIEND_TEST(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation); + FRIEND_TEST(OsnmaMsgReceiverTest, TagVerification); }; diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index 462fd5d34..b67454ddd 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -15,6 +15,7 @@ */ #include "osnma_helper.h" +#include uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const { @@ -24,11 +25,32 @@ uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const { - std::vector res(4); + std::vector res; - res[1] = static_cast((GST & 0xFF000000) >> 24); - res[2] = static_cast((GST & 0x00FF0000) >> 16); - res[3] = static_cast((GST & 0x0000FF00) >> 8); - res[4] = static_cast(GST & 0x000000FF); + res.push_back(static_cast((GST & 0xFF000000) >> 24)); + res.push_back(static_cast((GST & 0x00FF0000) >> 16)); + res.push_back(static_cast((GST & 0x0000FF00) >> 8)); + res.push_back(static_cast(GST & 0x000000FF)); return res; } + +std::vector Osnma_Helper::bytes(const std::string& binaryString) { + std::vector bytes; + + // Determine the size of the padding needed. + size_t padding_size = binaryString.size() % 8; + + std::string padded_binary = binaryString; + + if (padding_size != 0) { + padding_size = 8 - padding_size; // Compute padding size + padded_binary.append(padding_size, '0'); // Append zeros to the binary string + } + + for (size_t i = 0; i < padded_binary.size(); i += 8) { + uint8_t byte = std::bitset<8>(padded_binary.substr(i, 8)).to_ulong(); + bytes.push_back(byte); + } + + return bytes; +} \ No newline at end of file diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 0a1b72270..9bf1d860d 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -19,6 +19,7 @@ #include +#include #include class Osnma_Helper { @@ -27,6 +28,7 @@ public: ~Osnma_Helper() = default; uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; std::vector gst_to_uint8(uint32_t GST) const; + std::vector bytes(const std::string& binaryString); }; diff --git a/src/tests/single_test_main.cc b/src/tests/single_test_main.cc index 2bea64518..de02b421c 100644 --- a/src/tests/single_test_main.cc +++ b/src/tests/single_test_main.cc @@ -78,7 +78,6 @@ Concurrent_Map global_gps_acq_assist_map; int main(int argc, char **argv) { #if USE_GLOG_AND_GFLAGS - gflags::ParseCommandLineFlags(&argc, &argv, true); try { testing::InitGoogleTest(&argc, argv); diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index f251756e8..2b29ee3cf 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -58,6 +58,7 @@ public: TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Arrange + // ---------- osnma->d_tesla_key_verified = false; osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits @@ -75,6 +76,7 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Act + // ---------- bool result = osnma->verify_tesla_key(key, TOW); @@ -82,7 +84,8 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Assert - ASSERT_TRUE(result); // Adjust this according to what you expect + // ---------- + ASSERT_TRUE(result); } @@ -342,7 +345,6 @@ std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& return extracted_bytes; } - /** * @brief Sets the time based on the given input. * @@ -374,7 +376,6 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) } - void OsnmaMsgReceiverTest::initializeGoogleLog() { google::InitGoogleLogging(log_name.c_str()); @@ -416,4 +417,53 @@ void OsnmaMsgReceiverTest::initializeGoogleLog() throw; } } -} \ No newline at end of file +} + + +TEST_F(OsnmaMsgReceiverTest, TagVerification) { + // Arrange + // ---------- + osnma->d_tesla_key_verified = false; + osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 + osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits + osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; + // local_time_verification would do this operation. TODO - eliminate duplication. + osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); + osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; + + osnma->d_tesla_keys.insert((std::pair>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. + std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 + + + uint32_t TOW = 345630; + uint32_t WN = 1248; + uint32_t PRNa = 0; + uint8_t CTR = 2; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 0x00; + osnma->d_tesla_keys[TOW] = {0xEF, 0xF9}; + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0x00; + osnma->d_satellite_nav_data[PRNa][TOW].ephemeris_iono_vector_2 = ""; + osnma->d_osnma_data.d_nma_header.nmas = 0b00000010; + + MACK_tag_and_info MTI; + MTI.tag = 0x00; + MTI.tag_info.PRN_d = 0; + MTI.tag_info.ADKD = 0; + MTI.tag_info.cop = 0; + Tag t(MTI, TOW, WN, PRNa, CTR); + + // Act + // ---------- + bool result = osnma->verify_tag(t); + + + + + + // Assert + // ---------- + ASSERT_TRUE(result); + +} From 5cee46aa06b56ed4488f166a16baffea054e6aad Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 14 May 2024 16:15:17 +0200 Subject: [PATCH 109/219] [TAS-199] Add TagVerification test. Bugfix for verify_tag and osnma_helper. --- src/core/libs/osnma_msg_receiver.cc | 30 +++++--- src/core/libs/osnma_msg_receiver.h | 1 + src/core/system_parameters/osnma_helper.cc | 32 ++++++-- src/core/system_parameters/osnma_helper.h | 2 + src/tests/single_test_main.cc | 1 - .../osnma/osnma_msg_receiver_test.cc | 76 ++++++++++++++++++- 6 files changed, 122 insertions(+), 20 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 29f896f8b..51c495e0f 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -873,6 +873,7 @@ void osnma_msg_receiver::process_mack_message() if (ret || d_flag_debug){ for(std::size_t i = 0; i < mack->tag_and_info.size(); ++i) { + // add tags of current mack to the verification queue auto& tag = mack->tag_and_info[i]; Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); @@ -998,11 +999,13 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) } bool osnma_msg_receiver::verify_tag(Tag& tag) { + // TODO case tag0, to be verified here?, PRNd not needed for it // build message std::vector m; - m.push_back(static_cast(tag.PRN_d)); + if(tag.CTR != 1) + m.push_back(static_cast(tag.PRN_d)); m.push_back(static_cast(tag.PRNa)); - uint32_t GST = d_helper->compute_gst(tag.TOW, tag.WN); + uint32_t GST = d_helper->compute_gst( tag.WN,tag.TOW); std::vector GST_uint8 = d_helper->gst_to_uint8(GST); m.insert(m.end(),GST_uint8.begin(),GST_uint8.end()); m.push_back(tag.CTR); @@ -1012,8 +1015,8 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) m.push_back(two_bits_nmas); // convert std::string to vector - std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.TOW][tag.PRNa].ephemeris_iono_vector_2; - std::vector ephemeris_iono_vector_2_bytes(ephemeris_iono_vector_2.begin(), ephemeris_iono_vector_2.end()); + std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRNa][tag.TOW-30].ephemeris_iono_vector_2; + std::vector ephemeris_iono_vector_2_bytes = d_helper->bytes(ephemeris_iono_vector_2); // Convert and add ephemeris_iono_vector_2 into the vector for (uint8_t byte : ephemeris_iono_vector_2_bytes) { @@ -1035,15 +1038,21 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) } } } - +// m = { +// 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, +// 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, +// 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, +// 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, +// 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00 +// }; std::vector mac; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { - mac = d_crypto->computeHMAC_SHA_256(d_tesla_keys[tag.TOW], m); + mac = d_crypto->computeHMAC_SHA_256(d_tesla_keys[tag.TOW+30], m); } else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { - mac = d_crypto->computeCMAC_AES(d_tesla_keys[tag.TOW], m); + mac = d_crypto->computeCMAC_AES(d_tesla_keys[tag.TOW+30], m); } // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD @@ -1205,7 +1214,8 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() /** * @brief Verifies the MACSEQ of a received MACK_message. * - * \details checks for each tag in the retrieved mack message if its flexible (MACSEQ) or not (MACSEQ/MACLT depending on configuration param. (TODO) + * \details checks for each tag in the retrieved mack message if its flexible (MACSEQ) or not (MACSEQ/MACLT depending on configuration param, and + * verifies according to Eqs. 20, 21 SIS ICD. * @param message The MACK_message to verify. * @return True if the MACSEQ is valid, false otherwise. */ @@ -1218,7 +1228,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) std::vector sq2{}; std::vector applicable_sequence; const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); - // TODO as per RG example appears that the seq. q shall also be validated ageints either next or former Sf (depending on GST) + // TODO as per RG example appears that the seq. q shall also be validated against either next or former Sf (depending on GST) if (it != OSNMA_TABLE_16.cend()) { sq1 = it->second.sequence1; @@ -1317,7 +1327,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) // PRN was found, check if TOW exists in inner map LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; std::map& tow_map = prn_it->second; - auto tow_it = tow_map.find(t.TOW); + auto tow_it = tow_map.find(t.TOW-30); // TODO check ADKD to decide if (tow_it != tow_map.end()) { return true; } else { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 8137c9824..b655094df 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -122,6 +122,7 @@ private: FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); FRIEND_TEST(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation); + FRIEND_TEST(OsnmaMsgReceiverTest, TagVerification); }; diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index 462fd5d34..b67454ddd 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -15,6 +15,7 @@ */ #include "osnma_helper.h" +#include uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const { @@ -24,11 +25,32 @@ uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const { - std::vector res(4); + std::vector res; - res[1] = static_cast((GST & 0xFF000000) >> 24); - res[2] = static_cast((GST & 0x00FF0000) >> 16); - res[3] = static_cast((GST & 0x0000FF00) >> 8); - res[4] = static_cast(GST & 0x000000FF); + res.push_back(static_cast((GST & 0xFF000000) >> 24)); + res.push_back(static_cast((GST & 0x00FF0000) >> 16)); + res.push_back(static_cast((GST & 0x0000FF00) >> 8)); + res.push_back(static_cast(GST & 0x000000FF)); return res; } + +std::vector Osnma_Helper::bytes(const std::string& binaryString) { + std::vector bytes; + + // Determine the size of the padding needed. + size_t padding_size = binaryString.size() % 8; + + std::string padded_binary = binaryString; + + if (padding_size != 0) { + padding_size = 8 - padding_size; // Compute padding size + padded_binary.append(padding_size, '0'); // Append zeros to the binary string + } + + for (size_t i = 0; i < padded_binary.size(); i += 8) { + uint8_t byte = std::bitset<8>(padded_binary.substr(i, 8)).to_ulong(); + bytes.push_back(byte); + } + + return bytes; +} \ No newline at end of file diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 0a1b72270..9bf1d860d 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -19,6 +19,7 @@ #include +#include #include class Osnma_Helper { @@ -27,6 +28,7 @@ public: ~Osnma_Helper() = default; uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; std::vector gst_to_uint8(uint32_t GST) const; + std::vector bytes(const std::string& binaryString); }; diff --git a/src/tests/single_test_main.cc b/src/tests/single_test_main.cc index 2bea64518..de02b421c 100644 --- a/src/tests/single_test_main.cc +++ b/src/tests/single_test_main.cc @@ -78,7 +78,6 @@ Concurrent_Map global_gps_acq_assist_map; int main(int argc, char **argv) { #if USE_GLOG_AND_GFLAGS - gflags::ParseCommandLineFlags(&argc, &argv, true); try { testing::InitGoogleTest(&argc, argv); diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index f251756e8..7ee09c51f 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -58,6 +58,7 @@ public: TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Arrange + // ---------- osnma->d_tesla_key_verified = false; osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits @@ -75,6 +76,7 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Act + // ---------- bool result = osnma->verify_tesla_key(key, TOW); @@ -82,7 +84,8 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Assert - ASSERT_TRUE(result); // Adjust this according to what you expect + // ---------- + ASSERT_TRUE(result); } @@ -342,7 +345,6 @@ std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& return extracted_bytes; } - /** * @brief Sets the time based on the given input. * @@ -374,7 +376,6 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) } - void OsnmaMsgReceiverTest::initializeGoogleLog() { google::InitGoogleLogging(log_name.c_str()); @@ -416,4 +417,71 @@ void OsnmaMsgReceiverTest::initializeGoogleLog() throw; } } -} \ No newline at end of file +} + + +TEST_F(OsnmaMsgReceiverTest, TagVerification) { + // Arrange + // ---------- + // Tag0 + uint32_t TOW_Tag0 = 345660; + uint32_t TOW_NavData = TOW_Tag0 - 30; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t WN = 1248; + uint32_t PRNa = 2; + uint8_t CTR = 1; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "0000000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MACK_tag_and_info MTI; + MTI.tag = static_cast(0xE37BC4F858); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x00; + MTI.tag_info.cop = 0x0F; + Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + + + + // Act + // ---------- + bool result_tag0 = osnma->verify_tag(t0); + + + + + + // Assert + // ---------- + //ASSERT_TRUE(result_tag0); + + // Tag3 + uint32_t TOW_Tag3 = 345660; + uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; + uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30 ; + WN = 1248; + PRNa = 2; + CTR = 3; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = + "111111111111111111111111111111110000000000000000000000010001001001001000" + "111000001000100111100010010111111111011110111111111001001100000100000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MTI.tag = static_cast(0x7BB238C883); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x04; + MTI.tag_info.cop = 0x0F; + Tag t3(MTI, TOW_Tag0, WN, PRNa, CTR); + + bool result_tag3 = osnma->verify_tag(t3); + + ASSERT_TRUE(result_tag3); + +} From 585cae0d706050284ef8c09699cb40fd917ba0fe Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 20 May 2024 11:24:31 +0200 Subject: [PATCH 110/219] [TAS-201] Update gnss_crypto_test and osnma_msg_receiver_test sections in CMakeLists for abseil --- .gitignore | 1 + src/tests/CMakeLists.txt | 53 ++++++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index 5514c9cb4..c16e1f808 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ cmake-build-debug/ .vscode/ .vs/ Testing/ +/build/* \ No newline at end of file diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 9e0a2517a..97bbac838 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1344,17 +1344,13 @@ else() endif() endif() -if(ENABLE_BENCHMARKS) - add_subdirectory(benchmarks) -endif() - +######################################################### gnss_crypto_test if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) set(GNSS_CRYPTO_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc) - # Configure the test executable: if(USE_CMAKE_TARGET_SOURCES) add_executable(gnss_crypto_test) target_sources(gnss_crypto_test PRIVATE ${GNSS_CRYPTO_TEST_SOURCES}) @@ -1362,33 +1358,39 @@ if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) add_executable(gnss_crypto_test ${GNSS_CRYPTO_TEST_SOURCES}) endif() - # Link libraries that gnss_crypto_test requires: target_link_libraries(gnss_crypto_test PRIVATE Boost::thread - Gflags::gflags - Glog::glog GTest::GTest GTest::Main core_system_parameters + Pugixml::pugixml ) + if(ENABLE_GLOG_AND_GFLAGS) + target_link_libraries(gnss_crypto_test PRIVATE Gflags::gflags Glog::glog) + target_compile_definitions(gnss_crypto_test PRIVATE -DUSE_GLOG_AND_GFLAGS=1) + else() + target_link_libraries(gnss_crypto_test PRIVATE absl::flags absl::flags_parse absl::log $ absl::log_initialize) + endif() - # Include any directories your test needs for header files: target_include_directories(gnss_crypto_test PRIVATE - #${GNSSSDR_SOURCE_DIR}/src/algorithms, - #${GNSSSDR_SOURCE_DIR}/src/core, - #${GNSSSDR_SOURCE_DIR}/src/core/receiver, ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters) + + xcode_remove_warning_duplicates(gnss_crypto_test) # TODO - unsure if needed + + add_test(gnss_crypto_test gnss_crypto_test) + + set_property(TEST gnss_crypto_test PROPERTY TIMEOUT 1) endif() +######################################################### osnma_msg_receiver_test if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) set(OSNMA_MSG_RECEIVER_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc) - # Configure the test executable: if(USE_CMAKE_TARGET_SOURCES) add_executable(osnma_msg_receiver_test) target_sources(osnma_msg_receiver_test PRIVATE ${OSNMA_MSG_RECEIVER_TEST_SOURCES}) @@ -1396,22 +1398,31 @@ if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) add_executable(osnma_msg_receiver_test ${OSNMA_MSG_RECEIVER_TEST_SOURCES}) endif() - # Link libraries that gnss_crypto_test requires: target_link_libraries(osnma_msg_receiver_test PRIVATE Boost::thread - Gflags::gflags - Glog::glog GTest::GTest GTest::Main core_libs ) + if(ENABLE_GLOG_AND_GFLAGS) + target_link_libraries(osnma_msg_receiver_test PRIVATE Gflags::gflags Glog::glog) + target_compile_definitions(osnma_msg_receiver_test PRIVATE -DUSE_GLOG_AND_GFLAGS=1) + else() + target_link_libraries(osnma_msg_receiver_test PRIVATE absl::flags absl::flags_parse absl::log $ absl::log_initialize) + endif() + + xcode_remove_warning_duplicates(osnma_msg_receiver_test) # TODO - unsure if needed + + add_test(osnma_msg_receiver_test osnma_msg_receiver_test) + + set_property(TEST osnma_msg_receiver_test PROPERTY TIMEOUT 1) - # Include any directories your test needs for header files: target_include_directories(osnma_msg_receiver_test PRIVATE - #${GNSSSDR_SOURCE_DIR}/src/algorithms, - #${GNSSSDR_SOURCE_DIR}/src/core, - #${GNSSSDR_SOURCE_DIR}/src/core/receiver, ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters) -endif() \ No newline at end of file +endif() + +if(ENABLE_BENCHMARKS) + add_subdirectory(benchmarks) +endif() From a53b92b8614cf5e70f1962c982d88de3c5db367e Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 20 May 2024 15:36:50 +0200 Subject: [PATCH 111/219] [TAS-200] gnss_crypto_test :: extend unit test for m0 and adkd4 --- .../osnma/gnss_crypto_test.cc | 109 +++++++++++++----- 1 file changed, 78 insertions(+), 31 deletions(-) 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 d78c8d688..a72d86998 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 @@ -9,47 +9,47 @@ TEST(GnssCryptoTest, VerifySignature) { std::unique_ptr d_crypto = std::make_unique(); // RG example - import crt certificate - result: FAIL -//std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; -//std::vector publicKey { // PEM format - 1000 bits -// 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 } ; +std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; +std::vector publicKey { // PEM format - 1000 bits + 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 } ; // own ECDSA-P256 key and message generated and signed and verified successfully with openssl - std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message (unhashed) +// std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message (unhashed) // std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, // 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, // 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK // raw r and s values - std::vector signature = { - 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, - 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, - 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, - 0xA5, 0xB9, 0xB2, 0x56 }; +// std::vector signature = { +// 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, +// 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, +// 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, +// 0xA5, 0xB9, 0xB2, 0x56 }; // std::vector publicKey{// PK associated to the PrK, in der format ---test // 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4A, 0xF3, // 0xEE, 0x3A, 0x94, 0x25, 0x25, 0x3D, 0x55, 0xC2, 0x5A, 0xC2, 0x2D, 0xCF, 0x14, 0x4D, 0x39, 0x0D, 0xB1, 0xFC, 0x7F, 0x31, 0x5A, 0x2A, 0x19, 0xAE, 0x4E, 0xD6, 0xCB, 0xA6, 0x59, // 0xD6, 0x99, 0x7C, 0xE8, 0xBD, 0x1F, 0x43, 0x34, 0x1C, 0x59, 0xD9, 0xD9, 0xCA, 0xC3, 0xEE, 0x58, 0xE5, 0xEA, 0xD3, 0x55, 0x44, 0xEA, 0x89, 0x71, 0x65, 0xD0, 0x92, 0x72, 0xA2, // 0xC8, 0x3C, 0x87, 0x5D }; - std::vector publicKey{ // PK associated to the PrK, in pem format - 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, - 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, - 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, - 0x44, 0x79, 0x48, 0x58, 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 }; +// std::vector publicKey{ // PK associated to the PrK, in pem format +// 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, +// 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, +// 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, +// 0x44, 0x79, 0x48, 0x58, 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 }; // own key - GnuTLS error: The curve is unsupported... x192 EC unsupported?? // std::vector message = {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64 }; // hello world @@ -161,7 +161,7 @@ TEST(GnssCryptoTest,VerifyPubKeyImport) } // Unit test for computeHMAC_SHA_256 function. -TEST(GnssCryptoTest, TestComputeHMACSHA256) { +TEST(GnssCryptoTest, TestComputeHMACSHA256) { // key and message generated with openssl std::unique_ptr d_crypto = std::make_unique(); std::vector key = { 0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7, @@ -182,4 +182,51 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256) { ASSERT_EQ(expected_output, output); -} \ No newline at end of file +} + +TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) { // key and message generated from RG A.6.5.1 + std::unique_ptr d_crypto = std::make_unique(); + std::vector key = { // RG K4 @ 345690 + 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, + 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; + + std::vector message{// m0 + 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, + 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, + 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, + 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, + 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00}; + + std::vector expected_output = { + 0xE3, 0x7B, 0xC4, 0xF8, 0x58, 0xAE, 0x1E, 0x5C, + 0xFD, 0xC4, 0x6F, 0x05, 0x4B, 0x1F, 0x47, 0xB9, 0xD2, 0xEA, 0x61, 0xE1, + 0xEF, 0x09, 0x11, 0x5C, 0xFE, 0x70, 0x68, 0x52, 0xBF, 0xF2, 0x3A, 0x83}; + + std::vector output = d_crypto->computeHMAC_SHA_256(key, message); + + ASSERT_EQ(expected_output, output); +} + +TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) { // key and message generated from RG A.6.5.2 + std::unique_ptr d_crypto = std::make_unique(); + std::vector key = { // RG K4 @ 345690 + 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, + 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; + + std::vector message{ + 0x02, 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x03, 0xBF, + 0xFF, 0xFF, 0xFF, 0xC0, 0x00,0x00, 0x44, 0x92, 0x38, + 0x22, 0x78, 0x97, 0xFD, 0xEF, 0xF9, 0x30, 0x40}; + + std::vector expected_output = { + 0x7B, 0xB2, 0x38, 0xC8, 0x83, 0xC0, 0x6A, 0x2B, 0x50, 0x8F, + 0xE6, 0x3F, 0xB7, 0xF4, 0xF5, 0x4D, 0x44, 0xAB, 0xEE, 0x4D, + 0xCE, 0xB9, 0x3D, 0xCF, 0x65, 0xCB, 0x3A, 0x5B, 0x81, 0x4A, 0x34, 0xE9}; + + + std::vector output = d_crypto->computeHMAC_SHA_256(key, message); + + ASSERT_EQ(expected_output, output); +} + +// TODO extend to HMAC-AES \ No newline at end of file From d52603aba5f0888eaa359d048ab9815b03682d84 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 21 May 2024 18:08:25 +0200 Subject: [PATCH 112/219] [TAS-161] debug tag_verification :: extract build_message, unit test for BuildTagMessageM0 and fix unit test for TagVerification --- src/core/libs/osnma_msg_receiver.cc | 85 +++++++++---------- src/core/libs/osnma_msg_receiver.h | 2 + .../osnma/osnma_msg_receiver_test.cc | 53 +++++++++++- 3 files changed, 93 insertions(+), 47 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 51c495e0f..968015996 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -1001,50 +1001,8 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) { // TODO case tag0, to be verified here?, PRNd not needed for it // build message - std::vector m; - if(tag.CTR != 1) - m.push_back(static_cast(tag.PRN_d)); - m.push_back(static_cast(tag.PRNa)); - uint32_t GST = d_helper->compute_gst( tag.WN,tag.TOW); - std::vector GST_uint8 = d_helper->gst_to_uint8(GST); - m.insert(m.end(),GST_uint8.begin(),GST_uint8.end()); - m.push_back(tag.CTR); - // Extracts only two bits from d_osnma_data.d_nma_header.nmas - uint8_t two_bits_nmas = d_osnma_data.d_nma_header.nmas & 0b00000011; - two_bits_nmas = two_bits_nmas << 6; - m.push_back(two_bits_nmas); + std::vector m = build_message(tag); - // convert std::string to vector - std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRNa][tag.TOW-30].ephemeris_iono_vector_2; - std::vector ephemeris_iono_vector_2_bytes = d_helper->bytes(ephemeris_iono_vector_2); - - // Convert and add ephemeris_iono_vector_2 into the vector - for (uint8_t byte : ephemeris_iono_vector_2_bytes) { - m.back() |= (byte >> 2); // First take the 6 MSB bits of byte and add to m - m.push_back(byte << 6); // Then take the last 2 bits of byte, shift them to MSB position and insert the new element into m - } - if(m.back() == 0) { - m.pop_back(); // Remove the last element if its value is 0 (only padding was added) - } - else { - // Pad with zeros if the last element wasn't full - for (int bits = 2; bits < 8; bits += 2) { - // Check if the last element in the vector has 2 '00' bits in its LSB position - if((m.back() & 0b00000011) == 0) { - m.back() <<= 2; // Shift the existing bits to make room for new 2 bits - } - else { - break; // If it does not have 2 '00' bits in its LSB position, then the padding is complete - } - } - } -// m = { -// 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, -// 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, -// 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, -// 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, -// 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00 -// }; std::vector mac; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { @@ -1099,6 +1057,47 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) else return false; } +std::vector osnma_msg_receiver::build_message(const Tag& tag) +{ + std::vector m; + if(tag.CTR != 1) + m.push_back(static_cast(tag.PRN_d)); + m.push_back(static_cast(tag.PRNa)); + uint32_t GST = d_helper->compute_gst( tag.WN,tag.TOW); + std::vector GST_uint8 = d_helper->gst_to_uint8(GST); + m.insert(m.end(),GST_uint8.begin(),GST_uint8.end()); + m.push_back(tag.CTR); + // Extracts only two bits from d_osnma_data.d_nma_header.nmas + uint8_t two_bits_nmas = d_osnma_data.d_nma_header.nmas & 0b00000011; + two_bits_nmas = two_bits_nmas << 6; + m.push_back(two_bits_nmas); + + // convert std::string to vector + std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRNa][tag.TOW-30].ephemeris_iono_vector_2; + std::vector ephemeris_iono_vector_2_bytes = d_helper->bytes(ephemeris_iono_vector_2); + + // Convert and add ephemeris_iono_vector_2 into the vector + for (uint8_t byte : ephemeris_iono_vector_2_bytes) { + m.back() |= (byte >> 2); // First take the 6 MSB bits of byte and add to m + m.push_back(byte << 6); // Then take the last 2 bits of byte, shift them to MSB position and insert the new element into m + } + if(m.back() == 0) { + m.pop_back(); // Remove the last element if its value is 0 (only padding was added) + } + else { + // Pad with zeros if the last element wasn't full + for (int bits = 2; bits < 8; bits += 2) { + // Check if the last element in the vector has 2 '00' bits in its LSB position + if((m.back() & 0b00000011) == 0) { + m.back() <<= 2; // Shift the existing bits to make room for new 2 bits + } + else { + break; // If it does not have 2 '00' bits in its LSB position, then the padding is complete + } + } + } + return m; +} void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) { // control size of container diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index b655094df..d7aeb9df4 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -123,6 +123,8 @@ private: FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); FRIEND_TEST(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation); FRIEND_TEST(OsnmaMsgReceiverTest, TagVerification); + FRIEND_TEST(OsnmaMsgReceiverTest, BuildTagMessageM0); + std::vector build_message(const Tag& tag); }; diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 7ee09c51f..fe39fc979 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -420,6 +420,51 @@ void OsnmaMsgReceiverTest::initializeGoogleLog() } +TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) +{ + // Arrange + // ---------- + // m0 + std::vector expected_message = { + 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, + 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, + 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, + 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, + 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00 + }; + + uint32_t TOW_Tag0 = 345660; + uint32_t TOW_NavData = TOW_Tag0 - 30; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t WN = 1248; + uint32_t PRNa = 2; + uint8_t CTR = 1; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MACK_tag_and_info MTI; + MTI.tag = static_cast(0xE37BC4F858); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x00; + MTI.tag_info.cop = 0x0F; + Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + + + + // Act + // ---------- + auto computed_message = osnma->build_message(t0); + + + // Assert + // ---------- + ASSERT_TRUE(computed_message == expected_message); + +} TEST_F(OsnmaMsgReceiverTest, TagVerification) { // Arrange // ---------- @@ -432,9 +477,9 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { uint8_t CTR = 1; osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "0000000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000000"; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; osnma->d_osnma_data.d_nma_header.nmas = 0b10; MACK_tag_and_info MTI; @@ -467,7 +512,7 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { CTR = 3; osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 + osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "111111111111111111111111111111110000000000000000000000010001001001001000" @@ -482,6 +527,6 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { bool result_tag3 = osnma->verify_tag(t3); - ASSERT_TRUE(result_tag3); + ASSERT_TRUE(result_tag0 && result_tag3); } From 163c915c728deb88f3fb0cacc3a3710293d37899 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 21 May 2024 18:08:25 +0200 Subject: [PATCH 113/219] [TAS-161] debug tag_verification :: extract build_message, unit test for BuildTagMessageM0 and fix unit test for TagVerification --- src/tests/single_test_main.cc | 1 - .../osnma/osnma_msg_receiver_test.cc | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tests/single_test_main.cc b/src/tests/single_test_main.cc index de02b421c..beece7581 100644 --- a/src/tests/single_test_main.cc +++ b/src/tests/single_test_main.cc @@ -86,7 +86,6 @@ int main(int argc, char **argv) catch (...) { } // catch the "testing::internal::::ClassUniqueToAlwaysTrue" from gtest - google::InitGoogleLogging(argv[0]); #else absl::ParseCommandLine(argc, argv); try diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index fe39fc979..1769dfb45 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -40,8 +40,8 @@ protected: std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; set_time(input_time); - std::string pemFilePath = "OSNMA_PublicKey_20230803105952_newPKID_1.pem"; - std::string merkleFilePath = "OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; + std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; + std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); } void TearDown() override{ @@ -93,7 +93,11 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) { initializeGoogleLog(); // Arrange - std::vector testVectors = readTestVectorsFromFile(/*"/home/cgm/CLionProjects/osnma/src/tests/data/*/"16_AUG_2023_GST_05_00_01.csv"); + std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); + if (testVectors.empty()){ + ASSERT_TRUE(false); + } + bool end_of_hex_stream{false}; int offset_byte{0}; int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size From b0eb958be06314452bba4d26cd0eaa7e34bb3216 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Wed, 22 May 2024 21:01:24 +0200 Subject: [PATCH 114/219] [TAS-203] bug osnma_test_vector_config_1 adkd dependence on key selection --- src/core/libs/osnma_msg_receiver.cc | 17 ++++++++++++----- .../osnma/osnma_msg_receiver_test.cc | 19 ++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 968015996..42a89c957 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -570,7 +570,7 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrPRN,osnma_msg->TOW_sf0,d_osnma_data.d_nav_data); // TODO change place // DEBUG PARSING MACK MESSAGES WHEN DSM-KROOT NOT YET AVAILABLE // d_osnma_data.d_dsm_kroot_message.ts = 9; // d_osnma_data.d_dsm_kroot_message.ks = 4; @@ -860,6 +860,7 @@ void osnma_msg_receiver::process_mack_message() LOG(WARNING) << "But it will be processed for debugging purposes."; } // verify tesla key and add it to the container of verified keys if successful + // TODO not verify tesla key for each satellite if already verified. bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key, d_osnma_data.d_nav_data.TOW_sf0); if(retV){ d_tesla_keys.insert(std::pair(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); @@ -1004,13 +1005,19 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) std::vector m = build_message(tag); std::vector mac; - if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + std::vector applicable_key; + if (tag.ADKD == 0 || tag.ADKD == 4) + applicable_key = d_tesla_keys[tag.TOW + 30]; + else // ADKD 12 + applicable_key = d_tesla_keys[tag.TOW + 300]; + + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { - mac = d_crypto->computeHMAC_SHA_256(d_tesla_keys[tag.TOW+30], m); + mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); } else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { - mac = d_crypto->computeCMAC_AES(d_tesla_keys[tag.TOW+30], m); + mac = d_crypto->computeCMAC_AES(applicable_key, m); } // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD @@ -1073,7 +1080,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) m.push_back(two_bits_nmas); // convert std::string to vector - std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRNa][tag.TOW-30].ephemeris_iono_vector_2; + std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRNa][tag.TOW - 30].ephemeris_iono_vector_2; std::vector ephemeris_iono_vector_2_bytes = d_helper->bytes(ephemeris_iono_vector_2); // Convert and add ephemeris_iono_vector_2 into the vector diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 1769dfb45..4ba431e75 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -44,9 +44,6 @@ protected: std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); } - void TearDown() override{ - google::ShutdownGoogleLogging(); - } public: static std::vector parseNavBits(const std::string& hex); @@ -122,6 +119,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) std::array mack{}; byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) std::map> words; + for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe { // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index @@ -225,8 +223,6 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) uint8_t length = param.second.second; // Extract the required bits - std::bitset<128> word = words[wordKey]; - osnmaMsg_sptr->EphemerisClockAndStatusData_2 += words[wordKey]. to_string().substr( start, length); @@ -333,6 +329,19 @@ std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector& bytes } return bit_string; } + +/** + * @brief Extracts a range of bytes from a TestVector's navBits vector. + * + * This function extracts a extracts the bytes of complete page (odd+even) + * from the navBits vector of a TestVector object. + * + * + * @param tv The TestVector object from which to extract bytes. + * @param byte_index The index of the first byte to extract. + * @param num_bytes The number of bytes to extract. + * @return A vector containing the extracted bytes, or an empty vector if extraction is not possible. + */ std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes) { // Ensure we don't go beyond the end of tv.navBits From 434fff9cbfb0e98526b4dcb2ee5df822fecf688e Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 3 Jun 2024 19:59:32 +0200 Subject: [PATCH 115/219] [TAS-203] bug osnma_test_vector_config_1 II bug in build_message (PRN_d instead of PRNa) tags_awaiting_verification increase buffer size Reporting: modify tag reporting --- src/core/libs/osnma_msg_receiver.cc | 39 ++++++++++++------- .../osnma/osnma_msg_receiver_test.cc | 6 +-- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 42a89c957..dfc067796 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -453,9 +453,9 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_kroot_verified = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); if (d_kroot_verified) { - LOG(INFO) << "Galileo OSNMA: KROOT authentication successful !" << std::endl; - LOG(INFO) << "Galileo OSNMA: KROOT authentication successful !" << std::endl; - LOG(INFO) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " + LOG(WARNING) << "Galileo OSNMA: KROOT authentication successful !" << std::endl; + LOG(WARNING) << "Galileo OSNMA: KROOT authentication successful !" << std::endl; + LOG(WARNING) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; } @@ -860,12 +860,15 @@ void osnma_msg_receiver::process_mack_message() LOG(WARNING) << "But it will be processed for debugging purposes."; } // verify tesla key and add it to the container of verified keys if successful - // TODO not verify tesla key for each satellite if already verified. - bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key, d_osnma_data.d_nav_data.TOW_sf0); - if(retV){ - d_tesla_keys.insert(std::pair(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); + if (d_tesla_keys.find(d_osnma_data.d_nav_data.TOW_sf0) == d_tesla_keys.end()) // check if already available => no need to verify + { + bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key, d_osnma_data.d_nav_data.TOW_sf0); + if(retV){ + d_tesla_keys.insert(std::pair(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); + } } + // MACSEQ - verify current macks, then add current retrieved mack to the end. auto mack = d_macks_awaiting_MACSEQ_verification.begin(); while (mack != d_macks_awaiting_MACSEQ_verification.end()){ @@ -925,7 +928,7 @@ void osnma_msg_receiver::process_mack_message() else { it.second.status = Tag::FAIL; - LOG(ERROR) << "Galileo OSNMA: Tag verification failure for tag Id= " + LOG(ERROR) << "Galileo OSNMA: Tag verification :: FAILURE for tag Id= " << it.second.tag_id << ", TOW=" << it.second.TOW @@ -937,7 +940,7 @@ void osnma_msg_receiver::process_mack_message() } } else { - LOG(INFO) << "Galileo OSNMA: Tag verification skipped for Tag Id= " + LOG(WARNING) << "Galileo OSNMA: Tag verification :: SKIPPED for Tag Id= " << it.second.tag_id << ", TOW=" << it.second.TOW @@ -1080,7 +1083,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) m.push_back(two_bits_nmas); // convert std::string to vector - std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRNa][tag.TOW - 30].ephemeris_iono_vector_2; + std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; std::vector ephemeris_iono_vector_2_bytes = d_helper->bytes(ephemeris_iono_vector_2); // Convert and add ephemeris_iono_vector_2 into the vector @@ -1210,10 +1213,16 @@ void osnma_msg_receiver::remove_verified_tags() */ void osnma_msg_receiver::control_tags_awaiting_verify_size() { - while(d_tags_awaiting_verify.size() > 60) + while(d_tags_awaiting_verify.size() > 500) { - LOG(WARNING) << "Galileo OSNMA: delete tag due to exceeding buffer size. "; - d_tags_awaiting_verify.erase(d_tags_awaiting_verify.begin()); + auto it = d_tags_awaiting_verify.begin(); + LOG(WARNING) << "Galileo OSNMA: Tag verification :: DELETED tag due to exceeding buffer size. " + << "Tag Id= " << it->second.tag_id + << ", TOW=" << it->first + << ", ADKD=" << static_cast(it->second.ADKD) + << ", from satellite " << it->second.PRNa + << std::endl; + d_tags_awaiting_verify.erase(it); } } @@ -1328,12 +1337,12 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) } bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) { - auto prn_it = d_satellite_nav_data.find(t.PRNa); + auto prn_it = d_satellite_nav_data.find(t.PRN_d); if (prn_it != d_satellite_nav_data.end()) { // PRN was found, check if TOW exists in inner map LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; std::map& tow_map = prn_it->second; - auto tow_it = tow_map.find(t.TOW-30); // TODO check ADKD to decide + auto tow_it = tow_map.find(t.TOW - 30); if (tow_it != tow_map.end()) { return true; } else { diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 4ba431e75..2c6eca790 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -113,7 +113,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // Act while (end_of_hex_stream == false){ // loop over all bytes of data. Note all TestVectors have same amount of data. for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe - std::cout << "OsnmaTestVectorsSimulation: SVID "<< tv.svId << std::endl; + std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) "<< tv.svId << std::endl; auto osnmaMsg_sptr = std::make_shared(); std::array hkroot{}; std::array mack{}; @@ -191,7 +191,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ; - osnmaMsg_sptr->PRN = tv.svId; + osnmaMsg_sptr->PRN = tv.svId; // PRNa bool allWordsReceived = true; for (int i = 1; i <= 5; ++i) @@ -216,7 +216,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // TODO words 6 and 10 for TimingData }; - // Iterate over the extraction parameters + // Fill NavData bits -- Iterate over the extraction parameters for (const auto& param : extractionParams) { uint8_t wordKey = param.first; uint8_t start = param.second.first; From 6508e985a13a1efd916c5cd90b9235ffb6e507f0 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 4 Jun 2024 17:35:00 +0200 Subject: [PATCH 116/219] [TAS-206] [Feature] NavData for ADKD=4 for osnma_test_vector. --- src/core/libs/osnma_msg_receiver.cc | 20 ++++- .../system_parameters/galileo_inav_message.h | 1 + src/core/system_parameters/osnma_data.cc | 1 + src/core/system_parameters/osnma_data.h | 1 + .../osnma/osnma_msg_receiver_test.cc | 82 ++++++++++++------- 5 files changed, 70 insertions(+), 35 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index dfc067796..6e0b161c4 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -1082,12 +1082,24 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) two_bits_nmas = two_bits_nmas << 6; m.push_back(two_bits_nmas); + // Add applicable NavData bits to message + std::string applicable_nav_data; + std::vector applicable_nav_data_bytes; + if (tag.ADKD == 0 || tag.ADKD == 12) + { + applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; + } + else if (tag.ADKD == 4) + { + applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].utc_vector_2; + } + else + std::cerr<<"Galileo OSNMA :: Tag verification :: unknown ADKD" <<"\n"; // convert std::string to vector - std::string ephemeris_iono_vector_2 = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; - std::vector ephemeris_iono_vector_2_bytes = d_helper->bytes(ephemeris_iono_vector_2); + applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); - // Convert and add ephemeris_iono_vector_2 into the vector - for (uint8_t byte : ephemeris_iono_vector_2_bytes) { + // Convert and add NavData bytes into the message, taking care of that NMAS has only 2 bits + for (uint8_t byte : applicable_nav_data_bytes) { m.back() |= (byte >> 2); // First take the 6 MSB bits of byte and add to m m.push_back(byte << 6); // Then take the last 2 bits of byte, shift them to MSB position and insert the new element into m } diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 0e9c15b25..bc5d5f780 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -54,6 +54,7 @@ public: std::vector EphemerisClockAndStatusData {}; // TODO _2 rename and substitute this std::string EphemerisClockAndStatusData_2{}; std::vector TimingData {}; + std::string TimingData_2{}; Galileo_Ephemeris EphemerisData {}; Galileo_Iono IonoData {}; Galileo_Utc_Model UtcModelData {}; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 25124bb81..4424c55ba 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -38,6 +38,7 @@ void NavData::init(const std::shared_ptr &osnma_msg) // new parsing, directly parsing bits ephemeris_iono_vector_2 = osnma_msg->EphemerisClockAndStatusData_2; + utc_vector_2 = osnma_msg->TimingData_2; }; void NavData::generate_eph_iono_vector() { diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 6e3439a4c..cf9bcb7d9 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -134,6 +134,7 @@ public: std::vector ephemeris_iono_vector{}; std::string ephemeris_iono_vector_2{}; std::vector utc_vector{}; + std::string utc_vector_2{}; uint32_t PRNa{}; uint32_t WN_sf0{}; uint32_t TOW_sf0{}; diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 2c6eca790..1c4b1c7b9 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -90,6 +90,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) { initializeGoogleLog(); // Arrange + // ---------- std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); if (testVectors.empty()){ ASSERT_TRUE(false); @@ -98,10 +99,10 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) bool end_of_hex_stream{false}; int offset_byte{0}; int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size - const int SIZE_PAGE_BYTES{240/8}; - const int SIZE_SUBFRAME_PAGES{15}; - const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; - const int DURATION_SUBFRAME{30}; + const int SIZE_PAGE_BYTES{240/8}; // total bytes of a page + const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe + const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; // total bytes of a subframe + const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds const int DUMMY_PAGE{63}; bool flag_dummy_page{false}; @@ -110,7 +111,11 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) << ", WN=" << WN << std::endl; + + + // Act + // ---------- while (end_of_hex_stream == false){ // loop over all bytes of data. Note all TestVectors have same amount of data. for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) "<< tv.svId << std::endl; @@ -118,7 +123,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) std::array hkroot{}; std::array mack{}; byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) - std::map> words; + std::map> words; // structure containing and for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe { @@ -179,6 +184,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) byte_index += SIZE_PAGE_BYTES; } + std::cout<< "----------" << std::endl; if(end_of_hex_stream) break; @@ -193,17 +199,21 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ; osnmaMsg_sptr->PRN = tv.svId; // PRNa - bool allWordsReceived = true; + // TODO - refactor this logic, currently it is split + + // check if words 1--> 5 words are received + bool ephClockStatusWordsReceived = true; for (int i = 1; i <= 5; ++i) { - if (words.find(i) == words.end() && flag_dummy_page == false) + if (words.find(i) == words.end()) { - allWordsReceived = false; + ephClockStatusWordsReceived = false; std::cerr<< "OsnmaTestVectorsSimulation: error parsing words 1->5. " "Word "<< i << " should be received for each subframe but was not." << std::endl; } } - if(allWordsReceived) + // extract bits as needed by osnma block + if(ephClockStatusWordsReceived) { // Define the starting position and length of bits to extract for each word @@ -222,32 +232,38 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) uint8_t start = param.second.first; uint8_t length = param.second.second; - // Extract the required bits + // Extract the required bits and fill osnma block osnmaMsg_sptr->EphemerisClockAndStatusData_2 += words[wordKey]. to_string().substr( start, length); - -// std::bitset<8> byte; -// int byteIndex = 0; -// for (uint8_t i = start; i < start + length; ++i) { -// byte[byteIndex] = word[i]; -// byteIndex++; -// -// // Once we have collected 8 bits, we can add them as an uint8_t to the vector -// if (byteIndex == 8) { -// osnmaMsg_sptr->EphemerisClockAndStatusData.push_back(static_cast(byte.to_ulong())); -// byte.reset(); -// byteIndex = 0; -// } -// } -// -// // Push remaining bits if it didn't reach 8 bits -// if (byteIndex > 0) { -// osnmaMsg_sptr->EphemerisClockAndStatusData.push_back(static_cast(byte.to_ulong())); -// } } } + // check w6 && w10 is received + bool timingWordsReceived = words.find(6) != words.end() && + words.find(10) != words.end(); + + // extract bits as needed by osnma block + if(timingWordsReceived){ + // Define the starting position and length of bits to extract for each word + std::map> extractionParams = { + {6, {6, 99}}, + {10, {86, 42}} + }; + + // Fill NavData bits -- Iterate over the extraction parameters + for (const auto& param : extractionParams) + { + uint8_t wordKey = param.first; + uint8_t start = param.second.first; + uint8_t length = param.second.second; + + // Extract the required bits and fill osnma block + osnmaMsg_sptr->TimingData_2 += words[wordKey].to_string().substr( + start, length); + } + + } auto temp_obj = pmt::make_any(osnmaMsg_sptr); osnma->msg_handler_osnma(temp_obj); // osnma entry point @@ -266,8 +282,12 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) } + + // Assert - // TODO + // ---------- + + // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) } std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std::string& filename) @@ -527,7 +547,7 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = + osnma->d_satellite_nav_data[PRNa][TOW_NavData].utc_vector_2 = "111111111111111111111111111111110000000000000000000000010001001001001000" "111000001000100111100010010111111111011110111111111001001100000100000000"; osnma->d_osnma_data.d_nma_header.nmas = 0b10; From 6671d9bf7befccf77f22732dcb204fa5c757f605 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sun, 9 Jun 2024 22:22:39 +0200 Subject: [PATCH 117/219] [TAS-213] implement configuration_2 osnma test vectors TODO - parametrize test, since now the hardcoded configuration files are to be selected. --- .../osnma/osnma_msg_receiver_test.cc | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 1c4b1c7b9..498fd822c 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -14,6 +14,7 @@ struct TestVector std::vector navBits; }; +// TODO - parametrize class for different configurations (config_1, config_2, etc.. potentially 5 or 6 more) an make sure wont affect current TEST_F class OsnmaMsgReceiverTest : public ::testing::Test { protected: @@ -30,18 +31,22 @@ protected: std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm const uint32_t LEAP_SECONDS = 0;//13 + 5; void set_time(std::tm& input); - std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; +// std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; + std::string log_name {"CONFIG2-2023-07-20-PKID2-MT2-OSNMA"}; void initializeGoogleLog(); void SetUp() override { - flag_CRC_test = false; + flag_CRC_test = false; // TODO what for? page_even = ""; - std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; +// std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; + std::tm input_time = {0, 0, 0, 20, 7 - 1, 2023 - 1900, 0}; set_time(input_time); - std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; - std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; +// std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; +// std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; + std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.pem"; + std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); } @@ -91,7 +96,8 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) initializeGoogleLog(); // Arrange // ---------- - std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); +// std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); + std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); if (testVectors.empty()){ ASSERT_TRUE(false); } @@ -116,7 +122,10 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // Act // ---------- - while (end_of_hex_stream == false){ // loop over all bytes of data. Note all TestVectors have same amount of data. + + // loop over all bytes of data. Note: all TestVectors have same amount of data. + while (end_of_hex_stream == false){ + // loop over all SVs, extract a subframe for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) "<< tv.svId << std::endl; auto osnmaMsg_sptr = std::make_shared(); @@ -162,15 +171,6 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // store raw word std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); words[word_type] = data_combined; -// std::vector concatenatedData; -// for (std::size_t i = 0; i < data_k.size(); i += 8) { -// std::bitset<8> byte(data_k.to_string().substr(i, 8)); -// concatenatedData.push_back(static_cast(byte.to_ulong())); -// } -// for (std::size_t i = 0; i < data_j.size(); i += 8) { -// std::bitset<8> byte(data_j.to_string().substr(i, 8)); -// concatenatedData.push_back(static_cast(byte.to_ulong())); -// } } if(word_type == DUMMY_PAGE) flag_dummy_page = true; @@ -192,6 +192,8 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) flag_dummy_page = false; continue; // skip this SV } + + // Fill osnma object osnmaMsg_sptr->hkroot = hkroot; osnmaMsg_sptr->mack = mack; @@ -201,7 +203,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // TODO - refactor this logic, currently it is split - // check if words 1--> 5 words are received + // check if words 1--> 5 words are received => fill EphClockStatus data vector bool ephClockStatusWordsReceived = true; for (int i = 1; i <= 5; ++i) { @@ -239,10 +241,9 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) } } - // check w6 && w10 is received + // check w6 && w10 is received => fill TimingData data vector bool timingWordsReceived = words.find(6) != words.end() && words.find(10) != words.end(); - // extract bits as needed by osnma block if(timingWordsReceived){ // Define the starting position and length of bits to extract for each word @@ -264,6 +265,8 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) } } + + // Call the handler, as if it came from telemetry decoder block auto temp_obj = pmt::make_any(osnmaMsg_sptr); osnma->msg_handler_osnma(temp_obj); // osnma entry point @@ -412,7 +415,7 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) void OsnmaMsgReceiverTest::initializeGoogleLog() { google::InitGoogleLogging(log_name.c_str()); - FLAGS_minloglevel = 1; + FLAGS_minloglevel = 0; // INFO FLAGS_logtostderr = 0; // add this line FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; if (FLAGS_log_dir.empty()) From 5dfd479cb3e86bae096cf079ae48df2a28d2783f Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 10 Jun 2024 18:59:40 +0200 Subject: [PATCH 118/219] [TAS-216] configuration_2 debug verify_dsm_pkr() and make it work - several bugs fixed for DSM-PKR verification. - improved verification, taking into account leaf position (odd/even), which determines concatenation order. - now: configuration_2 leads to successful DSM-PKR verification. --- src/core/libs/osnma_msg_receiver.cc | 98 +++++++++++++++-------------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 6e0b161c4..f58fd0d29 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -223,19 +223,19 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } // Annotate bid d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; - // TODO FIXME Galileo OSNMA: Available blocks for DSM_ID 6: [ - - - - - X - - - - - - - - - - ] in the first received Sf.. size 16? - LOG(INFO) << "Galileo OSNMA: Available blocks for DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << ": [ "; + std::stringstream available_blocks; + available_blocks << "Galileo OSNMA: Available blocks for DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << ": [ "; if (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == 0) // block 0 not received yet { for (auto id_received : d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id]) { if (id_received == 0) { - LOG(INFO) << "- "; + available_blocks << "- "; } else { - LOG(INFO) << "X "; + available_blocks << "X "; } } } @@ -245,15 +245,16 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ { if (d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][k] == 0) { - LOG(INFO) << "- "; + available_blocks << "- "; } else { - LOG(INFO) << "X "; + available_blocks << "X "; } } } - LOG(INFO) << "]" << std::endl; + available_blocks<< "]" << std::endl; + LOG(INFO) << available_blocks.str() << std::endl; } /** @@ -402,7 +403,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg const uint16_t check_l_dk = 104 * std::ceil(1.0 + static_cast((l_lk_bytes * 8.0) + l_ds_bits) / 104.0); if (l_dk_bits != check_l_dk) { - LOG(ERROR) << "Galileo OSNMA: Failed length reading" << std::endl; + LOG(ERROR) << "Galileo OSNMA: Failed length reading of DSM-KROOT message" << std::endl; } else { @@ -475,58 +476,59 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) { - LOG(WARNING) << "OSNMA: DSM-PKR message received."; + LOG(WARNING) << "Galileo OSNMA: DSM-PKR message received."; // Save DSM-PKR message d_osnma_data.d_dsm_pkr_message.nb_dp = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_pkr_message.mid = d_dsm_reader->get_mid(dsm_msg); - for (int k = 0; k > 128; k++) + for (int k = 0; k < 128; k++) { d_osnma_data.d_dsm_pkr_message.itn[k] = dsm_msg[k + 1]; } d_osnma_data.d_dsm_pkr_message.npkt = d_dsm_reader->get_npkt(dsm_msg); d_osnma_data.d_dsm_pkr_message.npktid = d_dsm_reader->get_npktid(dsm_msg); - uint32_t l_npk = 0; + uint32_t l_npk_bytes = 0; const auto it = OSNMA_TABLE_5.find(d_osnma_data.d_dsm_pkr_message.npkt); if (it != OSNMA_TABLE_5.cend()) { const auto it2 = OSNMA_TABLE_6.find(it->second); if (it2 != OSNMA_TABLE_6.cend()) { - l_npk = it2->second / 8; + l_npk_bytes = it2->second / 8; } } - uint32_t l_dp = dsm_msg.size(); + uint32_t l_dp_bytes = dsm_msg.size(); if (d_osnma_data.d_dsm_pkr_message.npkt == 4) { LOG(WARNING) << "OSNMA: OAM received"; - l_npk = l_dp - 130; // bytes + l_npk_bytes = l_dp_bytes - 130; // bytes } - d_osnma_data.d_dsm_pkr_message.npk = std::vector(l_npk, 0); // ECDSA Public Key - for (uint32_t k = 0; k > l_npk; k++) + d_osnma_data.d_dsm_pkr_message.npk = std::vector(l_npk_bytes, 0); // ECDSA Public Key + for (uint32_t k = 0; k < l_npk_bytes; k++) { d_osnma_data.d_dsm_pkr_message.npk[k] = dsm_msg[k + 130]; } - uint32_t l_pd = l_dp - 130 - l_npk; - uint32_t check_l_dp = 104 * std::ceil(static_cast(1040.0 + l_npk * 8.0) / 104.0); - if (l_dp != check_l_dp) + uint32_t l_pd_bytes = l_dp_bytes - 130 - l_npk_bytes; + uint32_t check_l_dp_bytes = 104 * std::ceil(static_cast(1040.0 + l_npk_bytes * 8.0) / 104.0) / 8; + if (l_dp_bytes != check_l_dp_bytes) { - LOG(ERROR) << "Galileo OSNMA: Failed length reading" << std::endl; + LOG(ERROR) << "Galileo OSNMA: Failed length reading of DSM-PKR message" << std::endl; } else { - d_osnma_data.d_dsm_pkr_message.p_dp = std::vector(l_pd, 0); - for (uint32_t k = 0; k < l_pd; k++) + d_osnma_data.d_dsm_pkr_message.p_dp = std::vector(l_pd_bytes, 0); + for (uint32_t k = 0; k < l_pd_bytes; k++) { - d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp - l_pd + k]; + d_osnma_data.d_dsm_pkr_message.p_dp[k] = dsm_msg[l_dp_bytes - l_pd_bytes + k]; } + // TODO: kroot fields are 0 in case no DSM-KROOT received yet, need to take this into account. // std::vector mi; // (NPKT + NPKID + NPK) LOG(INFO) << "Galileo OSNMA: DSM-PKR with CID=" << static_cast(d_osnma_data.d_nma_header.cid) - << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) - << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) - << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 + << ", PKID=" << static_cast(d_osnma_data.d_dsm_pkr_message.npktid) + /*<< ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) + << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600*/ << " received" << std::endl; // C: NPK verification against Merkle tree root. if (!d_public_key_verified) @@ -962,35 +964,39 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) // TODO create function for recursively apply hash // build base leaf m_i -// auto leaf = message.mid; std::vector m_i; m_i.reserve(2 + message.npk.size()); - m_i[0] = message.npkt; - m_i[1] = message.npktid; - for (uint8_t i = 2; i < m_i.size(); i++) + m_i.push_back((message.npkt << 4) + message.npktid); + for (uint8_t i = 0; i < message.npk.size(); i++) { m_i.push_back(message.npk[i]); } // compute intermediate leafs' values - std::vector x_0,x_1,x_2,x_3,x_4; -// uint8_t k = 0; - x_0 = d_crypto->computeSHA256(m_i); - x_0.insert(x_0.end(),message.itn.begin(),&message.itn[31]); - x_1 = d_crypto->computeSHA256(x_0); - x_1.insert(x_1.end(),&message.itn[32],&message.itn[63]); - x_2 = d_crypto->computeSHA256(x_1); - x_2.insert(x_2.end(),&message.itn[64],&message.itn[95]); - x_3 = d_crypto->computeSHA256(x_2); - x_3.insert(x_3.end(),&message.itn[96],&message.itn[127]); - // root leaf computation - x_4 = d_crypto->computeSHA256(x_3); +// std::vector x_0,x_1,x_2,x_3,x_4; + LOG(INFO) << "Galileo OSNMA: DSM-PKR :: leaf provided: m_" << static_cast(message.mid) << std::endl; - // C: d_crypto->getMerkleRoot([m_0:m_15]) I realised I could have done this... - // C: ... but why computing all the possible results? I have only one leaf in each osnma message... - // verify that computed root matches merkle root + std::vector x_next, x_current = d_crypto->computeSHA256(m_i); + for (size_t i = 0 ; i < 4 ; i++) + { + x_next.clear(); + bool leaf_is_on_right = ((message.mid / (1 << (i))) % 2) == 1; - if(x_4 == d_crypto->getMerkleRoot()) + if (leaf_is_on_right) { + // Leaf is on the right -> first the itn, then concatenate the leaf + x_next.insert(x_next.end(), &message.itn[32*i], &message.itn[32*i + 32]); + x_next.insert(x_next.end(), x_current.begin(), x_current.end()); + } else { + // Leaf is on the left -> first the leaf, then concatenate the itn + x_next.insert(x_next.end(), x_current.begin(), x_current.end()); + x_next.insert(x_next.end(), &message.itn[32*i], &message.itn[32*i + 32]); + } + + // Compute the next node. + x_current = d_crypto->computeSHA256(x_next); + } + + if(x_current == d_crypto->getMerkleRoot()) { LOG(INFO) << "Galileo OSNMA: DSM-PKR verified successfully! " << std::endl; return true; From 4f7a22f35c80a737eb6d96f4140d118abd490fc9 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 10 Jun 2024 19:01:17 +0200 Subject: [PATCH 119/219] [TAS-219] Configuration_2, num_of_hashes needed huge - Confused PK date with recording date, lead to Kroot time to be in the future (impossible) --- .../signal-processing-blocks/osnma/osnma_msg_receiver_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 498fd822c..c480f9cb8 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -32,7 +32,7 @@ protected: const uint32_t LEAP_SECONDS = 0;//13 + 5; void set_time(std::tm& input); // std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; - std::string log_name {"CONFIG2-2023-07-20-PKID2-MT2-OSNMA"}; + std::string log_name {"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; void initializeGoogleLog(); void SetUp() override @@ -41,7 +41,7 @@ protected: page_even = ""; // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; - std::tm input_time = {0, 0, 0, 20, 7 - 1, 2023 - 1900, 0}; + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; set_time(input_time); // std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; // std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; From 8de00f92bf517755788056bdb084ccc9d48f82b4 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 10 Jun 2024 19:47:41 +0200 Subject: [PATCH 120/219] [TAS-198] tag verification: debug MACSEQ (flex) - reset the d_GST_Sf computation being d_GST_SIS - 30 seconds. All FLX tags successfuly verified. --- src/core/libs/osnma_msg_receiver.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index f58fd0d29..92c06497a 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -1255,7 +1255,7 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) { // MACSEQ verification - //d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. + d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. std::vector applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe std::vector sq1{}; std::vector sq2{}; @@ -1310,7 +1310,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) // Fixed as well as FLX Tags share first part - Eq. 22 ICD std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag - m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); + m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); // TODO d_GST_Sf left useless m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); m[4] = static_cast(d_GST_Sf & 0x000000FF); @@ -1321,10 +1321,6 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) m[2*i + 6] = mack.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | mack.tag_and_info[flxTags[i]].tag_info.cop; } - // m = {0x18, 0x4f, 0x93, 0x53, 0x04, 0x05, 0x0f, 0x1f, 0x0f}; - // applicable_key = {0x11, 0x26, 0x47, 0x3b, 0x0e, 0x05, 0x05, 0x35, - // 0xb0, 0xf2, 0xa7, 0x24, 0x00, 0x22, 0xba, 0x8f}; - // applicable_OSNMA.d_mack_message.header.macseq = 0xbb8; // compute mac std::vector mac; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 From 0e168a8ff03b90ec1626916f5b5f4c59093c1ae9 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 11 Jun 2024 14:16:36 +0200 Subject: [PATCH 121/219] Build fixes --- src/core/libs/osnma_msg_receiver.cc | 7 ++++++- src/core/system_parameters/CMakeLists.txt | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 92c06497a..c7fe99558 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -23,7 +23,6 @@ #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "osnma_helper.h" -#include // for DLOG #include // for gr::io_signature::make #include #include @@ -32,6 +31,12 @@ #include #include // for typeid +#if USE_GLOG_AND_GFLAGS +#include // for DLOG +#else +#include +#endif + #if HAS_GENERIC_LAMBDA #else #include diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 02f727d31..518e64264 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -96,8 +96,8 @@ set(SYSTEM_PARAMETERS_HEADERS Galileo_OSNMA.h osnma_data.h osnma_dsm_reader.h - osnma_helper.cc - osnma_helper.h + osnma_helper.cc + osnma_helper.h ) list(SORT SYSTEM_PARAMETERS_HEADERS) @@ -123,6 +123,8 @@ target_link_libraries(core_system_parameters PUBLIC Boost::date_time Boost::serialization + PRIVATE + Pugixml::pugixml ) if(ENABLE_GLOG_AND_GFLAGS) From ed32e84402e478467cfd329b03fb1f425f277e2c Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 11 Jun 2024 18:33:58 +0200 Subject: [PATCH 122/219] [TAS-221] [BUG] FLX tag verification fails for recorded signals but succeeds for configuration_2 (otv) Implemented changes to ensure accurate computation of the d_GST_Sf in message receiver. Checked test is not affected by this. Logging improvements have been made. --- src/core/libs/osnma_msg_receiver.cc | 27 +++++++++++-------- src/core/system_parameters/osnma_helper.cc | 10 +++++++ .../osnma/osnma_msg_receiver_test.cc | 2 ++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 92c06497a..f89cb6824 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -91,15 +91,19 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) { const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); - LOG(WARNING) << "Galileo OSNMA: Subframe received starting at " - << "WN=" - << nma_msg->WN_sf0 - << ", TOW=" - << nma_msg->TOW_sf0 - << ", from satellite " - << sat; - process_osnma_message(nma_msg); + std::ostringstream output_message; + output_message << "Galileo OSNMA: Subframe received starting at " + << "WN=" + << nma_msg->WN_sf0 + << ", TOW=" + << nma_msg->TOW_sf0 + << ", from satellite " + << sat; + LOG(WARNING) << output_message.str(); + std::cout << output_message.str() << std::endl; + + process_osnma_message(nma_msg); } else @@ -1079,6 +1083,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) if(tag.CTR != 1) m.push_back(static_cast(tag.PRN_d)); m.push_back(static_cast(tag.PRNa)); + // TODO: maybe here I have to use d_receiver_time instead of d_GST_SIS which is what I am computing uint32_t GST = d_helper->compute_gst( tag.WN,tag.TOW); std::vector GST_uint8 = d_helper->gst_to_uint8(GST); m.insert(m.end(),GST_uint8.begin(),GST_uint8.end()); @@ -1091,7 +1096,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) // Add applicable NavData bits to message std::string applicable_nav_data; std::vector applicable_nav_data_bytes; - if (tag.ADKD == 0 || tag.ADKD == 12) + if (tag.ADKD == 0 || tag.ADKD == 12) // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. { applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; } @@ -1100,7 +1105,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].utc_vector_2; } else - std::cerr<<"Galileo OSNMA :: Tag verification :: unknown ADKD" <<"\n"; + LOG(ERROR) <<"Galileo OSNMA :: Tag verification :: unknown ADKD" <<"\n"; // convert std::string to vector applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); @@ -1255,7 +1260,7 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) { // MACSEQ verification - d_GST_Sf = d_GST_SIS - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. + d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. std::vector applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe std::vector sq1{}; std::vector sq2{}; diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index b67454ddd..9ce394543 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -34,6 +34,16 @@ std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const return res; } +/** + * @brief Convert a binary string to a vector of bytes. + * + * This function takes a binary string and converts it into a vector of uint8_t bytes. + * The binary string is padded with zeros if necessary to ensure that the total number + * of bits is a multiple of a byte. + * + * @param binaryString The binary string to be converted. + * @return The vector of bytes converted from the binary string. + */ std::vector Osnma_Helper::bytes(const std::string& binaryString) { std::vector bytes; diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index c480f9cb8..226e8e892 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -408,6 +408,8 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) this->TOW = time_of_week + LEAP_SECONDS; // Return the week number and time of week as a pair + // TODO: d_GST_SIS or d_receiver_time? doubt + // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); From 1a32ccaa19bc817a4bddd4f488240abba36e0981 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 13 Jun 2024 01:13:17 +0200 Subject: [PATCH 123/219] [TAS-208 WIP ] [Feature] Retrieve directly NavData bits from Telemetry Decoder (ADKD4 and 0/12) - appear to retrieve data as expected. - However, tag verification fails still (new dat file) --- .../galileo_telemetry_decoder_gs.cc | 24 ++++++++++++++----- .../galileo_telemetry_decoder_gs.h | 6 ++--- .../system_parameters/galileo_inav_message.cc | 24 +++++++++++++++++++ .../system_parameters/galileo_inav_message.h | 19 +++++++++++++++ 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 859ef8b86..14e1c52d8 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -471,7 +471,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); d_first_eph_sent = true; // do not send reduced CED anymore, since we have the full ephemeris set - d_flag_osnma_ephemeris = true; + d_flag_osnma_adkd_0_12 = true; // W1-> W5 available } else { @@ -522,7 +522,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in << " dB-Hz" << TEXT_RESET << std::endl; } - d_flag_osnma_iono_and_time = true; } if (d_inav_nav.have_new_utc_model() == true) @@ -559,7 +558,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_delta_t = tmp_obj->A_0G + tmp_obj->A_1G * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - tmp_obj->t_0G + 604800 * (std::fmod(static_cast(d_inav_nav.get_Galileo_week() - tmp_obj->WN_0G), 64.0))); DLOG(INFO) << "delta_t=" << d_delta_t << "[s]"; - d_flag_osnma_utc_model = true; + d_flag_osnma_adkd_4_utc = true; } if (d_inav_nav.have_new_almanac() == true) @@ -593,15 +592,28 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in DLOG(INFO) << "Current parameters:"; DLOG(INFO) << "d_TOW_at_current_symbol_ms=" << d_TOW_at_current_symbol_ms; DLOG(INFO) << "d_nav.WN_0=" << d_inav_nav.get_Galileo_week(); + + d_flag_osnma_adkd_4_gst = true; } // get osnma message if the needed nav data is available - auto adkd_4_12_nav_data_available = d_flag_osnma_iono_and_time && d_flag_osnma_ephemeris; - auto newOSNMA = d_inav_nav.have_new_nma(); - if (d_band == '1' && newOSNMA && adkd_4_12_nav_data_available == true && d_flag_osnma_utc_model == true) + bool adkd_4_nav_data_available = d_flag_osnma_adkd_4_utc && d_flag_osnma_adkd_4_gst; + auto newOSNMA = d_inav_nav.have_new_nma();if (d_band == '1' && newOSNMA && (adkd_4_nav_data_available == true || d_flag_osnma_adkd_0_12 == true)) { + + const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); + + if(adkd_4_nav_data_available) + tmp_obj->TimingData_2 = d_inav_nav.get_osnma_adkd_4_nav_bits(); + if(d_flag_osnma_adkd_0_12) + tmp_obj->EphemerisClockAndStatusData_2 = d_inav_nav.get_osnma_adkd_0_12_nav_bits(); + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); + + d_flag_osnma_adkd_4_utc= false; + d_flag_osnma_adkd_4_gst = false; + d_flag_osnma_adkd_0_12 = false; } } diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h index bad8c8fc5..4b1725e8a 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h @@ -155,9 +155,9 @@ private: bool d_there_are_e1_channels; bool d_there_are_e6_channels; bool d_use_ced; - bool d_flag_osnma_ephemeris; // flag to indicate if the ephemeris is complete for OSNMA processing - bool d_flag_osnma_utc_model; // flag to indicate if the GST conversion parameters are complete for OSNMA processing - bool d_flag_osnma_iono_and_time; // flag to indicate if the iono correction and time is complete for OSNMA processing + bool d_flag_osnma_adkd_0_12; // flag to indicate if the ephemeris is complete for OSNMA processing + bool d_flag_osnma_adkd_4_gst; // flag to indicate if the GST conversion parameters are complete for OSNMA processing + bool d_flag_osnma_adkd_4_utc; // flag to indicate if the iono correction and time is complete for OSNMA processing }; diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index d31bd781b..442f67178 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -614,6 +614,7 @@ void Galileo_Inav_Message::read_page_1(const std::bitset& DLOG(INFO) << "A_1= " << A_1; flag_ephemeris_1 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + nav_bits_word_1 = data_bits.to_string().substr(5,120); } @@ -635,6 +636,7 @@ void Galileo_Inav_Message::read_page_2(const std::bitset& DLOG(INFO) << "iDot_2= " << iDot_2; flag_ephemeris_2 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + nav_bits_word_2 = data_bits.to_string().substr(5,120); } @@ -664,6 +666,7 @@ void Galileo_Inav_Message::read_page_3(const std::bitset& DLOG(INFO) << "SISA_3= " << SISA_3; flag_ephemeris_3 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + nav_bits_word_3 = data_bits.to_string().substr(5, 122); } @@ -697,6 +700,7 @@ void Galileo_Inav_Message::read_page_4(const std::bitset& DLOG(INFO) << "spare_4 = " << spare_4; flag_ephemeris_4 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + nav_bits_word_4 = data_bits.to_string().substr(5, 120); } @@ -1016,6 +1020,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) flag_iono_and_GST = true; // set to false externally flag_TOW_set = true; // set to false externally DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + nav_bits_word_5 = data_jk_bits.to_string().substr(5, 67); break; case 6: // Word type 6: GST-UTC conversion parameters @@ -1045,6 +1050,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) flag_utc_model = true; // set to false externally flag_TOW_set = true; // set to false externally DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + nav_bits_word_6 = data_jk_bits.to_string().substr(5, 99); break; case 7: // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number @@ -1201,6 +1207,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) DLOG(INFO) << "WN_0G_10= " << WN_0G_10; flag_almanac_4 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; + nav_bits_word_10 = data_jk_bits.to_string().substr(85, 42); break; case 16: // Word type 16: Reduced Clock and Ephemeris Data (CED) parameters @@ -1425,3 +1432,20 @@ bool Galileo_Inav_Message::have_new_nma() return false; } } +std::string Galileo_Inav_Message::get_osnma_adkd_4_nav_bits() +{ + nav_bits_adkd_4 = nav_bits_word_6 + nav_bits_word_10; + nav_bits_word_6 = ""; + nav_bits_word_10 = ""; + return nav_bits_adkd_4; +} +std::string Galileo_Inav_Message::get_osnma_adkd_0_12_nav_bits() +{ + nav_bits_adkd_0_12 = nav_bits_word_1 + nav_bits_word_2 + nav_bits_word_3 + nav_bits_word_4 + nav_bits_word_5; + nav_bits_word_1 = ""; + nav_bits_word_2 = ""; + nav_bits_word_3 = ""; + nav_bits_word_4 = ""; + nav_bits_word_5 = ""; + return nav_bits_adkd_0_12; +} diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index bc5d5f780..19999a735 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -139,6 +139,16 @@ public: */ OSNMA_msg get_osnma_msg(); + /* + * @brief Retrieves the OSNMA ADKD 4 NAV bits. Resets the string. + */ + std::string get_osnma_adkd_4_nav_bits(); + + /* + * @brief Retrieves the OSNMA ADKD 0/12 NAV bits. Resets the string. + */ + std::string get_osnma_adkd_0_12_nav_bits(); + inline bool get_flag_CRC_test() const { return flag_CRC_test; @@ -430,6 +440,15 @@ private: uint8_t page_position_in_inav_subframe{255}; std::array nma_position_filled{}; OSNMA_msg nma_msg{}; + std::string nav_bits_adkd_4{}; + std::string nav_bits_word_6{}; + std::string nav_bits_word_10{}; + std::string nav_bits_adkd_0_12{}; + std::string nav_bits_word_1{}; + std::string nav_bits_word_2{}; + std::string nav_bits_word_3{}; + std::string nav_bits_word_4{}; + std::string nav_bits_word_5{}; uint8_t IODnav_LSB17{}; uint8_t IODnav_LSB18{}; From d41efd2653004abd35d60f5c2d582b8b14eb1b58 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 21 Jun 2024 10:29:20 +0200 Subject: [PATCH 124/219] Really fix signature verification with GnuTLS --- src/core/system_parameters/gnss_crypto.cc | 364 ++++++++-------------- src/core/system_parameters/gnss_crypto.h | 34 +- 2 files changed, 143 insertions(+), 255 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index d3cd11380..12d113ae0 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -1,7 +1,8 @@ /*! * \file gnss_crypto.cc - * \brief Class for computing cryptografic functions - * \author Carles Fernandez, 2023. cfernandez(at)cttc.es + * \brief Class for computing cryptographic functions + * \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es + * Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de * * * ----------------------------------------------------------------------------- @@ -9,7 +10,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -20,9 +21,9 @@ #include #include #include +#include #include #include -#include #if USE_OPENSSL_FALLBACK #include @@ -30,29 +31,27 @@ #include #include #if USE_OPENSSL_3 -#include #include +#include #include #include -#include #include -#include #define OPENSSL_ENGINE nullptr #else #include #endif -#else +#else // GnuTLS +#include #include #include #include -#include #endif Gnss_Crypto::Gnss_Crypto(const std::string& pemFilePath, const std::string& merkleTreePath) { #if USE_OPENSSL_FALLBACK -#else - // gnutls_global_init(); +#else // GnuTLS + gnutls_global_init(); #endif readPublicKeyFromPEM(pemFilePath); read_merkle_xml(merkleTreePath); @@ -69,11 +68,13 @@ Gnss_Crypto::~Gnss_Crypto() EC_KEY_free(d_PublicKey); } #endif -#else // GNU-TLS - if (d_PublicKey != NULL) { +#else // GnuTLS + if (d_PublicKey != NULL) + { gnutls_pubkey_deinit(d_PublicKey); d_PublicKey = NULL; } + gnutls_global_deinit(); #endif } @@ -82,25 +83,12 @@ bool Gnss_Crypto::have_public_key() const { #if USE_OPENSSL_FALLBACK return (d_PublicKey != nullptr); -#else +#else // GnuTLS return (d_PublicKey != gnutls_pubkey_t{}); #endif } -std::string Gnss_Crypto::convert_to_utf8_str(const std::vector& input) const -{ - const char hex[] = "0123456789ABCDEF"; - std::string str(input.size() * 2, '0'); - for (size_t i = 0; i < input.size(); i++) - { - str[(i * 2) + 0] = hex[((input[i] & 0xF0) >> 4)]; - str[(i * 2) + 1] = hex[((input[i] & 0x0F))]; - } - return str; -} - - std::vector Gnss_Crypto::convert_from_hex_str(const std::string& input) const { std::vector result; @@ -236,11 +224,6 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) } -// void Gnss_Crypto::set_public_key(const std::vector& publickey) -// { -// } - - std::vector Gnss_Crypto::computeSHA256(const std::vector& input) const { std::vector output(32); // SHA256 hash size @@ -273,7 +256,7 @@ std::vector Gnss_Crypto::computeSHA256(const std::vector& inpu SHA256_Update(&sha256Context, input.data(), input.size()); SHA256_Final(output.data(), &sha256Context); #endif -#else +#else // GnuTLS std::vector output_aux(32); gnutls_hash_hd_t hashHandle; gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); @@ -301,7 +284,7 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in #else // SHA3-256 not implemented in OpenSSL < 3.0 #endif -#else +#else // GnuTLS std::vector output_aux(32); gnutls_hash_hd_t hashHandle; gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); @@ -358,7 +341,7 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector hmac.resize(hmacLen); output = hmac; #endif -#else +#else // GnuTLS std::vector output_aux(32); gnutls_hmac_hd_t hmac; gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); @@ -421,7 +404,7 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke output = mac; #endif -#else +#else // GnuTLS gnutls_cipher_hd_t cipher; std::vector mac(16); std::vector message = input; @@ -471,8 +454,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) std::cerr << "OpenSSL: error reading the Public Key from file " << pemFilePath << ". Aborting import" << std::endl; return; } - -#else +#else // GnuTLS // Import the PEM data gnutls_datum_t pemDatum = {const_cast(reinterpret_cast(pemContent.data())), static_cast(pemContent.size())}; gnutls_pubkey_t pubkey; @@ -493,62 +475,21 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) gnutls_pubkey_deinit(pubkey); #endif std::cout << "Public key successfully read from file " << pemFilePath << std::endl; - //print_pubkey_hex(d_PublicKey); } -bool Gnss_Crypto::verify_signature(const std::vector& message, const std::vector& signature) +bool Gnss_Crypto::verify_signature(const std::vector& message, const std::vector& signature) const { std::vector digest = this->computeSHA256(message); if (!have_public_key()) { - std::cerr << "Galileo OSNMA::Kroot verification error::Public key not available"<< std::endl; + std::cerr << "Galileo OSNMA KROOT verification error: Public key is not available" << std::endl; return false; } bool success = false; #if USE_OPENSSL_FALLBACK -// using low-level API to test function -- it works in unit tests, not in real bytes. -// EVP_MD_CTX *mdctx = NULL; // verification context; a struct that wraps the message to be verified. -// int ret = 0; // error -// -// /* Create the Message Digest Context */ -// if(!(mdctx = EVP_MD_CTX_new())) goto err; // Allocates and returns a digest context. -// -// /* Initialize `key` with a public key */ -// // hashes cnt bytes of data at d into the verification context ctx -// if(1 != EVP_DigestVerifyInit(mdctx, NULL /*TODO null?*/, EVP_sha256(), NULL, d_PublicKey)) goto err; -// -// /* Initialize `key` with a public key */ -// if(1 != EVP_DigestVerifyUpdate(mdctx, message.data(), message.size())) goto err; -// -// -// if( 1 == EVP_DigestVerifyFinal(mdctx, signature.data(), signature.size())) -// { -// return true; -// } -// else -// { -// unsigned long errCode = ERR_get_error(); -// int lib_code = ERR_GET_LIB(errCode); -// char* err = ERR_error_string(errCode, NULL); -// const char* error_string = ERR_error_string(errCode, NULL); -// std::cerr << "OpenSSL: message authentication failed: " << err /*<< -// "from library with code " << lib_code << -// " error string: " << error_string */<< std::endl; -// } -//err: -// if(ret != 1) -// { -// /* Do some error handling */ -// // notify other blocks -// std::cout << "ECDSA_Verify_OSSL()::error " << ret << std::endl; -// -// } - - #if USE_OPENSSL_3 EVP_PKEY_CTX* ctx; - //print_pubkey_hex(d_PublicKey); ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); bool do_operation = true; @@ -556,7 +497,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st { do_operation = false; } - // convert raw signature into DER format, needed for verify_signature + // convert raw signature into DER format size_t half_size = signature.size() / 2; std::vector raw_r(signature.begin(), signature.begin() + half_size); std::vector raw_s(signature.begin() + half_size, signature.end()); @@ -575,12 +516,12 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st if (ECDSA_SIG_set0(sig, r, s) != 1) { std::cerr << "Failed to set R and S values in ECDSA_SIG" << std::endl; - ECDSA_SIG_free(sig); // Free the ECDSA_SIG struct as it's no longer needed + ECDSA_SIG_free(sig); // Free the ECDSA_SIG struct as it is no longer needed return false; } std::vector derSignature; - unsigned char *derSig = nullptr; + unsigned char* derSig = nullptr; int derSigLength = i2d_ECDSA_SIG(sig, &derSig); if (derSigLength <= 0) @@ -591,7 +532,6 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st derSignature.assign(derSig, derSig + derSigLength); - if (EVP_PKEY_verify_init(ctx) <= 0) { do_operation = false; @@ -616,10 +556,9 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st { unsigned long errCode = ERR_get_error(); char* err = ERR_error_string(errCode, NULL); - std::cerr << "OpenSSL: message authentication failed: " << err << std::endl; + std::cerr << "OpenSSL: message authentication failed: " << err << std::endl; } #else - auto digest = this->computeSHA256(message); int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, signature.data(), static_cast(signature.size()), d_PublicKey); if (verification == 1) { @@ -635,34 +574,26 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } #endif -#else - // GNU-TLS - gnutls_global_init(); - // debug info gnu-tls remove when not needed anymore! - gnutls_global_set_log_level(9); - gnutls_global_set_log_function(Gnss_Crypto::my_log_func); +#else // GnuTLS + // Convert signature to DER format + std::vector der_sig; + if (!convert_raw_to_der_ecdsa(signature, der_sig)) + { + std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; + return false; + } - unsigned int bit_size; - if (gnutls_pubkey_get_pk_algorithm(d_PublicKey, &bit_size) != GNUTLS_PK_ECDSA) + // Prepare the digest datum + gnutls_datum_t digest_data = {const_cast(digest.data()), static_cast(digest.size())}; + gnutls_datum_t der_sig_data = {der_sig.data(), static_cast(der_sig.size())}; + + // Verify the DER-encoded signature + int ret = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &digest_data, &der_sig_data); + success = (ret >= 0); + if (!success) { - std::cerr << "GnuTLS: the Public Key does not contain a ECDSA key. Aborting signature verification" << std::endl; + std::cerr << "GnuTLS: message authentication failed: " << gnutls_strerror(ret) << std::endl; } - gnutls_datum_t signature_{}; - signature_.data = const_cast(signature.data()); - signature_.size = signature.size(); - gnutls_datum_t data_{}; - data_.data = const_cast(message.data()); - data_.size = message.size(); - int ret = gnutls_pubkey_verify_data2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &data_, &signature_); - if (ret >= 0) - { - success = true; - } - else - { - std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; - } - gnutls_global_deinit(); #endif return success; } @@ -707,75 +638,47 @@ std::vector Gnss_Crypto::getMerkleRoot(const std::vector& publicKey) { #if USE_OPENSSL_FALLBACK - BIO *bio = NULL; - EVP_PKEY *pkey = NULL; + BIO* bio = NULL; + EVP_PKEY* pkey = NULL; bio = BIO_new_mem_buf(publicKey.data(), publicKey.size()); - if (!bio) { + if (!bio) + { std::cerr << "Failed to create BIO for key \n"; return; } - pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); - BIO_free(bio); + pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + BIO_free(bio); - if (!pkey) { - std::cerr << "OpenSSL: error setting the public key " - << ". Aborting import" << std::endl; + if (!pkey) + { + std::cerr << "OpenSSL: error setting the public key." << std::endl; return; } - //print_pubkey_hex(pkey); - - if(!pubkey_copy(pkey, &d_PublicKey)) - return - - EVP_PKEY_free(pkey); -#else -// // GNU-TLS -// gnutls_global_init(); -// -// // debug info gnu-tls remove when not needed anymore! -// gnutls_global_set_log_level(9); -// gnutls_global_set_log_function(Gnss_Crypto::my_log_func); + if (!pubkey_copy(pkey, &d_PublicKey)) + { + return; + } + EVP_PKEY_free(pkey); +#else // GnuTLS gnutls_pubkey_t pubkey; gnutls_datum_t pemDatum = {const_cast(publicKey.data()), static_cast(publicKey.size())}; gnutls_pubkey_init(&pubkey); int ret = gnutls_pubkey_import(pubkey, &pemDatum, GNUTLS_X509_FMT_PEM); - //ret = gnutls_pubkey_import_x509_raw(pubkey, &pemDatum,GNUTLS_X509_FMT_PEM,0); if (ret != GNUTLS_E_SUCCESS) { gnutls_pubkey_deinit(pubkey); - std::cerr << "GnuTLS: error setting the public key " - << ". Aborting import" << std::endl; + std::cerr << "GnuTLS: error setting the public key" << std::endl; std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; return; } - // d_PublicKey = pubkey; pubkey_copy(pubkey, &d_PublicKey); -// std::cout << "pubkey: " << std::endl; -// print_pubkey_hex(pubkey); -// std::cout << "d_PublicKey before : " << std::endl; -// print_pubkey_hex(d_PublicKey); gnutls_pubkey_deinit(pubkey); -// std::cout << "d_PublicKey after: " << std::endl; -// print_pubkey_hex(d_PublicKey); - -// gnutls_global_deinit(); #endif - } -std::vector Gnss_Crypto::get_public_key() -{ -#if USE_OPENSSL_FALLBACK - // TODO -#else -// GNU-TLS - // TODO -#endif - return {}; -} #if USE_OPENSSL_FALLBACK bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) @@ -794,9 +697,6 @@ bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) return false; } - // Add a null-terminator to the data in the memory buffer - //BIO_write(mem_bio, "\0", 1); - // Read the data from the memory buffer char* bio_data; long data_len = BIO_get_mem_data(mem_bio, &bio_data); @@ -824,95 +724,87 @@ bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) return true; } -void Gnss_Crypto::print_pubkey_hex(EVP_PKEY* pubkey) + +#else // GnuTLS-specific functions + +bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const { - BIO* mem_bio = BIO_new(BIO_s_mem()); - if (!mem_bio) { - std::cerr << "Failed to create new memory BIO\n"; - return; + if (raw_signature.size() % 2 != 0) + { + std::cerr << "Invalid raw ECDSA signature size" << std::endl; + return false; } - if (!PEM_write_bio_PUBKEY(mem_bio, pubkey)){ - std::cerr << "Failed to write public key to BIO\n"; - BIO_free(mem_bio); - return; + size_t half_size = raw_signature.size() / 2; + std::vector raw_r(raw_signature.begin(), raw_signature.begin() + half_size); + std::vector raw_s(raw_signature.begin() + half_size, raw_signature.end()); + + auto encode_asn1_integer = [](const std::vector& value) -> std::vector { + std::vector result; + result.push_back(0x02); // INTEGER tag + + if (value[0] & 0x80) + { + result.push_back(value.size() + 1); // Length byte + result.push_back(0x00); // Add leading zero byte to ensure positive integer + } + else + { + result.push_back(value.size()); // Length byte + } + + result.insert(result.end(), value.begin(), value.end()); + return result; + }; + + std::vector der_r = encode_asn1_integer(raw_r); + std::vector der_s = encode_asn1_integer(raw_s); + + size_t total_length = der_r.size() + der_s.size(); + der_signature.push_back(0x30); // SEQUENCE tag + if (total_length > 127) + { + der_signature.push_back(0x81); // Long form length } + der_signature.push_back(static_cast(total_length)); - BUF_MEM* mem_ptr; - BIO_get_mem_ptr(mem_bio, &mem_ptr); // Fetch the underlying BUF_MEM structure from the BIO. + der_signature.insert(der_signature.end(), der_r.begin(), der_r.end()); + der_signature.insert(der_signature.end(), der_s.begin(), der_s.end()); - std::stringstream ss; - - // Iterate through each byte in mem_ptr->data and print its hex value. - for (size_t i = 0; i < mem_ptr->length; i++) { - ss << std::hex << std::setw(2) << std::setfill('0') << - static_cast(static_cast(mem_ptr->data[i])); - } - - //std::cout << "Public key in hex format: 0x" << ss.str() << std::endl; - - BIO_free(mem_bio); + return true; } -#else // gnutls-specific functions - void Gnss_Crypto::my_log_func(int level, const char *msg){ - fprintf(stderr, " %s", level, msg);} - bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) - { - gnutls_datum_t key_datum; - int ret; - // Export the public key from src to memory - ret = gnutls_pubkey_export2(src, GNUTLS_X509_FMT_PEM, &key_datum); - if (ret < 0) - { - gnutls_free(key_datum.data); - return false; - } +bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) +{ + gnutls_datum_t key_datum; - // Initialize dest - ret = gnutls_pubkey_init(dest); - if (ret < 0) - { - gnutls_free(key_datum.data); - return false; - } + // Export the public key from src to memory + int ret = gnutls_pubkey_export2(src, GNUTLS_X509_FMT_PEM, &key_datum); + if (ret < 0) + { + gnutls_free(key_datum.data); + return false; + } - // Import the public key data from key_datum to dest - ret = gnutls_pubkey_import(*dest, &key_datum, GNUTLS_X509_FMT_PEM); - gnutls_free(key_datum.data); + // Initialize dest + ret = gnutls_pubkey_init(dest); + if (ret < 0) + { + gnutls_free(key_datum.data); + return false; + } - if (ret < 0) - { - gnutls_pubkey_deinit(*dest); - return false; - } + // Import the public key data from key_datum to dest + ret = gnutls_pubkey_import(*dest, &key_datum, GNUTLS_X509_FMT_PEM); + gnutls_free(key_datum.data); - return true; - } + if (ret < 0) + { + gnutls_pubkey_deinit(*dest); + return false; + } - void Gnss_Crypto::print_pubkey_hex(gnutls_pubkey_t pubkey) - { - gnutls_datum_t key_datum; - int ret; - - // Export the public key from pubkey to memory in DER format - ret = gnutls_pubkey_export2(pubkey, GNUTLS_X509_FMT_PEM, &key_datum); - if (ret < 0) { - std::cerr << "Failed to export public key: " << gnutls_strerror(ret) << std::endl; - return; - } - - std::stringstream ss; - - // Iterate through each byte in key_datum.data and print its hex value - for (unsigned int i = 0; i < key_datum.size; ++i) { - ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(key_datum.data[i]); - } - - std::cout << "Public key in hex format: 0x" << ss.str() << std::endl; - - // Free the memory allocated to key_datum.data - gnutls_free(key_datum.data); - } + return true; +} #endif diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 1191a7ed5..41341d981 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -1,7 +1,8 @@ /*! * \file gnss_crypto.h - * \brief Class for computing cryptografic functions - * \author Carles Fernandez, 2023. cfernandez(at)cttc.es + * \brief Class for computing cryptographic functions + * \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es + * Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de * * * ----------------------------------------------------------------------------- @@ -9,7 +10,7 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -38,40 +39,35 @@ public: Gnss_Crypto() = default; ~Gnss_Crypto(); Gnss_Crypto(const std::string& pemFilePath, const std::string& merkleTreePath); + + void readPublicKeyFromPEM(const std::string& pemFilePath); + void read_merkle_xml(const std::string& merkleFilePath); + void set_public_key(const std::vector& publickey); bool have_public_key() const; - std::string convert_to_utf8_str(const std::vector& input) const; - std::vector convert_from_hex_str(const std::string& input) const; + bool verify_signature(const std::vector& message, const std::vector& signature) const; std::vector computeSHA256(const std::vector& input) const; std::vector computeSHA3_256(const std::vector& input) const; std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; - - bool verify_signature(const std::vector& message, const std::vector& signature); - void readPublicKeyFromPEM(const std::string& pemFilePath); - void read_merkle_xml(const std::string& merkleFilePath); std::vector getMerkleRoot(const std::vector>& merkle) const; - std::vector getMerkleRoot() const + + inline std::vector getMerkleRoot() const { return d_x_4_0; } - void set_public_key(const std::vector& publickey); - static std::vector get_public_key(); - private: + std::vector convert_from_hex_str(const std::string& input) const; #if USE_OPENSSL_FALLBACK - bool pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest); - void print_pubkey_hex(EVP_PKEY* pubkey); #if USE_OPENSSL_3 EVP_PKEY* d_PublicKey{}; #else EC_KEY* d_PublicKey = nullptr; #endif -#else + bool pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest); +#else // GnuTLS gnutls_pubkey_t d_PublicKey{}; - void set_ecc_key(const std::vector& pK, const std::vector ecP); - static void my_log_func(int level, const char* msg); - void print_pubkey_hex(gnutls_pubkey_t); + bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; bool pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest); #endif std::vector d_x_4_0; From c8c7d4c3520164f8425920e378c47bc0c46ef4bd Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Fri, 21 Jun 2024 19:46:49 +0200 Subject: [PATCH 125/219] [TAS-224] Update telemetry decoder to directly process Navigation Data bits This update refactors the telemetry decoder to directly retrieve and compute Navigation Data bits. WIP as the tag verification still fails --- .../galileo_telemetry_decoder_gs.cc | 56 +++++--- src/core/libs/osnma_msg_receiver.cc | 126 +++++++++++++----- src/core/libs/osnma_msg_receiver.h | 2 +- .../system_parameters/galileo_inav_message.cc | 49 ++++--- .../system_parameters/galileo_inav_message.h | 4 + src/core/system_parameters/osnma_data.cc | 4 +- 6 files changed, 172 insertions(+), 69 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 14e1c52d8..a404a100a 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -439,7 +439,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } // 4. Push the new navigation data to the queues - if (d_inav_nav.have_new_ephemeris() == true) + if (d_inav_nav.have_new_ephemeris() == true) // C: tells if W1-->W4 available from same blcok (and W5!) { // get object for this SV (mandatory) const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_ephemeris()); @@ -471,12 +471,26 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); d_first_eph_sent = true; // do not send reduced CED anymore, since we have the full ephemeris set - d_flag_osnma_adkd_0_12 = true; // W1-> W5 available +// d_flag_osnma_adkd_0_12 = true; // W1-> W5 available + // extract bits, reset container. + bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; + if(check_size_is_ok) + { + std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << d_satellite.get_PRN() << ") " << "TOW_sf=" << d_inav_nav.get_TOW5() - 24 <>( // < PRNd , navDataBits, TOW_Sosf> + d_satellite.get_PRN(), + d_inav_nav.get_osnma_adkd_0_12_nav_bits(), + d_inav_nav.get_TOW5() - 24); + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); + d_inav_nav.reset_osnma_nav_bits_adkd0_12(); + } + + } else { // If we still do not have ephemeris, check if we have a reduced CED - if ((d_band == '1') && d_use_ced && !d_first_eph_sent && (d_inav_nav.have_new_reduced_ced() == true)) + if ((d_band == '1') && d_use_ced && !d_first_eph_sent && (d_inav_nav.have_new_reduced_ced() == true)) // C: W16 has some Eph. params, uneeded for OSNMa I guess { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_reduced_ced()); this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); @@ -492,7 +506,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } } - if (d_inav_nav.have_new_iono_and_GST() == true) + if (d_inav_nav.have_new_iono_and_GST() == true) // C: W5 { // get object for this SV (mandatory) const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_iono()); @@ -521,10 +535,9 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in << d_satellite << " with CN0=" << std::setprecision(2) << cn0 << std::setprecision(default_precision) << " dB-Hz" << TEXT_RESET << std::endl; } - } - if (d_inav_nav.have_new_utc_model() == true) + if (d_inav_nav.have_new_utc_model() == true) // C: tells if W6 is available { // get object for this SV (mandatory) const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_utc_model()); @@ -561,7 +574,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_flag_osnma_adkd_4_utc = true; } - if (d_inav_nav.have_new_almanac() == true) + if (d_inav_nav.have_new_almanac() == true) // flag_almanac_4 tells if W10 available. { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_almanac()); this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); @@ -597,23 +610,32 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } // get osnma message if the needed nav data is available - bool adkd_4_nav_data_available = d_flag_osnma_adkd_4_utc && d_flag_osnma_adkd_4_gst; - auto newOSNMA = d_inav_nav.have_new_nma();if (d_band == '1' && newOSNMA && (adkd_4_nav_data_available == true || d_flag_osnma_adkd_0_12 == true)) + bool adkd_4_nav_data_available = d_flag_osnma_adkd_4_utc && d_flag_osnma_adkd_4_gst; // supposition: data did not change bt. flags reset and now. + + // bool adkd_4_nav_data_available = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; // newApproach: let decoder decide when block starts and let it fill the data, and just check for length + if(adkd_4_nav_data_available /*&& d_inav_nav.is_TOW5_set() not needed cause W6 has TOW also.*/) { + bool check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; + if(check_size_is_ok) + { + std::cout << "Galileo OSNMA: sending ADKD=4 navData, PRN_d (" << d_satellite.get_PRN() << ") " << "TOW_sf=" << d_inav_nav.get_TOW6() - 4 <>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe + d_satellite.get_PRN(), + d_inav_nav.get_osnma_adkd_4_nav_bits(), + d_inav_nav.get_TOW6() - 4); + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); + d_inav_nav.reset_osnma_nav_bits_adkd4(); + } + } + auto newOSNMA = d_inav_nav.have_new_nma(); + if (d_band == '1' && newOSNMA) + { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); - if(adkd_4_nav_data_available) - tmp_obj->TimingData_2 = d_inav_nav.get_osnma_adkd_4_nav_bits(); - if(d_flag_osnma_adkd_0_12) - tmp_obj->EphemerisClockAndStatusData_2 = d_inav_nav.get_osnma_adkd_0_12_nav_bits(); - this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - d_flag_osnma_adkd_4_utc= false; - d_flag_osnma_adkd_4_gst = false; - d_flag_osnma_adkd_0_12 = false; } } diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 1a9c8cfc7..302609798 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -95,7 +95,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) { const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); - const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); + const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); // TODO remove if unneeded std::ostringstream output_message; output_message << "Galileo OSNMA: Subframe received starting at " @@ -110,6 +110,27 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) process_osnma_message(nma_msg); + std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; + } + else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) + { + // TODO - PRNa is a typo here, I think for d_satellite_nav_data, is PRN_d the name to use + const auto inav_data = wht::any_cast>>(pmt::any_ref(msg)); + uint32_t PRNa = std::get<0>(*inav_data); + std::string nav_data = std::get<1>(*inav_data);; + uint32_t TOW = std::get<2>(*inav_data); + + // iono data => 549 bits, utc data, 141 bits. + if(nav_data.size() == 549) + { + d_satellite_nav_data[PRNa][TOW].ephemeris_iono_vector_2 = nav_data; + } + else if(nav_data.size() == 141) + { + d_satellite_nav_data[PRNa][TOW].utc_vector_2 = nav_data; + } + else + LOG(ERROR) << "osnma_msg_receiver incorrect navData parsing!"; } else { @@ -581,7 +602,7 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrPRN,osnma_msg->TOW_sf0,d_osnma_data.d_nav_data); // TODO change place +// add_satellite_data(osnma_msg->PRN,osnma_msg->TOW_sf0,d_osnma_data.d_nav_data); // TODO change place // DEBUG PARSING MACK MESSAGES WHEN DSM-KROOT NOT YET AVAILABLE // d_osnma_data.d_dsm_kroot_message.ts = 9; // d_osnma_data.d_dsm_kroot_message.ks = 4; @@ -923,14 +944,18 @@ void osnma_msg_receiver::process_mack_message() { it.second.status = Tag::SUCCESS; LOG(WARNING) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id= " - << it.second.tag_id - << ", TOW=" - << it.second.TOW - << ", ADKD=" - << static_cast(it.second.ADKD) - << ", from satellite " - << it.second.PRNa - << std::endl; + << it.second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it.second.received_tag << std::dec + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d) + << std::endl; } /* TODO notify PVT via pmt * have_new_data() true @@ -939,27 +964,36 @@ void osnma_msg_receiver::process_mack_message() else { it.second.status = Tag::FAIL; - LOG(ERROR) << "Galileo OSNMA: Tag verification :: FAILURE for tag Id= " - << it.second.tag_id - << ", TOW=" - << it.second.TOW - << ", ADKD=" - << static_cast(it.second.ADKD) - << ", from satellite " - << it.second.PRNa - << std::endl; + LOG(ERROR) << "Galileo OSNMA: Tag verification :: FAILURE for tag Id=" + << it.second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it.second.received_tag << std::dec + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d) + << std::endl; } } else { LOG(WARNING) << "Galileo OSNMA: Tag verification :: SKIPPED for Tag Id= " - << it.second.tag_id - << ", TOW=" - << it.second.TOW - << ", ADKD=" - << static_cast(it.second.ADKD) - << ", from satellite " - << it.second.PRNa - << " due to missing key or navData. "; + << it.second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it.second.received_tag << std::dec + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d) + << ". Key available ("<< tag_has_key_available(it.second) <<"), navData ("<< tag_has_nav_data_available(it.second) <<"). " + << std::endl; } } @@ -1078,7 +1112,23 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) // Compare computed tag with received one truncated if (tag.received_tag == computed_mac) + { + std::cout << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id= " + << tag.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << tag.received_tag << std::dec + << ", TOW=" + << tag.TOW + << ", ADKD=" + << static_cast(tag.ADKD) + << ", PRNa=" + << static_cast(tag.PRNa) + << ", PRNd=" + << static_cast(tag.PRN_d) + << std::endl; return true; + } + else return false; } @@ -1219,17 +1269,27 @@ void osnma_msg_receiver::remove_verified_tags() for (auto it = d_tags_awaiting_verify.begin(); it != d_tags_awaiting_verify.end() ; ){ if (it->second.status == Tag::SUCCESS || it->second.status == Tag::FAIL) { - LOG(INFO) << "Galileo OSNMA: delete tag for tag Id= " - << it->second.tag_id << ", PRN_a= " - << it->second.PRNa << ", TOW=" - << it->second.TOW << ", ADKD= " - << static_cast(it->second.ADKD) << ", status= " - << it->second.status << std::endl; + LOG(INFO) << "Galileo OSNMA: Tag verification :: DELETE tag Id=" + << it->second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it->second.received_tag << std::dec + << ", TOW=" + << it->second.TOW + << ", ADKD=" + << static_cast(it->second.ADKD) + << ", PRNa=" + << static_cast(it->second.PRNa) + << ", PRNd=" + << static_cast(it->second.PRN_d) + << ", status= " + << it->second.status + << std::endl; it = d_tags_awaiting_verify.erase(it); } else ++it; } + std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; } /** * @brief Control the size of the tags awaiting verification multimap. diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index d7aeb9df4..4e662ef55 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -83,7 +83,7 @@ private: bool tag_has_nav_data_available(Tag& t); bool tag_has_key_available(Tag& t); - std::map> d_satellite_nav_data; // map holding NavData sorted by SVID and TOW. + std::map> d_satellite_nav_data; // map holding NavData sorted by SVID (first key) and TOW (second key). std::map> d_tesla_keys; // tesla keys over time, sorted by TOW std::vector d_macks_awaiting_MACSEQ_verification; std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index 442f67178..baa140149 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -185,7 +185,7 @@ void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even if (page_position_in_inav_subframe != 255) { if (page_position_in_inav_subframe == 0) - { + { // TODO - is it redundant? receiving Word 2 already resets this nma_position_filled = std::array{}; nma_msg.mack = std::array{}; nma_msg.hkroot = std::array{}; @@ -215,7 +215,7 @@ void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even } } - +// C: tells if W1-->W4 available from same blcok bool Galileo_Inav_Message::have_new_ephemeris() // Check if we have a new ephemeris stored in the galileo navigation class { if ((flag_ephemeris_1 == true) and (flag_ephemeris_2 == true) and (flag_ephemeris_3 == true) and (flag_ephemeris_4 == true) and (flag_iono_and_GST == true)) @@ -349,7 +349,7 @@ bool Galileo_Inav_Message::have_new_ephemeris() // Check if we have a new ephem return false; } - +// C: tells if W5 is available bool Galileo_Inav_Message::have_new_iono_and_GST() // Check if we have a new iono data set stored in the galileo navigation class { if ((flag_iono_and_GST == true) and (flag_utc_model == true)) // the condition on flag_utc_model is added to have a time stamp for iono @@ -361,7 +361,7 @@ bool Galileo_Inav_Message::have_new_iono_and_GST() // Check if we have a new io return false; } - +// C: tells if W6 is available bool Galileo_Inav_Message::have_new_utc_model() // Check if we have a new utc data set stored in the galileo navigation class { if (flag_utc_model == true) @@ -373,9 +373,13 @@ bool Galileo_Inav_Message::have_new_utc_model() // Check if we have a new utc d return false; } - +// flag_almanac_4 tells if W10 available. bool Galileo_Inav_Message::have_new_almanac() // Check if we have a new almanac data set stored in the galileo navigation class { +// if(flag_almanac_4) +// { +// flag_adkd_4_complete = true; +// } if ((flag_almanac_1 == true) and (flag_almanac_2 == true) and (flag_almanac_3 == true) and (flag_almanac_4 == true)) { // All Almanac data have been received @@ -614,7 +618,7 @@ void Galileo_Inav_Message::read_page_1(const std::bitset& DLOG(INFO) << "A_1= " << A_1; flag_ephemeris_1 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_1 = data_bits.to_string().substr(5,120); + nav_bits_word_1 = data_bits.to_string().substr(6,120); } @@ -636,7 +640,7 @@ void Galileo_Inav_Message::read_page_2(const std::bitset& DLOG(INFO) << "iDot_2= " << iDot_2; flag_ephemeris_2 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_2 = data_bits.to_string().substr(5,120); + nav_bits_word_2 = data_bits.to_string().substr(6,120); } @@ -666,7 +670,7 @@ void Galileo_Inav_Message::read_page_3(const std::bitset& DLOG(INFO) << "SISA_3= " << SISA_3; flag_ephemeris_3 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_3 = data_bits.to_string().substr(5, 122); + nav_bits_word_3 = data_bits.to_string().substr(6, 122); } @@ -700,7 +704,7 @@ void Galileo_Inav_Message::read_page_4(const std::bitset& DLOG(INFO) << "spare_4 = " << spare_4; flag_ephemeris_4 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_4 = data_bits.to_string().substr(5, 120); + nav_bits_word_4 = data_bits.to_string().substr(6, 120); } @@ -872,10 +876,14 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) case 2: // Word type 2: Ephemeris (2/4) { + // start of subframe, reset osnma parameters TODO - refactor page_position_in_inav_subframe = 0; nma_msg.mack = std::array{}; nma_msg.hkroot = std::array{}; nma_position_filled = std::array{}; + reset_osnma_nav_bits_adkd4(); + reset_osnma_nav_bits_adkd0_12(); + read_page_2(data_jk_bits); if (enable_rs) { @@ -1020,7 +1028,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) flag_iono_and_GST = true; // set to false externally flag_TOW_set = true; // set to false externally DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_5 = data_jk_bits.to_string().substr(5, 67); + nav_bits_word_5 = data_jk_bits.to_string().substr(6, 67); break; case 6: // Word type 6: GST-UTC conversion parameters @@ -1050,7 +1058,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) flag_utc_model = true; // set to false externally flag_TOW_set = true; // set to false externally DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_6 = data_jk_bits.to_string().substr(5, 99); + nav_bits_word_6 = data_jk_bits.to_string().substr(6, 99); break; case 7: // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number @@ -1207,7 +1215,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) DLOG(INFO) << "WN_0G_10= " << WN_0G_10; flag_almanac_4 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_10 = data_jk_bits.to_string().substr(85, 42); + nav_bits_word_10 = data_jk_bits.to_string().substr(86, 42); break; case 16: // Word type 16: Reduced Clock and Ephemeris Data (CED) parameters @@ -1387,6 +1395,8 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) nma_position_filled = std::array{}; nma_msg.mack = std::array{}; nma_msg.hkroot = std::array{}; + reset_osnma_nav_bits_adkd4(); + reset_osnma_nav_bits_adkd0_12(); } return page_number; @@ -1407,7 +1417,7 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() nma_position_filled = std::array{}; // Fill TOW and WN nma_msg.WN_sf0 = WN_0; - int32_t TOW_sf0 = TOW_5 - 24; // TODO - why not TOW_0? + int32_t TOW_sf0 = TOW_5 - 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start if (TOW_sf0 < 0) { TOW_sf0 += 604800; @@ -1435,17 +1445,24 @@ bool Galileo_Inav_Message::have_new_nma() std::string Galileo_Inav_Message::get_osnma_adkd_4_nav_bits() { nav_bits_adkd_4 = nav_bits_word_6 + nav_bits_word_10; - nav_bits_word_6 = ""; - nav_bits_word_10 = ""; + return nav_bits_adkd_4; } std::string Galileo_Inav_Message::get_osnma_adkd_0_12_nav_bits() { nav_bits_adkd_0_12 = nav_bits_word_1 + nav_bits_word_2 + nav_bits_word_3 + nav_bits_word_4 + nav_bits_word_5; + return nav_bits_adkd_0_12; +} +void Galileo_Inav_Message::reset_osnma_nav_bits_adkd0_12() +{ nav_bits_word_1 = ""; nav_bits_word_2 = ""; nav_bits_word_3 = ""; nav_bits_word_4 = ""; nav_bits_word_5 = ""; - return nav_bits_adkd_0_12; +} +void Galileo_Inav_Message::reset_osnma_nav_bits_adkd4() +{ + nav_bits_word_6 = ""; + nav_bits_word_10 = ""; } diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 19999a735..a4cc6a31a 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -143,11 +143,15 @@ public: * @brief Retrieves the OSNMA ADKD 4 NAV bits. Resets the string. */ std::string get_osnma_adkd_4_nav_bits(); + void reset_osnma_nav_bits_adkd4(); + bool flag_adkd_4_complete{false}; /* * @brief Retrieves the OSNMA ADKD 0/12 NAV bits. Resets the string. */ std::string get_osnma_adkd_0_12_nav_bits(); + void reset_osnma_nav_bits_adkd0_12(); + bool flag_adkd_0_12_complete{false}; inline bool get_flag_CRC_test() const { diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 4424c55ba..49051b7be 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -37,8 +37,8 @@ void NavData::init(const std::shared_ptr &osnma_msg) TOW_sf0 = osnma_msg->TOW_sf0; // new parsing, directly parsing bits - ephemeris_iono_vector_2 = osnma_msg->EphemerisClockAndStatusData_2; - utc_vector_2 = osnma_msg->TimingData_2; +// ephemeris_iono_vector_2 = osnma_msg->EphemerisClockAndStatusData_2; +// utc_vector_2 = osnma_msg->TimingData_2; }; void NavData::generate_eph_iono_vector() { From f1e616c4e5e556e83fb49821875e62792fb4e5f7 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sat, 22 Jun 2024 14:04:08 +0200 Subject: [PATCH 126/219] =?UTF-8?q?[TAS-226]=20[FEAT]=20Remove=20tags=20sk?= =?UTF-8?q?ipped=20=E2=89=A5=2010=20times?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/libs/osnma_msg_receiver.cc | 25 ++++++++++++++++++++++--- src/core/system_parameters/osnma_data.h | 5 +++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 302609798..02c3d48e4 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -109,8 +109,6 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) std::cout << output_message.str() << std::endl; process_osnma_message(nma_msg); - - std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; } else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) { @@ -915,6 +913,7 @@ void osnma_msg_receiver::process_mack_message() d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; } + std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; mack = d_macks_awaiting_MACSEQ_verification.erase(mack); } else @@ -980,7 +979,8 @@ void osnma_msg_receiver::process_mack_message() } } else { - LOG(WARNING) << "Galileo OSNMA: Tag verification :: SKIPPED for Tag Id= " + it.second.skipped ++; + LOG(WARNING) << "Galileo OSNMA: Tag verification :: SKIPPED (x"<< it.second.skipped <<")for Tag Id= " << it.second.tag_id << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase << it.second.received_tag << std::dec @@ -1286,6 +1286,25 @@ void osnma_msg_receiver::remove_verified_tags() << std::endl; it = d_tags_awaiting_verify.erase(it); } + else if (it->second.skipped >= 10) + { + LOG(INFO) << "Galileo OSNMA: Tag verification :: DELETE tag Id=" + << it->second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it->second.received_tag << std::dec + << ", TOW=" + << it->second.TOW + << ", ADKD=" + << static_cast(it->second.ADKD) + << ", PRNa=" + << static_cast(it->second.PRNa) + << ", PRNd=" + << static_cast(it->second.PRN_d) + << ", status= " + << it->second.status + << std::endl; + it = d_tags_awaiting_verify.erase(it); + } else ++it; } diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index cf9bcb7d9..b27f6dfb3 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -182,8 +182,8 @@ public: computed_tag(0), PRN_d(MTI.tag_info.PRN_d), ADKD(MTI.tag_info.ADKD), - cop(MTI.tag_info.cop) - + cop(MTI.tag_info.cop), + skipped(0) { } @@ -201,6 +201,7 @@ public: uint8_t PRN_d; uint8_t ADKD; uint8_t cop; + uint32_t skipped; }; /** \} */ /** \} */ From 849a900adfde07030ed9a84e62270b754b7c830c Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sat, 22 Jun 2024 14:54:08 +0200 Subject: [PATCH 127/219] [TAS-228] [FEAT] adapt osnma test vector to new navData passing All tags either verified SUCCESSFULLY or Skipped. Skipping issue still present. --- src/core/libs/osnma_msg_receiver.cc | 6 ++-- .../osnma/osnma_msg_receiver_test.cc | 31 +++++++++++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 02c3d48e4..8447fb5fc 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -121,10 +121,12 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // iono data => 549 bits, utc data, 141 bits. if(nav_data.size() == 549) { + LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " << "TOW_sf=" << TOW <second.skipped >= 10) + else if (it->second.skipped >= 20) { LOG(INFO) << "Galileo OSNMA: Tag verification :: DELETE tag Id=" << it->second.tag_id diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 226e8e892..ec89911ce 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -225,20 +225,32 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) {3, {6, 122}}, {4, {6, 120}}, {5, {6, 67}}, - // TODO words 6 and 10 for TimingData }; // Fill NavData bits -- Iterate over the extraction parameters + std::string nav_data_ADKD_0_12 = ""; for (const auto& param : extractionParams) { uint8_t wordKey = param.first; uint8_t start = param.second.first; uint8_t length = param.second.second; // Extract the required bits and fill osnma block - osnmaMsg_sptr->EphemerisClockAndStatusData_2 += words[wordKey]. + nav_data_ADKD_0_12 += words[wordKey]. to_string().substr( start, length); } + // send to osnma block + bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; + if(check_size_is_ok) + { + std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <>( // < PRNd , navDataBits, TOW_Sosf> + tv.svId, + nav_data_ADKD_0_12, + osnmaMsg_sptr->TOW_sf0); + osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + + } } // check w6 && w10 is received => fill TimingData data vector @@ -252,6 +264,7 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) {10, {86, 42}} }; + std::string nav_data_ADKD_4 = ""; // Fill NavData bits -- Iterate over the extraction parameters for (const auto& param : extractionParams) { @@ -260,9 +273,21 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) uint8_t length = param.second.second; // Extract the required bits and fill osnma block - osnmaMsg_sptr->TimingData_2 += words[wordKey].to_string().substr( + nav_data_ADKD_4 += words[wordKey].to_string().substr( start, length); } + // send to osnma block + bool check_size_is_ok = nav_data_ADKD_4.size() == 141; + if(check_size_is_ok) + { + std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <>( // < PRNd , navDataBits, TOW_Sosf> + tv.svId, + nav_data_ADKD_4, + osnmaMsg_sptr->TOW_sf0); + osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + + } } From bac36b2df513f16a37b15526a24b937e1ce04146 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 23 Jun 2024 09:49:14 +0200 Subject: [PATCH 128/219] Read .crt files instead of .pem files Define the following global configuration parameters: GNSS-SDR.osnma_public_key (string, by default pointing to ../data/OSNMA_PublicKey_20240115100000_newPKID_1.crt) GNSS-SDR.osnma_merkletree (string, by default pointing to ../data/OSNMA_MerkleTree_20240115100000_newPKID_1.xml) Add logging of OSNMA events Clean public API of Gnss_Crypto class --- src/core/receiver/gnss_flowgraph.cc | 6 +- src/core/system_parameters/CMakeLists.txt | 4 +- src/core/system_parameters/Galileo_OSNMA.h | 3 +- src/core/system_parameters/gnss_crypto.cc | 185 ++++++++++++++++----- src/core/system_parameters/gnss_crypto.h | 8 +- 5 files changed, 159 insertions(+), 47 deletions(-) diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 4b5f71012..acdea9df2 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -124,9 +124,9 @@ void GNSSFlowgraph::init() if (configuration_->property("Channels_1B.count", 0) > 0) { enable_osnma_rx_ = true; - auto pemFilePath = configuration_->property("GNSS-SDR.OSNMA_pem", PEMFILE_DEFAULT); - auto merKleTreePath = configuration_->property("GNSS-SDR.OSNMA_MerkleTree", MERKLEFILE_DEFAULT); - osnma_rx_ = osnma_msg_receiver_make(pemFilePath, merKleTreePath); + const auto certFilePath = configuration_->property("GNSS-SDR.osnma_public_key", CRTFILE_DEFAULT); + const auto merKleTreePath = configuration_->property("GNSS-SDR.osnma_merkletree", MERKLEFILE_DEFAULT); + osnma_rx_ = osnma_msg_receiver_make(certFilePath, merKleTreePath); } else { diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 518e64264..607c3702a 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -29,8 +29,9 @@ set(SYSTEM_PARAMETERS_SOURCES glonass_gnav_utc_model.cc glonass_gnav_navigation_message.cc reed_solomon.cc - osnma_dsm_reader.cc osnma_data.cc + osnma_dsm_reader.cc + osnma_helper.cc ) set(SYSTEM_PARAMETERS_HEADERS @@ -96,7 +97,6 @@ set(SYSTEM_PARAMETERS_HEADERS Galileo_OSNMA.h osnma_data.h osnma_dsm_reader.h - osnma_helper.cc osnma_helper.h ) diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index e6530b610..bc919c4b3 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -161,7 +161,8 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} const std::string PEMFILE_DEFAULT("../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem"); -const std::string MERKLEFILE_DEFAULT("./OSNMA_MerkleTree_20210920133026.xml"); +const std::string CRTFILE_DEFAULT("../data/OSNMA_PublicKey_20240115100000_newPKID_1.crt"); +const std::string MERKLEFILE_DEFAULT("../data/OSNMA_MerkleTree_20240115100000_newPKID_1.xml"); class Mack_lookup { diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 12d113ae0..e78e29e39 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -30,6 +30,7 @@ #include #include #include +#include #if USE_OPENSSL_3 #include #include @@ -47,13 +48,23 @@ #include #endif -Gnss_Crypto::Gnss_Crypto(const std::string& pemFilePath, const std::string& merkleTreePath) +#if USE_GLOG_AND_GFLAGS +#include // for DLOG +#else +#include +#endif + + +Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath) { #if USE_OPENSSL_FALLBACK #else // GnuTLS gnutls_global_init(); #endif - readPublicKeyFromPEM(pemFilePath); + if (!readPublicKeyFromCRT(certFilePath)) + { + readPublicKeyFromPEM(PEMFILE_DEFAULT); + } read_merkle_xml(merkleTreePath); } @@ -69,10 +80,10 @@ Gnss_Crypto::~Gnss_Crypto() } #endif #else // GnuTLS - if (d_PublicKey != NULL) + if (d_PublicKey != nullptr) { gnutls_pubkey_deinit(d_PublicKey); - d_PublicKey = NULL; + d_PublicKey = nullptr; } gnutls_global_deinit(); #endif @@ -145,11 +156,11 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) std::string signalVersion = galHeader.child("signalVersion").text().get(); std::string dataVersion = galHeader.child("dataVersion").text().get(); - std::cout << " Source: " << source.child_value("mission") << " - " << source.child_value("segment") << " - " << source.child_value("element") << std::endl; - std::cout << " Destination: " << destination.child_value("mission") << " - " << destination.child_value("segment") << " - " << destination.child_value("element") << std::endl; - std::cout << " Issue Date: " << issueDate << std::endl; - std::cout << " Signal Version: " << signalVersion << std::endl; - std::cout << " Data Version: " << dataVersion << std::endl; + LOG(INFO) << "OSNMA Merkletree - Source: " << source.child_value("mission") << " - " << source.child_value("segment") << " - " << source.child_value("element"); + LOG(INFO) << "OSNMA Merkletree - Destination: " << destination.child_value("mission") << " - " << destination.child_value("segment") << " - " << destination.child_value("element"); + LOG(INFO) << "OSNMA Merkletree - Issue Date: " << issueDate; + LOG(INFO) << "OSNMA Merkletree - Signal Version: " << signalVersion; + LOG(INFO) << "OSNMA Merkletree - Data Version: " << dataVersion; // Accessing data from the body pugi::xml_node merkleTree = body.child("MerkleTree"); @@ -157,8 +168,8 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) int n = std::stoi(merkleTree.child_value("N")); std::string hashFunction = merkleTree.child_value("HashFunction"); - std::cout << " N: " << n << std::endl; - std::cout << " Hash Function: " << hashFunction << std::endl; + LOG(INFO) << "OSNMA Merkletree - N: " << n; + LOG(INFO) << "OSNMA Merkletree - Hash Function: " << hashFunction; for (pugi::xml_node publicKey : merkleTree.children("PublicKey")) { @@ -168,21 +179,21 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) std::string point = publicKey.child_value("point"); std::string pkType = publicKey.child_value("PKType"); - std::cout << " Public Key: " << i << std::endl; - std::cout << " PKID: " << pkid << std::endl; - std::cout << " Length in Bits: " << lengthInBits << std::endl; - std::cout << " Point: " << point << std::endl; - std::cout << " PK Type: " << pkType << std::endl; + LOG(INFO) << "OSNMA Merkletree - Public Key: " << i; + LOG(INFO) << "OSNMA Merkletree - PKID: " << pkid; + LOG(INFO) << "OSNMA Merkletree - Length in Bits: " << lengthInBits; + LOG(INFO) << "OSNMA Merkletree - Point: " << point; + LOG(INFO) << "OSNMA Merkletree - PK Type: " << pkType; } for (pugi::xml_node treeNode : merkleTree.children("TreeNode")) { int j = std::stoi(treeNode.child_value("j")); int i = std::stoi(treeNode.child_value("i")); int lengthInBits = std::stoi(treeNode.child_value("lengthInBits")); - std::cout << " Node length (bits): " << lengthInBits << std::endl; + LOG(INFO) << "OSNMA Merkletree - Node length (bits): " << lengthInBits; std::string x_ji = treeNode.child_value("x_ji"); - std::cout << " Size string (bytes): " << x_ji.size() << std::endl; - std::cout << " m_" << j << "_" << i << " = " << x_ji << std::endl; + LOG(INFO) << "OSNMA Merkletree - Size string (bytes): " << x_ji.size(); + LOG(INFO) << "OSNMA Merkletree - m_" << j << "_" << i << " = " << x_ji; if (j == 4 && i == 0) { d_x_4_0 = convert_from_hex_str(x_ji); @@ -220,7 +231,8 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) d_x_0_1 = convert_from_hex_str("AA1A8B68E5DB293106B5BC8806F9790E8ACF8DC2D28A6EF6C1AC7233A9813D3F"); return; } - std::cout << "Merkle Tree successfully read from file " << merkleFilePath << std::endl; + std::cout << "OSNMA Merkle Tree successfully read from file " << merkleFilePath << std::endl; + LOG(INFO) << "OSNMA Merkle Tree successfully read from file " << merkleFilePath; } @@ -451,7 +463,8 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) BIO_free(bio); if (d_PublicKey == nullptr) { - std::cerr << "OpenSSL: error reading the Public Key from file " << pemFilePath << ". Aborting import" << std::endl; + std::cerr << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import" << std::endl; + LOG(INFO) << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import"; return; } #else // GnuTLS @@ -464,17 +477,105 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) if (ret != GNUTLS_E_SUCCESS) { gnutls_pubkey_deinit(pubkey); - std::cerr << "GnuTLS: error reading the Public Key from file " + std::cerr << "GnuTLS: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import" << std::endl; std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; + LOG(INFO) << "GnuTLS: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import"; return; } pubkey_copy(pubkey, &d_PublicKey); gnutls_pubkey_deinit(pubkey); #endif - std::cout << "Public key successfully read from file " << pemFilePath << std::endl; + std::cout << "OSNMA Public key successfully read from file " << pemFilePath << std::endl; + LOG(INFO) << "OSNMA Public key successfully read from file " << pemFilePath; +} + + +bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) +{ +#if USE_OPENSSL_FALLBACK + // Open the .crt file + std::ifstream crtFile(crtFilePath, std::ios::binary); + if (!crtFile.is_open()) + { + std::cerr << "Unable to open file: " << crtFilePath << std::endl; + return false; + } + + // Read certificate + std::vector buffer((std::istreambuf_iterator(crtFile)), std::istreambuf_iterator()); + BIO* bio = BIO_new_mem_buf(buffer.data(), buffer.size()); + if (!bio) + { + std::cerr << "Unable to create BIO for file: " << crtFilePath << std::endl; + return false; + } + X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); + if (!cert) + { + std::cerr << "Unable to read certificate from file: " << crtFilePath << std::endl; + BIO_free(bio); + return false; + } + + // Read the public key from the certificate + EVP_PKEY* pubkey = X509_get_pubkey(cert); + if (!pubkey) + { + std::cerr << "Failed to extract the public key" << std::endl; + X509_free(cert); + return false; + } + pubkey_copy(pubkey, &d_PublicKey); + EVP_PKEY_free(pubkey); + BIO_free(bio); + X509_free(cert); +#else // GnuTLS + // Open the .crt file + std::ifstream crtFile(crtFilePath, std::ios::binary); + if (!crtFile.is_open()) + { + // CRT file not found + // If it was not the default, maybe it is a configuration error + if (crtFilePath != CRTFILE_DEFAULT) + { + std::cerr << "File " << crtFilePath << " not found" << std::endl; + } + return false; + } + + std::vector buffer((std::istreambuf_iterator(crtFile)), std::istreambuf_iterator()); + + gnutls_x509_crt_t cert; + gnutls_x509_crt_init(&cert); + int ret = gnutls_x509_crt_import(cert, (const gnutls_datum_t*)&buffer, GNUTLS_X509_FMT_PEM); + if (ret < 0) + { + std::cerr << "Failed to import certificate: " << gnutls_strerror(ret) << std::endl; + gnutls_x509_crt_deinit(cert); + return false; + } + + gnutls_pubkey_t pubkey; + gnutls_pubkey_init(&pubkey); + + ret = gnutls_pubkey_import_x509(pubkey, cert, 0); + if (ret < 0) + { + std::cerr << "Failed to import public key: " << gnutls_strerror(ret) << std::endl; + gnutls_pubkey_deinit(pubkey); + gnutls_x509_crt_deinit(cert); + return false; + } + pubkey_copy(pubkey, &d_PublicKey); + gnutls_x509_crt_deinit(cert); + gnutls_pubkey_deinit(pubkey); +#endif + std::cout << "OSNMA Public key successfully read from file " << crtFilePath << std::endl; + LOG(INFO) << "OSNMA Public key successfully read from file " << crtFilePath; + return true; } @@ -551,18 +652,21 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st if (verification == 1) { success = true; + LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; } else { unsigned long errCode = ERR_get_error(); - char* err = ERR_error_string(errCode, NULL); - std::cerr << "OpenSSL: message authentication failed: " << err << std::endl; + char* err = ERR_error_string(errCode, nullptr); + std::cerr << "OpenSSL: OSNMA message authentication failed: " << err << std::endl; + LOG(WARNING) << "OpenSSL: OSNMA message authentication failed: " << err; } #else int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, signature.data(), static_cast(signature.size()), d_PublicKey); if (verification == 1) { success = true; + LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; } else if (verification == 0) { @@ -570,9 +674,9 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } else { - std::cerr << "OpenSSL: message authentication failed" << std::endl; + std::cerr << "OpenSSL: OSNMA message authentication failed" << std::endl; + LOG(WARNING) << "OpenSSL: OSNMA message authentication failed"; } - #endif #else // GnuTLS // Convert signature to DER format @@ -590,9 +694,14 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st // Verify the DER-encoded signature int ret = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &digest_data, &der_sig_data); success = (ret >= 0); - if (!success) + if (success) { - std::cerr << "GnuTLS: message authentication failed: " << gnutls_strerror(ret) << std::endl; + LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; + } + else + { + std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; + LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); } #endif return success; @@ -638,8 +747,8 @@ std::vector Gnss_Crypto::getMerkleRoot(const std::vector& publicKey) { #if USE_OPENSSL_FALLBACK - BIO* bio = NULL; - EVP_PKEY* pkey = NULL; + BIO* bio = nullptr; + EVP_PKEY* pkey = nullptr; bio = BIO_new_mem_buf(publicKey.data(), publicKey.size()); if (!bio) { @@ -647,12 +756,13 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) return; } - pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); BIO_free(bio); if (!pkey) { - std::cerr << "OpenSSL: error setting the public key." << std::endl; + std::cerr << "OpenSSL: error setting the OSNMA public key." << std::endl; + LOG(INFO) << "OpenSSL: error setting the OSNMA public key."; return; } @@ -677,6 +787,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) pubkey_copy(pubkey, &d_PublicKey); gnutls_pubkey_deinit(pubkey); #endif + LOG(INFO) << "OSNMA Public Key successfully set up."; } @@ -685,7 +796,7 @@ bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) { // Open a memory buffer BIO* mem_bio = BIO_new(BIO_s_mem()); - if (mem_bio == NULL) + if (mem_bio == nullptr) { return false; } @@ -703,15 +814,15 @@ bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) // Create a new memory buffer and load the data into it BIO* mem_bio2 = BIO_new_mem_buf(bio_data, data_len); - if (mem_bio2 == NULL) + if (mem_bio2 == nullptr) { BIO_free(mem_bio); return false; } // Read the public key from the new memory buffer - *dest = PEM_read_bio_PUBKEY(mem_bio2, NULL, NULL, NULL); - if (*dest == NULL) + *dest = PEM_read_bio_PUBKEY(mem_bio2, nullptr, nullptr, nullptr); + if (*dest == nullptr) { BIO_free(mem_bio); BIO_free(mem_bio2); diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 41341d981..e8b41fddd 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -36,12 +36,9 @@ class Gnss_Crypto { public: - Gnss_Crypto() = default; + Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath); ~Gnss_Crypto(); - Gnss_Crypto(const std::string& pemFilePath, const std::string& merkleTreePath); - void readPublicKeyFromPEM(const std::string& pemFilePath); - void read_merkle_xml(const std::string& merkleFilePath); void set_public_key(const std::vector& publickey); bool have_public_key() const; bool verify_signature(const std::vector& message, const std::vector& signature) const; @@ -57,6 +54,9 @@ public: } private: + void read_merkle_xml(const std::string& merkleFilePath); + void readPublicKeyFromPEM(const std::string& pemFilePath); + bool readPublicKeyFromCRT(const std::string& crtFilePath); std::vector convert_from_hex_str(const std::string& input) const; #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 From 8dfd341d2c01dec6b41ee2c5fb88296c0a64a9cd Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 23 Jun 2024 11:10:40 +0200 Subject: [PATCH 129/219] Fix tests building --- src/tests/CMakeLists.txt | 54 +-- src/tests/single_test_main.cc | 3 +- src/tests/test_main.cc | 2 +- .../osnma/gnss_crypto_test.cc | 304 ++++++++------- .../osnma/osnma_msg_receiver_test.cc | 362 ++++++++---------- 5 files changed, 322 insertions(+), 403 deletions(-) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 97bbac838..8de611f5f 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1344,52 +1344,14 @@ else() endif() endif() -######################################################### gnss_crypto_test - -if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) - set(GNSS_CRYPTO_TEST_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc) - - if(USE_CMAKE_TARGET_SOURCES) - add_executable(gnss_crypto_test) - target_sources(gnss_crypto_test PRIVATE ${GNSS_CRYPTO_TEST_SOURCES}) - else() - add_executable(gnss_crypto_test ${GNSS_CRYPTO_TEST_SOURCES}) - endif() - - target_link_libraries(gnss_crypto_test - PRIVATE - Boost::thread - GTest::GTest - GTest::Main - core_system_parameters - Pugixml::pugixml - ) - if(ENABLE_GLOG_AND_GFLAGS) - target_link_libraries(gnss_crypto_test PRIVATE Gflags::gflags Glog::glog) - target_compile_definitions(gnss_crypto_test PRIVATE -DUSE_GLOG_AND_GFLAGS=1) - else() - target_link_libraries(gnss_crypto_test PRIVATE absl::flags absl::flags_parse absl::log $ absl::log_initialize) - endif() - - target_include_directories(gnss_crypto_test - PRIVATE - ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters) - - xcode_remove_warning_duplicates(gnss_crypto_test) # TODO - unsure if needed - - add_test(gnss_crypto_test gnss_crypto_test) - - set_property(TEST gnss_crypto_test PROPERTY TIMEOUT 1) -endif() ######################################################### osnma_msg_receiver_test if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) set(OSNMA_MSG_RECEIVER_TEST_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc) + ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc + ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc + ) if(USE_CMAKE_TARGET_SOURCES) add_executable(osnma_msg_receiver_test) @@ -1399,7 +1361,8 @@ if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) endif() target_link_libraries(osnma_msg_receiver_test - PRIVATE + PRIVATE + gnss_sdr_flags Boost::thread GTest::GTest GTest::Main @@ -1416,11 +1379,12 @@ if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) add_test(osnma_msg_receiver_test osnma_msg_receiver_test) - set_property(TEST osnma_msg_receiver_test PROPERTY TIMEOUT 1) + set_property(TEST osnma_msg_receiver_test PROPERTY TIMEOUT 30) target_include_directories(osnma_msg_receiver_test - PRIVATE - ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters) + PRIVATE + ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters + ) endif() if(ENABLE_BENCHMARKS) diff --git a/src/tests/single_test_main.cc b/src/tests/single_test_main.cc index beece7581..c0a6e1dee 100644 --- a/src/tests/single_test_main.cc +++ b/src/tests/single_test_main.cc @@ -19,6 +19,7 @@ #include "concurrent_map.h" #include "concurrent_queue.h" #include "gps_acq_assist.h" +#include "gnss_sdr_flags.h" #include #include #include @@ -36,7 +37,6 @@ using namespace google; DECLARE_string(log_dir); #endif #else -#include "gnss_sdr_flags.h" #include #include #include @@ -44,7 +44,6 @@ DECLARE_string(log_dir); #include #include #include - class TestLogSink : public absl::LogSink { public: diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 8611d44b8..7990ca258 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -113,7 +113,7 @@ private: #include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc" #include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc" #include "unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc" -#include "unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc" +// #include "unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc" #include "unit-tests/signal-processing-blocks/pvt/geohash_test.cc" #include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc" 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 a72d86998..a80ef055a 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 @@ -1,192 +1,186 @@ -#include #include "gnss_crypto.h" +#include class GnssCryptoTest : public ::testing::Test { - }; -TEST(GnssCryptoTest, VerifySignature) { - // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" - std::unique_ptr d_crypto = std::make_unique(); - -// RG example - import crt certificate - result: FAIL -std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; -std::vector publicKey { // PEM format - 1000 bits - 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 } ; - - // own ECDSA-P256 key and message generated and signed and verified successfully with openssl -// std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message (unhashed) -// std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, -// 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, -// 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK - // raw r and s values -// std::vector signature = { -// 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, -// 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, -// 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, -// 0xA5, 0xB9, 0xB2, 0x56 }; - - // std::vector publicKey{// PK associated to the PrK, in der format ---test -// 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4A, 0xF3, -// 0xEE, 0x3A, 0x94, 0x25, 0x25, 0x3D, 0x55, 0xC2, 0x5A, 0xC2, 0x2D, 0xCF, 0x14, 0x4D, 0x39, 0x0D, 0xB1, 0xFC, 0x7F, 0x31, 0x5A, 0x2A, 0x19, 0xAE, 0x4E, 0xD6, 0xCB, 0xA6, 0x59, -// 0xD6, 0x99, 0x7C, 0xE8, 0xBD, 0x1F, 0x43, 0x34, 0x1C, 0x59, 0xD9, 0xD9, 0xCA, 0xC3, 0xEE, 0x58, 0xE5, 0xEA, 0xD3, 0x55, 0x44, 0xEA, 0x89, 0x71, 0x65, 0xD0, 0x92, 0x72, 0xA2, -// 0xC8, 0x3C, 0x87, 0x5D }; -// std::vector publicKey{ // PK associated to the PrK, in pem format -// 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, -// 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, -// 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, -// 0x44, 0x79, 0x48, 0x58, 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 }; - - // own key - GnuTLS error: The curve is unsupported... x192 EC unsupported?? - // std::vector message = {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64 }; // hello world - // std::vector signature = {0x30, 0x34, 0x02, 0x18, 0x4F, 0xAC, 0x9C, 0x5A, 0x44, 0xCF, 0xFD, 0x42, 0x6A, 0x58, 0x97, 0xA4, 0x94, 0x53, 0x2C, 0x79, 0xD1, 0x7B, 0x8B, 0xF9, 0x93, 0x03, 0xA2, 0xAF, 0x02, 0x18, 0x46, 0xF2, 0xF3, 0xCF, 0x9A, 0x23, 0x39, 0xB4, 0x25, 0x11, 0x89, 0x9A, 0x44, 0x7E, 0x2F, 0xB1, 0xE1, 0x58, 0xAF, 0xCE, 0xC1,0xB4, 0xA1, 0x38 }; - // std::vector 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, 0x45, 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, 0x49, 0x44, 0x4D, 0x67, 0x41, 0x45, 0x51, 0x55, 0x61, 0x30, 0x6C, 0x38, 0x4D, 0x35, 0x76, 0x50, 0x58, 0x2B, 0x74, 0x4A, 0x76, 0x63, 0x4C, 0x2B, 0x45, 0x45, 0x4C, 0x34, 0x6E, 0x71, 0x79, 0x75, 0x53, 0x43, 0x0A, 0x4D, 0x4E, 0x46, 0x4A, 0x64, 0x43, 0x5A, 0x62, 0x62, 0x58, - // 0x35, 0x70, 0x4D, 0x36, 0x69, 0x4C, 0x52, 0x53, 0x30, 0x43, 0x51, 0x59, 0x45, 0x67, 0x56, 0x47, 0x51, 0x6B, 0x65, 0x75, 0x74, 0x74, 0x35, 0x78, 0x2F, 0x45, 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 }; - // std::vector ecparam = { - // 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, 0x4D, 0x42, 0x41, 0x67, 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, - // 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A }; - - d_crypto->set_public_key(publicKey); - bool result = d_crypto->verify_signature(message, signature); - - ASSERT_TRUE(result); - -//TEST(GnssCryptoTest, sha256Test) -//{ -// std::unique_ptr d_crypto; -// -// auto str = "Hello World!"; -// std::vector input (str, str + strlen(str)); -// -// auto expectedOutputStr = "86933b0b147ac4c010266b99004158fa17937db89a03dd7bb2ca5ef7f43c325a"; -// std::vector expectedOutput(expectedOutputStr, expectedOutputStr + strlen(expectedOutputStr)); -// -// std::vector computedOutput = d_crypto->computeSHA256(input); -// -// ASSERT_TRUE(computedOutput == expectedOutput - } - - -TEST(GnssCryptoTest,VerifyPubKeyImport) +TEST(GnssCryptoTest, VerifySignature) { // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" - std::unique_ptr d_crypto = std::make_unique(); + const std::string fake("fake"); + std::unique_ptr d_crypto = std::make_unique(fake, fake); + + // RG example - import crt certificate - result: FAIL + std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; + std::vector publicKey{// PEM format - 1000 bits + 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}; + + // own ECDSA-P256 key and message generated and signed and verified successfully with openssl + // std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message (unhashed) + // std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, + // 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, + // 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK + // raw r and s values + // std::vector signature = { + // 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, + // 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, + // 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, + // 0xA5, 0xB9, 0xB2, 0x56 }; + + // std::vector publicKey{// PK associated to the PrK, in der format ---test + // 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4A, 0xF3, + // 0xEE, 0x3A, 0x94, 0x25, 0x25, 0x3D, 0x55, 0xC2, 0x5A, 0xC2, 0x2D, 0xCF, 0x14, 0x4D, 0x39, 0x0D, 0xB1, 0xFC, 0x7F, 0x31, 0x5A, 0x2A, 0x19, 0xAE, 0x4E, 0xD6, 0xCB, 0xA6, 0x59, + // 0xD6, 0x99, 0x7C, 0xE8, 0xBD, 0x1F, 0x43, 0x34, 0x1C, 0x59, 0xD9, 0xD9, 0xCA, 0xC3, 0xEE, 0x58, 0xE5, 0xEA, 0xD3, 0x55, 0x44, 0xEA, 0x89, 0x71, 0x65, 0xD0, 0x92, 0x72, 0xA2, + // 0xC8, 0x3C, 0x87, 0x5D }; + // std::vector publicKey{ // PK associated to the PrK, in pem format + // 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, + // 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, + // 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, + // 0x44, 0x79, 0x48, 0x58, 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 }; + + // own key - GnuTLS error: The curve is unsupported... x192 EC unsupported?? + // std::vector message = {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64 }; // hello world + // std::vector signature = {0x30, 0x34, 0x02, 0x18, 0x4F, 0xAC, 0x9C, 0x5A, 0x44, 0xCF, 0xFD, 0x42, 0x6A, 0x58, 0x97, 0xA4, 0x94, 0x53, 0x2C, 0x79, 0xD1, 0x7B, 0x8B, 0xF9, 0x93, 0x03, 0xA2, 0xAF, 0x02, 0x18, 0x46, 0xF2, 0xF3, 0xCF, 0x9A, 0x23, 0x39, 0xB4, 0x25, 0x11, 0x89, 0x9A, 0x44, 0x7E, 0x2F, 0xB1, 0xE1, 0x58, 0xAF, 0xCE, 0xC1,0xB4, 0xA1, 0x38 }; + // std::vector 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, 0x45, 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, 0x49, 0x44, 0x4D, 0x67, 0x41, 0x45, 0x51, 0x55, 0x61, 0x30, 0x6C, 0x38, 0x4D, 0x35, 0x76, 0x50, 0x58, 0x2B, 0x74, 0x4A, 0x76, 0x63, 0x4C, 0x2B, 0x45, 0x45, 0x4C, 0x34, 0x6E, 0x71, 0x79, 0x75, 0x53, 0x43, 0x0A, 0x4D, 0x4E, 0x46, 0x4A, 0x64, 0x43, 0x5A, 0x62, 0x62, 0x58, + // 0x35, 0x70, 0x4D, 0x36, 0x69, 0x4C, 0x52, 0x53, 0x30, 0x43, 0x51, 0x59, 0x45, 0x67, 0x56, 0x47, 0x51, 0x6B, 0x65, 0x75, 0x74, 0x74, 0x35, 0x78, 0x2F, 0x45, 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 }; + // std::vector ecparam = { + // 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, 0x4D, 0x42, 0x41, 0x67, 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, + // 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A }; + + d_crypto->set_public_key(publicKey); + bool result = d_crypto->verify_signature(message, signature); + + ASSERT_TRUE(result); +} +// TEST(GnssCryptoTest, sha256Test) +//{ +// std::unique_ptr d_crypto; +// +// auto str = "Hello World!"; +// std::vector input (str, str + strlen(str)); +// +// auto expectedOutputStr = "86933b0b147ac4c010266b99004158fa17937db89a03dd7bb2ca5ef7f43c325a"; +// std::vector expectedOutput(expectedOutputStr, expectedOutputStr + strlen(expectedOutputStr)); +// +// std::vector computedOutput = d_crypto->computeSHA256(input); +// +// ASSERT_TRUE(computedOutput == expectedOutput + + +TEST(GnssCryptoTest, VerifyPubKeyImport) +{ + // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" + const std::string fake("fake"); + std::unique_ptr d_crypto = std::make_unique(fake, fake); // RG example - key is raw 520 bits example shown - // std::vector publicKey = { // base64 decoding error - // 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, - // - // 0x04, 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, 0x88, 0x68, 0x4D, 0x91, 0x8C, 0xF0, 0x27, 0x28, 0x8E, 0xBC, 0xB3, 0xF3, 0x8A, 0xFC, 0x73, - // 0xE0, 0xA0, 0xB9, 0x0E, 0xDA, 0x28, 0xD0, 0xF3, 0x10, 0x19, 0xC8, 0x37, 0x4F, 0x07, 0x57, 0x47, 0x49, - // - // 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 - // - // }; + // std::vector publicKey = { // base64 decoding error + // 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, + // + // 0x04, 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, 0x88, 0x68, 0x4D, 0x91, 0x8C, 0xF0, 0x27, 0x28, 0x8E, 0xBC, 0xB3, 0xF3, 0x8A, 0xFC, 0x73, + // 0xE0, 0xA0, 0xB9, 0x0E, 0xDA, 0x28, 0xD0, 0xF3, 0x10, 0x19, 0xC8, 0x37, 0x4F, 0x07, 0x57, 0x47, 0x49, + // + // 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 + // + // }; // RG example crt exported and convert PK.pem - key is raw 1000 bits ,..., why mismatch!? does key get truncated? - // std::vector 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 } ; + // std::vector 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 } ; // own ECDSA P 256 public key and own message generated (2024-02-19-Own-Key-ECDSA-openssl) - std::vector publicKey{ // PEM + std::vector 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, - 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, 0x44, 0x79, 0x48, 0x58, 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 }; + 0x2D, 0x2D, 0x2D, 0x0A}; d_crypto->set_public_key(publicKey); ASSERT_TRUE(d_crypto->have_public_key()); - - - - - - // std::vector publicKey = { // DER format -// 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, 0x30, 0x82, 0x02, 0x6C, 0x30, 0x82, 0x02, 0x12, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x47, 0xC4, 0xF1, 0x43, 0xC3, 0xFA, 0x61, 0xA5, 0x29, 0x4E, 0x63, -// 0xD5, 0x57, 0x2B, 0x01, 0x62, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x37, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x45, 0x55, 0x53, 0x50, 0x41, 0x31, 0x18, 0x30, -// 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x45, 0x55, 0x53, 0x50, 0x41, 0x20, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x20, 0x49, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x32, 0x33, 0x30, 0x37, 0x32, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x30, 0x5A, 0x17, 0x0D, 0x32, 0x35, 0x30, 0x38, 0x30, 0x38, 0x31, 0x31, 0x33, -// 0x33, 0x30, 0x30, 0x5A, 0x30, 0x3A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x45, 0x55, 0x53, 0x50, 0x41, 0x31, 0x1B, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x12, 0x45, 0x55, 0x53, 0x50, 0x41, -// 0x20, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x20, 0x45, 0x45, 0x20, 0x50, 0x4B, 0x52, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 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, 0x88, 0x68, 0x4D, 0x91, 0x8C, 0xF0, 0x27, 0x28, 0x8E, 0xBC, 0xB3, 0xF3, 0x8A, 0xFC, 0x73, 0xE0, 0xA0, 0xB9, 0x0E, 0xDA, 0x28, 0xD0, 0xF3, 0x10, 0x19, 0xC8, 0x37, 0x4F, 0x07, 0x57, -// 0x47, 0x49, 0xA3, 0x81, 0xFC, 0x30, 0x81, 0xF9, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x6A, 0x22, 0x16, 0x58, 0x9B, 0x23, 0xC9, 0x43, 0x41, 0x3C, 0xB6, 0xF8, 0x9D, 0x93, 0x0F, 0xE0, 0xFE, 0x6A, 0x3C, 0x54, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, -// 0x14, 0x20, 0xC0, 0x54, 0x85, 0xAF, 0x82, 0xAE, 0x96, 0x3C, 0xBC, 0xDF, 0xC1, 0xB9, 0x05, 0xDE, 0xD7, 0x46, 0x72, 0x32, 0xA3, 0x30, 0x63, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04, 0x5C, 0x30, 0x5A, 0x30, 0x4E, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0xD5, 0x11, 0x01, 0x01, 0x01, 0x30, 0x3F, 0x30, 0x3D, -// 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x67, 0x73, 0x63, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x61, 0x2E, 0x65, 0x75, 0x2F, 0x67, 0x73, 0x63, 0x2D, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2F, -// 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x2F, 0x50, 0x4B, 0x49, 0x2F, 0x30, 0x08, 0x06, 0x06, 0x04, 0x00, 0x8F, 0x7A, 0x01, 0x02, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1D, 0x1F, 0x04, 0x3B, 0x30, 0x39, 0x30, 0x37, 0xA0, 0x35, 0xA0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, -// 0x67, 0x73, 0x63, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x61, 0x2E, 0x65, 0x75, 0x2F, 0x67, 0x73, 0x63, 0x2D, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2F, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x2F, 0x50, 0x4B, 0x49, 0x2F, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, -// 0x07, 0x80, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xE9, 0xBB, 0x90, 0x8E, 0xE5, 0x0C, 0xF3, 0xDA, 0x57, 0x71, 0xE3, 0xD0, 0xD2, 0xEA, 0xAC, 0x1B, 0x00, 0xF3, 0x51, 0xE9, 0xD8, 0xBB, 0x0A, 0xB2, 0x4C, 0x8A, 0x65, 0x52, 0x79, -// 0x9F, 0x43, 0xF6, 0x02, 0x20, 0x10, 0x65, 0x2F, 0x6A, 0xF8, 0x26, 0x20, 0x42, 0xFF, 0x09, 0x6B, 0xD0, 0x8D, 0x0B, 0x75, 0x15, 0x24, 0xBF, 0xE4, 0xFE, 0x60, 0xC3, 0x6E, 0x2D, 0x31, 0x32, 0xED, 0x65, 0x6C, 0x5C, 0x8B, 0x14 }; - -// std::vector publicKey= { // PEM format -// 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 }; + // 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, 0x30, 0x82, 0x02, 0x6C, 0x30, 0x82, 0x02, 0x12, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x47, 0xC4, 0xF1, 0x43, 0xC3, 0xFA, 0x61, 0xA5, 0x29, 0x4E, 0x63, + // 0xD5, 0x57, 0x2B, 0x01, 0x62, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x37, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x45, 0x55, 0x53, 0x50, 0x41, 0x31, 0x18, 0x30, + // 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x45, 0x55, 0x53, 0x50, 0x41, 0x20, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x20, 0x49, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x32, 0x33, 0x30, 0x37, 0x32, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x30, 0x5A, 0x17, 0x0D, 0x32, 0x35, 0x30, 0x38, 0x30, 0x38, 0x31, 0x31, 0x33, + // 0x33, 0x30, 0x30, 0x5A, 0x30, 0x3A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x45, 0x55, 0x53, 0x50, 0x41, 0x31, 0x1B, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x12, 0x45, 0x55, 0x53, 0x50, 0x41, + // 0x20, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x20, 0x45, 0x45, 0x20, 0x50, 0x4B, 0x52, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 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, 0x88, 0x68, 0x4D, 0x91, 0x8C, 0xF0, 0x27, 0x28, 0x8E, 0xBC, 0xB3, 0xF3, 0x8A, 0xFC, 0x73, 0xE0, 0xA0, 0xB9, 0x0E, 0xDA, 0x28, 0xD0, 0xF3, 0x10, 0x19, 0xC8, 0x37, 0x4F, 0x07, 0x57, + // 0x47, 0x49, 0xA3, 0x81, 0xFC, 0x30, 0x81, 0xF9, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x6A, 0x22, 0x16, 0x58, 0x9B, 0x23, 0xC9, 0x43, 0x41, 0x3C, 0xB6, 0xF8, 0x9D, 0x93, 0x0F, 0xE0, 0xFE, 0x6A, 0x3C, 0x54, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + // 0x14, 0x20, 0xC0, 0x54, 0x85, 0xAF, 0x82, 0xAE, 0x96, 0x3C, 0xBC, 0xDF, 0xC1, 0xB9, 0x05, 0xDE, 0xD7, 0x46, 0x72, 0x32, 0xA3, 0x30, 0x63, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04, 0x5C, 0x30, 0x5A, 0x30, 0x4E, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0xD5, 0x11, 0x01, 0x01, 0x01, 0x30, 0x3F, 0x30, 0x3D, + // 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x67, 0x73, 0x63, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x61, 0x2E, 0x65, 0x75, 0x2F, 0x67, 0x73, 0x63, 0x2D, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2F, + // 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x2F, 0x50, 0x4B, 0x49, 0x2F, 0x30, 0x08, 0x06, 0x06, 0x04, 0x00, 0x8F, 0x7A, 0x01, 0x02, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1D, 0x1F, 0x04, 0x3B, 0x30, 0x39, 0x30, 0x37, 0xA0, 0x35, 0xA0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, + // 0x67, 0x73, 0x63, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x61, 0x2E, 0x65, 0x75, 0x2F, 0x67, 0x73, 0x63, 0x2D, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2F, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x2F, 0x50, 0x4B, 0x49, 0x2F, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, + // 0x07, 0x80, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xE9, 0xBB, 0x90, 0x8E, 0xE5, 0x0C, 0xF3, 0xDA, 0x57, 0x71, 0xE3, 0xD0, 0xD2, 0xEA, 0xAC, 0x1B, 0x00, 0xF3, 0x51, 0xE9, 0xD8, 0xBB, 0x0A, 0xB2, 0x4C, 0x8A, 0x65, 0x52, 0x79, + // 0x9F, 0x43, 0xF6, 0x02, 0x20, 0x10, 0x65, 0x2F, 0x6A, 0xF8, 0x26, 0x20, 0x42, 0xFF, 0x09, 0x6B, 0xD0, 0x8D, 0x0B, 0x75, 0x15, 0x24, 0xBF, 0xE4, 0xFE, 0x60, 0xC3, 0x6E, 0x2D, 0x31, 0x32, 0xED, 0x65, 0x6C, 0x5C, 0x8B, 0x14 }; + // std::vector publicKey= { // PEM format + // 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 }; } + // Unit test for computeHMAC_SHA_256 function. -TEST(GnssCryptoTest, TestComputeHMACSHA256) { // key and message generated with openssl - std::unique_ptr d_crypto = std::make_unique(); +TEST(GnssCryptoTest, TestComputeHMACSHA256) +{ + // key and message generated with openssl + const std::string fake("fake"); + std::unique_ptr d_crypto = std::make_unique(fake, fake); std::vector key = { - 0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7, - 0x7D, 0x48, 0xE7, 0xF1, 0x48, 0x0C, 0xC2, 0x98, - 0xEB, 0x62, 0x3E, 0x95, 0x6B, 0x2B, 0xCE, 0xA3, - 0xB4, 0xD4, 0xDB, 0x31, 0xEE, 0x96, 0xAB, 0xFA }; + 0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7, + 0x7D, 0x48, 0xE7, 0xF1, 0x48, 0x0C, 0xC2, 0x98, + 0xEB, 0x62, 0x3E, 0x95, 0x6B, 0x2B, 0xCE, 0xA3, + 0xB4, 0xD4, 0xDB, 0x31, 0xEE, 0x96, 0xAB, 0xFA}; - std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A + std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world con 0x0A std::vector expected_output = { - 0xC3, 0x51, 0xF6, 0xFD, 0xDD, 0xC9, 0x8B, 0x41, - 0xD6, 0xF4, 0x77, 0x6D, 0xAC, 0xE8, 0xE0, 0x14, - 0xB2, 0x7A, 0xCC, 0x22, 0x00, 0xAA, 0xD2, 0x37, - 0xD0, 0x79, 0x06, 0x12, 0x83, 0x40, 0xB7, 0xA6 }; - + 0xC3, 0x51, 0xF6, 0xFD, 0xDD, 0xC9, 0x8B, 0x41, + 0xD6, 0xF4, 0x77, 0x6D, 0xAC, 0xE8, 0xE0, 0x14, + 0xB2, 0x7A, 0xCC, 0x22, 0x00, 0xAA, 0xD2, 0x37, + 0xD0, 0x79, 0x06, 0x12, 0x83, 0x40, 0xB7, 0xA6}; std::vector output = d_crypto->computeHMAC_SHA_256(key, message); ASSERT_EQ(expected_output, output); - - } -TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) { // key and message generated from RG A.6.5.1 - std::unique_ptr d_crypto = std::make_unique(); - std::vector key = { // RG K4 @ 345690 + +TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) +{ // key and message generated from RG A.6.5.1 + const std::string fake("fake"); + std::unique_ptr d_crypto = std::make_unique(fake, fake); + std::vector key = {// RG K4 @ 345690 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; @@ -207,15 +201,18 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) { // key and message generated fr ASSERT_EQ(expected_output, output); } -TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) { // key and message generated from RG A.6.5.2 - std::unique_ptr d_crypto = std::make_unique(); - std::vector key = { // RG K4 @ 345690 + +TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) +{ // key and message generated from RG A.6.5.2 + const std::string fake("fake"); + std::unique_ptr d_crypto = std::make_unique(fake, fake); + std::vector key = {// RG K4 @ 345690 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; std::vector message{ 0x02, 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x03, 0xBF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00,0x00, 0x44, 0x92, 0x38, + 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x44, 0x92, 0x38, 0x22, 0x78, 0x97, 0xFD, 0xEF, 0xF9, 0x30, 0x40}; std::vector expected_output = { @@ -223,7 +220,6 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) { // key and message generated 0xE6, 0x3F, 0xB7, 0xF4, 0xF5, 0x4D, 0x44, 0xAB, 0xEE, 0x4D, 0xCE, 0xB9, 0x3D, 0xCF, 0x65, 0xCB, 0x3A, 0x5B, 0x81, 0x4A, 0x34, 0xE9}; - std::vector output = d_crypto->computeHMAC_SHA_256(key, message); ASSERT_EQ(expected_output, output); diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 226e8e892..c54d25580 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -2,7 +2,6 @@ #include #include #include -#include #include #include @@ -25,26 +24,26 @@ protected: std::string page_even; OSNMA_msg osnma_msg{}; std::array nma_position_filled; - uint32_t d_GST_SIS{}; // 16 AUG 2023 05 00 01 + uint32_t d_GST_SIS{}; // 16 AUG 2023 05 00 01 uint32_t TOW{}; uint32_t WN{}; - std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm - const uint32_t LEAP_SECONDS = 0;//13 + 5; + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm + const uint32_t LEAP_SECONDS = 0; // 13 + 5; void set_time(std::tm& input); -// std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; - std::string log_name {"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; - void initializeGoogleLog(); + // std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; + std::string log_name{"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; + // void initializeGoogleLog(); void SetUp() override { - flag_CRC_test = false; // TODO what for? + flag_CRC_test = false; // TODO what for? page_even = ""; -// std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; + // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; set_time(input_time); -// std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; -// std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; + // std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; + // std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.pem"; std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); @@ -58,121 +57,120 @@ public: }; -TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { +TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) +{ // Arrange // ---------- osnma->d_tesla_key_verified = false; - osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 - osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits + osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 + osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; // local_time_verification would do this operation. TODO - eliminate duplication. osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); - osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) - osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; + osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; - osnma->d_tesla_keys.insert((std::pair>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. - std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 + osnma->d_tesla_keys.insert((std::pair>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. + std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 uint32_t TOW = 345630; - - - // Act // ---------- bool result = osnma->verify_tesla_key(key, TOW); - - - - // Assert // ---------- ASSERT_TRUE(result); - } + TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) { - initializeGoogleLog(); + // initializeGoogleLog(); // Arrange // ---------- -// std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); + // std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); - if (testVectors.empty()){ + if (testVectors.empty()) + { ASSERT_TRUE(false); } bool end_of_hex_stream{false}; int offset_byte{0}; - int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size - const int SIZE_PAGE_BYTES{240/8}; // total bytes of a page - const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe - const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; // total bytes of a subframe - const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds + int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size + const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page + const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe + const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES * SIZE_SUBFRAME_PAGES}; // total bytes of a subframe + const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds const int DUMMY_PAGE{63}; bool flag_dummy_page{false}; - std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS - << ", TOW=" << TOW - << ", WN=" << WN << std::endl; - - - + std::cout << "OsnmaTestVectorsSimulation:" + << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; // Act // ---------- // loop over all bytes of data. Note: all TestVectors have same amount of data. - while (end_of_hex_stream == false){ + while (end_of_hex_stream == false) + { // loop over all SVs, extract a subframe - for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe - std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) "<< tv.svId << std::endl; + for (const TestVector& tv : testVectors) + { // loop over all SVs, extract a subframe + std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; auto osnmaMsg_sptr = std::make_shared(); std::array hkroot{}; std::array mack{}; - byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) - std::map> words; // structure containing and + byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) + std::map> words; // structure containing and - for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe + for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe { // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index - std::vector page_bytes = extract_page_bytes(tv,byte_index,SIZE_PAGE_BYTES); - if(page_bytes.empty()){ - std::cout<< "OsnmaTestVectorsSimulation: end of TestVectors \n" << "byte_index="< data_k(even_page.substr(2,112)); - std::bitset<16> data_j(odd_page.substr(2,16)); + std::bitset<112> data_k(even_page.substr(2, 112)); + std::bitset<16> data_j(odd_page.substr(2, 16)); std::bitset<112> shifted_data_k = data_k; -// uint8_t word_type = 0; -// for(int i = 0; i < 6; ++i) { -// word_type |= (data_k[104 + i] << i); -// } - uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word - std::cout<< "OsnmaTestVectorsSimulation: received Word "<< static_cast(word_type) << std::endl; - if( (word_type >= 1 && word_type <=5) || word_type == 6 || word_type == 10) + // uint8_t word_type = 0; + // for(int i = 0; i < 6; ++i) { + // word_type |= (data_k[104 + i] << i); + // } + uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word + std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast(word_type) << std::endl; + if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) { // store raw word std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); words[word_type] = data_combined; } - if(word_type == DUMMY_PAGE) + if (word_type == DUMMY_PAGE) flag_dummy_page = true; // place it into osnma object. std::bitset<40> osnmaBits(odd_page.substr(18, 40)); @@ -185,12 +183,13 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) byte_index += SIZE_PAGE_BYTES; } - std::cout<< "----------" << std::endl; - if(end_of_hex_stream) + std::cout << "----------" << std::endl; + if (end_of_hex_stream) break; - if(flag_dummy_page){ + if (flag_dummy_page) + { flag_dummy_page = false; - continue; // skip this SV + continue; // skip this SV } // Fill osnma object @@ -198,8 +197,8 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) osnmaMsg_sptr->mack = mack; osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; - osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ; - osnmaMsg_sptr->PRN = tv.svId; // PRNa + osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20; + osnmaMsg_sptr->PRN = tv.svId; // PRNa // TODO - refactor this logic, currently it is split @@ -210,14 +209,14 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) if (words.find(i) == words.end()) { ephClockStatusWordsReceived = false; - std::cerr<< "OsnmaTestVectorsSimulation: error parsing words 1->5. " - "Word "<< i << " should be received for each subframe but was not." << std::endl; + std::cerr << "OsnmaTestVectorsSimulation: error parsing words 1->5. " + "Word " + << i << " should be received for each subframe but was not." << std::endl; } } // extract bits as needed by osnma block - if(ephClockStatusWordsReceived) + if (ephClockStatusWordsReceived) { - // Define the starting position and length of bits to extract for each word std::map> extractionParams = { {1, {6, 120}}, @@ -229,15 +228,15 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) }; // Fill NavData bits -- Iterate over the extraction parameters - for (const auto& param : extractionParams) { + for (const auto& param : extractionParams) + { uint8_t wordKey = param.first; uint8_t start = param.second.first; uint8_t length = param.second.second; // Extract the required bits and fill osnma block - osnmaMsg_sptr->EphemerisClockAndStatusData_2 += words[wordKey]. - to_string().substr( - start, length); + osnmaMsg_sptr->EphemerisClockAndStatusData_2 += words[wordKey].to_string().substr( + start, length); } } @@ -245,12 +244,12 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) bool timingWordsReceived = words.find(6) != words.end() && words.find(10) != words.end(); // extract bits as needed by osnma block - if(timingWordsReceived){ + if (timingWordsReceived) + { // Define the starting position and length of bits to extract for each word std::map> extractionParams = { {6, {6, 99}}, - {10, {86, 42}} - }; + {10, {86, 42}}}; // Fill NavData bits -- Iterate over the extraction parameters for (const auto& param : extractionParams) @@ -263,27 +262,26 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) osnmaMsg_sptr->TimingData_2 += words[wordKey].to_string().substr( start, length); } - } // Call the handler, as if it came from telemetry decoder block auto temp_obj = pmt::make_any(osnmaMsg_sptr); - osnma->msg_handler_osnma(temp_obj); // osnma entry point + osnma->msg_handler_osnma(temp_obj); // osnma entry point } - if(!end_of_hex_stream){ - offset_byte = byte_index; // update offset for the next subframe + if (!end_of_hex_stream) + { + offset_byte = byte_index; // update offset for the next subframe d_GST_SIS += DURATION_SUBFRAME; TOW = d_GST_SIS & 0x000FFFFF; - WN = (d_GST_SIS & 0xFFF00000) >> 20 ; - std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS + WN = (d_GST_SIS & 0xFFF00000) >> 20; + std::cout << "OsnmaTestVectorsSimulation:" + << " d_GST_SIS= " << d_GST_SIS << ", TOW=" << TOW << ", WN=" << WN << std::endl; } - - } @@ -293,20 +291,24 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) } + std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std::string& filename) { std::ifstream file(filename); std::vector testVectors; - if (!file.is_open()) { - std::cerr<<"Error reading the file \"" << filename <<"\" \n"; + if (!file.is_open()) + { + std::cerr << "Error reading the file \"" << filename << "\" \n"; return testVectors; } std::string line; std::getline(file, line); - if (line != "SVID,NumNavBits,NavBitsHEX\r" ){ - std::cerr<<"Error parsing first line" <<"\n"; - } + if (line != "SVID,NumNavBits,NavBitsHEX\r") + { + std::cerr << "Error parsing first line" + << "\n"; + } while (std::getline(file, line)) { @@ -329,23 +331,27 @@ std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std: return testVectors; } + + std::vector OsnmaMsgReceiverTest::parseNavBits(const std::string& hex) { std::vector bytes; - for (unsigned int i = 0; i < hex.length()-1; i += 2) + for (unsigned int i = 0; i < hex.length() - 1; i += 2) { std::string byteString = hex.substr(i, 2); - uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16); + uint8_t byte = (uint8_t)strtol(byteString.c_str(), NULL, 16); bytes.push_back(byte); } return bytes; } + + std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector& bytes) { std::string bit_string; bit_string.reserve(bytes.size() * 8); - for(const auto& byte : bytes) + for (const auto& byte : bytes) { std::bitset<8> bits(byte); bit_string += bits.to_string(); @@ -353,6 +359,7 @@ std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector& bytes return bit_string; } + /** * @brief Extracts a range of bytes from a TestVector's navBits vector. * @@ -381,6 +388,8 @@ std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& return extracted_bytes; } + + /** * @brief Sets the time based on the given input. * @@ -404,118 +413,37 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) uint32_t sec_in_week = 7 * 24 * 60 * 60; uint32_t week_number = duration_sec.count() / sec_in_week; uint32_t time_of_week = duration_sec.count() % sec_in_week; - this->WN = week_number; - this->TOW = time_of_week + LEAP_SECONDS; + this->WN = week_number; + this->TOW = time_of_week + LEAP_SECONDS; // Return the week number and time of week as a pair // TODO: d_GST_SIS or d_receiver_time? doubt // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 - this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); - - -} -void OsnmaMsgReceiverTest::initializeGoogleLog() -{ - google::InitGoogleLogging(log_name.c_str()); - FLAGS_minloglevel = 0; // INFO - FLAGS_logtostderr = 0; // add this line - FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; - if (FLAGS_log_dir.empty()) - { - std::cout << "Logging will be written at " - << std::filesystem::temp_directory_path() - << '\n' - << "Use gnss-sdr --log_dir=/path/to/log to change that.\n"; - } - else - { - try - { - const std::filesystem::path p(FLAGS_log_dir); - if (!std::filesystem::exists(p)) - { - std::cout << "The path " - << FLAGS_log_dir - << " does not exist, attempting to create it.\n"; - std::error_code ec; - if (!std::filesystem::create_directory(p, ec)) - { - std::cout << "Could not create the " << FLAGS_log_dir << " folder.\n"; - gflags::ShutDownCommandLineFlags(); - throw std::runtime_error("Could not create folder for logs"); - } - } - std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; - } - catch (const std::exception& e) - { - std::cerr << e.what() << '\n'; - std::cerr << "Could not create the " << FLAGS_log_dir << " folder.\n"; - gflags::ShutDownCommandLineFlags(); - throw; - } - } + this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); } TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) { - // Arrange - // ---------- - // m0 - std::vector expected_message = { - 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, - 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, - 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, - 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, - 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00 - }; - - uint32_t TOW_Tag0 = 345660; - uint32_t TOW_NavData = TOW_Tag0 - 30; - uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; - uint32_t WN = 1248; - uint32_t PRNa = 2; - uint8_t CTR = 1; - - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 - osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; - osnma->d_osnma_data.d_nma_header.nmas = 0b10; - - MACK_tag_and_info MTI; - MTI.tag = static_cast(0xE37BC4F858); - MTI.tag_info.PRN_d = 0x02; - MTI.tag_info.ADKD = 0x00; - MTI.tag_info.cop = 0x0F; - Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); - - - - // Act - // ---------- - auto computed_message = osnma->build_message(t0); - - - // Assert - // ---------- - ASSERT_TRUE(computed_message == expected_message); - -} -TEST_F(OsnmaMsgReceiverTest, TagVerification) { // Arrange // ---------- - // Tag0 + // m0 + std::vector expected_message = { + 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, + 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, + 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, + 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, + 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00}; + uint32_t TOW_Tag0 = 345660; uint32_t TOW_NavData = TOW_Tag0 - 30; - uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; uint32_t WN = 1248; uint32_t PRNa = 2; uint8_t CTR = 1; - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; osnma->d_osnma_data.d_nma_header.nmas = 0b10; @@ -528,29 +456,62 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + // Act + // ---------- + auto computed_message = osnma->build_message(t0); + + + // Assert + // ---------- + ASSERT_TRUE(computed_message == expected_message); +} + + +TEST_F(OsnmaMsgReceiverTest, TagVerification) +{ + // Arrange + // ---------- + // Tag0 + uint32_t TOW_Tag0 = 345660; + uint32_t TOW_NavData = TOW_Tag0 - 30; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; + uint32_t WN = 1248; + uint32_t PRNa = 2; + uint8_t CTR = 1; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MACK_tag_and_info MTI; + MTI.tag = static_cast(0xE37BC4F858); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x00; + MTI.tag_info.cop = 0x0F; + Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + // Act // ---------- bool result_tag0 = osnma->verify_tag(t0); - - - // Assert // ---------- - //ASSERT_TRUE(result_tag0); + // ASSERT_TRUE(result_tag0); // Tag3 uint32_t TOW_Tag3 = 345660; uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; - uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30 ; + uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30; WN = 1248; PRNa = 2; CTR = 3; - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; osnma->d_satellite_nav_data[PRNa][TOW_NavData].utc_vector_2 = "111111111111111111111111111111110000000000000000000000010001001001001000" @@ -566,5 +527,4 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { bool result_tag3 = osnma->verify_tag(t3); ASSERT_TRUE(result_tag0 && result_tag3); - } From d4cc036cbd7866460b7de00190788286002c7f81 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 23 Jun 2024 12:03:12 +0200 Subject: [PATCH 130/219] Fix HMAC-SHA256 computation with OpenSSL > 3.0 --- src/core/system_parameters/gnss_crypto.cc | 60 ++++++++++++++++++----- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index e78e29e39..a73907e73 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -34,6 +34,7 @@ #if USE_OPENSSL_3 #include #include +#include #include #include #include @@ -315,23 +316,58 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 std::vector hmac(EVP_MAX_MD_SIZE); + size_t output_length = 0; + // Create the context for the HMAC operation + EVP_MAC* mac = EVP_MAC_fetch(nullptr, "HMAC", nullptr); + if (!mac) + { + LOG(WARNING) << "OSNMA HMAC_SHA_256 computation failed to fetch HMAC"; + return output; + } - // Create HMAC-SHA256 context - EVP_MD_CTX* ctx = EVP_MD_CTX_new(); - EVP_PKEY* pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key.data(), key.size()); + EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac); + if (!ctx) + { + EVP_MAC_free(mac); + LOG(WARNING) << "OSNMA HMAC_SHA_256 computation failed to create HMAC context"; + return output; + } - // Initialize HMAC-SHA256 context - EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, pkey); + // Initialize the HMAC context with the key and the SHA-256 algorithm + OSSL_PARAM params[] = { + OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_DIGEST, const_cast("SHA256"), 0), + OSSL_PARAM_construct_end()}; - // Compute HMAC-SHA256 - EVP_DigestSignUpdate(ctx, input.data(), input.size()); - size_t macLength; - EVP_DigestSignFinal(ctx, hmac.data(), &macLength); + if (EVP_MAC_init(ctx, key.data(), key.size(), params) <= 0) + { + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + LOG(WARNING) << "OSNMA HMAC_SHA_256 computation failed to initialize HMAC context"; + return output; + } - EVP_PKEY_free(pkey); - EVP_MD_CTX_free(ctx); + // Update the HMAC context with the input data + if (EVP_MAC_update(ctx, input.data(), input.size()) <= 0) + { + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + LOG(WARNING) << "OSNMA HMAC_SHA_256 computation failed to update HMAC context"; + return output; + } - hmac.resize(macLength); + // Finalize the HMAC and retrieve the output + if (EVP_MAC_final(ctx, hmac.data(), &output_length, hmac.size()) <= 0) + { + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + LOG(WARNING) << "OSNMA HMAC_SHA_256 computation failed to finalize HMAC"; + return output; + } + + // Clean up the HMAC context + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + hmac.resize(output_length); output = hmac; #else std::vector hmac(32); From 378820e76b654ef583b681d27cfa9230f00dc0bc Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 23 Jun 2024 13:10:38 +0200 Subject: [PATCH 131/219] Add unit test for SHA3-256 hash algorithm --- .../osnma/gnss_crypto_test.cc | 75 +++++-------------- 1 file changed, 18 insertions(+), 57 deletions(-) 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 a80ef055a..d17ae5e47 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 @@ -7,7 +7,6 @@ class GnssCryptoTest : public ::testing::Test TEST(GnssCryptoTest, VerifySignature) { - // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" const std::string fake("fake"); std::unique_ptr d_crypto = std::make_unique(fake, fake); @@ -22,66 +21,11 @@ TEST(GnssCryptoTest, VerifySignature) 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}; - // own ECDSA-P256 key and message generated and signed and verified successfully with openssl - // std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // Hello world con 0x0A al final. Raw message (unhashed) - // std::vector signature{0x30, 0x45, 0x02, 0x21, 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, 0xC8, 0x93, 0x16, 0x5A, - // 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, - // 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, 0xA5, 0xB9, 0xB2, 0x56}; // Hello world hashed and then encrypted with PrK - // raw r and s values - // std::vector signature = { - // 0x00, 0xFB, 0xE6, 0x09, 0x74, 0x5C, 0x12, 0xE8, 0x2C, 0x0C, 0xC9, 0x7A, 0x8E, 0x13, 0x88, 0x87, 0xDA, 0xBF, 0x08, 0x43, 0xF8, - // 0xC8, 0x93, 0x16, 0x5A, 0x0F, 0x7A, 0xA4, 0xBF, 0x4A, 0xE1, 0xE1, 0xDB, 0x02, 0x20, 0x6B, 0xCB, 0x2F, 0x80, 0x69, 0xBB, 0xDE, - // 0xC9, 0x11, 0x1D, 0x51, 0x2B, 0x9F, 0x61, 0xA0, 0xC1, 0x29, 0xD1, 0x0B, 0x58, 0x09, 0x82, 0x58, 0xFC, 0x9E, 0x00, 0xC7, 0xEE, - // 0xA5, 0xB9, 0xB2, 0x56 }; - - // std::vector publicKey{// PK associated to the PrK, in der format ---test - // 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4A, 0xF3, - // 0xEE, 0x3A, 0x94, 0x25, 0x25, 0x3D, 0x55, 0xC2, 0x5A, 0xC2, 0x2D, 0xCF, 0x14, 0x4D, 0x39, 0x0D, 0xB1, 0xFC, 0x7F, 0x31, 0x5A, 0x2A, 0x19, 0xAE, 0x4E, 0xD6, 0xCB, 0xA6, 0x59, - // 0xD6, 0x99, 0x7C, 0xE8, 0xBD, 0x1F, 0x43, 0x34, 0x1C, 0x59, 0xD9, 0xD9, 0xCA, 0xC3, 0xEE, 0x58, 0xE5, 0xEA, 0xD3, 0x55, 0x44, 0xEA, 0x89, 0x71, 0x65, 0xD0, 0x92, 0x72, 0xA2, - // 0xC8, 0x3C, 0x87, 0x5D }; - // std::vector publicKey{ // PK associated to the PrK, in pem format - // 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, - // 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, - // 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, - // 0x44, 0x79, 0x48, 0x58, 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 }; - - // own key - GnuTLS error: The curve is unsupported... x192 EC unsupported?? - // std::vector message = {0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64 }; // hello world - // std::vector signature = {0x30, 0x34, 0x02, 0x18, 0x4F, 0xAC, 0x9C, 0x5A, 0x44, 0xCF, 0xFD, 0x42, 0x6A, 0x58, 0x97, 0xA4, 0x94, 0x53, 0x2C, 0x79, 0xD1, 0x7B, 0x8B, 0xF9, 0x93, 0x03, 0xA2, 0xAF, 0x02, 0x18, 0x46, 0xF2, 0xF3, 0xCF, 0x9A, 0x23, 0x39, 0xB4, 0x25, 0x11, 0x89, 0x9A, 0x44, 0x7E, 0x2F, 0xB1, 0xE1, 0x58, 0xAF, 0xCE, 0xC1,0xB4, 0xA1, 0x38 }; - // std::vector 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, 0x45, 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, 0x49, 0x44, 0x4D, 0x67, 0x41, 0x45, 0x51, 0x55, 0x61, 0x30, 0x6C, 0x38, 0x4D, 0x35, 0x76, 0x50, 0x58, 0x2B, 0x74, 0x4A, 0x76, 0x63, 0x4C, 0x2B, 0x45, 0x45, 0x4C, 0x34, 0x6E, 0x71, 0x79, 0x75, 0x53, 0x43, 0x0A, 0x4D, 0x4E, 0x46, 0x4A, 0x64, 0x43, 0x5A, 0x62, 0x62, 0x58, - // 0x35, 0x70, 0x4D, 0x36, 0x69, 0x4C, 0x52, 0x53, 0x30, 0x43, 0x51, 0x59, 0x45, 0x67, 0x56, 0x47, 0x51, 0x6B, 0x65, 0x75, 0x74, 0x74, 0x35, 0x78, 0x2F, 0x45, 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 }; - // std::vector ecparam = { - // 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x42, 0x45, 0x47, 0x49, 0x4E, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6B, 0x6A, 0x4F, 0x50, 0x51, 0x4D, 0x42, 0x41, 0x67, 0x3D, 0x3D, 0x0A, 0x2D, 0x2D, 0x2D, 0x2D, - // 0x2D, 0x45, 0x4E, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4D, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A }; - d_crypto->set_public_key(publicKey); bool result = d_crypto->verify_signature(message, signature); ASSERT_TRUE(result); } -// TEST(GnssCryptoTest, sha256Test) -//{ -// std::unique_ptr d_crypto; -// -// auto str = "Hello World!"; -// std::vector input (str, str + strlen(str)); -// -// auto expectedOutputStr = "86933b0b147ac4c010266b99004158fa17937db89a03dd7bb2ca5ef7f43c325a"; -// std::vector expectedOutput(expectedOutputStr, expectedOutputStr + strlen(expectedOutputStr)); -// -// std::vector computedOutput = d_crypto->computeSHA256(input); -// -// ASSERT_TRUE(computedOutput == expectedOutput TEST(GnssCryptoTest, VerifyPubKeyImport) @@ -110,7 +54,7 @@ TEST(GnssCryptoTest, VerifyPubKeyImport) // 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 } ; // own ECDSA P 256 public key and own message generated (2024-02-19-Own-Key-ECDSA-openssl) - std::vector publicKey{// PEM + std::vector 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, 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, @@ -225,4 +169,21 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) ASSERT_EQ(expected_output, output); } + +TEST(GnssCryptoTest, TestComputeSHA3_256) +{ + const std::string fake("fake"); + std::unique_ptr d_crypto = std::make_unique(fake, fake); + std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world + + std::vector 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}; + + std::vector output = d_crypto->computeSHA3_256(message); + + ASSERT_EQ(expected_output, output); +} + // TODO extend to HMAC-AES \ No newline at end of file From a704c1004472f2612e30cb82e3a9cf47deec33e6 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 23 Jun 2024 13:34:57 +0200 Subject: [PATCH 132/219] Add SHA_256 unit test --- src/core/system_parameters/gnss_crypto.h | 1 + .../osnma/gnss_crypto_test.cc | 131 +++++++----------- 2 files changed, 51 insertions(+), 81 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index e8b41fddd..24d858f7d 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -36,6 +36,7 @@ class Gnss_Crypto { public: + Gnss_Crypto() = default; Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath); ~Gnss_Crypto(); 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 d17ae5e47..95137e21d 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 @@ -5,15 +5,46 @@ class GnssCryptoTest : public ::testing::Test }; +TEST(GnssCryptoTest, TestComputeSHA_256) +{ + std::unique_ptr d_crypto = std::make_unique(); + std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world + + std::vector 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}; + + std::vector output = d_crypto->computeSHA256(message); + + ASSERT_EQ(expected_output, output); +} + + +TEST(GnssCryptoTest, TestComputeSHA3_256) +{ + std::unique_ptr d_crypto = std::make_unique(); + std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world + + std::vector 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}; + + std::vector output = d_crypto->computeSHA3_256(message); + + ASSERT_EQ(expected_output, output); +} + + TEST(GnssCryptoTest, VerifySignature) { - const std::string fake("fake"); - std::unique_ptr d_crypto = std::make_unique(fake, fake); + std::unique_ptr d_crypto = std::make_unique(); - // RG example - import crt certificate - result: FAIL + // RG example - import crt certificate - result: FAIL std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; - std::vector publicKey{// PEM format - 1000 bits + std::vector publicKey{ // PEM format - 1000 bits 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, @@ -30,31 +61,9 @@ TEST(GnssCryptoTest, VerifySignature) TEST(GnssCryptoTest, VerifyPubKeyImport) { - // "../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem" - const std::string fake("fake"); - std::unique_ptr d_crypto = std::make_unique(fake, fake); + std::unique_ptr d_crypto = std::make_unique(); - // RG example - key is raw 520 bits example shown - // std::vector publicKey = { // base64 decoding error - // 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, - // - // 0x04, 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, 0x88, 0x68, 0x4D, 0x91, 0x8C, 0xF0, 0x27, 0x28, 0x8E, 0xBC, 0xB3, 0xF3, 0x8A, 0xFC, 0x73, - // 0xE0, 0xA0, 0xB9, 0x0E, 0xDA, 0x28, 0xD0, 0xF3, 0x10, 0x19, 0xC8, 0x37, 0x4F, 0x07, 0x57, 0x47, 0x49, - // - // 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 - // - // }; - - // RG example crt exported and convert PK.pem - key is raw 1000 bits ,..., why mismatch!? does key get truncated? - // std::vector 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 } ; - // own ECDSA P 256 public key and own message generated (2024-02-19-Own-Key-ECDSA-openssl) - std::vector publicKey{ // PEM + std::vector 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, 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, @@ -68,39 +77,14 @@ TEST(GnssCryptoTest, VerifyPubKeyImport) d_crypto->set_public_key(publicKey); ASSERT_TRUE(d_crypto->have_public_key()); - - // std::vector publicKey = { // DER format - // 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, 0x30, 0x82, 0x02, 0x6C, 0x30, 0x82, 0x02, 0x12, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x47, 0xC4, 0xF1, 0x43, 0xC3, 0xFA, 0x61, 0xA5, 0x29, 0x4E, 0x63, - // 0xD5, 0x57, 0x2B, 0x01, 0x62, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x37, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x45, 0x55, 0x53, 0x50, 0x41, 0x31, 0x18, 0x30, - // 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x0F, 0x45, 0x55, 0x53, 0x50, 0x41, 0x20, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x20, 0x49, 0x43, 0x41, 0x30, 0x1E, 0x17, 0x0D, 0x32, 0x33, 0x30, 0x37, 0x32, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x30, 0x5A, 0x17, 0x0D, 0x32, 0x35, 0x30, 0x38, 0x30, 0x38, 0x31, 0x31, 0x33, - // 0x33, 0x30, 0x30, 0x5A, 0x30, 0x3A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x45, 0x53, 0x31, 0x0E, 0x30, 0x0C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x05, 0x45, 0x55, 0x53, 0x50, 0x41, 0x31, 0x1B, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x12, 0x45, 0x55, 0x53, 0x50, 0x41, - // 0x20, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x20, 0x45, 0x45, 0x20, 0x50, 0x4B, 0x52, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 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, 0x88, 0x68, 0x4D, 0x91, 0x8C, 0xF0, 0x27, 0x28, 0x8E, 0xBC, 0xB3, 0xF3, 0x8A, 0xFC, 0x73, 0xE0, 0xA0, 0xB9, 0x0E, 0xDA, 0x28, 0xD0, 0xF3, 0x10, 0x19, 0xC8, 0x37, 0x4F, 0x07, 0x57, - // 0x47, 0x49, 0xA3, 0x81, 0xFC, 0x30, 0x81, 0xF9, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0x6A, 0x22, 0x16, 0x58, 0x9B, 0x23, 0xC9, 0x43, 0x41, 0x3C, 0xB6, 0xF8, 0x9D, 0x93, 0x0F, 0xE0, 0xFE, 0x6A, 0x3C, 0x54, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, - // 0x14, 0x20, 0xC0, 0x54, 0x85, 0xAF, 0x82, 0xAE, 0x96, 0x3C, 0xBC, 0xDF, 0xC1, 0xB9, 0x05, 0xDE, 0xD7, 0x46, 0x72, 0x32, 0xA3, 0x30, 0x63, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04, 0x5C, 0x30, 0x5A, 0x30, 0x4E, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0xD5, 0x11, 0x01, 0x01, 0x01, 0x30, 0x3F, 0x30, 0x3D, - // 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x67, 0x73, 0x63, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x61, 0x2E, 0x65, 0x75, 0x2F, 0x67, 0x73, 0x63, 0x2D, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2F, - // 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x2F, 0x50, 0x4B, 0x49, 0x2F, 0x30, 0x08, 0x06, 0x06, 0x04, 0x00, 0x8F, 0x7A, 0x01, 0x02, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1D, 0x1F, 0x04, 0x3B, 0x30, 0x39, 0x30, 0x37, 0xA0, 0x35, 0xA0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, - // 0x67, 0x73, 0x63, 0x2D, 0x65, 0x75, 0x72, 0x6F, 0x70, 0x61, 0x2E, 0x65, 0x75, 0x2F, 0x67, 0x73, 0x63, 0x2D, 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x73, 0x2F, 0x4F, 0x53, 0x4E, 0x4D, 0x41, 0x2F, 0x50, 0x4B, 0x49, 0x2F, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x01, 0x01, 0xFF, 0x04, 0x04, 0x03, 0x02, - // 0x07, 0x80, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xE9, 0xBB, 0x90, 0x8E, 0xE5, 0x0C, 0xF3, 0xDA, 0x57, 0x71, 0xE3, 0xD0, 0xD2, 0xEA, 0xAC, 0x1B, 0x00, 0xF3, 0x51, 0xE9, 0xD8, 0xBB, 0x0A, 0xB2, 0x4C, 0x8A, 0x65, 0x52, 0x79, - // 0x9F, 0x43, 0xF6, 0x02, 0x20, 0x10, 0x65, 0x2F, 0x6A, 0xF8, 0x26, 0x20, 0x42, 0xFF, 0x09, 0x6B, 0xD0, 0x8D, 0x0B, 0x75, 0x15, 0x24, 0xBF, 0xE4, 0xFE, 0x60, 0xC3, 0x6E, 0x2D, 0x31, 0x32, 0xED, 0x65, 0x6C, 0x5C, 0x8B, 0x14 }; - - // std::vector publicKey= { // PEM format - // 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 }; } // Unit test for computeHMAC_SHA_256 function. TEST(GnssCryptoTest, TestComputeHMACSHA256) { - // key and message generated with openssl - const std::string fake("fake"); - std::unique_ptr d_crypto = std::make_unique(fake, fake); + std::unique_ptr d_crypto = std::make_unique(); + std::vector key = { 0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7, 0x7D, 0x48, 0xE7, 0xF1, 0x48, 0x0C, 0xC2, 0x98, @@ -121,14 +105,15 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256) TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) -{ // key and message generated from RG A.6.5.1 - const std::string fake("fake"); - std::unique_ptr d_crypto = std::make_unique(fake, fake); - std::vector key = {// RG K4 @ 345690 +{ + // key and message generated from RG A.6.5.1 + std::unique_ptr d_crypto = std::make_unique(); + + std::vector key = { // RG K4 @ 345690 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; - std::vector message{// m0 + std::vector message{ // m0 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, @@ -147,10 +132,11 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) -{ // key and message generated from RG A.6.5.2 - const std::string fake("fake"); - std::unique_ptr d_crypto = std::make_unique(fake, fake); - std::vector key = {// RG K4 @ 345690 +{ + // key and message generated from RG A.6.5.2 + std::unique_ptr d_crypto = std::make_unique(); + + std::vector key = { // RG K4 @ 345690 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; @@ -169,21 +155,4 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) ASSERT_EQ(expected_output, output); } - -TEST(GnssCryptoTest, TestComputeSHA3_256) -{ - const std::string fake("fake"); - std::unique_ptr d_crypto = std::make_unique(fake, fake); - std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world - - std::vector 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}; - - std::vector output = d_crypto->computeSHA3_256(message); - - ASSERT_EQ(expected_output, output); -} - // TODO extend to HMAC-AES \ No newline at end of file From 8ea75116acbcb9405b63dccdf19f010e20d64d56 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 23 Jun 2024 13:48:31 +0200 Subject: [PATCH 133/219] Fix intantiation of Gnss_Crypto() with GnuTLS --- src/core/system_parameters/gnss_crypto.cc | 9 +++++++++ src/core/system_parameters/gnss_crypto.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index a73907e73..06c9d6538 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -56,6 +56,15 @@ #endif +Gnss_Crypto::Gnss_Crypto() +{ +#if USE_OPENSSL_FALLBACK +#else // GnuTLS + gnutls_global_init(); +#endif +} + + Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath) { #if USE_OPENSSL_FALLBACK diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 24d858f7d..9d60c8a77 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -36,7 +36,7 @@ class Gnss_Crypto { public: - Gnss_Crypto() = default; + Gnss_Crypto(); Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath); ~Gnss_Crypto(); From 584b95e62e01a44ccc7b4b80bd3f3be15d6c8b92 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 24 Jun 2024 14:01:34 +0200 Subject: [PATCH 134/219] Fix CMAC-AES implementation in OpenSSL>3.0.0. Add unit test --- src/core/system_parameters/gnss_crypto.cc | 70 +++++++++++++------ .../osnma/gnss_crypto_test.cc | 31 ++++++-- 2 files changed, 75 insertions(+), 26 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 06c9d6538..947b8a436 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -38,6 +38,7 @@ #include #include #include +#include #define OPENSSL_ENGINE nullptr #else #include @@ -416,35 +417,62 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke std::vector output(16); #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 - std::vector mac(EVP_MAX_MD_SIZE); // CMAC-AES output size + std::vector aux(EVP_MAX_MD_SIZE); // CMAC-AES output size + size_t output_length = 0; - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - EVP_MAC* cmac = EVP_MAC_fetch(nullptr, "CMAC-AES", nullptr); + // Create the context for the CMAC operation + EVP_MAC* mac = EVP_MAC_fetch(nullptr, "CMAC", nullptr); + if (!mac) + { + LOG(INFO) << "OSNMA CMAC-AES: Failed to fetch CMAC"; + return output; + } - EVP_MAC_CTX* cmacCtx = EVP_MAC_CTX_new(cmac); + EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac); + if (!ctx) + { + LOG(INFO) << "OSNMA CMAC-AES: Failed to create CMAC context"; + return output; + } - OSSL_PARAM params[4]; - params[0] = OSSL_PARAM_construct_utf8_string("key", (char*)key.data(), key.size()); - params[1] = OSSL_PARAM_construct_octet_string("iv", nullptr, 0); // Set IV to nullptr - params[2] = OSSL_PARAM_construct_octet_string("aad", nullptr, 0); // Set AAD to nullptr - params[3] = OSSL_PARAM_construct_end(); + // Initialize the CMAC context with the key and the AES algorithm + OSSL_PARAM params[] = { + OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, const_cast("AES-128-CBC"), 0), + OSSL_PARAM_construct_octet_string(OSSL_MAC_PARAM_KEY, const_cast(key.data()), key.size()), + OSSL_PARAM_construct_end()}; - // Set AES-128 CMAC cipher and key - EVP_MAC_init(cmacCtx, nullptr, 0, params); + if (EVP_MAC_init(ctx, nullptr, 0, params) <= 0) + { + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + LOG(INFO) << "OSNMA CMAC-AES: Failed to initialize CMAC context"; + return output; + } - // Compute CMAC-AES - EVP_MAC_update(cmacCtx, input.data(), input.size()); - size_t macLength = mac.size(); - size_t outputLength = 16; + // Update the CMAC context with the input data + if (EVP_MAC_update(ctx, input.data(), input.size()) <= 0) + { + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + LOG(INFO) << "OSNMA CMAC-AES: Failed to update CMAC context"; + return output; + } - EVP_MAC_final(cmacCtx, mac.data(), &macLength, outputLength); + // Finalize the CMAC and retrieve the output + if (EVP_MAC_final(ctx, aux.data(), &output_length, aux.size()) <= 0) + { + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); + LOG(INFO) << "OSNMA CMAC-AES: Failed to finalize CMAC"; + return output; + } - EVP_MAC_free(cmac); - EVP_MAC_CTX_free(cmacCtx); - EVP_CIPHER_CTX_free(ctx); + // Clean up the CMAC context + EVP_MAC_CTX_free(ctx); + EVP_MAC_free(mac); - mac.resize(macLength); - output = mac; + aux.resize(output_length); + output = aux; #else std::vector mac(16); // CMAC-AES output size 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 95137e21d..87f5afbfa 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 @@ -44,7 +44,7 @@ TEST(GnssCryptoTest, VerifySignature) // RG example - import crt certificate - result: FAIL std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; - std::vector publicKey{ // PEM format - 1000 bits + std::vector publicKey{// PEM format - 1000 bits 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, @@ -109,11 +109,11 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) // key and message generated from RG A.6.5.1 std::unique_ptr d_crypto = std::make_unique(); - std::vector key = { // RG K4 @ 345690 + std::vector key = {// RG K4 @ 345690 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; - std::vector message{ // m0 + std::vector message{// m0 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, @@ -136,7 +136,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) // key and message generated from RG A.6.5.2 std::unique_ptr d_crypto = std::make_unique(); - std::vector key = { // RG K4 @ 345690 + std::vector key = {// RG K4 @ 345690 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; @@ -155,4 +155,25 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) ASSERT_EQ(expected_output, output); } -// TODO extend to HMAC-AES \ No newline at end of file + +TEST(GnssCryptoTest, TestComputeCMAC_AES) +{ + // Tests vectors from https://datatracker.ietf.org/doc/html/rfc4493#appendix-A + std::unique_ptr d_crypto = std::make_unique(); + + std::vector key = { + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; + + std::vector message{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A}; + + std::vector expected_output = { + 0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44, + 0xF7, 0x9B, 0xDD, 0x9D, 0xD0, 0x4A, 0x28, 0x7C}; + + std::vector output = d_crypto->computeCMAC_AES(key, message); + + ASSERT_EQ(expected_output, output); +} \ No newline at end of file From 2cf96bda87ac04c96cad663f83211118bf20c8b0 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 24 Jun 2024 14:41:49 +0200 Subject: [PATCH 135/219] =?UTF-8?q?[TAS-226]=20[FEAT]=20Remove=20tags=20sk?= =?UTF-8?q?ipped=20=E2=89=A5=2010=20times?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take into account TOW to decide whether to skip a tag or not. Still, I dont like the logic of iterating over and over the tags. Once a tag is verified once, it should be not checked unless next TOW subframe came (new Data or new Key available) Adittionally: solved a small specification bug for ADKD=12, improved reporting (status of Tag is a string now) --- src/core/libs/osnma_msg_receiver.cc | 15 +++++++++------ src/core/system_parameters/osnma_helper.cc | 12 +++++++++++- src/core/system_parameters/osnma_helper.h | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 8447fb5fc..c515228ba 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -980,7 +980,10 @@ void osnma_msg_receiver::process_mack_message() << std::endl; } } - else { + else if(it.second.TOW > d_osnma_data.d_nav_data.TOW_sf0){ + // case 1: adkd=12 and t.Tow + 300 < current TOW + // case 2: adkd=0/4 and t.Tow + 30 < current TOW + // case 3: any adkd and t.Tow > current TOW it.second.skipped ++; LOG(WARNING) << "Galileo OSNMA: Tag verification :: SKIPPED (x"<< it.second.skipped <<")for Tag Id= " << it.second.tag_id @@ -1063,7 +1066,7 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) if (tag.ADKD == 0 || tag.ADKD == 4) applicable_key = d_tesla_keys[tag.TOW + 30]; else // ADKD 12 - applicable_key = d_tesla_keys[tag.TOW + 300]; + applicable_key = d_tesla_keys[tag.TOW + 330]; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { @@ -1284,7 +1287,7 @@ void osnma_msg_receiver::remove_verified_tags() << ", PRNd=" << static_cast(it->second.PRN_d) << ", status= " - << it->second.status + << d_helper->verification_status_str(it->second.status) << std::endl; it = d_tags_awaiting_verify.erase(it); } @@ -1303,7 +1306,7 @@ void osnma_msg_receiver::remove_verified_tags() << ", PRNd=" << static_cast(it->second.PRN_d) << ", status= " - << it->second.status + << d_helper->verification_status_str(it->second.status) << std::endl; it = d_tags_awaiting_verify.erase(it); } @@ -1478,14 +1481,14 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t){ } else if (t.ADKD == 12) { - auto it = d_tesla_keys.find(t.TOW + 300); + auto it = d_tesla_keys.find(t.TOW + 330); if (it != d_tesla_keys.end()) { LOG(INFO)<< "Galileo OSNMA: hasKey = true " << std::endl; return true; } } - LOG(INFO) << "Galileo OSNMA: hasKey = false " << std::endl; + LOG(INFO) << "Galileo OSNMA: hasKey = false "; return false; } std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes) diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index 9ce394543..aa338f408 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -63,4 +63,14 @@ std::vector Osnma_Helper::bytes(const std::string& binaryString) { } return bytes; -} \ No newline at end of file +} + +std::string Osnma_Helper::verification_status_str(int status) +{ + switch (status) { + case 0: return "SUCCESS"; + case 1: return "FAIL"; + case 2: return "UNVERIFIED"; + default: return "UNKNOWN"; + } +} diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 9bf1d860d..2f8df078b 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -29,7 +29,7 @@ public: uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; std::vector gst_to_uint8(uint32_t GST) const; std::vector bytes(const std::string& binaryString); + std::string verification_status_str(int status); }; - #endif // GNSS_SDR_OSNMA_HELPER_H From 9a1def7aa40c6ad631d3f9b82fd76901d1929187 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 25 Jun 2024 10:50:00 +0200 Subject: [PATCH 136/219] Fix building with old compilers --- src/core/libs/osnma_msg_receiver.cc | 650 ++++++++++-------- src/core/system_parameters/osnma_dsm_reader.h | 22 - 2 files changed, 348 insertions(+), 324 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index c515228ba..4a5e95ac9 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -21,15 +21,18 @@ #include "Galileo_OSNMA.h" #include "gnss_crypto.h" #include "gnss_satellite.h" -#include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader +#include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "osnma_helper.h" #include // for gr::io_signature::make +#include #include #include #include #include #include #include // for typeid +#include + #if USE_GLOG_AND_GFLAGS #include // for DLOG @@ -95,16 +98,16 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) { const auto nma_msg = wht::any_cast>(pmt::any_ref(msg)); - const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); // TODO remove if unneeded + const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); // TODO remove if unneeded std::ostringstream output_message; output_message << "Galileo OSNMA: Subframe received starting at " - << "WN=" - << nma_msg->WN_sf0 - << ", TOW=" - << nma_msg->TOW_sf0 - << ", from satellite " - << sat; + << "WN=" + << nma_msg->WN_sf0 + << ", TOW=" + << nma_msg->TOW_sf0 + << ", from satellite " + << sat; LOG(WARNING) << output_message.str(); std::cout << output_message.str() << std::endl; @@ -113,28 +116,31 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) { // TODO - PRNa is a typo here, I think for d_satellite_nav_data, is PRN_d the name to use - const auto inav_data = wht::any_cast>>(pmt::any_ref(msg)); + const auto inav_data = wht::any_cast>>(pmt::any_ref(msg)); uint32_t PRNa = std::get<0>(*inav_data); - std::string nav_data = std::get<1>(*inav_data);; + std::string nav_data = std::get<1>(*inav_data); + ; uint32_t TOW = std::get<2>(*inav_data); // iono data => 549 bits, utc data, 141 bits. - if(nav_data.size() == 549) + if (nav_data.size() == 549) { - LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " << "TOW_sf=" << TOW <(d_osnma_data); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); @@ -157,17 +163,17 @@ 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) { read_nma_header(osnma_msg->hkroot[0]); - if(d_osnma_data.d_nma_header.nmas == 0 || d_osnma_data.d_nma_header.nmas == 3 /*&& d_kroot_verified*/) + if (d_osnma_data.d_nma_header.nmas == 0 || d_osnma_data.d_nma_header.nmas == 3 /*&& d_kroot_verified*/) { - LOG(ERROR) << "Galileo OSNMA: NMAS invalid, skipping osnma message\n"; + LOG(WARNING) << "Galileo OSNMA: NMAS invalid, skipping osnma message"; return; } 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) + 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) local_time_verification(osnma_msg); - read_and_process_mack_block(osnma_msg); // only process them if at least 3 available. + read_and_process_mack_block(osnma_msg); // only process them if at least 3 available. } @@ -199,9 +205,8 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) d_osnma_data.d_dsm_header.dsm_block_id = d_dsm_reader->get_dsm_block_id(dsm_header); // BID LOG(INFO) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); LOG(INFO) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); - LOG(INFO)<< "Galileo OSNMA: Received block " << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) - << " from DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) - << std::endl; + LOG(INFO) << "Galileo OSNMA: Received block " << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) + << " from DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id); } /* @@ -219,7 +224,6 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ // First block indicates number of blocks in DSM message if (d_osnma_data.d_dsm_header.dsm_block_id == 0) { - uint8_t nb = d_dsm_reader->get_number_blocks_index(d_dsm_message[d_osnma_data.d_dsm_header.dsm_id][0]); uint16_t number_of_blocks = 0; if (d_osnma_data.d_dsm_header.dsm_id < 12) @@ -255,7 +259,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][d_osnma_data.d_dsm_header.dsm_block_id] = 1; std::stringstream available_blocks; available_blocks << "Galileo OSNMA: Available blocks for DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id) << ": [ "; - if (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == 0) // block 0 not received yet + if (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == 0) // block 0 not received yet { for (auto id_received : d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id]) { @@ -283,8 +287,8 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } } } - available_blocks<< "]" << std::endl; - LOG(INFO) << available_blocks.str() << std::endl; + available_blocks << "]"; + LOG(INFO) << available_blocks.str(); } /** @@ -296,57 +300,53 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptrWN_sf0 & 0x00000FFF) << 20 | (osnma_msg->TOW_sf0 & 0x000FFFFF); - //std::cout << "Galileo OSNMA: d_GST_SIS: " << d_GST_SIS << std::endl; - //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; - d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k * 3600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) - //d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; - // TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID. - if(d_receiver_time != 0) + // std::cout << "Galileo OSNMA: d_GST_SIS: " << d_GST_SIS << std::endl; + // d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; + d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k * 3600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + // d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; + // TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID. + if (d_receiver_time != 0) { - - d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G. -// d_receiver_time += 30; - //std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; - + d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G. + // d_receiver_time += 30; + // std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; } else - {// local time not initialised -> compute it. - d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G. - //std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; + { // local time not initialised -> compute it. + d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G. + // std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; } // verify time constraint std::time_t delta_T = abs(d_receiver_time - d_GST_SIS); - if( delta_T <= d_T_L ) + if (delta_T <= d_T_L) { d_tags_allowed = tags_to_verify::all; - d_tags_to_verify = {0,4,12}; - LOG(INFO) << "Galileo OSNMA: time constraint OK (" << delta_T << "\n"; - LOG(INFO) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; - //std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; + d_tags_to_verify = {0, 4, 12}; + LOG(INFO) << "Galileo OSNMA: time constraint OK (" << delta_T; + LOG(INFO) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS; + // std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; // TODO set flag to false to avoid processing dsm and MACK messages } - else if( delta_T > d_T_L && delta_T <= 10* delta_T ) + else if (delta_T > d_T_L && delta_T <= 10 * delta_T) { d_tags_allowed = tags_to_verify::slow_eph; d_tags_to_verify = {12}; - LOG(WARNING) << "Galileo OSNMA: time constraint allows only slow MACs to be verified\n"; - LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; - LOG(WARNING)<< "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; - + LOG(WARNING) << "Galileo OSNMA: time constraint allows only slow MACs to be verified"; + LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS; + LOG(WARNING) << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; } else { d_tags_allowed = tags_to_verify::none; d_tags_to_verify = {}; - LOG(ERROR) << "Galileo OSNMA: time constraint violation\n"; - LOG(ERROR) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS << "\n"; - LOG(ERROR) << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; - + LOG(WARNING) << "Galileo OSNMA: time constraint violation"; + LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS; + LOG(WARNING) << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; } - } + /** * @brief Process DSM block of an OSNMA message. * @@ -362,7 +362,8 @@ void osnma_msg_receiver::process_dsm_block(const std::shared_ptr& osn if ((d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] != 0) && (d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] == std::accumulate(d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cbegin(), d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id].cend(), 0))) { - std::vector dsm_msg(std::size_t(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) * SIZE_DSM_BLOCKS_BYTES, 0); + size_t len = std::size_t(d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]) * SIZE_DSM_BLOCKS_BYTES; + std::vector dsm_msg(len, 0); for (uint32_t i = 0; i < d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]; i++) { for (size_t j = 0; j < SIZE_DSM_BLOCKS_BYTES; j++) @@ -376,6 +377,7 @@ void osnma_msg_receiver::process_dsm_block(const std::shared_ptr& osn } } + /* * case DSM-Kroot: * - computes the padding and compares with received message @@ -415,7 +417,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg l_ds_bits = it->second; } const uint16_t l_ds_bytes = l_ds_bits / 8; - d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); // C: this accounts for padding in case needed. + d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); // C: this accounts for padding in case needed. for (uint16_t k = 0; k < l_ds_bytes; k++) { d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + l_lk_bytes + k]; @@ -433,20 +435,20 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg const uint16_t check_l_dk = 104 * std::ceil(1.0 + static_cast((l_lk_bytes * 8.0) + l_ds_bits) / 104.0); if (l_dk_bits != check_l_dk) { - LOG(ERROR) << "Galileo OSNMA: Failed length reading of DSM-KROOT message" << std::endl; + LOG(WARNING) << "Galileo OSNMA: Failed length reading of DSM-KROOT message"; } else { // validation of padding const uint16_t size_m = 13 + l_lk_bytes; std::vector MSG; - MSG.reserve(size_m + l_ds_bytes + 1); // C: message will get too many zeroes? ((12+1)+16) + 64 + 1? => in theory not, allocating is not assigning - MSG.push_back(osnma_msg->hkroot[0]); // C: NMA header + MSG.reserve(size_m + l_ds_bytes + 1); // C: message will get too many zeroes? ((12+1)+16) + 64 + 1? => in theory not, allocating is not assigning + MSG.push_back(osnma_msg->hkroot[0]); // C: NMA header for (uint16_t i = 1; i < size_m; i++) { MSG.push_back(dsm_msg[i]); } - std::vector message = MSG; // MSG = (M | DS) from ICD. Eq. 7 + std::vector 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]); @@ -479,27 +481,25 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg LOG(INFO) << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) - << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600 << std::endl; + << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; local_time_verification(osnma_msg); d_kroot_verified = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); if (d_kroot_verified) { - LOG(WARNING) << "Galileo OSNMA: KROOT authentication successful !" << std::endl; - LOG(WARNING) << "Galileo OSNMA: KROOT authentication successful !" << std::endl; - LOG(WARNING) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " + std::cout << "Galileo OSNMA: KROOT authentication successful!" << std::endl; + LOG(INFO) << "Galileo OSNMA: KROOT authentication successful!"; + LOG(INFO) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " - << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks) << std::endl; + << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks); } else { - LOG(ERROR) << "Galileo OSNMA: KROOT authentication failed. " << std::endl; - LOG(INFO) << "Galileo OSNMA: KROOT authentication failed. " << std::endl; + LOG(WARNING) << "Galileo OSNMA: KROOT authentication failed."; } - } else { - LOG(ERROR) << "Galileo OSNMA: Error computing padding bits." << std::endl; + LOG(WARNING) << "Galileo OSNMA: Error computing padding bits."; // TODO - here will have to decide if perform the verification or not. Since this step is not mandatory, one could as well have skipped it. } } @@ -544,7 +544,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg uint32_t check_l_dp_bytes = 104 * std::ceil(static_cast(1040.0 + l_npk_bytes * 8.0) / 104.0) / 8; if (l_dp_bytes != check_l_dp_bytes) { - LOG(ERROR) << "Galileo OSNMA: Failed length reading of DSM-PKR message" << std::endl; + LOG(WARNING) << "Galileo OSNMA: Failed length reading of DSM-PKR message"; } else { @@ -559,7 +559,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", PKID=" << static_cast(d_osnma_data.d_dsm_pkr_message.npktid) /*<< ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600*/ - << " received" << std::endl; + << " received"; // C: NPK verification against Merkle tree root. if (!d_public_key_verified) { @@ -570,7 +570,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk); } } - } } else @@ -582,6 +581,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } + /** * @brief Reads the Mack message from the given OSNMA_msg object. * @@ -601,16 +601,16 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrPRN,osnma_msg->TOW_sf0,d_osnma_data.d_nav_data); // TODO change place -// DEBUG PARSING MACK MESSAGES WHEN DSM-KROOT NOT YET AVAILABLE -// d_osnma_data.d_dsm_kroot_message.ts = 9; -// d_osnma_data.d_dsm_kroot_message.ks = 4; -// d_osnma_data.d_dsm_kroot_message.kroot = std::vector(16); - if (d_kroot_verified || d_tesla_key_verified || d_osnma_data.d_dsm_kroot_message.ts != 0 /*mack parser needs to know the tag size, otherwise cannot parse mack messages*/) // C: 4 ts < ts < 10 - { // TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future + d_osnma_data.d_nav_data.init(osnma_msg); // TODO refactor it + // add_satellite_data(osnma_msg->PRN,osnma_msg->TOW_sf0,d_osnma_data.d_nav_data); // TODO change place + // DEBUG PARSING MACK MESSAGES WHEN DSM-KROOT NOT YET AVAILABLE + // d_osnma_data.d_dsm_kroot_message.ts = 9; + // d_osnma_data.d_dsm_kroot_message.ks = 4; + // d_osnma_data.d_dsm_kroot_message.kroot = std::vector(16); + if (d_kroot_verified || d_tesla_key_verified || d_osnma_data.d_dsm_kroot_message.ts != 0 /*mack parser needs to know the tag size, otherwise cannot parse mack messages*/) // C: 4 ts < ts < 10 + { // TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future read_mack_header(); - d_osnma_data.d_mack_message.PRNa = osnma_msg->PRN; // FIXME this is ugly. + 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; d_osnma_data.d_mack_message.WN = osnma_msg->WN_sf0; read_mack_body(); @@ -620,14 +620,15 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr((d_mack_message[7/* bytes of MACK header */ + k * 7 /* offset of k-th tag */])) << 32); + tag += (static_cast((d_mack_message[7 /* bytes of MACK header */ + k * 7 /* offset of k-th tag */])) << 32); tag += (static_cast((d_mack_message[8 + k * 7])) << 24); tag += (static_cast((d_mack_message[9 + k * 7])) << 16); tag += (static_cast((d_mack_message[10 + k * 7])) << 8); @@ -847,7 +849,7 @@ void osnma_msg_receiver::read_mack_body() PRN_d += d_mack_message[12 + k * 7]; ADKD += ((d_mack_message[13 + k * 7] & 0xF0) >> 4); cop += (d_mack_message[13 + k * 7] & 0x0F); - if (k == (nt - 2)) // end of Tag&Info + if (k == (nt - 2)) // end of Tag&Info { d_osnma_data.d_mack_message.key = std::vector(d_osnma_data.d_dsm_kroot_message.kroot.size()); for (size_t j = 0; j < d_osnma_data.d_dsm_kroot_message.kroot.size(); j++) @@ -881,38 +883,43 @@ void osnma_msg_receiver::read_mack_body() */ void osnma_msg_receiver::process_mack_message() { - if(d_kroot_verified == false && d_tesla_key_verified == false) + if (d_kroot_verified == false && d_tesla_key_verified == false) { - LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed. "<< ", " - << "No Kroot nor TESLA key available" << std::endl; - if(!d_flag_debug){ - return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. + LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed. " + << ", " + << "No Kroot nor TESLA key available"; + if (!d_flag_debug) + { + return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. } else LOG(WARNING) << "But it will be processed for debugging purposes."; } // verify tesla key and add it to the container of verified keys if successful - if (d_tesla_keys.find(d_osnma_data.d_nav_data.TOW_sf0) == d_tesla_keys.end()) // check if already available => no need to verify + if (d_tesla_keys.find(d_osnma_data.d_nav_data.TOW_sf0) == d_tesla_keys.end()) // check if already available => no need to verify { bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key, d_osnma_data.d_nav_data.TOW_sf0); - if(retV){ - d_tesla_keys.insert(std::pair(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); + if (retV) + { + d_tesla_keys.insert(std::pair>(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); } } - // MACSEQ - verify current macks, then add current retrieved mack to the end. auto mack = d_macks_awaiting_MACSEQ_verification.begin(); - while (mack != d_macks_awaiting_MACSEQ_verification.end()){ - if(d_tesla_keys.find(mack->TOW + 30) != d_tesla_keys.end()){ + while (mack != d_macks_awaiting_MACSEQ_verification.end()) + { + if (d_tesla_keys.find(mack->TOW + 30) != d_tesla_keys.end()) + { bool ret = verify_macseq(*mack); - if (ret || d_flag_debug){ - for(std::size_t i = 0; i < mack->tag_and_info.size(); ++i) + if (ret || d_flag_debug) + { + for (std::size_t i = 0; i < mack->tag_and_info.size(); ++i) { // add tags of current mack to the verification queue auto& tag = mack->tag_and_info[i]; - Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. - d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); + Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. + d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; } std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; @@ -923,90 +930,91 @@ void osnma_msg_receiver::process_mack_message() mack = d_macks_awaiting_MACSEQ_verification.erase(mack); } } - else { // key not yet available - keep in container until then -- might be deleted if container size exceeds max allowed + else + { // key not yet available - keep in container until then -- might be deleted if container size exceeds max allowed ++mack; } } // add current received MACK to the container to be verified in the next iteration (on this one no key available) d_macks_awaiting_MACSEQ_verification.push_back(d_osnma_data.d_mack_message); - // Tag verification - for (auto & it : d_tags_awaiting_verify){ + for (auto& it : d_tags_awaiting_verify) + { bool ret; - if(tag_has_key_available(it.second) && tag_has_nav_data_available(it.second)){ + if (tag_has_key_available(it.second) && tag_has_nav_data_available(it.second)) + { ret = verify_tag(it.second); /* TODO - take into account: * - COP: if * - ADKD type * - NavData the tag verifies (min. number of bits verified to consider NavData OK) * */ - if(ret) + if (ret) { it.second.status = Tag::SUCCESS; LOG(WARNING) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id= " - << it.second.tag_id - << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase - << it.second.received_tag << std::dec - << ", TOW=" - << it.second.TOW - << ", ADKD=" - << static_cast(it.second.ADKD) - << ", PRNa=" - << static_cast(it.second.PRNa) - << ", PRNd=" - << static_cast(it.second.PRN_d) - << std::endl; + << it.second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it.second.received_tag << std::dec + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d); } - /* TODO notify PVT via pmt - * have_new_data() true - * signal which one is verified - * communicate to PVT*/ + /* TODO notify PVT via pmt + * have_new_data() true + * signal which one is verified + * communicate to PVT*/ else - { - it.second.status = Tag::FAIL; - LOG(ERROR) << "Galileo OSNMA: Tag verification :: FAILURE for tag Id=" - << it.second.tag_id - << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase - << it.second.received_tag << std::dec - << ", TOW=" - << it.second.TOW - << ", ADKD=" - << static_cast(it.second.ADKD) - << ", PRNa=" - << static_cast(it.second.PRNa) - << ", PRNd=" - << static_cast(it.second.PRN_d) - << std::endl; - } + { + it.second.status = Tag::FAIL; + LOG(WARNING) << "Galileo OSNMA: Tag verification :: FAILURE for tag Id=" + << it.second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it.second.received_tag << std::dec + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d); + } } - else if(it.second.TOW > d_osnma_data.d_nav_data.TOW_sf0){ + else if (it.second.TOW > d_osnma_data.d_nav_data.TOW_sf0) + { // case 1: adkd=12 and t.Tow + 300 < current TOW // case 2: adkd=0/4 and t.Tow + 30 < current TOW // case 3: any adkd and t.Tow > current TOW - it.second.skipped ++; - LOG(WARNING) << "Galileo OSNMA: Tag verification :: SKIPPED (x"<< it.second.skipped <<")for Tag Id= " - << it.second.tag_id - << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase - << it.second.received_tag << std::dec - << ", TOW=" - << it.second.TOW - << ", ADKD=" - << static_cast(it.second.ADKD) - << ", PRNa=" - << static_cast(it.second.PRNa) - << ", PRNd=" - << static_cast(it.second.PRN_d) - << ". Key available ("<< tag_has_key_available(it.second) <<"), navData ("<< tag_has_nav_data_available(it.second) <<"). " - << std::endl; + it.second.skipped++; + LOG(WARNING) << "Galileo OSNMA: Tag verification :: SKIPPED (x" << it.second.skipped << ")for Tag Id= " + << it.second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it.second.received_tag << std::dec + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d) + << ". Key available (" << tag_has_key_available(it.second) << "), navData (" << tag_has_nav_data_available(it.second) << "). "; } } remove_verified_tags(); - control_tags_awaiting_verify_size(); // remove the oldest tags if size is too big. + control_tags_awaiting_verify_size(); // remove the oldest tags if size is too big. } + bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) { // TODO create function for recursively apply hash @@ -1021,30 +1029,33 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) } // compute intermediate leafs' values -// std::vector x_0,x_1,x_2,x_3,x_4; - LOG(INFO) << "Galileo OSNMA: DSM-PKR :: leaf provided: m_" << static_cast(message.mid) << std::endl; + // std::vector x_0,x_1,x_2,x_3,x_4; + LOG(INFO) << "Galileo OSNMA: DSM-PKR :: leaf provided: m_" << static_cast(message.mid); std::vector x_next, x_current = d_crypto->computeSHA256(m_i); - for (size_t i = 0 ; i < 4 ; i++) - { - x_next.clear(); - bool leaf_is_on_right = ((message.mid / (1 << (i))) % 2) == 1; + for (size_t i = 0; i < 4; i++) + { + x_next.clear(); + bool leaf_is_on_right = ((message.mid / (1 << (i))) % 2) == 1; - if (leaf_is_on_right) { - // Leaf is on the right -> first the itn, then concatenate the leaf - x_next.insert(x_next.end(), &message.itn[32*i], &message.itn[32*i + 32]); - x_next.insert(x_next.end(), x_current.begin(), x_current.end()); - } else { - // Leaf is on the left -> first the leaf, then concatenate the itn - x_next.insert(x_next.end(), x_current.begin(), x_current.end()); - x_next.insert(x_next.end(), &message.itn[32*i], &message.itn[32*i + 32]); - } + if (leaf_is_on_right) + { + // Leaf is on the right -> first the itn, then concatenate the leaf + x_next.insert(x_next.end(), &message.itn[32 * i], &message.itn[32 * i + 32]); + x_next.insert(x_next.end(), x_current.begin(), x_current.end()); + } + else + { + // Leaf is on the left -> first the leaf, then concatenate the itn + x_next.insert(x_next.end(), x_current.begin(), x_current.end()); + x_next.insert(x_next.end(), &message.itn[32 * i], &message.itn[32 * i + 32]); + } - // Compute the next node. - x_current = d_crypto->computeSHA256(x_next); - } + // Compute the next node. + x_current = d_crypto->computeSHA256(x_next); + } - if(x_current == d_crypto->getMerkleRoot()) + if (x_current == d_crypto->getMerkleRoot()) { LOG(INFO) << "Galileo OSNMA: DSM-PKR verified successfully! " << std::endl; return true; @@ -1055,6 +1066,8 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) return false; } } + + bool osnma_msg_receiver::verify_tag(Tag& tag) { // TODO case tag0, to be verified here?, PRNd not needed for it @@ -1065,20 +1078,20 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) std::vector applicable_key; if (tag.ADKD == 0 || tag.ADKD == 4) applicable_key = d_tesla_keys[tag.TOW + 30]; - else // ADKD 12 + else // ADKD 12 applicable_key = d_tesla_keys[tag.TOW + 330]; - if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); } - else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { mac = d_crypto->computeCMAC_AES(applicable_key, m); } // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD - uint8_t lt_bits = 0; // TODO - remove this duplication of code. + uint8_t lt_bits = 0; // TODO - remove this duplication of code. const auto it2 = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); if (it2 != OSNMA_TABLE_11.cend()) { @@ -1119,34 +1132,33 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) if (tag.received_tag == computed_mac) { std::cout << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id= " - << tag.tag_id - << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase - << tag.received_tag << std::dec - << ", TOW=" - << tag.TOW - << ", ADKD=" - << static_cast(tag.ADKD) - << ", PRNa=" - << static_cast(tag.PRNa) - << ", PRNd=" - << static_cast(tag.PRN_d) - << std::endl; + << tag.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << tag.received_tag << std::dec + << ", TOW=" + << tag.TOW + << ", ADKD=" + << static_cast(tag.ADKD) + << ", PRNa=" + << static_cast(tag.PRNa) + << ", PRNd=" + << static_cast(tag.PRN_d); return true; } - - else - return false; + return false; } + + std::vector osnma_msg_receiver::build_message(const Tag& tag) { std::vector m; - if(tag.CTR != 1) + if (tag.CTR != 1) m.push_back(static_cast(tag.PRN_d)); m.push_back(static_cast(tag.PRNa)); // TODO: maybe here I have to use d_receiver_time instead of d_GST_SIS which is what I am computing - uint32_t GST = d_helper->compute_gst( tag.WN,tag.TOW); + uint32_t GST = d_helper->compute_gst(tag.WN, tag.TOW); std::vector GST_uint8 = d_helper->gst_to_uint8(GST); - m.insert(m.end(),GST_uint8.begin(),GST_uint8.end()); + m.insert(m.end(), GST_uint8.begin(), GST_uint8.end()); m.push_back(tag.CTR); // Extracts only two bits from d_osnma_data.d_nma_header.nmas uint8_t two_bits_nmas = d_osnma_data.d_nma_header.nmas & 0b00000011; @@ -1156,7 +1168,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) // Add applicable NavData bits to message std::string applicable_nav_data; std::vector applicable_nav_data_bytes; - if (tag.ADKD == 0 || tag.ADKD == 12) // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. + if (tag.ADKD == 0 || tag.ADKD == 12) // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. { applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; } @@ -1165,76 +1177,91 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].utc_vector_2; } else - LOG(ERROR) <<"Galileo OSNMA :: Tag verification :: unknown ADKD" <<"\n"; + LOG(WARNING) << "Galileo OSNMA :: Tag verification :: unknown ADKD"; // convert std::string to vector applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); // Convert and add NavData bytes into the message, taking care of that NMAS has only 2 bits - for (uint8_t byte : applicable_nav_data_bytes) { + for (uint8_t byte : applicable_nav_data_bytes) + { m.back() |= (byte >> 2); // First take the 6 MSB bits of byte and add to m - m.push_back(byte << 6); // Then take the last 2 bits of byte, shift them to MSB position and insert the new element into m + m.push_back(byte << 6); // Then take the last 2 bits of byte, shift them to MSB position and insert the new element into m } - if(m.back() == 0) { + if (m.back() == 0) + { m.pop_back(); // Remove the last element if its value is 0 (only padding was added) } - else { + else + { // Pad with zeros if the last element wasn't full - for (int bits = 2; bits < 8; bits += 2) { + for (int bits = 2; bits < 8; bits += 2) + { // Check if the last element in the vector has 2 '00' bits in its LSB position - if((m.back() & 0b00000011) == 0) { + if ((m.back() & 0b00000011) == 0) + { m.back() <<= 2; // Shift the existing bits to make room for new 2 bits } - else { + else + { break; // If it does not have 2 '00' bits in its LSB position, then the padding is complete } } } return m; } + + void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) { // control size of container - while (d_satellite_nav_data[SV_ID].size() >= 25) { + while (d_satellite_nav_data[SV_ID].size() >= 25) + { d_satellite_nav_data[SV_ID].erase(d_satellite_nav_data[SV_ID].begin()); } - //d_osnma_data[TOW] = crypto; // crypto - d_satellite_nav_data[SV_ID][TOW] = data; // nav - //std::cout << "Galileo OSNMA: added element, size is " << d_satellite_nav_data[SV_ID].size() << std::endl; + // d_osnma_data[TOW] = crypto; // crypto + d_satellite_nav_data[SV_ID][TOW] = data; // nav + // std::cout << "Galileo OSNMA: added element, size is " << d_satellite_nav_data[SV_ID].size() << std::endl; } + + void osnma_msg_receiver::display_data() { -// if(d_satellite_nav_data.empty()) -// return; -// -// for(const auto& satellite : d_satellite_nav_data) { -// std::cout << "SV_ID: " << satellite.first << std::endl; -// for(const auto& towData : satellite.second) { -// std::cout << "\tTOW: " << towData.first << " key: "; -// for(size_t i = 0; i < towData.second.d_mack_message.key.size(); i++) { -// std::cout << std::hex << std::setfill('0') << std::setw(2) -// << static_cast(towData.second.d_mack_message.key[i]) << " "; -// } -// } -// } + // if(d_satellite_nav_data.empty()) + // return; + // + // for(const auto& satellite : d_satellite_nav_data) { + // std::cout << "SV_ID: " << satellite.first << std::endl; + // for(const auto& towData : satellite.second) { + // std::cout << "\tTOW: " << towData.first << " key: "; + // for(size_t i = 0; i < towData.second.d_mack_message.key.size(); i++) { + // std::cout << std::hex << std::setfill('0') << std::setw(2) + // << static_cast(towData.second.d_mack_message.key[i]) << " "; + // } + // } + // } } + + bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TOW) { uint32_t num_of_hashes_needed; - uint32_t GST_SFi = d_receiver_time - 30; // GST of target key is to be used. + uint32_t GST_SFi = d_receiver_time - 30; // GST of target key is to be used. std::vector hash; - const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks)/8; - //std::vector validated_key; - if(d_tesla_key_verified){ // have to go up to last verified key + const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; + // std::vector validated_key; + if (d_tesla_key_verified) + { // have to go up to last verified key d_validated_key = d_tesla_keys.rbegin()->second; - num_of_hashes_needed = (d_receiver_time - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified - LOG(INFO) << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key " << std::endl; + num_of_hashes_needed = (d_receiver_time - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified + LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key"; - hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); + hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); } - else{// have to go until Kroot + else + { // have to go until Kroot d_validated_key = d_osnma_data.d_dsm_kroot_message.kroot; - num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 IC - LOG(INFO) << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) need to be performed up to Kroot " << std::endl; + num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 IC + LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to Kroot"; hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); } @@ -1247,23 +1274,26 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO } if (computed_key == d_validated_key && num_of_hashes_needed > 0) { - LOG(WARNING) << "Galileo OSNMA:: TESLA key verification :: SUCCESS! " << std::endl; - d_tesla_keys.insert(std::pair(TOW,key)); + LOG(WARNING) << "Galileo OSNMA:: TESLA key verification :: SUCCESS!"; + d_tesla_keys.insert(std::pair>(TOW, key)); d_tesla_key_verified = true; d_last_verified_key_GST = d_receiver_time; } - else if(num_of_hashes_needed > 0){ - LOG(ERROR) << "Galileo OSNMA:: TESLA key verification :: FAILED " << std::endl; - if(d_flag_debug){ - d_tesla_keys.insert(std::pair(TOW,key)); + else if (num_of_hashes_needed > 0) + { + LOG(WARNING) << "Galileo OSNMA:: TESLA key verification :: FAILED"; + if (d_flag_debug) + { + d_tesla_keys.insert(std::pair>(TOW, key)); d_last_verified_key_GST = d_receiver_time; d_tesla_key_verified = true; // TODO - if intermediate verification fails, can one still use the former verified tesla key or should go to Kroot or even retrieve new Kroot? } } return d_tesla_key_verified; - } + + /** * @brief Removes the tags that have been verified from the multimap d_tags_awaiting_verify. * @@ -1271,7 +1301,8 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO */ void osnma_msg_receiver::remove_verified_tags() { - for (auto it = d_tags_awaiting_verify.begin(); it != d_tags_awaiting_verify.end() ; ){ + for (auto it = d_tags_awaiting_verify.begin(); it != d_tags_awaiting_verify.end();) + { if (it->second.status == Tag::SUCCESS || it->second.status == Tag::FAIL) { LOG(INFO) << "Galileo OSNMA: Tag verification :: DELETE tag Id=" @@ -1287,8 +1318,7 @@ void osnma_msg_receiver::remove_verified_tags() << ", PRNd=" << static_cast(it->second.PRN_d) << ", status= " - << d_helper->verification_status_str(it->second.status) - << std::endl; + << d_helper->verification_status_str(it->second.status); it = d_tags_awaiting_verify.erase(it); } else if (it->second.skipped >= 20) @@ -1306,8 +1336,7 @@ void osnma_msg_receiver::remove_verified_tags() << ", PRNd=" << static_cast(it->second.PRN_d) << ", status= " - << d_helper->verification_status_str(it->second.status) - << std::endl; + << d_helper->verification_status_str(it->second.status); it = d_tags_awaiting_verify.erase(it); } else @@ -1315,6 +1344,8 @@ void osnma_msg_receiver::remove_verified_tags() } std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; } + + /** * @brief Control the size of the tags awaiting verification multimap. * @@ -1325,19 +1356,19 @@ void osnma_msg_receiver::remove_verified_tags() */ void osnma_msg_receiver::control_tags_awaiting_verify_size() { - while(d_tags_awaiting_verify.size() > 500) + while (d_tags_awaiting_verify.size() > 500) { auto it = d_tags_awaiting_verify.begin(); LOG(WARNING) << "Galileo OSNMA: Tag verification :: DELETED tag due to exceeding buffer size. " << "Tag Id= " << it->second.tag_id << ", TOW=" << it->first << ", ADKD=" << static_cast(it->second.ADKD) - << ", from satellite " << it->second.PRNa - << std::endl; + << ", from satellite " << it->second.PRNa; d_tags_awaiting_verify.erase(it); } } + /** * @brief Verifies the MACSEQ of a received MACK_message. * @@ -1349,8 +1380,8 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) { // MACSEQ verification - d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. - std::vector applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe + d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. + std::vector applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe std::vector sq1{}; std::vector sq2{}; std::vector applicable_sequence; @@ -1363,7 +1394,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) } // Assign relevant sequence based on subframe time - if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present. + if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present. { applicable_sequence = sq1; } @@ -1373,55 +1404,56 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) } else { - LOG(ERROR) << "Galileo OSNMA: Mismatch in the GST verification. " << std::endl; + LOG(WARNING) << "Galileo OSNMA: Mismatch in the GST verification."; } - if(mack.tag_and_info.size() != applicable_sequence.size() - 1) + if (mack.tag_and_info.size() != applicable_sequence.size() - 1) { - LOG(ERROR) << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!" << std::endl; + LOG(WARNING) << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!"; return false; } - std::vector flxTags {}; + std::vector flxTags{}; std::string tempADKD; // MACLT verification for (uint8_t i = 0; i < mack.tag_and_info.size(); i++) { - tempADKD = applicable_sequence[i+1]; - if(tempADKD == "FLX") + tempADKD = applicable_sequence[i + 1]; + if (tempADKD == "FLX") { - flxTags.push_back(i); // C: just need to save the index in the sequence + flxTags.push_back(i); // C: just need to save the index in the sequence } - else if(mack.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i+1])) + else if (mack.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i + 1])) { - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: ADKD mismatch against MAC Look-up table. " << std::endl; - return false; // C: suffices one incorrect to abort and not process the rest of the tags + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: ADKD mismatch against MAC Look-up table."; + return false; // C: suffices one incorrect to abort and not process the rest of the tags } } - if(flxTags.empty()){ - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: ADKD matches MAC Look-up table. " << std::endl; + if (flxTags.empty()) + { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: ADKD matches MAC Look-up table."; return true; } // Fixed as well as FLX Tags share first part - Eq. 22 ICD - std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes - m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag - m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); // TODO d_GST_Sf left useless + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag + m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); // TODO d_GST_Sf left useless m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); m[4] = static_cast(d_GST_Sf & 0x000000FF); // Case tags flexible - Eq. 21 ICD - for (uint8_t i = 0; i < flxTags.size() ; i++) + for (uint8_t i = 0; i < flxTags.size(); i++) { - m[2*i + 5] = mack.tag_and_info[flxTags[i]].tag_info.PRN_d; - m[2*i + 6] = mack.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | + m[2 * i + 5] = mack.tag_and_info[flxTags[i]].tag_info.PRN_d; + m[2 * i + 6] = mack.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | mack.tag_and_info[flxTags[i]].tag_info.cop; } // compute mac std::vector mac; - if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); } - else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { mac = d_crypto->computeCMAC_AES(applicable_key, m); } @@ -1432,39 +1464,51 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) mac_msb = (mac[0] << 8) + mac[1]; } uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; - if (computed_macseq == mack.header.macseq){ - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK " << std::endl; + if (computed_macseq == mack.header.macseq) + { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK"; return true; } - else{ - LOG(ERROR) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: FLX tags verification failed " << std::endl; + else + { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: FLX tags verification failed"; return false; } - } + + bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) { auto prn_it = d_satellite_nav_data.find(t.PRN_d); - if (prn_it != d_satellite_nav_data.end()) { + if (prn_it != d_satellite_nav_data.end()) + { // PRN was found, check if TOW exists in inner map LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; std::map& tow_map = prn_it->second; auto tow_it = tow_map.find(t.TOW - 30); - if (tow_it != tow_map.end()) { + if (tow_it != tow_map.end()) + { return true; - } else { + } + else + { // TOW not found return false; } - } else { + } + else + { // PRN was not found LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; return false; } return false; } -bool osnma_msg_receiver::tag_has_key_available(Tag& t){ + + +bool osnma_msg_receiver::tag_has_key_available(Tag& t) +{ // check adkd of tag // if adkd = 0 or 4 => look for d_tesla_keys[t.TOW+30] // if adkd = 12 => look for d_tesla_keys[t.TOW+300] @@ -1484,36 +1528,38 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t){ auto it = d_tesla_keys.find(t.TOW + 330); if (it != d_tesla_keys.end()) { - LOG(INFO)<< "Galileo OSNMA: hasKey = true " << std::endl; + LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; return true; } } LOG(INFO) << "Galileo OSNMA: hasKey = false "; return false; } + + std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes) { auto start = std::chrono::high_resolution_clock::now(); std::vector K_II = key; - std::vector K_I; // result of the recursive hash operations + std::vector K_I; // result of the recursive hash operations std::vector msg; // compute the tesla key for current SF (GST_SFi and K_II change in each iteration) - for (uint32_t i = 1; i <= num_of_hashes_needed ; i++) + for (uint32_t i = 1; i <= num_of_hashes_needed; i++) { // build message digest m = (K_I+1 || GST_SFi || alpha) msg.reserve(K_II.size() + sizeof(GST_SFi) + sizeof(d_osnma_data.d_dsm_kroot_message.alpha)); - std::copy(K_II.begin(),K_II.end(),std::back_inserter(msg)); + std::copy(K_II.begin(), K_II.end(), std::back_inserter(msg)); msg.push_back((GST_SFi & 0xFF000000) >> 24); msg.push_back((GST_SFi & 0x00FF0000) >> 16); msg.push_back((GST_SFi & 0x0000FF00) >> 8); msg.push_back(GST_SFi & 0x000000FF); - // extract alpha -// d_osnma_data.d_dsm_kroot_message.alpha = 0xa06221261ad9; - for (int k = 5; k >= 0;k--) + // extract alpha + // d_osnma_data.d_dsm_kroot_message.alpha = 0xa06221261ad9; + for (int k = 5; k >= 0; k--) { // TODO: static extracts the MSB in case from larger to shorter int? - msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (k * 8)) & 0xFF)); // extract first 6 bytes of alpha. + msg.push_back(static_cast((d_osnma_data.d_dsm_kroot_message.alpha >> (k * 8)) & 0xFF)); // extract first 6 bytes of alpha. } // compute hash std::vector hash; @@ -1530,31 +1576,31 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede hash = std::vector(32); } // truncate hash - K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits + K_I.reserve(lk_bytes); // TODO - case hash function has 512 bits for (int k = 0; k < lk_bytes; k++) { K_I.push_back(hash[k]); } // set parameters for next iteration - GST_SFi -= 30; // next SF time is the actual minus 30 seconds - K_II = K_I; // next key is the actual one - K_I.clear(); // empty the actual one for a new computation + GST_SFi -= 30; // next SF time is the actual minus 30 seconds + K_II = K_I; // next key is the actual one + K_I.clear(); // empty the actual one for a new computation msg.clear(); } // check that the final time matches the Kroot time bool check; - if(!d_tesla_key_verified) + if (!d_tesla_key_verified) check = GST_SFi + 30 == d_GST_0 - 30; else check = GST_SFi + 30 == d_last_verified_key_GST; - if(!check) - LOG(ERROR) << "Galileo OSNMA: TESLA verification error. Kroot time mismatch! \n"; // ICD. Eq. 18 + if (!check) + LOG(WARNING) << "Galileo OSNMA: TESLA verification error. Kroot time mismatch!"; // ICD. Eq. 18 else - LOG(INFO) << "Galileo OSNMA: TESLA verification. Kroot time matches! \n"; // ICD. Eq. 18 + LOG(INFO) << "Galileo OSNMA: TESLA verification. Kroot time matches!"; // ICD. Eq. 18 // compare computed current key against received key auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = end - start; - LOG(INFO) << "Galileo OSNMA: TESLA verification ("<< num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds.\n"; + LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; return K_II; } diff --git a/src/core/system_parameters/osnma_dsm_reader.h b/src/core/system_parameters/osnma_dsm_reader.h index 3eeeb5bea..5031a140e 100644 --- a/src/core/system_parameters/osnma_dsm_reader.h +++ b/src/core/system_parameters/osnma_dsm_reader.h @@ -63,7 +63,6 @@ public: uint8_t get_npktid(const std::vector& dsm_msg) const; private: -#if __cplusplus == 201103L static constexpr std::uint8_t mask_nmas{0xC0}; static constexpr std::uint8_t mask_cid{0x30}; static constexpr std::uint8_t mask_cpks{0x07}; @@ -83,27 +82,6 @@ private: static constexpr std::uint8_t mask_dsm_mid{0x0F}; static constexpr std::uint8_t mask_dsm_npkt{0xF0}; static constexpr std::uint8_t mask_dsm_npktid{0x0F}; -#else - static constexpr std::uint8_t mask_nmas{0b1100'0000}; - static constexpr std::uint8_t mask_cid{0b0011'0000}; - static constexpr std::uint8_t mask_cpks{0b0000'1110}; - static constexpr std::uint8_t mask_nma_header_reserved{0b0000'0001}; - static constexpr std::uint8_t mask_dsm_id{0b1111'0000}; - static constexpr std::uint8_t mask_dsm_block_id{0b0000'1111}; - static constexpr std::uint8_t mask_dsm_number_blocks{0b1111'0000}; - static constexpr std::uint8_t mask_dsm_pkid{0b0000'1111}; - static constexpr std::uint8_t mask_dsm_cidkr{0b1100'0000}; - static constexpr std::uint8_t mask_dsm_reserved1{0b0011'0000}; - static constexpr std::uint8_t mask_dsm_hf{0b0000'1100}; - static constexpr std::uint8_t mask_dsm_mf{0b0000'0011}; - static constexpr std::uint8_t mask_dsm_ks{0b1111'0000}; - static constexpr std::uint8_t mask_dsm_ts{0b0000'1111}; - static constexpr std::uint8_t mask_dsm_reserved{0b1111'0000}; - static constexpr std::uint8_t mask_dsm_wk_k_msbyte{0b0000'1111}; - static constexpr std::uint8_t mask_dsm_mid{0b0000'1111}; - static constexpr std::uint8_t mask_dsm_npkt{0b1111'0000}; - static constexpr std::uint8_t mask_dsm_npktid{0b0000'1111}; -#endif }; /** \} */ From 23bb5c85c581ca663acf736196686c925f3802cf Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 25 Jun 2024 11:45:09 +0200 Subject: [PATCH 137/219] Fix building against OpenSSL 1.0 --- src/core/system_parameters/gnss_crypto.cc | 99 ++++++++++++++++++----- src/core/system_parameters/gnss_crypto.h | 3 +- 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 947b8a436..9f2ba82fb 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -380,24 +380,16 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector hmac.resize(output_length); output = hmac; #else - std::vector hmac(32); - // Create HMAC context - HMAC_CTX* ctx = HMAC_CTX_new(); - HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr); + unsigned int outputLength = EVP_MAX_MD_SIZE; + unsigned char* result = HMAC(EVP_sha256(), key.data(), key.size(), input.data(), input.size(), output.data(), &outputLength); + if (result == nullptr) + { + LOG(WARNING) << "OSNMA HMAC_SHA_256 computation failed to compute HMAC-SHA256"; + return output; + } - // Update HMAC context with the message - HMAC_Update(ctx, input.data(), input.size()); - - // Finalize HMAC computation - unsigned int hmacLen; - HMAC_Final(ctx, hmac.data(), &hmacLen); - - // Clean up HMAC context - HMAC_CTX_free(ctx); - - // Resize the HMAC vector to the actual length - hmac.resize(hmacLen); - output = hmac; + // Resize the output vector to the actual length of the HMAC-SHA256 output + output.resize(outputLength); #endif #else // GnuTLS std::vector output_aux(32); @@ -595,6 +587,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) // Read the public key from the certificate EVP_PKEY* pubkey = X509_get_pubkey(cert); +#if USE_OPENSSL_3 if (!pubkey) { std::cerr << "Failed to extract the public key" << std::endl; @@ -603,6 +596,18 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) } pubkey_copy(pubkey, &d_PublicKey); EVP_PKEY_free(pubkey); +#else + EC_KEY* ec_pubkey = EVP_PKEY_get1_EC_KEY(pubkey); + EVP_PKEY_free(pubkey); + if (!ec_pubkey) + { + std::cerr << "Failed to extract the public key" << std::endl; + X509_free(cert); + return false; + } + pubkey_copy(ec_pubkey, &d_PublicKey); + EC_KEY_free(ec_pubkey); +#endif BIO_free(bio); X509_free(cert); #else // GnuTLS @@ -838,12 +843,19 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) LOG(INFO) << "OpenSSL: error setting the OSNMA public key."; return; } - +#if USE_OPENSSL_3 if (!pubkey_copy(pkey, &d_PublicKey)) { return; } - +#else + EC_KEY* ec_pkey = EVP_PKEY_get1_EC_KEY(pkey); + if (!pubkey_copy(ec_pkey, &d_PublicKey)) + { + return; + } + EC_KEY_free(ec_pkey); +#endif EVP_PKEY_free(pkey); #else // GnuTLS gnutls_pubkey_t pubkey; @@ -865,6 +877,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) #if USE_OPENSSL_FALLBACK +#if USE_OPENSSL_3 bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) { // Open a memory buffer @@ -909,6 +922,54 @@ bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) return true; } +#else // OpenSSL 1.x + +bool Gnss_Crypto::pubkey_copy(EC_KEY* src, EC_KEY** dest) +{ + // Open a memory buffer + BIO* mem_bio = BIO_new(BIO_s_mem()); + if (mem_bio == nullptr) + { + return false; + } + + // Export the public key from src into the memory buffer in PEM format + if (!PEM_write_bio_EC_PUBKEY(mem_bio, src)) + { + BIO_free(mem_bio); + return false; + } + + // Read the data from the memory buffer + char* bio_data; + long data_len = BIO_get_mem_data(mem_bio, &bio_data); + + // Create a new memory buffer and load the data into it + BIO* mem_bio2 = BIO_new_mem_buf(bio_data, data_len); + if (mem_bio2 == nullptr) + { + BIO_free(mem_bio); + return false; + } + + // Read the public key from the new memory buffer + *dest = PEM_read_bio_EC_PUBKEY(mem_bio2, nullptr, nullptr, nullptr); + if (*dest == nullptr) + { + BIO_free(mem_bio); + BIO_free(mem_bio2); + return false; + } + + // Clean up + BIO_free(mem_bio); + BIO_free(mem_bio2); + + return true; +} + +#endif + #else // GnuTLS-specific functions bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 9d60c8a77..dae62bf88 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -61,11 +61,12 @@ private: std::vector convert_from_hex_str(const std::string& input) const; #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 + bool pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest); EVP_PKEY* d_PublicKey{}; #else + bool pubkey_copy(EC_KEY* src, EC_KEY** dest); EC_KEY* d_PublicKey = nullptr; #endif - bool pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest); #else // GnuTLS gnutls_pubkey_t d_PublicKey{}; bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; From cae618b450d08221fdbbd07a2f3ac5fa63e08829 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 25 Jun 2024 12:42:07 +0200 Subject: [PATCH 138/219] Fix ECDSA signature verification when linking againts OpenSSL 1.0 --- src/core/system_parameters/gnss_crypto.cc | 115 ++++++++++++---------- src/core/system_parameters/gnss_crypto.h | 6 +- 2 files changed, 66 insertions(+), 55 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 9f2ba82fb..5adab48b3 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -305,7 +305,11 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in EVP_DigestFinal_ex(mdctx, output.data(), nullptr); EVP_MD_CTX_free(mdctx); #else - // SHA3-256 not implemented in OpenSSL < 3.0 + // SHA3-256 not implemented in OpenSSL 1.0, it was introduced in OpenSSL 1.1.1 + if (!input.empty()) + { + // TODO + } #endif #else // GnuTLS std::vector output_aux(32); @@ -384,8 +388,8 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector unsigned char* result = HMAC(EVP_sha256(), key.data(), key.size(), input.data(), input.size(), output.data(), &outputLength); if (result == nullptr) { - LOG(WARNING) << "OSNMA HMAC_SHA_256 computation failed to compute HMAC-SHA256"; - return output; + LOG(WARNING) << "OSNMA HMAC_SHA_256 computation failed to compute HMAC-SHA256"; + return output; } // Resize the output vector to the actual length of the HMAC-SHA256 output @@ -740,7 +744,13 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st LOG(WARNING) << "OpenSSL: OSNMA message authentication failed: " << err; } #else - int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, signature.data(), static_cast(signature.size()), d_PublicKey); + std::vector der_sig; + if (!convert_raw_to_der_ecdsa(signature, der_sig)) + { + std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; + return false; + } + int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, der_sig.data(), static_cast(der_sig.size()), d_PublicKey); if (verification == 1) { success = true; @@ -749,6 +759,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st else if (verification == 0) { std::cerr << "OpenSSL: invalid signature found when verifying message" << std::endl; + LOG(WARNING) << "OpenSSL: invalid signature found when verifying message"; } else { @@ -876,6 +887,54 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) } +bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const +{ + if (raw_signature.size() % 2 != 0) + { + std::cerr << "Invalid raw ECDSA signature size" << std::endl; + return false; + } + + size_t half_size = raw_signature.size() / 2; + std::vector raw_r(raw_signature.begin(), raw_signature.begin() + half_size); + std::vector raw_s(raw_signature.begin() + half_size, raw_signature.end()); + + auto encode_asn1_integer = [](const std::vector& value) -> std::vector { + std::vector result; + result.push_back(0x02); // INTEGER tag + + if (value[0] & 0x80) + { + result.push_back(value.size() + 1); // Length byte + result.push_back(0x00); // Add leading zero byte to ensure positive integer + } + else + { + result.push_back(value.size()); // Length byte + } + + result.insert(result.end(), value.begin(), value.end()); + return result; + }; + + std::vector der_r = encode_asn1_integer(raw_r); + std::vector der_s = encode_asn1_integer(raw_s); + + size_t total_length = der_r.size() + der_s.size(); + der_signature.push_back(0x30); // SEQUENCE tag + if (total_length > 127) + { + der_signature.push_back(0x81); // Long form length + } + der_signature.push_back(static_cast(total_length)); + + der_signature.insert(der_signature.end(), der_r.begin(), der_r.end()); + der_signature.insert(der_signature.end(), der_s.begin(), der_s.end()); + + return true; +} + + #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) @@ -972,54 +1031,6 @@ bool Gnss_Crypto::pubkey_copy(EC_KEY* src, EC_KEY** dest) #else // GnuTLS-specific functions -bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const -{ - if (raw_signature.size() % 2 != 0) - { - std::cerr << "Invalid raw ECDSA signature size" << std::endl; - return false; - } - - size_t half_size = raw_signature.size() / 2; - std::vector raw_r(raw_signature.begin(), raw_signature.begin() + half_size); - std::vector raw_s(raw_signature.begin() + half_size, raw_signature.end()); - - auto encode_asn1_integer = [](const std::vector& value) -> std::vector { - std::vector result; - result.push_back(0x02); // INTEGER tag - - if (value[0] & 0x80) - { - result.push_back(value.size() + 1); // Length byte - result.push_back(0x00); // Add leading zero byte to ensure positive integer - } - else - { - result.push_back(value.size()); // Length byte - } - - result.insert(result.end(), value.begin(), value.end()); - return result; - }; - - std::vector der_r = encode_asn1_integer(raw_r); - std::vector der_s = encode_asn1_integer(raw_s); - - size_t total_length = der_r.size() + der_s.size(); - der_signature.push_back(0x30); // SEQUENCE tag - if (total_length > 127) - { - der_signature.push_back(0x81); // Long form length - } - der_signature.push_back(static_cast(total_length)); - - der_signature.insert(der_signature.end(), der_r.begin(), der_r.end()); - der_signature.insert(der_signature.end(), der_s.begin(), der_s.end()); - - return true; -} - - bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) { gnutls_datum_t key_datum; diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index dae62bf88..bbcac1afa 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -58,19 +58,19 @@ private: void read_merkle_xml(const std::string& merkleFilePath); void readPublicKeyFromPEM(const std::string& pemFilePath); bool readPublicKeyFromCRT(const std::string& crtFilePath); + bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; std::vector convert_from_hex_str(const std::string& input) const; #if USE_OPENSSL_FALLBACK #if USE_OPENSSL_3 bool pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest); EVP_PKEY* d_PublicKey{}; -#else +#else // OpenSSL 1.x bool pubkey_copy(EC_KEY* src, EC_KEY** dest); EC_KEY* d_PublicKey = nullptr; #endif #else // GnuTLS - gnutls_pubkey_t d_PublicKey{}; - bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; bool pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest); + gnutls_pubkey_t d_PublicKey{}; #endif std::vector d_x_4_0; std::vector d_x_3_1; From 2c833051a5a2969d677063a6cf30108889c65ca3 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 25 Jun 2024 13:59:23 +0200 Subject: [PATCH 139/219] Fix SHA3-256 implementation when linking against OpenSSL 1.1.1 --- src/core/system_parameters/CMakeLists.txt | 4 ++++ src/core/system_parameters/gnss_crypto.cc | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 607c3702a..0ef4cf22e 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -163,6 +163,10 @@ if(OPENSSL_FOUND) target_compile_definitions(core_system_parameters PUBLIC -DUSE_OPENSSL_FALLBACK=1 -DUSE_OPENSSL_3=1) message("USE_OPENSSL_3: " ${DUSE_OPENSSL_3}) message("USE_OPENSSL_FALLBACK:" ${USE_OPENSSL_FALLBACK}) + else() + if(NOT OPENSSL_VERSION VERSION_LESS "1.1.1") + target_compile_definitions(core_system_parameters PRIVATE -DUSE_OPENSSL_FALLBACK=1 -DUSE_OPENSSL_111=1) + endif() endif() endif() diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 5adab48b3..0f1774271 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -60,6 +60,11 @@ Gnss_Crypto::Gnss_Crypto() { #if USE_OPENSSL_FALLBACK +#if !(USE_OPENSSL_3 || USE_OPENSSL_111) + LOG(WARNING) << "The OpenSSL library version you are linking against is too old for some OSNMA functions." + << " Please do not trust OSNMA ouputs or upgrade your system to a newer version of OpenSSL" + << " and rebuild GNSS-SDR against it."; +#endif #else // GnuTLS gnutls_global_init(); #endif @@ -69,6 +74,11 @@ Gnss_Crypto::Gnss_Crypto() Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath) { #if USE_OPENSSL_FALLBACK +#if !(USE_OPENSSL_3 || USE_OPENSSL_111) + LOG(WARNING) << "The OpenSSL library version you are linking against is too old for some OSNMA functions." + << " Please do not trust OSNMA ouputs or upgrade your system to a newer version of OpenSSL" + << " and rebuild GNSS-SDR against it."; +#endif #else // GnuTLS gnutls_global_init(); #endif @@ -296,7 +306,7 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in { std::vector output(32); // SHA256 hash size #if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 +#if USE_OPENSSL_3 || USE_OPENSSL_111 EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); const EVP_MD* md = EVP_sha3_256(); @@ -308,7 +318,7 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in // SHA3-256 not implemented in OpenSSL 1.0, it was introduced in OpenSSL 1.1.1 if (!input.empty()) { - // TODO + // do nothing } #endif #else // GnuTLS From 1d815f0bbf1ab797857a997b59764621dfdf25c2 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Wed, 26 Jun 2024 15:01:05 +0200 Subject: [PATCH 140/219] [TAS-227] [BUG] Tag verification fails for .dat files (WIP) WIP --- .../galileo_telemetry_decoder_gs.cc | 56 +- src/core/libs/osnma_msg_receiver.cc | 78 ++- src/core/libs/osnma_msg_receiver.h | 2 +- .../system_parameters/galileo_inav_message.cc | 2 +- src/core/system_parameters/osnma_helper.cc | 11 + src/core/system_parameters/osnma_helper.h | 1 + .../osnma/osnma_msg_receiver_test.cc | 513 ++++++++++-------- 7 files changed, 369 insertions(+), 294 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index a404a100a..3b3d4b06a 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -439,6 +439,35 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } // 4. Push the new navigation data to the queues + // extract OSNMA bits, reset container. + bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; + if(check_size_is_ok) + { + std::cout << "Galileo OSNMA: new ADKD=0/12 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW5() - 25 <>( // < PRNd , navDataBits, TOW_Sosf> + d_satellite.get_PRN(), + d_inav_nav.get_osnma_adkd_0_12_nav_bits(), + d_inav_nav.get_TOW5() - 25); + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW5() - 25) <<")";//: 0b" << d_inav_nav.get_osnma_adkd_0_12_nav_bits(); + d_inav_nav.reset_osnma_nav_bits_adkd0_12(); + } + + check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; + if(check_size_is_ok) + { + std::cout << "Galileo OSNMA: new ADKD=4 navData from " << d_satellite <<" at TOW_sf=" << d_inav_nav.get_TOW6() - 5 <>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe + d_satellite.get_PRN(), + d_inav_nav.get_osnma_adkd_4_nav_bits(), + d_inav_nav.get_TOW6() - 5); + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW6() - 5) <<")";//: 0b" << d_inav_nav.get_osnma_adkd_4_nav_bits(); + d_inav_nav.reset_osnma_nav_bits_adkd4(); + } + + if (d_inav_nav.have_new_ephemeris() == true) // C: tells if W1-->W4 available from same blcok (and W5!) { // get object for this SV (mandatory) @@ -472,20 +501,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_first_eph_sent = true; // do not send reduced CED anymore, since we have the full ephemeris set // d_flag_osnma_adkd_0_12 = true; // W1-> W5 available - // extract bits, reset container. - bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; - if(check_size_is_ok) - { - std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << d_satellite.get_PRN() << ") " << "TOW_sf=" << d_inav_nav.get_TOW5() - 24 <>( // < PRNd , navDataBits, TOW_Sosf> - d_satellite.get_PRN(), - d_inav_nav.get_osnma_adkd_0_12_nav_bits(), - d_inav_nav.get_TOW5() - 24); - this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); - d_inav_nav.reset_osnma_nav_bits_adkd0_12(); - } - - } else { @@ -615,19 +630,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in // bool adkd_4_nav_data_available = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; // newApproach: let decoder decide when block starts and let it fill the data, and just check for length if(adkd_4_nav_data_available /*&& d_inav_nav.is_TOW5_set() not needed cause W6 has TOW also.*/) { - bool check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; - if(check_size_is_ok) - { - std::cout << "Galileo OSNMA: sending ADKD=4 navData, PRN_d (" << d_satellite.get_PRN() << ") " << "TOW_sf=" << d_inav_nav.get_TOW6() - 4 <>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe - d_satellite.get_PRN(), - d_inav_nav.get_osnma_adkd_4_nav_bits(), - d_inav_nav.get_TOW6() - 4); - this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - d_inav_nav.reset_osnma_nav_bits_adkd4(); - } - } auto newOSNMA = d_inav_nav.have_new_nma(); if (d_band == '1' && newOSNMA) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 4a5e95ac9..45ad958ee 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -62,13 +62,13 @@ osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, osnma_msg_receiver::osnma_msg_receiver( - const std::string& pemFilePath, + 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)) { d_dsm_reader = std::make_unique(); - d_crypto = std::make_unique(pemFilePath, merkleFilePath); + d_crypto = std::make_unique(crtFilePath, merkleFilePath); d_helper = std::make_unique(); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); @@ -101,13 +101,13 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); // TODO remove if unneeded std::ostringstream output_message; - output_message << "Galileo OSNMA: Subframe received starting at " - << "WN=" - << nma_msg->WN_sf0 - << ", TOW=" - << nma_msg->TOW_sf0 - << ", from satellite " - << sat; + output_message << "Galileo OSNMA: complete OSNMA message received starting at " + << "WN=" + << nma_msg->WN_sf0 + << ", TOW=" + << nma_msg->TOW_sf0 + << ", from satellite " + << sat; LOG(WARNING) << output_message.str(); std::cout << output_message.str() << std::endl; @@ -125,14 +125,14 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // iono data => 549 bits, utc data, 141 bits. if (nav_data.size() == 549) { - LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " - << "TOW_sf=" << TOW; +// LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " +// << "TOW_sf=" << TOW; d_satellite_nav_data[PRNa][TOW].ephemeris_iono_vector_2 = nav_data; } else if (nav_data.size() == 141) { - LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " - << "TOW_sf=" << TOW; +// LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " +// << "TOW_sf=" << TOW; d_satellite_nav_data[PRNa][TOW].utc_vector_2 = nav_data; } else @@ -322,8 +322,8 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; // TODO set flag to false to avoid processing dsm and MACK messages @@ -914,13 +914,25 @@ void osnma_msg_receiver::process_mack_message() bool ret = verify_macseq(*mack); if (ret || d_flag_debug) { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; for (std::size_t i = 0; i < mack->tag_and_info.size(); ++i) { // add tags of current mack to the verification queue auto& tag = mack->tag_and_info[i]; Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; + LOG(INFO) << "Galileo OSNMA: Add Tag Id= " + << t.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << t.received_tag << std::dec + << ", TOW=" + << t.TOW + << ", ADKD=" + << static_cast(t.ADKD) + << ", PRNa=" + << static_cast(t.PRNa) + << ", PRNd=" + << static_cast(t.PRN_d); } std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; mack = d_macks_awaiting_MACSEQ_verification.erase(mack); @@ -1070,6 +1082,11 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) bool osnma_msg_receiver::verify_tag(Tag& tag) { + // Debug + LOG(INFO) << "Galileo OSNMA: Tag verification :: Start for tag Id= " + << tag.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << tag.received_tag << std::dec; // TODO case tag0, to be verified here?, PRNd not needed for it // build message std::vector m = build_message(tag); @@ -1077,9 +1094,16 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) std::vector mac; std::vector applicable_key; if (tag.ADKD == 0 || tag.ADKD == 4) - applicable_key = d_tesla_keys[tag.TOW + 30]; - else // ADKD 12 - applicable_key = d_tesla_keys[tag.TOW + 330]; + { + applicable_key = d_tesla_keys[tag.TOW + 30]; + LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 30); + } + else // ADKD 12 + { + applicable_key = d_tesla_keys[tag.TOW + 330]; + LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 330); + } + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { @@ -1142,7 +1166,7 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) << ", PRNa=" << static_cast(tag.PRNa) << ", PRNd=" - << static_cast(tag.PRN_d); + << static_cast(tag.PRN_d) << std::endl; return true; } return false; @@ -1171,10 +1195,12 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) if (tag.ADKD == 0 || tag.ADKD == 12) // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. { applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; + LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else if (tag.ADKD == 4) { applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].utc_vector_2; + LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else LOG(WARNING) << "Galileo OSNMA :: Tag verification :: unknown ADKD"; @@ -1484,7 +1510,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) if (prn_it != d_satellite_nav_data.end()) { // PRN was found, check if TOW exists in inner map - LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; + //LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; std::map& tow_map = prn_it->second; auto tow_it = tow_map.find(t.TOW - 30); if (tow_it != tow_map.end()) @@ -1500,7 +1526,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) else { // PRN was not found - LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; + //LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; return false; } return false; @@ -1519,7 +1545,7 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t) auto it = d_tesla_keys.find(t.TOW + 30); if (it != d_tesla_keys.end()) { - LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; + //LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; return true; } } @@ -1528,11 +1554,11 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t) auto it = d_tesla_keys.find(t.TOW + 330); if (it != d_tesla_keys.end()) { - LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; + //LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; return true; } } - LOG(INFO) << "Galileo OSNMA: hasKey = false "; + //LOG(INFO) << "Galileo OSNMA: hasKey = false "; return false; } @@ -1601,6 +1627,6 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede // compare computed current key against received key auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = end - start; - LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; +// LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; return K_II; } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 4e662ef55..aef9fd91e 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -59,7 +59,7 @@ public: ~osnma_msg_receiver() = default; //!< Default destructor private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); - osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); + osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index baa140149..a8509db23 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1417,7 +1417,7 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() nma_position_filled = std::array{}; // Fill TOW and WN nma_msg.WN_sf0 = WN_0; - int32_t TOW_sf0 = TOW_5 - 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start + int32_t TOW_sf0 = TOW_5 - 25;//- 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start TODO review if (TOW_sf0 < 0) { TOW_sf0 += 604800; diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index aa338f408..7cf3165c2 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -16,6 +16,8 @@ #include "osnma_helper.h" #include +#include +#include uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const { @@ -74,3 +76,12 @@ std::string Osnma_Helper::verification_status_str(int status) default: return "UNKNOWN"; } } +std::string Osnma_Helper::convert_to_hex_string(const std::vector& vector) +{ + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for (auto byte : vector) { + ss << std::setw(2) << static_cast(byte); + } + return ss.str(); +} diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 2f8df078b..e78fdba0f 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -30,6 +30,7 @@ public: std::vector gst_to_uint8(uint32_t GST) const; std::vector bytes(const std::string& binaryString); std::string verification_status_str(int status); + std::string convert_to_hex_string(const std::vector& vector); }; #endif // GNSS_SDR_OSNMA_HELPER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 35cb9fd45..7b94baf0c 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -14,42 +15,39 @@ struct TestVector }; // TODO - parametrize class for different configurations (config_1, config_2, etc.. potentially 5 or 6 more) an make sure wont affect current TEST_F +// note: until the test is parametrized for configuration 1 and 2, in order to change between them you have to comment/uncomment the respective calls in this test, identified with comments // conf. 1/2 +// log_name, input_time, crtFilePath, merkleFilePath, testVectors class OsnmaMsgReceiverTest : public ::testing::Test { protected: osnma_msg_receiver_sptr osnma; - Galileo_Inav_Message galileo_message; - uint8_t page_position_in_inav_subframe; - bool flag_CRC_test; - std::string page_even; OSNMA_msg osnma_msg{}; std::array nma_position_filled; - uint32_t d_GST_SIS{}; // 16 AUG 2023 05 00 01 + uint32_t d_GST_SIS{}; uint32_t TOW{}; uint32_t WN{}; - std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm - const uint32_t LEAP_SECONDS = 0; // 13 + 5; + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm + const uint32_t LEAP_SECONDS = 0; //13 + 5; void set_time(std::tm& input); - // std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; - std::string log_name{"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; - // void initializeGoogleLog(); +// std::string log_name {"CONFIG1-2023-08-16-PKID1-OSNMA"}; + std::string log_name {"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; + void initializeGoogleLog(); void SetUp() override { - flag_CRC_test = false; // TODO what for? - page_even = ""; - - // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; - std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; + initializeGoogleLog(); +// std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 set_time(input_time); - // std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; - // std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; - std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.pem"; +// std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.crt"; // conf. 1 +// std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; + std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; - osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); + osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); } public: + static std::vector parseNavBits(const std::string& hex); static std::vector readTestVectorsFromFile(const std::string& filename); std::string bytes_to_str(const std::vector& bytes); @@ -57,85 +55,199 @@ public: }; -TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) +TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) { + // Arrange + // ---------- + // m0 + std::vector expected_message = { + 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, + 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, + 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, + 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, + 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00 + }; + + uint32_t TOW_Tag0 = 345660; + uint32_t TOW_NavData = TOW_Tag0 - 30; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t WN = 1248; + uint32_t PRNa = 2; + uint8_t CTR = 1; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MACK_tag_and_info MTI; + MTI.tag = static_cast(0xE37BC4F858); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x00; + MTI.tag_info.cop = 0x0F; + Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + + + + // Act + // ---------- + auto computed_message = osnma->build_message(t0); + + + // Assert + // ---------- + ASSERT_TRUE(computed_message == expected_message); + +} + +TEST_F(OsnmaMsgReceiverTest, TagVerification) { + // Arrange + // ---------- + // Tag0 + uint32_t TOW_Tag0 = 345660; + uint32_t TOW_NavData = TOW_Tag0 - 30; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t WN = 1248; + uint32_t PRNa = 2; + uint8_t CTR = 1; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MACK_tag_and_info MTI; + MTI.tag = static_cast(0xE37BC4F858); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x00; + MTI.tag_info.cop = 0x0F; + Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + + + + // Act + // ---------- + bool result_tag0 = osnma->verify_tag(t0); + + + + + + // Assert + // ---------- + //ASSERT_TRUE(result_tag0); + + // Tag3 + uint32_t TOW_Tag3 = 345660; + uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; + uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30 ; + WN = 1248; + PRNa = 2; + CTR = 3; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].utc_vector_2 = + "111111111111111111111111111111110000000000000000000000010001001001001000" + "111000001000100111100010010111111111011110111111111001001100000100000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MTI.tag = static_cast(0x7BB238C883); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x04; + MTI.tag_info.cop = 0x0F; + Tag t3(MTI, TOW_Tag0, WN, PRNa, CTR); + + bool result_tag3 = osnma->verify_tag(t3); + + ASSERT_TRUE(result_tag0 && result_tag3); + +} + +TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Arrange // ---------- osnma->d_tesla_key_verified = false; - osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 - osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits + osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 + osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; // local_time_verification would do this operation. TODO - eliminate duplication. osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); - osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) - osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; + osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; - osnma->d_tesla_keys.insert((std::pair>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. - std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 + osnma->d_tesla_keys.insert((std::pair>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. + std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 uint32_t TOW = 345630; + + + // Act // ---------- bool result = osnma->verify_tesla_key(key, TOW); + + + + // Assert // ---------- ASSERT_TRUE(result); -} +} TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) { - // initializeGoogleLog(); // Arrange // ---------- - // std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); - std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); - if (testVectors.empty()) - { +// std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); // conf. 1 + std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 + if (testVectors.empty()){ ASSERT_TRUE(false); } bool end_of_hex_stream{false}; int offset_byte{0}; - int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size - const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page - const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe - const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES * SIZE_SUBFRAME_PAGES}; // total bytes of a subframe - const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds + int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size + const int SIZE_PAGE_BYTES{240/8}; // total bytes of a page + const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe + const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; // total bytes of a subframe + const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds const int DUMMY_PAGE{63}; bool flag_dummy_page{false}; - std::cout << "OsnmaTestVectorsSimulation:" - << " d_GST_SIS= " << d_GST_SIS - << ", TOW=" << TOW - << ", WN=" << WN << std::endl; + std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; + + + // Act // ---------- // loop over all bytes of data. Note: all TestVectors have same amount of data. - while (end_of_hex_stream == false) - { + while (end_of_hex_stream == false){ // loop over all SVs, extract a subframe - for (const TestVector& tv : testVectors) - { // loop over all SVs, extract a subframe - std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; + for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe + std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) "<< tv.svId << std::endl; auto osnmaMsg_sptr = std::make_shared(); std::array hkroot{}; std::array mack{}; - byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) - std::map> words; // structure containing and + byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) + std::map> words_for_OSNMA; // structure containing and - for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe + for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe { // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index - std::vector page_bytes = extract_page_bytes(tv, byte_index, SIZE_PAGE_BYTES); - if (page_bytes.empty()) - { - std::cout << "OsnmaTestVectorsSimulation: end of TestVectors \n" - << "byte_index=" << byte_index << " expected= " << 432000 / 8 << std::endl; + std::vector page_bytes = extract_page_bytes(tv,byte_index,SIZE_PAGE_BYTES); + if(page_bytes.empty()){ + std::cout<< "OsnmaTestVectorsSimulation: end of TestVectors \n" << "byte_index="< data_k(even_page.substr(2, 112)); - std::bitset<16> data_j(odd_page.substr(2, 16)); + std::bitset<112> data_k(even_page.substr(2,112)); + std::bitset<16> data_j(odd_page.substr(2,16)); std::bitset<112> shifted_data_k = data_k; - // uint8_t word_type = 0; - // for(int i = 0; i < 6; ++i) { - // word_type |= (data_k[104 + i] << i); - // } - uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word - std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast(word_type) << std::endl; - if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) + uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word + std::cout<< "OsnmaTestVectorsSimulation: received Word "<< static_cast(word_type) << std::endl; + if( (word_type >= 1 && word_type <=5) || word_type == 6 || word_type == 10) { // store raw word std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); - words[word_type] = data_combined; + words_for_OSNMA[word_type] = data_combined; } - if (word_type == DUMMY_PAGE) + if(word_type == DUMMY_PAGE) flag_dummy_page = true; + // place it into osnma object. std::bitset<40> osnmaBits(odd_page.substr(18, 40)); + // Extract bits for hkroot and mack std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8)); std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32)); @@ -183,13 +291,12 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) byte_index += SIZE_PAGE_BYTES; } - std::cout << "----------" << std::endl; - if (end_of_hex_stream) + std::cout<< "----------" << std::endl; + if(end_of_hex_stream) break; - if (flag_dummy_page) - { + if(flag_dummy_page){ flag_dummy_page = false; - continue; // skip this SV + continue; // skip this SV } // Fill osnma object @@ -197,26 +304,26 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) osnmaMsg_sptr->mack = mack; osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; - osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20; - osnmaMsg_sptr->PRN = tv.svId; // PRNa + osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ; + osnmaMsg_sptr->PRN = tv.svId; // PRNa // TODO - refactor this logic, currently it is split - // check if words 1--> 5 words are received => fill EphClockStatus data vector + // check if words_for_OSNMA 1--> 5 words_for_OSNMA are received => fill EphClockStatus data vector bool ephClockStatusWordsReceived = true; for (int i = 1; i <= 5; ++i) { - if (words.find(i) == words.end()) + if (words_for_OSNMA.find(i) == words_for_OSNMA.end()) { ephClockStatusWordsReceived = false; - std::cerr << "OsnmaTestVectorsSimulation: error parsing words 1->5. " - "Word " - << i << " should be received for each subframe but was not." << std::endl; + std::cerr<< "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " + "Word "<< i << " should be received for each subframe but was not." << std::endl; } } // extract bits as needed by osnma block - if (ephClockStatusWordsReceived) + if(ephClockStatusWordsReceived) { + // Define the starting position and length of bits to extract for each word std::map> extractionParams = { {1, {6, 120}}, @@ -226,41 +333,41 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) {5, {6, 67}}, }; - // Fill NavData bits -- Iterate over the extraction parameters // Fill NavData bits -- Iterate over the extraction parameters + // Fill NavData bits -- Iterate over the extraction parameters std::string nav_data_ADKD_0_12 = ""; - for (const auto& param : extractionParams) - { + for (const auto& param : extractionParams) { uint8_t wordKey = param.first; uint8_t start = param.second.first; uint8_t length = param.second.second; // Extract the required bits and fill osnma block - nav_data_ADKD_0_12 += words[wordKey].to_string().substr(start, length); + nav_data_ADKD_0_12 += words_for_OSNMA[wordKey].to_string().substr(start, length); } // send to osnma block bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; - if (check_size_is_ok) + if(check_size_is_ok) { - std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " - << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; - const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> + std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <>( // < PRNd , navDataBits, TOW_Sosf> tv.svId, nav_data_ADKD_0_12, osnmaMsg_sptr->TOW_sf0); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) <<"): 0b" << nav_data_ADKD_0_12; osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + } } // check w6 && w10 is received => fill TimingData data vector - bool timingWordsReceived = words.find(6) != words.end() && - words.find(10) != words.end(); + bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() && + words_for_OSNMA.find(10) != words_for_OSNMA.end(); // extract bits as needed by osnma block - if (timingWordsReceived) - { + if(timingWordsReceived){ // Define the starting position and length of bits to extract for each word std::map> extractionParams = { {6, {6, 99}}, - {10, {86, 42}}}; + {10, {86, 42}} + }; std::string nav_data_ADKD_4 = ""; // Fill NavData bits -- Iterate over the extraction parameters @@ -271,42 +378,42 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) uint8_t length = param.second.second; // Extract the required bits and fill osnma block - nav_data_ADKD_4 += words[wordKey].to_string().substr( - start, length); + nav_data_ADKD_4 += words_for_OSNMA[wordKey].to_string().substr(start, length); } - // send to osnma block bool check_size_is_ok = nav_data_ADKD_4.size() == 141; - if (check_size_is_ok) + if(check_size_is_ok) { - std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " - << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; - const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> + std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <>( // < PRNd , navDataBits, TOW_Sosf> tv.svId, nav_data_ADKD_4, osnmaMsg_sptr->TOW_sf0); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) <<"): 0b" << nav_data_ADKD_4; osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + } + } // Call the handler, as if it came from telemetry decoder block auto temp_obj = pmt::make_any(osnmaMsg_sptr); - osnma->msg_handler_osnma(temp_obj); // osnma entry point + osnma->msg_handler_osnma(temp_obj); // osnma entry point } - if (!end_of_hex_stream) - { - offset_byte = byte_index; // update offset for the next subframe + if(!end_of_hex_stream){ + offset_byte = byte_index; // update offset for the next subframe d_GST_SIS += DURATION_SUBFRAME; TOW = d_GST_SIS & 0x000FFFFF; - WN = (d_GST_SIS & 0xFFF00000) >> 20; - std::cout << "OsnmaTestVectorsSimulation:" - << " d_GST_SIS= " << d_GST_SIS + WN = (d_GST_SIS & 0xFFF00000) >> 20 ; + std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS << ", TOW=" << TOW << ", WN=" << WN << std::endl; } + + } @@ -316,24 +423,22 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) } - +// Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. +// Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std::string& filename) { std::ifstream file(filename); std::vector testVectors; - if (!file.is_open()) - { - std::cerr << "Error reading the file \"" << filename << "\" \n"; + if (!file.is_open()) { + std::cerr<<"Error reading the file \"" << filename <<"\" \n"; return testVectors; } std::string line; std::getline(file, line); - if (line != "SVID,NumNavBits,NavBitsHEX\r") - { - std::cerr << "Error parsing first line" - << "\n"; - } + if (line != "SVID,NumNavBits,NavBitsHEX\r" ){ + std::cerr<<"Error parsing first line" <<"\n"; + } while (std::getline(file, line)) { @@ -356,35 +461,29 @@ std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std: return testVectors; } - - std::vector OsnmaMsgReceiverTest::parseNavBits(const std::string& hex) { std::vector bytes; - for (unsigned int i = 0; i < hex.length() - 1; i += 2) + for (unsigned int i = 0; i < hex.length()-1; i += 2) { std::string byteString = hex.substr(i, 2); - uint8_t byte = (uint8_t)strtol(byteString.c_str(), NULL, 16); + uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16); bytes.push_back(byte); } return bytes; } - - std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector& bytes) { std::string bit_string; bit_string.reserve(bytes.size() * 8); - for (const auto& byte : bytes) + for(const auto& byte : bytes) { std::bitset<8> bits(byte); bit_string += bits.to_string(); } return bit_string; } - - /** * @brief Extracts a range of bytes from a TestVector's navBits vector. * @@ -413,8 +512,6 @@ std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& return extracted_bytes; } - - /** * @brief Sets the time based on the given input. * @@ -438,118 +535,56 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) uint32_t sec_in_week = 7 * 24 * 60 * 60; uint32_t week_number = duration_sec.count() / sec_in_week; uint32_t time_of_week = duration_sec.count() % sec_in_week; - this->WN = week_number; - this->TOW = time_of_week + LEAP_SECONDS; + this->WN = week_number; + this->TOW = time_of_week + LEAP_SECONDS; // Return the week number and time of week as a pair // TODO: d_GST_SIS or d_receiver_time? doubt // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 - this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); + this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); + + } - - -TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) +void OsnmaMsgReceiverTest::initializeGoogleLog() { - // Arrange - // ---------- - // m0 - std::vector expected_message = { - 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, - 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, - 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, - 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, - 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00}; - - uint32_t TOW_Tag0 = 345660; - uint32_t TOW_NavData = TOW_Tag0 - 30; - uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; - uint32_t WN = 1248; - uint32_t PRNa = 2; - uint8_t CTR = 1; - - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 - osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; - osnma->d_osnma_data.d_nma_header.nmas = 0b10; - - MACK_tag_and_info MTI; - MTI.tag = static_cast(0xE37BC4F858); - MTI.tag_info.PRN_d = 0x02; - MTI.tag_info.ADKD = 0x00; - MTI.tag_info.cop = 0x0F; - Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); - - - // Act - // ---------- - auto computed_message = osnma->build_message(t0); - - - // Assert - // ---------- - ASSERT_TRUE(computed_message == expected_message); + google::InitGoogleLogging(log_name.c_str()); + FLAGS_minloglevel = 0; // INFO + FLAGS_logtostderr = 0; // add this line + FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; + if (FLAGS_log_dir.empty()) + { + std::cout << "Logging will be written at " + << std::filesystem::temp_directory_path() + << '\n' + << "Use gnss-sdr --log_dir=/path/to/log to change that.\n"; + } + else + { + try + { + const std::filesystem::path p(FLAGS_log_dir); + if (!std::filesystem::exists(p)) + { + std::cout << "The path " + << FLAGS_log_dir + << " does not exist, attempting to create it.\n"; + std::error_code ec; + if (!std::filesystem::create_directory(p, ec)) + { + std::cout << "Could not create the " << FLAGS_log_dir << " folder.\n"; + gflags::ShutDownCommandLineFlags(); + throw std::runtime_error("Could not create folder for logs"); + } + } + std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; + } + catch (const std::exception& e) + { + std::cerr << e.what() << '\n'; + std::cerr << "Could not create the " << FLAGS_log_dir << " folder.\n"; + gflags::ShutDownCommandLineFlags(); + throw; + } + } } - -TEST_F(OsnmaMsgReceiverTest, TagVerification) -{ - // Arrange - // ---------- - // Tag0 - uint32_t TOW_Tag0 = 345660; - uint32_t TOW_NavData = TOW_Tag0 - 30; - uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; - uint32_t WN = 1248; - uint32_t PRNa = 2; - uint8_t CTR = 1; - - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 - osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; - osnma->d_osnma_data.d_nma_header.nmas = 0b10; - - MACK_tag_and_info MTI; - MTI.tag = static_cast(0xE37BC4F858); - MTI.tag_info.PRN_d = 0x02; - MTI.tag_info.ADKD = 0x00; - MTI.tag_info.cop = 0x0F; - Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); - - - // Act - // ---------- - bool result_tag0 = osnma->verify_tag(t0); - - - // Assert - // ---------- - // ASSERT_TRUE(result_tag0); - - // Tag3 - uint32_t TOW_Tag3 = 345660; - uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; - uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30; - WN = 1248; - PRNa = 2; - CTR = 3; - - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 - osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].utc_vector_2 = - "111111111111111111111111111111110000000000000000000000010001001001001000" - "111000001000100111100010010111111111011110111111111001001100000100000000"; - osnma->d_osnma_data.d_nma_header.nmas = 0b10; - - MTI.tag = static_cast(0x7BB238C883); - MTI.tag_info.PRN_d = 0x02; - MTI.tag_info.ADKD = 0x04; - MTI.tag_info.cop = 0x0F; - Tag t3(MTI, TOW_Tag0, WN, PRNa, CTR); - - bool result_tag3 = osnma->verify_tag(t3); - - ASSERT_TRUE(result_tag0 && result_tag3); -} From c38fb0fca5756884c7f3088742226b7fa9ba64ad Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 28 Jun 2024 10:51:10 +0200 Subject: [PATCH 141/219] Fix building (add missing include) --- src/core/system_parameters/osnma_helper.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index 7cf3165c2..3feeb96cf 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -18,6 +18,7 @@ #include #include #include +#include uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const { @@ -25,6 +26,7 @@ uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const return GST; } + std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const { std::vector res; @@ -36,6 +38,7 @@ std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const return res; } + /** * @brief Convert a binary string to a vector of bytes. * @@ -67,6 +70,7 @@ std::vector Osnma_Helper::bytes(const std::string& binaryString) { return bytes; } + std::string Osnma_Helper::verification_status_str(int status) { switch (status) { @@ -76,6 +80,8 @@ std::string Osnma_Helper::verification_status_str(int status) default: return "UNKNOWN"; } } + + std::string Osnma_Helper::convert_to_hex_string(const std::vector& vector) { std::stringstream ss; From 359693c0e88b92b0b34443a52bb3a5f19c143276 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 28 Jun 2024 13:03:14 +0200 Subject: [PATCH 142/219] Add GNSS-SDR.osnma_enable configuration parameter, by default set to true --- src/core/receiver/gnss_flowgraph.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index acdea9df2..af1795ee0 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -121,7 +121,7 @@ void GNSSFlowgraph::init() galileo_tow_map_ = nullptr; } - if (configuration_->property("Channels_1B.count", 0) > 0) + if (configuration_->property("Channels_1B.count", 0) > 0 && configuration_->property("GNSS-SDR.osnma_enable", true)) { enable_osnma_rx_ = true; const auto certFilePath = configuration_->property("GNSS-SDR.osnma_public_key", CRTFILE_DEFAULT); From db5466832cfeae205ee0f6f18611583dfa18f222 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 29 Jun 2024 11:10:35 +0200 Subject: [PATCH 143/219] Look for OpenSSL in the first place, fallback to GnuTLS if not found Fix test building in some environments --- CMakeLists.txt | 94 +--- cmake/Modules/GnssSdrCrypto.cmake | 152 ++++++ docs/CHANGELOG.md | 9 + src/core/libs/supl/CMakeLists.txt | 13 +- src/core/libs/supl/supl.h | 14 +- src/core/system_parameters/CMakeLists.txt | 49 +- src/core/system_parameters/gnss_crypto.cc | 436 +++++++++--------- src/core/system_parameters/gnss_crypto.h | 15 +- src/tests/CMakeLists.txt | 3 + .../osnma/osnma_msg_receiver_test.cc | 54 +-- 10 files changed, 410 insertions(+), 429 deletions(-) create mode 100644 cmake/Modules/GnssSdrCrypto.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index a97dee597..4264195a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2196,99 +2196,9 @@ endif() ################################################################################ -# GnuTLS - https://www.gnutls.org/ +# OpenSSL https://www.openssl.org/ or GnuTLS - https://www.gnutls.org/ ################################################################################ -find_package(GnuTLS) -set_package_properties(GnuTLS PROPERTIES - URL "https://www.gnutls.org/" - PURPOSE "Used for the SUPL protocol implementation." - TYPE REQUIRED -) -if(GnuTLS_FOUND AND GNUTLS_VERSION_STRING) - set_package_properties(GnuTLS PROPERTIES - DESCRIPTION "Transport Layer Security Library (found: v${GNUTLS_VERSION_STRING})" - ) -else() - set_package_properties(GnuTLS PROPERTIES - DESCRIPTION "Transport Layer Security Library" - ) -endif() -find_library(GNUTLS_OPENSSL_LIBRARY - NAMES gnutls-openssl libgnutls-openssl.so.27 - PATHS - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/i386-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/i386-gnu - /usr/lib/i686-gnu - /usr/lib/i686-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i686-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/sh4-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib -) -#if(NOT GNUTLS_OPENSSL_LIBRARY) -if(GNUTLS_OPENSSL_LIBRARY) - if(GnuTLS_FOUND) - message(STATUS " But it was not built with openssl compatibility.") - endif() - message(STATUS " Looking for OpenSSL instead...") - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(OPENSSL_ROOT_DIR /usr/local/opt/openssl) # Trick for Homebrew - endif() - find_package(OpenSSL) - set_package_properties(OpenSSL PROPERTIES - URL "https://www.openssl.org" - DESCRIPTION "Cryptography and SSL/TLS Toolkit (found: v${OPENSSL_VERSION})" - PURPOSE "Used for the SUPL protocol implementation." - TYPE REQUIRED - ) - message("OPENSSL_FOUND: " ${OPENSSL_FOUND}) - if(OPENSSL_FOUND) - set_package_properties(GnuTLS PROPERTIES - PURPOSE "Not found, but OpenSSL can replace it." - ) - set(GNUTLS_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR}) - set(GNUTLS_LIBRARIES "") - set(GNUTLS_OPENSSL_LIBRARY ${OPENSSL_SSL_LIBRARY}) - else() - message(" The GnuTLS library with openssl compatibility enabled has not been found.") - message(" You can try to install the required libraries by typing:") - if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|kFreeBSD|GNU") - if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(" sudo yum install openssl-devel") - else() - message(" sudo apt-get install libgnutls28-dev") - endif() - endif() - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - message(" 'sudo port install gnutls', if you are using Macports, or") - message(" 'brew install openssl', if you are using Homebrew.") - endif() - message(FATAL_ERROR "GnuTLS libraries with openssl compatibility are required to build gnss-sdr") - endif() -endif() +include(GnssSdrCrypto) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake new file mode 100644 index 000000000..33e1aaab1 --- /dev/null +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -0,0 +1,152 @@ +# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +# This file is part of GNSS-SDR. +# +# SPDX-FileCopyrightText: 2024 C. Fernandez-Prades cfernandez(at)cttc.es +# SPDX-License-Identifier: BSD-3-Clause + + +################################################################################ +# OpenSSL https://www.openssl.org/ +################################################################################ +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(OPENSSL_ROOT_DIR /usr/local/opt/openssl) # Trick for Homebrew +endif() +find_package(OpenSSL) +set_package_properties(OpenSSL + PROPERTIES + URL "https://www.openssl.org" + PURPOSE "Used for the OSNMA and SUPL protocol implementations." + TYPE REQUIRED +) +if(OPENSSL_FOUND) + set_package_properties(OpenSSL + PROPERTIES + DESCRIPTION "Cryptography and SSL/TLS Toolkit (found: v${OPENSSL_VERSION})" + ) +else() + set_package_properties(OpenSSL + PROPERTIES + DESCRIPTION "OpenSSL has not been found, but GnuTLS with openssl compatibility can replace it" + ) + ################################################################################ + # GnuTLS - https://www.gnutls.org/ + ################################################################################ + find_package(GnuTLS) + set_package_properties(GnuTLS PROPERTIES + URL "https://www.gnutls.org/" + PURPOSE "Used for the OSNMA and SUPL protocol implementations." + TYPE REQUIRED + ) + if(GnuTLS_FOUND AND GNUTLS_VERSION_STRING) + set_package_properties(GnuTLS PROPERTIES + DESCRIPTION "Transport Layer Security Library (found: v${GNUTLS_VERSION_STRING})" + ) + else() + set_package_properties(GnuTLS PROPERTIES + DESCRIPTION "Transport Layer Security Library" + ) + endif() + find_library(GNUTLS_OPENSSL_LIBRARY + NAMES gnutls-openssl libgnutls-openssl.so.27 + PATHS + /usr/lib + /usr/lib64 + /usr/lib/x86_64-linux-gnu + /usr/lib/aarch64-linux-gnu + /usr/lib/arm-linux-gnueabihf + /usr/lib/arm-linux-gnueabi + /usr/lib/i386-linux-gnu + /usr/lib/alpha-linux-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/i386-gnu + /usr/lib/i686-gnu + /usr/lib/i686-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i686-kfreebsd-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/mipsel-linux-gnu + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/riscv64-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/sh4-linux-gnu + /usr/lib/loongarch64-linux-gnu + /usr/local/lib + /usr/local/lib64 + /opt/local/lib + ) + + if(NOT GNUTLS_OPENSSL_LIBRARY) + message(" The GnuTLS library with openssl compatibility enabled has not been found.") + message(" You can try to install the required libraries by typing:") + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|kFreeBSD|GNU") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(" sudo yum install openssl-devel") + else() + message(" sudo apt-get install libgnutls28-dev") + endif() + endif() + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + message(" 'sudo port install gnutls', if you are using Macports, or") + message(" 'brew install openssl', if you are using Homebrew.") + endif() + message(FATAL_ERROR "OpenSSL or the GnuTLS libraries with openssl compatibility are required to build gnss-sdr") + endif() +endif() + +################################################################################ + +function(link_to_crypto_dependencies target) + if(OPENSSL_FOUND) + if(TARGET OpenSSL::SSL) + target_link_libraries(core_system_parameters + PUBLIC + OpenSSL::SSL + ) + if(TARGET OpenSSL::Crypto) + target_link_libraries(core_system_parameters + PUBLIC + OpenSSL::Crypto + ) + endif() + else() + target_link_libraries(core_system_parameters + PUBLIC + ${OPENSSL_LIBRARIES} + "${OPENSSL_CRYPTO_LIBRARIES}" + ) + target_include_directories(core_system_parameters + PUBLIC + ${OPENSSL_INCLUDE_DIR} + ) + endif() + if(OPENSSL_VERSION) + if(OPENSSL_VERSION VERSION_GREATER "3.0.0") + target_compile_definitions(${target} PUBLIC -DUSE_OPENSSL_3=1) + else() + if(NOT OPENSSL_VERSION VERSION_LESS "1.1.1") + target_compile_definitions(${target} PUBLIC -DUSE_OPENSSL_111=1) + else() + endif() + endif() + else() + endif() + else() # GnuTLS + target_link_libraries(core_system_parameters + PUBLIC + ${GNUTLS_LIBRARIES} + ${GNUTLS_OPENSSL_LIBRARY} + ) + target_include_directories(core_system_parameters + PUBLIC + ${GNUTLS_INCLUDE_DIR} + ) + target_compile_definitions(${target} PUBLIC -DUSE_GNUTLS_FALLBACK=1) + endif() +endfunction() diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index e7e594fb9..1812c76b7 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -55,6 +55,15 @@ All notable changes to GNSS-SDR will be documented in this file. This change has a downside in maintainability, since the source code becomes plagued with preprocessor directives required to maintain compatibility both with gflags and glog, and with Abseil. +- Historically, GNSS-SDR linked against the GnuTLS library for cryptographic + functions. If GnuTLS was not found, then the building system looked for and + linked against OpenSSL as a fallback. This was due to the OpenSSL 1.x dual + license scheme, which was incompatible with GPL v3.0 license, preventing it + from being a mandatory dependency for GNSS-SDR in most GNU/Linux + distributions. This issue was solved with the release of OpenSSL 3.0.0, which + transitioned to the Apache License 2.0, fully compatible with GPL v3.0. + Accordingly, the GNSS-SDR building system now looks for OpenSSL in the first + place and, if not found, then it looks for GnuTLS as a fallback. ### Improvements in Usability: diff --git a/src/core/libs/supl/CMakeLists.txt b/src/core/libs/supl/CMakeLists.txt index 743852047..78ab2b80e 100644 --- a/src/core/libs/supl/CMakeLists.txt +++ b/src/core/libs/supl/CMakeLists.txt @@ -46,16 +46,9 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang|GNU" AND (CMAKE_VERSION VERSION_GREATER "3 target_compile_options(core_libs_supl PUBLIC $<$:${MY_C_FLAGS}>) endif() -if(OPENSSL_FOUND) - target_compile_definitions(core_libs_supl PUBLIC -DUSE_OPENSSL_FALLBACK=1) -endif() -message("OPENSSL_FOUND: " ${OPENSSL_FOUND}) -message("USE_OPENSSL_FALLBACK:" ${USE_OPENSSL_FALLBACK}) -target_link_libraries(core_libs_supl - PUBLIC - ${GNUTLS_LIBRARIES} - ${GNUTLS_OPENSSL_LIBRARY} -) +# links to the appropriate library and defines +# USE_GNUTLS_FALLBACK, USE_OPENSSL_3, or USE_OPENSSL_111 accordingly. +link_to_crypto_dependencies(core_libs_supl) target_include_directories(core_libs_supl PUBLIC diff --git a/src/core/libs/supl/supl.h b/src/core/libs/supl/supl.h index c879112f6..8c9bef533 100644 --- a/src/core/libs/supl/supl.h +++ b/src/core/libs/supl/supl.h @@ -24,18 +24,18 @@ #define EXPORT #endif // clang-format off -#if USE_OPENSSL_FALLBACK -#include -#include -#include -#include -#include -#else +#if USE_GNUTLS_FALLBACK #include #include #include #include #include +#else +#include +#include +#include +#include +#include #endif // clang-format on #include diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 0ef4cf22e..055ff256e 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -124,7 +124,7 @@ target_link_libraries(core_system_parameters Boost::date_time Boost::serialization PRIVATE - Pugixml::pugixml + Pugixml::pugixml ) if(ENABLE_GLOG_AND_GFLAGS) @@ -140,50 +140,9 @@ target_include_directories(core_system_parameters ${GNSSSDR_SOURCE_DIR}/src/algorithms/libs ) -if(OPENSSL_FOUND) - message("OPENSSL_FOUND: " ${OPENSSL_FOUND}) - if(TARGET OpenSSL::SSL) - target_link_libraries(core_system_parameters - PUBLIC - OpenSSL::SSL - ) - else() - target_link_libraries(core_system_parameters - PUBLIC - ${OPENSSL_LIBRARIES} - ) - target_include_directories(core_system_parameters - PUBLIC - ${OPENSSL_INCLUDE_DIR} - ) - endif() - if(OPENSSL_VERSION) - message("OPENSSL_VERSION: " ${OPENSSL_VERSION}) - if(OPENSSL_VERSION VERSION_GREATER "3.0.0") - target_compile_definitions(core_system_parameters PUBLIC -DUSE_OPENSSL_FALLBACK=1 -DUSE_OPENSSL_3=1) - message("USE_OPENSSL_3: " ${DUSE_OPENSSL_3}) - message("USE_OPENSSL_FALLBACK:" ${USE_OPENSSL_FALLBACK}) - else() - if(NOT OPENSSL_VERSION VERSION_LESS "1.1.1") - target_compile_definitions(core_system_parameters PRIVATE -DUSE_OPENSSL_FALLBACK=1 -DUSE_OPENSSL_111=1) - endif() - endif() - endif() - -else() - target_link_libraries(core_system_parameters - PUBLIC - ${GNUTLS_LIBRARIES} - ${GNUTLS_OPENSSL_LIBRARY} - ) - target_include_directories(core_system_parameters - PUBLIC - ${GNUTLS_INCLUDE_DIR} - ) -endif() -if(OPENSSL_FOUND) - target_compile_definitions(core_system_parameters PUBLIC -DUSE_OPENSSL_FALLBACK=1) -endif() +# links to the appropriate library and defines +# USE_GNUTLS_FALLBACK, USE_OPENSSL_3, or USE_OPENSSL_111 accordingly. +link_to_crypto_dependencies(core_system_parameters) if(ENABLE_CLANG_TIDY) if(CLANG_TIDY_EXE) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 0f1774271..a50e2f00b 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -25,7 +25,12 @@ #include #include -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK +#include +#include +#include +#include +#else // OpenSSL #include #include #include @@ -40,14 +45,9 @@ #include #include #define OPENSSL_ENGINE nullptr -#else +#else // OpenSSL 1.x #include #endif -#else // GnuTLS -#include -#include -#include -#include #endif #if USE_GLOG_AND_GFLAGS @@ -59,28 +59,28 @@ Gnss_Crypto::Gnss_Crypto() { -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + gnutls_global_init(); +#else // OpenSSL #if !(USE_OPENSSL_3 || USE_OPENSSL_111) LOG(WARNING) << "The OpenSSL library version you are linking against is too old for some OSNMA functions." << " Please do not trust OSNMA ouputs or upgrade your system to a newer version of OpenSSL" << " and rebuild GNSS-SDR against it."; #endif -#else // GnuTLS - gnutls_global_init(); #endif } Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath) { -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + gnutls_global_init(); +#else // OpenSSL #if !(USE_OPENSSL_3 || USE_OPENSSL_111) LOG(WARNING) << "The OpenSSL library version you are linking against is too old for some OSNMA functions." << " Please do not trust OSNMA ouputs or upgrade your system to a newer version of OpenSSL" << " and rebuild GNSS-SDR against it."; #endif -#else // GnuTLS - gnutls_global_init(); #endif if (!readPublicKeyFromCRT(certFilePath)) { @@ -92,31 +92,30 @@ Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& mer Gnss_Crypto::~Gnss_Crypto() { -#if USE_OPENSSL_FALLBACK -#if USE_OPENSSL_3 -#else - if (d_PublicKey != nullptr) - { - EC_KEY_free(d_PublicKey); - } -#endif -#else // GnuTLS +#if USE_GNUTLS_FALLBACK if (d_PublicKey != nullptr) { gnutls_pubkey_deinit(d_PublicKey); d_PublicKey = nullptr; } gnutls_global_deinit(); +#else // OpenSSL +#if !USE_OPENSSL_3 + if (d_PublicKey != nullptr) + { + EC_KEY_free(d_PublicKey); + } +#endif #endif } bool Gnss_Crypto::have_public_key() const { -#if USE_OPENSSL_FALLBACK - return (d_PublicKey != nullptr); -#else // GnuTLS +#if USE_GNUTLS_FALLBACK return (d_PublicKey != gnutls_pubkey_t{}); +#else // OpenSSL + return (d_PublicKey != nullptr); #endif } @@ -260,7 +259,15 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) std::vector Gnss_Crypto::computeSHA256(const std::vector& input) const { std::vector output(32); // SHA256 hash size -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + std::vector output_aux(32); + gnutls_hash_hd_t hashHandle; + gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); + gnutls_hash(hashHandle, input.data(), input.size()); + gnutls_hash_output(hashHandle, output_aux.data()); + output = output_aux; + gnutls_hash_deinit(hashHandle, output_aux.data()); +#else // OpenSSL #if USE_OPENSSL_3 unsigned int mdLen; EVP_MD_CTX* mdCtx = EVP_MD_CTX_new(); @@ -283,20 +290,12 @@ std::vector Gnss_Crypto::computeSHA256(const std::vector& inpu return output; } EVP_MD_CTX_free(mdCtx); -#else +#else // OpenSSL 1.x SHA256_CTX sha256Context; SHA256_Init(&sha256Context); SHA256_Update(&sha256Context, input.data(), input.size()); SHA256_Final(output.data(), &sha256Context); #endif -#else // GnuTLS - std::vector output_aux(32); - gnutls_hash_hd_t hashHandle; - gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA256); - gnutls_hash(hashHandle, input.data(), input.size()); - gnutls_hash_output(hashHandle, output_aux.data()); - output = output_aux; - gnutls_hash_deinit(hashHandle, output_aux.data()); #endif return output; } @@ -305,7 +304,15 @@ std::vector Gnss_Crypto::computeSHA256(const std::vector& inpu std::vector Gnss_Crypto::computeSHA3_256(const std::vector& input) const { std::vector output(32); // SHA256 hash size -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + std::vector output_aux(32); + gnutls_hash_hd_t hashHandle; + gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); + gnutls_hash(hashHandle, input.data(), input.size()); + gnutls_hash_output(hashHandle, output_aux.data()); + output = output_aux; + gnutls_hash_deinit(hashHandle, output_aux.data()); +#else // OpenSSL #if USE_OPENSSL_3 || USE_OPENSSL_111 EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); const EVP_MD* md = EVP_sha3_256(); @@ -314,21 +321,13 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in EVP_DigestUpdate(mdctx, input.data(), input.size()); EVP_DigestFinal_ex(mdctx, output.data(), nullptr); EVP_MD_CTX_free(mdctx); -#else +#else // OpenSSL 1.x // SHA3-256 not implemented in OpenSSL 1.0, it was introduced in OpenSSL 1.1.1 if (!input.empty()) { // do nothing } #endif -#else // GnuTLS - std::vector output_aux(32); - gnutls_hash_hd_t hashHandle; - gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); - gnutls_hash(hashHandle, input.data(), input.size()); - gnutls_hash_output(hashHandle, output_aux.data()); - output = output_aux; - gnutls_hash_deinit(hashHandle, output_aux.data()); #endif return output; } @@ -337,7 +336,15 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const { std::vector output(32); -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + std::vector output_aux(32); + gnutls_hmac_hd_t hmac; + gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); + gnutls_hmac(hmac, input.data(), input.size()); + gnutls_hmac_output(hmac, output_aux.data()); + output = output_aux; + gnutls_hmac_deinit(hmac, output_aux.data()); +#else // OpenSSL #if USE_OPENSSL_3 std::vector hmac(EVP_MAX_MD_SIZE); size_t output_length = 0; @@ -393,7 +400,7 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector EVP_MAC_free(mac); hmac.resize(output_length); output = hmac; -#else +#else // OpenSSL 1.x unsigned int outputLength = EVP_MAX_MD_SIZE; unsigned char* result = HMAC(EVP_sha256(), key.data(), key.size(), input.data(), input.size(), output.data(), &outputLength); if (result == nullptr) @@ -405,14 +412,6 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector // Resize the output vector to the actual length of the HMAC-SHA256 output output.resize(outputLength); #endif -#else // GnuTLS - std::vector output_aux(32); - gnutls_hmac_hd_t hmac; - gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); - gnutls_hmac(hmac, input.data(), input.size()); - gnutls_hmac_output(hmac, output_aux.data()); - output = output_aux; - gnutls_hmac_deinit(hmac, output_aux.data()); #endif return output; } @@ -421,7 +420,18 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& key, const std::vector& input) const { std::vector output(16); -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + gnutls_cipher_hd_t cipher; + std::vector mac(16); + std::vector message = input; + gnutls_datum_t key_data = {const_cast(key.data()), static_cast(key.size())}; + gnutls_cipher_init(&cipher, GNUTLS_CIPHER_AES_128_CBC, &key_data, nullptr); + gnutls_cipher_set_iv(cipher, nullptr, 16); // Set IV to zero + gnutls_cipher_encrypt(cipher, message.data(), message.size()); // Encrypt the message with AES-128 + gnutls_cipher_tag(cipher, mac.data(), mac.size()); // Get the CMAC-AES tag + output = mac; + gnutls_cipher_deinit(cipher); +#else // OpenSSL #if USE_OPENSSL_3 std::vector aux(EVP_MAX_MD_SIZE); // CMAC-AES output size size_t output_length = 0; @@ -479,7 +489,7 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke aux.resize(output_length); output = aux; -#else +#else // OpenSSL 1.x std::vector mac(16); // CMAC-AES output size // Create CMAC context @@ -495,17 +505,6 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke output = mac; #endif -#else // GnuTLS - gnutls_cipher_hd_t cipher; - std::vector mac(16); - std::vector message = input; - gnutls_datum_t key_data = {const_cast(key.data()), static_cast(key.size())}; - gnutls_cipher_init(&cipher, GNUTLS_CIPHER_AES_128_CBC, &key_data, nullptr); - gnutls_cipher_set_iv(cipher, nullptr, 16); // Set IV to zero - gnutls_cipher_encrypt(cipher, message.data(), message.size()); // Encrypt the message with AES-128 - gnutls_cipher_tag(cipher, mac.data(), mac.size()); // Get the CMAC-AES tag - output = mac; - gnutls_cipher_deinit(cipher); #endif return output; } @@ -526,27 +525,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) return; } std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); -#if USE_OPENSSL_FALLBACK - // Create a BIO object from the string data - BIO* bio = BIO_new_mem_buf(pemContent.c_str(), pemContent.length()); - if (!bio) - { - std::cerr << "OpenSSL: error creating a BIO object with data read from file " << pemFilePath << ". Aborting import" << std::endl; - return; - } -#if USE_OPENSSL_3 - d_PublicKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); -#else - d_PublicKey = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); -#endif - BIO_free(bio); - if (d_PublicKey == nullptr) - { - std::cerr << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import" << std::endl; - LOG(INFO) << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import"; - return; - } -#else // GnuTLS +#if USE_GNUTLS_FALLBACK // Import the PEM data gnutls_datum_t pemDatum = {const_cast(reinterpret_cast(pemContent.data())), static_cast(pemContent.size())}; gnutls_pubkey_t pubkey; @@ -566,6 +545,26 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) pubkey_copy(pubkey, &d_PublicKey); gnutls_pubkey_deinit(pubkey); +#else // OpenSSL + // Create a BIO object from the string data + BIO* bio = BIO_new_mem_buf(pemContent.c_str(), pemContent.length()); + if (!bio) + { + std::cerr << "OpenSSL: error creating a BIO object with data read from file " << pemFilePath << ". Aborting import" << std::endl; + return; + } +#if USE_OPENSSL_3 + d_PublicKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); +#else // OpenSSL 1.x + d_PublicKey = PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr); +#endif + BIO_free(bio); + if (d_PublicKey == nullptr) + { + std::cerr << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import" << std::endl; + LOG(INFO) << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import"; + return; + } #endif std::cout << "OSNMA Public key successfully read from file " << pemFilePath << std::endl; LOG(INFO) << "OSNMA Public key successfully read from file " << pemFilePath; @@ -574,57 +573,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { -#if USE_OPENSSL_FALLBACK - // Open the .crt file - std::ifstream crtFile(crtFilePath, std::ios::binary); - if (!crtFile.is_open()) - { - std::cerr << "Unable to open file: " << crtFilePath << std::endl; - return false; - } - - // Read certificate - std::vector buffer((std::istreambuf_iterator(crtFile)), std::istreambuf_iterator()); - BIO* bio = BIO_new_mem_buf(buffer.data(), buffer.size()); - if (!bio) - { - std::cerr << "Unable to create BIO for file: " << crtFilePath << std::endl; - return false; - } - X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); - if (!cert) - { - std::cerr << "Unable to read certificate from file: " << crtFilePath << std::endl; - BIO_free(bio); - return false; - } - - // Read the public key from the certificate - EVP_PKEY* pubkey = X509_get_pubkey(cert); -#if USE_OPENSSL_3 - if (!pubkey) - { - std::cerr << "Failed to extract the public key" << std::endl; - X509_free(cert); - return false; - } - pubkey_copy(pubkey, &d_PublicKey); - EVP_PKEY_free(pubkey); -#else - EC_KEY* ec_pubkey = EVP_PKEY_get1_EC_KEY(pubkey); - EVP_PKEY_free(pubkey); - if (!ec_pubkey) - { - std::cerr << "Failed to extract the public key" << std::endl; - X509_free(cert); - return false; - } - pubkey_copy(ec_pubkey, &d_PublicKey); - EC_KEY_free(ec_pubkey); -#endif - BIO_free(bio); - X509_free(cert); -#else // GnuTLS +#if USE_GNUTLS_FALLBACK // Open the .crt file std::ifstream crtFile(crtFilePath, std::ios::binary); if (!crtFile.is_open()) @@ -664,6 +613,56 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) pubkey_copy(pubkey, &d_PublicKey); gnutls_x509_crt_deinit(cert); gnutls_pubkey_deinit(pubkey); +#else // OpenSSL + // Open the .crt file + std::ifstream crtFile(crtFilePath, std::ios::binary); + if (!crtFile.is_open()) + { + std::cerr << "Unable to open file: " << crtFilePath << std::endl; + return false; + } + + // Read certificate + std::vector buffer((std::istreambuf_iterator(crtFile)), std::istreambuf_iterator()); + BIO* bio = BIO_new_mem_buf(buffer.data(), buffer.size()); + if (!bio) + { + std::cerr << "Unable to create BIO for file: " << crtFilePath << std::endl; + return false; + } + X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); + if (!cert) + { + std::cerr << "Unable to read certificate from file: " << crtFilePath << std::endl; + BIO_free(bio); + return false; + } + + // Read the public key from the certificate + EVP_PKEY* pubkey = X509_get_pubkey(cert); +#if USE_OPENSSL_3 + if (!pubkey) + { + std::cerr << "Failed to extract the public key" << std::endl; + X509_free(cert); + return false; + } + pubkey_copy(pubkey, &d_PublicKey); + EVP_PKEY_free(pubkey); +#else // OpenSSL 1.x + EC_KEY* ec_pubkey = EVP_PKEY_get1_EC_KEY(pubkey); + EVP_PKEY_free(pubkey); + if (!ec_pubkey) + { + std::cerr << "Failed to extract the public key" << std::endl; + X509_free(cert); + return false; + } + pubkey_copy(ec_pubkey, &d_PublicKey); + EC_KEY_free(ec_pubkey); +#endif + BIO_free(bio); + X509_free(cert); #endif std::cout << "OSNMA Public key successfully read from file " << crtFilePath << std::endl; LOG(INFO) << "OSNMA Public key successfully read from file " << crtFilePath; @@ -680,7 +679,32 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st return false; } bool success = false; -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + // Convert signature to DER format + std::vector der_sig; + if (!convert_raw_to_der_ecdsa(signature, der_sig)) + { + std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; + return false; + } + + // Prepare the digest datum + gnutls_datum_t digest_data = {const_cast(digest.data()), static_cast(digest.size())}; + gnutls_datum_t der_sig_data = {der_sig.data(), static_cast(der_sig.size())}; + + // Verify the DER-encoded signature + int ret = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &digest_data, &der_sig_data); + success = (ret >= 0); + if (success) + { + LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; + } + else + { + std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; + LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); + } +#else // OpenSSL #if USE_OPENSSL_3 EVP_PKEY_CTX* ctx; ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); @@ -753,7 +777,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st std::cerr << "OpenSSL: OSNMA message authentication failed: " << err << std::endl; LOG(WARNING) << "OpenSSL: OSNMA message authentication failed: " << err; } -#else +#else // OpenSSL 1.x std::vector der_sig; if (!convert_raw_to_der_ecdsa(signature, der_sig)) { @@ -777,31 +801,6 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st LOG(WARNING) << "OpenSSL: OSNMA message authentication failed"; } #endif -#else // GnuTLS - // Convert signature to DER format - std::vector der_sig; - if (!convert_raw_to_der_ecdsa(signature, der_sig)) - { - std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; - return false; - } - - // Prepare the digest datum - gnutls_datum_t digest_data = {const_cast(digest.data()), static_cast(digest.size())}; - gnutls_datum_t der_sig_data = {der_sig.data(), static_cast(der_sig.size())}; - - // Verify the DER-encoded signature - int ret = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &digest_data, &der_sig_data); - success = (ret >= 0); - if (success) - { - LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; - } - else - { - std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; - LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); - } #endif return success; } @@ -845,7 +844,21 @@ std::vector Gnss_Crypto::getMerkleRoot(const std::vector& publicKey) { -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + gnutls_pubkey_t pubkey; + gnutls_datum_t pemDatum = {const_cast(publicKey.data()), static_cast(publicKey.size())}; + gnutls_pubkey_init(&pubkey); + int ret = gnutls_pubkey_import(pubkey, &pemDatum, GNUTLS_X509_FMT_PEM); + if (ret != GNUTLS_E_SUCCESS) + { + gnutls_pubkey_deinit(pubkey); + std::cerr << "GnuTLS: error setting the public key" << std::endl; + std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; + return; + } + pubkey_copy(pubkey, &d_PublicKey); + gnutls_pubkey_deinit(pubkey); +#else // OpenSSL BIO* bio = nullptr; EVP_PKEY* pkey = nullptr; bio = BIO_new_mem_buf(publicKey.data(), publicKey.size()); @@ -876,22 +889,8 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) return; } EC_KEY_free(ec_pkey); -#endif +#endif // OpenSSL 1.x EVP_PKEY_free(pkey); -#else // GnuTLS - gnutls_pubkey_t pubkey; - gnutls_datum_t pemDatum = {const_cast(publicKey.data()), static_cast(publicKey.size())}; - gnutls_pubkey_init(&pubkey); - int ret = gnutls_pubkey_import(pubkey, &pemDatum, GNUTLS_X509_FMT_PEM); - if (ret != GNUTLS_E_SUCCESS) - { - gnutls_pubkey_deinit(pubkey); - std::cerr << "GnuTLS: error setting the public key" << std::endl; - std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; - return; - } - pubkey_copy(pubkey, &d_PublicKey); - gnutls_pubkey_deinit(pubkey); #endif LOG(INFO) << "OSNMA Public Key successfully set up."; } @@ -945,7 +944,40 @@ bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signa } -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK // GnuTLS-specific functions +bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) +{ + gnutls_datum_t key_datum; + + // Export the public key from src to memory + int ret = gnutls_pubkey_export2(src, GNUTLS_X509_FMT_PEM, &key_datum); + if (ret < 0) + { + gnutls_free(key_datum.data); + return false; + } + + // Initialize dest + ret = gnutls_pubkey_init(dest); + if (ret < 0) + { + gnutls_free(key_datum.data); + return false; + } + + // Import the public key data from key_datum to dest + ret = gnutls_pubkey_import(*dest, &key_datum, GNUTLS_X509_FMT_PEM); + gnutls_free(key_datum.data); + + if (ret < 0) + { + gnutls_pubkey_deinit(*dest); + return false; + } + + return true; +} +#else // OpenSSL #if USE_OPENSSL_3 bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) { @@ -1036,41 +1068,5 @@ bool Gnss_Crypto::pubkey_copy(EC_KEY* src, EC_KEY** dest) return true; } - #endif - -#else // GnuTLS-specific functions - -bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) -{ - gnutls_datum_t key_datum; - - // Export the public key from src to memory - int ret = gnutls_pubkey_export2(src, GNUTLS_X509_FMT_PEM, &key_datum); - if (ret < 0) - { - gnutls_free(key_datum.data); - return false; - } - - // Initialize dest - ret = gnutls_pubkey_init(dest); - if (ret < 0) - { - gnutls_free(key_datum.data); - return false; - } - - // Import the public key data from key_datum to dest - ret = gnutls_pubkey_import(*dest, &key_datum, GNUTLS_X509_FMT_PEM); - gnutls_free(key_datum.data); - - if (ret < 0) - { - gnutls_pubkey_deinit(*dest); - return false; - } - - return true; -} #endif diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index bbcac1afa..7e0527750 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -22,10 +22,10 @@ #include #include #include -#if USE_OPENSSL_FALLBACK -#include -#else +#if USE_GNUTLS_FALLBACK #include +#else // OpenSSL +#include #endif /** \addtogroup Core @@ -60,7 +60,10 @@ private: bool readPublicKeyFromCRT(const std::string& crtFilePath); bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; std::vector convert_from_hex_str(const std::string& input) const; -#if USE_OPENSSL_FALLBACK +#if USE_GNUTLS_FALLBACK + bool pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest); + gnutls_pubkey_t d_PublicKey{}; +#else // OpenSSL #if USE_OPENSSL_3 bool pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest); EVP_PKEY* d_PublicKey{}; @@ -68,9 +71,6 @@ private: bool pubkey_copy(EC_KEY* src, EC_KEY** dest); EC_KEY* d_PublicKey = nullptr; #endif -#else // GnuTLS - bool pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest); - gnutls_pubkey_t d_PublicKey{}; #endif std::vector d_x_4_0; std::vector d_x_3_1; @@ -82,4 +82,5 @@ private: /** \} */ /** \} */ + #endif // GNSS_SDR_GNSS_CRYPTO_H \ No newline at end of file diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 8de611f5f..f1491b032 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1367,6 +1367,9 @@ if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) GTest::GTest GTest::Main core_libs + Gnuradio::blocks + Gnuradio::runtime + Gnuradio::filter # workaround for old systems ) if(ENABLE_GLOG_AND_GFLAGS) target_link_libraries(osnma_msg_receiver_test PRIVATE Gflags::gflags Glog::glog) diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 7b94baf0c..743c2b877 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -1,11 +1,14 @@ #include #include -#include #include -#include -#include #include +#include "osnma_msg_receiver.h" +#if USE_GLOG_AND_GFLAGS +#include // for LOG +#else +#include +#endif struct TestVector { @@ -31,11 +34,9 @@ protected: void set_time(std::tm& input); // std::string log_name {"CONFIG1-2023-08-16-PKID1-OSNMA"}; std::string log_name {"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; - void initializeGoogleLog(); void SetUp() override { - initializeGoogleLog(); // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 set_time(input_time); @@ -545,46 +546,3 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) } -void OsnmaMsgReceiverTest::initializeGoogleLog() -{ - google::InitGoogleLogging(log_name.c_str()); - FLAGS_minloglevel = 0; // INFO - FLAGS_logtostderr = 0; // add this line - FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; - if (FLAGS_log_dir.empty()) - { - std::cout << "Logging will be written at " - << std::filesystem::temp_directory_path() - << '\n' - << "Use gnss-sdr --log_dir=/path/to/log to change that.\n"; - } - else - { - try - { - const std::filesystem::path p(FLAGS_log_dir); - if (!std::filesystem::exists(p)) - { - std::cout << "The path " - << FLAGS_log_dir - << " does not exist, attempting to create it.\n"; - std::error_code ec; - if (!std::filesystem::create_directory(p, ec)) - { - std::cout << "Could not create the " << FLAGS_log_dir << " folder.\n"; - gflags::ShutDownCommandLineFlags(); - throw std::runtime_error("Could not create folder for logs"); - } - } - std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; - } - catch (const std::exception& e) - { - std::cerr << e.what() << '\n'; - std::cerr << "Could not create the " << FLAGS_log_dir << " folder.\n"; - gflags::ShutDownCommandLineFlags(); - throw; - } - } -} - From a530981d5bc7fb97b09e8f76fa28da50880fbff0 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 29 Jun 2024 11:41:28 +0200 Subject: [PATCH 144/219] Update README.md with openssl --- README.md | 30 ++++++++++++++---------------- cmake/Modules/GnssSdrCrypto.cmake | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index a904764b0..5b7bc9dfd 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ information about this open-source, software-defined GNSS receiver. - [Install Armadillo, a C++ linear algebra library](#install-armadillo-a-c-linear-algebra-library) - [Install Gflags, a commandline flags processing module for C++](#install-gflags-a-commandline-flags-processing-module-for-c) - [Install Glog, a library that implements application-level logging](#install-glog-a-library-that-implements-application-level-logging) - - [Install the GnuTLS or OpenSSL libraries](#install-the-gnutls-or-openssl-libraries) + - [Install the OpenSSL libraries](#install-the-openssl-libraries) - [Install Matio, MATLAB MAT file I/O library](#install-matio-matlab-mat-file-io-library) - [Install Protocol Buffers, a portable mechanism for serialization of structured data](#install-protocol-buffers-a-portable-mechanism-for-serialization-of-structured-data) - [Install Pugixml, a light-weight C++ XML processing library](#install-pugixml-a-light-weight-c-xml-processing-library) @@ -168,16 +168,19 @@ $ sudo apt-get install build-essential cmake git pkg-config libboost-dev libboos libboost-system-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev \ libboost-serialization-dev liblog4cpp5-dev libuhd-dev gnuradio-dev gr-osmosdr \ libblas-dev liblapack-dev libarmadillo-dev libgflags-dev libgoogle-glog-dev \ - libgnutls-openssl-dev libpcap-dev libmatio-dev libpugixml-dev libgtest-dev \ - libprotobuf-dev protobuf-compiler python3-mako + libssl-dev libpcap-dev libmatio-dev libpugixml-dev libgtest-dev \ + libprotobuf-dev libcpu-features-dev protobuf-compiler python3-mako ``` Please note that the required files from `libgtest-dev` were named `googletest` in Debian 9 "stretch" and Ubuntu 18.04 "bionic", and renamed to `libgtest-dev` in Debian 10 "buster" and above. -Since Ubuntu 21.04 Hirsute / Debian 11, the package `libcpu-features-dev` is -also required. +In distributions older than Ubuntu 21.04 Hirsute / Debian 11, the package +`libcpu-features-dev` is not required. + +In distributions older than Ubuntu 22.04 Jammy / Debian 12, the package +`libssl-dev` must be replaced by `libgnutls-openssl-dev`. **Note for Ubuntu 14.04 LTS "trusty" users:** you will need to build from source and install GNU Radio manually, as explained below, since GNSS-SDR requires @@ -451,20 +454,15 @@ Please note that Glog is replaced by the [Abseil Logging Library](https://abseil.io/docs/cpp/guides/logging) if Abseil >= v20240116 is available in your system. -#### Install the GnuTLS or OpenSSL libraries +#### Install the OpenSSL libraries ``` -$ sudo apt-get install libgnutls-openssl-dev # For Debian/Ubuntu/LinuxMint -$ sudo yum install openssl-devel # For Fedora/CentOS/RHEL -$ sudo zypper install openssl-devel # For OpenSUSE -$ sudo pacman -S openssl # For Arch Linux +$ sudo apt-get install libssl-dev # For Debian/Ubuntu/LinuxMint +$ sudo yum install openssl-devel # For Fedora/CentOS/RHEL +$ sudo zypper install openssl-devel # For OpenSUSE +$ sudo pacman -S openssl # For Arch Linux ``` -In case the [GnuTLS](https://www.gnutls.org/ "GnuTLS's Homepage") library with -openssl extensions package is not available in your GNU/Linux distribution, -GNSS-SDR can also work well with -[OpenSSL](https://www.openssl.org/ "OpenSSL's Homepage"). - #### Install [Matio](https://github.com/tbeu/matio "Matio's Homepage"), MATLAB MAT file I/O library ``` @@ -838,7 +836,7 @@ In a terminal, type: ``` $ sudo port selfupdate $ sudo port upgrade outdated -$ sudo port install armadillo cmake pkgconfig protobuf3-cpp pugixml gnutls +$ sudo port install armadillo cmake pkgconfig protobuf3-cpp pugixml openssl3 $ sudo port install gnuradio +uhd +grc +zeromq $ sudo port install boost matio libad9361-iio libiio $ sudo port install py311-mako diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index 33e1aaab1..c873c6bc3 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -93,7 +93,7 @@ else() endif() endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - message(" 'sudo port install gnutls', if you are using Macports, or") + message(" 'sudo port install openssl3', if you are using Macports, or") message(" 'brew install openssl', if you are using Homebrew.") endif() message(FATAL_ERROR "OpenSSL or the GnuTLS libraries with openssl compatibility are required to build gnss-sdr") From 609b85b8641b7603f2a2d0b5411be0504bd126b0 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 29 Jun 2024 11:45:00 +0200 Subject: [PATCH 145/219] Fix cmakelint formatting --- cmake/Modules/GnssSdrCrypto.cmake | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index c873c6bc3..7c427bab2 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -20,12 +20,12 @@ set_package_properties(OpenSSL ) if(OPENSSL_FOUND) set_package_properties(OpenSSL - PROPERTIES + PROPERTIES DESCRIPTION "Cryptography and SSL/TLS Toolkit (found: v${OPENSSL_VERSION})" ) else() set_package_properties(OpenSSL - PROPERTIES + PROPERTIES DESCRIPTION "OpenSSL has not been found, but GnuTLS with openssl compatibility can replace it" ) ################################################################################ @@ -114,7 +114,7 @@ function(link_to_crypto_dependencies target) PUBLIC OpenSSL::Crypto ) - endif() + endif() else() target_link_libraries(core_system_parameters PUBLIC @@ -131,10 +131,9 @@ function(link_to_crypto_dependencies target) target_compile_definitions(${target} PUBLIC -DUSE_OPENSSL_3=1) else() if(NOT OPENSSL_VERSION VERSION_LESS "1.1.1") - target_compile_definitions(${target} PUBLIC -DUSE_OPENSSL_111=1) - else() + target_compile_definitions(${target} PUBLIC -DUSE_OPENSSL_111=1) endif() - endif() + endif() else() endif() else() # GnuTLS From 668ca7a5d8d6db1aa3c57bc6920c04064239544f Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 29 Jun 2024 11:52:06 +0200 Subject: [PATCH 146/219] Fix link_to_crypto_dependencies function --- cmake/Modules/GnssSdrCrypto.cmake | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index 7c427bab2..67648d702 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -105,23 +105,23 @@ endif() function(link_to_crypto_dependencies target) if(OPENSSL_FOUND) if(TARGET OpenSSL::SSL) - target_link_libraries(core_system_parameters + target_link_libraries(${target} PUBLIC OpenSSL::SSL ) if(TARGET OpenSSL::Crypto) - target_link_libraries(core_system_parameters + target_link_libraries(${target} PUBLIC OpenSSL::Crypto ) endif() else() - target_link_libraries(core_system_parameters + target_link_libraries(${target} PUBLIC ${OPENSSL_LIBRARIES} "${OPENSSL_CRYPTO_LIBRARIES}" ) - target_include_directories(core_system_parameters + target_include_directories(${target} PUBLIC ${OPENSSL_INCLUDE_DIR} ) @@ -137,12 +137,12 @@ function(link_to_crypto_dependencies target) else() endif() else() # GnuTLS - target_link_libraries(core_system_parameters + target_link_libraries(${target} PUBLIC ${GNUTLS_LIBRARIES} ${GNUTLS_OPENSSL_LIBRARY} ) - target_include_directories(core_system_parameters + target_include_directories(${target} PUBLIC ${GNUTLS_INCLUDE_DIR} ) From 22b6d703185b85bcb5e41213d13a4f345fbe2478 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 30 Jun 2024 09:45:51 +0200 Subject: [PATCH 147/219] Fix building of benchmarks in some environments --- src/tests/benchmarks/CMakeLists.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tests/benchmarks/CMakeLists.txt b/src/tests/benchmarks/CMakeLists.txt index 133174871..28bddd050 100644 --- a/src/tests/benchmarks/CMakeLists.txt +++ b/src/tests/benchmarks/CMakeLists.txt @@ -104,10 +104,15 @@ macro(add_benchmark) ) endmacro() +set(EXTRA_BENCHMARK_DEPENDENCIES "") +if(ENABLE_GLOG_AND_GFLAGS) + set(EXTRA_BENCHMARK_DEPENDENCIES "Gflags::gflags;Glog::glog") +endif() + add_benchmark(benchmark_copy) -add_benchmark(benchmark_preamble core_system_parameters) -add_benchmark(benchmark_detector core_system_parameters) -add_benchmark(benchmark_reed_solomon core_system_parameters) +add_benchmark(benchmark_preamble core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) +add_benchmark(benchmark_detector core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) +add_benchmark(benchmark_reed_solomon core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) add_benchmark(benchmark_atan2 Gnuradio::runtime) if(has_std_plus_void) From 413e5309ba9ed29772c46d06da9517953d746ee7 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 30 Jun 2024 10:10:03 +0200 Subject: [PATCH 148/219] Add missing include --- .../signal-processing-blocks/osnma/osnma_msg_receiver_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 743c2b877..dc3e69684 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -1,5 +1,6 @@ #include #include +#include #include #include #include "osnma_msg_receiver.h" From d984822b453d7ba3fdac7182bebead653aecd985 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 30 Jun 2024 10:24:21 +0200 Subject: [PATCH 149/219] Fix for cross-compilation --- src/core/libs/osnma_msg_receiver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 45ad958ee..955712c76 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -317,7 +317,7 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS)); if (delta_T <= d_T_L) { d_tags_allowed = tags_to_verify::all; From c2bb06076af3dc20b819a0cdc75fc2c2f0a2bb4a Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 30 Jun 2024 12:04:57 +0200 Subject: [PATCH 150/219] Fix for old OpenSSL --- src/core/system_parameters/gnss_crypto.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index a50e2f00b..322e4acdd 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -547,7 +547,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) gnutls_pubkey_deinit(pubkey); #else // OpenSSL // Create a BIO object from the string data - BIO* bio = BIO_new_mem_buf(pemContent.c_str(), pemContent.length()); + BIO* bio = BIO_new_mem_buf(const_cast(pemContent.c_str()), pemContent.length()); if (!bio) { std::cerr << "OpenSSL: error creating a BIO object with data read from file " << pemFilePath << ". Aborting import" << std::endl; @@ -861,7 +861,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) #else // OpenSSL BIO* bio = nullptr; EVP_PKEY* pkey = nullptr; - bio = BIO_new_mem_buf(publicKey.data(), publicKey.size()); + bio = BIO_new_mem_buf(const_cast(publicKey.data()), publicKey.size()); if (!bio) { std::cerr << "Failed to create BIO for key \n"; From 95e3329f1011779628bd75baf97f99035c7ff3fb Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 1 Jul 2024 01:31:09 +0200 Subject: [PATCH 151/219] Fix for old GnuTLS --- cmake/Modules/GnssSdrCrypto.cmake | 37 +++++++++++++++++++ src/core/system_parameters/gnss_crypto.cc | 45 +++++++++++++++++------ src/core/system_parameters/gnss_crypto.h | 1 + 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index 67648d702..a5e383790 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -82,6 +82,15 @@ else() /opt/local/lib ) + find_path(GNUTLS_INCLUDE_DIR NAMES gnutls/gnutls.h + PATHS + /usr/include + /usr/local/include + /opt/local/include # default location in Macports + /opt/homebrew/opt/gnutls/include/ + ${GNUTLS_ROOT_DIR}/include/ + ) + if(NOT GNUTLS_OPENSSL_LIBRARY) message(" The GnuTLS library with openssl compatibility enabled has not been found.") message(" You can try to install the required libraries by typing:") @@ -98,6 +107,22 @@ else() endif() message(FATAL_ERROR "OpenSSL or the GnuTLS libraries with openssl compatibility are required to build gnss-sdr") endif() + + # Test GnuTLS capabilities + file(READ "${GNUTLS_INCLUDE_DIR}/gnutls/gnutls.h" gnutls_gnutls_file_contents) + if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_SIGN_ECDSA_SHA256") + set(GNUTLS_SIGN_ECDSA_SHA256 TRUE) + endif() + if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_DIG_SHA3_256") + set(GNUTLS_DIG_SHA3_256 TRUE) + endif() + if("${gnutls_gnutls_file_contents}" MATCHES "#define GNUTLS_VERSION_MAJOR 2") + set(GNUTLS_HMAC_INIT_WITH_DIGEST TRUE) + endif() + file(READ "${GNUTLS_INCLUDE_DIR}/gnutls/abstract.h" gnutls_abstract_file_contents) + if("${gnutls_abstract_file_contents}" MATCHES "gnutls_pubkey_export2") + set(GNUTLS_PUBKEY_EXPORT2 TRUE) + endif() endif() ################################################################################ @@ -147,5 +172,17 @@ function(link_to_crypto_dependencies target) ${GNUTLS_INCLUDE_DIR} ) target_compile_definitions(${target} PUBLIC -DUSE_GNUTLS_FALLBACK=1) + if(GNUTLS_SIGN_ECDSA_SHA256) + target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_SIGN_ECDSA_SHA256=1) + endif() + if(GNUTLS_DIG_SHA3_256) + target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_DIG_SHA3_256=1) + endif() + if(GNUTLS_PUBKEY_EXPORT2) + target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_PUBKEY_EXPORT2=1) + endif() + if(GNUTLS_HMAC_INIT_WITH_DIGEST) + target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_HMAC_INIT_WITH_DIGEST=1) + endif() endif() endfunction() diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 322e4acdd..8ad7e55bb 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -27,7 +27,6 @@ #if USE_GNUTLS_FALLBACK #include -#include #include #include #else // OpenSSL @@ -61,6 +60,11 @@ Gnss_Crypto::Gnss_Crypto() { #if USE_GNUTLS_FALLBACK gnutls_global_init(); +#if !HAVE_GNUTLS_SIGN_ECDSA_SHA256 + LOG(WARNING) << "The GnuTLS library version you are linking against is too old for some OSNMA functions." + << " Please do not trust OSNMA ouputs or upgrade your system to a newer version of GnuTLS or OpenSSL" + << " and rebuild GNSS-SDR against it."; +#endif #else // OpenSSL #if !(USE_OPENSSL_3 || USE_OPENSSL_111) LOG(WARNING) << "The OpenSSL library version you are linking against is too old for some OSNMA functions." @@ -75,6 +79,11 @@ Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& mer { #if USE_GNUTLS_FALLBACK gnutls_global_init(); +#if !HAVE_GNUTLS_SIGN_ECDSA_SHA256 + LOG(WARNING) << "The GnuTLS library version you are linking against is too old for some OSNMA functions." + << " Please do not trust OSNMA ouputs or upgrade your system to a newer version of GnuTLS or OpenSSL" + << " and rebuild GNSS-SDR against it."; +#endif #else // OpenSSL #if !(USE_OPENSSL_3 || USE_OPENSSL_111) LOG(WARNING) << "The OpenSSL library version you are linking against is too old for some OSNMA functions." @@ -305,6 +314,7 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in { std::vector output(32); // SHA256 hash size #if USE_GNUTLS_FALLBACK +#if HAVE_GNUTLS_DIG_SHA3_256 std::vector output_aux(32); gnutls_hash_hd_t hashHandle; gnutls_hash_init(&hashHandle, GNUTLS_DIG_SHA3_256); @@ -312,6 +322,7 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in gnutls_hash_output(hashHandle, output_aux.data()); output = output_aux; gnutls_hash_deinit(hashHandle, output_aux.data()); +#endif #else // OpenSSL #if USE_OPENSSL_3 || USE_OPENSSL_111 EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); @@ -339,7 +350,11 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector #if USE_GNUTLS_FALLBACK std::vector output_aux(32); gnutls_hmac_hd_t hmac; +#if HAVE_GNUTLS_HMAC_INIT_WITH_DIGEST + gnutls_hmac_init(&hmac, GNUTLS_DIG_SHA256, key.data(), key.size()); +#else gnutls_hmac_init(&hmac, GNUTLS_MAC_SHA256, key.data(), key.size()); +#endif gnutls_hmac(hmac, input.data(), input.size()); gnutls_hmac_output(hmac, output_aux.data()); output = output_aux; @@ -421,16 +436,15 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke { std::vector output(16); #if USE_GNUTLS_FALLBACK - gnutls_cipher_hd_t cipher; - std::vector mac(16); - std::vector message = input; - gnutls_datum_t key_data = {const_cast(key.data()), static_cast(key.size())}; - gnutls_cipher_init(&cipher, GNUTLS_CIPHER_AES_128_CBC, &key_data, nullptr); - gnutls_cipher_set_iv(cipher, nullptr, 16); // Set IV to zero - gnutls_cipher_encrypt(cipher, message.data(), message.size()); // Encrypt the message with AES-128 - gnutls_cipher_tag(cipher, mac.data(), mac.size()); // Get the CMAC-AES tag - output = mac; - gnutls_cipher_deinit(cipher); + // CMAC-AES not implemented in GnuTLS + if (!key.empty()) + { + // do nothing + } + if (!input.empty()) + { + // do nothing + } #else // OpenSSL #if USE_OPENSSL_3 std::vector aux(EVP_MAX_MD_SIZE); // CMAC-AES output size @@ -527,7 +541,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); #if USE_GNUTLS_FALLBACK // Import the PEM data - gnutls_datum_t pemDatum = {const_cast(reinterpret_cast(pemContent.data())), static_cast(pemContent.size())}; + gnutls_datum_t pemDatum = {const_cast(reinterpret_cast(const_cast(pemContent.data()))), static_cast(pemContent.size())}; gnutls_pubkey_t pubkey; gnutls_pubkey_init(&pubkey); @@ -680,6 +694,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } bool success = false; #if USE_GNUTLS_FALLBACK +#if HAVE_GNUTLS_SIGN_ECDSA_SHA256 // Convert signature to DER format std::vector der_sig; if (!convert_raw_to_der_ecdsa(signature, der_sig)) @@ -704,6 +719,7 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); } +#endif #else // OpenSSL #if USE_OPENSSL_3 EVP_PKEY_CTX* ctx; @@ -950,7 +966,12 @@ bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) gnutls_datum_t key_datum; // Export the public key from src to memory +#if HAVE_GNUTLS_PUBKEY_EXPORT2 int ret = gnutls_pubkey_export2(src, GNUTLS_X509_FMT_PEM, &key_datum); +#else + size_t output_stata_size; + int ret = gnutls_pubkey_export(src, GNUTLS_X509_FMT_PEM, &key_datum, &output_stata_size); +#endif if (ret < 0) { gnutls_free(key_datum.data); diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 7e0527750..69df8d45d 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -23,6 +23,7 @@ #include #include #if USE_GNUTLS_FALLBACK +#include #include #else // OpenSSL #include From 2f475d6aafbe01113fcb75f8e80a95036ee18b3a Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 1 Jul 2024 02:44:22 +0200 Subject: [PATCH 152/219] Fix CMAC-AES algorithm for OpenSSL 1.x --- src/core/system_parameters/gnss_crypto.cc | 37 +++++++++++++++++++---- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 8ad7e55bb..2062b0674 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -504,20 +504,45 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke aux.resize(output_length); output = aux; #else // OpenSSL 1.x - std::vector mac(16); // CMAC-AES output size + size_t mac_length = 0; // to hold the length of the MAC output // Create CMAC context CMAC_CTX* cmacCtx = CMAC_CTX_new(); - CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr); + if (!cmacCtx) + { + LOG(INFO) << "OSNMA CMAC-AES: Failed to create CMAC context"; + return output; + } - // Compute CMAC-AES - CMAC_Update(cmacCtx, input.data(), input.size()); - CMAC_Final(cmacCtx, mac.data(), nullptr); + // Initialize the CMAC context with the key and cipher + if (1 != CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr)) + { + LOG(INFO) << "OSNMA CMAC-AES: MAC_Init failed"; + CMAC_CTX_free(cmacCtx); + return output; + } + + // Compute the CMAC + if (1 != CMAC_Update(cmacCtx, input.data(), input.size())) + { + LOG(INFO) << "OSNMA CMAC-AES: CMAC_Update failed"; + CMAC_CTX_free(cmacCtx); + return output; + } + + // Finalize the CMAC computation and retrieve the output + if (1 != CMAC_Final(cmacCtx, output.data(), &mac_length)) + { + LOG(INFO) << "OSNMA CMAC-AES:CMAC_Final failed"; + CMAC_CTX_free(cmacCtx); + return output; + } // Clean up CMAC context CMAC_CTX_free(cmacCtx); - output = mac; + // Ensure the output vector is properly sized according to the actual MAC length + output.resize(mac_length); #endif #endif return output; From 4b4f6b9d7f9e1a255c5109979d7d34d4d2c72578 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 1 Jul 2024 22:43:54 +0200 Subject: [PATCH 153/219] Fix CMAC-AES with GnuTLS --- cmake/Modules/GnssSdrCrypto.cmake | 6 ++++ src/core/system_parameters/gnss_crypto.cc | 36 +++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index a5e383790..9649da9da 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -119,6 +119,9 @@ else() if("${gnutls_gnutls_file_contents}" MATCHES "#define GNUTLS_VERSION_MAJOR 2") set(GNUTLS_HMAC_INIT_WITH_DIGEST TRUE) endif() + if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_MAC_AES_CMAC_128") + set(GNUTLS_MAC_AES_CMAC_128 TRUE) + endif() file(READ "${GNUTLS_INCLUDE_DIR}/gnutls/abstract.h" gnutls_abstract_file_contents) if("${gnutls_abstract_file_contents}" MATCHES "gnutls_pubkey_export2") set(GNUTLS_PUBKEY_EXPORT2 TRUE) @@ -184,5 +187,8 @@ function(link_to_crypto_dependencies target) if(GNUTLS_HMAC_INIT_WITH_DIGEST) target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_HMAC_INIT_WITH_DIGEST=1) endif() + if(GNUTLS_MAC_AES_CMAC_128) + target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_MAC_AES_CMAC_128=1) + endif() endif() endfunction() diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 2062b0674..055bd0382 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -436,7 +436,32 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke { std::vector output(16); #if USE_GNUTLS_FALLBACK - // CMAC-AES not implemented in GnuTLS +#if HAVE_GNUTLS_MAC_AES_CMAC_128 + gnutls_hmac_hd_t hmac; + + // Initialize the HMAC context with the CMAC algorithm and key + int ret = gnutls_hmac_init(&hmac, GNUTLS_MAC_AES_CMAC_128, key.data(), key.size()); + if (ret != GNUTLS_E_SUCCESS) + { + LOG(INFO) << "OSNMA CMAC-AES: gnutls_hmac_init failed: " << gnutls_strerror(ret); + return output; + } + + // Update the HMAC context with the input data + ret = gnutls_hmac(hmac, input.data(), input.size()); + if (ret != GNUTLS_E_SUCCESS) + { + LOG(INFO) << "OSNMA CMAC-AES: gnutls_hmac failed: " << gnutls_strerror(ret); + gnutls_hmac_deinit(hmac, nullptr); + return output; + } + + // Retrieve the HMAC output + gnutls_hmac_output(hmac, output.data()); + + // Clean up the HMAC context + gnutls_hmac_deinit(hmac, nullptr); +#else if (!key.empty()) { // do nothing @@ -445,6 +470,7 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke { // do nothing } +#endif #else // OpenSSL #if USE_OPENSSL_3 std::vector aux(EVP_MAX_MD_SIZE); // CMAC-AES output size @@ -515,7 +541,7 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke } // Initialize the CMAC context with the key and cipher - if (1 != CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr)) + if (CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr) != 1) { LOG(INFO) << "OSNMA CMAC-AES: MAC_Init failed"; CMAC_CTX_free(cmacCtx); @@ -523,7 +549,7 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke } // Compute the CMAC - if (1 != CMAC_Update(cmacCtx, input.data(), input.size())) + if (CMAC_Update(cmacCtx, input.data(), input.size()) != 1) { LOG(INFO) << "OSNMA CMAC-AES: CMAC_Update failed"; CMAC_CTX_free(cmacCtx); @@ -531,9 +557,9 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke } // Finalize the CMAC computation and retrieve the output - if (1 != CMAC_Final(cmacCtx, output.data(), &mac_length)) + if (CMAC_Final(cmacCtx, output.data(), &mac_length) != 1) { - LOG(INFO) << "OSNMA CMAC-AES:CMAC_Final failed"; + LOG(INFO) << "OSNMA CMAC-AES: CMAC_Final failed"; CMAC_CTX_free(cmacCtx); return output; } From b77784d1f3ba98ee603266b44725e0eda63df2ef Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Wed, 26 Jun 2024 15:01:05 +0200 Subject: [PATCH 154/219] [TAS-227] [BUG] Tag verification fails for .dat files --- .../galileo_telemetry_decoder_gs.cc | 56 +- src/core/libs/osnma_msg_receiver.cc | 86 ++- src/core/libs/osnma_msg_receiver.h | 2 +- .../system_parameters/galileo_inav_message.cc | 2 +- src/core/system_parameters/osnma_helper.cc | 11 + src/core/system_parameters/osnma_helper.h | 1 + .../osnma/osnma_msg_receiver_test.cc | 513 ++++++++++-------- 7 files changed, 373 insertions(+), 298 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index a404a100a..a84db6946 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -439,6 +439,35 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } // 4. Push the new navigation data to the queues + // extract OSNMA bits, reset container. + bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; + if(check_size_is_ok) + { + std::cout << "Galileo OSNMA: new ADKD=0/12 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW5() - 25 <>( // < PRNd , navDataBits, TOW_Sosf> + d_satellite.get_PRN(), + d_inav_nav.get_osnma_adkd_0_12_nav_bits(), + d_inav_nav.get_TOW5() - 25); + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); + LOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d="<< static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW5() - 25) <<")";//: 0b" << d_inav_nav.get_osnma_adkd_0_12_nav_bits(); + d_inav_nav.reset_osnma_nav_bits_adkd0_12(); + } + + check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; + if(check_size_is_ok) + { + std::cout << "Galileo OSNMA: new ADKD=4 navData from " << d_satellite <<" at TOW_sf=" << d_inav_nav.get_TOW6() - 5 <>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe + d_satellite.get_PRN(), + d_inav_nav.get_osnma_adkd_4_nav_bits(), + d_inav_nav.get_TOW6() - 5); + this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); + LOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d="<< static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW6() - 5) <<")";//: 0b" << d_inav_nav.get_osnma_adkd_4_nav_bits(); + d_inav_nav.reset_osnma_nav_bits_adkd4(); + } + + if (d_inav_nav.have_new_ephemeris() == true) // C: tells if W1-->W4 available from same blcok (and W5!) { // get object for this SV (mandatory) @@ -472,20 +501,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_first_eph_sent = true; // do not send reduced CED anymore, since we have the full ephemeris set // d_flag_osnma_adkd_0_12 = true; // W1-> W5 available - // extract bits, reset container. - bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; - if(check_size_is_ok) - { - std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << d_satellite.get_PRN() << ") " << "TOW_sf=" << d_inav_nav.get_TOW5() - 24 <>( // < PRNd , navDataBits, TOW_Sosf> - d_satellite.get_PRN(), - d_inav_nav.get_osnma_adkd_0_12_nav_bits(), - d_inav_nav.get_TOW5() - 24); - this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); - d_inav_nav.reset_osnma_nav_bits_adkd0_12(); - } - - } else { @@ -615,19 +630,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in // bool adkd_4_nav_data_available = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; // newApproach: let decoder decide when block starts and let it fill the data, and just check for length if(adkd_4_nav_data_available /*&& d_inav_nav.is_TOW5_set() not needed cause W6 has TOW also.*/) { - bool check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; - if(check_size_is_ok) - { - std::cout << "Galileo OSNMA: sending ADKD=4 navData, PRN_d (" << d_satellite.get_PRN() << ") " << "TOW_sf=" << d_inav_nav.get_TOW6() - 4 <>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe - d_satellite.get_PRN(), - d_inav_nav.get_osnma_adkd_4_nav_bits(), - d_inav_nav.get_TOW6() - 4); - this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - d_inav_nav.reset_osnma_nav_bits_adkd4(); - } - } auto newOSNMA = d_inav_nav.have_new_nma(); if (d_band == '1' && newOSNMA) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 4a5e95ac9..e03303a66 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -62,13 +62,13 @@ osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, osnma_msg_receiver::osnma_msg_receiver( - const std::string& pemFilePath, + 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)) { d_dsm_reader = std::make_unique(); - d_crypto = std::make_unique(pemFilePath, merkleFilePath); + d_crypto = std::make_unique(crtFilePath, merkleFilePath); d_helper = std::make_unique(); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); @@ -101,13 +101,13 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); // TODO remove if unneeded std::ostringstream output_message; - output_message << "Galileo OSNMA: Subframe received starting at " - << "WN=" - << nma_msg->WN_sf0 - << ", TOW=" - << nma_msg->TOW_sf0 - << ", from satellite " - << sat; + output_message << "Galileo OSNMA: complete OSNMA message received starting at " + << "WN=" + << nma_msg->WN_sf0 + << ", TOW=" + << nma_msg->TOW_sf0 + << ", from satellite " + << sat; LOG(WARNING) << output_message.str(); std::cout << output_message.str() << std::endl; @@ -125,14 +125,14 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // iono data => 549 bits, utc data, 141 bits. if (nav_data.size() == 549) { - LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " - << "TOW_sf=" << TOW; +// LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " +// << "TOW_sf=" << TOW; d_satellite_nav_data[PRNa][TOW].ephemeris_iono_vector_2 = nav_data; } else if (nav_data.size() == 141) { - LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " - << "TOW_sf=" << TOW; +// LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " +// << "TOW_sf=" << TOW; d_satellite_nav_data[PRNa][TOW].utc_vector_2 = nav_data; } else @@ -203,10 +203,10 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { d_osnma_data.d_dsm_header.dsm_id = d_dsm_reader->get_dsm_id(dsm_header); d_osnma_data.d_dsm_header.dsm_block_id = d_dsm_reader->get_dsm_block_id(dsm_header); // BID - LOG(INFO) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); - LOG(INFO) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); - LOG(INFO) << "Galileo OSNMA: Received block " << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) - << " from DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id); +// LOG(INFO) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); +// LOG(INFO) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); + LOG(INFO) << "Galileo OSNMA: Received block DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) + << " with DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id); } /* @@ -322,8 +322,8 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; // TODO set flag to false to avoid processing dsm and MACK messages @@ -914,13 +914,25 @@ void osnma_msg_receiver::process_mack_message() bool ret = verify_macseq(*mack); if (ret || d_flag_debug) { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; for (std::size_t i = 0; i < mack->tag_and_info.size(); ++i) { // add tags of current mack to the verification queue auto& tag = mack->tag_and_info[i]; Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; + LOG(INFO) << "Galileo OSNMA: Add Tag Id= " + << t.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << t.received_tag << std::dec + << ", TOW=" + << t.TOW + << ", ADKD=" + << static_cast(t.ADKD) + << ", PRNa=" + << static_cast(t.PRNa) + << ", PRNd=" + << static_cast(t.PRN_d); } std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; mack = d_macks_awaiting_MACSEQ_verification.erase(mack); @@ -1070,6 +1082,11 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) bool osnma_msg_receiver::verify_tag(Tag& tag) { + // Debug +// LOG(INFO) << "Galileo OSNMA: Tag verification :: Start for tag Id= " +// << tag.tag_id +// << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase +// << tag.received_tag << std::dec; // TODO case tag0, to be verified here?, PRNd not needed for it // build message std::vector m = build_message(tag); @@ -1077,9 +1094,16 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) std::vector mac; std::vector applicable_key; if (tag.ADKD == 0 || tag.ADKD == 4) - applicable_key = d_tesla_keys[tag.TOW + 30]; - else // ADKD 12 - applicable_key = d_tesla_keys[tag.TOW + 330]; + { + applicable_key = d_tesla_keys[tag.TOW + 30]; +// LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 30); + } + else // ADKD 12 + { + applicable_key = d_tesla_keys[tag.TOW + 330]; +// LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 330); + } + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { @@ -1142,7 +1166,7 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) << ", PRNa=" << static_cast(tag.PRNa) << ", PRNd=" - << static_cast(tag.PRN_d); + << static_cast(tag.PRN_d) << std::endl; return true; } return false; @@ -1171,10 +1195,12 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) if (tag.ADKD == 0 || tag.ADKD == 12) // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. { applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; +// LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else if (tag.ADKD == 4) { applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].utc_vector_2; +// LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else LOG(WARNING) << "Galileo OSNMA :: Tag verification :: unknown ADKD"; @@ -1484,7 +1510,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) if (prn_it != d_satellite_nav_data.end()) { // PRN was found, check if TOW exists in inner map - LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; + //LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; std::map& tow_map = prn_it->second; auto tow_it = tow_map.find(t.TOW - 30); if (tow_it != tow_map.end()) @@ -1500,7 +1526,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) else { // PRN was not found - LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; + //LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; return false; } return false; @@ -1519,7 +1545,7 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t) auto it = d_tesla_keys.find(t.TOW + 30); if (it != d_tesla_keys.end()) { - LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; + //LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; return true; } } @@ -1528,11 +1554,11 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t) auto it = d_tesla_keys.find(t.TOW + 330); if (it != d_tesla_keys.end()) { - LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; + //LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; return true; } } - LOG(INFO) << "Galileo OSNMA: hasKey = false "; + //LOG(INFO) << "Galileo OSNMA: hasKey = false "; return false; } @@ -1601,6 +1627,6 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede // compare computed current key against received key auto end = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed = end - start; - LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; +// LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; return K_II; } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 4e662ef55..aef9fd91e 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -59,7 +59,7 @@ public: ~osnma_msg_receiver() = default; //!< Default destructor private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); - osnma_msg_receiver(const std::string& pemFilePath, const std::string& merkleFilePath); + osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index baa140149..a8509db23 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1417,7 +1417,7 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() nma_position_filled = std::array{}; // Fill TOW and WN nma_msg.WN_sf0 = WN_0; - int32_t TOW_sf0 = TOW_5 - 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start + int32_t TOW_sf0 = TOW_5 - 25;//- 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start TODO review if (TOW_sf0 < 0) { TOW_sf0 += 604800; diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index aa338f408..7cf3165c2 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -16,6 +16,8 @@ #include "osnma_helper.h" #include +#include +#include uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const { @@ -74,3 +76,12 @@ std::string Osnma_Helper::verification_status_str(int status) default: return "UNKNOWN"; } } +std::string Osnma_Helper::convert_to_hex_string(const std::vector& vector) +{ + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for (auto byte : vector) { + ss << std::setw(2) << static_cast(byte); + } + return ss.str(); +} diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 2f8df078b..e78fdba0f 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -30,6 +30,7 @@ public: std::vector gst_to_uint8(uint32_t GST) const; std::vector bytes(const std::string& binaryString); std::string verification_status_str(int status); + std::string convert_to_hex_string(const std::vector& vector); }; #endif // GNSS_SDR_OSNMA_HELPER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 35cb9fd45..7b94baf0c 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -14,42 +15,39 @@ struct TestVector }; // TODO - parametrize class for different configurations (config_1, config_2, etc.. potentially 5 or 6 more) an make sure wont affect current TEST_F +// note: until the test is parametrized for configuration 1 and 2, in order to change between them you have to comment/uncomment the respective calls in this test, identified with comments // conf. 1/2 +// log_name, input_time, crtFilePath, merkleFilePath, testVectors class OsnmaMsgReceiverTest : public ::testing::Test { protected: osnma_msg_receiver_sptr osnma; - Galileo_Inav_Message galileo_message; - uint8_t page_position_in_inav_subframe; - bool flag_CRC_test; - std::string page_even; OSNMA_msg osnma_msg{}; std::array nma_position_filled; - uint32_t d_GST_SIS{}; // 16 AUG 2023 05 00 01 + uint32_t d_GST_SIS{}; uint32_t TOW{}; uint32_t WN{}; - std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm - const uint32_t LEAP_SECONDS = 0; // 13 + 5; + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm + const uint32_t LEAP_SECONDS = 0; //13 + 5; void set_time(std::tm& input); - // std::string log_name {"CONFIG1-2023-08-23-PKID1-OSNMA"}; - std::string log_name{"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; - // void initializeGoogleLog(); +// std::string log_name {"CONFIG1-2023-08-16-PKID1-OSNMA"}; + std::string log_name {"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; + void initializeGoogleLog(); void SetUp() override { - flag_CRC_test = false; // TODO what for? - page_even = ""; - - // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; - std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; + initializeGoogleLog(); +// std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 set_time(input_time); - // std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.pem"; - // std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; - std::string pemFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.pem"; +// std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.crt"; // conf. 1 +// std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; + std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; - osnma = osnma_msg_receiver_make(pemFilePath, merkleFilePath); + osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); } public: + static std::vector parseNavBits(const std::string& hex); static std::vector readTestVectorsFromFile(const std::string& filename); std::string bytes_to_str(const std::vector& bytes); @@ -57,85 +55,199 @@ public: }; -TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) +TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) { + // Arrange + // ---------- + // m0 + std::vector expected_message = { + 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, + 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, + 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, + 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, + 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00 + }; + + uint32_t TOW_Tag0 = 345660; + uint32_t TOW_NavData = TOW_Tag0 - 30; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t WN = 1248; + uint32_t PRNa = 2; + uint8_t CTR = 1; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MACK_tag_and_info MTI; + MTI.tag = static_cast(0xE37BC4F858); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x00; + MTI.tag_info.cop = 0x0F; + Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + + + + // Act + // ---------- + auto computed_message = osnma->build_message(t0); + + + // Assert + // ---------- + ASSERT_TRUE(computed_message == expected_message); + +} + +TEST_F(OsnmaMsgReceiverTest, TagVerification) { + // Arrange + // ---------- + // Tag0 + uint32_t TOW_Tag0 = 345660; + uint32_t TOW_NavData = TOW_Tag0 - 30; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t WN = 1248; + uint32_t PRNa = 2; + uint8_t CTR = 1; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MACK_tag_and_info MTI; + MTI.tag = static_cast(0xE37BC4F858); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x00; + MTI.tag_info.cop = 0x0F; + Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + + + + // Act + // ---------- + bool result_tag0 = osnma->verify_tag(t0); + + + + + + // Assert + // ---------- + //ASSERT_TRUE(result_tag0); + + // Tag3 + uint32_t TOW_Tag3 = 345660; + uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; + uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30 ; + WN = 1248; + PRNa = 2; + CTR = 3; + + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].utc_vector_2 = + "111111111111111111111111111111110000000000000000000000010001001001001000" + "111000001000100111100010010111111111011110111111111001001100000100000000"; + osnma->d_osnma_data.d_nma_header.nmas = 0b10; + + MTI.tag = static_cast(0x7BB238C883); + MTI.tag_info.PRN_d = 0x02; + MTI.tag_info.ADKD = 0x04; + MTI.tag_info.cop = 0x0F; + Tag t3(MTI, TOW_Tag0, WN, PRNa, CTR); + + bool result_tag3 = osnma->verify_tag(t3); + + ASSERT_TRUE(result_tag0 && result_tag3); + +} + +TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { // Arrange // ---------- osnma->d_tesla_key_verified = false; - osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 - osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits + osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 + osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; // local_time_verification would do this operation. TODO - eliminate duplication. osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); - osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) - osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; + osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; - osnma->d_tesla_keys.insert((std::pair>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. - std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 + osnma->d_tesla_keys.insert((std::pair>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. + std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 uint32_t TOW = 345630; + + + // Act // ---------- bool result = osnma->verify_tesla_key(key, TOW); + + + + // Assert // ---------- ASSERT_TRUE(result); -} +} TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) { - // initializeGoogleLog(); // Arrange // ---------- - // std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); - std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); - if (testVectors.empty()) - { +// std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); // conf. 1 + std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 + if (testVectors.empty()){ ASSERT_TRUE(false); } bool end_of_hex_stream{false}; int offset_byte{0}; - int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size - const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page - const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe - const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES * SIZE_SUBFRAME_PAGES}; // total bytes of a subframe - const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds + int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size + const int SIZE_PAGE_BYTES{240/8}; // total bytes of a page + const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe + const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; // total bytes of a subframe + const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds const int DUMMY_PAGE{63}; bool flag_dummy_page{false}; - std::cout << "OsnmaTestVectorsSimulation:" - << " d_GST_SIS= " << d_GST_SIS - << ", TOW=" << TOW - << ", WN=" << WN << std::endl; + std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; + + + // Act // ---------- // loop over all bytes of data. Note: all TestVectors have same amount of data. - while (end_of_hex_stream == false) - { + while (end_of_hex_stream == false){ // loop over all SVs, extract a subframe - for (const TestVector& tv : testVectors) - { // loop over all SVs, extract a subframe - std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; + for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe + std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) "<< tv.svId << std::endl; auto osnmaMsg_sptr = std::make_shared(); std::array hkroot{}; std::array mack{}; - byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) - std::map> words; // structure containing and + byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) + std::map> words_for_OSNMA; // structure containing and - for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe + for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe { // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index - std::vector page_bytes = extract_page_bytes(tv, byte_index, SIZE_PAGE_BYTES); - if (page_bytes.empty()) - { - std::cout << "OsnmaTestVectorsSimulation: end of TestVectors \n" - << "byte_index=" << byte_index << " expected= " << 432000 / 8 << std::endl; + std::vector page_bytes = extract_page_bytes(tv,byte_index,SIZE_PAGE_BYTES); + if(page_bytes.empty()){ + std::cout<< "OsnmaTestVectorsSimulation: end of TestVectors \n" << "byte_index="< data_k(even_page.substr(2, 112)); - std::bitset<16> data_j(odd_page.substr(2, 16)); + std::bitset<112> data_k(even_page.substr(2,112)); + std::bitset<16> data_j(odd_page.substr(2,16)); std::bitset<112> shifted_data_k = data_k; - // uint8_t word_type = 0; - // for(int i = 0; i < 6; ++i) { - // word_type |= (data_k[104 + i] << i); - // } - uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word - std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast(word_type) << std::endl; - if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) + uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word + std::cout<< "OsnmaTestVectorsSimulation: received Word "<< static_cast(word_type) << std::endl; + if( (word_type >= 1 && word_type <=5) || word_type == 6 || word_type == 10) { // store raw word std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); - words[word_type] = data_combined; + words_for_OSNMA[word_type] = data_combined; } - if (word_type == DUMMY_PAGE) + if(word_type == DUMMY_PAGE) flag_dummy_page = true; + // place it into osnma object. std::bitset<40> osnmaBits(odd_page.substr(18, 40)); + // Extract bits for hkroot and mack std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8)); std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32)); @@ -183,13 +291,12 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) byte_index += SIZE_PAGE_BYTES; } - std::cout << "----------" << std::endl; - if (end_of_hex_stream) + std::cout<< "----------" << std::endl; + if(end_of_hex_stream) break; - if (flag_dummy_page) - { + if(flag_dummy_page){ flag_dummy_page = false; - continue; // skip this SV + continue; // skip this SV } // Fill osnma object @@ -197,26 +304,26 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) osnmaMsg_sptr->mack = mack; osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; - osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20; - osnmaMsg_sptr->PRN = tv.svId; // PRNa + osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ; + osnmaMsg_sptr->PRN = tv.svId; // PRNa // TODO - refactor this logic, currently it is split - // check if words 1--> 5 words are received => fill EphClockStatus data vector + // check if words_for_OSNMA 1--> 5 words_for_OSNMA are received => fill EphClockStatus data vector bool ephClockStatusWordsReceived = true; for (int i = 1; i <= 5; ++i) { - if (words.find(i) == words.end()) + if (words_for_OSNMA.find(i) == words_for_OSNMA.end()) { ephClockStatusWordsReceived = false; - std::cerr << "OsnmaTestVectorsSimulation: error parsing words 1->5. " - "Word " - << i << " should be received for each subframe but was not." << std::endl; + std::cerr<< "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " + "Word "<< i << " should be received for each subframe but was not." << std::endl; } } // extract bits as needed by osnma block - if (ephClockStatusWordsReceived) + if(ephClockStatusWordsReceived) { + // Define the starting position and length of bits to extract for each word std::map> extractionParams = { {1, {6, 120}}, @@ -226,41 +333,41 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) {5, {6, 67}}, }; - // Fill NavData bits -- Iterate over the extraction parameters // Fill NavData bits -- Iterate over the extraction parameters + // Fill NavData bits -- Iterate over the extraction parameters std::string nav_data_ADKD_0_12 = ""; - for (const auto& param : extractionParams) - { + for (const auto& param : extractionParams) { uint8_t wordKey = param.first; uint8_t start = param.second.first; uint8_t length = param.second.second; // Extract the required bits and fill osnma block - nav_data_ADKD_0_12 += words[wordKey].to_string().substr(start, length); + nav_data_ADKD_0_12 += words_for_OSNMA[wordKey].to_string().substr(start, length); } // send to osnma block bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; - if (check_size_is_ok) + if(check_size_is_ok) { - std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " - << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; - const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> + std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <>( // < PRNd , navDataBits, TOW_Sosf> tv.svId, nav_data_ADKD_0_12, osnmaMsg_sptr->TOW_sf0); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) <<"): 0b" << nav_data_ADKD_0_12; osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + } } // check w6 && w10 is received => fill TimingData data vector - bool timingWordsReceived = words.find(6) != words.end() && - words.find(10) != words.end(); + bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() && + words_for_OSNMA.find(10) != words_for_OSNMA.end(); // extract bits as needed by osnma block - if (timingWordsReceived) - { + if(timingWordsReceived){ // Define the starting position and length of bits to extract for each word std::map> extractionParams = { {6, {6, 99}}, - {10, {86, 42}}}; + {10, {86, 42}} + }; std::string nav_data_ADKD_4 = ""; // Fill NavData bits -- Iterate over the extraction parameters @@ -271,42 +378,42 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) uint8_t length = param.second.second; // Extract the required bits and fill osnma block - nav_data_ADKD_4 += words[wordKey].to_string().substr( - start, length); + nav_data_ADKD_4 += words_for_OSNMA[wordKey].to_string().substr(start, length); } - // send to osnma block bool check_size_is_ok = nav_data_ADKD_4.size() == 141; - if (check_size_is_ok) + if(check_size_is_ok) { - std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " - << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; - const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> + std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <>( // < PRNd , navDataBits, TOW_Sosf> tv.svId, nav_data_ADKD_4, osnmaMsg_sptr->TOW_sf0); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) <<"): 0b" << nav_data_ADKD_4; osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + } + } // Call the handler, as if it came from telemetry decoder block auto temp_obj = pmt::make_any(osnmaMsg_sptr); - osnma->msg_handler_osnma(temp_obj); // osnma entry point + osnma->msg_handler_osnma(temp_obj); // osnma entry point } - if (!end_of_hex_stream) - { - offset_byte = byte_index; // update offset for the next subframe + if(!end_of_hex_stream){ + offset_byte = byte_index; // update offset for the next subframe d_GST_SIS += DURATION_SUBFRAME; TOW = d_GST_SIS & 0x000FFFFF; - WN = (d_GST_SIS & 0xFFF00000) >> 20; - std::cout << "OsnmaTestVectorsSimulation:" - << " d_GST_SIS= " << d_GST_SIS + WN = (d_GST_SIS & 0xFFF00000) >> 20 ; + std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS << ", TOW=" << TOW << ", WN=" << WN << std::endl; } + + } @@ -316,24 +423,22 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) } - +// Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. +// Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std::string& filename) { std::ifstream file(filename); std::vector testVectors; - if (!file.is_open()) - { - std::cerr << "Error reading the file \"" << filename << "\" \n"; + if (!file.is_open()) { + std::cerr<<"Error reading the file \"" << filename <<"\" \n"; return testVectors; } std::string line; std::getline(file, line); - if (line != "SVID,NumNavBits,NavBitsHEX\r") - { - std::cerr << "Error parsing first line" - << "\n"; - } + if (line != "SVID,NumNavBits,NavBitsHEX\r" ){ + std::cerr<<"Error parsing first line" <<"\n"; + } while (std::getline(file, line)) { @@ -356,35 +461,29 @@ std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std: return testVectors; } - - std::vector OsnmaMsgReceiverTest::parseNavBits(const std::string& hex) { std::vector bytes; - for (unsigned int i = 0; i < hex.length() - 1; i += 2) + for (unsigned int i = 0; i < hex.length()-1; i += 2) { std::string byteString = hex.substr(i, 2); - uint8_t byte = (uint8_t)strtol(byteString.c_str(), NULL, 16); + uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16); bytes.push_back(byte); } return bytes; } - - std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector& bytes) { std::string bit_string; bit_string.reserve(bytes.size() * 8); - for (const auto& byte : bytes) + for(const auto& byte : bytes) { std::bitset<8> bits(byte); bit_string += bits.to_string(); } return bit_string; } - - /** * @brief Extracts a range of bytes from a TestVector's navBits vector. * @@ -413,8 +512,6 @@ std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& return extracted_bytes; } - - /** * @brief Sets the time based on the given input. * @@ -438,118 +535,56 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) uint32_t sec_in_week = 7 * 24 * 60 * 60; uint32_t week_number = duration_sec.count() / sec_in_week; uint32_t time_of_week = duration_sec.count() % sec_in_week; - this->WN = week_number; - this->TOW = time_of_week + LEAP_SECONDS; + this->WN = week_number; + this->TOW = time_of_week + LEAP_SECONDS; // Return the week number and time of week as a pair // TODO: d_GST_SIS or d_receiver_time? doubt // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 - this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); + this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); + + } - - -TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) +void OsnmaMsgReceiverTest::initializeGoogleLog() { - // Arrange - // ---------- - // m0 - std::vector expected_message = { - 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, - 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, - 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, - 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, - 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00}; - - uint32_t TOW_Tag0 = 345660; - uint32_t TOW_NavData = TOW_Tag0 - 30; - uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; - uint32_t WN = 1248; - uint32_t PRNa = 2; - uint8_t CTR = 1; - - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 - osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; - osnma->d_osnma_data.d_nma_header.nmas = 0b10; - - MACK_tag_and_info MTI; - MTI.tag = static_cast(0xE37BC4F858); - MTI.tag_info.PRN_d = 0x02; - MTI.tag_info.ADKD = 0x00; - MTI.tag_info.cop = 0x0F; - Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); - - - // Act - // ---------- - auto computed_message = osnma->build_message(t0); - - - // Assert - // ---------- - ASSERT_TRUE(computed_message == expected_message); + google::InitGoogleLogging(log_name.c_str()); + FLAGS_minloglevel = 0; // INFO + FLAGS_logtostderr = 0; // add this line + FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; + if (FLAGS_log_dir.empty()) + { + std::cout << "Logging will be written at " + << std::filesystem::temp_directory_path() + << '\n' + << "Use gnss-sdr --log_dir=/path/to/log to change that.\n"; + } + else + { + try + { + const std::filesystem::path p(FLAGS_log_dir); + if (!std::filesystem::exists(p)) + { + std::cout << "The path " + << FLAGS_log_dir + << " does not exist, attempting to create it.\n"; + std::error_code ec; + if (!std::filesystem::create_directory(p, ec)) + { + std::cout << "Could not create the " << FLAGS_log_dir << " folder.\n"; + gflags::ShutDownCommandLineFlags(); + throw std::runtime_error("Could not create folder for logs"); + } + } + std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; + } + catch (const std::exception& e) + { + std::cerr << e.what() << '\n'; + std::cerr << "Could not create the " << FLAGS_log_dir << " folder.\n"; + gflags::ShutDownCommandLineFlags(); + throw; + } + } } - -TEST_F(OsnmaMsgReceiverTest, TagVerification) -{ - // Arrange - // ---------- - // Tag0 - uint32_t TOW_Tag0 = 345660; - uint32_t TOW_NavData = TOW_Tag0 - 30; - uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; - uint32_t WN = 1248; - uint32_t PRNa = 2; - uint8_t CTR = 1; - - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 - osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; - osnma->d_osnma_data.d_nma_header.nmas = 0b10; - - MACK_tag_and_info MTI; - MTI.tag = static_cast(0xE37BC4F858); - MTI.tag_info.PRN_d = 0x02; - MTI.tag_info.ADKD = 0x00; - MTI.tag_info.cop = 0x0F; - Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); - - - // Act - // ---------- - bool result_tag0 = osnma->verify_tag(t0); - - - // Assert - // ---------- - // ASSERT_TRUE(result_tag0); - - // Tag3 - uint32_t TOW_Tag3 = 345660; - uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; - uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30; - WN = 1248; - PRNa = 2; - CTR = 3; - - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 - osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].utc_vector_2 = - "111111111111111111111111111111110000000000000000000000010001001001001000" - "111000001000100111100010010111111111011110111111111001001100000100000000"; - osnma->d_osnma_data.d_nma_header.nmas = 0b10; - - MTI.tag = static_cast(0x7BB238C883); - MTI.tag_info.PRN_d = 0x02; - MTI.tag_info.ADKD = 0x04; - MTI.tag_info.cop = 0x0F; - Tag t3(MTI, TOW_Tag0, WN, PRNa, CTR); - - bool result_tag3 = osnma->verify_tag(t3); - - ASSERT_TRUE(result_tag0 && result_tag3); -} From aede664b5a91a013aeadab186f2fc1373b39600e Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Wed, 3 Jul 2024 18:45:40 +0200 Subject: [PATCH 155/219] [TAS-232 ] [FEAT] verify tag m0 * add new constructor to Tag for Tag0 * minor reporting and comments. * forgot an include from fix5 merge * gitignore release folder --- .gitignore | 3 ++- src/core/libs/osnma_msg_receiver.cc | 21 +++++++------------ src/core/system_parameters/osnma_data.h | 18 ++++++++++++++-- .../osnma/osnma_msg_receiver_test.cc | 2 ++ 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index c16e1f808..dd9645f6d 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ cmake-build-debug/ .vscode/ .vs/ Testing/ -/build/* \ No newline at end of file +/build/* +/cmake-build-release/* \ No newline at end of file diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index d9726e269..7b5fbe51b 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -601,14 +601,10 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrPRN,osnma_msg->TOW_sf0,d_osnma_data.d_nav_data); // TODO change place - // DEBUG PARSING MACK MESSAGES WHEN DSM-KROOT NOT YET AVAILABLE - // d_osnma_data.d_dsm_kroot_message.ts = 9; - // d_osnma_data.d_dsm_kroot_message.ks = 4; - // d_osnma_data.d_dsm_kroot_message.kroot = std::vector(16); + d_osnma_data.d_nav_data.init(osnma_msg); + if (d_kroot_verified || d_tesla_key_verified || d_osnma_data.d_dsm_kroot_message.ts != 0 /*mack parser needs to know the tag size, otherwise cannot parse mack messages*/) // C: 4 ts < ts < 10 - { // TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future + {// TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future 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; @@ -911,6 +907,9 @@ void osnma_msg_receiver::process_mack_message() { if (d_tesla_keys.find(mack->TOW + 30) != d_tesla_keys.end()) { + // add tag0 first + Tag tag0 (*mack); + d_tags_awaiting_verify.insert(std::pair(mack->TOW, tag0)); bool ret = verify_macseq(*mack); if (ret || d_flag_debug) { @@ -1001,6 +1000,7 @@ void osnma_msg_receiver::process_mack_message() } else if (it.second.TOW > d_osnma_data.d_nav_data.TOW_sf0) { + // TODO - I dont understand logic. This needs to be reviewed. // case 1: adkd=12 and t.Tow + 300 < current TOW // case 2: adkd=0/4 and t.Tow + 30 < current TOW // case 3: any adkd and t.Tow > current TOW @@ -1087,7 +1087,6 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) // << tag.tag_id // << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase // << tag.received_tag << std::dec; - // TODO case tag0, to be verified here?, PRNd not needed for it // build message std::vector m = build_message(tag); @@ -1428,10 +1427,6 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) { applicable_sequence = sq2; } - else - { - LOG(WARNING) << "Galileo OSNMA: Mismatch in the GST verification."; - } if (mack.tag_and_info.size() != applicable_sequence.size() - 1) { LOG(WARNING) << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!"; @@ -1450,7 +1445,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) else if (mack.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i + 1])) { LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: ADKD mismatch against MAC Look-up table."; - return false; // C: suffices one incorrect to abort and not process the rest of the tags + return false; // TODO macseq shall be individual to each tag, a wrongly verified macseq should not discard the whole MACK tags } } diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index b27f6dfb3..aed9ae685 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -171,7 +171,7 @@ public: SUCCESS, FAIL, UNVERIFIED}; - Tag(const MACK_tag_and_info& MTI, uint32_t TOW,uint32_t WN, uint32_t PRNa,uint8_t CTR) + Tag(const MACK_tag_and_info& MTI, uint32_t TOW,uint32_t WN, uint32_t PRNa,uint8_t CTR) // standard tag constructor, for tags within Tag&Info field : tag_id(id_counter++), TOW(TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, NavData missing WN(WN), @@ -186,7 +186,21 @@ public: skipped(0) { } - + Tag(const MACK_message& mack) // constructor for Tag0 + : tag_id(id_counter++), + TOW(mack.TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, NavData missing + WN(mack.WN), + PRNa(mack.PRNa), + CTR(1), + status(UNVERIFIED), + received_tag(mack.header.tag0), + computed_tag(0), + PRN_d(mack.PRNa), // Tag0 are self-authenticating + ADKD(0), + cop(mack.header.cop), + skipped(0) + { + } const uint32_t tag_id; uint32_t TOW; uint32_t WN; diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index f001bab72..f7ff50fe7 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -7,6 +7,7 @@ #if USE_GLOG_AND_GFLAGS #include // for LOG +#include #else #include #endif @@ -557,6 +558,7 @@ void OsnmaMsgReceiverTest::initializeGoogleLog() FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; if (FLAGS_log_dir.empty()) { + std::cout << "Logging will be written at " << std::filesystem::temp_directory_path() << '\n' From f534ef859c4cd3ffe0dd01a9077f9cd8c19c87fc Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 9 Jul 2024 17:13:40 +0200 Subject: [PATCH 156/219] [TAS-212] [TEST] implement tests for DSM-PKR Verification * VerifyPublicKey, ComputeBaseLeaf, ComputeMerkleRoot * Refactored verify_dsm_pkr to allow for the new tests * add convert_from_hex function in the helper --- src/core/libs/osnma_msg_receiver.cc | 62 +++++++++------ src/core/libs/osnma_msg_receiver.h | 36 +++++---- src/core/system_parameters/gnss_crypto.h | 3 + src/core/system_parameters/osnma_helper.cc | 24 +++++- src/core/system_parameters/osnma_helper.h | 7 +- .../osnma/osnma_msg_receiver_test.cc | 78 ++++++++++++++++++- 6 files changed, 164 insertions(+), 46 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 7b5fbe51b..1d1414c45 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -1027,56 +1027,70 @@ void osnma_msg_receiver::process_mack_message() } +/** + * @brief Verify received DSM-PKR message + * + * \details This method provides the functionality to verify the DSM-PKR message. The verification includes generating the base leaf + * and intermediate leafs, and comparing the computed merkle root leaf with the received one. + * \pre DSM_PKR_message correctly filled in especially the 1024 intermediate tree nodes + * \returns true if computed merkle root matches received one, false otherwise + */ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) { - // TODO create function for recursively apply hash + std::vector computed_merkle_root; // x_4_0 + std::vector base_leaf = compute_base_leaf(message); // m_i - // build base leaf m_i - std::vector m_i; - m_i.reserve(2 + message.npk.size()); - m_i.push_back((message.npkt << 4) + message.npktid); - for (uint8_t i = 0; i < message.npk.size(); i++) - { - m_i.push_back(message.npk[i]); - } - - // compute intermediate leafs' values - // std::vector x_0,x_1,x_2,x_3,x_4; LOG(INFO) << "Galileo OSNMA: DSM-PKR :: leaf provided: m_" << static_cast(message.mid); + computed_merkle_root = compute_merke_root(message, base_leaf); + + if (computed_merkle_root == d_crypto->getMerkleRoot()) + { + LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: SUCCESS!." << std::endl; + return true; + } + else + { + LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: FAILURE." << std::endl; + return false; + } +} +std::vector osnma_msg_receiver::compute_merke_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const +{ std::vector x_next, x_current = d_crypto->computeSHA256(m_i); for (size_t i = 0; i < 4; i++) { x_next.clear(); - bool leaf_is_on_right = ((message.mid / (1 << (i))) % 2) == 1; + bool leaf_is_on_right = ((dsm_pkr_message.mid / (1 << (i))) % 2) == 1; if (leaf_is_on_right) { // Leaf is on the right -> first the itn, then concatenate the leaf - x_next.insert(x_next.end(), &message.itn[32 * i], &message.itn[32 * i + 32]); + x_next.insert(x_next.end(), &dsm_pkr_message.itn[32 * i], &dsm_pkr_message.itn[32 * i + 32]); x_next.insert(x_next.end(), x_current.begin(), x_current.end()); } else { // Leaf is on the left -> first the leaf, then concatenate the itn x_next.insert(x_next.end(), x_current.begin(), x_current.end()); - x_next.insert(x_next.end(), &message.itn[32 * i], &message.itn[32 * i + 32]); + x_next.insert(x_next.end(), &dsm_pkr_message.itn[32 * i], &dsm_pkr_message.itn[32 * i + 32]); } // Compute the next node. x_current = d_crypto->computeSHA256(x_next); } - - if (x_current == d_crypto->getMerkleRoot()) + return x_current; +} +std::vector osnma_msg_receiver::compute_base_leaf(const DSM_PKR_message& dsm_pkr_message) const +{ // build base leaf m_i + std::vector m_i; + m_i.reserve(2 + dsm_pkr_message.npk.size()); + m_i.push_back((dsm_pkr_message.npkt << 4) + dsm_pkr_message.npktid); + for (uint8_t i = 0; i < dsm_pkr_message.npk.size(); i++) { - LOG(INFO) << "Galileo OSNMA: DSM-PKR verified successfully! " << std::endl; - return true; - } - else - { - LOG(INFO) << "Galileo OSNMA: DSM-PKR verification unsuccessful !" << std::endl; - return false; + m_i.push_back(dsm_pkr_message.npk[i]); } + return m_i; } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index aef9fd91e..8bb8eb452 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -69,26 +69,35 @@ private: void local_time_verification(const std::shared_ptr& osnma_msg); void process_dsm_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); - bool verify_dsm_pkr(DSM_PKR_message message); void read_and_process_mack_block(const std::shared_ptr& osnma_msg); void read_mack_header(); void read_mack_body(); void process_mack_message(); void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData &data); - bool verify_tesla_key(std::vector& key, uint32_t TOW); + void remove_verified_tags(); + void control_tags_awaiting_verify_size(); + std::vector build_message(const Tag& tag); std::vector hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes); - void display_data();bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); + std::vector compute_base_leaf(const DSM_PKR_message& dsm_pkr_message) const; + std::vector compute_merke_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const; + void display_data(); + bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); + bool verify_tesla_key(std::vector& key, uint32_t TOW); bool verify_tag(Tag& tag); bool is_next_subframe(); bool tag_has_nav_data_available(Tag& t); bool tag_has_key_available(Tag& t); + bool verify_macseq(const MACK_message& mack); + bool verify_dsm_pkr(DSM_PKR_message message); + enum tags_to_verify{all,utc,slow_eph, eph, none}; + tags_to_verify d_tags_allowed{tags_to_verify::all}; std::map> d_satellite_nav_data; // map holding NavData sorted by SVID (first key) and TOW (second key). std::map> d_tesla_keys; // tesla keys over time, sorted by TOW std::vector d_macks_awaiting_MACSEQ_verification; std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW - std::unique_ptr d_dsm_reader; - std::unique_ptr d_crypto; + std::unique_ptr d_dsm_reader; // osnma parameters parser + std::unique_ptr d_crypto; // access to cryptographic functions std::unique_ptr d_helper; std::array, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself. @@ -104,27 +113,26 @@ private: bool d_flag_debug{false}; uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification TODO need really to be global var? uint32_t d_last_verified_key_GST{0}; + uint32_t d_GST_0 {}; + uint32_t d_GST_SIS {}; + std::time_t d_receiver_time {0}; uint8_t d_Lt_min {}; // minimum equivalent tag length uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing uint8_t const d_T_L{30}; // s RG Section 2.1 uint8_t const d_delta_COP{30}; // s SIS ICD Table 14 - uint32_t d_GST_0 {}; - uint32_t d_GST_SIS {}; - std::time_t d_receiver_time {0}; - enum tags_to_verify{all,utc,slow_eph, eph, none}; // TODO is this safe? I hope so - tags_to_verify d_tags_allowed{tags_to_verify::all}; + std::vector d_tags_to_verify{0,4,12}; std::vector d_validated_key{}; - void remove_verified_tags(); - void control_tags_awaiting_verify_size(); - bool verify_macseq(const MACK_message& mack); + // Provide access to inner functions to Gtest FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); FRIEND_TEST(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation); FRIEND_TEST(OsnmaMsgReceiverTest, TagVerification); FRIEND_TEST(OsnmaMsgReceiverTest, BuildTagMessageM0); - std::vector build_message(const Tag& tag); + FRIEND_TEST(OsnmaMsgReceiverTest, VerifyPublicKey); + FRIEND_TEST(OsnmaMsgReceiverTest, ComputeBaseLeaf); + FRIEND_TEST(OsnmaMsgReceiverTest, ComputeMerkleRoot); }; diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 69df8d45d..c0de86e24 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -54,6 +54,9 @@ public: { return d_x_4_0; } + inline void setMerkleRoot(std::vector v){ + d_x_4_0 = v; + } private: void read_merkle_xml(const std::string& merkleFilePath); diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index bd469a079..2002c72ca 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -47,7 +47,7 @@ std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const * @param binaryString The binary string to be converted. * @return The vector of bytes converted from the binary string. */ -std::vector Osnma_Helper::bytes(const std::string& binaryString) { +std::vector Osnma_Helper::bytes(const std::string& binaryString) const { std::vector bytes; // Determine the size of the padding needed. @@ -68,7 +68,7 @@ std::vector Osnma_Helper::bytes(const std::string& binaryString) { return bytes; } -std::string Osnma_Helper::verification_status_str(int status) +std::string Osnma_Helper::verification_status_str(const int& status) const { switch (status) { case 0: return "SUCCESS"; @@ -77,7 +77,7 @@ std::string Osnma_Helper::verification_status_str(int status) default: return "UNKNOWN"; } } -std::string Osnma_Helper::convert_to_hex_string(const std::vector& vector) +std::string Osnma_Helper::convert_to_hex_string(const std::vector& vector) const { std::stringstream ss; ss << std::hex << std::setfill('0'); @@ -86,3 +86,21 @@ std::string Osnma_Helper::convert_to_hex_string(const std::vector& vect } return ss.str(); } + +std::vector Osnma_Helper::convert_from_hex_string(const std::string& hex_string) const +{ + std::vector result; + + std::string adjusted_hex_string = hex_string; + if (hex_string.length() % 2 != 0) { + adjusted_hex_string = "0" + hex_string; + } + + for (std::size_t i = 0; i < adjusted_hex_string.length(); i += 2) { + std::string byte_string = adjusted_hex_string.substr(i, 2); + uint8_t byte = static_cast(std::stoul(byte_string, nullptr, 16)); + result.push_back(byte); + } + + return result; +} diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index e78fdba0f..761306efc 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -28,9 +28,10 @@ public: ~Osnma_Helper() = default; uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; std::vector gst_to_uint8(uint32_t GST) const; - std::vector bytes(const std::string& binaryString); - std::string verification_status_str(int status); - std::string convert_to_hex_string(const std::vector& vector); + std::vector bytes(const std::string& binaryString) const; + std::string verification_status_str(const int& status) const; + std::string convert_to_hex_string(const std::vector& vector) const ; + std::vector convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto }; #endif // GNSS_SDR_OSNMA_HELPER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index f7ff50fe7..6b7f280a4 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -6,6 +6,8 @@ #include #if USE_GLOG_AND_GFLAGS +#include "osnma_helper.h" +#include "gnss_crypto.h" #include // for LOG #include #else @@ -25,6 +27,7 @@ struct TestVector class OsnmaMsgReceiverTest : public ::testing::Test { protected: + Osnma_Helper helper; osnma_msg_receiver_sptr osnma; OSNMA_msg osnma_msg{}; std::array nma_position_filled; @@ -59,6 +62,77 @@ public: std::vector extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes); }; +TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot) +{ + // Arrange + // ---------- + std::vector computed_merkle_root; + std::vector expected_merkle_root = helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D"); + DSM_PKR_message dsm_pkr_message; + dsm_pkr_message.npkt = 0x01; + dsm_pkr_message.npktid = 0x2; + dsm_pkr_message.mid = 0x01; + std::vector base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); + + std::vector vec = helper.convert_from_hex_string("7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06" + "956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7" + "407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1" + "24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87"); + std::copy(vec.begin(), vec.end(), dsm_pkr_message.itn.begin()); + dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); + + // Act + // ---------- + computed_merkle_root = osnma->compute_merke_root(dsm_pkr_message,base_leaf); + + // Assert + // ---------- + ASSERT_EQ(computed_merkle_root, expected_merkle_root); +} + +TEST_F(OsnmaMsgReceiverTest, ComputeBaseLeaf) +{ + // Arrange + // ---------- + std::vector expected_base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); + DSM_PKR_message dsm_pkr_message; + dsm_pkr_message.npkt = 0x01; + dsm_pkr_message.npktid = 0x2; + dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); + + // Act + // ---------- + std::vector computed_base_leaf = osnma->compute_base_leaf(dsm_pkr_message); + + // Assert + // ---------- + ASSERT_EQ(computed_base_leaf,expected_base_leaf); +} + +TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey){ // values taken from RG A.7 + // Arrange + // ---------- + osnma->d_crypto->setMerkleRoot(helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D")); + DSM_PKR_message dsm_pkr_message; + dsm_pkr_message.npkt = 0x01; + dsm_pkr_message.npktid = 0x2; + dsm_pkr_message.mid = 0x01; + std::vector vec = helper.convert_from_hex_string("7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06" + "956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7" + "407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1" + "24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87"); + std::copy(vec.begin(), vec.end(), dsm_pkr_message.itn.begin()); + dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); + + // Act + // ---------- + bool result = osnma->verify_dsm_pkr(dsm_pkr_message); + + // Assert + // ---------- + ASSERT_TRUE(result); + +} TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) { @@ -552,10 +626,10 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) } void OsnmaMsgReceiverTest::initializeGoogleLog() { - google::InitGoogleLogging(log_name.c_str()); + google::InitGoogleLogging(log_name.c_str()); // TODO - running all tests causes conflict due to being called twice FLAGS_minloglevel = 0; // INFO FLAGS_logtostderr = 0; // add this line - FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/build/src/tests/logs"; + FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/data/build/src/tests/logs"; if (FLAGS_log_dir.empty()) { From fdb6c079e9cfd69c677b776d4ef95979a0a68522 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 15 Jul 2024 17:11:18 +0200 Subject: [PATCH 157/219] [TAS-223][FEAT] discard only failed FLX tags, not all belonging to MACK Refactored the verification process of MAC sequences in the OSNMA message receiver. Added a function to selectively verify and return tags for which the verification was successful. Replaced usage of direct verification and tag addition with calls to this function. Made corresponding changes to the data structure to accommodate a counter for each tag. --- src/core/libs/osnma_msg_receiver.cc | 175 ++++++++++++++++++++---- src/core/libs/osnma_msg_receiver.h | 1 + src/core/system_parameters/osnma_data.h | 2 +- 3 files changed, 149 insertions(+), 29 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 1d1414c45..74b46f7dc 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -855,6 +855,7 @@ void osnma_msg_receiver::read_mack_body() } } d_osnma_data.d_mack_message.tag_and_info[k].tag = tag; + d_osnma_data.d_mack_message.tag_and_info[k].counter = k + 2; // CTR==1 for Tag0, increases subsequently for all other tags. d_osnma_data.d_mack_message.tag_and_info[k].tag_info.PRN_d = PRN_d; d_osnma_data.d_mack_message.tag_and_info[k].tag_info.ADKD = ADKD; d_osnma_data.d_mack_message.tag_and_info[k].tag_info.cop = cop; @@ -910,36 +911,30 @@ void osnma_msg_receiver::process_mack_message() // add tag0 first Tag tag0 (*mack); d_tags_awaiting_verify.insert(std::pair(mack->TOW, tag0)); - bool ret = verify_macseq(*mack); - if (ret || d_flag_debug) +// bool ret = verify_macseq(*mack); + std::vector macseq_verified_tags = verify_macseq_new(*mack); + for (std::size_t i = 0; i < macseq_verified_tags.size(); ++i) { - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS for Mack at TOW=" << mack->TOW << ", PRN" << mack->PRNa; - for (std::size_t i = 0; i < mack->tag_and_info.size(); ++i) - { - // add tags of current mack to the verification queue - auto& tag = mack->tag_and_info[i]; - Tag t(tag, mack->TOW, mack->WN, mack->PRNa, i + 2); // tag0 (mack header) has CTR1, so first tag of MTI has CTR = 2. - d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); - LOG(INFO) << "Galileo OSNMA: Add Tag Id= " - << t.tag_id - << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase - << t.received_tag << std::dec - << ", TOW=" - << t.TOW - << ", ADKD=" - << static_cast(t.ADKD) - << ", PRNa=" - << static_cast(t.PRNa) - << ", PRNd=" - << static_cast(t.PRN_d); - } - std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; - mack = d_macks_awaiting_MACSEQ_verification.erase(mack); - } - else - { - mack = d_macks_awaiting_MACSEQ_verification.erase(mack); + // add tags of current mack to the verification queue + auto& tag_and_info = macseq_verified_tags[i]; + Tag t(tag_and_info, mack->TOW, mack->WN, mack->PRNa, tag_and_info.counter); + d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); + LOG(INFO) << "Galileo OSNMA: Add Tag Id= " + << t.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << t.received_tag << std::dec + << ", TOW=" + << t.TOW + << ", ADKD=" + << static_cast(t.ADKD) + << ", PRNa=" + << static_cast(t.PRNa) + << ", PRNd=" + << static_cast(t.PRN_d); } + std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; + mack = d_macks_awaiting_MACSEQ_verification.erase(mack); + } else { // key not yet available - keep in container until then -- might be deleted if container size exceeds max allowed @@ -1408,6 +1403,7 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() } +// TODO - remove this method /** * @brief Verifies the MACSEQ of a received MACK_message. * @@ -1458,6 +1454,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) } else if (mack.tag_and_info[i].tag_info.ADKD != std::stoi(applicable_sequence[i + 1])) { + // fill index of tags failed LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: ADKD mismatch against MAC Look-up table."; return false; // TODO macseq shall be individual to each tag, a wrongly verified macseq should not discard the whole MACK tags } @@ -1639,3 +1636,125 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede // LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; return K_II; } + +/** + * @brief Verifies the MAC sequence of a received MACK message. + * + * This function is responsible for verifying the MAC sequence of a received MACK message. + * It takes a reference to a constant MACK_message object as input and returns a vector containing + * the tags for which the MACSEQ verification was successful + * + * @param mack The MACK message object to verify the MAC sequence for. + * @return vector MACK_tag_and_info for which the MACSEQ was successful + */ +std::vector osnma_msg_receiver::verify_macseq_new(const MACK_message& mack) +{ + std::vector verified_tags {}; + + // MACSEQ verification + d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. + std::vector applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe + std::vector sq1{}; + std::vector sq2{}; + std::vector applicable_sequence; + const auto it = OSNMA_TABLE_16.find(d_osnma_data.d_dsm_kroot_message.maclt); + if (it != OSNMA_TABLE_16.cend()) + { + sq1 = it->second.sequence1; + sq2 = it->second.sequence2; + } + + // Assign relevant sequence based on subframe time + if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present. + { + applicable_sequence = sq1; + } + else if (mack.TOW % 60 >= 30) + { + applicable_sequence = sq2; + } + if (mack.tag_and_info.size() != applicable_sequence.size() - 1) + { + LOG(WARNING) << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!"; + return verified_tags; + } + std::vector flxTags{}; + std::string tempADKD; + // MACLT verification + for (uint8_t i = 0; i < mack.tag_and_info.size(); i++) + { + tempADKD = applicable_sequence[i + 1]; + if (tempADKD == "FLX") + { + flxTags.push_back(i); // C: just need to save the index in the sequence + } + else if (mack.tag_and_info[i].tag_info.ADKD == std::stoi(applicable_sequence[i + 1])) + { + // fill index of tags failed + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: ADKD match 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; + verified_tags.push_back(mack.tag_and_info[i]); + } + else + { + // discard tag + 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; + } + } + + if (flxTags.empty() /*TODO add check d_flag_check_mackseq_fixed_tags*/) + { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: No FLX tags to verify."; + return verified_tags; + } + // Fixed as well as FLX Tags share first part - Eq. 22 ICD + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag + m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); // TODO d_GST_Sf left useless + m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); + m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); + m[4] = static_cast(d_GST_Sf & 0x000000FF); + // Case tags flexible - Eq. 21 ICD + for (uint8_t i = 0; i < flxTags.size(); i++) + { + m[2 * i + 5] = mack.tag_and_info[flxTags[i]].tag_info.PRN_d; + m[2 * i + 6] = mack.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | + mack.tag_and_info[flxTags[i]].tag_info.cop; + } + // compute mac + std::vector mac; + if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 + { + mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + } + else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES + { + mac = d_crypto->computeCMAC_AES(applicable_key, m); + } + // Truncate the twelve MSBits and compare with received MACSEQ + uint16_t mac_msb = 0; + if (!mac.empty()) + { + mac_msb = (mac[0] << 8) + mac[1]; + } + uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; + if (computed_macseq == mack.header.macseq) + { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK"; + for (uint8_t i = 0; i < flxTags.size(); i++) + { + verified_tags.push_back(mack.tag_and_info[flxTags[i]]); + } + return verified_tags; + } + + else + { + LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: FLX tags verification failed"; + return verified_tags; + } + +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 8bb8eb452..ad397cc2f 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -80,6 +80,7 @@ private: std::vector hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes); std::vector compute_base_leaf(const DSM_PKR_message& dsm_pkr_message) const; std::vector compute_merke_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const; + std::vector verify_macseq_new(const MACK_message& mack); void display_data(); bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); bool verify_tesla_key(std::vector& key, uint32_t TOW); diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index aed9ae685..105c4cbc2 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -74,7 +74,7 @@ public: MACK_tag_and_info() = default; uint64_t tag; // C: 20-40 bits MACK_tag_info tag_info; - // TODO - std::vector with complete Tag + uint32_t counter; // CTR }; class DSM_PKR_message From ef8f00f6d651961d1867eccb2e99c5cdee156428 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 15 Jul 2024 17:19:17 +0200 Subject: [PATCH 158/219] Add a building configuration parameter -DENABLE_GNUTLS, by default to OFF, to allow the user to link against GnuTLS instead of OpenSSL (#7) --- CMakeLists.txt | 3 +++ cmake/Modules/GnssSdrCrypto.cmake | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4264195a6..97fa74039 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,8 @@ option(ENABLE_STRIP "Create stripped binaries without debugging symbols (in Rele option(Boost_USE_STATIC_LIBS "Use Boost static libs" OFF) +option(ENABLE_GNUTLS "Forces linking against GnuTLS" OFF) + if(ENABLE_PACKAGING) set(ENABLE_ARMA_NO_DEBUG ON) set(CMAKE_VERBOSE_MAKEFILE ON) @@ -3472,6 +3474,7 @@ add_feature_info(ENABLE_OWN_GLOG ENABLE_OWN_GLOG "Forces the downloading and bui add_feature_info(ENABLE_GLOG_AND_GFLAGS ENABLE_GLOG_AND_GFLAGS "Forces the usage of Google glog and Gflags instead of Abseil.") add_feature_info(ENABLE_OWN_ABSEIL ENABLE_OWN_ABSEIL "Forces downloading and building Abseil. Supersedes ENABLE_OWN_GLOG.") add_feature_info(ENABLE_OWN_ARMADILLO ENABLE_OWN_ARMADILLO "Forces the downloading and building of Armadillo.") +add_feature_info(ENABLE_GNUTLS ENABLE_GNUTLS "Forces linking against GnuTLS instead of OpenSSL.") add_feature_info(ENABLE_LOG ENABLE_LOG "Enables runtime internal logging.") add_feature_info(ENABLE_ORC ENABLE_ORC "Use the Optimized Inner Loop Runtime Compiler (ORC) for building volk_gnsssdr.") add_feature_info(ENABLE_STRIP ENABLE_STRIP "Enables the generation of stripped binaries (without debugging symbols).") diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index 9649da9da..58c1c94e2 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -11,7 +11,11 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(OPENSSL_ROOT_DIR /usr/local/opt/openssl) # Trick for Homebrew endif() -find_package(OpenSSL) +unset(OPENSSL_FOUND CACHE) +unset(GnuTLS_FOUND CACHE) +if(NOT ENABLE_GNUTLS) + find_package(OpenSSL) +endif() set_package_properties(OpenSSL PROPERTIES URL "https://www.openssl.org" @@ -162,7 +166,6 @@ function(link_to_crypto_dependencies target) target_compile_definitions(${target} PUBLIC -DUSE_OPENSSL_111=1) endif() endif() - else() endif() else() # GnuTLS target_link_libraries(${target} From 1c26d43e2de1956249d87d541eba28884be56c67 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 12 Jul 2024 16:18:41 +0200 Subject: [PATCH 159/219] Add function to store the public key in a .pem file --- src/core/system_parameters/gnss_crypto.cc | 119 +++++++++++++++++- src/core/system_parameters/gnss_crypto.h | 6 +- .../osnma/gnss_crypto_test.cc | 63 ++++++++-- 3 files changed, 177 insertions(+), 11 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 055bd0382..a41159abd 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -93,7 +93,7 @@ Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& mer #endif if (!readPublicKeyFromCRT(certFilePath)) { - readPublicKeyFromPEM(PEMFILE_DEFAULT); + readPublicKeyFromPEM(certFilePath); } read_merkle_xml(merkleTreePath); } @@ -1142,3 +1142,120 @@ bool Gnss_Crypto::pubkey_copy(EC_KEY* src, EC_KEY** dest) } #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 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 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 + std::vector output(mem_ptr->length); + memcpy(output.data(), mem_ptr->data, mem_ptr->length); + + // Clean up the BIO + BIO_free(mem); +#endif + return output; +} \ No newline at end of file diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index c0de86e24..fccf1b23c 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -44,17 +44,19 @@ public: void set_public_key(const std::vector& publickey); bool have_public_key() const; bool verify_signature(const std::vector& message, const std::vector& signature) const; + bool store_public_key(const std::string& pubKeyFilePath) const; std::vector computeSHA256(const std::vector& input) const; std::vector computeSHA3_256(const std::vector& input) const; std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; std::vector getMerkleRoot(const std::vector>& merkle) const; - + std::vector getPublicKey() const; inline std::vector getMerkleRoot() const { return d_x_4_0; } - inline void setMerkleRoot(std::vector v){ + inline void setMerkleRoot(std::vector v) + { d_x_4_0 = v; } 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 87f5afbfa..5095269c7 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 @@ -1,5 +1,10 @@ #include "gnss_crypto.h" +#include "gnss_sdr_filesystem.h" +#include "gnss_sdr_make_unique.h" #include +#include +#include + class GnssCryptoTest : public ::testing::Test { }; @@ -7,7 +12,7 @@ class GnssCryptoTest : public ::testing::Test TEST(GnssCryptoTest, TestComputeSHA_256) { - std::unique_ptr d_crypto = std::make_unique(); + auto d_crypto = std::make_unique(); std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world std::vector expected_output = { @@ -23,7 +28,7 @@ TEST(GnssCryptoTest, TestComputeSHA_256) TEST(GnssCryptoTest, TestComputeSHA3_256) { - std::unique_ptr d_crypto = std::make_unique(); + auto d_crypto = std::make_unique(); std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world std::vector expected_output = { @@ -39,7 +44,7 @@ TEST(GnssCryptoTest, TestComputeSHA3_256) TEST(GnssCryptoTest, VerifySignature) { - std::unique_ptr d_crypto = std::make_unique(); + auto d_crypto = std::make_unique(); // RG example - import crt certificate - result: FAIL std::vector 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) { - std::unique_ptr d_crypto = std::make_unique(); + auto d_crypto = std::make_unique(); std::vector 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, @@ -80,10 +85,52 @@ TEST(GnssCryptoTest, VerifyPubKeyImport) } +TEST(GnssCryptoTest, VerifyPublicKeyStorage) +{ + auto d_crypto = std::make_unique(); + + const std::string f1("./osnma_test_file1.pem"); + const std::string f2("./osnma_test_file2.pem"); + + std::vector 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(f1, ""); + bool result2 = d_crypto2->store_public_key(f2); + ASSERT_TRUE(result2); + + std::ifstream t(f1); + std::string content_file((std::istreambuf_iterator(t)), std::istreambuf_iterator()); + + std::ifstream t2(f2); + std::string content_file2((std::istreambuf_iterator(t2)), std::istreambuf_iterator()); + + ASSERT_EQ(content_file, content_file2); + + std::vector 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. TEST(GnssCryptoTest, TestComputeHMACSHA256) { - std::unique_ptr d_crypto = std::make_unique(); + auto d_crypto = std::make_unique(); std::vector key = { 0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7, @@ -107,7 +154,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256) TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) { // key and message generated from RG A.6.5.1 - std::unique_ptr d_crypto = std::make_unique(); + auto d_crypto = std::make_unique(); std::vector key = {// RG K4 @ 345690 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, @@ -134,7 +181,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) { // key and message generated from RG A.6.5.2 - std::unique_ptr d_crypto = std::make_unique(); + auto d_crypto = std::make_unique(); std::vector key = {// RG K4 @ 345690 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, @@ -159,7 +206,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) TEST(GnssCryptoTest, TestComputeCMAC_AES) { // Tests vectors from https://datatracker.ietf.org/doc/html/rfc4493#appendix-A - std::unique_ptr d_crypto = std::make_unique(); + auto d_crypto = std::make_unique(); std::vector key = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, From d79ee8497f7ad4aaf61d812c2933a034b2c61c60 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 13 Jul 2024 07:19:32 +0200 Subject: [PATCH 160/219] Store public key when received from a DSM-PKR message --- src/core/libs/osnma_msg_receiver.cc | 1 + src/core/system_parameters/Galileo_OSNMA.h | 2 +- src/core/system_parameters/gnss_crypto.cc | 62 +++++----------------- src/core/system_parameters/gnss_crypto.h | 4 +- 4 files changed, 16 insertions(+), 53 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 74b46f7dc..43e62a738 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -568,6 +568,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_public_key_verified = true; d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk); + d_crypto->store_public_key(PEMFILE_STORED); } } } diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index bc919c4b3..6032be061 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -160,7 +160,7 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("SHA-256"), 512}, {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} -const std::string PEMFILE_DEFAULT("../data/OSNMA_PublicKey_20240115100000_newPKID_1.pem"); +const std::string PEMFILE_STORED("./OSNMA_PublicKey.pem"); const std::string CRTFILE_DEFAULT("../data/OSNMA_PublicKey_20240115100000_newPKID_1.crt"); const std::string MERKLEFILE_DEFAULT("../data/OSNMA_MerkleTree_20240115100000_newPKID_1.xml"); diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index a41159abd..b7595fa59 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -94,6 +94,10 @@ Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& mer if (!readPublicKeyFromCRT(certFilePath)) { readPublicKeyFromPEM(certFilePath); + if (!have_public_key()) + { + readPublicKeyFromPEM(PEMFILE_STORED); + } } read_merkle_xml(merkleTreePath); } @@ -160,7 +164,7 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) // If it was not the default, maybe it is a configuration error, warn user if (merkleFilePath != MERKLEFILE_DEFAULT) { - std::cerr << "File " << merkleFilePath << " not found" << std::endl; + LOG(INFO) << "File " << merkleFilePath << " not found"; } // fill default values d_x_4_0 = convert_from_hex_str("C5B2A3BD24E819EF82B17ACE83C0E7F41D34AC9B488CB7CE4D765FDE7DCA0297"); @@ -581,12 +585,6 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) std::ifstream pemFile(pemFilePath); if (!pemFile) { - // PEM file not found - // If it was not the default, maybe it is a configuration error - if (pemFilePath != PEMFILE_DEFAULT) - { - std::cerr << "File " << pemFilePath << " not found" << std::endl; - } return; } std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); @@ -659,7 +657,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) int ret = gnutls_x509_crt_import(cert, (const gnutls_datum_t*)&buffer, GNUTLS_X509_FMT_PEM); if (ret < 0) { - std::cerr << "Failed to import certificate: " << gnutls_strerror(ret) << std::endl; + LOG(INFO) << "GnuTLS: Failed to import certificate: " << gnutls_strerror(ret); gnutls_x509_crt_deinit(cert); return false; } @@ -670,7 +668,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) ret = gnutls_pubkey_import_x509(pubkey, cert, 0); if (ret < 0) { - std::cerr << "Failed to import public key: " << gnutls_strerror(ret) << std::endl; + LOG(INFO) << "GnuTLS: Failed to import public key: " << gnutls_strerror(ret); gnutls_pubkey_deinit(pubkey); gnutls_x509_crt_deinit(cert); return false; @@ -683,7 +681,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) std::ifstream crtFile(crtFilePath, std::ios::binary); if (!crtFile.is_open()) { - std::cerr << "Unable to open file: " << crtFilePath << std::endl; + LOG(INFO) << "OpenSSL: Unable to open file: " << crtFilePath; return false; } @@ -692,13 +690,13 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) BIO* bio = BIO_new_mem_buf(buffer.data(), buffer.size()); if (!bio) { - std::cerr << "Unable to create BIO for file: " << crtFilePath << std::endl; + LOG(INFO) << "OpenSSL: Unable to create BIO for file: " << crtFilePath; return false; } X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); if (!cert) { - std::cerr << "Unable to read certificate from file: " << crtFilePath << std::endl; + LOG(INFO) << "OpenSSL: Unable to read certificate from file: " << crtFilePath; BIO_free(bio); return false; } @@ -708,7 +706,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) #if USE_OPENSSL_3 if (!pubkey) { - std::cerr << "Failed to extract the public key" << std::endl; + LOG(INFO) << "OpenSSL: Failed to extract the public key"; X509_free(cert); return false; } @@ -719,7 +717,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) EVP_PKEY_free(pubkey); if (!ec_pubkey) { - std::cerr << "Failed to extract the public key" << std::endl; + LOG(INFO) << "OpenSSL: Failed to extract the public key"; X509_free(cert); return false; } @@ -873,42 +871,6 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } -std::vector Gnss_Crypto::getMerkleRoot(const std::vector>& merkle) const -{ - if (merkle.empty()) - { - return {}; - } - else if (merkle.size() == 1) - { - return this->computeSHA3_256(merkle[0]); - } - - std::vector> new_merkle = merkle; - - while (new_merkle.size() > 1) - { - if (new_merkle.size() % 2 == 1) - { - new_merkle.push_back(merkle.back()); - } - - std::vector> result; - - for (size_t i = 0; i < new_merkle.size(); i += 2) - { - std::vector var1 = this->computeSHA3_256(new_merkle[i]); - std::vector var2 = this->computeSHA3_256(new_merkle[i + 1]); - var1.insert(var1.end(), var2.begin(), var2.end()); - std::vector hash = this->computeSHA3_256(var1); - result.push_back(hash); - } - new_merkle = result; - } - return new_merkle[0]; -} - - void Gnss_Crypto::set_public_key(const std::vector& publicKey) { #if USE_GNUTLS_FALLBACK diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index fccf1b23c..95db7032a 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -45,12 +45,12 @@ public: bool have_public_key() const; bool verify_signature(const std::vector& message, const std::vector& signature) const; bool store_public_key(const std::string& pubKeyFilePath) const; + std::vector getPublicKey() const; std::vector computeSHA256(const std::vector& input) const; std::vector computeSHA3_256(const std::vector& input) const; std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; - std::vector getMerkleRoot(const std::vector>& merkle) const; - std::vector getPublicKey() const; + inline std::vector getMerkleRoot() const { return d_x_4_0; From fe36fe7a604df9fafb2fe2bdd64454a46cd660b7 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 13 Jul 2024 09:12:13 +0200 Subject: [PATCH 161/219] Fix certificate reading when using GnuTLS --- src/core/system_parameters/gnss_crypto.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index b7595fa59..231c33004 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -650,11 +650,12 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) return false; } - std::vector buffer((std::istreambuf_iterator(crtFile)), std::istreambuf_iterator()); + const std::vector buffer((std::istreambuf_iterator(crtFile)), std::istreambuf_iterator()); + const gnutls_datum_t buffer_datum = {const_cast(buffer.data()), static_cast(buffer.size())}; gnutls_x509_crt_t cert; gnutls_x509_crt_init(&cert); - int ret = gnutls_x509_crt_import(cert, (const gnutls_datum_t*)&buffer, GNUTLS_X509_FMT_PEM); + int ret = gnutls_x509_crt_import(cert, &buffer_datum, GNUTLS_X509_FMT_PEM); if (ret < 0) { LOG(INFO) << "GnuTLS: Failed to import certificate: " << gnutls_strerror(ret); From a06897590b8333a4203c3b92687c82278fc4c36c Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 15 Jul 2024 10:29:34 +0200 Subject: [PATCH 162/219] Add current values of the Merkle Tree by default --- src/core/system_parameters/gnss_crypto.cc | 28 +++++++++-------------- src/core/system_parameters/gnss_crypto.h | 3 +-- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 231c33004..fba8d643e 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -167,12 +167,11 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) LOG(INFO) << "File " << merkleFilePath << " not found"; } // fill default values - d_x_4_0 = convert_from_hex_str("C5B2A3BD24E819EF82B17ACE83C0E7F41D34AC9B488CB7CE4D765FDE7DCA0297"); - d_x_3_1 = convert_from_hex_str("C8314BA8084E0CA101E595E88F170012F1F5CE71EEEFAB27334283E15935E8E6"); - d_x_2_1 = convert_from_hex_str("6FB21E4DDF3F8E517A5C5B1C6D843F9236707FF11D96F9BA954BFEAA3A44E56B"); - d_x_1_1 = convert_from_hex_str("86E53A50D345FBDAD49835F3363EE4A7262DB738CBDFC399229AE2803679300D"); - d_x_0_0 = convert_from_hex_str("40CAA1D70F7B1D370219674A25721311170A49DE4E4A0CE4FE328674E01CF750"); - d_x_0_1 = convert_from_hex_str("AA1A8B68E5DB293106B5BC8806F9790E8ACF8DC2D28A6EF6C1AC7233A9813D3F"); + d_x_4_0 = convert_from_hex_str("832E15EDE55655EAC6E399A539477B7C034CCE24C3C93FFC904ACD9BF842F04E"); + d_x_3_1 = convert_from_hex_str("84DE3669E6DA551292979E5B8D045787FA967C57CC23638A30237614EDD9171A"); + d_x_2_1 = convert_from_hex_str("DE73D209E4C5BCDC34CD117F2FE40FD08B110009997AD2B3291D3A2CF29943F9"); + d_x_1_1 = convert_from_hex_str("6AAFDE28017BF0744D42819CE40E3A0CDA1ECA3F7A4EA67E134E7AA714C1E843"); + d_x_0_1 = convert_from_hex_str("941BD34EA7DF668B6FC5BE75C1D93464D109BC615CB52C8124847FAFB09CBB2B"); return; } try @@ -243,25 +242,20 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) { d_x_1_1 = convert_from_hex_str(x_ji); } - if (j == 0 && i == 0) - { - d_x_0_0 = convert_from_hex_str(x_ji); - } if (j == 0 && i == 1) { - d_x_0_0 = convert_from_hex_str(x_ji); + d_x_0_1 = convert_from_hex_str(x_ji); } } } catch (const std::exception& e) { std::cerr << "Exception raised reading the " << merkleFilePath << " file: " << e.what() << '\n'; - d_x_4_0 = convert_from_hex_str("C5B2A3BD24E819EF82B17ACE83C0E7F41D34AC9B488CB7CE4D765FDE7DCA0297"); - d_x_3_1 = convert_from_hex_str("C8314BA8084E0CA101E595E88F170012F1F5CE71EEEFAB27334283E15935E8E6"); - d_x_2_1 = convert_from_hex_str("6FB21E4DDF3F8E517A5C5B1C6D843F9236707FF11D96F9BA954BFEAA3A44E56B"); - d_x_1_1 = convert_from_hex_str("86E53A50D345FBDAD49835F3363EE4A7262DB738CBDFC399229AE2803679300D"); - d_x_0_0 = convert_from_hex_str("40CAA1D70F7B1D370219674A25721311170A49DE4E4A0CE4FE328674E01CF750"); - d_x_0_1 = convert_from_hex_str("AA1A8B68E5DB293106B5BC8806F9790E8ACF8DC2D28A6EF6C1AC7233A9813D3F"); + d_x_4_0 = convert_from_hex_str("832E15EDE55655EAC6E399A539477B7C034CCE24C3C93FFC904ACD9BF842F04E"); + d_x_3_1 = convert_from_hex_str("84DE3669E6DA551292979E5B8D045787FA967C57CC23638A30237614EDD9171A"); + d_x_2_1 = convert_from_hex_str("DE73D209E4C5BCDC34CD117F2FE40FD08B110009997AD2B3291D3A2CF29943F9"); + d_x_1_1 = convert_from_hex_str("6AAFDE28017BF0744D42819CE40E3A0CDA1ECA3F7A4EA67E134E7AA714C1E843"); + d_x_0_1 = convert_from_hex_str("941BD34EA7DF668B6FC5BE75C1D93464D109BC615CB52C8124847FAFB09CBB2B"); return; } std::cout << "OSNMA Merkle Tree successfully read from file " << merkleFilePath << std::endl; diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 95db7032a..b8164e0ac 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -55,7 +55,7 @@ public: { return d_x_4_0; } - inline void setMerkleRoot(std::vector v) + inline void setMerkleRoot(const std::vector& v) { d_x_4_0 = v; } @@ -82,7 +82,6 @@ private: std::vector d_x_3_1; std::vector d_x_2_1; std::vector d_x_1_1; - std::vector d_x_0_0; std::vector d_x_0_1; }; From fcb20cb9143b604ac46faea12b508f4cf5449516 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 17 Jul 2024 19:53:21 +0200 Subject: [PATCH 163/219] Add ECDSA P-521 signature verification algorithm --- src/core/system_parameters/gnss_crypto.cc | 119 ++++++++++++++++++ src/core/system_parameters/gnss_crypto.h | 2 + .../osnma/gnss_crypto_test.cc | 45 +++++++ 3 files changed, 166 insertions(+) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index fba8d643e..ce6231617 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -866,6 +866,125 @@ bool Gnss_Crypto::verify_signature(const std::vector& message, const st } +bool Gnss_Crypto::verify_signature_p521(const std::vector& message, const std::vector& signature) const +{ + if (!have_public_key()) + { + std::cerr << "Galileo OSNMA KROOT verification error: Public key is not available" << std::endl; + return false; + } + bool success = false; + + // Convert signature to DER format + std::vector der_sig; + if (!convert_raw_to_der_ecdsa(signature, der_sig)) + { + LOG(INFO) << "Failed to convert raw ECDSA signature to DER format"; + return false; + } +#if USE_GNUTLS_FALLBACK + // Compute SHA-512 hash of the message + std::vector digest(64); + gnutls_hash_hd_t hash; + if (gnutls_hash_init(&hash, GNUTLS_DIG_SHA512) != GNUTLS_E_SUCCESS) + { + LOG(INFO) << "OpenSSL: gnutls_hash_init failed"; + return false; + } + gnutls_hash(hash, message.data(), message.size()); + gnutls_hash_deinit(hash, digest.data()); + + gnutls_datum_t digest_data = {const_cast(digest.data()), static_cast(digest.size())}; + gnutls_datum_t signature_data = {const_cast(der_sig.data()), static_cast(der_sig.size())}; + + // Verify the ECDSA signature + int ret = gnutls_pubkey_verify_data2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA512, 0, &digest_data, &signature_data); + success = (ret >= 0); + if (success) + { + LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; + } + else + { + std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; + LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); + } +#else // OpenSSL + // Compute SHA-512 hash of the message + std::vector digest(SHA512_DIGEST_LENGTH); + if (!EVP_Digest(message.data(), message.size(), digest.data(), nullptr, EVP_sha512(), nullptr)) + { + LOG(INFO) << "OpenSSL: EVP_Digest failed"; + return false; + } +#if USE_OPENSSL_3 + // Verify the signature + EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); + if (pctx == nullptr) + { + LOG(INFO) << "OpenSSL: EVP_PKEY_CTX_new failed"; + return false; + } + + if (EVP_PKEY_verify_init(pctx) <= 0) + { + LOG(INFO) << "OpenSSL: EVP_PKEY_verify_init failed"; + EVP_PKEY_CTX_free(pctx); + return false; + } + + if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha512()) <= 0) + { + LOG(INFO) << "OpenSSL: EVP_PKEY_CTX_set_signature_md failed"; + EVP_PKEY_CTX_free(pctx); + return false; + } + + int verification = EVP_PKEY_verify(pctx, der_sig.data(), der_sig.size(), digest.data(), digest.size()); + EVP_PKEY_CTX_free(pctx); + + if (verification == 1) + { + LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + success = true; + } + else if (verification == 0) + { + LOG(INFO) << "OpenSSL: invalid signature found when verifying message"; + } + else + { + LOG(INFO) << "OpenSSL: OSNMA message authentication failed"; + } +#else // OpenSSL 1.x + const unsigned char* sig_ptr = der_sig.data(); + ECDSA_SIG* ecdsa_sig = d2i_ECDSA_SIG(nullptr, &sig_ptr, der_sig.size()); + if (ecdsa_sig == nullptr) + { + LOG(INFO) << "OpenSSL: d2i_ECDSA_SIG failed"; + return false; + } + int verification = ECDSA_do_verify(digest.data(), digest.size(), ecdsa_sig, d_PublicKey); + ECDSA_SIG_free(ecdsa_sig); + if (verification == 1) + { + LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + success = true; + } + else if (verification == 0) + { + LOG(INFO) << "OpenSSL: invalid signature found when verifying message"; + } + else + { + LOG(INFO) << "OpenSSL: OSNMA message authentication failed"; + } +#endif +#endif + return success; +} + + void Gnss_Crypto::set_public_key(const std::vector& publicKey) { #if USE_GNUTLS_FALLBACK diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index b8164e0ac..bd0c2a64d 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -44,7 +44,9 @@ public: void set_public_key(const std::vector& publickey); bool have_public_key() const; bool verify_signature(const std::vector& message, const std::vector& signature) const; + bool verify_signature_p521(const std::vector& message, const std::vector& signature) const; bool store_public_key(const std::string& pubKeyFilePath) const; + std::vector getPublicKey() const; std::vector computeSHA256(const std::vector& input) const; std::vector computeSHA3_256(const std::vector& input) const; 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 5095269c7..994256da1 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 @@ -64,6 +64,51 @@ TEST(GnssCryptoTest, VerifySignature) } +TEST(GnssCryptoTest, VerifySignatureP521) +{ + std::unique_ptr d_crypto = std::make_unique(); + + // Message to be verified + std::vector message = { + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 // "Hello World" + }; + + // Public key in PEM format + std::vector 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, 0x49, 0x47, 0x62, 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, 0x53, 0x75, 0x42, 0x42, 0x41, 0x41, + 0x6a, 0x41, 0x34, 0x47, 0x47, 0x41, 0x41, 0x51, 0x41, 0x6f, 0x35, 0x76, 0x77, 0x66, 0x6e, 0x47, 0x57, 0x47, 0x33, 0x44, 0x63, 0x59, 0x75, 0x2b, 0x2f, 0x61, 0x58, + 0x47, 0x32, 0x7a, 0x74, 0x65, 0x41, 0x46, 0x50, 0x54, 0x33, 0x0a, 0x48, 0x36, 0x4c, 0x76, 0x4f, 0x4c, 0x76, 0x49, 0x51, 0x6a, 0x61, 0x2b, 0x6a, 0x74, 0x57, 0x73, + 0x70, 0x4f, 0x38, 0x37, 0x6f, 0x50, 0x32, 0x4e, 0x6d, 0x72, 0x34, 0x6e, 0x50, 0x68, 0x76, 0x62, 0x53, 0x58, 0x52, 0x4d, 0x37, 0x6a, 0x49, 0x69, 0x46, 0x38, 0x47, + 0x70, 0x6b, 0x75, 0x58, 0x6a, 0x75, 0x4e, 0x7a, 0x34, 0x72, 0x61, 0x56, 0x4f, 0x65, 0x49, 0x4d, 0x42, 0x77, 0x45, 0x2b, 0x61, 0x0a, 0x30, 0x4c, 0x76, 0x7a, 0x37, + 0x69, 0x54, 0x4d, 0x5a, 0x46, 0x41, 0x41, 0x51, 0x64, 0x2b, 0x70, 0x47, 0x72, 0x56, 0x54, 0x47, 0x77, 0x66, 0x53, 0x48, 0x49, 0x72, 0x49, 0x49, 0x45, 0x78, 0x74, + 0x5a, 0x35, 0x77, 0x30, 0x38, 0x51, 0x4f, 0x43, 0x58, 0x2f, 0x75, 0x46, 0x65, 0x2b, 0x30, 0x78, 0x52, 0x78, 0x4c, 0x64, 0x2f, 0x33, 0x36, 0x42, 0x4e, 0x74, 0x63, + 0x74, 0x69, 0x2f, 0x45, 0x4c, 0x0a, 0x4b, 0x31, 0x35, 0x67, 0x2b, 0x4b, 0x32, 0x71, 0x67, 0x2f, 0x6c, 0x39, 0x46, 0x42, 0x47, 0x67, 0x4d, 0x2b, 0x51, 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}; + + // ECDSA P-521 signature + std::vector signature = { + 0x01, 0x7b, 0x59, 0xac, 0x3a, 0x03, 0x5c, 0xb4, 0x07, 0xcd, 0xc1, 0xeb, 0xbe, 0xe5, 0xa6, 0xcb, + 0xda, 0x0a, 0xff, 0x4d, 0x38, 0x61, 0x16, 0x0f, 0xb3, 0x77, 0xe5, 0x8a, 0xdc, 0xf3, 0xfd, 0x79, + 0x38, 0x1e, 0xe8, 0x08, 0x3d, 0x5d, 0xbc, 0xc2, 0x80, 0x6e, 0xe9, 0x2b, 0xc3, 0xef, 0x07, 0x3d, + 0x0c, 0x82, 0x4c, 0x9b, 0x7a, 0x5c, 0x2e, 0xd5, 0x46, 0xbd, 0x22, 0x21, 0x13, 0x8a, 0xb2, 0xca, + 0x96, 0x3d, 0x01, 0xba, 0x2a, 0xc4, 0x3f, 0xdb, 0x66, 0x3c, 0x40, 0x26, 0xd9, 0xbc, 0x26, 0xd5, 0x57, 0xd4, + 0xbd, 0x15, 0x16, 0x88, 0x21, 0x3b, 0xaa, 0x07, 0x89, 0xef, 0x29, 0x8f, 0x2f, 0x85, 0x76, 0x58, + 0x9d, 0xca, 0x00, 0xcc, 0xc8, 0x30, 0x88, 0x31, 0x99, 0xc1, 0x94, 0xb9, 0xaf, 0x91, 0xdc, 0xc4, + 0x6f, 0x19, 0x2b, 0x12, 0xa2, 0x82, 0xa5, 0x66, 0x5e, 0x4b, 0xbb, 0xdf, 0x65, 0x81, 0x52, 0x14, + 0x01, 0xd7}; + + d_crypto->set_public_key(publicKey); + bool result = d_crypto->verify_signature_p521(message, signature); + ASSERT_TRUE(result); + + std::vector wrong_signature = signature; + wrong_signature[1] = 1; + bool result2 = d_crypto->verify_signature_p521(message, wrong_signature); + ASSERT_TRUE(!result2); +} + + TEST(GnssCryptoTest, VerifyPubKeyImport) { auto d_crypto = std::make_unique(); From 659ef2f0a8fc55918710c872847575c1cb45a129 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 18 Jul 2024 07:53:53 +0200 Subject: [PATCH 164/219] Improve code formatting --- src/core/system_parameters/gnss_crypto.cc | 1083 ++++++++--------- src/core/system_parameters/gnss_crypto.h | 54 +- .../osnma/gnss_crypto_test.cc | 365 ++++-- 3 files changed, 798 insertions(+), 704 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index ce6231617..7b1d837e0 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -133,133 +133,389 @@ bool Gnss_Crypto::have_public_key() const } -std::vector Gnss_Crypto::convert_from_hex_str(const std::string& input) const +bool Gnss_Crypto::verify_signature(const std::vector& message, const std::vector& signature) const { - std::vector result; - - // Iterate over the input string in pairs - for (size_t i = 0; i < input.length(); i += 2) + std::vector digest = this->computeSHA256(message); + if (!have_public_key()) { - // Extract two hexadecimal characters from the input string - std::string hexByte = input.substr(i, 2); - - // Convert the hexadecimal string to an integer value - auto value = static_cast(std::stoul(hexByte, nullptr, 16)); - - // Append the value to the result vector - result.push_back(value); + std::cerr << "Galileo OSNMA KROOT verification error: Public key is not available" << std::endl; + return false; + } + bool success = false; +#if USE_GNUTLS_FALLBACK +#if HAVE_GNUTLS_SIGN_ECDSA_SHA256 + // Convert signature to DER format + std::vector der_sig; + if (!convert_raw_to_der_ecdsa(signature, der_sig)) + { + std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; + return false; } - return result; + // Prepare the digest datum + gnutls_datum_t digest_data = {const_cast(digest.data()), static_cast(digest.size())}; + gnutls_datum_t der_sig_data = {der_sig.data(), static_cast(der_sig.size())}; + + // Verify the DER-encoded signature + int ret = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &digest_data, &der_sig_data); + success = (ret >= 0); + if (success) + { + LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; + } + else + { + std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; + LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); + } +#endif +#else // OpenSSL +#if USE_OPENSSL_3 + EVP_PKEY_CTX* ctx; + ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); + bool do_operation = true; + + if (!ctx) + { + do_operation = false; + } + // convert raw signature into DER format + size_t half_size = signature.size() / 2; + std::vector raw_r(signature.begin(), signature.begin() + half_size); + std::vector raw_s(signature.begin() + half_size, signature.end()); + + // Convert raw R and S to BIGNUMs + BIGNUM* r = BN_bin2bn(raw_r.data(), raw_r.size(), nullptr); + BIGNUM* s = BN_bin2bn(raw_s.data(), raw_s.size(), nullptr); + + ECDSA_SIG* sig = ECDSA_SIG_new(); + if (r == nullptr || s == nullptr || sig == nullptr) + { + std::cerr << "Failed to allocate memory for BIGNUMs or ECDSA_SIG" << std::endl; + return false; + } + + if (ECDSA_SIG_set0(sig, r, s) != 1) + { + std::cerr << "Failed to set R and S values in ECDSA_SIG" << std::endl; + ECDSA_SIG_free(sig); // Free the ECDSA_SIG struct as it is no longer needed + return false; + } + + std::vector derSignature; + unsigned char* derSig = nullptr; + int derSigLength = i2d_ECDSA_SIG(sig, &derSig); + + if (derSigLength <= 0) + { + std::cerr << "Failed to convert ECDSA_SIG to DER format" << std::endl; + return false; + } + + derSignature.assign(derSig, derSig + derSigLength); + + if (EVP_PKEY_verify_init(ctx) <= 0) + { + do_operation = false; + } + if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) + { + do_operation = false; + } + int verification = 0; + if (do_operation) + { + verification = EVP_PKEY_verify(ctx, derSignature.data(), derSignature.size(), digest.data(), digest.size()); + } + EVP_PKEY_CTX_free(ctx); + OPENSSL_free(derSig); + ECDSA_SIG_free(sig); + if (verification == 1) + { + success = true; + LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + } + else + { + unsigned long errCode = ERR_get_error(); + char* err = ERR_error_string(errCode, nullptr); + std::cerr << "OpenSSL: OSNMA message authentication failed: " << err << std::endl; + LOG(WARNING) << "OpenSSL: OSNMA message authentication failed: " << err; + } +#else // OpenSSL 1.x + std::vector der_sig; + if (!convert_raw_to_der_ecdsa(signature, der_sig)) + { + std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; + return false; + } + int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, der_sig.data(), static_cast(der_sig.size()), d_PublicKey); + if (verification == 1) + { + success = true; + LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + } + else if (verification == 0) + { + std::cerr << "OpenSSL: invalid signature found when verifying message" << std::endl; + LOG(WARNING) << "OpenSSL: invalid signature found when verifying message"; + } + else + { + std::cerr << "OpenSSL: OSNMA message authentication failed" << std::endl; + LOG(WARNING) << "OpenSSL: OSNMA message authentication failed"; + } +#endif +#endif + return success; } -void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) +bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& message, const std::vector& signature) const { - pugi::xml_document doc; - pugi::xml_parse_result result = doc.load_file(merkleFilePath.c_str()); - if (!result) + if (!have_public_key()) { - // XML file not found - // If it was not the default, maybe it is a configuration error, warn user - if (merkleFilePath != MERKLEFILE_DEFAULT) - { - LOG(INFO) << "File " << merkleFilePath << " not found"; - } - // fill default values - d_x_4_0 = convert_from_hex_str("832E15EDE55655EAC6E399A539477B7C034CCE24C3C93FFC904ACD9BF842F04E"); - d_x_3_1 = convert_from_hex_str("84DE3669E6DA551292979E5B8D045787FA967C57CC23638A30237614EDD9171A"); - d_x_2_1 = convert_from_hex_str("DE73D209E4C5BCDC34CD117F2FE40FD08B110009997AD2B3291D3A2CF29943F9"); - d_x_1_1 = convert_from_hex_str("6AAFDE28017BF0744D42819CE40E3A0CDA1ECA3F7A4EA67E134E7AA714C1E843"); - d_x_0_1 = convert_from_hex_str("941BD34EA7DF668B6FC5BE75C1D93464D109BC615CB52C8124847FAFB09CBB2B"); - return; + LOG(ERROR) << "Galileo OSNMA KROOT verification error: Public key is not available"; + return false; } - try + + if (signature.size() != 132) { - pugi::xml_node root = doc.child("signalData"); - pugi::xml_node header = root.child("header"); - pugi::xml_node body = root.child("body"); - - // Accessing data from the header - pugi::xml_node galHeader = header.child("GAL-header"); - pugi::xml_node source = galHeader.child("source").child("GAL-EXT-GOC-SC-GLAd"); - pugi::xml_node destination = galHeader.child("destination").child("GAL-EXT-GOC-SC-GLAd"); - std::string issueDate = galHeader.child("issueDate").text().get(); - std::string signalVersion = galHeader.child("signalVersion").text().get(); - std::string dataVersion = galHeader.child("dataVersion").text().get(); - - LOG(INFO) << "OSNMA Merkletree - Source: " << source.child_value("mission") << " - " << source.child_value("segment") << " - " << source.child_value("element"); - LOG(INFO) << "OSNMA Merkletree - Destination: " << destination.child_value("mission") << " - " << destination.child_value("segment") << " - " << destination.child_value("element"); - LOG(INFO) << "OSNMA Merkletree - Issue Date: " << issueDate; - LOG(INFO) << "OSNMA Merkletree - Signal Version: " << signalVersion; - LOG(INFO) << "OSNMA Merkletree - Data Version: " << dataVersion; - - // Accessing data from the body - pugi::xml_node merkleTree = body.child("MerkleTree"); - - int n = std::stoi(merkleTree.child_value("N")); - std::string hashFunction = merkleTree.child_value("HashFunction"); - - LOG(INFO) << "OSNMA Merkletree - N: " << n; - LOG(INFO) << "OSNMA Merkletree - Hash Function: " << hashFunction; - - for (pugi::xml_node publicKey : merkleTree.children("PublicKey")) - { - int i = std::stoi(publicKey.child_value("i")); - std::string pkid = publicKey.child_value("PKID"); - int lengthInBits = std::stoi(publicKey.child_value("lengthInBits")); - std::string point = publicKey.child_value("point"); - std::string pkType = publicKey.child_value("PKType"); - - LOG(INFO) << "OSNMA Merkletree - Public Key: " << i; - LOG(INFO) << "OSNMA Merkletree - PKID: " << pkid; - LOG(INFO) << "OSNMA Merkletree - Length in Bits: " << lengthInBits; - LOG(INFO) << "OSNMA Merkletree - Point: " << point; - LOG(INFO) << "OSNMA Merkletree - PK Type: " << pkType; - } - for (pugi::xml_node treeNode : merkleTree.children("TreeNode")) - { - int j = std::stoi(treeNode.child_value("j")); - int i = std::stoi(treeNode.child_value("i")); - int lengthInBits = std::stoi(treeNode.child_value("lengthInBits")); - LOG(INFO) << "OSNMA Merkletree - Node length (bits): " << lengthInBits; - std::string x_ji = treeNode.child_value("x_ji"); - LOG(INFO) << "OSNMA Merkletree - Size string (bytes): " << x_ji.size(); - LOG(INFO) << "OSNMA Merkletree - m_" << j << "_" << i << " = " << x_ji; - if (j == 4 && i == 0) - { - d_x_4_0 = convert_from_hex_str(x_ji); - } - if (j == 3 && i == 1) - { - d_x_3_1 = convert_from_hex_str(x_ji); - } - if (j == 2 && i == 1) - { - d_x_2_1 = convert_from_hex_str(x_ji); - } - if (j == 1 && i == 1) - { - d_x_1_1 = convert_from_hex_str(x_ji); - } - if (j == 0 && i == 1) - { - d_x_0_1 = convert_from_hex_str(x_ji); - } - } + LOG(ERROR) << "Invalid signature length for P-521. Expected 132 bytes, got " << signature.size(); + return false; } - catch (const std::exception& e) + + std::vector der_sig; + if (!convert_raw_to_der_ecdsa(signature, der_sig)) { - std::cerr << "Exception raised reading the " << merkleFilePath << " file: " << e.what() << '\n'; - d_x_4_0 = convert_from_hex_str("832E15EDE55655EAC6E399A539477B7C034CCE24C3C93FFC904ACD9BF842F04E"); - d_x_3_1 = convert_from_hex_str("84DE3669E6DA551292979E5B8D045787FA967C57CC23638A30237614EDD9171A"); - d_x_2_1 = convert_from_hex_str("DE73D209E4C5BCDC34CD117F2FE40FD08B110009997AD2B3291D3A2CF29943F9"); - d_x_1_1 = convert_from_hex_str("6AAFDE28017BF0744D42819CE40E3A0CDA1ECA3F7A4EA67E134E7AA714C1E843"); - d_x_0_1 = convert_from_hex_str("941BD34EA7DF668B6FC5BE75C1D93464D109BC615CB52C8124847FAFB09CBB2B"); - return; + LOG(ERROR) << "Failed to convert raw ECDSA signature to DER format"; + return false; } - std::cout << "OSNMA Merkle Tree successfully read from file " << merkleFilePath << std::endl; - LOG(INFO) << "OSNMA Merkle Tree successfully read from file " << merkleFilePath; + bool success = false; +#if USE_GNUTLS_FALLBACK + std::vector digest(64); + gnutls_hash_hd_t hash; + int ret = gnutls_hash_init(&hash, GNUTLS_DIG_SHA512); + if (ret != GNUTLS_E_SUCCESS) + { + LOG(ERROR) << "GnuTLS: gnutls_hash_init failed: " << gnutls_strerror(ret); + return false; + } + + gnutls_hash(hash, message.data(), message.size()); + gnutls_hash_deinit(hash, digest.data()); + + gnutls_datum_t digest_data = {digest.data(), static_cast(digest.size())}; + gnutls_datum_t signature_data = {der_sig.data(), static_cast(der_sig.size())}; + + // Verify the ECDSA signature + ret = gnutls_pubkey_verify_data2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA512, 0, &digest_data, &signature_data); + + if (ret >= 0) + { + LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; + success = true; + } + else + { + LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); + } +#else // OpenSSL + // Compute SHA-512 hash of the message + std::vector digest(SHA512_DIGEST_LENGTH); + if (!EVP_Digest(message.data(), message.size(), digest.data(), nullptr, EVP_sha512(), nullptr)) + { + LOG(INFO) << "OpenSSL: EVP_Digest failed"; + return false; + } +#if USE_OPENSSL_3 + // Verify the signature + EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); + if (pctx == nullptr) + { + LOG(INFO) << "OpenSSL: EVP_PKEY_CTX_new failed"; + return false; + } + + if (EVP_PKEY_verify_init(pctx) <= 0) + { + LOG(INFO) << "OpenSSL: EVP_PKEY_verify_init failed"; + EVP_PKEY_CTX_free(pctx); + return false; + } + + if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha512()) <= 0) + { + LOG(INFO) << "OpenSSL: EVP_PKEY_CTX_set_signature_md failed"; + EVP_PKEY_CTX_free(pctx); + return false; + } + + int verification = EVP_PKEY_verify(pctx, der_sig.data(), der_sig.size(), digest.data(), digest.size()); + EVP_PKEY_CTX_free(pctx); + + if (verification == 1) + { + LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + success = true; + } + else if (verification == 0) + { + LOG(INFO) << "OpenSSL: invalid signature found when verifying message"; + } + else + { + LOG(INFO) << "OpenSSL: OSNMA message authentication failed"; + } +#else // OpenSSL 1.x + const unsigned char* sig_ptr = der_sig.data(); + ECDSA_SIG* ecdsa_sig = d2i_ECDSA_SIG(nullptr, &sig_ptr, der_sig.size()); + if (ecdsa_sig == nullptr) + { + LOG(INFO) << "OpenSSL: d2i_ECDSA_SIG failed"; + return false; + } + int verification = ECDSA_do_verify(digest.data(), digest.size(), ecdsa_sig, d_PublicKey); + ECDSA_SIG_free(ecdsa_sig); + if (verification == 1) + { + LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + success = true; + } + else if (verification == 0) + { + LOG(INFO) << "OpenSSL: invalid signature found when verifying message"; + } + else + { + LOG(INFO) << "OpenSSL: OSNMA message authentication failed"; + } +#endif +#endif + return success; +} + + +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 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 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 + std::vector 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 Gnss_Crypto::getMerkleRoot() const +{ + return d_x_4_0; } @@ -573,6 +829,152 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke } +void Gnss_Crypto::set_public_key(const std::vector& publicKey) +{ +#if USE_GNUTLS_FALLBACK + gnutls_pubkey_t pubkey{}; + gnutls_datum_t pemDatum = {const_cast(publicKey.data()), static_cast(publicKey.size())}; + gnutls_pubkey_init(&pubkey); + int ret = gnutls_pubkey_import(pubkey, &pemDatum, GNUTLS_X509_FMT_PEM); + if (ret != GNUTLS_E_SUCCESS) + { + gnutls_pubkey_deinit(pubkey); + std::cerr << "GnuTLS: error setting the public key" << std::endl; + std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; + LOG(WARNING) << "GnuTLS: error setting the OSNMA public key: " << gnutls_strerror(ret); + return; + } + pubkey_copy(pubkey, &d_PublicKey); + gnutls_pubkey_deinit(pubkey); +#else // OpenSSL + BIO* bio = nullptr; + EVP_PKEY* pkey = nullptr; + bio = BIO_new_mem_buf(const_cast(publicKey.data()), publicKey.size()); + if (!bio) + { + LOG(INFO) << "OpenSSL: Failed to create BIO for key."; + return; + } + + pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); + BIO_free(bio); + + if (!pkey) + { + std::cerr << "OpenSSL: error setting the OSNMA public key." << std::endl; + LOG(INFO) << "OpenSSL: error setting the OSNMA public key."; + return; + } +#if USE_OPENSSL_3 + if (!pubkey_copy(pkey, &d_PublicKey)) + { + return; + } +#else + EC_KEY* ec_pkey = EVP_PKEY_get1_EC_KEY(pkey); + if (!pubkey_copy(ec_pkey, &d_PublicKey)) + { + return; + } + EC_KEY_free(ec_pkey); +#endif // OpenSSL 1.x + EVP_PKEY_free(pkey); +#endif + LOG(INFO) << "OSNMA Public Key successfully set up."; +} + + +void Gnss_Crypto::setMerkleRoot(const std::vector& v) +{ + d_x_4_0 = v; +} + + +void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) +{ + pugi::xml_document doc; + pugi::xml_parse_result result = doc.load_file(merkleFilePath.c_str()); + if (!result) + { + // XML file not found + // If it was not the default, maybe it is a configuration error, warn user + if (merkleFilePath != MERKLEFILE_DEFAULT && !merkleFilePath.empty()) + { + LOG(INFO) << "File " << merkleFilePath << " not found"; + } + // fill default values + d_x_4_0 = convert_from_hex_str("832E15EDE55655EAC6E399A539477B7C034CCE24C3C93FFC904ACD9BF842F04E"); + return; + } + try + { + pugi::xml_node root = doc.child("signalData"); + pugi::xml_node header = root.child("header"); + pugi::xml_node body = root.child("body"); + + // Accessing data from the header + pugi::xml_node galHeader = header.child("GAL-header"); + pugi::xml_node source = galHeader.child("source").child("GAL-EXT-GOC-SC-GLAd"); + pugi::xml_node destination = galHeader.child("destination").child("GAL-EXT-GOC-SC-GLAd"); + std::string issueDate = galHeader.child("issueDate").text().get(); + std::string signalVersion = galHeader.child("signalVersion").text().get(); + std::string dataVersion = galHeader.child("dataVersion").text().get(); + + LOG(INFO) << "OSNMA Merkletree - Source: " << source.child_value("mission") << " - " << source.child_value("segment") << " - " << source.child_value("element"); + LOG(INFO) << "OSNMA Merkletree - Destination: " << destination.child_value("mission") << " - " << destination.child_value("segment") << " - " << destination.child_value("element"); + LOG(INFO) << "OSNMA Merkletree - Issue Date: " << issueDate; + LOG(INFO) << "OSNMA Merkletree - Signal Version: " << signalVersion; + LOG(INFO) << "OSNMA Merkletree - Data Version: " << dataVersion; + + // Accessing data from the body + pugi::xml_node merkleTree = body.child("MerkleTree"); + + int n = std::stoi(merkleTree.child_value("N")); + std::string hashFunction = merkleTree.child_value("HashFunction"); + + LOG(INFO) << "OSNMA Merkletree - N: " << n; + LOG(INFO) << "OSNMA Merkletree - Hash Function: " << hashFunction; + + for (pugi::xml_node publicKey : merkleTree.children("PublicKey")) + { + int i = std::stoi(publicKey.child_value("i")); + std::string pkid = publicKey.child_value("PKID"); + int lengthInBits = std::stoi(publicKey.child_value("lengthInBits")); + std::string point = publicKey.child_value("point"); + std::string pkType = publicKey.child_value("PKType"); + + LOG(INFO) << "OSNMA Merkletree - Public Key: " << i; + LOG(INFO) << "OSNMA Merkletree - PKID: " << pkid; + LOG(INFO) << "OSNMA Merkletree - Length in Bits: " << lengthInBits; + LOG(INFO) << "OSNMA Merkletree - Point: " << point; + LOG(INFO) << "OSNMA Merkletree - PK Type: " << pkType; + } + for (pugi::xml_node treeNode : merkleTree.children("TreeNode")) + { + int j = std::stoi(treeNode.child_value("j")); + int i = std::stoi(treeNode.child_value("i")); + int lengthInBits = std::stoi(treeNode.child_value("lengthInBits")); + LOG(INFO) << "OSNMA Merkletree - Node length (bits): " << lengthInBits; + std::string x_ji = treeNode.child_value("x_ji"); + LOG(INFO) << "OSNMA Merkletree - Size string (bytes): " << x_ji.size(); + LOG(INFO) << "OSNMA Merkletree - m_" << j << "_" << i << " = " << x_ji; + if (j == 4 && i == 0) + { + d_x_4_0 = convert_from_hex_str(x_ji); + } + } + } + catch (const std::exception& e) + { + std::cerr << "Exception raised reading the " << merkleFilePath << " file: " << e.what() << '\n'; + d_x_4_0 = convert_from_hex_str("832E15EDE55655EAC6E399A539477B7C034CCE24C3C93FFC904ACD9BF842F04E"); + return; + } + std::cout << "OSNMA Merkle Tree successfully read from file " << merkleFilePath << std::endl; + LOG(INFO) << "OSNMA Merkle Tree successfully read from file " << merkleFilePath; +} + + void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) { // Open the .pem file @@ -728,317 +1130,6 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) } -bool Gnss_Crypto::verify_signature(const std::vector& message, const std::vector& signature) const -{ - std::vector digest = this->computeSHA256(message); - if (!have_public_key()) - { - std::cerr << "Galileo OSNMA KROOT verification error: Public key is not available" << std::endl; - return false; - } - bool success = false; -#if USE_GNUTLS_FALLBACK -#if HAVE_GNUTLS_SIGN_ECDSA_SHA256 - // Convert signature to DER format - std::vector der_sig; - if (!convert_raw_to_der_ecdsa(signature, der_sig)) - { - std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; - return false; - } - - // Prepare the digest datum - gnutls_datum_t digest_data = {const_cast(digest.data()), static_cast(digest.size())}; - gnutls_datum_t der_sig_data = {der_sig.data(), static_cast(der_sig.size())}; - - // Verify the DER-encoded signature - int ret = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA256, 0, &digest_data, &der_sig_data); - success = (ret >= 0); - if (success) - { - LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; - } - else - { - std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; - LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); - } -#endif -#else // OpenSSL -#if USE_OPENSSL_3 - EVP_PKEY_CTX* ctx; - ctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); - bool do_operation = true; - - if (!ctx) - { - do_operation = false; - } - // convert raw signature into DER format - size_t half_size = signature.size() / 2; - std::vector raw_r(signature.begin(), signature.begin() + half_size); - std::vector raw_s(signature.begin() + half_size, signature.end()); - - // Convert raw R and S to BIGNUMs - BIGNUM* r = BN_bin2bn(raw_r.data(), raw_r.size(), nullptr); - BIGNUM* s = BN_bin2bn(raw_s.data(), raw_s.size(), nullptr); - - ECDSA_SIG* sig = ECDSA_SIG_new(); - if (r == nullptr || s == nullptr || sig == nullptr) - { - std::cerr << "Failed to allocate memory for BIGNUMs or ECDSA_SIG" << std::endl; - return false; - } - - if (ECDSA_SIG_set0(sig, r, s) != 1) - { - std::cerr << "Failed to set R and S values in ECDSA_SIG" << std::endl; - ECDSA_SIG_free(sig); // Free the ECDSA_SIG struct as it is no longer needed - return false; - } - - std::vector derSignature; - unsigned char* derSig = nullptr; - int derSigLength = i2d_ECDSA_SIG(sig, &derSig); - - if (derSigLength <= 0) - { - std::cerr << "Failed to convert ECDSA_SIG to DER format" << std::endl; - return false; - } - - derSignature.assign(derSig, derSig + derSigLength); - - if (EVP_PKEY_verify_init(ctx) <= 0) - { - do_operation = false; - } - if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) - { - do_operation = false; - } - int verification = 0; - if (do_operation) - { - verification = EVP_PKEY_verify(ctx, derSignature.data(), derSignature.size(), digest.data(), digest.size()); - } - EVP_PKEY_CTX_free(ctx); - OPENSSL_free(derSig); - ECDSA_SIG_free(sig); - if (verification == 1) - { - success = true; - LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; - } - else - { - unsigned long errCode = ERR_get_error(); - char* err = ERR_error_string(errCode, nullptr); - std::cerr << "OpenSSL: OSNMA message authentication failed: " << err << std::endl; - LOG(WARNING) << "OpenSSL: OSNMA message authentication failed: " << err; - } -#else // OpenSSL 1.x - std::vector der_sig; - if (!convert_raw_to_der_ecdsa(signature, der_sig)) - { - std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; - return false; - } - int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, der_sig.data(), static_cast(der_sig.size()), d_PublicKey); - if (verification == 1) - { - success = true; - LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; - } - else if (verification == 0) - { - std::cerr << "OpenSSL: invalid signature found when verifying message" << std::endl; - LOG(WARNING) << "OpenSSL: invalid signature found when verifying message"; - } - else - { - std::cerr << "OpenSSL: OSNMA message authentication failed" << std::endl; - LOG(WARNING) << "OpenSSL: OSNMA message authentication failed"; - } -#endif -#endif - return success; -} - - -bool Gnss_Crypto::verify_signature_p521(const std::vector& message, const std::vector& signature) const -{ - if (!have_public_key()) - { - std::cerr << "Galileo OSNMA KROOT verification error: Public key is not available" << std::endl; - return false; - } - bool success = false; - - // Convert signature to DER format - std::vector der_sig; - if (!convert_raw_to_der_ecdsa(signature, der_sig)) - { - LOG(INFO) << "Failed to convert raw ECDSA signature to DER format"; - return false; - } -#if USE_GNUTLS_FALLBACK - // Compute SHA-512 hash of the message - std::vector digest(64); - gnutls_hash_hd_t hash; - if (gnutls_hash_init(&hash, GNUTLS_DIG_SHA512) != GNUTLS_E_SUCCESS) - { - LOG(INFO) << "OpenSSL: gnutls_hash_init failed"; - return false; - } - gnutls_hash(hash, message.data(), message.size()); - gnutls_hash_deinit(hash, digest.data()); - - gnutls_datum_t digest_data = {const_cast(digest.data()), static_cast(digest.size())}; - gnutls_datum_t signature_data = {const_cast(der_sig.data()), static_cast(der_sig.size())}; - - // Verify the ECDSA signature - int ret = gnutls_pubkey_verify_data2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA512, 0, &digest_data, &signature_data); - success = (ret >= 0); - if (success) - { - LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; - } - else - { - std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; - LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); - } -#else // OpenSSL - // Compute SHA-512 hash of the message - std::vector digest(SHA512_DIGEST_LENGTH); - if (!EVP_Digest(message.data(), message.size(), digest.data(), nullptr, EVP_sha512(), nullptr)) - { - LOG(INFO) << "OpenSSL: EVP_Digest failed"; - return false; - } -#if USE_OPENSSL_3 - // Verify the signature - EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); - if (pctx == nullptr) - { - LOG(INFO) << "OpenSSL: EVP_PKEY_CTX_new failed"; - return false; - } - - if (EVP_PKEY_verify_init(pctx) <= 0) - { - LOG(INFO) << "OpenSSL: EVP_PKEY_verify_init failed"; - EVP_PKEY_CTX_free(pctx); - return false; - } - - if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha512()) <= 0) - { - LOG(INFO) << "OpenSSL: EVP_PKEY_CTX_set_signature_md failed"; - EVP_PKEY_CTX_free(pctx); - return false; - } - - int verification = EVP_PKEY_verify(pctx, der_sig.data(), der_sig.size(), digest.data(), digest.size()); - EVP_PKEY_CTX_free(pctx); - - if (verification == 1) - { - LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; - success = true; - } - else if (verification == 0) - { - LOG(INFO) << "OpenSSL: invalid signature found when verifying message"; - } - else - { - LOG(INFO) << "OpenSSL: OSNMA message authentication failed"; - } -#else // OpenSSL 1.x - const unsigned char* sig_ptr = der_sig.data(); - ECDSA_SIG* ecdsa_sig = d2i_ECDSA_SIG(nullptr, &sig_ptr, der_sig.size()); - if (ecdsa_sig == nullptr) - { - LOG(INFO) << "OpenSSL: d2i_ECDSA_SIG failed"; - return false; - } - int verification = ECDSA_do_verify(digest.data(), digest.size(), ecdsa_sig, d_PublicKey); - ECDSA_SIG_free(ecdsa_sig); - if (verification == 1) - { - LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; - success = true; - } - else if (verification == 0) - { - LOG(INFO) << "OpenSSL: invalid signature found when verifying message"; - } - else - { - LOG(INFO) << "OpenSSL: OSNMA message authentication failed"; - } -#endif -#endif - return success; -} - - -void Gnss_Crypto::set_public_key(const std::vector& publicKey) -{ -#if USE_GNUTLS_FALLBACK - gnutls_pubkey_t pubkey; - gnutls_datum_t pemDatum = {const_cast(publicKey.data()), static_cast(publicKey.size())}; - gnutls_pubkey_init(&pubkey); - int ret = gnutls_pubkey_import(pubkey, &pemDatum, GNUTLS_X509_FMT_PEM); - if (ret != GNUTLS_E_SUCCESS) - { - gnutls_pubkey_deinit(pubkey); - std::cerr << "GnuTLS: error setting the public key" << std::endl; - std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; - return; - } - pubkey_copy(pubkey, &d_PublicKey); - gnutls_pubkey_deinit(pubkey); -#else // OpenSSL - BIO* bio = nullptr; - EVP_PKEY* pkey = nullptr; - bio = BIO_new_mem_buf(const_cast(publicKey.data()), publicKey.size()); - if (!bio) - { - std::cerr << "Failed to create BIO for key \n"; - return; - } - - pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); - BIO_free(bio); - - if (!pkey) - { - std::cerr << "OpenSSL: error setting the OSNMA public key." << std::endl; - LOG(INFO) << "OpenSSL: error setting the OSNMA public key."; - return; - } -#if USE_OPENSSL_3 - if (!pubkey_copy(pkey, &d_PublicKey)) - { - return; - } -#else - EC_KEY* ec_pkey = EVP_PKEY_get1_EC_KEY(pkey); - if (!pubkey_copy(ec_pkey, &d_PublicKey)) - { - return; - } - EC_KEY_free(ec_pkey); -#endif // OpenSSL 1.x - EVP_PKEY_free(pkey); -#endif - LOG(INFO) << "OSNMA Public Key successfully set up."; -} - - bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const { if (raw_signature.size() % 2 != 0) @@ -1087,6 +1178,27 @@ bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signa } +std::vector Gnss_Crypto::convert_from_hex_str(const std::string& input) const +{ + std::vector result; + + // Iterate over the input string in pairs + for (size_t i = 0; i < input.length(); i += 2) + { + // Extract two hexadecimal characters from the input string + std::string hexByte = input.substr(i, 2); + + // Convert the hexadecimal string to an integer value + auto value = static_cast(std::stoul(hexByte, nullptr, 16)); + + // Append the value to the result vector + result.push_back(value); + } + + return result; +} + + #if USE_GNUTLS_FALLBACK // GnuTLS-specific functions bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) { @@ -1170,9 +1282,7 @@ bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) return true; } - -#else // OpenSSL 1.x - +#else // OpenSSL 1.x bool Gnss_Crypto::pubkey_copy(EC_KEY* src, EC_KEY** dest) { // Open a memory buffer @@ -1216,122 +1326,5 @@ bool Gnss_Crypto::pubkey_copy(EC_KEY* src, EC_KEY** dest) return true; } +#endif // OpenSSL #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 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 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 - std::vector output(mem_ptr->length); - memcpy(output.data(), mem_ptr->data, mem_ptr->length); - - // Clean up the BIO - BIO_free(mem); -#endif - return output; -} \ No newline at end of file diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index bd0c2a64d..117d5e0a7 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -34,33 +34,43 @@ /** \addtogroup System_Parameters * \{ */ +/*! + * \brief Class implementing cryptographic functions + * for Navigation Message Authentication + */ class Gnss_Crypto { public: - Gnss_Crypto(); - Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath); - ~Gnss_Crypto(); + Gnss_Crypto(); //!< Default constructor - void set_public_key(const std::vector& publickey); - bool have_public_key() const; - bool verify_signature(const std::vector& message, const std::vector& signature) const; - bool verify_signature_p521(const std::vector& message, const std::vector& signature) const; + /*! + * Constructor with a .crt or .pem file for the ECDSA Public Key + * and a XML file for the Merkle Tree root. + * Files can be downloaded by registering at https://www.gsc-europa.eu/ + */ + Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath); + ~Gnss_Crypto(); //!< Default destructor + + bool have_public_key() const; //!< Returns true if the ECDSA Public Key is already loaded + + bool verify_signature(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P256 signature (message in hex, signature in raw format) + bool verify_signature_ecdsa_p521(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P521 signature (message in hex, signature in raw format) + + /*! + * Stores the ECDSA Public Key in a .pem file, which is read in a following run if the .crt file is not found + */ bool store_public_key(const std::string& pubKeyFilePath) const; - std::vector getPublicKey() const; - std::vector computeSHA256(const std::vector& input) const; - std::vector computeSHA3_256(const std::vector& input) const; - std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; - std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; + std::vector getPublicKey() const; //!< Gets the ECDSA Public Key in PEM format + std::vector getMerkleRoot() const; //!< Gets the Merkle Tree root node (\f$ x_{4,0} \f$) - inline std::vector getMerkleRoot() const - { - return d_x_4_0; - } - inline void setMerkleRoot(const std::vector& v) - { - d_x_4_0 = v; - } + std::vector computeSHA256(const std::vector& input) const; //!< Computes SHA-256 hash + std::vector computeSHA3_256(const std::vector& input) const; //!< Computes SHA3-256 hash + std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; //!< Computes HMAC-SHA-256 message authentication code + std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; //!< Computes CMAC-AES message authentication code + + void set_public_key(const std::vector& publickey); //!< Sets the ECDSA Public Key (publickey in PEM format) + void setMerkleRoot(const std::vector& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$) private: void read_merkle_xml(const std::string& merkleFilePath); @@ -81,10 +91,6 @@ private: #endif #endif std::vector d_x_4_0; - std::vector d_x_3_1; - std::vector d_x_2_1; - std::vector d_x_1_1; - std::vector d_x_0_1; }; /** \} */ 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 994256da1..bbe01d905 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 @@ -1,3 +1,21 @@ +/*! + * \file gnss_crypto_test.cc + * \brief Tests for the Gnss_Crypto class. + * \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es + * Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + #include "gnss_crypto.h" #include "gnss_sdr_filesystem.h" #include "gnss_sdr_make_unique.h" @@ -10,119 +28,26 @@ class GnssCryptoTest : public ::testing::Test }; -TEST(GnssCryptoTest, TestComputeSHA_256) -{ - auto d_crypto = std::make_unique(); - std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world - - std::vector 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}; - - std::vector output = d_crypto->computeSHA256(message); - - ASSERT_EQ(expected_output, output); -} - - -TEST(GnssCryptoTest, TestComputeSHA3_256) -{ - auto d_crypto = std::make_unique(); - std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world - - std::vector 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}; - - std::vector output = d_crypto->computeSHA3_256(message); - - ASSERT_EQ(expected_output, output); -} - - -TEST(GnssCryptoTest, VerifySignature) -{ - auto d_crypto = std::make_unique(); - - // RG example - import crt certificate - result: FAIL - std::vector 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 signature = {0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; - std::vector publicKey{// PEM format - 1000 bits - 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->verify_signature(message, signature); - - ASSERT_TRUE(result); -} - - -TEST(GnssCryptoTest, VerifySignatureP521) -{ - std::unique_ptr d_crypto = std::make_unique(); - - // Message to be verified - std::vector message = { - 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 // "Hello World" - }; - - // Public key in PEM format - std::vector 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, 0x49, 0x47, 0x62, 0x4d, 0x42, 0x41, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, 0x53, 0x75, 0x42, 0x42, 0x41, 0x41, - 0x6a, 0x41, 0x34, 0x47, 0x47, 0x41, 0x41, 0x51, 0x41, 0x6f, 0x35, 0x76, 0x77, 0x66, 0x6e, 0x47, 0x57, 0x47, 0x33, 0x44, 0x63, 0x59, 0x75, 0x2b, 0x2f, 0x61, 0x58, - 0x47, 0x32, 0x7a, 0x74, 0x65, 0x41, 0x46, 0x50, 0x54, 0x33, 0x0a, 0x48, 0x36, 0x4c, 0x76, 0x4f, 0x4c, 0x76, 0x49, 0x51, 0x6a, 0x61, 0x2b, 0x6a, 0x74, 0x57, 0x73, - 0x70, 0x4f, 0x38, 0x37, 0x6f, 0x50, 0x32, 0x4e, 0x6d, 0x72, 0x34, 0x6e, 0x50, 0x68, 0x76, 0x62, 0x53, 0x58, 0x52, 0x4d, 0x37, 0x6a, 0x49, 0x69, 0x46, 0x38, 0x47, - 0x70, 0x6b, 0x75, 0x58, 0x6a, 0x75, 0x4e, 0x7a, 0x34, 0x72, 0x61, 0x56, 0x4f, 0x65, 0x49, 0x4d, 0x42, 0x77, 0x45, 0x2b, 0x61, 0x0a, 0x30, 0x4c, 0x76, 0x7a, 0x37, - 0x69, 0x54, 0x4d, 0x5a, 0x46, 0x41, 0x41, 0x51, 0x64, 0x2b, 0x70, 0x47, 0x72, 0x56, 0x54, 0x47, 0x77, 0x66, 0x53, 0x48, 0x49, 0x72, 0x49, 0x49, 0x45, 0x78, 0x74, - 0x5a, 0x35, 0x77, 0x30, 0x38, 0x51, 0x4f, 0x43, 0x58, 0x2f, 0x75, 0x46, 0x65, 0x2b, 0x30, 0x78, 0x52, 0x78, 0x4c, 0x64, 0x2f, 0x33, 0x36, 0x42, 0x4e, 0x74, 0x63, - 0x74, 0x69, 0x2f, 0x45, 0x4c, 0x0a, 0x4b, 0x31, 0x35, 0x67, 0x2b, 0x4b, 0x32, 0x71, 0x67, 0x2f, 0x6c, 0x39, 0x46, 0x42, 0x47, 0x67, 0x4d, 0x2b, 0x51, 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}; - - // ECDSA P-521 signature - std::vector signature = { - 0x01, 0x7b, 0x59, 0xac, 0x3a, 0x03, 0x5c, 0xb4, 0x07, 0xcd, 0xc1, 0xeb, 0xbe, 0xe5, 0xa6, 0xcb, - 0xda, 0x0a, 0xff, 0x4d, 0x38, 0x61, 0x16, 0x0f, 0xb3, 0x77, 0xe5, 0x8a, 0xdc, 0xf3, 0xfd, 0x79, - 0x38, 0x1e, 0xe8, 0x08, 0x3d, 0x5d, 0xbc, 0xc2, 0x80, 0x6e, 0xe9, 0x2b, 0xc3, 0xef, 0x07, 0x3d, - 0x0c, 0x82, 0x4c, 0x9b, 0x7a, 0x5c, 0x2e, 0xd5, 0x46, 0xbd, 0x22, 0x21, 0x13, 0x8a, 0xb2, 0xca, - 0x96, 0x3d, 0x01, 0xba, 0x2a, 0xc4, 0x3f, 0xdb, 0x66, 0x3c, 0x40, 0x26, 0xd9, 0xbc, 0x26, 0xd5, 0x57, 0xd4, - 0xbd, 0x15, 0x16, 0x88, 0x21, 0x3b, 0xaa, 0x07, 0x89, 0xef, 0x29, 0x8f, 0x2f, 0x85, 0x76, 0x58, - 0x9d, 0xca, 0x00, 0xcc, 0xc8, 0x30, 0x88, 0x31, 0x99, 0xc1, 0x94, 0xb9, 0xaf, 0x91, 0xdc, 0xc4, - 0x6f, 0x19, 0x2b, 0x12, 0xa2, 0x82, 0xa5, 0x66, 0x5e, 0x4b, 0xbb, 0xdf, 0x65, 0x81, 0x52, 0x14, - 0x01, 0xd7}; - - d_crypto->set_public_key(publicKey); - bool result = d_crypto->verify_signature_p521(message, signature); - ASSERT_TRUE(result); - - std::vector wrong_signature = signature; - wrong_signature[1] = 1; - bool result2 = d_crypto->verify_signature_p521(message, wrong_signature); - ASSERT_TRUE(!result2); -} - - TEST(GnssCryptoTest, VerifyPubKeyImport) { auto d_crypto = std::make_unique(); - std::vector 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, - 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, 0x53, 0x76, 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, - 0x73, 0x66, 0x78, 0x2F, 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, - 0x48, 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, 0x69, 0x79, - 0x44, 0x79, 0x48, 0x58, 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}; + // PEM format + std::vector 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, 0x53, 0x76, + 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, + 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, 0x73, 0x66, 0x78, 0x2F, + 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, + 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, 0x48, + 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, + 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, + 0x69, 0x79, 0x44, 0x79, 0x48, 0x58, 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); @@ -137,14 +62,22 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) const std::string f1("./osnma_test_file1.pem"); const std::string f2("./osnma_test_file2.pem"); - std::vector 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}; + // PEM format + std::vector 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, 0x53, 0x76, + 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, + 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, 0x73, 0x66, 0x78, 0x2F, + 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, + 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, 0x48, + 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, + 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, + 0x69, 0x79, 0x44, 0x79, 0x48, 0x58, 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); @@ -172,6 +105,40 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) } +TEST(GnssCryptoTest, TestComputeSHA_256) +{ + auto d_crypto = std::make_unique(); + std::vector message{ + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world + + std::vector 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}; + + std::vector output = d_crypto->computeSHA256(message); + + ASSERT_EQ(expected_output, output); +} + + +TEST(GnssCryptoTest, TestComputeSHA3_256) +{ + auto d_crypto = std::make_unique(); + std::vector message{ + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world + + std::vector 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}; + + std::vector output = d_crypto->computeSHA3_256(message); + + ASSERT_EQ(expected_output, output); +} + + // Unit test for computeHMAC_SHA_256 function. TEST(GnssCryptoTest, TestComputeHMACSHA256) { @@ -183,7 +150,9 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256) 0xEB, 0x62, 0x3E, 0x95, 0x6B, 0x2B, 0xCE, 0xA3, 0xB4, 0xD4, 0xDB, 0x31, 0xEE, 0x96, 0xAB, 0xFA}; - std::vector message{0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world con 0x0A + std::vector message{ + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // Hello world + std::vector expected_output = { 0xC3, 0x51, 0xF6, 0xFD, 0xDD, 0xC9, 0x8B, 0x41, 0xD6, 0xF4, 0x77, 0x6D, 0xAC, 0xE8, 0xE0, 0x14, @@ -201,21 +170,29 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) // key and message generated from RG A.6.5.1 auto d_crypto = std::make_unique(); - std::vector key = {// RG K4 @ 345690 + // RG K4 @ 345690 + std::vector key = { 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; - std::vector message{// m0 - 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, - 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, - 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, - 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, - 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00}; + // m0 + std::vector message = { + 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, + 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, + 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, + 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, + 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, + 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, + 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, + 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, + 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, + 0xF7, 0xFC, 0x00}; std::vector expected_output = { 0xE3, 0x7B, 0xC4, 0xF8, 0x58, 0xAE, 0x1E, 0x5C, - 0xFD, 0xC4, 0x6F, 0x05, 0x4B, 0x1F, 0x47, 0xB9, 0xD2, 0xEA, 0x61, 0xE1, - 0xEF, 0x09, 0x11, 0x5C, 0xFE, 0x70, 0x68, 0x52, 0xBF, 0xF2, 0x3A, 0x83}; + 0xFD, 0xC4, 0x6F, 0x05, 0x4B, 0x1F, 0x47, 0xB9, + 0xD2, 0xEA, 0x61, 0xE1, 0xEF, 0x09, 0x11, 0x5C, + 0xFE, 0x70, 0x68, 0x52, 0xBF, 0xF2, 0x3A, 0x83}; std::vector output = d_crypto->computeHMAC_SHA_256(key, message); @@ -228,19 +205,22 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) // key and message generated from RG A.6.5.2 auto d_crypto = std::make_unique(); - std::vector key = {// RG K4 @ 345690 + // RG K4 @ 345690 + std::vector key = { 0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; - std::vector message{ + std::vector message = { 0x02, 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x03, 0xBF, - 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x44, 0x92, 0x38, - 0x22, 0x78, 0x97, 0xFD, 0xEF, 0xF9, 0x30, 0x40}; + 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x44, 0x92, + 0x38, 0x22, 0x78, 0x97, 0xFD, 0xEF, 0xF9, 0x30, + 0x40}; std::vector expected_output = { - 0x7B, 0xB2, 0x38, 0xC8, 0x83, 0xC0, 0x6A, 0x2B, 0x50, 0x8F, - 0xE6, 0x3F, 0xB7, 0xF4, 0xF5, 0x4D, 0x44, 0xAB, 0xEE, 0x4D, - 0xCE, 0xB9, 0x3D, 0xCF, 0x65, 0xCB, 0x3A, 0x5B, 0x81, 0x4A, 0x34, 0xE9}; + 0x7B, 0xB2, 0x38, 0xC8, 0x83, 0xC0, 0x6A, 0x2B, + 0x50, 0x8F, 0xE6, 0x3F, 0xB7, 0xF4, 0xF5, 0x4D, + 0x44, 0xAB, 0xEE, 0x4D, 0xCE, 0xB9, 0x3D, 0xCF, + 0x65, 0xCB, 0x3A, 0x5B, 0x81, 0x4A, 0x34, 0xE9}; std::vector output = d_crypto->computeHMAC_SHA_256(key, message); @@ -268,4 +248,119 @@ TEST(GnssCryptoTest, TestComputeCMAC_AES) std::vector output = d_crypto->computeCMAC_AES(key, message); ASSERT_EQ(expected_output, output); -} \ No newline at end of file +} + + +TEST(GnssCryptoTest, VerifySignature) +{ + auto d_crypto = std::make_unique(); + + // RG example - import crt certificate + std::vector 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}; + + // ECDSA P-256 signature, raw format + std::vector signature = { + 0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, + 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, + 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, + 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, + 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, + 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, + 0x28, 0xC1, 0x77, 0xFB}; + + // PEM format + std::vector 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->verify_signature(message, signature); + ASSERT_TRUE(result); + + std::vector wrong_signature = signature; + wrong_signature[1] = 1; + bool result2 = d_crypto->verify_signature(message, wrong_signature); + ASSERT_TRUE(!result2); +} + + +TEST(GnssCryptoTest, VerifySignatureP521) +{ + std::unique_ptr d_crypto = std::make_unique(); + + // Message to be verified + std::vector message = { + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 // "Hello World" + }; + + // Public key in PEM format + std::vector 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, 0x49, 0x47, 0x62, 0x4D, 0x42, 0x41, 0x47, 0x42, + 0x79, 0x71, 0x47, 0x53, 0x4D, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, + 0x53, 0x75, 0x42, 0x42, 0x41, 0x41, 0x6A, 0x41, 0x34, 0x47, 0x47, 0x41, + 0x41, 0x51, 0x41, 0x6F, 0x35, 0x76, 0x77, 0x66, 0x6E, 0x47, 0x57, 0x47, + 0x33, 0x44, 0x63, 0x59, 0x75, 0x2B, 0x2F, 0x61, 0x58, 0x47, 0x32, 0x7A, + 0x74, 0x65, 0x41, 0x46, 0x50, 0x54, 0x33, 0x0A, 0x48, 0x36, 0x4C, 0x76, + 0x4F, 0x4C, 0x76, 0x49, 0x51, 0x6A, 0x61, 0x2B, 0x6A, 0x74, 0x57, 0x73, + 0x70, 0x4F, 0x38, 0x37, 0x6F, 0x50, 0x32, 0x4E, 0x6D, 0x72, 0x34, 0x6E, + 0x50, 0x68, 0x76, 0x62, 0x53, 0x58, 0x52, 0x4D, 0x37, 0x6A, 0x49, 0x69, + 0x46, 0x38, 0x47, 0x70, 0x6B, 0x75, 0x58, 0x6A, 0x75, 0x4E, 0x7A, 0x34, + 0x72, 0x61, 0x56, 0x4F, 0x65, 0x49, 0x4D, 0x42, 0x77, 0x45, 0x2B, 0x61, + 0x0A, 0x30, 0x4C, 0x76, 0x7A, 0x37, 0x69, 0x54, 0x4D, 0x5A, 0x46, 0x41, + 0x41, 0x51, 0x64, 0x2B, 0x70, 0x47, 0x72, 0x56, 0x54, 0x47, 0x77, 0x66, + 0x53, 0x48, 0x49, 0x72, 0x49, 0x49, 0x45, 0x78, 0x74, 0x5A, 0x35, 0x77, + 0x30, 0x38, 0x51, 0x4F, 0x43, 0x58, 0x2F, 0x75, 0x46, 0x65, 0x2B, 0x30, + 0x78, 0x52, 0x78, 0x4C, 0x64, 0x2F, 0x33, 0x36, 0x42, 0x4E, 0x74, 0x63, + 0x74, 0x69, 0x2F, 0x45, 0x4C, 0x0A, 0x4B, 0x31, 0x35, 0x67, 0x2B, 0x4B, + 0x32, 0x71, 0x67, 0x2F, 0x6C, 0x39, 0x46, 0x42, 0x47, 0x67, 0x4D, 0x2B, + 0x51, 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}; + + // ECDSA P-521 signature, raw format + std::vector signature = { + 0x01, 0x7B, 0x59, 0xAC, 0x3A, 0x03, 0x5C, 0xB4, 0x07, 0xCD, + 0xC1, 0xEB, 0xBE, 0xE5, 0xA6, 0xCB, 0xDA, 0x0A, 0xFF, 0x4D, + 0x38, 0x61, 0x16, 0x0F, 0xB3, 0x77, 0xE5, 0x8A, 0xDC, 0xF3, + 0xFD, 0x79, 0x38, 0x1E, 0xE8, 0x08, 0x3D, 0x5D, 0xBC, 0xC2, + 0x80, 0x6E, 0xE9, 0x2B, 0xC3, 0xEF, 0x07, 0x3D, 0x0C, 0x82, + 0x4C, 0x9B, 0x7A, 0x5C, 0x2E, 0xD5, 0x46, 0xBD, 0x22, 0x21, + 0x13, 0x8A, 0xB2, 0xCA, 0x96, 0x3D, 0x01, 0xBA, 0x2A, 0xC4, + 0x3F, 0xDB, 0x66, 0x3C, 0x40, 0x26, 0xD9, 0xBC, 0x26, 0xD5, + 0x57, 0xD4, 0xBD, 0x15, 0x16, 0x88, 0x21, 0x3B, 0xAA, 0x07, + 0x89, 0xEF, 0x29, 0x8F, 0x2F, 0x85, 0x76, 0x58, 0x9D, 0xCA, + 0x00, 0xCC, 0xC8, 0x30, 0x88, 0x31, 0x99, 0xC1, 0x94, 0xB9, + 0xAF, 0x91, 0xDC, 0xC4, 0x6F, 0x19, 0x2B, 0x12, 0xA2, 0x82, + 0xA5, 0x66, 0x5E, 0x4B, 0xBB, 0xDF, 0x65, 0x81, 0x52, 0x14, + 0x01, 0xD7}; + + d_crypto->set_public_key(publicKey); + bool result = d_crypto->verify_signature_ecdsa_p521(message, signature); + ASSERT_TRUE(result); + + std::vector wrong_signature = signature; + wrong_signature[1] = 1; + bool result2 = d_crypto->verify_signature_ecdsa_p521(message, wrong_signature); + ASSERT_TRUE(!result2); +} From cb0c0d02fb72ce8d42f2167e621c7c981862f591 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 18 Jul 2024 08:43:03 +0200 Subject: [PATCH 165/219] Fix ECDSA P-521 in GnuTLS --- src/core/system_parameters/gnss_crypto.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 7b1d837e0..0e98280cf 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -309,7 +309,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag gnutls_datum_t signature_data = {der_sig.data(), static_cast(der_sig.size())}; // Verify the ECDSA signature - ret = gnutls_pubkey_verify_data2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA512, 0, &digest_data, &signature_data); + ret = gnutls_pubkey_verify_hash2(d_PublicKey, GNUTLS_SIGN_ECDSA_SHA512, 0, &digest_data, &signature_data); if (ret >= 0) { From d6871931565836b683fcda757e7f266384e63804 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 18 Jul 2024 10:49:52 +0200 Subject: [PATCH 166/219] Improve consistency of public API member function names in Gnss_Crypto --- src/core/libs/osnma_msg_receiver.cc | 28 +- src/core/system_parameters/gnss_crypto.cc | 260 +++++++++--------- src/core/system_parameters/gnss_crypto.h | 20 +- .../osnma/gnss_crypto_test.cc | 20 +- .../osnma/osnma_msg_receiver_test.cc | 2 +- 5 files changed, 165 insertions(+), 165 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 43e62a738..293058b26 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -457,11 +457,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg std::vector hash; if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. { - hash = d_crypto->computeSHA256(MSG); + hash = d_crypto->compute_SHA_256(MSG); } else if (d_osnma_data.d_dsm_kroot_message.hf == 2) { - hash = d_crypto->computeSHA3_256(MSG); + hash = d_crypto->compute_SHA3_256(MSG); } else { @@ -483,7 +483,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; local_time_verification(osnma_msg); - d_kroot_verified = d_crypto->verify_signature(message, d_osnma_data.d_dsm_kroot_message.ds); + d_kroot_verified = d_crypto->verify_signature_ecdsa_p256(message, d_osnma_data.d_dsm_kroot_message.ds); if (d_kroot_verified) { std::cout << "Galileo OSNMA: KROOT authentication successful!" << std::endl; @@ -1040,7 +1040,7 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) computed_merkle_root = compute_merke_root(message, base_leaf); - if (computed_merkle_root == d_crypto->getMerkleRoot()) + if (computed_merkle_root == d_crypto->get_merkle_root()) { LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: SUCCESS!." << std::endl; return true; @@ -1053,7 +1053,7 @@ bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) } std::vector osnma_msg_receiver::compute_merke_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const { - std::vector x_next, x_current = d_crypto->computeSHA256(m_i); + std::vector x_next, x_current = d_crypto->compute_SHA_256(m_i); for (size_t i = 0; i < 4; i++) { x_next.clear(); @@ -1073,7 +1073,7 @@ std::vector osnma_msg_receiver::compute_merke_root(const DSM_PKR_messag } // Compute the next node. - x_current = d_crypto->computeSHA256(x_next); + x_current = d_crypto->compute_SHA_256(x_next); } return x_current; } @@ -1116,11 +1116,11 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { - mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + mac = d_crypto->compute_HMAC_SHA_256(applicable_key, m); } else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { - mac = d_crypto->computeCMAC_AES(applicable_key, m); + mac = d_crypto->compute_CMAC_AES(applicable_key, m); } // truncate the computed mac: trunc(l_t, mac(K,m)) Eq. 23 ICD @@ -1484,11 +1484,11 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) std::vector mac; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { - mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + mac = d_crypto->compute_HMAC_SHA_256(applicable_key, m); } else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { - mac = d_crypto->computeCMAC_AES(applicable_key, m); + mac = d_crypto->compute_CMAC_AES(applicable_key, m); } // Truncate the twelve MSBits and compare with received MACSEQ uint16_t mac_msb = 0; @@ -1598,11 +1598,11 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede std::vector hash; if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. { - hash = d_crypto->computeSHA256(msg); + hash = d_crypto->compute_SHA_256(msg); } else if (d_osnma_data.d_dsm_kroot_message.hf == 2) { - hash = d_crypto->computeSHA3_256(msg); + hash = d_crypto->compute_SHA3_256(msg); } else { @@ -1729,11 +1729,11 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ std::vector mac; if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { - mac = d_crypto->computeHMAC_SHA_256(applicable_key, m); + mac = d_crypto->compute_HMAC_SHA_256(applicable_key, m); } else if (d_osnma_data.d_dsm_kroot_message.mf == 1) // C: CMAC-AES { - mac = d_crypto->computeCMAC_AES(applicable_key, m); + mac = d_crypto->compute_CMAC_AES(applicable_key, m); } // Truncate the twelve MSBits and compare with received MACSEQ uint16_t mac_msb = 0; diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 0e98280cf..289b7e17f 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -133,9 +133,73 @@ bool Gnss_Crypto::have_public_key() const } -bool Gnss_Crypto::verify_signature(const std::vector& message, const std::vector& signature) const +bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const { - std::vector digest = this->computeSHA256(message); + 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; +} + + +bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& message, const std::vector& signature) const +{ + std::vector digest = this->compute_SHA_256(message); if (!have_public_key()) { std::cerr << "Galileo OSNMA KROOT verification error: Public key is not available" << std::endl; @@ -396,130 +460,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag } -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 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 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 - std::vector 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 Gnss_Crypto::getMerkleRoot() const -{ - return d_x_4_0; -} - - -std::vector Gnss_Crypto::computeSHA256(const std::vector& input) const +std::vector Gnss_Crypto::compute_SHA_256(const std::vector& input) const { std::vector output(32); // SHA256 hash size #if USE_GNUTLS_FALLBACK @@ -564,7 +505,7 @@ std::vector Gnss_Crypto::computeSHA256(const std::vector& inpu } -std::vector Gnss_Crypto::computeSHA3_256(const std::vector& input) const +std::vector Gnss_Crypto::compute_SHA3_256(const std::vector& input) const { std::vector output(32); // SHA256 hash size #if USE_GNUTLS_FALLBACK @@ -598,7 +539,7 @@ std::vector Gnss_Crypto::computeSHA3_256(const std::vector& in } -std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const +std::vector Gnss_Crypto::compute_HMAC_SHA_256(const std::vector& key, const std::vector& input) const { std::vector output(32); #if USE_GNUTLS_FALLBACK @@ -686,7 +627,7 @@ std::vector Gnss_Crypto::computeHMAC_SHA_256(const std::vector } -std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& key, const std::vector& input) const +std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& key, const std::vector& input) const { std::vector output(16); #if USE_GNUTLS_FALLBACK @@ -829,6 +770,65 @@ std::vector Gnss_Crypto::computeCMAC_AES(const std::vector& ke } +std::vector Gnss_Crypto::get_public_key() 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 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 + std::vector 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 Gnss_Crypto::get_merkle_root() const +{ + return d_x_4_0; +} + + void Gnss_Crypto::set_public_key(const std::vector& publicKey) { #if USE_GNUTLS_FALLBACK @@ -884,7 +884,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) } -void Gnss_Crypto::setMerkleRoot(const std::vector& v) +void Gnss_Crypto::set_merkle_root(const std::vector& v) { d_x_4_0 = v; } diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 117d5e0a7..8e89f1525 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -53,24 +53,24 @@ public: bool have_public_key() const; //!< Returns true if the ECDSA Public Key is already loaded - bool verify_signature(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P256 signature (message in hex, signature in raw format) - bool verify_signature_ecdsa_p521(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P521 signature (message in hex, signature in raw format) - /*! * Stores the ECDSA Public Key in a .pem file, which is read in a following run if the .crt file is not found */ bool store_public_key(const std::string& pubKeyFilePath) const; - std::vector getPublicKey() const; //!< Gets the ECDSA Public Key in PEM format - std::vector getMerkleRoot() const; //!< Gets the Merkle Tree root node (\f$ x_{4,0} \f$) + bool verify_signature_ecdsa_p256(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P256 signature (message in plain hex, signature in raw format) + bool verify_signature_ecdsa_p521(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P521 signature (message in plain hex, signature in raw format) - std::vector computeSHA256(const std::vector& input) const; //!< Computes SHA-256 hash - std::vector computeSHA3_256(const std::vector& input) const; //!< Computes SHA3-256 hash - std::vector computeHMAC_SHA_256(const std::vector& key, const std::vector& input) const; //!< Computes HMAC-SHA-256 message authentication code - std::vector computeCMAC_AES(const std::vector& key, const std::vector& input) const; //!< Computes CMAC-AES message authentication code + std::vector compute_SHA_256(const std::vector& input) const; //!< Computes SHA-256 hash + std::vector compute_SHA3_256(const std::vector& input) const; //!< Computes SHA3-256 hash + std::vector compute_HMAC_SHA_256(const std::vector& key, const std::vector& input) const; //!< Computes HMAC-SHA-256 message authentication code + std::vector compute_CMAC_AES(const std::vector& key, const std::vector& input) const; //!< Computes CMAC-AES message authentication code + + std::vector get_public_key() const; //!< Gets the ECDSA Public Key in PEM format + std::vector get_merkle_root() const; //!< Gets the Merkle Tree root node (\f$ x_{4,0} \f$) void set_public_key(const std::vector& publickey); //!< Sets the ECDSA Public Key (publickey in PEM format) - void setMerkleRoot(const std::vector& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$) + void set_merkle_root(const std::vector& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$) private: void read_merkle_xml(const std::string& merkleFilePath); 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 bbe01d905..2d7355fd7 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 @@ -96,7 +96,7 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) ASSERT_EQ(content_file, content_file2); - std::vector readkey = d_crypto2->getPublicKey(); + std::vector readkey = d_crypto2->get_public_key(); ASSERT_EQ(publicKey, readkey); errorlib::error_code ec; @@ -116,7 +116,7 @@ TEST(GnssCryptoTest, TestComputeSHA_256) 0x43, 0xAC, 0x4E, 0x43, 0xFC, 0x00, 0x4C, 0x89, 0x16, 0x04, 0xB2, 0x6F, 0x8C, 0x69, 0xE1, 0xE8, 0x3E, 0xA2, 0xAF, 0xC7, 0xC4, 0x8F}; - std::vector output = d_crypto->computeSHA256(message); + std::vector output = d_crypto->compute_SHA_256(message); ASSERT_EQ(expected_output, output); } @@ -133,7 +133,7 @@ TEST(GnssCryptoTest, TestComputeSHA3_256) 0xBB, 0x2C, 0x24, 0x36, 0x72, 0x5E, 0x2E, 0x8D, 0xC7, 0x5B, 0x99, 0xE7, 0xF6, 0xC4, 0x50, 0x5B, 0x2A, 0x93, 0x6E, 0xB6, 0x3B, 0x3F}; - std::vector output = d_crypto->computeSHA3_256(message); + std::vector output = d_crypto->compute_SHA3_256(message); ASSERT_EQ(expected_output, output); } @@ -159,7 +159,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256) 0xB2, 0x7A, 0xCC, 0x22, 0x00, 0xAA, 0xD2, 0x37, 0xD0, 0x79, 0x06, 0x12, 0x83, 0x40, 0xB7, 0xA6}; - std::vector output = d_crypto->computeHMAC_SHA_256(key, message); + std::vector output = d_crypto->compute_HMAC_SHA_256(key, message); ASSERT_EQ(expected_output, output); } @@ -194,7 +194,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_m0) 0xD2, 0xEA, 0x61, 0xE1, 0xEF, 0x09, 0x11, 0x5C, 0xFE, 0x70, 0x68, 0x52, 0xBF, 0xF2, 0x3A, 0x83}; - std::vector output = d_crypto->computeHMAC_SHA_256(key, message); + std::vector output = d_crypto->compute_HMAC_SHA_256(key, message); ASSERT_EQ(expected_output, output); } @@ -222,7 +222,7 @@ TEST(GnssCryptoTest, TestComputeHMACSHA256_adkd4) 0x44, 0xAB, 0xEE, 0x4D, 0xCE, 0xB9, 0x3D, 0xCF, 0x65, 0xCB, 0x3A, 0x5B, 0x81, 0x4A, 0x34, 0xE9}; - std::vector output = d_crypto->computeHMAC_SHA_256(key, message); + std::vector output = d_crypto->compute_HMAC_SHA_256(key, message); ASSERT_EQ(expected_output, output); } @@ -245,13 +245,13 @@ TEST(GnssCryptoTest, TestComputeCMAC_AES) 0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44, 0xF7, 0x9B, 0xDD, 0x9D, 0xD0, 0x4A, 0x28, 0x7C}; - std::vector output = d_crypto->computeCMAC_AES(key, message); + std::vector output = d_crypto->compute_CMAC_AES(key, message); ASSERT_EQ(expected_output, output); } -TEST(GnssCryptoTest, VerifySignature) +TEST(GnssCryptoTest, VerifySignatureP256) { auto d_crypto = std::make_unique(); @@ -293,12 +293,12 @@ TEST(GnssCryptoTest, VerifySignature) 0x45, 0x59, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x0A}; d_crypto->set_public_key(publicKey); - bool result = d_crypto->verify_signature(message, signature); + bool result = d_crypto->verify_signature_ecdsa_p256(message, signature); ASSERT_TRUE(result); std::vector wrong_signature = signature; wrong_signature[1] = 1; - bool result2 = d_crypto->verify_signature(message, wrong_signature); + bool result2 = d_crypto->verify_signature_ecdsa_p256(message, wrong_signature); ASSERT_TRUE(!result2); } diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 6b7f280a4..7daa43fb4 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -112,7 +112,7 @@ TEST_F(OsnmaMsgReceiverTest, ComputeBaseLeaf) TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey){ // values taken from RG A.7 // Arrange // ---------- - osnma->d_crypto->setMerkleRoot(helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D")); + osnma->d_crypto->set_merkle_root(helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D")); DSM_PKR_message dsm_pkr_message; dsm_pkr_message.npkt = 0x01; dsm_pkr_message.npktid = 0x2; From 82973db0d65684dce5044219c332becf45a5d894 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 18 Jul 2024 14:37:02 +0200 Subject: [PATCH 167/219] Fixes for old GnuTLS --- cmake/Modules/GnssSdrCrypto.cmake | 6 + src/core/system_parameters/gnss_crypto.cc | 138 ++++++++++++---------- 2 files changed, 83 insertions(+), 61 deletions(-) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index 58c1c94e2..b1edb5982 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -117,6 +117,9 @@ else() if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_SIGN_ECDSA_SHA256") set(GNUTLS_SIGN_ECDSA_SHA256 TRUE) endif() + if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_SIGN_ECDSA_SHA512") + set(GNUTLS_SIGN_ECDSA_SHA512 TRUE) + endif() if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_DIG_SHA3_256") set(GNUTLS_DIG_SHA3_256 TRUE) endif() @@ -181,6 +184,9 @@ function(link_to_crypto_dependencies target) if(GNUTLS_SIGN_ECDSA_SHA256) target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_SIGN_ECDSA_SHA256=1) endif() + if(GNUTLS_SIGN_ECDSA_SHA512) + target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_SIGN_ECDSA_SHA512=1) + endif() if(GNUTLS_DIG_SHA3_256) target_compile_definitions(${target} PRIVATE -DHAVE_GNUTLS_DIG_SHA3_256=1) endif() diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 289b7e17f..12828cdca 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -142,7 +142,7 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const std::ofstream pubKeyFile(pubKeyFilePath, std::ios::binary); if (!pubKeyFile.is_open()) { - LOG(INFO) << "Unable to open file: " << pubKeyFilePath; + LOG(WARNING) << "Unable to open file for storing the Public Key: " << pubKeyFilePath; return false; } #if USE_GNUTLS_FALLBACK @@ -155,7 +155,7 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const #endif if (ret != GNUTLS_E_SUCCESS) { - LOG(INFO) << "GnuTLS: Failed to export public key: " << gnutls_strerror(ret); + LOG(WARNING) << "GnuTLS: Failed to export public key: " << gnutls_strerror(ret); return false; } @@ -166,7 +166,7 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const BIO* bio = BIO_new(BIO_s_mem()); if (!bio) { - LOG(INFO) << "OpenSSL: Failed to create BIO"; + LOG(WARNING) << "OpenSSL: Failed to create BIO"; return false; } #if USE_OPENSSL_3 @@ -175,7 +175,7 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const if (!PEM_write_bio_EC_PUBKEY(bio, d_PublicKey)) #endif { - LOG(INFO) << "OpenSSL: Failed to write public key to BIO"; + LOG(WARNING) << "OpenSSL: Failed to write public key to BIO"; BIO_free(bio); return false; } @@ -184,7 +184,7 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const auto bio_len = BIO_get_mem_data(bio, &bio_data); if (bio_len <= 0) { - LOG(INFO) << "OpenSSL: Failed to get BIO data"; + LOG(WARNING) << "OpenSSL: Failed to get BIO data"; BIO_free(bio); return false; } @@ -202,7 +202,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag std::vector digest = this->compute_SHA_256(message); if (!have_public_key()) { - std::cerr << "Galileo OSNMA KROOT verification error: Public key is not available" << std::endl; + LOG(WARNING) << "Galileo OSNMA KROOT verification error: Public key is not available"; return false; } bool success = false; @@ -212,7 +212,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag std::vector der_sig; if (!convert_raw_to_der_ecdsa(signature, der_sig)) { - std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; + LOG(WARNING) << "Failed to convert raw ECDSA signature to DER format"; return false; } @@ -229,9 +229,13 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag } else { - std::cerr << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret) << std::endl; LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); } +#else + if (signature.empty()) + { + // do nothing + } #endif #else // OpenSSL #if USE_OPENSSL_3 @@ -255,13 +259,13 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag ECDSA_SIG* sig = ECDSA_SIG_new(); if (r == nullptr || s == nullptr || sig == nullptr) { - std::cerr << "Failed to allocate memory for BIGNUMs or ECDSA_SIG" << std::endl; + LOG(WARNING) << "OpenSSL: Failed to allocate memory for BIGNUMs or ECDSA_SIG"; return false; } if (ECDSA_SIG_set0(sig, r, s) != 1) { - std::cerr << "Failed to set R and S values in ECDSA_SIG" << std::endl; + LOG(WARNING) << "OpenSSL: Failed to set R and S values in ECDSA_SIG"; ECDSA_SIG_free(sig); // Free the ECDSA_SIG struct as it is no longer needed return false; } @@ -272,7 +276,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag if (derSigLength <= 0) { - std::cerr << "Failed to convert ECDSA_SIG to DER format" << std::endl; + LOG(WARNING) << "OpenSSL: Failed to convert ECDSA_SIG to DER format"; return false; } @@ -303,14 +307,13 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag { unsigned long errCode = ERR_get_error(); char* err = ERR_error_string(errCode, nullptr); - std::cerr << "OpenSSL: OSNMA message authentication failed: " << err << std::endl; LOG(WARNING) << "OpenSSL: OSNMA message authentication failed: " << err; } #else // OpenSSL 1.x std::vector der_sig; if (!convert_raw_to_der_ecdsa(signature, der_sig)) { - std::cerr << "Failed to convert raw ECDSA signature to DER format" << std::endl; + LOG(WARNING) << "OpenSSL: Failed to convert raw ECDSA signature to DER format"; return false; } int verification = ECDSA_verify(0, digest.data(), SHA256_DIGEST_LENGTH, der_sig.data(), static_cast(der_sig.size()), d_PublicKey); @@ -321,12 +324,10 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag } else if (verification == 0) { - std::cerr << "OpenSSL: invalid signature found when verifying message" << std::endl; LOG(WARNING) << "OpenSSL: invalid signature found when verifying message"; } else { - std::cerr << "OpenSSL: OSNMA message authentication failed" << std::endl; LOG(WARNING) << "OpenSSL: OSNMA message authentication failed"; } #endif @@ -339,30 +340,31 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag { if (!have_public_key()) { - LOG(ERROR) << "Galileo OSNMA KROOT verification error: Public key is not available"; + LOG(WARNING) << "Galileo OSNMA KROOT verification error: Public key is not available"; return false; } if (signature.size() != 132) { - LOG(ERROR) << "Invalid signature length for P-521. Expected 132 bytes, got " << signature.size(); + LOG(WARNING) << "Invalid signature length for P-521. Expected 132 bytes, got " << signature.size(); return false; } std::vector der_sig; if (!convert_raw_to_der_ecdsa(signature, der_sig)) { - LOG(ERROR) << "Failed to convert raw ECDSA signature to DER format"; + LOG(WARNING) << "Failed to convert raw ECDSA signature to DER format"; return false; } bool success = false; #if USE_GNUTLS_FALLBACK +#if HAVE_GNUTLS_SIGN_ECDSA_SHA512 std::vector digest(64); gnutls_hash_hd_t hash; int ret = gnutls_hash_init(&hash, GNUTLS_DIG_SHA512); if (ret != GNUTLS_E_SUCCESS) { - LOG(ERROR) << "GnuTLS: gnutls_hash_init failed: " << gnutls_strerror(ret); + LOG(WARNING) << "GnuTLS: gnutls_hash_init failed: " << gnutls_strerror(ret); return false; } @@ -384,12 +386,18 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag { LOG(WARNING) << "GnuTLS: OSNMA message authentication failed: " << gnutls_strerror(ret); } +#else + if (message.empty()) + { + // do nothing + } +#endif #else // OpenSSL // Compute SHA-512 hash of the message std::vector digest(SHA512_DIGEST_LENGTH); if (!EVP_Digest(message.data(), message.size(), digest.data(), nullptr, EVP_sha512(), nullptr)) { - LOG(INFO) << "OpenSSL: EVP_Digest failed"; + LOG(WARNING) << "OpenSSL: EVP_Digest failed"; return false; } #if USE_OPENSSL_3 @@ -397,20 +405,20 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new(d_PublicKey, nullptr); if (pctx == nullptr) { - LOG(INFO) << "OpenSSL: EVP_PKEY_CTX_new failed"; + LOG(WARNING) << "OpenSSL: EVP_PKEY_CTX_new failed"; return false; } if (EVP_PKEY_verify_init(pctx) <= 0) { - LOG(INFO) << "OpenSSL: EVP_PKEY_verify_init failed"; + LOG(WARNING) << "OpenSSL: EVP_PKEY_verify_init failed"; EVP_PKEY_CTX_free(pctx); return false; } if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha512()) <= 0) { - LOG(INFO) << "OpenSSL: EVP_PKEY_CTX_set_signature_md failed"; + LOG(WARNING) << "OpenSSL: EVP_PKEY_CTX_set_signature_md failed"; EVP_PKEY_CTX_free(pctx); return false; } @@ -425,18 +433,18 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag } else if (verification == 0) { - LOG(INFO) << "OpenSSL: invalid signature found when verifying message"; + LOG(WARNING) << "OpenSSL: invalid signature found when verifying message"; } else { - LOG(INFO) << "OpenSSL: OSNMA message authentication failed"; + LOG(WARNING) << "OpenSSL: OSNMA message authentication failed"; } #else // OpenSSL 1.x const unsigned char* sig_ptr = der_sig.data(); ECDSA_SIG* ecdsa_sig = d2i_ECDSA_SIG(nullptr, &sig_ptr, der_sig.size()); if (ecdsa_sig == nullptr) { - LOG(INFO) << "OpenSSL: d2i_ECDSA_SIG failed"; + LOG(WARNING) << "OpenSSL: d2i_ECDSA_SIG failed"; return false; } int verification = ECDSA_do_verify(digest.data(), digest.size(), ecdsa_sig, d_PublicKey); @@ -448,11 +456,11 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag } else if (verification == 0) { - LOG(INFO) << "OpenSSL: invalid signature found when verifying message"; + LOG(WARNING) << "OpenSSL: invalid signature found when verifying message"; } else { - LOG(INFO) << "OpenSSL: OSNMA message authentication failed"; + LOG(WARNING) << "OpenSSL: OSNMA message authentication failed"; } #endif #endif @@ -517,6 +525,11 @@ std::vector Gnss_Crypto::compute_SHA3_256(const std::vector& i gnutls_hash_output(hashHandle, output_aux.data()); output = output_aux; gnutls_hash_deinit(hashHandle, output_aux.data()); +#else + if (input.empty()) + { + // do nothing + } #endif #else // OpenSSL #if USE_OPENSSL_3 || USE_OPENSSL_111 @@ -638,7 +651,7 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k int ret = gnutls_hmac_init(&hmac, GNUTLS_MAC_AES_CMAC_128, key.data(), key.size()); if (ret != GNUTLS_E_SUCCESS) { - LOG(INFO) << "OSNMA CMAC-AES: gnutls_hmac_init failed: " << gnutls_strerror(ret); + LOG(WARNING) << "OSNMA CMAC-AES: gnutls_hmac_init failed: " << gnutls_strerror(ret); return output; } @@ -646,7 +659,7 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k ret = gnutls_hmac(hmac, input.data(), input.size()); if (ret != GNUTLS_E_SUCCESS) { - LOG(INFO) << "OSNMA CMAC-AES: gnutls_hmac failed: " << gnutls_strerror(ret); + LOG(WARNING) << "OSNMA CMAC-AES: gnutls_hmac failed: " << gnutls_strerror(ret); gnutls_hmac_deinit(hmac, nullptr); return output; } @@ -675,14 +688,14 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k EVP_MAC* mac = EVP_MAC_fetch(nullptr, "CMAC", nullptr); if (!mac) { - LOG(INFO) << "OSNMA CMAC-AES: Failed to fetch CMAC"; + LOG(WARNING) << "OSNMA CMAC-AES: Failed to fetch CMAC"; return output; } EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac); if (!ctx) { - LOG(INFO) << "OSNMA CMAC-AES: Failed to create CMAC context"; + LOG(WARNING) << "OSNMA CMAC-AES: Failed to create CMAC context"; return output; } @@ -696,7 +709,7 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k { EVP_MAC_CTX_free(ctx); EVP_MAC_free(mac); - LOG(INFO) << "OSNMA CMAC-AES: Failed to initialize CMAC context"; + LOG(WARNING) << "OSNMA CMAC-AES: Failed to initialize CMAC context"; return output; } @@ -705,7 +718,7 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k { EVP_MAC_CTX_free(ctx); EVP_MAC_free(mac); - LOG(INFO) << "OSNMA CMAC-AES: Failed to update CMAC context"; + LOG(WARNING) << "OSNMA CMAC-AES: Failed to update CMAC context"; return output; } @@ -714,7 +727,7 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k { EVP_MAC_CTX_free(ctx); EVP_MAC_free(mac); - LOG(INFO) << "OSNMA CMAC-AES: Failed to finalize CMAC"; + LOG(WARNING) << "OSNMA CMAC-AES: Failed to finalize CMAC"; return output; } @@ -731,14 +744,14 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k CMAC_CTX* cmacCtx = CMAC_CTX_new(); if (!cmacCtx) { - LOG(INFO) << "OSNMA CMAC-AES: Failed to create CMAC context"; + LOG(WARNING) << "OSNMA CMAC-AES: Failed to create CMAC context"; return output; } // Initialize the CMAC context with the key and cipher if (CMAC_Init(cmacCtx, key.data(), key.size(), EVP_aes_128_cbc(), nullptr) != 1) { - LOG(INFO) << "OSNMA CMAC-AES: MAC_Init failed"; + LOG(WARNING) << "OSNMA CMAC-AES: MAC_Init failed"; CMAC_CTX_free(cmacCtx); return output; } @@ -746,7 +759,7 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k // Compute the CMAC if (CMAC_Update(cmacCtx, input.data(), input.size()) != 1) { - LOG(INFO) << "OSNMA CMAC-AES: CMAC_Update failed"; + LOG(WARNING) << "OSNMA CMAC-AES: CMAC_Update failed"; CMAC_CTX_free(cmacCtx); return output; } @@ -754,7 +767,7 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k // Finalize the CMAC computation and retrieve the output if (CMAC_Final(cmacCtx, output.data(), &mac_length) != 1) { - LOG(INFO) << "OSNMA CMAC-AES: CMAC_Final failed"; + LOG(WARNING) << "OSNMA CMAC-AES: CMAC_Final failed"; CMAC_CTX_free(cmacCtx); return output; } @@ -778,11 +791,15 @@ std::vector Gnss_Crypto::get_public_key() const } #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(INFO) << "GnuTLS: Failed to export public key to PEM format."; + LOG(WARNING) << "GnuTLS: Failed to export public key to PEM format."; return {}; } std::vector output(pem_data.data, pem_data.data + pem_data.size); @@ -794,7 +811,7 @@ std::vector Gnss_Crypto::get_public_key() const BIO* mem = BIO_new(BIO_s_mem()); if (!mem) { - LOG(INFO) << "OpenSSL: Failed to create BIO."; + LOG(WARNING) << "OpenSSL: Failed to create BIO."; return {}; } #if USE_OPENSSL_3 @@ -804,7 +821,7 @@ std::vector Gnss_Crypto::get_public_key() const #endif { BIO_free(mem); - LOG(INFO) << "OpenSSL: Failed to write public key to PEM format."; + LOG(WARNING) << "OpenSSL: Failed to write public key to PEM format."; return {}; } @@ -852,7 +869,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) bio = BIO_new_mem_buf(const_cast(publicKey.data()), publicKey.size()); if (!bio) { - LOG(INFO) << "OpenSSL: Failed to create BIO for key."; + LOG(WARNING) << "OpenSSL: Failed to create BIO for key."; return; } @@ -861,8 +878,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) if (!pkey) { - std::cerr << "OpenSSL: error setting the OSNMA public key." << std::endl; - LOG(INFO) << "OpenSSL: error setting the OSNMA public key."; + LOG(WARNING) << "OpenSSL: error setting the OSNMA public key."; return; } #if USE_OPENSSL_3 @@ -900,7 +916,7 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) // If it was not the default, maybe it is a configuration error, warn user if (merkleFilePath != MERKLEFILE_DEFAULT && !merkleFilePath.empty()) { - LOG(INFO) << "File " << merkleFilePath << " not found"; + LOG(WARNING) << "File " << merkleFilePath << " not found"; } // fill default values d_x_4_0 = convert_from_hex_str("832E15EDE55655EAC6E399A539477B7C034CCE24C3C93FFC904ACD9BF842F04E"); @@ -966,7 +982,7 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) } catch (const std::exception& e) { - std::cerr << "Exception raised reading the " << merkleFilePath << " file: " << e.what() << '\n'; + LOG(INFO) << "Exception raised reading the " << merkleFilePath << " file: " << e.what(); d_x_4_0 = convert_from_hex_str("832E15EDE55655EAC6E399A539477B7C034CCE24C3C93FFC904ACD9BF842F04E"); return; } @@ -997,8 +1013,8 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) std::cerr << "GnuTLS: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import" << std::endl; - std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; - LOG(INFO) << "GnuTLS: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import"; + LOG(WARNING) << "GnuTLS: error reading the OSNMA Public Key from file " + << pemFilePath << ". Aborting import. Error " << gnutls_strerror(ret); return; } @@ -1009,7 +1025,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) BIO* bio = BIO_new_mem_buf(const_cast(pemContent.c_str()), pemContent.length()); if (!bio) { - std::cerr << "OpenSSL: error creating a BIO object with data read from file " << pemFilePath << ". Aborting import" << std::endl; + LOG(WARNING) << "OpenSSL: error creating a BIO object with data read from file " << pemFilePath << ". Aborting import."; return; } #if USE_OPENSSL_3 @@ -1021,7 +1037,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) if (d_PublicKey == nullptr) { std::cerr << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import" << std::endl; - LOG(INFO) << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import"; + LOG(WARNING) << "OpenSSL: error reading the OSNMA Public Key from file " << pemFilePath << ". Aborting import."; return; } #endif @@ -1039,7 +1055,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { // CRT file not found // If it was not the default, maybe it is a configuration error - if (crtFilePath != CRTFILE_DEFAULT) + if (crtFilePath != CRTFILE_DEFAULT && !crtFilePath.empty()) { std::cerr << "File " << crtFilePath << " not found" << std::endl; } @@ -1054,7 +1070,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) int ret = gnutls_x509_crt_import(cert, &buffer_datum, GNUTLS_X509_FMT_PEM); if (ret < 0) { - LOG(INFO) << "GnuTLS: Failed to import certificate: " << gnutls_strerror(ret); + LOG(WARNING) << "GnuTLS: Failed to import certificate: " << gnutls_strerror(ret); gnutls_x509_crt_deinit(cert); return false; } @@ -1065,7 +1081,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) ret = gnutls_pubkey_import_x509(pubkey, cert, 0); if (ret < 0) { - LOG(INFO) << "GnuTLS: Failed to import public key: " << gnutls_strerror(ret); + LOG(WARNING) << "GnuTLS: Failed to import public key: " << gnutls_strerror(ret); gnutls_pubkey_deinit(pubkey); gnutls_x509_crt_deinit(cert); return false; @@ -1078,7 +1094,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) std::ifstream crtFile(crtFilePath, std::ios::binary); if (!crtFile.is_open()) { - LOG(INFO) << "OpenSSL: Unable to open file: " << crtFilePath; + LOG(WARNING) << "OpenSSL: Unable to open file: " << crtFilePath; return false; } @@ -1087,13 +1103,13 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) BIO* bio = BIO_new_mem_buf(buffer.data(), buffer.size()); if (!bio) { - LOG(INFO) << "OpenSSL: Unable to create BIO for file: " << crtFilePath; + LOG(WARNING) << "OpenSSL: Unable to create BIO for file: " << crtFilePath; return false; } X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); if (!cert) { - LOG(INFO) << "OpenSSL: Unable to read certificate from file: " << crtFilePath; + LOG(WARNING) << "OpenSSL: Unable to read certificate from file: " << crtFilePath; BIO_free(bio); return false; } @@ -1103,7 +1119,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) #if USE_OPENSSL_3 if (!pubkey) { - LOG(INFO) << "OpenSSL: Failed to extract the public key"; + LOG(WARNING) << "OpenSSL: Failed to extract the public key"; X509_free(cert); return false; } @@ -1114,7 +1130,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) EVP_PKEY_free(pubkey); if (!ec_pubkey) { - LOG(INFO) << "OpenSSL: Failed to extract the public key"; + LOG(WARNING) << "OpenSSL: Failed to extract the public key"; X509_free(cert); return false; } @@ -1134,7 +1150,7 @@ bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signa { if (raw_signature.size() % 2 != 0) { - std::cerr << "Invalid raw ECDSA signature size" << std::endl; + LOG(WARNING) << "Invalid raw ECDSA signature size"; return false; } From 1a2cbe45067c0d84db68f9dac3d9118c19f9c2fd Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 20 Jul 2024 21:25:53 +0200 Subject: [PATCH 168/219] Code cleaning --- src/core/libs/osnma_msg_receiver.cc | 272 +++++++++++------- src/core/libs/osnma_msg_receiver.h | 108 ++++--- src/core/system_parameters/osnma_data.h | 2 +- .../osnma/osnma_msg_receiver_test.cc | 4 +- 4 files changed, 227 insertions(+), 159 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 293058b26..e73f74ad4 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -3,14 +3,15 @@ * \brief GNU Radio block that processes Galileo OSNMA data received from * Galileo E1B telemetry blocks. After successful decoding, sends the content to * the PVT block. - * \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es + * \author Carles Fernandez-Prades, 2023-2024. cfernandez(at)cttc.es + * Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de * * ----------------------------------------------------------------------------- * * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -24,12 +25,13 @@ #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "osnma_helper.h" #include // for gr::io_signature::make -#include #include #include -#include +#include // for std::setfill +#include // for std::hex, std::uppercase #include -#include +#include // for std::accumulate +#include // std::stringstream #include // for typeid #include @@ -101,14 +103,14 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) const auto sat = Gnss_Satellite(std::string("Galileo"), nma_msg->PRN); // TODO remove if unneeded std::ostringstream output_message; - output_message << "Galileo OSNMA: complete OSNMA message received starting at " + output_message << "Galileo OSNMA: data received starting at " << "WN=" << nma_msg->WN_sf0 << ", TOW=" << nma_msg->TOW_sf0 << ", from satellite " << sat; - LOG(WARNING) << output_message.str(); + LOG(INFO) << output_message.str(); std::cout << output_message.str() << std::endl; process_osnma_message(nma_msg); @@ -119,33 +121,32 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) const auto inav_data = wht::any_cast>>(pmt::any_ref(msg)); uint32_t PRNa = std::get<0>(*inav_data); std::string nav_data = std::get<1>(*inav_data); - ; uint32_t TOW = std::get<2>(*inav_data); // iono data => 549 bits, utc data, 141 bits. if (nav_data.size() == 549) { -// LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " -// << "TOW_sf=" << TOW; + // LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " + // << "TOW_sf=" << TOW; d_satellite_nav_data[PRNa][TOW].ephemeris_iono_vector_2 = nav_data; } else if (nav_data.size() == 141) { -// LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " -// << "TOW_sf=" << TOW; + // LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " + // << "TOW_sf=" << TOW; d_satellite_nav_data[PRNa][TOW].utc_vector_2 = nav_data; } else - LOG(WARNING) << "osnma_msg_receiver incorrect navData parsing!"; + LOG(WARNING) << "Galileo OSNMA: osnma_msg_receiver incorrect navData parsing!"; } else { - LOG(WARNING) << "osnma_msg_receiver received an unknown object type!"; + LOG(WARNING) << "Galileo OSNMA: osnma_msg_receiver received an unknown object type!"; } } catch (const wht::bad_any_cast& e) { - LOG(WARNING) << "osnma_msg_receiver Bad any_cast: " << e.what(); + LOG(WARNING) << "Galileo OSNMA: osnma_msg_receiver Bad any_cast: " << e.what(); } // Send the resulting decoded NMA data (if available) to PVT @@ -155,7 +156,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); d_new_data = false; // d_osnma_data = OSNMA_data(); - DLOG(INFO) << "NMA info sent to the PVT block through the OSNMA_to_PVT async message port"; + DLOG(INFO) << "Galileo OSNMA: NMA info sent to the PVT block through the OSNMA_to_PVT async message port"; } } @@ -172,7 +173,9 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& 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) - local_time_verification(osnma_msg); + { + local_time_verification(osnma_msg); + } read_and_process_mack_block(osnma_msg); // only process them if at least 3 available. } @@ -203,8 +206,6 @@ void osnma_msg_receiver::read_dsm_header(uint8_t dsm_header) { d_osnma_data.d_dsm_header.dsm_id = d_dsm_reader->get_dsm_id(dsm_header); d_osnma_data.d_dsm_header.dsm_block_id = d_dsm_reader->get_dsm_block_id(dsm_header); // BID -// LOG(INFO) << "OSNMA: DSM_ID=" << static_cast(d_osnma_data.d_dsm_header.dsm_id); -// LOG(INFO) << "OSNMA: DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id); LOG(INFO) << "Galileo OSNMA: Received block DSM_BID=" << static_cast(d_osnma_data.d_dsm_header.dsm_block_id) << " with DSM_ID " << static_cast(d_osnma_data.d_dsm_header.dsm_id); } @@ -246,7 +247,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = number_of_blocks; - LOG(INFO) << "OSNMA: number_of_blocks=" << static_cast(number_of_blocks); + LOG(INFO) << "Galileo OSNMA: number of blocks in this message: " << static_cast(number_of_blocks); if (number_of_blocks == 0) { // Something is wrong, start over @@ -289,8 +290,10 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } available_blocks << "]"; LOG(INFO) << available_blocks.str(); + std::cout << available_blocks.str() << std::endl; } + /** * @brief Function to verify the local time based on GST_SIS and GST_0 * @@ -323,7 +326,7 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; // TODO set flag to false to avoid processing dsm and MACK messages @@ -334,7 +337,7 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; + LOG(WARNING) << "Galileo OSNMA: ( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; } else { @@ -342,7 +345,7 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; + LOG(WARNING) << "Galileo OSNMA: ( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; } } @@ -391,7 +394,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg if (d_osnma_data.d_dsm_header.dsm_id < 12) { // Parse Kroot message - LOG(INFO) << "OSNMA: DSM-KROOT message received."; + LOG(INFO) << "Galileo OSNMA: DSM-KROOT message received."; d_osnma_data.d_dsm_kroot_message.nb_dk = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_kroot_message.pkid = d_dsm_reader->get_pkid(dsm_msg); d_osnma_data.d_dsm_kroot_message.cidkr = d_dsm_reader->get_cidkr(dsm_msg); @@ -483,7 +486,14 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; local_time_verification(osnma_msg); - d_kroot_verified = d_crypto->verify_signature_ecdsa_p256(message, d_osnma_data.d_dsm_kroot_message.ds); + if(l_ds_bits == 512) + { + d_kroot_verified = d_crypto->verify_signature_ecdsa_p256(message, d_osnma_data.d_dsm_kroot_message.ds); + } + else if(l_ds_bits == 1056) + { + d_kroot_verified = d_crypto->verify_signature_ecdsa_p521(message, d_osnma_data.d_dsm_kroot_message.ds); + } if (d_kroot_verified) { std::cout << "Galileo OSNMA: KROOT authentication successful!" << std::endl; @@ -495,6 +505,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg else { LOG(WARNING) << "Galileo OSNMA: KROOT authentication failed."; + std::cerr << "Galileo OSNMA: KROOT authentication failed." << std::endl; } } else @@ -506,7 +517,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) { - LOG(WARNING) << "Galileo OSNMA: DSM-PKR message received."; + LOG(INFO) << "Galileo OSNMA: DSM-PKR message received."; // Save DSM-PKR message d_osnma_data.d_dsm_pkr_message.nb_dp = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_pkr_message.mid = d_dsm_reader->get_mid(dsm_msg); @@ -530,7 +541,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg uint32_t l_dp_bytes = dsm_msg.size(); if (d_osnma_data.d_dsm_pkr_message.npkt == 4) { - LOG(WARNING) << "OSNMA: OAM received"; + LOG(WARNING) << "Galileo OSNMA: OAM received"; l_npk_bytes = l_dp_bytes - 130; // bytes } @@ -576,8 +587,8 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg else { // Reserved message? - LOG(WARNING) << "OSNMA Reserved message received"; - // d_osnma_data = OSNMA_data(); + LOG(WARNING) << "Galileo OSNMA: Reserved message received"; + std::cerr << "Galileo OSNMA: Reserved message received" << std::endl; } d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; } @@ -883,15 +894,16 @@ void osnma_msg_receiver::process_mack_message() { if (d_kroot_verified == false && d_tesla_key_verified == false) { - LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed. " - << ", " - << "No Kroot nor TESLA key available"; + LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed, " + << "no Kroot nor TESLA key available."; if (!d_flag_debug) { return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. } else - LOG(WARNING) << "But it will be processed for debugging purposes."; + { + LOG(WARNING) << "Galileo OSNMA: But it will be processed for debugging purposes."; + } } // verify tesla key and add it to the container of verified keys if successful if (d_tesla_keys.find(d_osnma_data.d_nav_data.TOW_sf0) == d_tesla_keys.end()) // check if already available => no need to verify @@ -933,12 +945,13 @@ void osnma_msg_receiver::process_mack_message() << ", PRNd=" << static_cast(t.PRN_d); } - std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; + LOG(INFO) << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size(); mack = d_macks_awaiting_MACSEQ_verification.erase(mack); } else - { // key not yet available - keep in container until then -- might be deleted if container size exceeds max allowed + { + // key not yet available - keep in container until then -- might be deleted if container size exceeds max allowed ++mack; } } @@ -960,18 +973,24 @@ void osnma_msg_receiver::process_mack_message() if (ret) { it.second.status = Tag::SUCCESS; - LOG(WARNING) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id= " - << it.second.tag_id - << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase - << it.second.received_tag << std::dec - << ", TOW=" - << it.second.TOW - << ", ADKD=" - << static_cast(it.second.ADKD) - << ", PRNa=" - << static_cast(it.second.PRNa) - << ", PRNd=" - << static_cast(it.second.PRN_d); + LOG(INFO) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id=" + << it.second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it.second.received_tag << std::dec + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d); + std::cout << "Galileo OSNMA: Tag verification :: SUCCESS for tag ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d) << std::endl; } /* TODO notify PVT via pmt * have_new_data() true @@ -980,7 +999,7 @@ void osnma_msg_receiver::process_mack_message() else { it.second.status = Tag::FAIL; - LOG(WARNING) << "Galileo OSNMA: Tag verification :: FAILURE for tag Id=" + LOG(WARNING) << "Galileo OSNMA: Tag verification :: FAILURE for tag Id=" << it.second.tag_id << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase << it.second.received_tag << std::dec @@ -992,6 +1011,12 @@ void osnma_msg_receiver::process_mack_message() << static_cast(it.second.PRNa) << ", PRNd=" << static_cast(it.second.PRN_d); + std::cerr << "Galileo OSNMA: Tag verification :: FAILURE for tag ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d) << std::endl; } } else if (it.second.TOW > d_osnma_data.d_nav_data.TOW_sf0) @@ -1031,27 +1056,29 @@ void osnma_msg_receiver::process_mack_message() * \pre DSM_PKR_message correctly filled in especially the 1024 intermediate tree nodes * \returns true if computed merkle root matches received one, false otherwise */ -bool osnma_msg_receiver::verify_dsm_pkr(DSM_PKR_message message) +bool osnma_msg_receiver::verify_dsm_pkr(const DSM_PKR_message& message) const { - std::vector computed_merkle_root; // x_4_0 - std::vector base_leaf = compute_base_leaf(message); // m_i - - LOG(INFO) << "Galileo OSNMA: DSM-PKR :: leaf provided: m_" << static_cast(message.mid); - - computed_merkle_root = compute_merke_root(message, base_leaf); + const auto base_leaf = get_merkle_tree_leaves(message); // m_i + const auto computed_merkle_root = compute_merkle_root(message, base_leaf); // x_4_0 + const auto msg_id = static_cast(message.mid); + LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: leaf provided for Message ID " << msg_id; if (computed_merkle_root == d_crypto->get_merkle_root()) { - LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: SUCCESS!." << std::endl; + LOG(INFO) << "Galileo OSNMA: DSM-PKR verification for Message ID " << msg_id << " :: SUCCESS."; + std::cout << "Galileo OSNMA: DSM-PKR verification for Message ID " << msg_id << " :: SUCCESS." << std::endl; return true; } else { - LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: FAILURE." << std::endl; + LOG(WARNING) << "Galileo OSNMA: DSM-PKR verification for Message ID " << msg_id << " :: FAILURE."; + std::cerr << "Galileo OSNMA: DSM-PKR verification for Message ID " << msg_id << " :: FAILURE." << std::endl; return false; } } -std::vector osnma_msg_receiver::compute_merke_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const + + +std::vector osnma_msg_receiver::compute_merkle_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const { std::vector x_next, x_current = d_crypto->compute_SHA_256(m_i); for (size_t i = 0; i < 4; i++) @@ -1077,12 +1104,16 @@ std::vector osnma_msg_receiver::compute_merke_root(const DSM_PKR_messag } return x_current; } -std::vector osnma_msg_receiver::compute_base_leaf(const DSM_PKR_message& dsm_pkr_message) const -{ // build base leaf m_i + + +std::vector osnma_msg_receiver::get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const +{ + // build base leaf m_i according to OSNMA SIS ICD v1.1, section 6.2 DSM-PKR Verification std::vector m_i; - m_i.reserve(2 + dsm_pkr_message.npk.size()); + const size_t size_npk = dsm_pkr_message.npk.size(); + m_i.reserve(1 + size_npk); m_i.push_back((dsm_pkr_message.npkt << 4) + dsm_pkr_message.npktid); - for (uint8_t i = 0; i < dsm_pkr_message.npk.size(); i++) + for (size_t i = 0; i < size_npk; i++) { m_i.push_back(dsm_pkr_message.npk[i]); } @@ -1090,13 +1121,13 @@ std::vector osnma_msg_receiver::compute_base_leaf(const DSM_PKR_message } -bool osnma_msg_receiver::verify_tag(Tag& tag) +bool osnma_msg_receiver::verify_tag(const Tag& tag) { // Debug -// LOG(INFO) << "Galileo OSNMA: Tag verification :: Start for tag Id= " -// << tag.tag_id -// << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase -// << tag.received_tag << std::dec; + // LOG(INFO) << "Galileo OSNMA: Tag verification :: Start for tag Id= " + // << tag.tag_id + // << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + // << tag.received_tag << std::dec; // build message std::vector m = build_message(tag); @@ -1105,14 +1136,13 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) if (tag.ADKD == 0 || tag.ADKD == 4) { applicable_key = d_tesla_keys[tag.TOW + 30]; -// LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 30); + // LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 30); + } + else // ADKD 12 + { + applicable_key = d_tesla_keys[tag.TOW + 330]; + // LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 330); } - else // ADKD 12 - { - applicable_key = d_tesla_keys[tag.TOW + 330]; -// LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 330); - } - if (d_osnma_data.d_dsm_kroot_message.mf == 0) // C: HMAC-SHA-256 { @@ -1164,7 +1194,7 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) // Compare computed tag with received one truncated if (tag.received_tag == computed_mac) { - std::cout << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id= " + LOG(INFO) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id=" << tag.tag_id << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase << tag.received_tag << std::dec @@ -1175,6 +1205,14 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) << ", PRNa=" << static_cast(tag.PRNa) << ", PRNd=" + << static_cast(tag.PRN_d); + std::cout << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id=" + << tag.tag_id + << ", ADKD=" + << static_cast(tag.ADKD) + << ", PRNa=" + << static_cast(tag.PRNa) + << ", PRNd=" << static_cast(tag.PRN_d) << std::endl; return true; } @@ -1186,7 +1224,9 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) { std::vector m; if (tag.CTR != 1) - m.push_back(static_cast(tag.PRN_d)); + { + m.push_back(static_cast(tag.PRN_d)); + } m.push_back(static_cast(tag.PRNa)); // TODO: maybe here I have to use d_receiver_time instead of d_GST_SIS which is what I am computing uint32_t GST = d_helper->compute_gst(tag.WN, tag.TOW); @@ -1204,15 +1244,17 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) if (tag.ADKD == 0 || tag.ADKD == 12) // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. { applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; -// LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; + // LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else if (tag.ADKD == 4) { applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].utc_vector_2; -// LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; + // LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else - LOG(WARNING) << "Galileo OSNMA :: Tag verification :: unknown ADKD"; + { + LOG(WARNING) << "Galileo OSNMA: Tag verification :: unknown ADKD"; + } // convert std::string to vector applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); @@ -1309,14 +1351,16 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO } if (computed_key == d_validated_key && num_of_hashes_needed > 0) { - LOG(WARNING) << "Galileo OSNMA:: TESLA key verification :: SUCCESS!"; + LOG(INFO) << "Galileo OSNMA: TESLA key verification :: SUCCESS!"; + std::cout << "Galileo OSNMA: TESLA key verification :: SUCCESS!" << std::endl; d_tesla_keys.insert(std::pair>(TOW, key)); d_tesla_key_verified = true; d_last_verified_key_GST = d_receiver_time; } else if (num_of_hashes_needed > 0) { - LOG(WARNING) << "Galileo OSNMA:: TESLA key verification :: FAILED"; + LOG(WARNING) << "Galileo OSNMA: TESLA key verification :: FAILED"; + std::cerr << "Galileo OSNMA: TESLA key verification :: FAILED" << std::endl; if (d_flag_debug) { d_tesla_keys.insert(std::pair>(TOW, key)); @@ -1375,9 +1419,11 @@ void osnma_msg_receiver::remove_verified_tags() it = d_tags_awaiting_verify.erase(it); } else - ++it; + { + ++it; + } } - std::cout << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size() << std::endl; + LOG(INFO) << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size(); } @@ -1394,11 +1440,11 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() while (d_tags_awaiting_verify.size() > 500) { auto it = d_tags_awaiting_verify.begin(); - LOG(WARNING) << "Galileo OSNMA: Tag verification :: DELETED tag due to exceeding buffer size. " - << "Tag Id= " << it->second.tag_id - << ", TOW=" << it->first - << ", ADKD=" << static_cast(it->second.ADKD) - << ", from satellite " << it->second.PRNa; + LOG(INFO) << "Galileo OSNMA: Tag verification :: DELETED tag due to exceeding buffer size. " + << "Tag Id= " << it->second.tag_id + << ", TOW=" << it->first + << ", ADKD=" << static_cast(it->second.ADKD) + << ", from satellite " << it->second.PRNa; d_tags_awaiting_verify.erase(it); } } @@ -1463,7 +1509,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) if (flxTags.empty()) { - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: ADKD matches MAC Look-up table."; + LOG(INFO) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: ADKD matches MAC Look-up table."; return true; } // Fixed as well as FLX Tags share first part - Eq. 22 ICD @@ -1499,7 +1545,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; if (computed_macseq == mack.header.macseq) { - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK"; + LOG(INFO) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK"; return true; } @@ -1511,7 +1557,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) } -bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) +bool osnma_msg_receiver::tag_has_nav_data_available(const Tag& t) { auto prn_it = d_satellite_nav_data.find(t.PRN_d); if (prn_it != d_satellite_nav_data.end()) @@ -1540,7 +1586,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(Tag& t) } -bool osnma_msg_receiver::tag_has_key_available(Tag& t) +bool osnma_msg_receiver::tag_has_key_available(const Tag& t) { // check adkd of tag // if adkd = 0 or 4 => look for d_tesla_keys[t.TOW+30] @@ -1572,7 +1618,6 @@ bool osnma_msg_receiver::tag_has_key_available(Tag& t) std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes) { - auto start = std::chrono::high_resolution_clock::now(); std::vector K_II = key; std::vector K_I; // result of the recursive hash operations std::vector msg; @@ -1624,20 +1669,26 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede // check that the final time matches the Kroot time bool check; if (!d_tesla_key_verified) - check = GST_SFi + 30 == d_GST_0 - 30; + { + check = GST_SFi + 30 == d_GST_0 - 30; + } else - check = GST_SFi + 30 == d_last_verified_key_GST; + { + check = GST_SFi + 30 == d_last_verified_key_GST; + } if (!check) - LOG(WARNING) << "Galileo OSNMA: TESLA verification error. Kroot time mismatch!"; // ICD. Eq. 18 + { + LOG(WARNING) << "Galileo OSNMA: TESLA key chain verification error: KROOT time mismatch!"; // ICD. Eq. 18 + std::cerr << "Galileo OSNMA: TESLA key chain verification error: KROOT time mismatch!" << std::endl; + } else - LOG(INFO) << "Galileo OSNMA: TESLA verification. Kroot time matches!"; // ICD. Eq. 18 - // compare computed current key against received key - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; -// LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) took " << elapsed.count() << " seconds."; + { + LOG(INFO) << "Galileo OSNMA: TESLA key chain verification: KROOT time matches."; // ICD. Eq. 18 + } return K_II; } + /** * @brief Verifies the MAC sequence of a received MACK message. * @@ -1650,7 +1701,7 @@ std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_neede */ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_message& mack) { - std::vector verified_tags {}; + std::vector verified_tags{}; // MACSEQ verification d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. @@ -1692,23 +1743,23 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ else if (mack.tag_and_info[i].tag_info.ADKD == std::stoi(applicable_sequence[i + 1])) { // fill index of tags failed - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: ADKD match 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; + LOG(INFO) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: ADKD match 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; verified_tags.push_back(mack.tag_and_info[i]); } else { // discard tag - 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; + 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; } } if (flxTags.empty() /*TODO add check d_flag_check_mackseq_fixed_tags*/) { - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: No FLX tags to verify."; + LOG(INFO) << "Galileo OSNMA: MACSEQ verification :: No FLX tags to verify."; return verified_tags; } // Fixed as well as FLX Tags share first part - Eq. 22 ICD @@ -1744,7 +1795,7 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ uint16_t computed_macseq = (mac_msb & 0xFFF0) >> 4; if (computed_macseq == mack.header.macseq) { - LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK"; + LOG(INFO) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK"; for (uint8_t i = 0; i < flxTags.size(); i++) { verified_tags.push_back(mack.tag_and_info[flxTags[i]]); @@ -1757,5 +1808,4 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: FLX tags verification failed"; return verified_tags; } - } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index ad397cc2f..148b1266e 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -3,14 +3,15 @@ * \brief GNU Radio block that processes Galileo OSNMA data received from * Galileo E1B telemetry blocks. After successful decoding, sends the content to * the PVT block. - * \author Carles Fernandez-Prades, 2023. cfernandez(at)cttc.es + * \author Carles Fernandez-Prades, 2023-2024. cfernandez(at)cttc.es + * Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de * * ----------------------------------------------------------------------------- * * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -18,20 +19,23 @@ #ifndef GNSS_SDR_OSNMA_MSG_RECEIVER_H #define GNSS_SDR_OSNMA_MSG_RECEIVER_H -#define FRIEND_TEST(test_case_name, test_name)\ -friend class test_case_name##_##test_name##_Test + +#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 -#include -#include // for gr::block -#include // for pmt::pmt_t -#include // for std::array -#include // for std::shared_ptr -#include -#include +#include "osnma_data.h" // for OSNMA_data structures +#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::vector /** \addtogroup Core * \{ */ @@ -73,58 +77,72 @@ private: void read_mack_header(); void read_mack_body(); void process_mack_message(); - void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData &data); + void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data); void remove_verified_tags(); void control_tags_awaiting_verify_size(); - std::vector build_message(const Tag& tag); - std::vector hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes); - std::vector compute_base_leaf(const DSM_PKR_message& dsm_pkr_message) const; - std::vector compute_merke_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const; - std::vector verify_macseq_new(const MACK_message& mack); void display_data(); + bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); bool verify_tesla_key(std::vector& key, uint32_t TOW); - bool verify_tag(Tag& tag); + bool verify_tag(const Tag& tag); bool is_next_subframe(); - bool tag_has_nav_data_available(Tag& t); - bool tag_has_key_available(Tag& t); + bool tag_has_nav_data_available(const Tag& t); + bool tag_has_key_available(const Tag& t); bool verify_macseq(const MACK_message& mack); - bool verify_dsm_pkr(DSM_PKR_message message); + bool verify_dsm_pkr(const DSM_PKR_message& message) const; - enum tags_to_verify{all,utc,slow_eph, eph, none}; - tags_to_verify d_tags_allowed{tags_to_verify::all}; - std::map> d_satellite_nav_data; // map holding NavData sorted by SVID (first key) and TOW (second key). - std::map> d_tesla_keys; // tesla keys over time, sorted by TOW + std::vector get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const; + std::vector compute_merkle_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const; + std::vector build_message(const Tag& tag); + std::vector hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes); + std::vector verify_macseq_new(const MACK_message& mack); + + std::map> d_satellite_nav_data; // map holding NavData sorted by SVID (first key) and TOW (second key). + std::map> d_tesla_keys; // tesla keys over time, sorted by TOW + std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW + + std::vector d_tags_to_verify{0, 4, 12}; + std::vector d_validated_key{}; std::vector d_macks_awaiting_MACSEQ_verification; - std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW - std::unique_ptr d_dsm_reader; // osnma parameters parser - std::unique_ptr d_crypto; // access to cryptographic functions - std::unique_ptr d_helper; - std::array, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself. + std::array, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself. std::array, 16> d_dsm_id_received{}; std::array d_number_of_blocks{}; - std::array d_mack_message{}; // C: 480 b + std::array d_mack_message{}; // C: 480 b + + std::unique_ptr d_dsm_reader; // osnma parameters parser + std::unique_ptr d_crypto; // access to cryptographic functions + std::unique_ptr d_helper; OSNMA_data d_osnma_data{}; + + enum tags_to_verify + { + all, + utc, + slow_eph, + eph, + none + }; + tags_to_verify d_tags_allowed{tags_to_verify::all}; + std::time_t d_receiver_time{0}; + + uint32_t d_GST_Sf{}; // C: used for MACSEQ and Tesla Key verification TODO need really to be global var? + uint32_t d_last_verified_key_GST{0}; + uint32_t d_GST_0{}; + uint32_t d_GST_SIS{}; + + uint8_t d_Lt_min{}; // minimum equivalent tag length + uint8_t d_Lt_verified_eph{0}; // verified tag bits - ephemeris + uint8_t d_Lt_verified_utc{0}; // verified tag bits - timing + uint8_t const d_T_L{30}; // s RG Section 2.1 + uint8_t const d_delta_COP{30}; // s SIS ICD Table 14 + bool d_new_data{false}; bool d_public_key_verified{false}; bool d_kroot_verified{false}; bool d_tesla_key_verified{false}; bool d_flag_debug{false}; - uint32_t d_GST_Sf {}; // C: used for MACSEQ and Tesla Key verification TODO need really to be global var? - uint32_t d_last_verified_key_GST{0}; - uint32_t d_GST_0 {}; - uint32_t d_GST_SIS {}; - std::time_t d_receiver_time {0}; - uint8_t d_Lt_min {}; // minimum equivalent tag length - uint8_t d_Lt_verified_eph {0}; // verified tag bits - ephemeris - uint8_t d_Lt_verified_utc {0}; // verified tag bits - timing - uint8_t const d_T_L{30}; // s RG Section 2.1 - uint8_t const d_delta_COP{30}; // s SIS ICD Table 14 - - std::vector d_tags_to_verify{0,4,12}; - std::vector d_validated_key{}; // Provide access to inner functions to Gtest FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 105c4cbc2..484fa0162 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -82,7 +82,7 @@ class DSM_PKR_message public: DSM_PKR_message() = default; - std::array itn; // bitset<1024> + std::array itn{}; // bitset<1024> std::vector npk; std::vector p_dp; uint8_t nb_dp{}; diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 7daa43fb4..d0df27a3b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -83,7 +83,7 @@ TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot) // Act // ---------- - computed_merkle_root = osnma->compute_merke_root(dsm_pkr_message,base_leaf); + computed_merkle_root = osnma->compute_merkle_root(dsm_pkr_message, base_leaf); // Assert // ---------- @@ -102,7 +102,7 @@ TEST_F(OsnmaMsgReceiverTest, ComputeBaseLeaf) // Act // ---------- - std::vector computed_base_leaf = osnma->compute_base_leaf(dsm_pkr_message); + std::vector computed_base_leaf = osnma->get_merkle_tree_leaves(dsm_pkr_message); // Assert // ---------- From 2378fb4fbc7868b85f5352764b804cf32add83e9 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 20 Jul 2024 21:44:06 +0200 Subject: [PATCH 169/219] Fix for CMake 3.30 --- src/tests/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 80aebc3dc..d7bbab2ee 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1387,7 +1387,8 @@ if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) target_link_libraries(osnma_msg_receiver_test PRIVATE Gflags::gflags Glog::glog) target_compile_definitions(osnma_msg_receiver_test PRIVATE -DUSE_GLOG_AND_GFLAGS=1) else() - target_link_libraries(osnma_msg_receiver_test PRIVATE absl::flags absl::flags_parse absl::log $ absl::log_initialize) + target_link_libraries(osnma_msg_receiver_test PRIVATE absl::flags absl::flags_parse absl::log absl::log_initialize) + target_link_libraries(osnma_msg_receiver_test INTERFACE "$") endif() xcode_remove_warning_duplicates(osnma_msg_receiver_test) # TODO - unsure if needed From c5c58c8d1db9dc753c1449d5c313191aa9adf669 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 22 Jul 2024 08:24:12 +0200 Subject: [PATCH 170/219] Fix defects detected by clang-tidy --- src/core/libs/osnma_msg_receiver.cc | 23 ++++++++++++----------- src/core/libs/osnma_msg_receiver.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e73f74ad4..8a12c6d42 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -137,7 +137,9 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) d_satellite_nav_data[PRNa][TOW].utc_vector_2 = nav_data; } else - LOG(WARNING) << "Galileo OSNMA: osnma_msg_receiver incorrect navData parsing!"; + { + LOG(WARNING) << "Galileo OSNMA: osnma_msg_receiver incorrect navData parsing!"; + } } else { @@ -276,7 +278,7 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ } else { - for (uint8_t k = 0; k < d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]; k++) + for (uint16_t k = 0; k < d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id]; k++) { if (d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id][k] == 0) { @@ -926,10 +928,9 @@ void osnma_msg_receiver::process_mack_message() d_tags_awaiting_verify.insert(std::pair(mack->TOW, tag0)); // bool ret = verify_macseq(*mack); std::vector macseq_verified_tags = verify_macseq_new(*mack); - for (std::size_t i = 0; i < macseq_verified_tags.size(); ++i) + for (auto & tag_and_info : macseq_verified_tags) { // add tags of current mack to the verification queue - auto& tag_and_info = macseq_verified_tags[i]; Tag t(tag_and_info, mack->TOW, mack->WN, mack->PRNa, tag_and_info.counter); d_tags_awaiting_verify.insert(std::pair(mack->TOW, t)); LOG(INFO) << "Galileo OSNMA: Add Tag Id= " @@ -1080,7 +1081,8 @@ bool osnma_msg_receiver::verify_dsm_pkr(const DSM_PKR_message& message) const std::vector osnma_msg_receiver::compute_merkle_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const { - std::vector x_next, x_current = d_crypto->compute_SHA_256(m_i); + std::vector x_next; + std::vector x_current = d_crypto->compute_SHA_256(m_i); for (size_t i = 0; i < 4; i++) { x_next.clear(); @@ -1345,7 +1347,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO // truncate hash std::vector computed_key; computed_key.reserve(key.size()); - for (uint16_t i = 0; i < key.size(); i++) + for (size_t i = 0; i < key.size(); i++) { computed_key.push_back(hash[i]); } @@ -1520,7 +1522,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); m[4] = static_cast(d_GST_Sf & 0x000000FF); // Case tags flexible - Eq. 21 ICD - for (uint8_t i = 0; i < flxTags.size(); i++) + for (size_t i = 0; i < flxTags.size(); i++) { m[2 * i + 5] = mack.tag_and_info[flxTags[i]].tag_info.PRN_d; m[2 * i + 6] = mack.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | @@ -1548,7 +1550,6 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) LOG(INFO) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK"; return true; } - else { LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: FLX tags verification failed"; @@ -1616,7 +1617,7 @@ bool osnma_msg_receiver::tag_has_key_available(const Tag& t) } -std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes) +std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, const std::vector& key, uint32_t GST_SFi, const uint8_t lk_bytes) { std::vector K_II = key; std::vector K_I; // result of the recursive hash operations @@ -1796,9 +1797,9 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ if (computed_macseq == mack.header.macseq) { LOG(INFO) << "Galileo OSNMA: MACSEQ verification :: SUCCESS :: FLX tags verification OK"; - for (uint8_t i = 0; i < flxTags.size(); i++) + for (uint8_t flxTag : flxTags) { - verified_tags.push_back(mack.tag_and_info[flxTags[i]]); + verified_tags.push_back(mack.tag_and_info[flxTag]); } return verified_tags; } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 148b1266e..f5881af07 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -94,7 +94,7 @@ private: std::vector get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const; std::vector compute_merkle_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const; std::vector build_message(const Tag& tag); - std::vector hash_chain(uint32_t num_of_hashes_needed, std::vector key, uint32_t GST_SFi, const uint8_t lk_bytes); + std::vector hash_chain(uint32_t num_of_hashes_needed, const std::vector& key, uint32_t GST_SFi, const uint8_t lk_bytes); std::vector verify_macseq_new(const MACK_message& mack); std::map> d_satellite_nav_data; // map holding NavData sorted by SVID (first key) and TOW (second key). From 8fd6e4dc4015b175e9102abc9ccee64437dbde60 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 22 Jul 2024 09:46:28 +0200 Subject: [PATCH 171/219] Improve const correctness --- src/core/libs/osnma_msg_receiver.cc | 75 +++++++++++++++++++++-------- src/core/libs/osnma_msg_receiver.h | 13 ++--- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 8a12c6d42..0688af6e9 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -1123,7 +1123,7 @@ std::vector osnma_msg_receiver::get_merkle_tree_leaves(const DSM_PKR_me } -bool osnma_msg_receiver::verify_tag(const Tag& tag) +bool osnma_msg_receiver::verify_tag(const Tag& tag) const { // Debug // LOG(INFO) << "Galileo OSNMA: Tag verification :: Start for tag Id= " @@ -1137,12 +1137,28 @@ bool osnma_msg_receiver::verify_tag(const Tag& tag) std::vector applicable_key; if (tag.ADKD == 0 || tag.ADKD == 4) { - applicable_key = d_tesla_keys[tag.TOW + 30]; + const auto it = d_tesla_keys.find(tag.TOW + 30); + if(it != d_tesla_keys.cend()) + { + applicable_key = it->second; + } + else + { + return false; + } // LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 30); } else // ADKD 12 { - applicable_key = d_tesla_keys[tag.TOW + 330]; + const auto it = d_tesla_keys.find(tag.TOW + 330); + if(it != d_tesla_keys.cend()) + { + applicable_key = it->second; + } + else + { + return false; + } // LOG(INFO) << "|---> Galileo OSNMA :: applicable key: 0x" << d_helper->convert_to_hex_string(applicable_key) << "TOW="<(tag.TOW + 330); } @@ -1222,7 +1238,7 @@ bool osnma_msg_receiver::verify_tag(const Tag& tag) } -std::vector osnma_msg_receiver::build_message(const Tag& tag) +std::vector osnma_msg_receiver::build_message(const Tag& tag) const { std::vector m; if (tag.CTR != 1) @@ -1245,12 +1261,28 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) std::vector applicable_nav_data_bytes; if (tag.ADKD == 0 || tag.ADKD == 12) // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. { - applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].ephemeris_iono_vector_2; + const auto it = d_satellite_nav_data.find(tag.PRN_d); + if (it != d_satellite_nav_data.cend()) + { + const auto it2 = it->second.find(tag.TOW - 30); + if (it2 != it->second.cend()) + { + applicable_nav_data = it2->second.ephemeris_iono_vector_2; + } + } // LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else if (tag.ADKD == 4) { - applicable_nav_data = d_satellite_nav_data[tag.PRN_d][tag.TOW - 30].utc_vector_2; + const auto it = d_satellite_nav_data.find(tag.PRN_d); + if (it != d_satellite_nav_data.cend()) + { + const auto it2 = it->second.find(tag.TOW - 30); + if (it2 != it->second.cend()) + { + applicable_nav_data = it2->second.utc_vector_2; + } + } // LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else @@ -1327,10 +1359,10 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO uint32_t GST_SFi = d_receiver_time - 30; // GST of target key is to be used. std::vector hash; const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; - // std::vector validated_key; + std::vector validated_key; if (d_tesla_key_verified) { // have to go up to last verified key - d_validated_key = d_tesla_keys.rbegin()->second; + validated_key = d_tesla_keys.rbegin()->second; num_of_hashes_needed = (d_receiver_time - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key"; @@ -1338,7 +1370,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO } else { // have to go until Kroot - d_validated_key = d_osnma_data.d_dsm_kroot_message.kroot; + validated_key = d_osnma_data.d_dsm_kroot_message.kroot; num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 IC LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to Kroot"; @@ -1351,7 +1383,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO { computed_key.push_back(hash[i]); } - if (computed_key == d_validated_key && num_of_hashes_needed > 0) + if (computed_key == validated_key && num_of_hashes_needed > 0) { LOG(INFO) << "Galileo OSNMA: TESLA key verification :: SUCCESS!"; std::cout << "Galileo OSNMA: TESLA key verification :: SUCCESS!" << std::endl; @@ -1494,7 +1526,7 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) std::vector flxTags{}; std::string tempADKD; // MACLT verification - for (uint8_t i = 0; i < mack.tag_and_info.size(); i++) + for (size_t i = 0; i < mack.tag_and_info.size(); i++) { tempADKD = applicable_sequence[i + 1]; if (tempADKD == "FLX") @@ -1558,14 +1590,14 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) } -bool osnma_msg_receiver::tag_has_nav_data_available(const Tag& t) +bool osnma_msg_receiver::tag_has_nav_data_available(const Tag& t) const { auto prn_it = d_satellite_nav_data.find(t.PRN_d); if (prn_it != d_satellite_nav_data.end()) { // PRN was found, check if TOW exists in inner map //LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; - std::map& tow_map = prn_it->second; + std::map tow_map = prn_it->second; auto tow_it = tow_map.find(t.TOW - 30); if (tow_it != tow_map.end()) { @@ -1587,7 +1619,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(const Tag& t) } -bool osnma_msg_receiver::tag_has_key_available(const Tag& t) +bool osnma_msg_receiver::tag_has_key_available(const Tag& t) const { // check adkd of tag // if adkd = 0 or 4 => look for d_tesla_keys[t.TOW+30] @@ -1617,7 +1649,7 @@ bool osnma_msg_receiver::tag_has_key_available(const Tag& t) } -std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, const std::vector& key, uint32_t GST_SFi, const uint8_t lk_bytes) +std::vector osnma_msg_receiver::hash_chain(uint32_t num_of_hashes_needed, const std::vector& key, uint32_t GST_SFi, const uint8_t lk_bytes) const { std::vector K_II = key; std::vector K_I; // result of the recursive hash operations @@ -1705,8 +1737,13 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ std::vector verified_tags{}; // MACSEQ verification - d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. - std::vector applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe + d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received. + std::vector applicable_key; + const auto key_it = d_tesla_keys.find(mack.TOW + 30); // current tesla key ie transmitted in the next subframe + if (key_it != d_tesla_keys.cend()) + { + applicable_key = key_it->second; + } std::vector sq1{}; std::vector sq2{}; std::vector applicable_sequence; @@ -1734,7 +1771,7 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ std::vector flxTags{}; std::string tempADKD; // MACLT verification - for (uint8_t i = 0; i < mack.tag_and_info.size(); i++) + for (size_t i = 0; i < mack.tag_and_info.size(); i++) { tempADKD = applicable_sequence[i + 1]; if (tempADKD == "FLX") @@ -1771,7 +1808,7 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); m[4] = static_cast(d_GST_Sf & 0x000000FF); // Case tags flexible - Eq. 21 ICD - for (uint8_t i = 0; i < flxTags.size(); i++) + for (size_t i = 0; i < flxTags.size(); i++) { m[2 * i + 5] = mack.tag_and_info[flxTags[i]].tag_info.PRN_d; m[2 * i + 6] = mack.tag_and_info[flxTags[i]].tag_info.ADKD << 4 | diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index f5881af07..7ecbe7428 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -82,19 +82,17 @@ private: void control_tags_awaiting_verify_size(); void display_data(); - bool verify_tag(MACK_tag_and_info tag_and_info, OSNMA_data applicable_OSNMA, uint8_t tag_position, const std::vector& applicable_key, NavData applicable_NavData); bool verify_tesla_key(std::vector& key, uint32_t TOW); - bool verify_tag(const Tag& tag); - bool is_next_subframe(); - bool tag_has_nav_data_available(const Tag& t); - bool tag_has_key_available(const Tag& t); + bool verify_tag(const Tag& tag) const; + bool tag_has_nav_data_available(const Tag& t) const; + bool tag_has_key_available(const Tag& t) const; bool verify_macseq(const MACK_message& mack); bool verify_dsm_pkr(const DSM_PKR_message& message) const; std::vector get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const; std::vector compute_merkle_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const; - std::vector build_message(const Tag& tag); - std::vector hash_chain(uint32_t num_of_hashes_needed, const std::vector& key, uint32_t GST_SFi, const uint8_t lk_bytes); + std::vector build_message(const Tag& tag) const; + std::vector hash_chain(uint32_t num_of_hashes_needed, const std::vector& key, uint32_t GST_SFi, const uint8_t lk_bytes) const; std::vector verify_macseq_new(const MACK_message& mack); std::map> d_satellite_nav_data; // map holding NavData sorted by SVID (first key) and TOW (second key). @@ -102,7 +100,6 @@ private: std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW std::vector d_tags_to_verify{0, 4, 12}; - std::vector d_validated_key{}; std::vector d_macks_awaiting_MACSEQ_verification; std::array, 16> d_dsm_message{}; // structure for recording DSM blocks, when filled it sends them to parse and resets itself. From d0a1825c24b937b99faeb1c99836c1b3c00bfb1a Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 22 Jul 2024 12:52:06 +0200 Subject: [PATCH 172/219] Fix defects detected by clang-tidy --- src/core/system_parameters/gnss_crypto.cc | 4 +- src/core/system_parameters/osnma_helper.cc | 71 ++++++++++++++-------- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 12828cdca..9ff183ed3 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -305,7 +305,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag } else { - unsigned long errCode = ERR_get_error(); + uint64_t errCode = ERR_get_error(); char* err = ERR_error_string(errCode, nullptr); LOG(WARNING) << "OpenSSL: OSNMA message authentication failed: " << err; } @@ -1273,7 +1273,7 @@ bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) // Read the data from the memory buffer char* bio_data; - long data_len = BIO_get_mem_data(mem_bio, &bio_data); + int64_t data_len = BIO_get_mem_data(mem_bio, &bio_data); // Create a new memory buffer and load the data into it BIO* mem_bio2 = BIO_new_mem_buf(bio_data, data_len); diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index 2002c72ca..6a7876f02 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -1,17 +1,17 @@ /*! -* \file osnma_helper.h -* \brief Class for auxiliary osnma functions -* \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es -* -* ----------------------------------------------------------------------------- -* -* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -* This file is part of GNSS-SDR. -* -* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) -* SPDX-License-Identifier: GPL-3.0-or-later -* -* ----------------------------------------------------------------------------- + * \file osnma_helper.h + * \brief Class for auxiliary osnma functions + * \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- */ #include "osnma_helper.h" @@ -26,6 +26,7 @@ uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const return GST; } + std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const { std::vector res; @@ -37,6 +38,7 @@ std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const return res; } + /** * @brief Convert a binary string to a vector of bytes. * @@ -47,7 +49,8 @@ std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const * @param binaryString The binary string to be converted. * @return The vector of bytes converted from the binary string. */ -std::vector Osnma_Helper::bytes(const std::string& binaryString) const { +std::vector Osnma_Helper::bytes(const std::string& binaryString) const +{ std::vector bytes; // Determine the size of the padding needed. @@ -55,12 +58,14 @@ std::vector Osnma_Helper::bytes(const std::string& binaryString) const std::string padded_binary = binaryString; - if (padding_size != 0) { - padding_size = 8 - padding_size; // Compute padding size + if (padding_size != 0) + { + padding_size = 8 - padding_size; // Compute padding size padded_binary.append(padding_size, '0'); // Append zeros to the binary string } - for (size_t i = 0; i < padded_binary.size(); i += 8) { + for (size_t i = 0; i < padded_binary.size(); i += 8) + { uint8_t byte = std::bitset<8>(padded_binary.substr(i, 8)).to_ulong(); bytes.push_back(byte); } @@ -68,37 +73,49 @@ std::vector Osnma_Helper::bytes(const std::string& binaryString) const return bytes; } + std::string Osnma_Helper::verification_status_str(const int& status) const { - switch (status) { - case 0: return "SUCCESS"; - case 1: return "FAIL"; - case 2: return "UNVERIFIED"; - default: return "UNKNOWN"; - } + switch (status) + { + case 0: + return "SUCCESS"; + case 1: + return "FAIL"; + case 2: + return "UNVERIFIED"; + default: + return "UNKNOWN"; + } } + + std::string Osnma_Helper::convert_to_hex_string(const std::vector& vector) const { std::stringstream ss; ss << std::hex << std::setfill('0'); - for (auto byte : vector) { + for (auto byte : vector) + { ss << std::setw(2) << static_cast(byte); } return ss.str(); } + std::vector Osnma_Helper::convert_from_hex_string(const std::string& hex_string) const { std::vector result; std::string adjusted_hex_string = hex_string; - if (hex_string.length() % 2 != 0) { + if (hex_string.length() % 2 != 0) + { adjusted_hex_string = "0" + hex_string; } - for (std::size_t i = 0; i < adjusted_hex_string.length(); i += 2) { + for (std::size_t i = 0; i < adjusted_hex_string.length(); i += 2) + { std::string byte_string = adjusted_hex_string.substr(i, 2); - uint8_t byte = static_cast(std::stoul(byte_string, nullptr, 16)); + auto byte = static_cast(std::stoul(byte_string, nullptr, 16)); result.push_back(byte); } From 6ae7684ba7e60adab9ea79fc8dc6c05630318a8b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 22 Jul 2024 12:59:54 +0200 Subject: [PATCH 173/219] Fix const correctness --- src/core/system_parameters/osnma_helper.cc | 2 +- src/core/system_parameters/osnma_helper.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index 6a7876f02..f8650ed3f 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -74,7 +74,7 @@ std::vector Osnma_Helper::bytes(const std::string& binaryString) const } -std::string Osnma_Helper::verification_status_str(const int& status) const +std::string Osnma_Helper::verification_status_str(int status) const { switch (status) { diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 761306efc..686ef5e99 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -29,7 +29,7 @@ public: uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; std::vector gst_to_uint8(uint32_t GST) const; std::vector bytes(const std::string& binaryString) const; - std::string verification_status_str(const int& status) const; + std::string verification_status_str(int status) const; std::string convert_to_hex_string(const std::vector& vector) const ; std::vector convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto }; From 39f94dcbe69559fb235d161b90467ee292a864e5 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 23 Jul 2024 11:16:45 +0200 Subject: [PATCH 174/219] Code cleaning --- .../galileo_telemetry_decoder_gs.cc | 28 +- .../galileo_telemetry_decoder_gs.h | 3 - src/core/libs/osnma_msg_receiver.cc | 111 +++-- src/core/libs/osnma_msg_receiver.h | 4 +- .../system_parameters/galileo_inav_message.cc | 30 +- .../system_parameters/galileo_inav_message.h | 14 +- src/core/system_parameters/osnma_data.cc | 207 +++------- src/core/system_parameters/osnma_data.h | 62 ++- src/core/system_parameters/osnma_helper.h | 4 +- .../osnma/osnma_msg_receiver_test.cc | 379 +++++++++--------- 10 files changed, 360 insertions(+), 482 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index a84db6946..4fe185501 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -369,6 +369,8 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in // 1. De-interleave std::vector page_part_symbols_soft_value(frame_length); deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS, GALILEO_INAV_INTERLEAVER_COLS, page_part_symbols, page_part_symbols_soft_value.data()); + bool flag_osnma_adkd_4_gst = false; + bool flag_osnma_adkd_4_utc = false; // 2. Viterbi decoder // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) @@ -441,33 +443,31 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in // 4. Push the new navigation data to the queues // extract OSNMA bits, reset container. bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; - if(check_size_is_ok) + if (check_size_is_ok) { - std::cout << "Galileo OSNMA: new ADKD=0/12 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW5() - 25 <>( // < PRNd , navDataBits, TOW_Sosf> + DLOG(INFO) << "Galileo OSNMA: new ADKD=0/12 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW5() - 25; + const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> d_satellite.get_PRN(), d_inav_nav.get_osnma_adkd_0_12_nav_bits(), d_inav_nav.get_TOW5() - 25); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); - LOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d="<< static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW5() - 25) <<")";//: 0b" << d_inav_nav.get_osnma_adkd_0_12_nav_bits(); + DLOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d=" << static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW5() - 25) << ")"; //: 0b" << d_inav_nav.get_osnma_adkd_0_12_nav_bits(); d_inav_nav.reset_osnma_nav_bits_adkd0_12(); } check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; - if(check_size_is_ok) + if (check_size_is_ok) { - std::cout << "Galileo OSNMA: new ADKD=4 navData from " << d_satellite <<" at TOW_sf=" << d_inav_nav.get_TOW6() - 5 <>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe + DLOG(INFO) << "Galileo OSNMA: new ADKD=4 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW6() - 5; + const auto tmp_obj = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe d_satellite.get_PRN(), d_inav_nav.get_osnma_adkd_4_nav_bits(), d_inav_nav.get_TOW6() - 5); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - LOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d="<< static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW6() - 5) <<")";//: 0b" << d_inav_nav.get_osnma_adkd_4_nav_bits(); + DLOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d=" << static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW6() - 5) << ")"; //: 0b" << d_inav_nav.get_osnma_adkd_4_nav_bits(); d_inav_nav.reset_osnma_nav_bits_adkd4(); } - if (d_inav_nav.have_new_ephemeris() == true) // C: tells if W1-->W4 available from same blcok (and W5!) { // get object for this SV (mandatory) @@ -499,8 +499,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); d_first_eph_sent = true; // do not send reduced CED anymore, since we have the full ephemeris set - -// d_flag_osnma_adkd_0_12 = true; // W1-> W5 available } else { @@ -586,7 +584,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_delta_t = tmp_obj->A_0G + tmp_obj->A_1G * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - tmp_obj->t_0G + 604800 * (std::fmod(static_cast(d_inav_nav.get_Galileo_week() - tmp_obj->WN_0G), 64.0))); DLOG(INFO) << "delta_t=" << d_delta_t << "[s]"; - d_flag_osnma_adkd_4_utc = true; + flag_osnma_adkd_4_utc = true; } if (d_inav_nav.have_new_almanac() == true) // flag_almanac_4 tells if W10 available. @@ -621,11 +619,11 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in DLOG(INFO) << "d_TOW_at_current_symbol_ms=" << d_TOW_at_current_symbol_ms; DLOG(INFO) << "d_nav.WN_0=" << d_inav_nav.get_Galileo_week(); - d_flag_osnma_adkd_4_gst = true; + flag_osnma_adkd_4_gst = true; } // get osnma message if the needed nav data is available - bool adkd_4_nav_data_available = d_flag_osnma_adkd_4_utc && d_flag_osnma_adkd_4_gst; // supposition: data did not change bt. flags reset and now. + bool adkd_4_nav_data_available = flag_osnma_adkd_4_utc && flag_osnma_adkd_4_gst; // supposition: data did not change bt. flags reset and now. // bool adkd_4_nav_data_available = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; // newApproach: let decoder decide when block starts and let it fill the data, and just check for length if(adkd_4_nav_data_available /*&& d_inav_nav.is_TOW5_set() not needed cause W6 has TOW also.*/) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h index 4b1725e8a..a6391a2e0 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.h @@ -155,9 +155,6 @@ private: bool d_there_are_e1_channels; bool d_there_are_e6_channels; bool d_use_ced; - bool d_flag_osnma_adkd_0_12; // flag to indicate if the ephemeris is complete for OSNMA processing - bool d_flag_osnma_adkd_4_gst; // flag to indicate if the GST conversion parameters are complete for OSNMA processing - bool d_flag_osnma_adkd_4_utc; // flag to indicate if the iono correction and time is complete for OSNMA processing }; diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 0688af6e9..701f358c9 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -25,13 +25,15 @@ #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "osnma_helper.h" #include // for gr::io_signature::make +#include #include #include #include // for std::setfill #include // for std::hex, std::uppercase #include -#include // for std::accumulate -#include // std::stringstream +#include // for std::accumulate +#include // std::stringstream +#include #include // for typeid #include @@ -104,12 +106,12 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) std::ostringstream output_message; output_message << "Galileo OSNMA: data received starting at " - << "WN=" - << nma_msg->WN_sf0 - << ", TOW=" - << nma_msg->TOW_sf0 - << ", from satellite " - << sat; + << "WN=" + << nma_msg->WN_sf0 + << ", TOW=" + << nma_msg->TOW_sf0 + << ", from satellite " + << sat; LOG(INFO) << output_message.str(); std::cout << output_message.str() << std::endl; @@ -126,15 +128,15 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) // iono data => 549 bits, utc data, 141 bits. if (nav_data.size() == 549) { - // LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " + // LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 OSNMA_NavData, PRN_d (" << PRNa << ") " // << "TOW_sf=" << TOW; - d_satellite_nav_data[PRNa][TOW].ephemeris_iono_vector_2 = nav_data; + d_satellite_nav_data[PRNa][TOW].set_ephemeris_iono_data(nav_data); } else if (nav_data.size() == 141) { - // LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " + // LOG(INFO) << "Galileo OSNMA: received ADKD=4 OSNMA_NavData, PRN_d (" << PRNa << ") " // << "TOW_sf=" << TOW; - d_satellite_nav_data[PRNa][TOW].utc_vector_2 = nav_data; + d_satellite_nav_data[PRNa][TOW].set_utc_data(nav_data); } else { @@ -488,11 +490,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; local_time_verification(osnma_msg); - if(l_ds_bits == 512) + if (l_ds_bits == 512) { d_kroot_verified = d_crypto->verify_signature_ecdsa_p256(message, d_osnma_data.d_dsm_kroot_message.ds); } - else if(l_ds_bits == 1056) + else if (l_ds_bits == 1056) { d_kroot_verified = d_crypto->verify_signature_ecdsa_p521(message, d_osnma_data.d_dsm_kroot_message.ds); } @@ -614,11 +616,11 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrPRN; // FIXME this is ugly. d_osnma_data.d_mack_message.TOW = osnma_msg->TOW_sf0; @@ -626,7 +628,7 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr no need to verify + if (d_tesla_keys.find(d_osnma_data.d_nav_data.get_tow_sf0()) == d_tesla_keys.end()) // check if already available => no need to verify { - bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key, d_osnma_data.d_nav_data.TOW_sf0); + bool retV = verify_tesla_key(d_osnma_data.d_mack_message.key, d_osnma_data.d_nav_data.get_tow_sf0()); if (retV) { - d_tesla_keys.insert(std::pair>(d_osnma_data.d_nav_data.TOW_sf0, d_osnma_data.d_mack_message.key)); + d_tesla_keys.insert(std::pair>(d_osnma_data.d_nav_data.get_tow_sf0(), d_osnma_data.d_mack_message.key)); } } @@ -924,11 +926,11 @@ void osnma_msg_receiver::process_mack_message() if (d_tesla_keys.find(mack->TOW + 30) != d_tesla_keys.end()) { // add tag0 first - Tag tag0 (*mack); + Tag tag0(*mack); d_tags_awaiting_verify.insert(std::pair(mack->TOW, tag0)); -// bool ret = verify_macseq(*mack); + // bool ret = verify_macseq(*mack); std::vector macseq_verified_tags = verify_macseq_new(*mack); - for (auto & tag_and_info : macseq_verified_tags) + for (auto& tag_and_info : macseq_verified_tags) { // add tags of current mack to the verification queue Tag t(tag_and_info, mack->TOW, mack->WN, mack->PRNa, tag_and_info.counter); @@ -948,7 +950,6 @@ void osnma_msg_receiver::process_mack_message() } LOG(INFO) << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size(); mack = d_macks_awaiting_MACSEQ_verification.erase(mack); - } else { @@ -969,7 +970,7 @@ void osnma_msg_receiver::process_mack_message() /* TODO - take into account: * - COP: if * - ADKD type - * - NavData the tag verifies (min. number of bits verified to consider NavData OK) + * - OSNMA_NavData the tag verifies (min. number of bits verified to consider OSNMA_NavData OK) * */ if (ret) { @@ -1020,7 +1021,7 @@ void osnma_msg_receiver::process_mack_message() << static_cast(it.second.PRN_d) << std::endl; } } - else if (it.second.TOW > d_osnma_data.d_nav_data.TOW_sf0) + else if (it.second.TOW > d_osnma_data.d_nav_data.get_tow_sf0()) { // TODO - I dont understand logic. This needs to be reviewed. // case 1: adkd=12 and t.Tow + 300 < current TOW @@ -1059,7 +1060,7 @@ void osnma_msg_receiver::process_mack_message() */ bool osnma_msg_receiver::verify_dsm_pkr(const DSM_PKR_message& message) const { - const auto base_leaf = get_merkle_tree_leaves(message); // m_i + const auto base_leaf = get_merkle_tree_leaves(message); // m_i const auto computed_merkle_root = compute_merkle_root(message, base_leaf); // x_4_0 const auto msg_id = static_cast(message.mid); LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: leaf provided for Message ID " << msg_id; @@ -1110,7 +1111,7 @@ std::vector osnma_msg_receiver::compute_merkle_root(const DSM_PKR_messa std::vector osnma_msg_receiver::get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const { - // build base leaf m_i according to OSNMA SIS ICD v1.1, section 6.2 DSM-PKR Verification + // build base leaf m_i according to OSNMA SIS ICD v1.1, section 6.2 DSM-PKR Verification std::vector m_i; const size_t size_npk = dsm_pkr_message.npk.size(); m_i.reserve(1 + size_npk); @@ -1138,7 +1139,7 @@ bool osnma_msg_receiver::verify_tag(const Tag& tag) const if (tag.ADKD == 0 || tag.ADKD == 4) { const auto it = d_tesla_keys.find(tag.TOW + 30); - if(it != d_tesla_keys.cend()) + if (it != d_tesla_keys.cend()) { applicable_key = it->second; } @@ -1151,7 +1152,7 @@ bool osnma_msg_receiver::verify_tag(const Tag& tag) const else // ADKD 12 { const auto it = d_tesla_keys.find(tag.TOW + 330); - if(it != d_tesla_keys.cend()) + if (it != d_tesla_keys.cend()) { applicable_key = it->second; } @@ -1212,26 +1213,6 @@ bool osnma_msg_receiver::verify_tag(const Tag& tag) const // Compare computed tag with received one truncated if (tag.received_tag == computed_mac) { - LOG(INFO) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id=" - << tag.tag_id - << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase - << tag.received_tag << std::dec - << ", TOW=" - << tag.TOW - << ", ADKD=" - << static_cast(tag.ADKD) - << ", PRNa=" - << static_cast(tag.PRNa) - << ", PRNd=" - << static_cast(tag.PRN_d); - std::cout << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id=" - << tag.tag_id - << ", ADKD=" - << static_cast(tag.ADKD) - << ", PRNa=" - << static_cast(tag.PRNa) - << ", PRNd=" - << static_cast(tag.PRN_d) << std::endl; return true; } return false; @@ -1267,7 +1248,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) const const auto it2 = it->second.find(tag.TOW - 30); if (it2 != it->second.cend()) { - applicable_nav_data = it2->second.ephemeris_iono_vector_2; + applicable_nav_data = it2->second.get_ephemeris_iono_data(); } } // LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; @@ -1280,10 +1261,10 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) const const auto it2 = it->second.find(tag.TOW - 30); if (it2 != it->second.cend()) { - applicable_nav_data = it2->second.utc_vector_2; + applicable_nav_data = it2->second.get_utc_data(); } } - // LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; + // LOG(INFO) << "|---> Galileo OSNMA :: applicable OSNMA_NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; } else { @@ -1292,7 +1273,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) const // convert std::string to vector applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); - // Convert and add NavData bytes into the message, taking care of that NMAS has only 2 bits + // Convert and add OSNMA_NavData bytes into the message, taking care of that NMAS has only 2 bits for (uint8_t byte : applicable_nav_data_bytes) { m.back() |= (byte >> 2); // First take the 6 MSB bits of byte and add to m @@ -1322,7 +1303,7 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) const } -void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) +void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const OSNMA_NavData& data) { // control size of container while (d_satellite_nav_data[SV_ID].size() >= 25) @@ -1596,8 +1577,8 @@ bool osnma_msg_receiver::tag_has_nav_data_available(const Tag& t) const if (prn_it != d_satellite_nav_data.end()) { // PRN was found, check if TOW exists in inner map - //LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; - std::map tow_map = prn_it->second; + // LOG(INFO) << "Galileo OSNMA: hasData = true " << std::endl; + std::map tow_map = prn_it->second; auto tow_it = tow_map.find(t.TOW - 30); if (tow_it != tow_map.end()) { @@ -1612,7 +1593,7 @@ bool osnma_msg_receiver::tag_has_nav_data_available(const Tag& t) const else { // PRN was not found - //LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; + // LOG(INFO) << "Galileo OSNMA: hasData = false " << std::endl; return false; } return false; @@ -1631,7 +1612,7 @@ bool osnma_msg_receiver::tag_has_key_available(const Tag& t) const auto it = d_tesla_keys.find(t.TOW + 30); if (it != d_tesla_keys.end()) { - //LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; + // LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; return true; } } @@ -1640,11 +1621,11 @@ bool osnma_msg_receiver::tag_has_key_available(const Tag& t) const auto it = d_tesla_keys.find(t.TOW + 330); if (it != d_tesla_keys.end()) { - //LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; + // LOG(INFO) << "Galileo OSNMA: hasKey = true " << std::endl; return true; } } - //LOG(INFO) << "Galileo OSNMA: hasKey = false "; + // LOG(INFO) << "Galileo OSNMA: hasKey = false "; return false; } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 7ecbe7428..40ac73e78 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -77,7 +77,7 @@ private: void read_mack_header(); void read_mack_body(); void process_mack_message(); - void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data); + void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const OSNMA_NavData& data); void remove_verified_tags(); void control_tags_awaiting_verify_size(); void display_data(); @@ -95,7 +95,7 @@ private: std::vector hash_chain(uint32_t num_of_hashes_needed, const std::vector& key, uint32_t GST_SFi, const uint8_t lk_bytes) const; std::vector verify_macseq_new(const MACK_message& mack); - std::map> d_satellite_nav_data; // map holding NavData sorted by SVID (first key) and TOW (second key). + std::map> d_satellite_nav_data; // map holding OSNMA_NavData sorted by SVID (first key) and TOW (second key). std::map> d_tesla_keys; // tesla keys over time, sorted by TOW std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index a8509db23..c5ddcbfaa 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -185,7 +185,7 @@ void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even if (page_position_in_inav_subframe != 255) { if (page_position_in_inav_subframe == 0) - { // TODO - is it redundant? receiving Word 2 already resets this + { // TODO - is it redundant? receiving Word 2 already resets this nma_position_filled = std::array{}; nma_msg.mack = std::array{}; nma_msg.hkroot = std::array{}; @@ -215,6 +215,7 @@ void Galileo_Inav_Message::split_page(std::string page_string, int32_t flag_even } } + // C: tells if W1-->W4 available from same blcok bool Galileo_Inav_Message::have_new_ephemeris() // Check if we have a new ephemeris stored in the galileo navigation class { @@ -349,6 +350,7 @@ bool Galileo_Inav_Message::have_new_ephemeris() // Check if we have a new ephem return false; } + // C: tells if W5 is available bool Galileo_Inav_Message::have_new_iono_and_GST() // Check if we have a new iono data set stored in the galileo navigation class { @@ -361,6 +363,7 @@ bool Galileo_Inav_Message::have_new_iono_and_GST() // Check if we have a new io return false; } + // C: tells if W6 is available bool Galileo_Inav_Message::have_new_utc_model() // Check if we have a new utc data set stored in the galileo navigation class { @@ -373,13 +376,14 @@ bool Galileo_Inav_Message::have_new_utc_model() // Check if we have a new utc d return false; } + // flag_almanac_4 tells if W10 available. bool Galileo_Inav_Message::have_new_almanac() // Check if we have a new almanac data set stored in the galileo navigation class { -// if(flag_almanac_4) -// { -// flag_adkd_4_complete = true; -// } + // if(flag_almanac_4) + // { + // flag_adkd_4_complete = true; + // } if ((flag_almanac_1 == true) and (flag_almanac_2 == true) and (flag_almanac_3 == true) and (flag_almanac_4 == true)) { // All Almanac data have been received @@ -618,7 +622,7 @@ void Galileo_Inav_Message::read_page_1(const std::bitset& DLOG(INFO) << "A_1= " << A_1; flag_ephemeris_1 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_1 = data_bits.to_string().substr(6,120); + nav_bits_word_1 = data_bits.to_string().substr(6, 120); } @@ -640,7 +644,7 @@ void Galileo_Inav_Message::read_page_2(const std::bitset& DLOG(INFO) << "iDot_2= " << iDot_2; flag_ephemeris_2 = true; DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_2 = data_bits.to_string().substr(6,120); + nav_bits_word_2 = data_bits.to_string().substr(6, 120); } @@ -1058,7 +1062,7 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) flag_utc_model = true; // set to false externally flag_TOW_set = true; // set to false externally DLOG(INFO) << "flag_tow_set" << flag_TOW_set; - nav_bits_word_6 = data_jk_bits.to_string().substr(6, 99); + nav_bits_word_6 = data_jk_bits.to_string().substr(6, 99); break; case 7: // Word type 7: Almanac for SVID1 (1/2), almanac reference time and almanac reference week number @@ -1417,7 +1421,7 @@ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() nma_position_filled = std::array{}; // Fill TOW and WN nma_msg.WN_sf0 = WN_0; - int32_t TOW_sf0 = TOW_5 - 25;//- 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start TODO review + int32_t TOW_sf0 = TOW_5 - 25; //- 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start TODO review if (TOW_sf0 < 0) { TOW_sf0 += 604800; @@ -1442,17 +1446,23 @@ bool Galileo_Inav_Message::have_new_nma() return false; } } + + std::string Galileo_Inav_Message::get_osnma_adkd_4_nav_bits() { nav_bits_adkd_4 = nav_bits_word_6 + nav_bits_word_10; return nav_bits_adkd_4; } + + std::string Galileo_Inav_Message::get_osnma_adkd_0_12_nav_bits() { nav_bits_adkd_0_12 = nav_bits_word_1 + nav_bits_word_2 + nav_bits_word_3 + nav_bits_word_4 + nav_bits_word_5; return nav_bits_adkd_0_12; } + + void Galileo_Inav_Message::reset_osnma_nav_bits_adkd0_12() { nav_bits_word_1 = ""; @@ -1461,6 +1471,8 @@ void Galileo_Inav_Message::reset_osnma_nav_bits_adkd0_12() nav_bits_word_4 = ""; nav_bits_word_5 = ""; } + + void Galileo_Inav_Message::reset_osnma_nav_bits_adkd4() { nav_bits_word_6 = ""; diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index a4cc6a31a..2ecb8aa53 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -49,17 +49,15 @@ public: std::array mack{}; std::array hkroot{}; uint32_t PRN{}; - uint32_t WN_sf0{}; // TODO - this is present in UtcModelData already + uint32_t WN_sf0{}; // TODO - this is present in UtcModelData already uint32_t TOW_sf0{}; - std::vector EphemerisClockAndStatusData {}; // TODO _2 rename and substitute this + std::vector EphemerisClockAndStatusData{}; // TODO _2 rename and substitute this std::string EphemerisClockAndStatusData_2{}; - std::vector TimingData {}; + std::vector TimingData{}; std::string TimingData_2{}; - Galileo_Ephemeris EphemerisData {}; - Galileo_Iono IonoData {}; - Galileo_Utc_Model UtcModelData {}; - - + Galileo_Ephemeris EphemerisData{}; + Galileo_Iono IonoData{}; + Galileo_Utc_Model UtcModelData{}; }; /*! diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 49051b7be..91a32a1f3 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -1,172 +1,55 @@ /*! -* \file osnma_data.cc -* \brief Class for Galileo OSNMA data storage -* \author Carles Fernandez-Prades, 2020-2023 cfernandez(at)cttc.es -* -* ----------------------------------------------------------------------------- -* -* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -* This file is part of GNSS-SDR. -* -* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) -* SPDX-License-Identifier: GPL-3.0-or-later -* -* ----------------------------------------------------------------------------- -*/ - -#include "osnma_data.h" -#include -#include - -/** - * @brief Constructs a NavData object with the given osnma_msg. - * \details Packs the ephemeris, iono and utc data from the current subframe into the NavData structure. It also gets the PRNa and the GST. - * @param osnma_msg The shared pointer to the OSNMA_msg object. + * \file osnma_data.cc + * \brief Class for Galileo OSNMA data storage + * \author Carles Fernandez-Prades, 2020-2023 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- */ +#include "osnma_data.h" + uint32_t Tag::id_counter = 0; -void NavData::init(const std::shared_ptr &osnma_msg) + + +void OSNMA_NavData::init(const std::shared_ptr& osnma_msg) { - EphemerisData = osnma_msg->EphemerisData; - IonoData = osnma_msg->IonoData; - UtcData = osnma_msg->UtcModelData; - generate_eph_iono_vector(); - generate_utc_vector(); - PRNa = osnma_msg->PRN; - WN_sf0 = osnma_msg->WN_sf0; - TOW_sf0 = osnma_msg->TOW_sf0; - - // new parsing, directly parsing bits -// ephemeris_iono_vector_2 = osnma_msg->EphemerisClockAndStatusData_2; -// utc_vector_2 = osnma_msg->TimingData_2; -}; -void NavData::generate_eph_iono_vector() -{ - ephemeris_iono_vector.clear(); - uint64_t bit_buffer = 0; // variable to store the bits to be extracted, it can contain bits from different variables - int bit_count = 0; // Number of bits in the buffer, i.e. to be extracted - - // create structure to hold the variables to store into the vector along with their bit size - std::vector> variables = { - // data from word type 1 - {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, - {static_cast(&EphemerisData.toe), sizeof(EphemerisData.toe) * 8}, - {static_cast(&EphemerisData.M_0), sizeof(EphemerisData.M_0) * 8}, - {static_cast(&EphemerisData.ecc), sizeof(EphemerisData.ecc) * 8}, - {static_cast(&EphemerisData.sqrtA), sizeof(EphemerisData.sqrtA) * 8}, - // data from word type 2 - {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, - {static_cast(&EphemerisData.OMEGA_0), sizeof(EphemerisData.OMEGA_0) * 8}, - {static_cast(&EphemerisData.i_0), sizeof(EphemerisData.i_0) * 8}, - {static_cast(&EphemerisData.omega), sizeof(EphemerisData.omega) * 8}, - {static_cast(&EphemerisData.idot), sizeof(EphemerisData.idot) * 8}, - {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, - // data from word type 3 - {static_cast(&EphemerisData.OMEGAdot), sizeof(EphemerisData.OMEGAdot) * 8}, - {static_cast(&EphemerisData.delta_n), sizeof(EphemerisData.delta_n) * 8}, - {static_cast(&EphemerisData.Cuc), sizeof(EphemerisData.Cuc) * 8}, - {static_cast(&EphemerisData.Cus), sizeof(EphemerisData.Cus) * 8}, - {static_cast(&EphemerisData.Crc), sizeof(EphemerisData.Crc) * 8}, - {static_cast(&EphemerisData.Crs), sizeof(EphemerisData.Crs) * 8}, - {static_cast(&EphemerisData.SISA), sizeof(EphemerisData.SISA) * 8}, - // data from word type 4 - {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, - {static_cast(&EphemerisData.PRN), sizeof(EphemerisData.PRN) * 8}, - {static_cast(&EphemerisData.Cic), sizeof(EphemerisData.Cic) * 8}, - {static_cast(&EphemerisData.Cis), sizeof(EphemerisData.Cis) * 8}, - {static_cast(&EphemerisData.toe), sizeof(EphemerisData.toe) * 8}, - {static_cast(&EphemerisData.af0), sizeof(EphemerisData.af0) * 8}, - {static_cast(&EphemerisData.af1), sizeof(EphemerisData.af1) * 8}, - {static_cast(&EphemerisData.af2), sizeof(EphemerisData.af2) * 8}, - // data from word type 5 - {static_cast(&IonoData.ai0), sizeof(IonoData.ai0) * 8}, - {static_cast(&IonoData.ai1), sizeof(IonoData.ai1) * 8}, - {static_cast(&IonoData.ai2), sizeof(IonoData.ai2) * 8}, - {static_cast(&IonoData.Region1_flag), sizeof(IonoData.Region1_flag) * 8}, - {static_cast(&IonoData.Region2_flag), sizeof(IonoData.Region2_flag) * 8}, - {static_cast(&IonoData.Region3_flag), sizeof(IonoData.Region3_flag) * 8}, - {static_cast(&IonoData.Region4_flag), sizeof(IonoData.Region4_flag) * 8}, - {static_cast(&IonoData.Region5_flag), sizeof(IonoData.Region5_flag) * 8}, - {static_cast(&EphemerisData.BGD_E1E5a), sizeof(EphemerisData.BGD_E1E5a) * 8}, - {static_cast(&EphemerisData.BGD_E1E5b), sizeof(EphemerisData.BGD_E1E5b) * 8}, - {static_cast(&EphemerisData.E5b_HS), sizeof(EphemerisData.E5b_HS) * 8}, - {static_cast(&EphemerisData.E1B_HS), sizeof(EphemerisData.E1B_HS) * 8}, - {static_cast(&EphemerisData.E5b_DVS), sizeof(EphemerisData.E5b_DVS) * 8}, - {static_cast(&EphemerisData.E1B_DVS), sizeof(EphemerisData.E1B_DVS) * 8}, - }; - - for (auto& var : variables) - { - // extract the bits from the variable - uint64_t binary_representation; - memcpy(&binary_representation, var.first, var.second / 8); - - // Append the bits to the buffer and update the bit count - bit_buffer = (bit_buffer << var.second) | binary_representation; - bit_count += var.second; - // While there are 8 or more bits in the buffer - while (bit_count >= 8) - { - // Extract the 8 bits starting from last bit position and add them to the vector - uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; - ephemeris_iono_vector.push_back(extracted_bits); - - // Remove the extracted bits from the buffer - bit_count -= 8; - bit_buffer = bit_buffer & ~(0xFF << bit_count); - } - - } - - // If there are any bits left in the buffer, add them to the vector - if (bit_count > 0) - { - ephemeris_iono_vector.push_back(static_cast(bit_buffer)); - } + d_TOW_sf0 = osnma_msg->TOW_sf0; } -void NavData::generate_utc_vector() + +std::string OSNMA_NavData::get_ephemeris_iono_data() const { - utc_vector.clear(); - uint64_t bit_buffer = 0; - int bit_count = 0; - - std::vector> variables = { - {static_cast(&UtcData.A0), sizeof(UtcData.A0) * 8}, - {static_cast(&UtcData.A1), sizeof(UtcData.A1) * 8}, - {static_cast(&UtcData.Delta_tLS), sizeof(UtcData.Delta_tLS) * 8}, - {static_cast(&UtcData.tot), sizeof(UtcData.tot) * 8}, - {static_cast(&UtcData.WNot), sizeof(UtcData.WNot) * 8}, - {static_cast(&UtcData.WN_LSF), sizeof(UtcData.WN_LSF) * 8}, - {static_cast(&UtcData.DN), sizeof(UtcData.DN) * 8}, - {static_cast(&UtcData.Delta_tLSF), sizeof(UtcData.Delta_tLSF) * 8}, - {static_cast(&UtcData.A_0G), sizeof(UtcData.A_0G) * 8}, - {static_cast(&UtcData.A_1G), sizeof(UtcData.A_1G) * 8}, - {static_cast(&UtcData.t_0G), sizeof(UtcData.t_0G) * 8}, - {static_cast(&UtcData.WN_0G), sizeof(UtcData.WN_0G) * 8}, - }; - - for (auto& var : variables) - { - uint64_t binary_representation; - memcpy(&binary_representation, var.first, var.second / 8); - - bit_buffer = (bit_buffer << var.second) | binary_representation; - bit_count += var.second; - - while (bit_count >= 8) - { - uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; - utc_vector.push_back(extracted_bits); - - bit_count -= 8; - bit_buffer = bit_buffer & ~(0xFF << bit_count); - } - } - - if (bit_count > 0) - { - utc_vector.push_back(static_cast(bit_buffer)); - } + return d_ephemeris_iono; } + +std::string OSNMA_NavData::get_utc_data() const +{ + return d_utc; +} + + +uint32_t OSNMA_NavData::get_tow_sf0() const +{ + return d_TOW_sf0; +} + + +void OSNMA_NavData::set_ephemeris_iono_data(const std::string& iono_data) +{ + d_ephemeris_iono = iono_data; +} + + +void OSNMA_NavData::set_utc_data(const std::string& utc_data) +{ + d_utc = utc_data; +} diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 484fa0162..910ee3e2d 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -18,12 +18,10 @@ #ifndef GNSS_SDR_OSNMA_DATA_H #define GNSS_SDR_OSNMA_DATA_H -#include "galileo_ephemeris.h" -#include "galileo_inav_message.h" -#include "galileo_iono.h" -#include "galileo_utc_model.h" +#include "galileo_inav_message.h" // for OSNMA_msg #include #include +#include #include #include @@ -72,9 +70,9 @@ class MACK_tag_and_info { public: MACK_tag_and_info() = default; - uint64_t tag; // C: 20-40 bits + uint64_t tag; // C: 20-40 bits MACK_tag_info tag_info; - uint32_t counter; // CTR + uint32_t counter; // CTR }; class DSM_PKR_message @@ -107,7 +105,7 @@ public: uint8_t reserved1{}; uint8_t hf{}; uint8_t mf{}; - uint8_t ks{}; // key size, in bits + uint8_t ks{}; // key size, in bits uint8_t ts{}; uint8_t maclt{}; uint8_t reserved{}; @@ -121,31 +119,26 @@ public: MACK_header header; std::vector tag_and_info; std::vector key; - uint32_t TOW; // TODO duplicated variable, also in NavData + uint32_t TOW; // TODO duplicated variable, also in OSNMA_NavData uint32_t WN; uint32_t PRNa; }; -class NavData +class OSNMA_NavData { public: - NavData()=default; - void init(const std::shared_ptr &osnma_msg); - std::vector ephemeris_iono_vector{}; - std::string ephemeris_iono_vector_2{}; - std::vector utc_vector{}; - std::string utc_vector_2{}; - uint32_t PRNa{}; - uint32_t WN_sf0{}; - uint32_t TOW_sf0{}; + OSNMA_NavData() = default; + void init(const std::shared_ptr& osnma_msg); + std::string get_ephemeris_iono_data() const; + std::string get_utc_data() const; + uint32_t get_tow_sf0() const; + void set_ephemeris_iono_data(const std::string& iono_data); + void set_utc_data(const std::string& utc_data); + private: - Galileo_Ephemeris EphemerisData; - Galileo_Iono IonoData; - Galileo_Utc_Model UtcData; - void generate_eph_iono_vector(); // TODO pass data directly fro Telemetry Decoder (if bits are in the needed order) - void generate_utc_vector(); // TODO - - + std::string d_ephemeris_iono; + std::string d_utc; + uint32_t d_TOW_sf0{}; }; /*! @@ -161,19 +154,22 @@ public: DSM_PKR_message d_dsm_pkr_message; DSM_KROOT_message d_dsm_kroot_message; MACK_message d_mack_message; - NavData d_nav_data; + OSNMA_NavData d_nav_data; }; + class Tag { public: - enum e_verification_status{ + enum e_verification_status + { SUCCESS, FAIL, - UNVERIFIED}; - Tag(const MACK_tag_and_info& MTI, uint32_t TOW,uint32_t WN, uint32_t PRNa,uint8_t CTR) // standard tag constructor, for tags within Tag&Info field + UNVERIFIED + }; + Tag(const MACK_tag_and_info& MTI, uint32_t TOW, uint32_t WN, uint32_t PRNa, uint8_t CTR) // standard tag constructor, for tags within Tag&Info field : tag_id(id_counter++), - TOW(TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, NavData missing + TOW(TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, OSNMA_NavData missing WN(WN), PRNa(PRNa), CTR(CTR), @@ -186,16 +182,16 @@ public: skipped(0) { } - Tag(const MACK_message& mack) // constructor for Tag0 + Tag(const MACK_message& mack) // constructor for Tag0 : tag_id(id_counter++), - TOW(mack.TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, NavData missing + TOW(mack.TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, OSNMA_NavData missing WN(mack.WN), PRNa(mack.PRNa), CTR(1), status(UNVERIFIED), received_tag(mack.header.tag0), computed_tag(0), - PRN_d(mack.PRNa), // Tag0 are self-authenticating + PRN_d(mack.PRNa), // Tag0 are self-authenticating ADKD(0), cop(mack.header.cop), skipped(0) diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 686ef5e99..07a3c457f 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -30,8 +30,8 @@ public: std::vector gst_to_uint8(uint32_t GST) const; std::vector bytes(const std::string& binaryString) const; std::string verification_status_str(int status) const; - std::string convert_to_hex_string(const std::vector& vector) const ; - std::vector convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto + std::string convert_to_hex_string(const std::vector& vector) const; + std::vector convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto }; #endif // GNSS_SDR_OSNMA_HELPER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index d0df27a3b..5f1efcee3 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -1,13 +1,31 @@ +/*! + * \file osmna_msg_receiver_testt.cc + * \brief Tests for the osnma_msg_receiver class. + * \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es + * Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "gnss_crypto.h" +#include "osnma_helper.h" +#include "osnma_msg_receiver.h" #include #include #include #include -#include #include #if USE_GLOG_AND_GFLAGS -#include "osnma_helper.h" -#include "gnss_crypto.h" #include // for LOG #include #else @@ -21,11 +39,18 @@ struct TestVector std::vector navBits; }; + // TODO - parametrize class for different configurations (config_1, config_2, etc.. potentially 5 or 6 more) an make sure wont affect current TEST_F // note: until the test is parametrized for configuration 1 and 2, in order to change between them you have to comment/uncomment the respective calls in this test, identified with comments // conf. 1/2 // log_name, input_time, crtFilePath, merkleFilePath, testVectors class OsnmaMsgReceiverTest : public ::testing::Test { +public: + static std::vector parseNavBits(const std::string& hex); + static std::vector readTestVectorsFromFile(const std::string& filename); + std::string bytes_to_str(const std::vector& bytes); + std::vector extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes); + protected: Osnma_Helper helper; osnma_msg_receiver_sptr osnma; @@ -34,38 +59,31 @@ protected: uint32_t d_GST_SIS{}; uint32_t TOW{}; uint32_t WN{}; - std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm - const uint32_t LEAP_SECONDS = 0; //13 + 5; + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm + const uint32_t LEAP_SECONDS = 0; // 13 + 5; void set_time(std::tm& input); -// std::string log_name {"CONFIG1-2023-08-16-PKID1-OSNMA"}; - std::string log_name {"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; + // std::string log_name {"CONFIG1-2023-08-16-PKID1-OSNMA"}; + std::string log_name{"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; void initializeGoogleLog(); void SetUp() override { initializeGoogleLog(); -// std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 - std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 + // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 set_time(input_time); -// std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.crt"; // conf. 1 -// std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; - std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 + // std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.crt"; // conf. 1 + // std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; + std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); } - -public: - - static std::vector parseNavBits(const std::string& hex); - static std::vector readTestVectorsFromFile(const std::string& filename); - std::string bytes_to_str(const std::vector& bytes); - std::vector extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes); }; + TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot) { // Arrange - // ---------- std::vector computed_merkle_root; std::vector expected_merkle_root = helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D"); DSM_PKR_message dsm_pkr_message; @@ -73,8 +91,8 @@ TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot) dsm_pkr_message.npktid = 0x2; dsm_pkr_message.mid = 0x01; std::vector base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); - - std::vector vec = helper.convert_from_hex_string("7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06" + std::vector vec = helper.convert_from_hex_string( + "7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06" "956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7" "407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1" "24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87"); @@ -82,18 +100,16 @@ TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot) dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); // Act - // ---------- computed_merkle_root = osnma->compute_merkle_root(dsm_pkr_message, base_leaf); // Assert - // ---------- ASSERT_EQ(computed_merkle_root, expected_merkle_root); } + TEST_F(OsnmaMsgReceiverTest, ComputeBaseLeaf) { // Arrange - // ---------- std::vector expected_base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); DSM_PKR_message dsm_pkr_message; dsm_pkr_message.npkt = 0x01; @@ -101,63 +117,68 @@ TEST_F(OsnmaMsgReceiverTest, ComputeBaseLeaf) dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); // Act - // ---------- std::vector computed_base_leaf = osnma->get_merkle_tree_leaves(dsm_pkr_message); // Assert - // ---------- - ASSERT_EQ(computed_base_leaf,expected_base_leaf); + ASSERT_EQ(computed_base_leaf, expected_base_leaf); } -TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey){ // values taken from RG A.7 + +TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey) +{ + // values taken from RG A.7 // Arrange - // ---------- osnma->d_crypto->set_merkle_root(helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D")); DSM_PKR_message dsm_pkr_message; dsm_pkr_message.npkt = 0x01; dsm_pkr_message.npktid = 0x2; dsm_pkr_message.mid = 0x01; - std::vector vec = helper.convert_from_hex_string("7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06" - "956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7" - "407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1" - "24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87"); + std::vector vec = helper.convert_from_hex_string( + "7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06" + "956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7" + "407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1" + "24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87"); std::copy(vec.begin(), vec.end(), dsm_pkr_message.itn.begin()); dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); // Act - // ---------- bool result = osnma->verify_dsm_pkr(dsm_pkr_message); // Assert - // ---------- ASSERT_TRUE(result); - } + TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) { // Arrange - // ---------- - // m0 - std::vector expected_message = { + std::vector expected_message = { 0x02, 0x4E, 0x05, 0x46, 0x3C, 0x01, 0x83, 0xA5, 0x91, 0x05, 0x1D, 0x69, 0x25, 0x80, 0x07, 0x6B, 0x3E, 0xEA, 0x81, 0x41, 0xBF, 0x03, 0xAD, 0xCB, 0x5A, 0xAD, 0xB2, 0x77, 0xAF, 0x6F, 0xCF, 0x21, 0xFB, 0x98, 0xFF, 0x7E, 0x83, 0xAF, 0xFC, 0x37, 0x02, 0x03, 0xB0, 0xD8, 0xE1, 0x0E, 0xB1, 0x4D, 0x11, 0x18, 0xE6, 0xB0, 0xE8, 0x20, 0x01, 0xA0, 0x00, 0xE5, 0x91, 0x00, 0x06, 0xD3, 0x1F, 0x00, - 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00 - }; + 0x02, 0x68, 0x05, 0x4A, 0x02, 0xC2, 0x26, 0x07, 0xF7, 0xFC, 0x00}; uint32_t TOW_Tag0 = 345660; uint32_t TOW_NavData = TOW_Tag0 - 30; - uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; uint32_t WN = 1248; uint32_t PRNa = 2; uint8_t CTR = 1; - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].set_ephemeris_iono_data( + "000011101001011001000100000101000111010110100100100101100000000000" + "011101101011001111101110101010000001010000011011111100000011101011" + "011100101101011010101011011011001001110111101011110110111111001111" + "001000011111101110011000111111110111111010000011101011111111110000" + "110111000000100000001110110000110110001110000100001110101100010100" + "110100010001000110001110011010110000111010000010000000000001101000" + "000000000011100101100100010000000000000110110100110001111100000000" + "000000100110100000000101010010100000001011000010001001100000011111" + "110111111111000000000"); osnma->d_osnma_data.d_nma_header.nmas = 0b10; MACK_tag_and_info MTI; @@ -167,34 +188,39 @@ TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) MTI.tag_info.cop = 0x0F; Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); - - // Act - // ---------- auto computed_message = osnma->build_message(t0); - // Assert - // ---------- ASSERT_TRUE(computed_message == expected_message); - } -TEST_F(OsnmaMsgReceiverTest, TagVerification) { + +TEST_F(OsnmaMsgReceiverTest, TagVerification) +{ // Arrange - // ---------- // Tag0 uint32_t TOW_Tag0 = 345660; uint32_t TOW_NavData = TOW_Tag0 - 30; - uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30 ; + uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; uint32_t WN = 1248; uint32_t PRNa = 2; uint8_t CTR = 1; - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].ephemeris_iono_vector_2 = "000011101001011001000100000101000111010110100100100101100000000000011101101011001111101110101010000001010000011011111100000011101011011100101101011010101011011011001001110111101011110110111111001111001000011111101110011000111111110111111010000011101011111111110000110111000000100000001110110000110110001110000100001110101100010100110100010001000110001110011010110000111010000010000000000001101000000000000011100101100100010000000000000110110100110001111100000000000000100110100000000101010010100000001011000010001001100000011111110111111111000000000"; + osnma->d_satellite_nav_data[PRNa][TOW_NavData].set_ephemeris_iono_data(""); + osnma->d_satellite_nav_data[PRNa][TOW_NavData].set_ephemeris_iono_data( + "000011101001011001000100000101000111010110100100100101100000000000" + "011101101011001111101110101010000001010000011011111100000011101011" + "011100101101011010101011011011001001110111101011110110111111001111" + "001000011111101110011000111111110111111010000011101011111111110000" + "110111000000100000001110110000110110001110000100001110101100010100" + "110100010001000110001110011010110000111010000010000000000001101000" + "000000000011100101100100010000000000000110110100110001111100000000" + "000000100110100000000101010010100000001011000010001001100000011111" + "110111111111000000000"); osnma->d_osnma_data.d_nma_header.nmas = 0b10; MACK_tag_and_info MTI; @@ -204,34 +230,25 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { MTI.tag_info.cop = 0x0F; Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); - - // Act - // ---------- bool result_tag0 = osnma->verify_tag(t0); - - - - // Assert - // ---------- - //ASSERT_TRUE(result_tag0); // Tag3 uint32_t TOW_Tag3 = 345660; uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; - uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30 ; + uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30; WN = 1248; PRNa = 2; CTR = 3; - osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit - osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].utc_vector_2 = + osnma->d_satellite_nav_data[PRNa][TOW_NavData].set_utc_data( "111111111111111111111111111111110000000000000000000000010001001001001000" - "111000001000100111100010010111111111011110111111111001001100000100000000"; + "111000001000100111100010010111111111011110111111111001001100000100000000"); osnma->d_osnma_data.d_nma_header.nmas = 0b10; MTI.tag = static_cast(0x7BB238C883); @@ -243,90 +260,78 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { bool result_tag3 = osnma->verify_tag(t3); ASSERT_TRUE(result_tag0 && result_tag3); - } -TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { + +TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) +{ // Arrange - // ---------- osnma->d_tesla_key_verified = false; - osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 - osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits + osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 + osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; // local_time_verification would do this operation. TODO - eliminate duplication. osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); - osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) - osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; + osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; - osnma->d_tesla_keys.insert((std::pair>(345600,{0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. - std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 + osnma->d_tesla_keys.insert((std::pair>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. + std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 uint32_t TOW = 345630; - - - // Act - // ---------- bool result = osnma->verify_tesla_key(key, TOW); - - - - // Assert - // ---------- ASSERT_TRUE(result); - } + TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) { // Arrange - // ---------- -// std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/16_AUG_2023_GST_05_00_01.csv"); // conf. 1 - std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 - if (testVectors.empty()){ + std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 + if (testVectors.empty()) + { ASSERT_TRUE(false); } bool end_of_hex_stream{false}; int offset_byte{0}; - int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size - const int SIZE_PAGE_BYTES{240/8}; // total bytes of a page - const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe - const int SIZE_SUBFRAME_BYTES{SIZE_PAGE_BYTES*SIZE_SUBFRAME_PAGES}; // total bytes of a subframe - const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds + int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size + const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page + const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe + const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds const int DUMMY_PAGE{63}; bool flag_dummy_page{false}; - std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS - << ", TOW=" << TOW - << ", WN=" << WN << std::endl; - - - - + std::cout << "OsnmaTestVectorsSimulation:" + << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; // Act - // ---------- - // loop over all bytes of data. Note: all TestVectors have same amount of data. - while (end_of_hex_stream == false){ + while (end_of_hex_stream == false) + { // loop over all SVs, extract a subframe - for(const TestVector& tv : testVectors) { // loop over all SVs, extract a subframe - std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) "<< tv.svId << std::endl; + for (const TestVector& tv : testVectors) + { // loop over all SVs, extract a subframe + std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; auto osnmaMsg_sptr = std::make_shared(); std::array hkroot{}; std::array mack{}; - byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) - std::map> words_for_OSNMA; // structure containing and + byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) + std::map> words_for_OSNMA; // structure containing and - for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe + for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe { // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index - std::vector page_bytes = extract_page_bytes(tv,byte_index,SIZE_PAGE_BYTES); - if(page_bytes.empty()){ - std::cout<< "OsnmaTestVectorsSimulation: end of TestVectors \n" << "byte_index="< data_k(even_page.substr(2,112)); - std::bitset<16> data_j(odd_page.substr(2,16)); + std::bitset<112> data_k(even_page.substr(2, 112)); + std::bitset<16> data_j(odd_page.substr(2, 16)); std::bitset<112> shifted_data_k = data_k; - uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word - std::cout<< "OsnmaTestVectorsSimulation: received Word "<< static_cast(word_type) << std::endl; - if( (word_type >= 1 && word_type <=5) || word_type == 6 || word_type == 10) + uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word + std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast(word_type) << std::endl; + if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) { // store raw word std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); words_for_OSNMA[word_type] = data_combined; } - if(word_type == DUMMY_PAGE) + if (word_type == DUMMY_PAGE) flag_dummy_page = true; // place it into osnma object. @@ -370,12 +376,13 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) byte_index += SIZE_PAGE_BYTES; } - std::cout<< "----------" << std::endl; - if(end_of_hex_stream) + std::cout << "----------" << std::endl; + if (end_of_hex_stream) break; - if(flag_dummy_page){ + if (flag_dummy_page) + { flag_dummy_page = false; - continue; // skip this SV + continue; // skip this SV } // Fill osnma object @@ -383,8 +390,8 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) osnmaMsg_sptr->mack = mack; osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; - osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20 ; - osnmaMsg_sptr->PRN = tv.svId; // PRNa + osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20; + osnmaMsg_sptr->PRN = tv.svId; // PRNa // TODO - refactor this logic, currently it is split @@ -395,14 +402,14 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) if (words_for_OSNMA.find(i) == words_for_OSNMA.end()) { ephClockStatusWordsReceived = false; - std::cerr<< "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " - "Word "<< i << " should be received for each subframe but was not." << std::endl; + std::cerr << "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " + "Word " + << i << " should be received for each subframe but was not." << std::endl; } } // extract bits as needed by osnma block - if(ephClockStatusWordsReceived) + if (ephClockStatusWordsReceived) { - // Define the starting position and length of bits to extract for each word std::map> extractionParams = { {1, {6, 120}}, @@ -414,7 +421,8 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) // Fill NavData bits -- Iterate over the extraction parameters std::string nav_data_ADKD_0_12 = ""; - for (const auto& param : extractionParams) { + for (const auto& param : extractionParams) + { uint8_t wordKey = param.first; uint8_t start = param.second.first; uint8_t length = param.second.second; @@ -424,16 +432,16 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) } // send to osnma block bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; - if(check_size_is_ok) + if (check_size_is_ok) { - std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <>( // < PRNd , navDataBits, TOW_Sosf> + std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " + << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; + const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> tv.svId, nav_data_ADKD_0_12, osnmaMsg_sptr->TOW_sf0); - LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) <<"): 0b" << nav_data_ADKD_0_12; + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12; osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); - } } @@ -441,12 +449,12 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() && words_for_OSNMA.find(10) != words_for_OSNMA.end(); // extract bits as needed by osnma block - if(timingWordsReceived){ + if (timingWordsReceived) + { // Define the starting position and length of bits to extract for each word std::map> extractionParams = { {6, {6, 99}}, - {10, {86, 42}} - }; + {10, {86, 42}}}; std::string nav_data_ADKD_4 = ""; // Fill NavData bits -- Iterate over the extraction parameters @@ -461,63 +469,62 @@ TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) } // send to osnma block bool check_size_is_ok = nav_data_ADKD_4.size() == 141; - if(check_size_is_ok) + if (check_size_is_ok) { - std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 <>( // < PRNd , navDataBits, TOW_Sosf> + std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " + << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; + const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> tv.svId, nav_data_ADKD_4, osnmaMsg_sptr->TOW_sf0); - LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d="<< static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) <<"): 0b" << nav_data_ADKD_4; + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4; osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); - } - } // Call the handler, as if it came from telemetry decoder block auto temp_obj = pmt::make_any(osnmaMsg_sptr); - osnma->msg_handler_osnma(temp_obj); // osnma entry point + osnma->msg_handler_osnma(temp_obj); // osnma entry point } - - if(!end_of_hex_stream){ - offset_byte = byte_index; // update offset for the next subframe + if (!end_of_hex_stream) + { + offset_byte = byte_index; // update offset for the next subframe d_GST_SIS += DURATION_SUBFRAME; TOW = d_GST_SIS & 0x000FFFFF; - WN = (d_GST_SIS & 0xFFF00000) >> 20 ; - std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS + WN = (d_GST_SIS & 0xFFF00000) >> 20; + std::cout << "OsnmaTestVectorsSimulation:" + << " d_GST_SIS= " << d_GST_SIS << ", TOW=" << TOW << ", WN=" << WN << std::endl; } - - } - - // Assert - // ---------- // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) } + // Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. // Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std::string& filename) { std::ifstream file(filename); std::vector testVectors; - if (!file.is_open()) { - std::cerr<<"Error reading the file \"" << filename <<"\" \n"; + if (!file.is_open()) + { + std::cerr << "Error reading the file \"" << filename << "\" \n"; return testVectors; } std::string line; std::getline(file, line); - if (line != "SVID,NumNavBits,NavBitsHEX\r" ){ - std::cerr<<"Error parsing first line" <<"\n"; - } + if (line != "SVID,NumNavBits,NavBitsHEX\r") + { + std::cerr << "Error parsing first line" + << "\n"; + } while (std::getline(file, line)) { @@ -540,29 +547,35 @@ std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std: return testVectors; } + + std::vector OsnmaMsgReceiverTest::parseNavBits(const std::string& hex) { std::vector bytes; - for (unsigned int i = 0; i < hex.length()-1; i += 2) + for (unsigned int i = 0; i < hex.length() - 1; i += 2) { std::string byteString = hex.substr(i, 2); - uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16); + uint8_t byte = (uint8_t)strtol(byteString.c_str(), NULL, 16); bytes.push_back(byte); } return bytes; } + + std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector& bytes) { std::string bit_string; bit_string.reserve(bytes.size() * 8); - for(const auto& byte : bytes) + for (const auto& byte : bytes) { std::bitset<8> bits(byte); bit_string += bits.to_string(); } return bit_string; } + + /** * @brief Extracts a range of bytes from a TestVector's navBits vector. * @@ -591,6 +604,8 @@ std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& return extracted_bytes; } + + /** * @brief Sets the time based on the given input. * @@ -614,25 +629,24 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) uint32_t sec_in_week = 7 * 24 * 60 * 60; uint32_t week_number = duration_sec.count() / sec_in_week; uint32_t time_of_week = duration_sec.count() % sec_in_week; - this->WN = week_number; - this->TOW = time_of_week + LEAP_SECONDS; + this->WN = week_number; + this->TOW = time_of_week + LEAP_SECONDS; // Return the week number and time of week as a pair // TODO: d_GST_SIS or d_receiver_time? doubt // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 - this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); - - + this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); } + + void OsnmaMsgReceiverTest::initializeGoogleLog() { - google::InitGoogleLogging(log_name.c_str()); // TODO - running all tests causes conflict due to being called twice - FLAGS_minloglevel = 0; // INFO - FLAGS_logtostderr = 0; // add this line + google::InitGoogleLogging(log_name.c_str()); // TODO - running all tests causes conflict due to being called twice + FLAGS_minloglevel = 0; // INFO + FLAGS_logtostderr = 0; // add this line FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/data/build/src/tests/logs"; if (FLAGS_log_dir.empty()) { - std::cout << "Logging will be written at " << std::filesystem::temp_directory_path() << '\n' @@ -667,4 +681,3 @@ void OsnmaMsgReceiverTest::initializeGoogleLog() } } } - From 49eb854b162f9a3f9406d2ccd32fb0ee2401eac6 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 23 Jul 2024 16:51:59 +0200 Subject: [PATCH 175/219] Fix formatting --- cmake/Modules/GnssSdrCrypto.cmake | 2 +- .../galileo_telemetry_decoder_gs.cc | 17 ++++++----- src/core/libs/osnma_msg_receiver.h | 4 +-- src/core/system_parameters/Galileo_OSNMA.h | 3 +- src/core/system_parameters/osnma_data.cc | 2 +- src/core/system_parameters/osnma_data.h | 2 +- src/core/system_parameters/osnma_helper.h | 28 +++++++++---------- 7 files changed, 28 insertions(+), 30 deletions(-) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index b1edb5982..5286c6d01 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -127,7 +127,7 @@ else() set(GNUTLS_HMAC_INIT_WITH_DIGEST TRUE) endif() if("${gnutls_gnutls_file_contents}" MATCHES "GNUTLS_MAC_AES_CMAC_128") - set(GNUTLS_MAC_AES_CMAC_128 TRUE) + set(GNUTLS_MAC_AES_CMAC_128 TRUE) endif() file(READ "${GNUTLS_INCLUDE_DIR}/gnutls/abstract.h" gnutls_abstract_file_contents) if("${gnutls_abstract_file_contents}" MATCHES "gnutls_pubkey_export2") diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 4fe185501..156194544 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -45,6 +45,7 @@ #include // for std::numeric_limits #include // for std::map #include // for std::out_of_range +#include // for std::tuple #include // for typeid #include // for std::pair @@ -468,7 +469,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_inav_nav.reset_osnma_nav_bits_adkd4(); } - if (d_inav_nav.have_new_ephemeris() == true) // C: tells if W1-->W4 available from same blcok (and W5!) + if (d_inav_nav.have_new_ephemeris() == true) // C: tells if W1-->W4 available from same blcok (and W5!) { // get object for this SV (mandatory) const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_ephemeris()); @@ -503,7 +504,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in else { // If we still do not have ephemeris, check if we have a reduced CED - if ((d_band == '1') && d_use_ced && !d_first_eph_sent && (d_inav_nav.have_new_reduced_ced() == true)) // C: W16 has some Eph. params, uneeded for OSNMa I guess + if ((d_band == '1') && d_use_ced && !d_first_eph_sent && (d_inav_nav.have_new_reduced_ced() == true)) // C: W16 has some Eph. params, uneeded for OSNMa I guess { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_reduced_ced()); this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); @@ -519,7 +520,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } } - if (d_inav_nav.have_new_iono_and_GST() == true) // C: W5 + if (d_inav_nav.have_new_iono_and_GST() == true) // C: W5 { // get object for this SV (mandatory) const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_iono()); @@ -550,7 +551,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } } - if (d_inav_nav.have_new_utc_model() == true) // C: tells if W6 is available + if (d_inav_nav.have_new_utc_model() == true) // C: tells if W6 is available { // get object for this SV (mandatory) const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_utc_model()); @@ -587,7 +588,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in flag_osnma_adkd_4_utc = true; } - if (d_inav_nav.have_new_almanac() == true) // flag_almanac_4 tells if W10 available. + if (d_inav_nav.have_new_almanac() == true) // flag_almanac_4 tells if W10 available. { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_almanac()); this->message_port_pub(pmt::mp("telemetry"), pmt::make_any(tmp_obj)); @@ -623,19 +624,17 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in } // get osnma message if the needed nav data is available - bool adkd_4_nav_data_available = flag_osnma_adkd_4_utc && flag_osnma_adkd_4_gst; // supposition: data did not change bt. flags reset and now. + bool adkd_4_nav_data_available = flag_osnma_adkd_4_utc && flag_osnma_adkd_4_gst; // supposition: data did not change bt. flags reset and now. // bool adkd_4_nav_data_available = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; // newApproach: let decoder decide when block starts and let it fill the data, and just check for length - if(adkd_4_nav_data_available /*&& d_inav_nav.is_TOW5_set() not needed cause W6 has TOW also.*/) + if (adkd_4_nav_data_available /*&& d_inav_nav.is_TOW5_set() not needed cause W6 has TOW also.*/) { } auto newOSNMA = d_inav_nav.have_new_nma(); if (d_band == '1' && newOSNMA) { const std::shared_ptr tmp_obj = std::make_shared(d_inav_nav.get_osnma_msg()); - this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 40ac73e78..c554f861a 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -96,8 +96,8 @@ private: std::vector verify_macseq_new(const MACK_message& mack); std::map> d_satellite_nav_data; // map holding OSNMA_NavData sorted by SVID (first key) and TOW (second key). - std::map> d_tesla_keys; // tesla keys over time, sorted by TOW - std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW + std::map> d_tesla_keys; // tesla keys over time, sorted by TOW + std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW std::vector d_tags_to_verify{0, 4, 12}; std::vector d_macks_awaiting_MACSEQ_verification; diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 6032be061..09f615e08 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -193,8 +193,7 @@ const std::unordered_map OSNMA_TABLE_16 = { {38, {2, 5, {"00S", "FLX", "04S", "FLX", "12S"}, {"00S", "FLX", "FLX", "12S", "FLX"}}}, {39, {2, 4, {"00S", "FLX", "04S", "FLX"}, {"00S", "FLX", "00E", "12S"}}}, {40, {2, 4, {"00S", "00E", "04S", "12S"}, {"00S", "00E", "00E", "12E"}}}, - {41, {2, 4, {"00S", "FLX", "04S", "FLX"}, {"00S", "FLX", "FLX", "12S"}}} -}; + {41, {2, 4, {"00S", "FLX", "04S", "FLX"}, {"00S", "FLX", "FLX", "12S"}}}}; /** \} */ /** \} */ diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 91a32a1f3..1e37ed26f 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -39,7 +39,7 @@ std::string OSNMA_NavData::get_utc_data() const uint32_t OSNMA_NavData::get_tow_sf0() const { - return d_TOW_sf0; + return d_TOW_sf0; } diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 910ee3e2d..cbdaa9c9a 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -182,7 +182,7 @@ public: skipped(0) { } - Tag(const MACK_message& mack) // constructor for Tag0 + explicit Tag(const MACK_message& mack) // constructor for Tag0 : tag_id(id_counter++), TOW(mack.TOW), // TODO missing for build_message WN for GST computation, CTR, NMAS, OSNMA_NavData missing WN(mack.WN), diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 07a3c457f..1e0eae235 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -1,18 +1,18 @@ /*! -* \file osnma_helper.h -* \brief Class for auxiliary osnma functions -* \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es -* -* ----------------------------------------------------------------------------- -* -* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -* This file is part of GNSS-SDR. -* -* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) -* SPDX-License-Identifier: GPL-3.0-or-later -* -* ----------------------------------------------------------------------------- -*/ + * \file osnma_helper.h + * \brief Class for auxiliary osnma functions + * \author Carles Fernandez-Prades, 2024 cfernandez(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ #ifndef GNSS_SDR_OSNMA_HELPER_H #define GNSS_SDR_OSNMA_HELPER_H From 70315ecfae59373402d997aefb40ae8d0014427b Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 23 Jul 2024 17:32:47 +0200 Subject: [PATCH 176/219] Fix formatting --- src/tests/single_test_main.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/single_test_main.cc b/src/tests/single_test_main.cc index c0a6e1dee..27dc60c17 100644 --- a/src/tests/single_test_main.cc +++ b/src/tests/single_test_main.cc @@ -18,8 +18,8 @@ #include "concurrent_map.h" #include "concurrent_queue.h" -#include "gps_acq_assist.h" #include "gnss_sdr_flags.h" +#include "gps_acq_assist.h" #include #include #include From 8ff339671b26e00df1b7304a24b1a5e8d5b44c17 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 24 Jul 2024 20:39:40 +0200 Subject: [PATCH 177/219] Code cleaning --- .../galileo_telemetry_decoder_gs.cc | 8 ++++++-- src/core/system_parameters/galileo_inav_message.cc | 5 ----- src/core/system_parameters/galileo_inav_message.h | 10 ++++++++-- src/core/system_parameters/gnss_crypto.cc | 14 +++++++------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index 156194544..e83bfb05c 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -452,7 +452,9 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_inav_nav.get_osnma_adkd_0_12_nav_bits(), d_inav_nav.get_TOW5() - 25); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); - DLOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d=" << static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW5() - 25) << ")"; //: 0b" << d_inav_nav.get_osnma_adkd_0_12_nav_bits(); + DLOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d=" + << static_cast(d_satellite.get_PRN()) + << ", TOW=" << static_cast(d_inav_nav.get_TOW5() - 25) << ")"; //: 0b" << d_inav_nav.get_osnma_adkd_0_12_nav_bits(); d_inav_nav.reset_osnma_nav_bits_adkd0_12(); } @@ -465,7 +467,9 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_inav_nav.get_osnma_adkd_4_nav_bits(), d_inav_nav.get_TOW6() - 5); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - DLOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d=" << static_cast(d_satellite.get_PRN()) << ", TOW=" << static_cast(d_inav_nav.get_TOW6() - 5) << ")"; //: 0b" << d_inav_nav.get_osnma_adkd_4_nav_bits(); + DLOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d=" + << static_cast(d_satellite.get_PRN()) + << ", TOW=" << static_cast(d_inav_nav.get_TOW6() - 5) << ")"; //: 0b" << d_inav_nav.get_osnma_adkd_4_nav_bits(); d_inav_nav.reset_osnma_nav_bits_adkd4(); } diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index c5ddcbfaa..ab62b684c 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -380,10 +380,6 @@ bool Galileo_Inav_Message::have_new_utc_model() // Check if we have a new utc d // flag_almanac_4 tells if W10 available. bool Galileo_Inav_Message::have_new_almanac() // Check if we have a new almanac data set stored in the galileo navigation class { - // if(flag_almanac_4) - // { - // flag_adkd_4_complete = true; - // } if ((flag_almanac_1 == true) and (flag_almanac_2 == true) and (flag_almanac_3 == true) and (flag_almanac_4 == true)) { // All Almanac data have been received @@ -1451,7 +1447,6 @@ bool Galileo_Inav_Message::have_new_nma() std::string Galileo_Inav_Message::get_osnma_adkd_4_nav_bits() { nav_bits_adkd_4 = nav_bits_word_6 + nav_bits_word_10; - return nav_bits_adkd_4; } diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 2ecb8aa53..820478c77 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -141,15 +141,21 @@ public: * @brief Retrieves the OSNMA ADKD 4 NAV bits. Resets the string. */ std::string get_osnma_adkd_4_nav_bits(); + + /* + * @brief Resets the OSNMA ADKD 4 NAV bits. + */ void reset_osnma_nav_bits_adkd4(); - bool flag_adkd_4_complete{false}; /* * @brief Retrieves the OSNMA ADKD 0/12 NAV bits. Resets the string. */ std::string get_osnma_adkd_0_12_nav_bits(); + + /* + * @brief Resets the OSNMA ADKD 0/12 NAV bits. + */ void reset_osnma_nav_bits_adkd0_12(); - bool flag_adkd_0_12_complete{false}; inline bool get_flag_CRC_test() const { diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 9ff183ed3..fa47720b1 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -225,7 +225,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag success = (ret >= 0); if (success) { - LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; + DLOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; } else { @@ -301,7 +301,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag if (verification == 1) { success = true; - LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + DLOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; } else { @@ -320,7 +320,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag if (verification == 1) { success = true; - LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + DLOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; } else if (verification == 0) { @@ -379,7 +379,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag if (ret >= 0) { - LOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; + DLOG(INFO) << "GnuTLS: OSNMA signature authenticated successfully"; success = true; } else @@ -428,7 +428,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag if (verification == 1) { - LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + DLOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; success = true; } else if (verification == 0) @@ -451,7 +451,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag ECDSA_SIG_free(ecdsa_sig); if (verification == 1) { - LOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; + DLOG(INFO) << "OpenSSL: OSNMA signature authenticated successfully"; success = true; } else if (verification == 0) @@ -896,7 +896,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) #endif // OpenSSL 1.x EVP_PKEY_free(pkey); #endif - LOG(INFO) << "OSNMA Public Key successfully set up."; + DLOG(INFO) << "OSNMA Public Key successfully set up."; } From 8a208d57d8132a93e4e7d08a5d02645fb6ad1f4d Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 24 Jul 2024 21:02:39 +0200 Subject: [PATCH 178/219] Add benchmarks for cryptographic functions --- src/tests/benchmarks/CMakeLists.txt | 9 +- src/tests/benchmarks/benchmark_crypto.cc | 213 +++++++++++++++++++++++ 2 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 src/tests/benchmarks/benchmark_crypto.cc diff --git a/src/tests/benchmarks/CMakeLists.txt b/src/tests/benchmarks/CMakeLists.txt index 28bddd050..74607d1a1 100644 --- a/src/tests/benchmarks/CMakeLists.txt +++ b/src/tests/benchmarks/CMakeLists.txt @@ -109,11 +109,12 @@ if(ENABLE_GLOG_AND_GFLAGS) set(EXTRA_BENCHMARK_DEPENDENCIES "Gflags::gflags;Glog::glog") endif() -add_benchmark(benchmark_copy) -add_benchmark(benchmark_preamble core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) -add_benchmark(benchmark_detector core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) -add_benchmark(benchmark_reed_solomon core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) add_benchmark(benchmark_atan2 Gnuradio::runtime) +add_benchmark(benchmark_copy) +add_benchmark(benchmark_crypto core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) +add_benchmark(benchmark_detector core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) +add_benchmark(benchmark_preamble core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) +add_benchmark(benchmark_reed_solomon core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) if(has_std_plus_void) target_compile_definitions(benchmark_detector PRIVATE -DCOMPILER_HAS_STD_PLUS_VOID=1) diff --git a/src/tests/benchmarks/benchmark_crypto.cc b/src/tests/benchmarks/benchmark_crypto.cc new file mode 100644 index 000000000..43d5f1035 --- /dev/null +++ b/src/tests/benchmarks/benchmark_crypto.cc @@ -0,0 +1,213 @@ +/*! + * \file benchmark_crypto.cc + * \brief Benchmarks for cryptographic functions + * \author Carles Fernandez-Prades, 2024. cfernandez(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "gnss_crypto.h" +#include + +void bm_SHA_256(benchmark::State& state) +{ + auto d_crypto = std::make_unique(); + + std::vector message{ + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; + + while (state.KeepRunning()) + { + std::vector output = d_crypto->compute_SHA_256(message); + } +} + + +void bm_SHA3_256(benchmark::State& state) +{ + auto d_crypto = std::make_unique(); + + std::vector message{ + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; + + while (state.KeepRunning()) + { + std::vector output = d_crypto->compute_SHA3_256(message); + } +} + + +void bm_HMAC_SHA_256(benchmark::State& state) +{ + auto d_crypto = std::make_unique(); + + std::vector key = { + 0x24, 0x24, 0x3B, 0x76, 0xF9, 0x14, 0xB1, 0xA7, + 0x7D, 0x48, 0xE7, 0xF1, 0x48, 0x0C, 0xC2, 0x98, + 0xEB, 0x62, 0x3E, 0x95, 0x6B, 0x2B, 0xCE, 0xA3, + 0xB4, 0xD4, 0xDB, 0x31, 0xEE, 0x96, 0xAB, 0xFA}; + + std::vector message{ + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; + + while (state.KeepRunning()) + { + std::vector output = d_crypto->compute_HMAC_SHA_256(key, message); + } +} + + +void bm_CMAC_AES(benchmark::State& state) +{ + auto d_crypto = std::make_unique(); + + std::vector key = { + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; + + std::vector message{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A}; + + while (state.KeepRunning()) + { + std::vector output = d_crypto->compute_CMAC_AES(key, message); + } +} + + +void bm_verify_ecdsa_p256(benchmark::State& state) +{ + auto d_crypto = std::make_unique(); + + // RG example - import crt certificate + std::vector 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}; + + // ECDSA P-256 signature, raw format + std::vector signature = { + 0xF8, 0xCD, 0x88, 0x29, 0x9F, 0xA4, 0x60, 0x58, 0x00, 0x20, + 0x7B, 0xFE, 0xBE, 0xAC, 0x55, 0x02, 0x40, 0x53, 0xF3, 0x0F, + 0x7C, 0x69, 0xB3, 0x5C, 0x15, 0xE6, 0x08, 0x00, 0xAC, 0x3B, + 0x6F, 0xE3, 0xED, 0x06, 0x39, 0x95, 0x2F, 0x7B, 0x02, 0x8D, + 0x86, 0x86, 0x74, 0x45, 0x96, 0x1F, 0xFE, 0x94, 0xFB, 0x22, + 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, + 0x28, 0xC1, 0x77, 0xFB}; + + // PEM format + std::vector 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); + + while (state.KeepRunning()) + { + bool output = d_crypto->verify_signature_ecdsa_p256(message, signature); + if (output) + { + // Avoid unused-but-set-variable warning + } + } +} + + +void bm_verify_ecdsa_p521(benchmark::State& state) +{ + std::unique_ptr d_crypto = std::make_unique(); + + // Message to be verified + std::vector message = { + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64}; + + // Public key in PEM format + std::vector 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, 0x49, 0x47, 0x62, 0x4D, 0x42, 0x41, 0x47, 0x42, + 0x79, 0x71, 0x47, 0x53, 0x4D, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, + 0x53, 0x75, 0x42, 0x42, 0x41, 0x41, 0x6A, 0x41, 0x34, 0x47, 0x47, 0x41, + 0x41, 0x51, 0x41, 0x6F, 0x35, 0x76, 0x77, 0x66, 0x6E, 0x47, 0x57, 0x47, + 0x33, 0x44, 0x63, 0x59, 0x75, 0x2B, 0x2F, 0x61, 0x58, 0x47, 0x32, 0x7A, + 0x74, 0x65, 0x41, 0x46, 0x50, 0x54, 0x33, 0x0A, 0x48, 0x36, 0x4C, 0x76, + 0x4F, 0x4C, 0x76, 0x49, 0x51, 0x6A, 0x61, 0x2B, 0x6A, 0x74, 0x57, 0x73, + 0x70, 0x4F, 0x38, 0x37, 0x6F, 0x50, 0x32, 0x4E, 0x6D, 0x72, 0x34, 0x6E, + 0x50, 0x68, 0x76, 0x62, 0x53, 0x58, 0x52, 0x4D, 0x37, 0x6A, 0x49, 0x69, + 0x46, 0x38, 0x47, 0x70, 0x6B, 0x75, 0x58, 0x6A, 0x75, 0x4E, 0x7A, 0x34, + 0x72, 0x61, 0x56, 0x4F, 0x65, 0x49, 0x4D, 0x42, 0x77, 0x45, 0x2B, 0x61, + 0x0A, 0x30, 0x4C, 0x76, 0x7A, 0x37, 0x69, 0x54, 0x4D, 0x5A, 0x46, 0x41, + 0x41, 0x51, 0x64, 0x2B, 0x70, 0x47, 0x72, 0x56, 0x54, 0x47, 0x77, 0x66, + 0x53, 0x48, 0x49, 0x72, 0x49, 0x49, 0x45, 0x78, 0x74, 0x5A, 0x35, 0x77, + 0x30, 0x38, 0x51, 0x4F, 0x43, 0x58, 0x2F, 0x75, 0x46, 0x65, 0x2B, 0x30, + 0x78, 0x52, 0x78, 0x4C, 0x64, 0x2F, 0x33, 0x36, 0x42, 0x4E, 0x74, 0x63, + 0x74, 0x69, 0x2F, 0x45, 0x4C, 0x0A, 0x4B, 0x31, 0x35, 0x67, 0x2B, 0x4B, + 0x32, 0x71, 0x67, 0x2F, 0x6C, 0x39, 0x46, 0x42, 0x47, 0x67, 0x4D, 0x2B, + 0x51, 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}; + + // ECDSA P-521 signature, raw format + std::vector signature = { + 0x01, 0x7B, 0x59, 0xAC, 0x3A, 0x03, 0x5C, 0xB4, 0x07, 0xCD, + 0xC1, 0xEB, 0xBE, 0xE5, 0xA6, 0xCB, 0xDA, 0x0A, 0xFF, 0x4D, + 0x38, 0x61, 0x16, 0x0F, 0xB3, 0x77, 0xE5, 0x8A, 0xDC, 0xF3, + 0xFD, 0x79, 0x38, 0x1E, 0xE8, 0x08, 0x3D, 0x5D, 0xBC, 0xC2, + 0x80, 0x6E, 0xE9, 0x2B, 0xC3, 0xEF, 0x07, 0x3D, 0x0C, 0x82, + 0x4C, 0x9B, 0x7A, 0x5C, 0x2E, 0xD5, 0x46, 0xBD, 0x22, 0x21, + 0x13, 0x8A, 0xB2, 0xCA, 0x96, 0x3D, 0x01, 0xBA, 0x2A, 0xC4, + 0x3F, 0xDB, 0x66, 0x3C, 0x40, 0x26, 0xD9, 0xBC, 0x26, 0xD5, + 0x57, 0xD4, 0xBD, 0x15, 0x16, 0x88, 0x21, 0x3B, 0xAA, 0x07, + 0x89, 0xEF, 0x29, 0x8F, 0x2F, 0x85, 0x76, 0x58, 0x9D, 0xCA, + 0x00, 0xCC, 0xC8, 0x30, 0x88, 0x31, 0x99, 0xC1, 0x94, 0xB9, + 0xAF, 0x91, 0xDC, 0xC4, 0x6F, 0x19, 0x2B, 0x12, 0xA2, 0x82, + 0xA5, 0x66, 0x5E, 0x4B, 0xBB, 0xDF, 0x65, 0x81, 0x52, 0x14, + 0x01, 0xD7}; + + d_crypto->set_public_key(publicKey); + + while (state.KeepRunning()) + { + bool output = d_crypto->verify_signature_ecdsa_p521(message, signature); + if (output) + { + // Avoid unused-but-set-variable warning + } + } +} + + +BENCHMARK(bm_SHA_256); +BENCHMARK(bm_SHA3_256); +BENCHMARK(bm_HMAC_SHA_256); +BENCHMARK(bm_CMAC_AES); +BENCHMARK(bm_verify_ecdsa_p256); +BENCHMARK(bm_verify_ecdsa_p521); + +BENCHMARK_MAIN(); From 8566eca92fecb9208cb681caaf79a75a7ec5f004 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 23 Jul 2024 20:53:05 +0200 Subject: [PATCH 179/219] [TAS-238][FEAT] Implement Tag accumulation * New class: osnma_nav_data_manager => manages navigation data coming to osnma * navigation data is grouped now avoiding duplication => a NavData entry has now TOW_start and TOW_end * tag accumulation: now, navigation data has verified_bits field, which shows how many tags have verified that data. unless L_T_min achieved, validation is not considered successful --- src/core/libs/osnma_msg_receiver.cc | 164 ++++++------- src/core/libs/osnma_msg_receiver.h | 9 +- src/core/system_parameters/CMakeLists.txt | 2 + src/core/system_parameters/osnma_data.cc | 167 +++---------- src/core/system_parameters/osnma_data.h | 38 +-- .../osnma_nav_data_manager.cc | 226 ++++++++++++++++++ .../osnma_nav_data_manager.h | 41 ++++ .../osnma/osnma_msg_receiver_test.cc | 31 +-- 8 files changed, 409 insertions(+), 269 deletions(-) create mode 100644 src/core/system_parameters/osnma_nav_data_manager.cc create mode 100644 src/core/system_parameters/osnma_nav_data_manager.h diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 0688af6e9..b1d83b3d9 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -24,6 +24,7 @@ #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "osnma_helper.h" +#include "osnma_nav_data_manager.h" // TODO - all these repeated includes, is it good practice to include them in the source file? #include // for gr::io_signature::make #include #include @@ -72,6 +73,7 @@ osnma_msg_receiver::osnma_msg_receiver( d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(crtFilePath, merkleFilePath); d_helper = std::make_unique(); + d_nav_data_manager = std::make_unique(); // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -114,8 +116,8 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) std::cout << output_message.str() << std::endl; process_osnma_message(nma_msg); - } - else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) + } // OSNMA frame received + else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) // Navigation data bits for OSNMA received { // TODO - PRNa is a typo here, I think for d_satellite_nav_data, is PRN_d the name to use const auto inav_data = wht::any_cast>>(pmt::any_ref(msg)); @@ -123,23 +125,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) std::string nav_data = std::get<1>(*inav_data); uint32_t TOW = std::get<2>(*inav_data); - // iono data => 549 bits, utc data, 141 bits. - if (nav_data.size() == 549) - { - // LOG(INFO) << "Galileo OSNMA: received ADKD=0/12 navData, PRN_d (" << PRNa << ") " - // << "TOW_sf=" << TOW; - d_satellite_nav_data[PRNa][TOW].ephemeris_iono_vector_2 = nav_data; - } - else if (nav_data.size() == 141) - { - // LOG(INFO) << "Galileo OSNMA: received ADKD=4 navData, PRN_d (" << PRNa << ") " - // << "TOW_sf=" << TOW; - d_satellite_nav_data[PRNa][TOW].utc_vector_2 = nav_data; - } - else - { - LOG(WARNING) << "Galileo OSNMA: osnma_msg_receiver incorrect navData parsing!"; - } + d_nav_data_manager->add_navigation_data(nav_data,PRNa,TOW); } else { @@ -614,8 +600,7 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrTOW_sf0; if (d_kroot_verified || d_tesla_key_verified || d_osnma_data.d_dsm_kroot_message.ts != 0 /*mack parser needs to know the tag size, otherwise cannot parse mack messages*/) // C: 4 ts < ts < 10 {// TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future @@ -963,7 +948,7 @@ void osnma_msg_receiver::process_mack_message() for (auto& it : d_tags_awaiting_verify) { bool ret; - if (tag_has_key_available(it.second) && tag_has_nav_data_available(it.second)) + if (tag_has_key_available(it.second) && d_nav_data_manager->have_nav_data(it.second))//tag_has_nav_data_available(it.second)) { ret = verify_tag(it.second); /* TODO - take into account: @@ -1043,6 +1028,17 @@ void osnma_msg_receiver::process_mack_message() } } + uint8_t tag_size = 0; + const auto it = OSNMA_TABLE_11.find(d_osnma_data.d_dsm_kroot_message.ts); + if (it != OSNMA_TABLE_11.cend()) + { + tag_size = it->second; + } + d_nav_data_manager->update_nav_data(d_tags_awaiting_verify, tag_size); + auto data_to_send = d_nav_data_manager->get_verified_data(); + d_nav_data_manager->print_status(); + send_data_to_pvt(data_to_send); + remove_verified_tags(); control_tags_awaiting_verify_size(); // remove the oldest tags if size is too big. @@ -1123,7 +1119,7 @@ std::vector osnma_msg_receiver::get_merkle_tree_leaves(const DSM_PKR_me } -bool osnma_msg_receiver::verify_tag(const Tag& tag) const +bool osnma_msg_receiver::verify_tag(Tag& tag) const { // Debug // LOG(INFO) << "Galileo OSNMA: Tag verification :: Start for tag Id= " @@ -1209,36 +1205,25 @@ bool osnma_msg_receiver::verify_tag(const Tag& tag) const computed_mac += static_cast(mac[4]); } + tag.computed_tag = computed_mac; // update with computed value // Compare computed tag with received one truncated if (tag.received_tag == computed_mac) { - LOG(INFO) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id=" - << tag.tag_id - << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase - << tag.received_tag << std::dec - << ", TOW=" - << tag.TOW - << ", ADKD=" - << static_cast(tag.ADKD) - << ", PRNa=" - << static_cast(tag.PRNa) - << ", PRNd=" - << static_cast(tag.PRN_d); - std::cout << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id=" - << tag.tag_id - << ", ADKD=" - << static_cast(tag.ADKD) - << ", PRNa=" - << static_cast(tag.PRNa) - << ", PRNd=" - << static_cast(tag.PRN_d) << std::endl; return true; } return false; } -std::vector osnma_msg_receiver::build_message(const Tag& tag) const +/** + * \brief generates the message for computing the tag + * \remarks It also sets some parameters to the Tag object, based on the verification process. + * + * \param tag The tag containing the information to be included in the message. + * + * \return The built OSNMA message as a vector of uint8_t. + */ +std::vector osnma_msg_receiver::build_message(Tag& tag) const { std::vector m; if (tag.CTR != 1) @@ -1257,40 +1242,9 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) const m.push_back(two_bits_nmas); // Add applicable NavData bits to message - std::string applicable_nav_data; - std::vector applicable_nav_data_bytes; - if (tag.ADKD == 0 || tag.ADKD == 12) // note: for ADKD=12 still the same logic applies. Only the Key selection is shifted 10 Subframes into the future. - { - const auto it = d_satellite_nav_data.find(tag.PRN_d); - if (it != d_satellite_nav_data.cend()) - { - const auto it2 = it->second.find(tag.TOW - 30); - if (it2 != it->second.cend()) - { - applicable_nav_data = it2->second.ephemeris_iono_vector_2; - } - } - // LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; - } - else if (tag.ADKD == 4) - { - const auto it = d_satellite_nav_data.find(tag.PRN_d); - if (it != d_satellite_nav_data.cend()) - { - const auto it2 = it->second.find(tag.TOW - 30); - if (it2 != it->second.cend()) - { - applicable_nav_data = it2->second.utc_vector_2; - } - } - // LOG(INFO) << "|---> Galileo OSNMA :: applicable NavData (PRN_d="<< static_cast(tag.PRN_d) << ", TOW=" << tag.TOW - 30 <<"): 0b" << applicable_nav_data; - } - else - { - LOG(WARNING) << "Galileo OSNMA: Tag verification :: unknown ADKD"; - } - // convert std::string to vector - applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); + std::string applicable_nav_data = d_nav_data_manager->get_navigation_data(tag); + std::vector applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); + tag.nav_data = applicable_nav_data; // update tag with applicable data // Convert and add NavData bytes into the message, taking care of that NMAS has only 2 bits for (uint8_t byte : applicable_nav_data_bytes) @@ -1322,17 +1276,17 @@ std::vector osnma_msg_receiver::build_message(const Tag& tag) const } -void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) -{ - // control size of container - while (d_satellite_nav_data[SV_ID].size() >= 25) - { - d_satellite_nav_data[SV_ID].erase(d_satellite_nav_data[SV_ID].begin()); - } - // d_osnma_data[TOW] = crypto; // crypto - d_satellite_nav_data[SV_ID][TOW] = data; // nav - // std::cout << "Galileo OSNMA: added element, size is " << d_satellite_nav_data[SV_ID].size() << std::endl; -} +//void osnma_msg_receiver::add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data) +//{ +// // control size of container +// while (d_satellite_nav_data[SV_ID].size() >= 25) +// { +// d_satellite_nav_data[SV_ID].erase(d_satellite_nav_data[SV_ID].begin()); +// } +// // d_osnma_data[TOW] = crypto; // crypto +// d_satellite_nav_data[SV_ID][TOW] = data; // nav +// // std::cout << "Galileo OSNMA: added element, size is " << d_satellite_nav_data[SV_ID].size() << std::endl; +//} void osnma_msg_receiver::display_data() @@ -1411,6 +1365,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO * @brief Removes the tags that have been verified from the multimap d_tags_awaiting_verify. * * This function iterates through the multimap d_tags_awaiting_verify, and removes the tags that have a status of SUCCESS or FAIL. + * \remarks it also prints the current unverified tags */ void osnma_msg_receiver::remove_verified_tags() { @@ -1458,9 +1413,25 @@ void osnma_msg_receiver::remove_verified_tags() } } LOG(INFO) << "Galileo OSNMA: d_tags_awaiting_verify :: size: " << d_tags_awaiting_verify.size(); + for (const auto& it : d_tags_awaiting_verify) + { + LOG(INFO) << "Galileo OSNMA: Tag verification :: status tag Id=" + << it.second.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << it.second.received_tag << std::dec + << ", TOW=" + << it.second.TOW + << ", ADKD=" + << static_cast(it.second.ADKD) + << ", PRNa=" + << static_cast(it.second.PRNa) + << ", PRNd=" + << static_cast(it.second.PRN_d) + << ", status= " + << d_helper->verification_status_str(it.second.status); + } } - /** * @brief Control the size of the tags awaiting verification multimap. * @@ -1847,3 +1818,16 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ return verified_tags; } } +void osnma_msg_receiver::send_data_to_pvt(std::vector data) +{ + if (!data.empty()) + { + for (size_t i = 0; i < data.size(); i++) + { + const auto tmp_obj = std::make_shared(data[i]); + this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(tmp_obj)); + } + + } + +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 7ecbe7428..dd8d6ebf3 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -27,6 +27,7 @@ #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 @@ -77,13 +78,14 @@ private: void read_mack_header(); void read_mack_body(); void process_mack_message(); - void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data); +// void add_satellite_data(uint32_t SV_ID, uint32_t TOW, const NavData& data); void remove_verified_tags(); void control_tags_awaiting_verify_size(); void display_data(); + void send_data_to_pvt(std::vector); bool verify_tesla_key(std::vector& key, uint32_t TOW); - bool verify_tag(const Tag& tag) const; + bool verify_tag(Tag& tag) const; bool tag_has_nav_data_available(const Tag& t) const; bool tag_has_key_available(const Tag& t) const; bool verify_macseq(const MACK_message& mack); @@ -91,7 +93,7 @@ private: std::vector get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const; std::vector compute_merkle_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const; - std::vector build_message(const Tag& tag) const; + std::vector build_message(Tag& tag) const; std::vector hash_chain(uint32_t num_of_hashes_needed, const std::vector& key, uint32_t GST_SFi, const uint8_t lk_bytes) const; std::vector verify_macseq_new(const MACK_message& mack); @@ -110,6 +112,7 @@ private: std::unique_ptr d_dsm_reader; // osnma parameters parser std::unique_ptr d_crypto; // access to cryptographic functions std::unique_ptr d_helper; + std::unique_ptr d_nav_data_manager; // refactor for holding and processing navigation data OSNMA_data d_osnma_data{}; diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 055ff256e..5e42732c7 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -32,6 +32,7 @@ set(SYSTEM_PARAMETERS_SOURCES osnma_data.cc osnma_dsm_reader.cc osnma_helper.cc + osnma_nav_data_manager.cc ) set(SYSTEM_PARAMETERS_HEADERS @@ -98,6 +99,7 @@ set(SYSTEM_PARAMETERS_HEADERS osnma_data.h osnma_dsm_reader.h osnma_helper.h + osnma_nav_data_manager.h ) list(SORT SYSTEM_PARAMETERS_HEADERS) diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 49051b7be..14382e21a 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -25,148 +25,37 @@ */ uint32_t Tag::id_counter = 0; -void NavData::init(const std::shared_ptr &osnma_msg) +uint32_t NavData::id_counter = 0; + +bool NavData::add_nav_data(std::string nav_data) { - EphemerisData = osnma_msg->EphemerisData; - IonoData = osnma_msg->IonoData; - UtcData = osnma_msg->UtcModelData; - generate_eph_iono_vector(); - generate_utc_vector(); - PRNa = osnma_msg->PRN; - WN_sf0 = osnma_msg->WN_sf0; - TOW_sf0 = osnma_msg->TOW_sf0; - - // new parsing, directly parsing bits -// ephemeris_iono_vector_2 = osnma_msg->EphemerisClockAndStatusData_2; -// utc_vector_2 = osnma_msg->TimingData_2; -}; -void NavData::generate_eph_iono_vector() -{ - ephemeris_iono_vector.clear(); - uint64_t bit_buffer = 0; // variable to store the bits to be extracted, it can contain bits from different variables - int bit_count = 0; // Number of bits in the buffer, i.e. to be extracted - - // create structure to hold the variables to store into the vector along with their bit size - std::vector> variables = { - // data from word type 1 - {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, - {static_cast(&EphemerisData.toe), sizeof(EphemerisData.toe) * 8}, - {static_cast(&EphemerisData.M_0), sizeof(EphemerisData.M_0) * 8}, - {static_cast(&EphemerisData.ecc), sizeof(EphemerisData.ecc) * 8}, - {static_cast(&EphemerisData.sqrtA), sizeof(EphemerisData.sqrtA) * 8}, - // data from word type 2 - {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, - {static_cast(&EphemerisData.OMEGA_0), sizeof(EphemerisData.OMEGA_0) * 8}, - {static_cast(&EphemerisData.i_0), sizeof(EphemerisData.i_0) * 8}, - {static_cast(&EphemerisData.omega), sizeof(EphemerisData.omega) * 8}, - {static_cast(&EphemerisData.idot), sizeof(EphemerisData.idot) * 8}, - {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, - // data from word type 3 - {static_cast(&EphemerisData.OMEGAdot), sizeof(EphemerisData.OMEGAdot) * 8}, - {static_cast(&EphemerisData.delta_n), sizeof(EphemerisData.delta_n) * 8}, - {static_cast(&EphemerisData.Cuc), sizeof(EphemerisData.Cuc) * 8}, - {static_cast(&EphemerisData.Cus), sizeof(EphemerisData.Cus) * 8}, - {static_cast(&EphemerisData.Crc), sizeof(EphemerisData.Crc) * 8}, - {static_cast(&EphemerisData.Crs), sizeof(EphemerisData.Crs) * 8}, - {static_cast(&EphemerisData.SISA), sizeof(EphemerisData.SISA) * 8}, - // data from word type 4 - {static_cast(&EphemerisData.IOD_nav), sizeof(EphemerisData.IOD_nav) * 8}, - {static_cast(&EphemerisData.PRN), sizeof(EphemerisData.PRN) * 8}, - {static_cast(&EphemerisData.Cic), sizeof(EphemerisData.Cic) * 8}, - {static_cast(&EphemerisData.Cis), sizeof(EphemerisData.Cis) * 8}, - {static_cast(&EphemerisData.toe), sizeof(EphemerisData.toe) * 8}, - {static_cast(&EphemerisData.af0), sizeof(EphemerisData.af0) * 8}, - {static_cast(&EphemerisData.af1), sizeof(EphemerisData.af1) * 8}, - {static_cast(&EphemerisData.af2), sizeof(EphemerisData.af2) * 8}, - // data from word type 5 - {static_cast(&IonoData.ai0), sizeof(IonoData.ai0) * 8}, - {static_cast(&IonoData.ai1), sizeof(IonoData.ai1) * 8}, - {static_cast(&IonoData.ai2), sizeof(IonoData.ai2) * 8}, - {static_cast(&IonoData.Region1_flag), sizeof(IonoData.Region1_flag) * 8}, - {static_cast(&IonoData.Region2_flag), sizeof(IonoData.Region2_flag) * 8}, - {static_cast(&IonoData.Region3_flag), sizeof(IonoData.Region3_flag) * 8}, - {static_cast(&IonoData.Region4_flag), sizeof(IonoData.Region4_flag) * 8}, - {static_cast(&IonoData.Region5_flag), sizeof(IonoData.Region5_flag) * 8}, - {static_cast(&EphemerisData.BGD_E1E5a), sizeof(EphemerisData.BGD_E1E5a) * 8}, - {static_cast(&EphemerisData.BGD_E1E5b), sizeof(EphemerisData.BGD_E1E5b) * 8}, - {static_cast(&EphemerisData.E5b_HS), sizeof(EphemerisData.E5b_HS) * 8}, - {static_cast(&EphemerisData.E1B_HS), sizeof(EphemerisData.E1B_HS) * 8}, - {static_cast(&EphemerisData.E5b_DVS), sizeof(EphemerisData.E5b_DVS) * 8}, - {static_cast(&EphemerisData.E1B_DVS), sizeof(EphemerisData.E1B_DVS) * 8}, - }; - - for (auto& var : variables) - { - // extract the bits from the variable - uint64_t binary_representation; - memcpy(&binary_representation, var.first, var.second / 8); - - // Append the bits to the buffer and update the bit count - bit_buffer = (bit_buffer << var.second) | binary_representation; - bit_count += var.second; - // While there are 8 or more bits in the buffer - while (bit_count >= 8) + if (nav_data.size() == 549) { - // Extract the 8 bits starting from last bit position and add them to the vector - uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; - ephemeris_iono_vector.push_back(extracted_bits); - - // Remove the extracted bits from the buffer - bit_count -= 8; - bit_buffer = bit_buffer & ~(0xFF << bit_count); + ephemeris_iono_vector_2 = nav_data; + std::bitset<10> bits(nav_data.substr(0,10)); + IOD_nav = static_cast(bits.to_ulong()); + return true; } - - } - - // If there are any bits left in the buffer, add them to the vector - if (bit_count > 0) - { - ephemeris_iono_vector.push_back(static_cast(bit_buffer)); - } + else if (nav_data.size() == 141) + { + utc_vector_2 = nav_data; + return true; + } + return false; } - -void NavData::generate_utc_vector() +std::string NavData::get_utc_data() const { - utc_vector.clear(); - uint64_t bit_buffer = 0; - int bit_count = 0; - - std::vector> variables = { - {static_cast(&UtcData.A0), sizeof(UtcData.A0) * 8}, - {static_cast(&UtcData.A1), sizeof(UtcData.A1) * 8}, - {static_cast(&UtcData.Delta_tLS), sizeof(UtcData.Delta_tLS) * 8}, - {static_cast(&UtcData.tot), sizeof(UtcData.tot) * 8}, - {static_cast(&UtcData.WNot), sizeof(UtcData.WNot) * 8}, - {static_cast(&UtcData.WN_LSF), sizeof(UtcData.WN_LSF) * 8}, - {static_cast(&UtcData.DN), sizeof(UtcData.DN) * 8}, - {static_cast(&UtcData.Delta_tLSF), sizeof(UtcData.Delta_tLSF) * 8}, - {static_cast(&UtcData.A_0G), sizeof(UtcData.A_0G) * 8}, - {static_cast(&UtcData.A_1G), sizeof(UtcData.A_1G) * 8}, - {static_cast(&UtcData.t_0G), sizeof(UtcData.t_0G) * 8}, - {static_cast(&UtcData.WN_0G), sizeof(UtcData.WN_0G) * 8}, - }; - - for (auto& var : variables) - { - uint64_t binary_representation; - memcpy(&binary_representation, var.first, var.second / 8); - - bit_buffer = (bit_buffer << var.second) | binary_representation; - bit_count += var.second; - - while (bit_count >= 8) - { - uint8_t extracted_bits = (bit_buffer >> (bit_count - 8)) & 0xFF; - utc_vector.push_back(extracted_bits); - - bit_count -= 8; - bit_buffer = bit_buffer & ~(0xFF << bit_count); - } - } - - if (bit_count > 0) - { - utc_vector.push_back(static_cast(bit_buffer)); - } + return utc_vector_2; +} +std::string NavData::get_ephemeris_data() const +{ + return ephemeris_iono_vector_2; +} +/** + * Updates the last TOW the NavData bits were received. + * @param TOW + */ +void NavData::update_last_received_timestamp(uint32_t TOW) +{ + last_received_TOW = TOW; } - diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 484fa0162..57e4b7012 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -129,23 +129,28 @@ public: class NavData { public: - NavData()=default; - void init(const std::shared_ptr &osnma_msg); - std::vector ephemeris_iono_vector{}; - std::string ephemeris_iono_vector_2{}; - std::vector utc_vector{}; - std::string utc_vector_2{}; - uint32_t PRNa{}; - uint32_t WN_sf0{}; - uint32_t TOW_sf0{}; + NavData(): nav_data_id(id_counter++){ + + } + bool have_this_bits(std::string nav_data); + bool add_nav_data(std::string nav_data); + void update_last_received_timestamp(uint32_t TOW); + const uint32_t nav_data_id; + uint32_t verified_bits{0}; + uint32_t TOW_sf0{0}; + uint32_t last_received_TOW{0}; + uint32_t IOD_nav{0}; + std::string get_utc_data() const; + std::string get_ephemeris_data() const; + bool verified{false}; + uint32_t PRNd{0}; + uint32_t ADKD{}; private: - Galileo_Ephemeris EphemerisData; - Galileo_Iono IonoData; - Galileo_Utc_Model UtcData; - void generate_eph_iono_vector(); // TODO pass data directly fro Telemetry Decoder (if bits are in the needed order) - void generate_utc_vector(); // TODO + std::string ephemeris_iono_vector_2{}; + std::string utc_vector_2{}; + uint32_t static id_counter; }; /*! @@ -202,20 +207,19 @@ public: { } const uint32_t tag_id; + uint32_t static id_counter; uint32_t TOW; uint32_t WN; uint32_t PRNa; uint8_t CTR; e_verification_status status; uint64_t received_tag; - - uint32_t static id_counter; uint64_t computed_tag; - uint8_t PRN_d; uint8_t ADKD; uint8_t cop; uint32_t skipped; + std::string nav_data; }; /** \} */ /** \} */ diff --git a/src/core/system_parameters/osnma_nav_data_manager.cc b/src/core/system_parameters/osnma_nav_data_manager.cc new file mode 100644 index 000000000..c8c979306 --- /dev/null +++ b/src/core/system_parameters/osnma_nav_data_manager.cc @@ -0,0 +1,226 @@ +// +// Created by cgm on 23/07/24. +// + +#include "osnma_nav_data_manager.h" +#if USE_GLOG_AND_GFLAGS +#include // for DLOG +#else +#include +#endif + +/** + * @brief Adds the navigation data bits to the container holding NavData objects. + * + * @param nav_bits The navigation bits. + * @param PRNd The satellite ID. + * @param TOW The TOW of the received data. + */ +void OSNMA_nav_data_Manager::add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW) +{ + if(not have_nav_data(nav_bits, PRNd, TOW)) + { + _satellite_nav_data[PRNd][TOW].add_nav_data(nav_bits); + _satellite_nav_data[PRNd][TOW].PRNd = PRNd; + _satellite_nav_data[PRNd][TOW].TOW_sf0 = TOW; + } +} +/** + * @brief loops over the verified tags and updates the navigation data tag length + */ +void OSNMA_nav_data_Manager::update_nav_data(const std::multimap& tags_verified, const uint8_t tag_size) +{ + // loop through all tags + for (const auto& tag : tags_verified) + { + // if tag status is verified, look for corresponding navData and add increase verified tag bits. + if (tag.second.status == Tag::e_verification_status::SUCCESS) + { + if(have_PRNd_nav_data(tag.second.PRN_d)) + { + std::map tow_map = _satellite_nav_data.find(tag.second.PRN_d)->second; + for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + { + std::string nav_data; + if(tag.second.ADKD == 0 || tag.second.ADKD == 12){ + nav_data = tow_it->second.get_ephemeris_data(); + } + else if(tag.second.ADKD == 4){ + nav_data = tow_it->second.get_utc_data(); + } + // find associated navData + if (tag.second.nav_data == nav_data){ + _satellite_nav_data[tag.second.PRN_d][tow_it->first].verified_bits += tag_size; + } + } + } + } + } +} +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_nav_data_Manager::get_verified_data() +{ + std::vector result; + for (const auto& prna : _satellite_nav_data) + { + for (const auto& tow_navdata : prna.second) + { + if (tow_navdata.second.verified_bits >= L_t_min) + { + result.push_back(tow_navdata.second); + _satellite_nav_data[prna.first][tow_navdata.first].verified = true; + } + } + } + return result; +} +bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD) +{ + if (ADKD == 0 || ADKD == 12) + { + const auto it = _satellite_nav_data.find(PRNd); + if (it != _satellite_nav_data.cend()) + { + const auto it2 = it->second.find(TOW); + if (it2 != it->second.cend() && it->second[TOW].get_ephemeris_data() != "") + { + return true; + } + } + } + else if (ADKD == 4) + { + const auto it = _satellite_nav_data.find(PRNd); + if (it != _satellite_nav_data.cend()) + { + const auto it2 = it->second.find(TOW); + if (it2 != it->second.cend() && it->second[TOW].get_utc_data() != "") + { + return true; + } + } + } + return false; +} +/** + * @brief returns NavData object. + * @remarks assumes it exists (called have_nav_data before), otherwise undefined behavior + * TODO - maybe add const promise and use find() instead? this is kinda sensitive topic. + */ +std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) +{ + auto prn_it = _satellite_nav_data.find(tag.PRN_d); + if (prn_it == _satellite_nav_data.end()){ + return ""; + } + + // satellite was found, check if TOW exists in inner map + std::map tow_map = prn_it->second; + for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + { + // Check if current key (TOW) fulfills condition + if ((tag.TOW - 30 * tag.cop) <= tow_it->first && tow_it->first <= tag.TOW - 30) + { + if(tag.ADKD == 0 || tag.ADKD == 12) + { + if(tow_it->second.get_ephemeris_data() != ""){ + return tow_it->second.get_ephemeris_data(); + } + } + else if(tag.ADKD == 4) + { + if(tow_it->second.get_utc_data() != ""){ + return tow_it->second.get_utc_data(); + } + } + } + } + return ""; +} +/** + * @brief Checks if the navData bits are already present. In case affirmative, it updates the 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. + * @param nav_bits + * @param PRNd + * @return + */ +bool OSNMA_nav_data_Manager::have_nav_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW) +{ + if(_satellite_nav_data.find(PRNd) != _satellite_nav_data.end()){ + for (auto& data_timestamp : _satellite_nav_data[PRNd]) + { + if(nav_bits.size() == EPH_SIZE){ + if(data_timestamp.second.get_ephemeris_data() == nav_bits){ + data_timestamp.second.update_last_received_timestamp(TOW); + return true; + } + } + else if(nav_bits.size() == UTC_SIZE){ + if(data_timestamp.second.get_utc_data() == nav_bits){ + data_timestamp.second.update_last_received_timestamp(TOW); + return true; + } + } + } + } + return false; +} +/** + * @brief Checks if there is a NavData element within the COP time interval for a Tag t + * @param t Tag object + * @return True if the needed navigation data for the tag is available (oldest possible NavData available) + */ +bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const +{ + auto prn_it = _satellite_nav_data.find(t.PRN_d); + if (prn_it == _satellite_nav_data.end()){ + return false; + } + // satellite was found, check if TOW exists in inner map + std::map tow_map = prn_it->second; + for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + { + // Check if current key (TOW) fulfills condition + if (t.TOW - 30 * t.cop <= tow_it->first && tow_it->first <= t.TOW - 30) + { + if(t.ADKD == 0 || t.ADKD == 12) + { + if(tow_it->second.get_ephemeris_data() != ""){ + return true; + } + } + else if(t.ADKD == 4) + { + if(tow_it->second.get_utc_data() != ""){ + return true; + } + } + + } + } + return false; +} +void OSNMA_nav_data_Manager::print_status() +{ + for (const auto& satellite : _satellite_nav_data){ + LOG(INFO) << "Galileo OSNMA: NavData status :: SVID=" << satellite.first; + auto& tow_data = satellite.second; + for (const auto& nav_data : tow_data) + LOG(INFO) << "Galileo OSNMA: IOD_nav=0b" << std::uppercase + << std::bitset<10>(nav_data.second.IOD_nav) + << ", TOW_start=" + << nav_data.second.TOW_sf0 + << ", TOW_last=" + << nav_data.second.last_received_TOW + << ", l_t=" + << nav_data.second.verified_bits + << ", PRNd=" + << nav_data.second.PRNd + << ", verified=" + << nav_data.second.verified; + } +} diff --git a/src/core/system_parameters/osnma_nav_data_manager.h b/src/core/system_parameters/osnma_nav_data_manager.h new file mode 100644 index 000000000..9471a14a8 --- /dev/null +++ b/src/core/system_parameters/osnma_nav_data_manager.h @@ -0,0 +1,41 @@ +// +// Created by cgm on 23/07/24. +// + +#ifndef GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H +#define GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H + +#include "osnma_data.h" // NavData +#include // uint32_t +#include +#include + +/** + * @class OSNMA_nav_data_Manager + * @brief Class for managing OSNMA navigation data + * @details It does good stuff + * @remarks throw it whatever, it will improve it. Does good stuff + */ +class OSNMA_nav_data_Manager{ +public: + OSNMA_nav_data_Manager() = default; + bool have_nav_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); + bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD); + bool have_nav_data(const Tag& t) const; + void add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list + std::string get_navigation_data(const Tag& t); + + void update_nav_data(const std::multimap& tags_verified, const uint8_t tag_size); + std::vector get_verified_data(); + void print_status(); +private: + bool have_PRNd_nav_data(uint32_t PRNd); + + std::map> _satellite_nav_data{}; // NavData sorted by [PRNd][TOW_start] + const uint32_t L_t_min{40}; + const uint16_t EPH_SIZE{549}; + const uint16_t UTC_SIZE{141}; + const uint16_t MAX_ALLOWED_SIZE{150}; // arbitrary maximum for the navigation data container + +}; +#endif // GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index d0df27a3b..d741dfbf6 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -64,6 +64,7 @@ public: TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot) { + // input data taken from Receiver Guidelines v1.3, A.7 // Arrange // ---------- std::vector computed_merkle_root; @@ -74,6 +75,7 @@ TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot) dsm_pkr_message.mid = 0x01; std::vector base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); + // ITN std::vector vec = helper.convert_from_hex_string("7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06" "956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7" "407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1" @@ -92,6 +94,7 @@ TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot) TEST_F(OsnmaMsgReceiverTest, ComputeBaseLeaf) { + // input data taken from Receiver Guidelines v1.3, A.7 // Arrange // ---------- std::vector expected_base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); @@ -109,7 +112,9 @@ TEST_F(OsnmaMsgReceiverTest, ComputeBaseLeaf) ASSERT_EQ(computed_base_leaf,expected_base_leaf); } -TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey){ // values taken from RG A.7 +TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey){ + + // input data taken from Receiver Guidelines v1.3, A.7 // Arrange // ---------- osnma->d_crypto->set_merkle_root(helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D")); @@ -126,7 +131,7 @@ TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey){ // values taken from RG A.7 // Act // ---------- - bool result = osnma->verify_dsm_pkr(dsm_pkr_message); + bool result = osnma->verify_dsm_pkr(dsm_pkr_message); // TODO - refactor method so that output is more than a boolean. // Assert // ---------- @@ -136,6 +141,7 @@ TEST_F(OsnmaMsgReceiverTest, VerifyPublicKey){ // values taken from RG A.7 TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) { + // input data taken from Receiver Guidelines v1.3, A.6.5.1 // Arrange // ---------- // m0 @@ -181,6 +187,7 @@ TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) } TEST_F(OsnmaMsgReceiverTest, TagVerification) { + // input data taken from Receiver Guidelines v1.3, A.6.5.1 // Arrange // ---------- // Tag0 @@ -204,20 +211,10 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { MTI.tag_info.cop = 0x0F; Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); - - // Act // ---------- bool result_tag0 = osnma->verify_tag(t0); - - - - - // Assert - // ---------- - //ASSERT_TRUE(result_tag0); - // Tag3 uint32_t TOW_Tag3 = 345660; uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; @@ -247,6 +244,7 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) { } TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { + // input data taken from Receiver Guidelines v1.3, A.5.2 // Arrange // ---------- osnma->d_tesla_key_verified = false; @@ -262,16 +260,9 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) { std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 uint32_t TOW = 345630; - - - // Act // ---------- - bool result = osnma->verify_tesla_key(key, TOW); - - - - + bool result = osnma->verify_tesla_key(key, TOW); // TODO - refactor so that output is not a boolean. Or use last_verified_tesla_key? // Assert // ---------- From e0506eaf9b08f3d76a893a5761684eff9a6bbd6b Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 25 Jul 2024 16:00:43 +0200 Subject: [PATCH 180/219] Consider CI/CD comments (x2) --- src/core/libs/osnma_msg_receiver.cc | 19 +++--- src/core/libs/osnma_msg_receiver.h | 2 +- src/core/system_parameters/osnma_data.cc | 2 +- src/core/system_parameters/osnma_data.h | 6 +- .../osnma_nav_data_manager.cc | 58 +++++++++++-------- .../osnma_nav_data_manager.h | 30 +++++++--- .../osnma/osnma_msg_receiver_test.cc | 37 ++++++------ 7 files changed, 88 insertions(+), 66 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index f01414ad4..49ee685bf 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -24,7 +24,7 @@ #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "osnma_helper.h" -#include "osnma_nav_data_manager.h" // TODO - all these repeated includes, is it good practice to include them in the source file? +#include "osnma_nav_data_manager.h" // TODO - all these repeated includes, is it good practice to include them in the source file? #include // for gr::io_signature::make #include #include @@ -118,16 +118,15 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) std::cout << output_message.str() << std::endl; process_osnma_message(nma_msg); - } // OSNMA frame received - else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) // Navigation data bits for OSNMA received + } // OSNMA frame received + else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) // Navigation data bits for OSNMA received { // TODO - PRNa is a typo here, I think for d_satellite_nav_data, is PRN_d the name to use const auto inav_data = wht::any_cast>>(pmt::any_ref(msg)); uint32_t PRNa = std::get<0>(*inav_data); std::string nav_data = std::get<1>(*inav_data); uint32_t TOW = std::get<2>(*inav_data); - - d_nav_data_manager->add_navigation_data(nav_data,PRNa,TOW); + d_nav_data_manager->add_navigation_data(nav_data, PRNa,TOW); } else { @@ -605,7 +604,7 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrTOW_sf0); if (d_kroot_verified || d_tesla_key_verified || d_osnma_data.d_dsm_kroot_message.ts != 0 /*mack parser needs to know the tag size, otherwise cannot parse mack messages*/) // C: 4 ts < ts < 10 - {// TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future + { // TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future 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; @@ -949,7 +948,7 @@ void osnma_msg_receiver::process_mack_message() for (auto& it : d_tags_awaiting_verify) { bool ret; - if (tag_has_key_available(it.second) && d_nav_data_manager->have_nav_data(it.second))//tag_has_nav_data_available(it.second)) + if (tag_has_key_available(it.second) && d_nav_data_manager->have_nav_data(it.second)) // tag_has_nav_data_available(it.second)) { ret = verify_tag(it.second); /* TODO - take into account: @@ -1206,7 +1205,7 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) const computed_mac += static_cast(mac[4]); } - tag.computed_tag = computed_mac; // update with computed value + tag.computed_tag = computed_mac; // update with computed value // Compare computed tag with received one truncated if (tag.received_tag == computed_mac) { @@ -1245,7 +1244,7 @@ std::vector osnma_msg_receiver::build_message(Tag& tag) const // Add applicable NavData bits to message std::string applicable_nav_data = d_nav_data_manager->get_navigation_data(tag); std::vector applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); - tag.nav_data = applicable_nav_data; // update tag with applicable data + tag.nav_data = applicable_nav_data; // update tag with applicable data // Convert and add OSNMA_NavData bytes into the message, taking care of that NMAS has only 2 bits for (uint8_t byte : applicable_nav_data_bytes) @@ -1814,7 +1813,5 @@ void osnma_msg_receiver::send_data_to_pvt(std::vector data) const auto tmp_obj = std::make_shared(data[i]); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(tmp_obj)); } - } - } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 19fc9a4a3..53931d2cc 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -111,7 +111,7 @@ private: std::unique_ptr d_dsm_reader; // osnma parameters parser std::unique_ptr d_crypto; // access to cryptographic functions std::unique_ptr d_helper; - std::unique_ptr d_nav_data_manager; // refactor for holding and processing navigation data + std::unique_ptr d_nav_data_manager; // refactor for holding and processing navigation data OSNMA_data d_osnma_data{}; diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index aef0f9e10..d19a30cab 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -24,7 +24,7 @@ bool OSNMA_NavData::add_nav_data(std::string nav_data) if (nav_data.size() == 549) { d_ephemeris_iono = nav_data; - std::bitset<10> bits(nav_data.substr(0,10)); + std::bitset<10> bits(nav_data.substr(0, 10)); IOD_nav = static_cast(bits.to_ulong()); return true; } diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 72fa0fa37..46b54dcfe 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -127,9 +127,7 @@ public: class OSNMA_NavData { public: - OSNMA_NavData(): nav_data_id(id_counter++){ - - } + OSNMA_NavData(): nav_data_id(id_counter++){} bool have_this_bits(std::string nav_data); bool add_nav_data(std::string nav_data); void update_last_received_timestamp(uint32_t TOW); @@ -141,6 +139,8 @@ public: uint32_t IOD_nav{0}; std::string get_utc_data() const; std::string get_ephemeris_data() const; + void set_ephemeris_data(std::string value) {d_ephemeris_iono = value;} + void set_utc_data(std::string value) {d_utc = value;} bool verified{false}; uint32_t PRNd{0}; uint32_t ADKD{}; diff --git a/src/core/system_parameters/osnma_nav_data_manager.cc b/src/core/system_parameters/osnma_nav_data_manager.cc index c792239ec..5b42e799d 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.cc +++ b/src/core/system_parameters/osnma_nav_data_manager.cc @@ -1,10 +1,23 @@ -// -// Created by cgm on 23/07/24. -// +/*! +* \file osnma_nav_data_manager.cc +* \brief Class for Galileo OSNMA navigation data management +* \author Cesare Ghionoiu-Martinez, 2020-2023 cesare.martinez(at)proton.me +* +* ----------------------------------------------------------------------------- +* +* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +* This file is part of GNSS-SDR. +* +* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) +* SPDX-License-Identifier: GPL-3.0-or-later +* +* ----------------------------------------------------------------------------- +*/ #include "osnma_nav_data_manager.h" #if USE_GLOG_AND_GFLAGS #include // for DLOG +#include #else #include #endif @@ -18,7 +31,7 @@ */ void OSNMA_nav_data_Manager::add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW) { - if(not have_nav_data(nav_bits, PRNd, TOW)) + if (not have_nav_data(nav_bits, PRNd, TOW)) { _satellite_nav_data[PRNd][TOW].add_nav_data(nav_bits); _satellite_nav_data[PRNd][TOW].PRNd = PRNd; @@ -36,16 +49,16 @@ void OSNMA_nav_data_Manager::update_nav_data(const std::multimap& // if tag status is verified, look for corresponding OSNMA_NavData and add increase verified tag bits. if (tag.second.status == Tag::e_verification_status::SUCCESS) { - if(have_PRNd_nav_data(tag.second.PRN_d)) + if (have_PRNd_nav_data(tag.second.PRN_d)) { std::map tow_map = _satellite_nav_data.find(tag.second.PRN_d)->second; - for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // 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){ + else if (tag.second.ADKD == 4){ nav_data = tow_it->second.get_utc_data(); } // find associated OSNMA_NavData @@ -120,20 +133,20 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) // satellite was found, check if TOW exists in inner map std::map tow_map = prn_it->second; - for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset { // Check if current key (TOW) fulfills condition if ((tag.TOW - 30 * tag.cop) <= tow_it->first && tow_it->first <= tag.TOW - 30) { - if(tag.ADKD == 0 || tag.ADKD == 12) + if (tag.ADKD == 0 || tag.ADKD == 12) { - if(tow_it->second.get_ephemeris_data() != ""){ + if (tow_it->second.get_ephemeris_data() != ""){ return tow_it->second.get_ephemeris_data(); } } else if(tag.ADKD == 4) { - if(tow_it->second.get_utc_data() != ""){ + if (tow_it->second.get_utc_data() != ""){ return tow_it->second.get_utc_data(); } } @@ -150,17 +163,17 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) */ bool OSNMA_nav_data_Manager::have_nav_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW) { - if(_satellite_nav_data.find(PRNd) != _satellite_nav_data.end()){ + if (_satellite_nav_data.find(PRNd) != _satellite_nav_data.end()){ for (auto& data_timestamp : _satellite_nav_data[PRNd]) { - if(nav_bits.size() == EPH_SIZE){ - if(data_timestamp.second.get_ephemeris_data() == nav_bits){ + if (nav_bits.size() == EPH_SIZE){ + if (data_timestamp.second.get_ephemeris_data() == nav_bits){ data_timestamp.second.update_last_received_timestamp(TOW); return true; } } - else if(nav_bits.size() == UTC_SIZE){ - if(data_timestamp.second.get_utc_data() == nav_bits){ + else if (nav_bits.size() == UTC_SIZE){ + if (data_timestamp.second.get_utc_data() == nav_bits){ data_timestamp.second.update_last_received_timestamp(TOW); return true; } @@ -182,24 +195,23 @@ bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const } // satellite was found, check if TOW exists in inner map std::map tow_map = prn_it->second; - for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset { // Check if current key (TOW) fulfills condition if (t.TOW - 30 * t.cop <= tow_it->first && tow_it->first <= t.TOW - 30) { - if(t.ADKD == 0 || t.ADKD == 12) + if (t.ADKD == 0 || t.ADKD == 12) { - if(tow_it->second.get_ephemeris_data() != ""){ + if (tow_it->second.get_ephemeris_data() != ""){ return true; } } - else if(t.ADKD == 4) + else if (t.ADKD == 4) { - if(tow_it->second.get_utc_data() != ""){ + if (tow_it->second.get_utc_data() != ""){ return true; } } - } } return false; diff --git a/src/core/system_parameters/osnma_nav_data_manager.h b/src/core/system_parameters/osnma_nav_data_manager.h index cfea6ca94..2101bef3a 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.h +++ b/src/core/system_parameters/osnma_nav_data_manager.h @@ -1,13 +1,26 @@ -// -// Created by cgm on 23/07/24. -// +/*! +* \file osnma_nav_data_manager.h +* \brief Class for Galileo OSNMA navigation data management +* \author Cesare Ghionoiu-Martinez, 2020-2023 cesare.martinez(at)proton.me +* +* ----------------------------------------------------------------------------- +* +* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +* This file is part of GNSS-SDR. +* +* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) +* SPDX-License-Identifier: GPL-3.0-or-later +* +* ----------------------------------------------------------------------------- +*/ #ifndef GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H #define GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H -#include "osnma_data.h" // NavData -#include // uint32_t +#include "osnma_data.h" // NavData +#include // uint32_t #include +#include #include /** @@ -22,7 +35,7 @@ public: bool have_nav_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD); bool have_nav_data(const Tag& t) const; - void add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list + void add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list std::string get_navigation_data(const Tag& t); void update_nav_data(const std::multimap& tags_verified, const uint8_t tag_size); @@ -31,11 +44,10 @@ public: private: bool have_PRNd_nav_data(uint32_t PRNd); - std::map> _satellite_nav_data{}; // NavData sorted by [PRNd][TOW_start] + std::map> _satellite_nav_data{}; // NavData sorted by [PRNd][TOW_start] const uint32_t L_t_min{40}; const uint16_t EPH_SIZE{549}; const uint16_t UTC_SIZE{141}; - const uint16_t MAX_ALLOWED_SIZE{150}; // arbitrary maximum for the navigation data container - + const uint16_t MAX_ALLOWED_SIZE{150}; // arbitrary maximum for the navigation data container }; #endif // GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 08873dc47..c67b2b208 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -63,7 +63,7 @@ protected: const uint32_t LEAP_SECONDS = 0; // 13 + 5; void set_time(std::tm& input); // std::string log_name {"CONFIG1-2023-08-16-PKID1-OSNMA"}; - std::string log_name{"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; + std::string log_name{"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; // TODO - google::InitGoogleLogging(log_name.c_str()); but cannot be called twice void initializeGoogleLog(); void SetUp() override @@ -174,7 +174,7 @@ TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDB, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].set_ephemeris_iono_data( + osnma->d_nav_data_manager->add_navigation_data( "000011101001011001000100000101000111010110100100100101100000000000" "011101101011001111101110101010000001010000011011111100000011101011" "011100101101011010101011011011001001110111101011110110111111001111" @@ -183,7 +183,8 @@ TEST_F(OsnmaMsgReceiverTest, BuildTagMessageM0) "110100010001000110001110011010110000111010000010000000000001101000" "000000000011100101100100010000000000000110110100110001111100000000" "000000100110100000000101010010100000001011000010001001100000011111" - "110111111111000000000"); + "110111111111000000000", + PRNa, TOW_NavData); osnma->d_osnma_data.d_nma_header.nmas = 0b10; MACK_tag_and_info MTI; @@ -216,17 +217,16 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].set_ephemeris_iono_data(""); - osnma->d_satellite_nav_data[PRNa][TOW_NavData].set_ephemeris_iono_data( - "000011101001011001000100000101000111010110100100100101100000000000" - "011101101011001111101110101010000001010000011011111100000011101011" - "011100101101011010101011011011001001110111101011110110111111001111" - "001000011111101110011000111111110111111010000011101011111111110000" - "110111000000100000001110110000110110001110000100001110101100010100" - "110100010001000110001110011010110000111010000010000000000001101000" - "000000000011100101100100010000000000000110110100110001111100000000" - "000000100110100000000101010010100000001011000010001001100000011111" - "110111111111000000000"); + osnma->d_nav_data_manager->add_navigation_data( + "000011101001011001000100000101000111010110100100100101100000000000" + "011101101011001111101110101010000001010000011011111100000011101011" + "011100101101011010101011011011001001110111101011110110111111001111" + "001000011111101110011000111111110111111010000011101011111111110000" + "110111000000100000001110110000110110001110000100001110101100010100" + "110100010001000110001110011010110000111010000010000000000001101000" + "000000000011100101100100010000000000000110110100110001111100000000" + "000000100110100000000101010010100000001011000010001001100000011111" + "110111111111000000000", PRNa, TOW_NavData); osnma->d_osnma_data.d_nma_header.nmas = 0b10; MACK_tag_and_info MTI; @@ -252,9 +252,10 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit osnma->d_tesla_keys[TOW_Key_Tag3] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; - osnma->d_satellite_nav_data[PRNa][TOW_NavData].set_utc_data( + osnma->d_nav_data_manager->add_navigation_data( "111111111111111111111111111111110000000000000000000000010001001001001000" - "111000001000100111100010010111111111011110111111111001001100000100000000"); + "111000001000100111100010010111111111011110111111111001001100000100000" + , PRNa, TOW_NavData); osnma->d_osnma_data.d_nma_header.nmas = 0b10; MTI.tag = static_cast(0x7BB238C883); @@ -648,10 +649,10 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) void OsnmaMsgReceiverTest::initializeGoogleLog() { - google::InitGoogleLogging(log_name.c_str()); // TODO - running all tests causes conflict due to being called twice + // google::InitGoogleLogging(log_name.c_str()); FLAGS_minloglevel = 0; // INFO FLAGS_logtostderr = 0; // add this line - FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/data/build/src/tests/logs"; + // FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/data/logs"; if (FLAGS_log_dir.empty()) { std::cout << "Logging will be written at " From 3cc12e9b66b303a6ed15b058f787b62b66bc8eae Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 25 Jul 2024 21:40:43 +0200 Subject: [PATCH 181/219] Add basic infrastructure for the GNSS-SDR.osnma_mode=strict mode --- src/algorithms/PVT/adapters/rtklib_pvt.cc | 11 ++++++ .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 38 +++++++++++++++---- .../PVT/gnuradio_blocks/rtklib_pvt_gs.h | 1 + src/algorithms/PVT/libs/pvt_conf.h | 1 + 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.cc b/src/algorithms/PVT/adapters/rtklib_pvt.cc index bdd1f97c6..e964cf5a6 100644 --- a/src/algorithms/PVT/adapters/rtklib_pvt.cc +++ b/src/algorithms/PVT/adapters/rtklib_pvt.cc @@ -919,6 +919,17 @@ Rtklib_Pvt::Rtklib_Pvt(const ConfigurationInterface* configuration, // Use unhealthy satellites pvt_output_parameters.use_unhealthy_sats = configuration->property(role + ".use_unhealthy_sats", pvt_output_parameters.use_unhealthy_sats); + // OSNMA + if (gal_1B_count > 0) + { + std::string osnma_mode = configuration->property("GNSS-SDR.osnma_mode", std::string("")); + bool enable_osnma = configuration->property("GNSS-SDR.osnma_enable", true); + if (enable_osnma && osnma_mode == "strict") + { + pvt_output_parameters.osnma_strict = true; + } + } + // make PVT object pvt_ = rtklib_make_pvt_gs(in_streams_, pvt_output_parameters, rtk); DLOG(INFO) << "pvt(" << pvt_->unique_id() << ")"; diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 20982d650..109b935c7 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -185,7 +185,8 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, d_an_printer_enabled(conf_.an_output_enabled), d_log_timetag(conf_.log_source_timetag), d_use_has_corrections(conf_.use_has_corrections), - d_use_unhealthy_sats(conf_.use_unhealthy_sats) + d_use_unhealthy_sats(conf_.use_unhealthy_sats), + d_osnma_strict(conf_.osnma_strict) { // Send feedback message to observables block with the receiver clock offset this->message_port_register_out(pmt::mp("pvt_to_observables")); @@ -1652,10 +1653,18 @@ void rtklib_pvt_gs::msg_handler_osnma(const pmt::pmt_t& msg) { try { + // Still not sure about what we should receive here. + // It should be a structure with the list of PRNs authenticated (NavData and utcData, + // so with ADKD0 and ADKD12 validated), their corresponding TOW at the beginning + // of the authenticated subframe, and maybe the COP. const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) { // Act according to NMA data + if (d_osnma_strict) + { + // TODO + } } } catch (const wht::bad_any_cast& e) @@ -2023,7 +2032,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item bool store_valid_observable = false; - if (tmp_eph_iter_gps != d_internal_pvt_solver->gps_ephemeris_map.cend()) + if (!d_osnma_strict && tmp_eph_iter_gps != d_internal_pvt_solver->gps_ephemeris_map.cend()) { const uint32_t prn_aux = tmp_eph_iter_gps->second.PRN; if ((prn_aux == in[i][epoch].PRN) && (std::string(in[i][epoch].Signal, 2) == std::string("1C")) && (d_use_unhealthy_sats || (tmp_eph_iter_gps->second.SV_health == 0))) @@ -2039,10 +2048,18 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item ((std::string(in[i][epoch].Signal, 2) == std::string("5X")) && (d_use_unhealthy_sats || ((tmp_eph_iter_gal->second.E5a_DVS == false) && (tmp_eph_iter_gal->second.E5a_HS == 0)))) || ((std::string(in[i][epoch].Signal, 2) == std::string("7X")) && (d_use_unhealthy_sats || ((tmp_eph_iter_gal->second.E5b_DVS == false) && (tmp_eph_iter_gal->second.E5b_HS == 0)))))) { - store_valid_observable = true; + if (d_osnma_strict && ((std::string(in[i][epoch].Signal, 2) == std::string("1B")) || ((std::string(in[i][epoch].Signal, 2) == std::string("7X"))))) + { + // Pick up only authenticated satellites + // TODO + } + else + { + store_valid_observable = true; + } } } - if (tmp_eph_iter_cnav != d_internal_pvt_solver->gps_cnav_ephemeris_map.cend()) + if (!d_osnma_strict && tmp_eph_iter_cnav != d_internal_pvt_solver->gps_cnav_ephemeris_map.cend()) { const uint32_t prn_aux = tmp_eph_iter_cnav->second.PRN; if ((prn_aux == in[i][epoch].PRN) && (((std::string(in[i][epoch].Signal, 2) == std::string("2S")) || (std::string(in[i][epoch].Signal, 2) == std::string("L5"))))) @@ -2050,7 +2067,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item store_valid_observable = true; } } - if (tmp_eph_iter_glo_gnav != d_internal_pvt_solver->glonass_gnav_ephemeris_map.cend()) + if (!d_osnma_strict && tmp_eph_iter_glo_gnav != d_internal_pvt_solver->glonass_gnav_ephemeris_map.cend()) { const uint32_t prn_aux = tmp_eph_iter_glo_gnav->second.PRN; if ((prn_aux == in[i][epoch].PRN) && ((std::string(in[i][epoch].Signal, 2) == std::string("1G")) || (std::string(in[i][epoch].Signal, 2) == std::string("2G")))) @@ -2058,7 +2075,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item store_valid_observable = true; } } - if (tmp_eph_iter_bds_dnav != d_internal_pvt_solver->beidou_dnav_ephemeris_map.cend()) + if (!d_osnma_strict && tmp_eph_iter_bds_dnav != d_internal_pvt_solver->beidou_dnav_ephemeris_map.cend()) { const uint32_t prn_aux = tmp_eph_iter_bds_dnav->second.PRN; if ((prn_aux == in[i][epoch].PRN) && (((std::string(in[i][epoch].Signal, 2) == std::string("B1")) || (std::string(in[i][epoch].Signal, 2) == std::string("B3"))) && (d_use_unhealthy_sats || (tmp_eph_iter_bds_dnav->second.SV_health == 0)))) @@ -2068,7 +2085,14 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item } if (std::string(in[i][epoch].Signal, 2) == std::string("E6")) { - store_valid_observable = true; + if (d_osnma_strict) + { + // TODO + } + else + { + store_valid_observable = true; + } } if (store_valid_observable) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h index 96c527e25..4acc14728 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h @@ -280,6 +280,7 @@ private: bool d_log_timetag; bool d_use_has_corrections; bool d_use_unhealthy_sats; + bool d_osnma_strict; }; diff --git a/src/algorithms/PVT/libs/pvt_conf.h b/src/algorithms/PVT/libs/pvt_conf.h index 37d9b5aac..19d0a2e8d 100644 --- a/src/algorithms/PVT/libs/pvt_conf.h +++ b/src/algorithms/PVT/libs/pvt_conf.h @@ -95,6 +95,7 @@ public: bool use_e6_for_pvt = true; bool use_has_corrections = true; bool use_unhealthy_sats = false; + bool osnma_strict = false; // PVT KF parameters bool enable_pvt_kf = false; From 06e0c4b63ad9b036ea899fefc3d6276c2838216c Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Fri, 26 Jul 2024 18:03:21 +0200 Subject: [PATCH 182/219] [TAS-247][FEAT][Kroot] enable hotstart with last known Kroot * Kroot is now saved into binary file if successfuly verified. * on startup, file is checked first. * This should enable a much quicker TTFAF --- src/core/libs/osnma_msg_receiver.cc | 22 ++++-- src/core/libs/osnma_msg_receiver.h | 9 +-- src/core/receiver/gnss_flowgraph.cc | 3 +- src/core/system_parameters/Galileo_OSNMA.h | 1 + src/core/system_parameters/gnss_crypto.cc | 67 ++++++++++++++++++- src/core/system_parameters/gnss_crypto.h | 14 +++- .../osnma/osnma_msg_receiver_test.cc | 4 +- 7 files changed, 102 insertions(+), 18 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 49ee685bf..27130600f 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -60,22 +60,26 @@ namespace wht = std; #endif -osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath) +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath) { - return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath, merkleFilePath)); + return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath, merkleFilePath, rootKeyFilePath)); } -osnma_msg_receiver::osnma_msg_receiver( - const std::string& crtFilePath, - const std::string& merkleFilePath) : gr::block("osnma_msg_receiver", +osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath) : gr::block("osnma_msg_receiver", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)) { d_dsm_reader = std::make_unique(); - d_crypto = std::make_unique(crtFilePath, merkleFilePath); + d_crypto = std::make_unique(crtFilePath, merkleFilePath, rootKeyFilePath); d_helper = std::make_unique(); d_nav_data_manager = std::make_unique(); + + if(d_crypto->have_root_key()){ + d_kroot = d_crypto->get_root_key(); + d_kroot_verified = true; + } + // register OSNMA input message port from telemetry blocks this->message_port_register_in(pmt::mp("OSNMA_from_TLM")); // register OSNMA output message port to PVT block @@ -126,7 +130,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) uint32_t PRNa = std::get<0>(*inav_data); std::string nav_data = std::get<1>(*inav_data); uint32_t TOW = std::get<2>(*inav_data); - d_nav_data_manager->add_navigation_data(nav_data, PRNa,TOW); + d_nav_data_manager->add_navigation_data(nav_data, PRNa, TOW); } else { @@ -490,6 +494,10 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg LOG(INFO) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks); + // Save Kroot into a permanent storage + d_crypto->store_root_key(ROOTKEYFILE_DEFAULT); + d_kroot = d_osnma_data.d_dsm_kroot_message.kroot; + d_crypto->set_root_key(d_kroot); } else { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 53931d2cc..412296f12 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -50,7 +50,7 @@ class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; -osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath); /*! * \brief GNU Radio block that receives asynchronous OSNMA messages @@ -63,8 +63,8 @@ class osnma_msg_receiver : public gr::block public: ~osnma_msg_receiver() = default; //!< Default destructor private: - friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); - osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath); + friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath); + osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); @@ -100,6 +100,7 @@ private: std::map> d_tesla_keys; // tesla keys over time, sorted by TOW std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW + std::vector d_kroot; // last available stored root key std::vector d_tags_to_verify{0, 4, 12}; std::vector d_macks_awaiting_MACSEQ_verification; @@ -110,7 +111,7 @@ private: std::unique_ptr d_dsm_reader; // osnma parameters parser std::unique_ptr d_crypto; // access to cryptographic functions - std::unique_ptr d_helper; + std::unique_ptr d_helper; // helper class with auxiliary functions std::unique_ptr d_nav_data_manager; // refactor for holding and processing navigation data OSNMA_data d_osnma_data{}; diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index af1795ee0..035d690dc 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -126,7 +126,8 @@ void GNSSFlowgraph::init() enable_osnma_rx_ = true; const auto certFilePath = configuration_->property("GNSS-SDR.osnma_public_key", CRTFILE_DEFAULT); const auto merKleTreePath = configuration_->property("GNSS-SDR.osnma_merkletree", MERKLEFILE_DEFAULT); - osnma_rx_ = osnma_msg_receiver_make(certFilePath, merKleTreePath); + const auto rootKeyPath = configuration_->property("GNSS-SDR.osnma_root_key", ROOTKEYFILE_DEFAULT); + osnma_rx_ = osnma_msg_receiver_make(certFilePath, merKleTreePath, rootKeyPath); } else { diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 09f615e08..08a14c93e 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -163,6 +163,7 @@ const std::unordered_map OSNMA_TABLE_15 = { const std::string PEMFILE_STORED("./OSNMA_PublicKey.pem"); const std::string CRTFILE_DEFAULT("../data/OSNMA_PublicKey_20240115100000_newPKID_1.crt"); const std::string MERKLEFILE_DEFAULT("../data/OSNMA_MerkleTree_20240115100000_newPKID_1.xml"); +const std::string ROOTKEYFILE_DEFAULT("../data/OSNMA_RootKey.bin"); class Mack_lookup { diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index fa47720b1..e31a76acc 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -75,7 +75,7 @@ Gnss_Crypto::Gnss_Crypto() } -Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath) +Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath, const std::string& rootKeyFilePath) { #if USE_GNUTLS_FALLBACK gnutls_global_init(); @@ -100,6 +100,7 @@ Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& mer } } read_merkle_xml(merkleTreePath); + read_root_key(rootKeyFilePath); } @@ -122,7 +123,10 @@ Gnss_Crypto::~Gnss_Crypto() #endif } - +bool Gnss_Crypto::have_root_key() const +{ + return !d_kroot.empty(); +} bool Gnss_Crypto::have_public_key() const { #if USE_GNUTLS_FALLBACK @@ -196,6 +200,22 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const return true; } +bool Gnss_Crypto::store_root_key(const std::string& rootKeyFilePath) const +{ + if (!have_root_key()) + { + return false; + } + std::ofstream file(rootKeyFilePath, std::ios::binary | std::ios::out); + + if (!file) { + return false; + } + + file.write(reinterpret_cast(d_kroot.data()), d_kroot.size()); + + return file.good(); +} bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& message, const std::vector& signature) const { @@ -845,6 +865,10 @@ std::vector Gnss_Crypto::get_merkle_root() const return d_x_4_0; } +std::vector Gnss_Crypto::get_root_key() const +{ + return d_kroot; +} void Gnss_Crypto::set_public_key(const std::vector& publicKey) { @@ -899,12 +923,15 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) DLOG(INFO) << "OSNMA Public Key successfully set up."; } - void Gnss_Crypto::set_merkle_root(const std::vector& v) { d_x_4_0 = v; } +void Gnss_Crypto::set_root_key(const std::vector& root_key) +{ + d_kroot = root_key; +} void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) { @@ -1145,6 +1172,40 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) return true; } +/** + * \brief Reads the TESLA root key from a file and stores it. + * \param rootKeyFilePath The file path of the TESLA root key. + * \return True if the root key was successfully read and stored, false otherwise. + */ +bool Gnss_Crypto::read_root_key(const std::string& rootKeyFilePath) +{ + std::ifstream file(rootKeyFilePath, std::ios::binary | std::ios::in); + + if (!file) { + LOG(WARNING) << "Unable to open file: " << rootKeyFilePath; + return false; + } + + // Determine file size + file.seekg(0, std::ios::end); + std::streamsize size = file.tellg(); + file.seekg(0, std::ios::beg); + + if (size == 0) { + LOG(WARNING) << "File is empty: " << rootKeyFilePath; + return false; + } + + // Resize the vector and read file + d_kroot.resize(size); + if (!file.read(reinterpret_cast(d_kroot.data()), size)) { + LOG(WARNING) << "Failed to read the file: " << rootKeyFilePath; + return false; + } + std::cout << "OSNMA TESLA Root Key successfully read from file " << rootKeyFilePath << std::endl; + LOG(INFO) << "OSNMA TESLA Root Key successfully read from file " << rootKeyFilePath; + return true; +} bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const { diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 8e89f1525..6ff60650c 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -48,15 +48,22 @@ public: * and a XML file for the Merkle Tree root. * Files can be downloaded by registering at https://www.gsc-europa.eu/ */ - Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath); + Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath, const std::string& rootKeyFilePath); ~Gnss_Crypto(); //!< Default destructor + bool have_root_key() const; //!< Returns true if the TESLA root key is already loaded bool have_public_key() const; //!< Returns true if the ECDSA Public Key is already loaded /*! * Stores the ECDSA Public Key in a .pem file, which is read in a following run if the .crt file is not found */ bool store_public_key(const std::string& pubKeyFilePath) const; + /*! + * Stores the TESLA root key in a plaintext file, which is read in a following run for a faster TTFAF. + * @param kroot TESLA root key + * @return true if successful + */ + bool store_root_key(const std::string& rootKeyFilePath) const; bool verify_signature_ecdsa_p256(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P256 signature (message in plain hex, signature in raw format) bool verify_signature_ecdsa_p521(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P521 signature (message in plain hex, signature in raw format) @@ -68,13 +75,15 @@ public: std::vector get_public_key() const; //!< Gets the ECDSA Public Key in PEM format std::vector get_merkle_root() const; //!< Gets the Merkle Tree root node (\f$ x_{4,0} \f$) + std::vector get_root_key() const; //!< Gets the TESLA root key in binary format void set_public_key(const std::vector& publickey); //!< Sets the ECDSA Public Key (publickey in PEM format) void set_merkle_root(const std::vector& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$) - + void set_root_key(const std::vector& root_key); //!< Sets the TESLA root key private: void read_merkle_xml(const std::string& merkleFilePath); void readPublicKeyFromPEM(const std::string& pemFilePath); + bool read_root_key(const std::string& rootKeyFilePath); bool readPublicKeyFromCRT(const std::string& crtFilePath); bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; std::vector convert_from_hex_str(const std::string& input) const; @@ -91,6 +100,7 @@ private: #endif #endif std::vector d_x_4_0; + std::vector d_kroot; }; /** \} */ diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index c67b2b208..1d2c628ae 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -24,6 +24,7 @@ #include #include #include +#include "Galileo_OSNMA.h" #if USE_GLOG_AND_GFLAGS #include // for LOG @@ -76,7 +77,8 @@ protected: // std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; - osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + std::string rootKeyFilePath = ROOTKEYFILE_DEFAULT; + osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath, ROOTKEYFILE_DEFAULT); } }; From ec127089ab19a090d682933f71e3ad1477654eee Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 26 Jul 2024 18:09:25 +0200 Subject: [PATCH 183/219] Fix building of OSNMA tests --- src/core/libs/osnma_msg_receiver.h | 2 +- src/tests/CMakeLists.txt | 60 +-- src/tests/test_main.cc | 3 +- .../osnma/osnma_msg_receiver_test.cc | 417 +---------------- .../osnma/osnma_test_vectors.cc | 423 ++++++++++++++++++ 5 files changed, 453 insertions(+), 452 deletions(-) create mode 100644 src/tests/unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 412296f12..cda571321 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -146,12 +146,12 @@ private: // Provide access to inner functions to Gtest FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); - FRIEND_TEST(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation); FRIEND_TEST(OsnmaMsgReceiverTest, TagVerification); FRIEND_TEST(OsnmaMsgReceiverTest, BuildTagMessageM0); FRIEND_TEST(OsnmaMsgReceiverTest, VerifyPublicKey); FRIEND_TEST(OsnmaMsgReceiverTest, ComputeBaseLeaf); FRIEND_TEST(OsnmaMsgReceiverTest, ComputeMerkleRoot); + FRIEND_TEST(OsnmaTestVectors, OsnmaTestVectorsSimulation); }; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index d7bbab2ee..deca361e3 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -550,6 +550,18 @@ if(ENABLE_UNIT_TESTING_EXTRA) EXPECTED_HASH MD5=066d0d8434a8bc81e161778b7c34cc07 ) endif() + if(NOT EXISTS ${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/Test_vectors.zip) + message(STATUS "Downloading file: Test_vectors.zip") + file(DOWNLOAD https://www.gsc-europa.eu/sites/default/files/sites/all/files/Test_vectors.zip + ${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/Test_vectors.zip + SHOW_PROGRESS + EXPECTED_HASH MD5=8158aebee735652c9398e5bb6d944364 + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xzf ${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/Test_vectors.zip + WORKING_DIRECTORY ${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/ + ) + endif() message(STATUS "Done.") if(ENABLE_INSTALL_TESTS) install(FILES ${GNSSSDR_BINARY_DIR}/thirdparty/signal_samples/gps_l2c_m_prn7_5msps.dat DESTINATION share/gnss-sdr/signal_samples) @@ -652,6 +664,7 @@ if(ENABLE_UNIT_TESTING) if(GNSSTK_OLDER_THAN_9) target_compile_definitions(run_tests PRIVATE -DGNSSTK_OLDER_THAN_9=1) endif() + target_compile_definitions(run_tests PRIVATE -DBASE_OSNMA_TEST_VECTORS="${GNSSSDR_BINARY_DIR}/thirdparty/osnma_tests/Test_vectors/") endif() xcode_remove_warning_duplicates(run_tests) if(ENABLE_STRIP) @@ -1356,53 +1369,6 @@ else() endif() endif() - -######################################################### osnma_msg_receiver_test - -if(NOT ENABLE_PACKAGING AND NOT ENABLE_FPGA) - set(OSNMA_MSG_RECEIVER_TEST_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/single_test_main.cc - ${CMAKE_CURRENT_SOURCE_DIR}/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc - ) - - if(USE_CMAKE_TARGET_SOURCES) - add_executable(osnma_msg_receiver_test) - target_sources(osnma_msg_receiver_test PRIVATE ${OSNMA_MSG_RECEIVER_TEST_SOURCES}) - else() - add_executable(osnma_msg_receiver_test ${OSNMA_MSG_RECEIVER_TEST_SOURCES}) - endif() - - target_link_libraries(osnma_msg_receiver_test - PRIVATE - gnss_sdr_flags - Boost::thread - GTest::GTest - GTest::Main - core_libs - Gnuradio::blocks - Gnuradio::runtime - Gnuradio::filter # workaround for old systems - ) - if(ENABLE_GLOG_AND_GFLAGS) - target_link_libraries(osnma_msg_receiver_test PRIVATE Gflags::gflags Glog::glog) - target_compile_definitions(osnma_msg_receiver_test PRIVATE -DUSE_GLOG_AND_GFLAGS=1) - else() - target_link_libraries(osnma_msg_receiver_test PRIVATE absl::flags absl::flags_parse absl::log absl::log_initialize) - target_link_libraries(osnma_msg_receiver_test INTERFACE "$") - endif() - - xcode_remove_warning_duplicates(osnma_msg_receiver_test) # TODO - unsure if needed - - add_test(osnma_msg_receiver_test osnma_msg_receiver_test) - - set_property(TEST osnma_msg_receiver_test PROPERTY TIMEOUT 30) - - target_include_directories(osnma_msg_receiver_test - PRIVATE - ${GNSSSDR_SOURCE_DIR}/src/core/system_parameters - ) -endif() - if(ENABLE_BENCHMARKS) add_subdirectory(benchmarks) endif() diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index 7990ca258..bcd2b7018 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -113,7 +113,7 @@ private: #include "unit-tests/signal-processing-blocks/adapter/pass_through_test.cc" #include "unit-tests/signal-processing-blocks/libs/item_type_helpers_test.cc" #include "unit-tests/signal-processing-blocks/osnma/gnss_crypto_test.cc" -// #include "unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc" +#include "unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc" #include "unit-tests/signal-processing-blocks/pvt/geohash_test.cc" #include "unit-tests/signal-processing-blocks/pvt/nmea_printer_test.cc" #include "unit-tests/signal-processing-blocks/pvt/rinex_printer_test.cc" @@ -184,6 +184,7 @@ private: #include "unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc" #include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc" +#include "unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc" #endif // #include "unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc" #include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc" diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 1d2c628ae..05da06b9d 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -1,5 +1,5 @@ /*! - * \file osmna_msg_receiver_testt.cc + * \file osmna_msg_receiver_test.cc * \brief Tests for the osnma_msg_receiver class. * \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es * Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de @@ -28,30 +28,12 @@ #if USE_GLOG_AND_GFLAGS #include // for LOG -#include #else #include #endif -struct TestVector -{ - int svId; - int numNavBits; - std::vector navBits; -}; - - -// TODO - parametrize class for different configurations (config_1, config_2, etc.. potentially 5 or 6 more) an make sure wont affect current TEST_F -// note: until the test is parametrized for configuration 1 and 2, in order to change between them you have to comment/uncomment the respective calls in this test, identified with comments // conf. 1/2 -// log_name, input_time, crtFilePath, merkleFilePath, testVectors class OsnmaMsgReceiverTest : public ::testing::Test { -public: - static std::vector parseNavBits(const std::string& hex); - static std::vector readTestVectorsFromFile(const std::string& filename); - std::string bytes_to_str(const std::vector& bytes); - std::vector extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes); - protected: Osnma_Helper helper; osnma_msg_receiver_sptr osnma; @@ -63,22 +45,13 @@ protected: std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm const uint32_t LEAP_SECONDS = 0; // 13 + 5; void set_time(std::tm& input); - // std::string log_name {"CONFIG1-2023-08-16-PKID1-OSNMA"}; - std::string log_name{"CONFIG2-2023-07-27-PKID2-MT2-OSNMA"}; // TODO - google::InitGoogleLogging(log_name.c_str()); but cannot be called twice - void initializeGoogleLog(); void SetUp() override { - initializeGoogleLog(); // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 set_time(input_time); - // std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230803105952_newPKID_1.crt"; // conf. 1 - // std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; - std::string crtFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 - std::string merkleFilePath = "/home/cgm/CLionProjects/osnma/data/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; - std::string rootKeyFilePath = ROOTKEYFILE_DEFAULT; - osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath, ROOTKEYFILE_DEFAULT); + osnma = osnma_msg_receiver_make("", ""); } }; @@ -220,15 +193,16 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; osnma->d_nav_data_manager->add_navigation_data( - "000011101001011001000100000101000111010110100100100101100000000000" - "011101101011001111101110101010000001010000011011111100000011101011" - "011100101101011010101011011011001001110111101011110110111111001111" - "001000011111101110011000111111110111111010000011101011111111110000" - "110111000000100000001110110000110110001110000100001110101100010100" - "110100010001000110001110011010110000111010000010000000000001101000" - "000000000011100101100100010000000000000110110100110001111100000000" - "000000100110100000000101010010100000001011000010001001100000011111" - "110111111111000000000", PRNa, TOW_NavData); + "000011101001011001000100000101000111010110100100100101100000000000" + "011101101011001111101110101010000001010000011011111100000011101011" + "011100101101011010101011011011001001110111101011110110111111001111" + "001000011111101110011000111111110111111010000011101011111111110000" + "110111000000100000001110110000110110001110000100001110101100010100" + "110100010001000110001110011010110000111010000010000000000001101000" + "000000000011100101100100010000000000000110110100110001111100000000" + "000000100110100000000101010010100000001011000010001001100000011111" + "110111111111000000000", + PRNa, TOW_NavData); osnma->d_osnma_data.d_nma_header.nmas = 0b10; MACK_tag_and_info MTI; @@ -256,8 +230,8 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; osnma->d_nav_data_manager->add_navigation_data( "111111111111111111111111111111110000000000000000000000010001001001001000" - "111000001000100111100010010111111111011110111111111001001100000100000" - , PRNa, TOW_NavData); + "111000001000100111100010010111111111011110111111111001001100000100000", + PRNa, TOW_NavData); osnma->d_osnma_data.d_nma_header.nmas = 0b10; MTI.tag = static_cast(0x7BB238C883); @@ -297,325 +271,6 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) } -TEST_F(OsnmaMsgReceiverTest, OsnmaTestVectorsSimulation) -{ - // Arrange - std::vector testVectors = readTestVectorsFromFile("/home/cgm/CLionProjects/osnma/data/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 - if (testVectors.empty()) - { - ASSERT_TRUE(false); - } - - bool end_of_hex_stream{false}; - int offset_byte{0}; - int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size - const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page - const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe - const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds - - const int DUMMY_PAGE{63}; - bool flag_dummy_page{false}; - std::cout << "OsnmaTestVectorsSimulation:" - << " d_GST_SIS= " << d_GST_SIS - << ", TOW=" << TOW - << ", WN=" << WN << std::endl; - - // Act - // loop over all bytes of data. Note: all TestVectors have same amount of data. - while (end_of_hex_stream == false) - { - // loop over all SVs, extract a subframe - for (const TestVector& tv : testVectors) - { // loop over all SVs, extract a subframe - std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; - auto osnmaMsg_sptr = std::make_shared(); - std::array hkroot{}; - std::array mack{}; - byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) - std::map> words_for_OSNMA; // structure containing and - - for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe - { - // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index - std::vector page_bytes = extract_page_bytes(tv, byte_index, SIZE_PAGE_BYTES); - if (page_bytes.empty()) - { - std::cout << "OsnmaTestVectorsSimulation: end of TestVectors \n" - << "byte_index=" << byte_index << " expected= " << 432000 / 8 << std::endl; - end_of_hex_stream = true; - break; - } - // convert them to bitset representation using bytes_to_string - std::string page_bits = bytes_to_str(page_bytes); - // Extract the 40 OSNMA bits starting from the 18th bit - std::string even_page = page_bits.substr(0, page_bits.size() / 2); - std::string odd_page = page_bits.substr(page_bits.size() / 2); - if (even_page.size() < 120 || odd_page.size() < 120) - { - std::cout << "OsnmaTestVectorsSimulation: error parsing pages" << std::endl; - } - bool even_odd_OK = even_page[0] == '0' && odd_page[0] == '1'; - bool page_type_OK = even_page[1] == '0' && odd_page[1] == '0'; - bool tail_bits_OK = even_page.substr(even_page.size() - 6) == "000000" && odd_page.substr(odd_page.size() - 6) == "000000"; - if (!even_odd_OK || !page_type_OK || !tail_bits_OK) - std::cerr << "OsnmaTestVectorsSimulation: error parsing pages." << std::endl; - - std::bitset<112> data_k(even_page.substr(2, 112)); - std::bitset<16> data_j(odd_page.substr(2, 16)); - std::bitset<112> shifted_data_k = data_k; - uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word - std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast(word_type) << std::endl; - if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) - { - // store raw word - std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); - words_for_OSNMA[word_type] = data_combined; - } - if (word_type == DUMMY_PAGE) - flag_dummy_page = true; - - // place it into osnma object. - std::bitset<40> osnmaBits(odd_page.substr(18, 40)); - - // Extract bits for hkroot and mack - std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8)); - std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32)); - hkroot[idx] = static_cast(hkrootBits.to_ulong()); - mack[idx] = static_cast(mackBits.to_ulong()); - - byte_index += SIZE_PAGE_BYTES; - } - - std::cout << "----------" << std::endl; - if (end_of_hex_stream) - break; - if (flag_dummy_page) - { - flag_dummy_page = false; - continue; // skip this SV - } - - // Fill osnma object - osnmaMsg_sptr->hkroot = hkroot; - osnmaMsg_sptr->mack = mack; - - osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; - osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20; - osnmaMsg_sptr->PRN = tv.svId; // PRNa - - // TODO - refactor this logic, currently it is split - - // check if words_for_OSNMA 1--> 5 words_for_OSNMA are received => fill EphClockStatus data vector - bool ephClockStatusWordsReceived = true; - for (int i = 1; i <= 5; ++i) - { - if (words_for_OSNMA.find(i) == words_for_OSNMA.end()) - { - ephClockStatusWordsReceived = false; - std::cerr << "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " - "Word " - << i << " should be received for each subframe but was not." << std::endl; - } - } - // extract bits as needed by osnma block - if (ephClockStatusWordsReceived) - { - // Define the starting position and length of bits to extract for each word - std::map> extractionParams = { - {1, {6, 120}}, - {2, {6, 120}}, - {3, {6, 122}}, - {4, {6, 120}}, - {5, {6, 67}}, - }; - - // Fill NavData bits -- Iterate over the extraction parameters - std::string nav_data_ADKD_0_12 = ""; - for (const auto& param : extractionParams) - { - uint8_t wordKey = param.first; - uint8_t start = param.second.first; - uint8_t length = param.second.second; - - // Extract the required bits and fill osnma block - nav_data_ADKD_0_12 += words_for_OSNMA[wordKey].to_string().substr(start, length); - } - // send to osnma block - bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; - if (check_size_is_ok) - { - std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " - << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; - const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> - tv.svId, - nav_data_ADKD_0_12, - osnmaMsg_sptr->TOW_sf0); - LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12; - osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); - } - } - - // check w6 && w10 is received => fill TimingData data vector - bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() && - words_for_OSNMA.find(10) != words_for_OSNMA.end(); - // extract bits as needed by osnma block - if (timingWordsReceived) - { - // Define the starting position and length of bits to extract for each word - std::map> extractionParams = { - {6, {6, 99}}, - {10, {86, 42}}}; - - std::string nav_data_ADKD_4 = ""; - // Fill NavData bits -- Iterate over the extraction parameters - for (const auto& param : extractionParams) - { - uint8_t wordKey = param.first; - uint8_t start = param.second.first; - uint8_t length = param.second.second; - - // Extract the required bits and fill osnma block - nav_data_ADKD_4 += words_for_OSNMA[wordKey].to_string().substr(start, length); - } - // send to osnma block - bool check_size_is_ok = nav_data_ADKD_4.size() == 141; - if (check_size_is_ok) - { - std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " - << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; - const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> - tv.svId, - nav_data_ADKD_4, - osnmaMsg_sptr->TOW_sf0); - LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4; - osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); - } - } - - // Call the handler, as if it came from telemetry decoder block - auto temp_obj = pmt::make_any(osnmaMsg_sptr); - - osnma->msg_handler_osnma(temp_obj); // osnma entry point - } - - if (!end_of_hex_stream) - { - offset_byte = byte_index; // update offset for the next subframe - d_GST_SIS += DURATION_SUBFRAME; - TOW = d_GST_SIS & 0x000FFFFF; - WN = (d_GST_SIS & 0xFFF00000) >> 20; - std::cout << "OsnmaTestVectorsSimulation:" - << " d_GST_SIS= " << d_GST_SIS - << ", TOW=" << TOW - << ", WN=" << WN << std::endl; - } - } - // Assert - - // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) -} - - -// Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. -// Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. -std::vector OsnmaMsgReceiverTest::readTestVectorsFromFile(const std::string& filename) -{ - std::ifstream file(filename); - std::vector testVectors; - if (!file.is_open()) - { - std::cerr << "Error reading the file \"" << filename << "\" \n"; - return testVectors; - } - - std::string line; - std::getline(file, line); - if (line != "SVID,NumNavBits,NavBitsHEX\r") - { - std::cerr << "Error parsing first line" - << "\n"; - } - - while (std::getline(file, line)) - { - std::stringstream ss(line); - TestVector tv; - - std::string val; - - std::getline(ss, val, ','); - tv.svId = std::stoi(val); - - std::getline(ss, val, ','); - tv.numNavBits = std::stoi(val); - - std::getline(ss, val, ','); - tv.navBits = OsnmaMsgReceiverTest::parseNavBits(val); - - testVectors.push_back(tv); - } - - return testVectors; -} - - -std::vector OsnmaMsgReceiverTest::parseNavBits(const std::string& hex) -{ - std::vector bytes; - - for (unsigned int i = 0; i < hex.length() - 1; i += 2) - { - std::string byteString = hex.substr(i, 2); - uint8_t byte = (uint8_t)strtol(byteString.c_str(), NULL, 16); - bytes.push_back(byte); - } - return bytes; -} - - -std::string OsnmaMsgReceiverTest::bytes_to_str(const std::vector& bytes) -{ - std::string bit_string; - bit_string.reserve(bytes.size() * 8); - for (const auto& byte : bytes) - { - std::bitset<8> bits(byte); - bit_string += bits.to_string(); - } - return bit_string; -} - - -/** - * @brief Extracts a range of bytes from a TestVector's navBits vector. - * - * This function extracts a extracts the bytes of complete page (odd+even) - * from the navBits vector of a TestVector object. - * - * - * @param tv The TestVector object from which to extract bytes. - * @param byte_index The index of the first byte to extract. - * @param num_bytes The number of bytes to extract. - * @return A vector containing the extracted bytes, or an empty vector if extraction is not possible. - */ -std::vector OsnmaMsgReceiverTest::extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes) -{ - // Ensure we don't go beyond the end of tv.navBits - int num_bytes_to_extract = std::min(num_bytes, static_cast(tv.navBits.size() - byte_index)); - - // If byte_index is beyond the end of tv.navBits, return an empty vector - if (num_bytes_to_extract <= 0) - { - return std::vector(); - } - - // Use std::next to get an iterator to the range to extract - std::vector extracted_bytes(tv.navBits.begin() + byte_index, tv.navBits.begin() + byte_index + num_bytes_to_extract); - - return extracted_bytes; -} - - /** * @brief Sets the time based on the given input. * @@ -647,47 +302,3 @@ void OsnmaMsgReceiverTest::set_time(std::tm& input) // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); } - - -void OsnmaMsgReceiverTest::initializeGoogleLog() -{ - // google::InitGoogleLogging(log_name.c_str()); - FLAGS_minloglevel = 0; // INFO - FLAGS_logtostderr = 0; // add this line - // FLAGS_log_dir = "/home/cgm/CLionProjects/osnma/data/logs"; - if (FLAGS_log_dir.empty()) - { - std::cout << "Logging will be written at " - << std::filesystem::temp_directory_path() - << '\n' - << "Use gnss-sdr --log_dir=/path/to/log to change that.\n"; - } - else - { - try - { - const std::filesystem::path p(FLAGS_log_dir); - if (!std::filesystem::exists(p)) - { - std::cout << "The path " - << FLAGS_log_dir - << " does not exist, attempting to create it.\n"; - std::error_code ec; - if (!std::filesystem::create_directory(p, ec)) - { - std::cout << "Could not create the " << FLAGS_log_dir << " folder.\n"; - gflags::ShutDownCommandLineFlags(); - throw std::runtime_error("Could not create folder for logs"); - } - } - std::cout << "Logging will be written at " << FLAGS_log_dir << '\n'; - } - catch (const std::exception& e) - { - std::cerr << e.what() << '\n'; - std::cerr << "Could not create the " << FLAGS_log_dir << " folder.\n"; - gflags::ShutDownCommandLineFlags(); - throw; - } - } -} 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 new file mode 100644 index 000000000..edb8b401f --- /dev/null +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc @@ -0,0 +1,423 @@ +/*! + * \file osmna_test_vectors.cc + * \brief Tests for the osnma_msg_receiver class. + * \author Carles Fernandez, 2023-2024. cfernandez(at)cttc.es + * Cesare Ghionoiu Martinez, 2023-2024. c.ghionoiu-martinez@tu-braunschweig.de + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "gnss_crypto.h" +#include "osnma_helper.h" +#include "osnma_msg_receiver.h" +#include +#include +#include +#include +#include + +#if USE_GLOG_AND_GFLAGS +#include // for LOG +#else +#include +#endif + +struct TestVector +{ + int svId; + int numNavBits; + std::vector navBits; +}; + + +class OsnmaTestVectors : public ::testing::Test +{ +public: + static std::vector parseNavBits(const std::string& hex); + static std::vector readTestVectorsFromFile(const std::string& filename); + std::string bytes_to_str(const std::vector& bytes); + std::vector extract_page_bytes(const TestVector& tv, int byte_index, int num_bytes); + +protected: + Osnma_Helper helper; + osnma_msg_receiver_sptr osnma; + OSNMA_msg osnma_msg{}; + std::array nma_position_filled; + uint32_t d_GST_SIS{}; + uint32_t TOW{}; + uint32_t WN{}; + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm + const uint32_t LEAP_SECONDS = 0; // 13 + 5; + void set_time(std::tm& input); + + void SetUp() override + { + // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 + set_time(input_time); + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; + osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + } +}; + + +TEST_F(OsnmaTestVectors, OsnmaTestVectorsSimulation) +{ + // Arrange + std::vector testVectors = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/configuration_2/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 + if (testVectors.empty()) + { + ASSERT_TRUE(false); + } + + bool end_of_hex_stream{false}; + int offset_byte{0}; + int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size + const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page + const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe + const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds + + const int DUMMY_PAGE{63}; + bool flag_dummy_page{false}; + std::cout << "OsnmaTestVectorsSimulation:" + << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; + + // Act + // loop over all bytes of data. Note: all TestVectors have same amount of data. + while (end_of_hex_stream == false) + { + // loop over all SVs, extract a subframe + for (const TestVector& tv : testVectors) + { // loop over all SVs, extract a subframe + std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; + auto osnmaMsg_sptr = std::make_shared(); + std::array hkroot{}; + std::array mack{}; + byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) + std::map> words_for_OSNMA; // structure containing and + + for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe + { + // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index + std::vector page_bytes = extract_page_bytes(tv, byte_index, SIZE_PAGE_BYTES); + if (page_bytes.empty()) + { + std::cout << "OsnmaTestVectorsSimulation: end of TestVectors \n" + << "byte_index=" << byte_index << " expected= " << 432000 / 8 << std::endl; + end_of_hex_stream = true; + break; + } + // convert them to bitset representation using bytes_to_string + std::string page_bits = bytes_to_str(page_bytes); + // Extract the 40 OSNMA bits starting from the 18th bit + std::string even_page = page_bits.substr(0, page_bits.size() / 2); + std::string odd_page = page_bits.substr(page_bits.size() / 2); + if (even_page.size() < 120 || odd_page.size() < 120) + { + std::cout << "OsnmaTestVectorsSimulation: error parsing pages" << std::endl; + } + bool even_odd_OK = even_page[0] == '0' && odd_page[0] == '1'; + bool page_type_OK = even_page[1] == '0' && odd_page[1] == '0'; + bool tail_bits_OK = even_page.substr(even_page.size() - 6) == "000000" && odd_page.substr(odd_page.size() - 6) == "000000"; + if (!even_odd_OK || !page_type_OK || !tail_bits_OK) + std::cerr << "OsnmaTestVectorsSimulation: error parsing pages." << std::endl; + + std::bitset<112> data_k(even_page.substr(2, 112)); + std::bitset<16> data_j(odd_page.substr(2, 16)); + std::bitset<112> shifted_data_k = data_k; + uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word + std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast(word_type) << std::endl; + if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) + { + // store raw word + std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); + words_for_OSNMA[word_type] = data_combined; + } + if (word_type == DUMMY_PAGE) + flag_dummy_page = true; + + // place it into osnma object. + std::bitset<40> osnmaBits(odd_page.substr(18, 40)); + + // Extract bits for hkroot and mack + std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8)); + std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32)); + hkroot[idx] = static_cast(hkrootBits.to_ulong()); + mack[idx] = static_cast(mackBits.to_ulong()); + + byte_index += SIZE_PAGE_BYTES; + } + + std::cout << "----------" << std::endl; + if (end_of_hex_stream) + break; + if (flag_dummy_page) + { + flag_dummy_page = false; + continue; // skip this SV + } + + // Fill osnma object + osnmaMsg_sptr->hkroot = hkroot; + osnmaMsg_sptr->mack = mack; + + osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; + osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20; + osnmaMsg_sptr->PRN = tv.svId; // PRNa + + // TODO - refactor this logic, currently it is split + + // check if words_for_OSNMA 1--> 5 words_for_OSNMA are received => fill EphClockStatus data vector + bool ephClockStatusWordsReceived = true; + for (int i = 1; i <= 5; ++i) + { + if (words_for_OSNMA.find(i) == words_for_OSNMA.end()) + { + ephClockStatusWordsReceived = false; + std::cerr << "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " + "Word " + << i << " should be received for each subframe but was not." << std::endl; + } + } + // extract bits as needed by osnma block + if (ephClockStatusWordsReceived) + { + // Define the starting position and length of bits to extract for each word + std::map> extractionParams = { + {1, {6, 120}}, + {2, {6, 120}}, + {3, {6, 122}}, + {4, {6, 120}}, + {5, {6, 67}}, + }; + + // Fill NavData bits -- Iterate over the extraction parameters + std::string nav_data_ADKD_0_12 = ""; + for (const auto& param : extractionParams) + { + uint8_t wordKey = param.first; + uint8_t start = param.second.first; + uint8_t length = param.second.second; + + // Extract the required bits and fill osnma block + nav_data_ADKD_0_12 += words_for_OSNMA[wordKey].to_string().substr(start, length); + } + // send to osnma block + bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; + if (check_size_is_ok) + { + std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " + << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; + const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> + tv.svId, + nav_data_ADKD_0_12, + osnmaMsg_sptr->TOW_sf0); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12; + osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + } + } + + // check w6 && w10 is received => fill TimingData data vector + bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() && + words_for_OSNMA.find(10) != words_for_OSNMA.end(); + // extract bits as needed by osnma block + if (timingWordsReceived) + { + // Define the starting position and length of bits to extract for each word + std::map> extractionParams = { + {6, {6, 99}}, + {10, {86, 42}}}; + + std::string nav_data_ADKD_4 = ""; + // Fill NavData bits -- Iterate over the extraction parameters + for (const auto& param : extractionParams) + { + uint8_t wordKey = param.first; + uint8_t start = param.second.first; + uint8_t length = param.second.second; + + // Extract the required bits and fill osnma block + nav_data_ADKD_4 += words_for_OSNMA[wordKey].to_string().substr(start, length); + } + // send to osnma block + bool check_size_is_ok = nav_data_ADKD_4.size() == 141; + if (check_size_is_ok) + { + std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " + << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; + const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> + tv.svId, + nav_data_ADKD_4, + osnmaMsg_sptr->TOW_sf0); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4; + osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + } + } + + // Call the handler, as if it came from telemetry decoder block + auto temp_obj = pmt::make_any(osnmaMsg_sptr); + + osnma->msg_handler_osnma(temp_obj); // osnma entry point + } + + if (!end_of_hex_stream) + { + offset_byte = byte_index; // update offset for the next subframe + d_GST_SIS += DURATION_SUBFRAME; + TOW = d_GST_SIS & 0x000FFFFF; + WN = (d_GST_SIS & 0xFFF00000) >> 20; + std::cout << "OsnmaTestVectorsSimulation:" + << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; + } + } + // Assert + + // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) +} + + +// Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. +// Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. +std::vector OsnmaTestVectors::readTestVectorsFromFile(const std::string& filename) +{ + std::ifstream file(filename); + std::vector testVectors; + if (!file.is_open()) + { + std::cerr << "Error reading the file \"" << filename << "\" \n"; + return testVectors; + } + + std::string line; + std::getline(file, line); + if (line != "SVID,NumNavBits,NavBitsHEX\r") + { + std::cerr << "Error parsing first line" + << "\n"; + } + + while (std::getline(file, line)) + { + std::stringstream ss(line); + TestVector tv; + + std::string val; + + std::getline(ss, val, ','); + tv.svId = std::stoi(val); + + std::getline(ss, val, ','); + tv.numNavBits = std::stoi(val); + + std::getline(ss, val, ','); + tv.navBits = OsnmaTestVectors::parseNavBits(val); + + testVectors.push_back(tv); + } + + return testVectors; +} + + +std::vector OsnmaTestVectors::parseNavBits(const std::string& hexadecimal) +{ + std::vector bytes; + + for (unsigned int i = 0; i < hexadecimal.length() - 1; i += 2) + { + std::string byteString = hexadecimal.substr(i, 2); + uint8_t byte = static_cast(strtol(byteString.c_str(), nullptr, 16)); + bytes.push_back(byte); + } + return bytes; +} + + +std::string OsnmaTestVectors::bytes_to_str(const std::vector& bytes) +{ + std::string bit_string; + bit_string.reserve(bytes.size() * 8); + for (const auto& byte : bytes) + { + std::bitset<8> bits(byte); + bit_string += bits.to_string(); + } + return bit_string; +} + + +/** + * @brief Extracts a range of bytes from a TestVector's navBits vector. + * + * This function extracts a extracts the bytes of complete page (odd+even) + * from the navBits vector of a TestVector object. + * + * + * @param tv The TestVector object from which to extract bytes. + * @param byte_index The index of the first byte to extract. + * @param num_bytes The number of bytes to extract. + * @return A vector containing the extracted bytes, or an empty vector if extraction is not possible. + */ +std::vector OsnmaTestVectors::extract_page_bytes(const TestVector& tv, int byte_index, int num_bytes) +{ + // Ensure we don't go beyond the end of tv.navBits + int num_bytes_to_extract = std::min(num_bytes, static_cast(tv.navBits.size() - byte_index)); + + // If byte_index is beyond the end of tv.navBits, return an empty vector + if (num_bytes_to_extract <= 0) + { + return std::vector(); + } + + // Use std::next to get an iterator to the range to extract + std::vector extracted_bytes(tv.navBits.begin() + byte_index, tv.navBits.begin() + byte_index + num_bytes_to_extract); + + return extracted_bytes; +} + + +/** + * @brief Sets the time based on the given input. + * + * This function calculates the week number (WN) and time of week (TOW) + * based on the input time and the GST_START_EPOCH. It then stores the + * calculated values in the WN and TOW member variables. Finally, it + * combines the WN and TOW into a single 32-bit value and stores it in + * the d_GST_SIS member variable. + * + * @param input The input time as a tm struct. + */ +void OsnmaTestVectors::set_time(std::tm& input) +{ + auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH)); + auto input_time_point = std::chrono::system_clock::from_time_t(mktime(&input)); + + // Get the duration from epoch in seconds + auto duration_sec = std::chrono::duration_cast(input_time_point - epoch_time_point); + + // Calculate the week number (WN) and time of week (TOW) + uint32_t sec_in_week = 7 * 24 * 60 * 60; + uint32_t week_number = duration_sec.count() / sec_in_week; + uint32_t time_of_week = duration_sec.count() % sec_in_week; + this->WN = week_number; + this->TOW = time_of_week + LEAP_SECONDS; + // Return the week number and time of week as a pair + + // TODO: d_GST_SIS or d_receiver_time? doubt + // I am assuming that local realisation of receiver is identical to SIS GST time coming from W5 or W0 + this->d_GST_SIS = (this->WN & 0x00000FFF) << 20 | (this->TOW & 0x000FFFFF); +} From 6cfc8a351fd5042d4c3198d6cffd8d600c12cf2c Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 26 Jul 2024 18:20:24 +0200 Subject: [PATCH 184/219] Adapt to new API --- .../signal-processing-blocks/osnma/gnss_crypto_test.cc | 2 +- .../signal-processing-blocks/osnma/osnma_msg_receiver_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 2d7355fd7..4f9a75690 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 @@ -84,7 +84,7 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) ASSERT_TRUE(result); - auto d_crypto2 = std::make_unique(f1, ""); + auto d_crypto2 = std::make_unique(f1, "", ""); bool result2 = d_crypto2->store_public_key(f2); ASSERT_TRUE(result2); diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 05da06b9d..519f78a22 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -51,7 +51,7 @@ protected: // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 set_time(input_time); - osnma = osnma_msg_receiver_make("", ""); + osnma = osnma_msg_receiver_make("", "", ""); } }; From c54f941dce148ca78b09ab6f8d67bc241f19200c Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 26 Jul 2024 18:26:15 +0200 Subject: [PATCH 185/219] Adapt to new API --- .../signal-processing-blocks/osnma/osnma_test_vectors.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 edb8b401f..31da16907 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 @@ -66,7 +66,7 @@ protected: set_time(input_time); std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; - osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath, ""); } }; From 27f93e5626c17847aef45c13a83bd36bfff4b9cc Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 26 Jul 2024 20:02:15 +0200 Subject: [PATCH 186/219] Add OSNMA tests to the GitHub CI --- .github/workflows/main.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8323fdea8..91d1a3930 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,8 @@ jobs: - name: check run: cd build && ninja check && ../install/volk_gnsssdr_profile && ../install/run_tests - name: default position_test - run: cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON .. && ninja && ../install/position_test + run: cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. && \ + ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma* --log_dir=./ build-macos: runs-on: macos-latest @@ -66,7 +67,8 @@ jobs: - name: check run: cd build && ninja check && ../install/volk_gnsssdr_profile && ../install/run_tests - name: default position_test - run: cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON .. && ninja && ../install/position_test + run: cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. && \ + ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma* build-macos-xcode: runs-on: macos-latest @@ -104,9 +106,10 @@ jobs: - name: default position_test run: | cd build - cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON .. + cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. xcodebuild -configuration Release -target position_test ../install/position_test + ../install/run_tests --gtest_filter=Osnma* clang-format: runs-on: ubuntu-latest From 03a8366fa23bb6c5735337ff21478842d2a3c08e Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 26 Jul 2024 20:21:45 +0200 Subject: [PATCH 187/219] Add OSNMA tests to the GitHub CI --- .github/workflows/main.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 91d1a3930..e4bd9f38d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,8 +34,9 @@ jobs: - name: check run: cd build && ninja check && ../install/volk_gnsssdr_profile && ../install/run_tests - name: default position_test - run: cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. && \ - ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma* --log_dir=./ + run: | + cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. && \ + ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma* build-macos: runs-on: macos-latest @@ -67,8 +68,9 @@ jobs: - name: check run: cd build && ninja check && ../install/volk_gnsssdr_profile && ../install/run_tests - name: default position_test - run: cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. && \ - ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma* + run: | + cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. && \ + ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma* build-macos-xcode: runs-on: macos-latest From 491a4ab40fd55b49f49da026c26ecabd5f491d01 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 27 Jul 2024 07:48:34 +0200 Subject: [PATCH 188/219] Add missing include --- src/tests/benchmarks/benchmark_crypto.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/benchmarks/benchmark_crypto.cc b/src/tests/benchmarks/benchmark_crypto.cc index 43d5f1035..2adc95348 100644 --- a/src/tests/benchmarks/benchmark_crypto.cc +++ b/src/tests/benchmarks/benchmark_crypto.cc @@ -17,6 +17,7 @@ #include "gnss_crypto.h" #include +#include void bm_SHA_256(benchmark::State& state) { From a4cfe5151517442ea42f7cf1b1d1f549b014b7b4 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sat, 27 Jul 2024 18:25:20 +0200 Subject: [PATCH 189/219] [TAS-248] [BUG][Kroot] Kroot and PK available, but until DSM-Kroot arrived no MACK processing * reverted commit [TAS-247][FEAT][Kroot] enable hotstart with last known Kroot * DSM-KROOT loaded during startup * if new DSM verified => stored * this improves TTFAF from 4 min to 1 minute. --- src/core/libs/osnma_msg_receiver.cc | 96 +++++++++++++++---- src/core/libs/osnma_msg_receiver.h | 12 ++- src/core/receiver/gnss_flowgraph.cc | 3 +- src/core/system_parameters/Galileo_OSNMA.h | 8 +- src/core/system_parameters/gnss_crypto.cc | 71 +------------- src/core/system_parameters/gnss_crypto.h | 13 +-- .../osnma/osnma_msg_receiver_test.cc | 2 +- 7 files changed, 92 insertions(+), 113 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 27130600f..80613ca3d 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -24,7 +24,7 @@ #include "gnss_satellite.h" #include "osnma_dsm_reader.h" // for OSNMA_DSM_Reader #include "osnma_helper.h" -#include "osnma_nav_data_manager.h" // TODO - all these repeated includes, is it good practice to include them in the source file? +#include "osnma_nav_data_manager.h" #include // for gr::io_signature::make #include #include @@ -37,6 +37,7 @@ #include #include // for typeid #include +#include // for std::ifstream and std::ofstream #if USE_GLOG_AND_GFLAGS @@ -60,24 +61,36 @@ namespace wht = std; #endif -osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath) +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath) { - return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath, merkleFilePath, rootKeyFilePath)); + return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath, merkleFilePath)); } -osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath) : gr::block("osnma_msg_receiver", +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)) { d_dsm_reader = std::make_unique(); - d_crypto = std::make_unique(crtFilePath, merkleFilePath, rootKeyFilePath); + d_crypto = std::make_unique(crtFilePath, merkleFilePath); d_helper = std::make_unique(); d_nav_data_manager = std::make_unique(); - if(d_crypto->have_root_key()){ - d_kroot = d_crypto->get_root_key(); - d_kroot_verified = true; + if(d_crypto->have_public_key()){ // Hot start is enabled + auto dsm_nmah = parse_dsm_kroot(); + 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; + process_dsm_message(dsm_nmah.first, dsm_nmah.second); + LOG(WARNING) << "OSNMA DSM-KROOT available :: HOT START"; + std::cout << "OSNMA DSM-KROOT available :: HOT START" << std::endl; + } + else + { + LOG(WARNING) << "OSNMA DSM-KROOT not available :: WARM START"; + std::cout << "OSNMA DSM-KROOT not available :: WARM START" << std::endl; + } } // register OSNMA input message port from telemetry blocks @@ -369,7 +382,7 @@ void osnma_msg_receiver::process_dsm_block(const std::shared_ptr& osn } d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; - process_dsm_message(dsm_msg, osnma_msg); + process_dsm_message(dsm_msg, osnma_msg->hkroot[0]); } } @@ -381,10 +394,10 @@ void osnma_msg_receiver::process_dsm_block(const std::shared_ptr& osn * case DSM-PKR: * - calls verify_dsm_pkr to verify the public key * */ -void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg) +void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg, const uint8_t& nma_header) { // DSM-KROOT message - if (d_osnma_data.d_dsm_header.dsm_id < 12) + if (d_osnma_data.d_dsm_header.dsm_id < 12 || d_flag_hot_start) { // Parse Kroot message LOG(INFO) << "Galileo OSNMA: DSM-KROOT message received."; @@ -438,13 +451,13 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // validation of padding const uint16_t size_m = 13 + l_lk_bytes; std::vector MSG; - MSG.reserve(size_m + l_ds_bytes + 1); // C: message will get too many zeroes? ((12+1)+16) + 64 + 1? => in theory not, allocating is not assigning - MSG.push_back(osnma_msg->hkroot[0]); // C: NMA header + MSG.reserve(size_m + l_ds_bytes + 1); + MSG.push_back(nma_header); // NMA header for (uint16_t i = 1; i < size_m; i++) { MSG.push_back(dsm_msg[i]); } - std::vector message = MSG; // MSG = (M | DS) from ICD. Eq. 7 + std::vector 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]); @@ -478,7 +491,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; - local_time_verification(osnma_msg); + // local_time_verification(osnma_msg); // FIXME TODO: real time verification needed if (l_ds_bits == 512) { d_kroot_verified = d_crypto->verify_signature_ecdsa_p256(message, d_osnma_data.d_dsm_kroot_message.ds); @@ -494,10 +507,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg LOG(INFO) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks); - // Save Kroot into a permanent storage - d_crypto->store_root_key(ROOTKEYFILE_DEFAULT); - d_kroot = d_osnma_data.d_dsm_kroot_message.kroot; - d_crypto->set_root_key(d_kroot); + // Save DSM-Kroot and NMA header into a permanent storage + if(d_flag_hot_start){ + d_flag_hot_start = false; + return; + } + store_dsm_kroot(dsm_msg, nma_header); } else { @@ -576,7 +591,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { d_public_key_verified = true; d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk); - d_crypto->store_public_key(PEMFILE_STORED); + d_crypto->store_public_key(PEMFILE_DEFAULT); } } } @@ -1812,6 +1827,7 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ return verified_tags; } } + void osnma_msg_receiver::send_data_to_pvt(std::vector data) { if (!data.empty()) @@ -1823,3 +1839,43 @@ void osnma_msg_receiver::send_data_to_pvt(std::vector data) } } } + +bool osnma_msg_receiver::store_dsm_kroot(const std::vector& dsm, const uint8_t nma_header) const +{ + std::ofstream file(KROOTFILE_DEFAULT, std::ios::binary | std::ios::out); + + if (!file.is_open()) { + return false; + } + + // NMA header + file.write(reinterpret_cast(&nma_header), 1); + + // Then writing the entire dsm_msg vector to the file + file.write(reinterpret_cast(dsm.data()), dsm.size()); + + return file.good(); +} + +std::pair, uint8_t> osnma_msg_receiver::parse_dsm_kroot() const +{ + std::ifstream file(KROOTFILE_DEFAULT, std::ios::binary | std::ios::in); + if (!file) { + return {std::vector(), 0}; + } + + // Read the first byte into hkroot[0] + uint8_t nma_header; + file.read(reinterpret_cast(&nma_header), 1); + + // Read the remaining file content into dsm_msg + std::vector dsm_msg((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + + file.close(); + + if (file.bad()) { + return {std::vector(), 0}; + } + + return {dsm_msg, nma_header}; +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index cda571321..15abc632d 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -50,7 +50,7 @@ class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; -osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath); +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); /*! * \brief GNU Radio block that receives asynchronous OSNMA messages @@ -63,8 +63,8 @@ class osnma_msg_receiver : public gr::block public: ~osnma_msg_receiver() = default; //!< Default destructor private: - friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath); - osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath, const std::string& rootKeyFilePath); + friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); + osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath); void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); @@ -73,7 +73,7 @@ private: void read_dsm_block(const std::shared_ptr& osnma_msg); void local_time_verification(const std::shared_ptr& osnma_msg); void process_dsm_block(const std::shared_ptr& osnma_msg); - void process_dsm_message(const std::vector& dsm_msg, const std::shared_ptr& osnma_msg); + void process_dsm_message(const std::vector& dsm_msg, const uint8_t& nma_header); void read_and_process_mack_block(const std::shared_ptr& osnma_msg); void read_mack_header(); void read_mack_body(); @@ -89,7 +89,9 @@ private: bool tag_has_key_available(const Tag& t) const; bool verify_macseq(const MACK_message& mack); bool verify_dsm_pkr(const DSM_PKR_message& message) const; + bool store_dsm_kroot(const std::vector& dsm, const uint8_t nma_header) const; + std::pair, uint8_t> parse_dsm_kroot() const; std::vector get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const; std::vector compute_merkle_root(const DSM_PKR_message& dsm_pkr_message, const std::vector& m_i) const; std::vector build_message(Tag& tag) const; @@ -100,7 +102,6 @@ private: std::map> d_tesla_keys; // tesla keys over time, sorted by TOW std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW - std::vector d_kroot; // last available stored root key std::vector d_tags_to_verify{0, 4, 12}; std::vector d_macks_awaiting_MACSEQ_verification; @@ -143,6 +144,7 @@ private: bool d_kroot_verified{false}; bool d_tesla_key_verified{false}; bool d_flag_debug{false}; + bool d_flag_hot_start{false}; // Provide access to inner functions to Gtest FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 035d690dc..af1795ee0 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -126,8 +126,7 @@ void GNSSFlowgraph::init() enable_osnma_rx_ = true; const auto certFilePath = configuration_->property("GNSS-SDR.osnma_public_key", CRTFILE_DEFAULT); const auto merKleTreePath = configuration_->property("GNSS-SDR.osnma_merkletree", MERKLEFILE_DEFAULT); - const auto rootKeyPath = configuration_->property("GNSS-SDR.osnma_root_key", ROOTKEYFILE_DEFAULT); - osnma_rx_ = osnma_msg_receiver_make(certFilePath, merKleTreePath, rootKeyPath); + osnma_rx_ = osnma_msg_receiver_make(certFilePath, merKleTreePath); } else { diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 08a14c93e..94274cc36 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -160,10 +160,10 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("SHA-256"), 512}, {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} -const std::string PEMFILE_STORED("./OSNMA_PublicKey.pem"); -const std::string CRTFILE_DEFAULT("../data/OSNMA_PublicKey_20240115100000_newPKID_1.crt"); -const std::string MERKLEFILE_DEFAULT("../data/OSNMA_MerkleTree_20240115100000_newPKID_1.xml"); -const std::string ROOTKEYFILE_DEFAULT("../data/OSNMA_RootKey.bin"); +const std::string PEMFILE_DEFAULT("./data/OSNMA_PublicKey.pem"); +const std::string CRTFILE_DEFAULT("./data/OSNMA_PublicKey_20240115100000_newPKID_1.crt"); +const std::string MERKLEFILE_DEFAULT("./data/OSNMA_MerkleTree_20240115100000_newPKID_1.xml"); +const std::string KROOTFILE_DEFAULT("./data/OSNMA_DSM_KROOT_NMAHeader.bin"); class Mack_lookup { diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index e31a76acc..2a819c60c 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -75,7 +75,7 @@ Gnss_Crypto::Gnss_Crypto() } -Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath, const std::string& rootKeyFilePath) +Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath) { #if USE_GNUTLS_FALLBACK gnutls_global_init(); @@ -96,11 +96,10 @@ Gnss_Crypto::Gnss_Crypto(const std::string& certFilePath, const std::string& mer readPublicKeyFromPEM(certFilePath); if (!have_public_key()) { - readPublicKeyFromPEM(PEMFILE_STORED); + readPublicKeyFromPEM(PEMFILE_DEFAULT); } } read_merkle_xml(merkleTreePath); - read_root_key(rootKeyFilePath); } @@ -123,10 +122,6 @@ Gnss_Crypto::~Gnss_Crypto() #endif } -bool Gnss_Crypto::have_root_key() const -{ - return !d_kroot.empty(); -} bool Gnss_Crypto::have_public_key() const { #if USE_GNUTLS_FALLBACK @@ -200,23 +195,6 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const return true; } -bool Gnss_Crypto::store_root_key(const std::string& rootKeyFilePath) const -{ - if (!have_root_key()) - { - return false; - } - std::ofstream file(rootKeyFilePath, std::ios::binary | std::ios::out); - - if (!file) { - return false; - } - - file.write(reinterpret_cast(d_kroot.data()), d_kroot.size()); - - return file.good(); -} - bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& message, const std::vector& signature) const { std::vector digest = this->compute_SHA_256(message); @@ -865,11 +843,6 @@ std::vector Gnss_Crypto::get_merkle_root() const return d_x_4_0; } -std::vector Gnss_Crypto::get_root_key() const -{ - return d_kroot; -} - void Gnss_Crypto::set_public_key(const std::vector& publicKey) { #if USE_GNUTLS_FALLBACK @@ -928,11 +901,6 @@ void Gnss_Crypto::set_merkle_root(const std::vector& v) d_x_4_0 = v; } -void Gnss_Crypto::set_root_key(const std::vector& root_key) -{ - d_kroot = root_key; -} - void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) { pugi::xml_document doc; @@ -1172,41 +1140,6 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) return true; } -/** - * \brief Reads the TESLA root key from a file and stores it. - * \param rootKeyFilePath The file path of the TESLA root key. - * \return True if the root key was successfully read and stored, false otherwise. - */ -bool Gnss_Crypto::read_root_key(const std::string& rootKeyFilePath) -{ - std::ifstream file(rootKeyFilePath, std::ios::binary | std::ios::in); - - if (!file) { - LOG(WARNING) << "Unable to open file: " << rootKeyFilePath; - return false; - } - - // Determine file size - file.seekg(0, std::ios::end); - std::streamsize size = file.tellg(); - file.seekg(0, std::ios::beg); - - if (size == 0) { - LOG(WARNING) << "File is empty: " << rootKeyFilePath; - return false; - } - - // Resize the vector and read file - d_kroot.resize(size); - if (!file.read(reinterpret_cast(d_kroot.data()), size)) { - LOG(WARNING) << "Failed to read the file: " << rootKeyFilePath; - return false; - } - std::cout << "OSNMA TESLA Root Key successfully read from file " << rootKeyFilePath << std::endl; - LOG(INFO) << "OSNMA TESLA Root Key successfully read from file " << rootKeyFilePath; - return true; -} - bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const { if (raw_signature.size() % 2 != 0) diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 6ff60650c..a331c78d0 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -48,22 +48,15 @@ public: * and a XML file for the Merkle Tree root. * Files can be downloaded by registering at https://www.gsc-europa.eu/ */ - Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath, const std::string& rootKeyFilePath); + Gnss_Crypto(const std::string& certFilePath, const std::string& merkleTreePath); ~Gnss_Crypto(); //!< Default destructor - bool have_root_key() const; //!< Returns true if the TESLA root key is already loaded bool have_public_key() const; //!< Returns true if the ECDSA Public Key is already loaded /*! * Stores the ECDSA Public Key in a .pem file, which is read in a following run if the .crt file is not found */ bool store_public_key(const std::string& pubKeyFilePath) const; - /*! - * Stores the TESLA root key in a plaintext file, which is read in a following run for a faster TTFAF. - * @param kroot TESLA root key - * @return true if successful - */ - bool store_root_key(const std::string& rootKeyFilePath) const; bool verify_signature_ecdsa_p256(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P256 signature (message in plain hex, signature in raw format) bool verify_signature_ecdsa_p521(const std::vector& message, const std::vector& signature) const; //!< Verify ECDSA-P521 signature (message in plain hex, signature in raw format) @@ -75,15 +68,12 @@ public: std::vector get_public_key() const; //!< Gets the ECDSA Public Key in PEM format std::vector get_merkle_root() const; //!< Gets the Merkle Tree root node (\f$ x_{4,0} \f$) - std::vector get_root_key() const; //!< Gets the TESLA root key in binary format void set_public_key(const std::vector& publickey); //!< Sets the ECDSA Public Key (publickey in PEM format) void set_merkle_root(const std::vector& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$) - void set_root_key(const std::vector& root_key); //!< Sets the TESLA root key private: void read_merkle_xml(const std::string& merkleFilePath); void readPublicKeyFromPEM(const std::string& pemFilePath); - bool read_root_key(const std::string& rootKeyFilePath); bool readPublicKeyFromCRT(const std::string& crtFilePath); bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; std::vector convert_from_hex_str(const std::string& input) const; @@ -100,7 +90,6 @@ private: #endif #endif std::vector d_x_4_0; - std::vector d_kroot; }; /** \} */ diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 519f78a22..a9d6e60c5 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -51,7 +51,7 @@ protected: // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 set_time(input_time); - osnma = osnma_msg_receiver_make("", "", ""); + osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT); } }; From a947f10fd826aa0dd86b0c994a72b8dbaafc08c3 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sat, 27 Jul 2024 19:14:13 +0200 Subject: [PATCH 190/219] [TAS-246] [TEST] CI/CD set up - more fixes --- src/core/libs/osnma_msg_receiver.h | 1 + .../signal-processing-blocks/osnma/gnss_crypto_test.cc | 2 +- .../osnma/osnma_msg_receiver_test.cc | 8 +++----- .../signal-processing-blocks/osnma/osnma_test_vectors.cc | 8 ++++---- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 15abc632d..78f949ab4 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -37,6 +37,7 @@ #include // for std::shared_ptr #include // for std::string #include // for std::vector +#include // for std::pair /** \addtogroup Core * \{ */ 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 4f9a75690..2d7355fd7 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 @@ -84,7 +84,7 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) ASSERT_TRUE(result); - auto d_crypto2 = std::make_unique(f1, "", ""); + auto d_crypto2 = std::make_unique(f1, ""); bool result2 = d_crypto2->store_public_key(f2); ASSERT_TRUE(result2); diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index a9d6e60c5..70e060cf9 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -42,14 +42,14 @@ protected: uint32_t d_GST_SIS{}; uint32_t TOW{}; uint32_t WN{}; - std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; // months start with 0 and years since 1900 in std::tm const uint32_t LEAP_SECONDS = 0; // 13 + 5; void set_time(std::tm& input); void SetUp() override { - // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 - std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 + // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 1 + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 2 set_time(input_time); osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT); } @@ -218,8 +218,6 @@ TEST_F(OsnmaMsgReceiverTest, TagVerification) // Assert // Tag3 - uint32_t TOW_Tag3 = 345660; - uint32_t TOW_NavData_Tag3 = TOW_Tag3 - 30; uint32_t TOW_Key_Tag3 = TOW_Tag0 + 30; WN = 1248; PRNa = 2; 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 31da16907..3f711f7d8 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 @@ -55,18 +55,18 @@ protected: uint32_t d_GST_SIS{}; uint32_t TOW{}; uint32_t WN{}; - std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0}; // months start with 0 and years since 1900 in std::tm + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; // months start with 0 and years since 1900 in std::tm const uint32_t LEAP_SECONDS = 0; // 13 + 5; void set_time(std::tm& input); void SetUp() override { - // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0}; // conf. 1 - std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0}; // conf. 2 + // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 1 + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 2 set_time(input_time); std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; - osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath, ""); + osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); } }; From 5675b996e8490d0e4d63d705141f7349a4896135 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 29 Jul 2024 12:16:55 +0200 Subject: [PATCH 191/219] [TAS-251] set_public_key accepts compressed ECDSA PK. Make Crypto tests pass again (OSSL3 and OSSL<3) * both P256 and P521 curves. Tested successfully. --- src/core/system_parameters/gnss_crypto.cc | 115 +++++++++++---- src/core/system_parameters/gnss_crypto.h | 4 +- .../osnma/gnss_crypto_test.cc | 132 ++++++------------ 3 files changed, 132 insertions(+), 119 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 2a819c60c..86f1525f2 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -131,7 +132,6 @@ bool Gnss_Crypto::have_public_key() const #endif } - bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const { if (!have_public_key()) @@ -780,7 +780,7 @@ std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k return output; } - +// TODO - deprecate: change return type to respective key type, PEM is not needed. std::vector Gnss_Crypto::get_public_key() const { if (!have_public_key()) @@ -846,10 +846,25 @@ std::vector Gnss_Crypto::get_merkle_root() const void Gnss_Crypto::set_public_key(const std::vector& publicKey) { #if USE_GNUTLS_FALLBACK + // TODO - changed to import a compressed ECC key, either P256 or P521, but have not tested it yet gnutls_pubkey_t pubkey{}; - gnutls_datum_t pemDatum = {const_cast(publicKey.data()), static_cast(publicKey.size())}; + gnutls_datum_t x_coord = {(unsigned char*)&publicKey[1], 32}; + gnutls_datum_t y_coord = {NULL, 0}; + gnutls_ecc_curve_t curve; + gnutls_pubkey_init(&pubkey); - int ret = gnutls_pubkey_import(pubkey, &pemDatum, GNUTLS_X509_FMT_PEM); + + if (publicKey.size() == 33) + { + curve = GNUTLS_ECC_CURVE_SECP256R1; + } + else + { + curve = GNUTLS_ECC_CURVE_SECP521R1; + } + + + int ret = gnutls_pubkey_import_ecc_raw(pubkey, curve, &x_coord, &y_coord); if (ret != GNUTLS_E_SUCCESS) { gnutls_pubkey_deinit(pubkey); @@ -861,37 +876,88 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) pubkey_copy(pubkey, &d_PublicKey); gnutls_pubkey_deinit(pubkey); #else // OpenSSL - BIO* bio = nullptr; - EVP_PKEY* pkey = nullptr; - bio = BIO_new_mem_buf(const_cast(publicKey.data()), publicKey.size()); - if (!bio) - { - LOG(WARNING) << "OpenSSL: Failed to create BIO for key."; - return; - } - pkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr); - BIO_free(bio); - - if (!pkey) - { - LOG(WARNING) << "OpenSSL: error setting the OSNMA public key."; - return; - } #if USE_OPENSSL_3 - if (!pubkey_copy(pkey, &d_PublicKey)) +// Uses the new EVP_PKEY envelope as well as the parameter builder functions +// generate the uncompressed key, then add it into the EVP_PKEY* struct +EVP_PKEY* pkey = NULL; +EVP_PKEY_CTX* ctx = NULL; +OSSL_PARAM_BLD *param_bld; +OSSL_PARAM *params = NULL; + +param_bld = OSSL_PARAM_BLD_new(); +if (param_bld != NULL + && 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); + +ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); +if (ctx == NULL + || params == NULL + || EVP_PKEY_fromdata_init(ctx) <= 0 + || EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) { + return; + } else { + if (!pubkey_copy(pkey, &d_PublicKey)) + { + return; + } + } +EVP_PKEY_free(pkey); +EVP_PKEY_CTX_free(ctx); +OSSL_PARAM_free(params); +OSSL_PARAM_BLD_free(param_bld); +#else + EVP_PKEY* pkey = NULL; // Generic public key type + EC_KEY* ec_key = NULL; // ECC Key pair + EC_POINT* point = NULL; // Represents the point in the EC the public key belongs to + EC_GROUP* group = NULL; // Defines the curve the public key belongs + if (publicKey.size() == 33) // ECDSA-P-256 { + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + } + else // ECDSA-P-521 + { + group = EC_GROUP_new_by_curve_name(NID_secp521r1); + } + if(!group){ + return; + } + + point = EC_POINT_new(group); + if(!point){ + return; + } + + if(!EC_POINT_oct2point(group, point, publicKey.data(), publicKey.size(), NULL)){ + return; + } + + if (publicKey.size() == 33) // ECDSA-P-256 + { + ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + } + else // ECDSA-P-521 + { + ec_key = EC_KEY_new_by_curve_name(NID_secp521r1); + } + if(!ec_key){ + return; + } + + if(!EC_KEY_set_public_key(ec_key, point)){ return; } -#else - EC_KEY* ec_pkey = EVP_PKEY_get1_EC_KEY(pkey); if (!pubkey_copy(ec_pkey, &d_PublicKey)) { return; } EC_KEY_free(ec_pkey); + EC_POINT_free(point); + EC_GROUP_free(group); #endif // OpenSSL 1.x - EVP_PKEY_free(pkey); #endif DLOG(INFO) << "OSNMA Public Key successfully set up."; } @@ -1208,7 +1274,6 @@ std::vector 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) { diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index a331c78d0..85993d063 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -69,10 +69,10 @@ public: std::vector get_public_key() const; //!< Gets the ECDSA Public Key in PEM format std::vector get_merkle_root() const; //!< Gets the Merkle Tree root node (\f$ x_{4,0} \f$) - void set_public_key(const std::vector& publickey); //!< Sets the ECDSA Public Key (publickey in PEM format) + void set_public_key(const std::vector& publickey); //!< Sets the ECDSA Public Key (publickey compressed format) void set_merkle_root(const std::vector& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$) -private: void read_merkle_xml(const std::string& merkleFilePath); +private: void readPublicKeyFromPEM(const std::string& pemFilePath); bool readPublicKeyFromCRT(const std::string& crtFilePath); bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; 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 2d7355fd7..a6429bc7b 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 @@ -31,23 +31,13 @@ class GnssCryptoTest : public ::testing::Test TEST(GnssCryptoTest, VerifyPubKeyImport) { auto d_crypto = std::make_unique(); - - // PEM format + // Input taken from RG 1.3 A7.1 + // compressed ECDSA P-256 format std::vector 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, 0x53, 0x76, - 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, - 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, 0x73, 0x66, 0x78, 0x2F, - 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, - 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, 0x48, - 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, - 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, - 0x69, 0x79, 0x44, 0x79, 0x48, 0x58, 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}; + 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()); d_crypto->set_public_key(publicKey); @@ -62,22 +52,11 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) const std::string f1("./osnma_test_file1.pem"); const std::string f2("./osnma_test_file2.pem"); - // PEM format + // Input taken from RG 1.3 A7.1 + // compressed ECDSA P-256 format std::vector 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, 0x53, 0x76, - 0x50, 0x75, 0x4F, 0x70, 0x51, 0x6C, 0x4A, 0x54, 0x31, 0x56, 0x77, 0x6C, 0x72, - 0x43, 0x4C, 0x63, 0x38, 0x55, 0x54, 0x54, 0x6B, 0x4E, 0x73, 0x66, 0x78, 0x2F, - 0x0A, 0x4D, 0x56, 0x6F, 0x71, 0x47, 0x61, 0x35, 0x4F, 0x31, 0x73, 0x75, 0x6D, - 0x57, 0x64, 0x61, 0x5A, 0x66, 0x4F, 0x69, 0x39, 0x48, 0x30, 0x4D, 0x30, 0x48, - 0x46, 0x6E, 0x5A, 0x32, 0x63, 0x72, 0x44, 0x37, 0x6C, 0x6A, 0x6C, 0x36, 0x74, - 0x4E, 0x56, 0x52, 0x4F, 0x71, 0x4A, 0x63, 0x57, 0x58, 0x51, 0x6B, 0x6E, 0x4B, - 0x69, 0x79, 0x44, 0x79, 0x48, 0x58, 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}; + 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); @@ -96,8 +75,9 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) ASSERT_EQ(content_file, content_file2); - std::vector readkey = d_crypto2->get_public_key(); - ASSERT_EQ(publicKey, readkey); + // TODO - this cannot be tested right now + // std::vector readkey = d_crypto2->get_public_key(); + // ASSERT_EQ(publicKey, readkey); errorlib::error_code ec; ASSERT_TRUE(fs::remove(fs::path(f1), ec)); @@ -271,26 +251,11 @@ TEST(GnssCryptoTest, VerifySignatureP256) 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; - // PEM format + // Input taken from RG 1.3 A7.1 + // compressed ECDSA P-256 format std::vector 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}; + 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); @@ -309,51 +274,34 @@ TEST(GnssCryptoTest, VerifySignatureP521) // Message to be verified std::vector message = { - 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 // "Hello World" - }; + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // "Hello world\n" - // Public key in PEM format + // Public key in compressed X format std::vector 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, 0x49, 0x47, 0x62, 0x4D, 0x42, 0x41, 0x47, 0x42, - 0x79, 0x71, 0x47, 0x53, 0x4D, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, - 0x53, 0x75, 0x42, 0x42, 0x41, 0x41, 0x6A, 0x41, 0x34, 0x47, 0x47, 0x41, - 0x41, 0x51, 0x41, 0x6F, 0x35, 0x76, 0x77, 0x66, 0x6E, 0x47, 0x57, 0x47, - 0x33, 0x44, 0x63, 0x59, 0x75, 0x2B, 0x2F, 0x61, 0x58, 0x47, 0x32, 0x7A, - 0x74, 0x65, 0x41, 0x46, 0x50, 0x54, 0x33, 0x0A, 0x48, 0x36, 0x4C, 0x76, - 0x4F, 0x4C, 0x76, 0x49, 0x51, 0x6A, 0x61, 0x2B, 0x6A, 0x74, 0x57, 0x73, - 0x70, 0x4F, 0x38, 0x37, 0x6F, 0x50, 0x32, 0x4E, 0x6D, 0x72, 0x34, 0x6E, - 0x50, 0x68, 0x76, 0x62, 0x53, 0x58, 0x52, 0x4D, 0x37, 0x6A, 0x49, 0x69, - 0x46, 0x38, 0x47, 0x70, 0x6B, 0x75, 0x58, 0x6A, 0x75, 0x4E, 0x7A, 0x34, - 0x72, 0x61, 0x56, 0x4F, 0x65, 0x49, 0x4D, 0x42, 0x77, 0x45, 0x2B, 0x61, - 0x0A, 0x30, 0x4C, 0x76, 0x7A, 0x37, 0x69, 0x54, 0x4D, 0x5A, 0x46, 0x41, - 0x41, 0x51, 0x64, 0x2B, 0x70, 0x47, 0x72, 0x56, 0x54, 0x47, 0x77, 0x66, - 0x53, 0x48, 0x49, 0x72, 0x49, 0x49, 0x45, 0x78, 0x74, 0x5A, 0x35, 0x77, - 0x30, 0x38, 0x51, 0x4F, 0x43, 0x58, 0x2F, 0x75, 0x46, 0x65, 0x2B, 0x30, - 0x78, 0x52, 0x78, 0x4C, 0x64, 0x2F, 0x33, 0x36, 0x42, 0x4E, 0x74, 0x63, - 0x74, 0x69, 0x2F, 0x45, 0x4C, 0x0A, 0x4B, 0x31, 0x35, 0x67, 0x2B, 0x4B, - 0x32, 0x71, 0x67, 0x2F, 0x6C, 0x39, 0x46, 0x42, 0x47, 0x67, 0x4D, 0x2B, - 0x51, 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}; + 0x03, 0x00, 0x28, 0x35, 0xBB, 0xE9, 0x24, 0x59, 0x4E, 0xF0, + 0xE3, 0xA2, 0xDB, 0xC0, 0x49, 0x30, 0x60, 0x7C, 0x61, 0x90, + 0xE4, 0x03, 0xE0, 0xC7, 0xB8, 0xC2, 0x62, 0x37, 0xF7, 0x58, + 0x56, 0xBE, 0x63, 0x5C, 0x97, 0xF7, 0x53, 0x64, 0x7E, 0xE1, + 0x0C, 0x07, 0xD3, 0x97, 0x8D, 0x58, 0x46, 0xFD, 0x6E, 0x06, + 0x44, 0x01, 0xA7, 0xAA, 0xC4, 0x95, 0x13, 0x5D, 0xC9, 0x77, + 0x26, 0xE9, 0xF8, 0x72, 0x0C, 0xD3, 0x88 }; // ECDSA P-521 signature, raw format std::vector signature = { - 0x01, 0x7B, 0x59, 0xAC, 0x3A, 0x03, 0x5C, 0xB4, 0x07, 0xCD, - 0xC1, 0xEB, 0xBE, 0xE5, 0xA6, 0xCB, 0xDA, 0x0A, 0xFF, 0x4D, - 0x38, 0x61, 0x16, 0x0F, 0xB3, 0x77, 0xE5, 0x8A, 0xDC, 0xF3, - 0xFD, 0x79, 0x38, 0x1E, 0xE8, 0x08, 0x3D, 0x5D, 0xBC, 0xC2, - 0x80, 0x6E, 0xE9, 0x2B, 0xC3, 0xEF, 0x07, 0x3D, 0x0C, 0x82, - 0x4C, 0x9B, 0x7A, 0x5C, 0x2E, 0xD5, 0x46, 0xBD, 0x22, 0x21, - 0x13, 0x8A, 0xB2, 0xCA, 0x96, 0x3D, 0x01, 0xBA, 0x2A, 0xC4, - 0x3F, 0xDB, 0x66, 0x3C, 0x40, 0x26, 0xD9, 0xBC, 0x26, 0xD5, - 0x57, 0xD4, 0xBD, 0x15, 0x16, 0x88, 0x21, 0x3B, 0xAA, 0x07, - 0x89, 0xEF, 0x29, 0x8F, 0x2F, 0x85, 0x76, 0x58, 0x9D, 0xCA, - 0x00, 0xCC, 0xC8, 0x30, 0x88, 0x31, 0x99, 0xC1, 0x94, 0xB9, - 0xAF, 0x91, 0xDC, 0xC4, 0x6F, 0x19, 0x2B, 0x12, 0xA2, 0x82, - 0xA5, 0x66, 0x5E, 0x4B, 0xBB, 0xDF, 0x65, 0x81, 0x52, 0x14, - 0x01, 0xD7}; + 0x01, 0x5C, 0x23, 0xC0, 0xBE, 0xAD, 0x1E, 0x44, 0x60, 0xD4, + 0xE0, 0x81, 0x38, 0xF2, 0xBA, 0xF5, 0xB5, 0x37, 0x5A, 0x34, + 0xB5, 0xCA, 0x6B, 0xC8, 0x0F, 0xCD, 0x75, 0x1D, 0x5E, 0xC0, + 0x8A, 0xD3, 0xD7, 0x79, 0xA7, 0xC1, 0xB8, 0xA2, 0xC6, 0xEA, + 0x5A, 0x7D, 0x60, 0x66, 0x50, 0x97, 0x37, 0x6C, 0xF9, 0x0A, + 0xF6, 0x3D, 0x77, 0x9A, 0xE2, 0x19, 0xF7, 0xF9, 0xDD, 0x52, + 0xC4, 0x0F, 0x98, 0xAA, 0xA2, 0xA4, 0x01, 0xC9, 0x41, 0x0B, + 0xD0, 0x25, 0xDD, 0xC9, 0x7C, 0x3F, 0x70, 0x32, 0x23, 0xCF, + 0xFE, 0x37, 0x67, 0x3A, 0xBC, 0x0B, 0x76, 0x16, 0x82, 0x83, + 0x27, 0x3D, 0x1D, 0x19, 0x15, 0x78, 0x08, 0x2B, 0xD4, 0xA7, + 0xC2, 0x0F, 0x11, 0xF4, 0xDD, 0xE5, 0x5A, 0x5D, 0x04, 0x8D, + 0x6D, 0x5E, 0xC4, 0x1F, 0x54, 0x44, 0xA9, 0x13, 0x34, 0x71, + 0x0F, 0xF7, 0x57, 0x9A, 0x9F, 0x2E, 0xF4, 0x97, 0x7D, 0xAE, + 0x28, 0xEF}; d_crypto->set_public_key(publicKey); bool result = d_crypto->verify_signature_ecdsa_p521(message, signature); From fc1541ef10302350066fc259c1d37678709669ef Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 29 Jul 2024 12:18:08 +0200 Subject: [PATCH 192/219] [TAS-250] [FEAT] Implement PK renewal and revocation. --- src/core/libs/osnma_msg_receiver.cc | 44 ++- src/core/libs/osnma_msg_receiver.h | 7 + src/core/system_parameters/Galileo_OSNMA.h | 8 +- .../system_parameters/galileo_inav_message.h | 2 +- .../system_parameters/osnma_dsm_reader.cc | 2 +- src/core/system_parameters/osnma_dsm_reader.h | 2 +- .../osnma/osnma_msg_receiver_test.cc | 8 +- .../osnma/osnma_test_vectors.cc | 266 +++++++++++++++++- 8 files changed, 306 insertions(+), 33 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 80613ca3d..d9602a62e 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -156,7 +156,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) } // Send the resulting decoded NMA data (if available) to PVT - if (d_new_data == true) // TODO where is it set to true? + if (d_new_data) // TODO where is it set to true? { auto osnma_data_ptr = std::make_shared(d_osnma_data); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); @@ -170,11 +170,22 @@ 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) { read_nma_header(osnma_msg->hkroot[0]); - if (d_osnma_data.d_nma_header.nmas == 0 || d_osnma_data.d_nma_header.nmas == 3 /*&& d_kroot_verified*/) + if (d_osnma_data.d_nma_header.nmas == 0 || d_osnma_data.d_nma_header.nmas == 3) { LOG(WARNING) << "Galileo OSNMA: NMAS invalid, skipping osnma message"; return; } + if (d_osnma_data.d_nma_header.nmas == 2 /*OP*/ && d_osnma_data.d_nma_header.cpks == 4 /*NPK*/ && d_GST_PKR_start == 0){ + d_flag_PK_renewal = true; + d_GST_PKR_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); + LOG(INFO) << "Galileo OSNMA: Public Key Renewal :: Start at GST=" << d_GST_PKR_start; + std::cout << "Galileo OSNMA: Public Key Renewal :: Start at GST=" << d_GST_PKR_start << 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*/ ){ + d_flag_PK_renewal = false; + LOG(INFO) << "Galileo OSNMA: Public Key Renewal :: Finished at GST=" << d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); + std::cout << "Galileo OSNMA: Public Key Renewal :: Finished at GST=" << d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0) << std::endl; + } 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 @@ -337,7 +348,7 @@ void osnma_msg_receiver::local_time_verification(const std::shared_ptr d_T_L && delta_T <= 10 * delta_T) + else if (delta_T > d_T_L && delta_T <= 10 * d_T_L) { d_tags_allowed = tags_to_verify::slow_eph; d_tags_to_verify = {12}; @@ -492,6 +503,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; // local_time_verification(osnma_msg); // FIXME TODO: real time verification needed + if(d_flag_PK_renewal && d_osnma_data.d_dsm_kroot_message.pkid == d_new_public_key_id && d_flag_NPK_set == false){ + // set new public key to be used. + d_crypto->set_public_key(d_new_public_key); + d_crypto->store_public_key(PEMFILE_DEFAULT); + d_flag_NPK_set = true; + } if (l_ds_bits == 512) { d_kroot_verified = d_crypto->verify_signature_ecdsa_p256(message, d_osnma_data.d_dsm_kroot_message.ds); @@ -538,7 +555,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_pkr_message.itn[k] = dsm_msg[k + 1]; } d_osnma_data.d_dsm_pkr_message.npkt = d_dsm_reader->get_npkt(dsm_msg); - d_osnma_data.d_dsm_pkr_message.npktid = d_dsm_reader->get_npktid(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){ + d_new_public_key_id = npktid; + } + d_osnma_data.d_dsm_pkr_message.npktid = npktid; uint32_t l_npk_bytes = 0; const auto it = OSNMA_TABLE_5.find(d_osnma_data.d_dsm_pkr_message.npkt); @@ -584,12 +605,15 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600*/ << " received"; // C: NPK verification against Merkle tree root. - if (!d_public_key_verified) + bool verification = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message); + if (verification) { - bool verification = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message); - if (verification) - { - d_public_key_verified = true; + LOG(INFO) << "Galileo OSNMA: DSM-PKR verified successfully"; + d_public_key_verified = true; + if (d_flag_PK_renewal){ + d_new_public_key = d_osnma_data.d_dsm_pkr_message.npk; + } + else { d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk); d_crypto->store_public_key(PEMFILE_DEFAULT); } @@ -903,7 +927,7 @@ void osnma_msg_receiver::read_mack_body() */ void osnma_msg_receiver::process_mack_message() { - if (d_kroot_verified == false && d_tesla_key_verified == false) + if (!d_kroot_verified && !d_tesla_key_verified) { LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed, " << "no Kroot nor TESLA key available."; diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 78f949ab4..9afab20d1 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -133,6 +133,7 @@ private: uint32_t d_last_verified_key_GST{0}; uint32_t d_GST_0{}; uint32_t d_GST_SIS{}; + uint32_t d_GST_PKR_start{}; uint8_t d_Lt_min{}; // minimum equivalent tag length uint8_t d_Lt_verified_eph{0}; // verified tag bits - ephemeris @@ -146,6 +147,11 @@ private: bool d_tesla_key_verified{false}; bool d_flag_debug{false}; bool d_flag_hot_start{false}; + bool d_flag_PK_renewal{false}; + bool d_flag_PK_revocation{false}; + uint8_t d_new_public_key_id{}; + std::vector d_new_public_key; + bool d_flag_NPK_set{false}; // Provide access to inner functions to Gtest FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); @@ -155,6 +161,7 @@ private: FRIEND_TEST(OsnmaMsgReceiverTest, ComputeBaseLeaf); FRIEND_TEST(OsnmaMsgReceiverTest, ComputeMerkleRoot); FRIEND_TEST(OsnmaTestVectors, OsnmaTestVectorsSimulation); + FRIEND_TEST(OsnmaTestVectors, PublicKeyRenewal); }; diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 94274cc36..bdfc76a11 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -32,7 +32,7 @@ constexpr size_t SIZE_DSM_BLOCKS_BYTES = 13; -// OSNMA User ICD for the Test Phase, Issue 1.0, Table 1 +// OSNMA User ICD, Issue 1.1, Table 1 const std::unordered_map OSNMA_TABLE_1 = { {0, std::string("Reserved")}, {1, std::string("Test")}, @@ -40,14 +40,14 @@ const std::unordered_map OSNMA_TABLE_1 = { {3, std::string("Don't use")}}; // key: nmas, value: nmas status -// OSNMA User ICD for the Test Phase, Issue 1.0, Table 1 +// OSNMA User ICD, Issue 1.1, Table 2 const std::unordered_map OSNMA_TABLE_2 = { {0, std::string("Reserved")}, {1, std::string("Nominal")}, {2, std::string("End of Chain (EOC)")}, {3, std::string("Chain Revoked (CREV)")}, - {4, std::string("Public Key Revoked (PKREV)")}, - {5, std::string("Chain Revoked (CREV)")}, + {4, std::string("New Publick Key (NPK)")}, + {5, std::string("Public Key Revoked (PKREV)")}, {6, std::string("New Merkle Tree (NMT)")}, {7, std::string("Alert Message (AM)")}}; // key: cpks, value: cpks status diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 820478c77..6eeffddaf 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -49,7 +49,7 @@ public: std::array mack{}; std::array hkroot{}; uint32_t PRN{}; - uint32_t WN_sf0{}; // TODO - this is present in UtcModelData already + uint32_t WN_sf0{}; uint32_t TOW_sf0{}; std::vector EphemerisClockAndStatusData{}; // TODO _2 rename and substitute this std::string EphemerisClockAndStatusData_2{}; diff --git a/src/core/system_parameters/osnma_dsm_reader.cc b/src/core/system_parameters/osnma_dsm_reader.cc index 65caddd51..16bd12114 100644 --- a/src/core/system_parameters/osnma_dsm_reader.cc +++ b/src/core/system_parameters/osnma_dsm_reader.cc @@ -38,7 +38,7 @@ uint8_t OSNMA_DSM_Reader::get_cpks(uint8_t nma_header) const bool OSNMA_DSM_Reader::get_nma_header_reserved(uint8_t nma_header) const { - return ((nma_header & mask_nma_header_reserved) ? true : false); + return (nma_header & mask_nma_header_reserved) != 0; } diff --git a/src/core/system_parameters/osnma_dsm_reader.h b/src/core/system_parameters/osnma_dsm_reader.h index 5031a140e..121746052 100644 --- a/src/core/system_parameters/osnma_dsm_reader.h +++ b/src/core/system_parameters/osnma_dsm_reader.h @@ -65,7 +65,7 @@ public: private: static constexpr std::uint8_t mask_nmas{0xC0}; static constexpr std::uint8_t mask_cid{0x30}; - static constexpr std::uint8_t mask_cpks{0x07}; + static constexpr std::uint8_t mask_cpks{0x0E}; static constexpr std::uint8_t mask_nma_header_reserved{0x01}; static constexpr std::uint8_t mask_dsm_id{0xF0}; static constexpr std::uint8_t mask_dsm_block_id{0x0F}; diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 70e060cf9..7dd2e7a8d 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -16,15 +16,15 @@ * ----------------------------------------------------------------------------- */ -#include "gnss_crypto.h" -#include "osnma_helper.h" -#include "osnma_msg_receiver.h" #include #include #include #include #include #include "Galileo_OSNMA.h" +#include "gnss_crypto.h" +#include "osnma_helper.h" +#include "osnma_msg_receiver.h" #if USE_GLOG_AND_GFLAGS #include // for LOG @@ -43,7 +43,7 @@ protected: uint32_t TOW{}; uint32_t WN{}; std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; // months start with 0 and years since 1900 in std::tm - const uint32_t LEAP_SECONDS = 0; // 13 + 5; + const uint32_t LEAP_SECONDS = 0; // tried with 13 + 5, which is the official count, but won't parse correctly void set_time(std::tm& input); void SetUp() override 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 3f711f7d8..d0a5ab0dd 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 @@ -61,19 +61,19 @@ protected: void SetUp() override { - // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 1 - std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 2 - set_time(input_time); - std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 - std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; - osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); } }; - +// TODO - split this into configuration 1 and configuration 2 TEST_F(OsnmaTestVectors, OsnmaTestVectorsSimulation) { // Arrange + // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 1 + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 2 + set_time(input_time); + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; + osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); std::vector testVectors = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/configuration_2/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 if (testVectors.empty()) { @@ -96,7 +96,7 @@ TEST_F(OsnmaTestVectors, OsnmaTestVectorsSimulation) // Act // loop over all bytes of data. Note: all TestVectors have same amount of data. - while (end_of_hex_stream == false) + while (!end_of_hex_stream) { // loop over all SVs, extract a subframe for (const TestVector& tv : testVectors) @@ -289,7 +289,252 @@ TEST_F(OsnmaTestVectors, OsnmaTestVectorsSimulation) // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) } +TEST_F(OsnmaTestVectors, PublicKeyRenewal) +{ + // Arrange + std::tm input_time_step1 = {0, 45, 2, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::tm input_time_step2 = {0, 45, 3, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::tm input_time_step3 = {0, 45, 4, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::vector input_times = {input_time_step1, input_time_step2, input_time_step3}; + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt"; + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml"; + osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + + std::vector testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step1/07_OCT_2023_GST_02_45_01.csv"); + std::vector testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step2/07_OCT_2023_GST_03_45_01.csv"); + std::vector testVectors_step3 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step3/07_OCT_2023_GST_04_45_01.csv"); + std::vector> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3}; + + if (testVectors_step1.empty() || testVectors_step2.empty() || testVectors_step3.empty()) + { + ASSERT_TRUE(false); + } + + bool end_of_hex_stream; + int offset_byte{0}; + int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size + const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page + const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe + const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds + + const int DUMMY_PAGE{63}; + bool flag_dummy_page{false}; + // Act + // loop over all bytes of data. Note: all TestVectors have same amount of data. + for (int test_step = 0; test_step < 3 ; test_step++) + { + // set variables for each file + end_of_hex_stream = false; + offset_byte = 0; + byte_index = 0; + set_time(input_times[test_step]); + std::cout << "OsnmaTestVectorsSimulation:" + << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; + + if (test_step == 1 ){ + // step 2: this simulates the osnma connecting to the GSC server and downloading the Merkle tree of the next public key + osnma->d_crypto->read_merkle_xml( + std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007081500_PKID_8.xml"); + } + + while (!end_of_hex_stream) + { + // loop over all SVs, extract a subframe + for (const TestVector& tv : testVectors[test_step]) + { // loop over all SVs, extract a subframe + std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; + auto osnmaMsg_sptr = std::make_shared(); + std::array hkroot{}; + std::array mack{}; + byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) + std::map> words_for_OSNMA; // structure containing and + + for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe + { + // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index + std::vector page_bytes = extract_page_bytes(tv, byte_index, SIZE_PAGE_BYTES); + if (page_bytes.empty()) + { + std::cout << "OsnmaTestVectorsSimulation: end of TestVectors \n" + << "byte_index=" << byte_index << " expected= " << 432000 / 8 << std::endl; + end_of_hex_stream = true; + break; + } + // convert them to bitset representation using bytes_to_string + std::string page_bits = bytes_to_str(page_bytes); + // Extract the 40 OSNMA bits starting from the 18th bit + std::string even_page = page_bits.substr(0, page_bits.size() / 2); + std::string odd_page = page_bits.substr(page_bits.size() / 2); + if (even_page.size() < 120 || odd_page.size() < 120) + { + std::cout << "OsnmaTestVectorsSimulation: error parsing pages" << std::endl; + } + bool even_odd_OK = even_page[0] == '0' && odd_page[0] == '1'; + bool page_type_OK = even_page[1] == '0' && odd_page[1] == '0'; + bool tail_bits_OK = even_page.substr(even_page.size() - 6) == "000000" && odd_page.substr(odd_page.size() - 6) == "000000"; + if (!even_odd_OK || !page_type_OK || !tail_bits_OK) + std::cerr << "OsnmaTestVectorsSimulation: error parsing pages." << std::endl; + + std::bitset<112> data_k(even_page.substr(2, 112)); + std::bitset<16> data_j(odd_page.substr(2, 16)); + std::bitset<112> shifted_data_k = data_k; + uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word + // std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast(word_type) << std::endl; + if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) + { + // store raw word + std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); + words_for_OSNMA[word_type] = data_combined; + } + if (word_type == DUMMY_PAGE) + flag_dummy_page = true; + + // place it into osnma object. + std::bitset<40> osnmaBits(odd_page.substr(18, 40)); + + // Extract bits for hkroot and mack + std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8)); + std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32)); + hkroot[idx] = static_cast(hkrootBits.to_ulong()); + mack[idx] = static_cast(mackBits.to_ulong()); + + byte_index += SIZE_PAGE_BYTES; + } + + // std::cout << "----------" << std::endl; + if (end_of_hex_stream) + break; + if (flag_dummy_page) + { + flag_dummy_page = false; + continue; // skip this SV + } + + // Fill osnma object + osnmaMsg_sptr->hkroot = hkroot; + osnmaMsg_sptr->mack = mack; + + osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; + osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20; + osnmaMsg_sptr->PRN = tv.svId; // PRNa + + // TODO - refactor this logic, currently it is split + // check if words_for_OSNMA 1--> 5 words_for_OSNMA are received => fill EphClockStatus data vector + bool ephClockStatusWordsReceived = true; + for (int i = 1; i <= 5; ++i) + { + if (words_for_OSNMA.find(i) == words_for_OSNMA.end()) + { + ephClockStatusWordsReceived = false; + std::cerr << "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " + "Word " + << i << " should be received for each subframe but was not." << std::endl; + } + } + // extract bits as needed by osnma block + if (ephClockStatusWordsReceived) + { + // Define the starting position and length of bits to extract for each word + std::map> extractionParams = { + {1, {6, 120}}, + {2, {6, 120}}, + {3, {6, 122}}, + {4, {6, 120}}, + {5, {6, 67}}, + }; + + // Fill NavData bits -- Iterate over the extraction parameters + std::string nav_data_ADKD_0_12 = ""; + for (const auto& param : extractionParams) + { + uint8_t wordKey = param.first; + uint8_t start = param.second.first; + uint8_t length = param.second.second; + + // Extract the required bits and fill osnma block + nav_data_ADKD_0_12 += words_for_OSNMA[wordKey].to_string().substr(start, length); + } + // send to osnma block + bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; + if (check_size_is_ok) + { + std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " + << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; + const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> + tv.svId, + nav_data_ADKD_0_12, + osnmaMsg_sptr->TOW_sf0); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12; + osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + } + } + + // check w6 && w10 is received => fill TimingData data vector + bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() && + words_for_OSNMA.find(10) != words_for_OSNMA.end(); + // extract bits as needed by osnma block + if (timingWordsReceived) + { + // Define the starting position and length of bits to extract for each word + std::map> extractionParams = { + {6, {6, 99}}, + {10, {86, 42}}}; + + std::string nav_data_ADKD_4 = ""; + // Fill NavData bits -- Iterate over the extraction parameters + for (const auto& param : extractionParams) + { + uint8_t wordKey = param.first; + uint8_t start = param.second.first; + uint8_t length = param.second.second; + + // Extract the required bits and fill osnma block + nav_data_ADKD_4 += words_for_OSNMA[wordKey].to_string().substr(start, length); + } + // send to osnma block + bool check_size_is_ok = nav_data_ADKD_4.size() == 141; + if (check_size_is_ok) + { + std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " + << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; + const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> + tv.svId, + nav_data_ADKD_4, + osnmaMsg_sptr->TOW_sf0); + LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4; + osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + } + } + + // Call the handler, as if it came from telemetry decoder block + auto temp_obj = pmt::make_any(osnmaMsg_sptr); + + osnma->msg_handler_osnma(temp_obj); // osnma entry point + } + + if (!end_of_hex_stream) + { + offset_byte = byte_index; // update offset for the next subframe + d_GST_SIS += DURATION_SUBFRAME; + TOW = d_GST_SIS & 0x000FFFFF; + WN = (d_GST_SIS & 0xFFF00000) >> 20; + std::cout << "OsnmaTestVectorsSimulation:" + << " d_GST_SIS= " << d_GST_SIS + << ", TOW=" << TOW + << ", WN=" << WN << std::endl; + } + } + } + // Assert + + // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) + + // Assert + +} // Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. // Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. std::vector OsnmaTestVectors::readTestVectorsFromFile(const std::string& filename) @@ -332,7 +577,6 @@ std::vector OsnmaTestVectors::readTestVectorsFromFile(const std::str return testVectors; } - std::vector OsnmaTestVectors::parseNavBits(const std::string& hexadecimal) { std::vector bytes; @@ -346,7 +590,6 @@ std::vector OsnmaTestVectors::parseNavBits(const std::string& hexadecim return bytes; } - std::string OsnmaTestVectors::bytes_to_str(const std::vector& bytes) { std::string bit_string; @@ -359,7 +602,6 @@ std::string OsnmaTestVectors::bytes_to_str(const std::vector& bytes) return bit_string; } - /** * @brief Extracts a range of bytes from a TestVector's navBits vector. * @@ -389,7 +631,6 @@ std::vector OsnmaTestVectors::extract_page_bytes(const TestVector& tv, return extracted_bytes; } - /** * @brief Sets the time based on the given input. * @@ -398,6 +639,7 @@ std::vector OsnmaTestVectors::extract_page_bytes(const TestVector& tv, * calculated values in the WN and TOW member variables. Finally, it * combines the WN and TOW into a single 32-bit value and stores it in * the d_GST_SIS member variable. + * \post WN, TOW and GST_SIS are set up based on the input time. * * @param input The input time as a tm struct. */ From 440dc582b5f4e7fe4acf31503e45d45bcdde408b Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 29 Jul 2024 15:21:35 +0200 Subject: [PATCH 193/219] [TEST][OsnmaTestVector] refactor parsing code into feedOsnmaWithTestVectors method. * could not find a way to access osnma private methods, so had to make d_crypto and msg_handler_osnma public. Looking for a way to avoid that. --- src/core/libs/osnma_msg_receiver.cc | 16 +- src/core/libs/osnma_msg_receiver.h | 12 +- .../osnma/osnma_test_vectors.cc | 341 +++++------------- 3 files changed, 111 insertions(+), 258 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index d9602a62e..ec8758fe7 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -535,12 +535,14 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { LOG(WARNING) << "Galileo OSNMA: KROOT authentication failed."; std::cerr << "Galileo OSNMA: KROOT authentication failed." << std::endl; + d_count_failed_Kroot ++; } } else { LOG(WARNING) << "Galileo OSNMA: Error computing padding bits."; // TODO - here will have to decide if perform the verification or not. Since this step is not mandatory, one could as well have skipped it. + d_count_failed_Kroot++; } } } @@ -608,7 +610,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg bool verification = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message); if (verification) { - LOG(INFO) << "Galileo OSNMA: DSM-PKR verified successfully"; + LOG(INFO) << "Galileo OSNMA: DSM-PKR verification :: SUCCESS"; d_public_key_verified = true; if (d_flag_PK_renewal){ d_new_public_key = d_osnma_data.d_dsm_pkr_message.npk; @@ -618,6 +620,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_crypto->store_public_key(PEMFILE_DEFAULT); } } + else + { + LOG(ERROR) << "Galileo OSNMA: DSM-PKR verification :: FAILURE"; + d_public_key_verified = false; + d_count_failed_pubKey ++; + } } } else @@ -1005,6 +1013,7 @@ void osnma_msg_receiver::process_mack_message() * */ if (ret) { + d_count_successful_tags++; it.second.status = Tag::SUCCESS; LOG(INFO) << "Galileo OSNMA: Tag verification :: SUCCESS for tag Id=" << it.second.tag_id @@ -1031,6 +1040,7 @@ void osnma_msg_receiver::process_mack_message() * communicate to PVT*/ else { + d_count_failed_tags++; it.second.status = Tag::FAIL; LOG(WARNING) << "Galileo OSNMA: Tag verification :: FAILURE for tag Id=" << it.second.tag_id @@ -1770,6 +1780,7 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ if (mack.tag_and_info.size() != applicable_sequence.size() - 1) { LOG(WARNING) << "Galileo OSNMA: Number of retrieved tags does not match MACLT sequence size!"; + d_count_failed_macseq += mack.tag_and_info.size(); return verified_tags; } std::vector flxTags{}; @@ -1796,6 +1807,7 @@ std::vector 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 ++; } } @@ -1844,10 +1856,10 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ } return verified_tags; } - else { LOG(WARNING) << "Galileo OSNMA: MACSEQ verification :: FAILURE :: FLX tags verification failed"; + d_count_failed_macseq += flxTags.size(); return verified_tags; } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 9afab20d1..43ec15669 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -63,11 +63,12 @@ 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 private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath); - void msg_handler_osnma(const pmt::pmt_t& msg); void process_osnma_message(const std::shared_ptr& osnma_msg); void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); @@ -112,7 +113,6 @@ private: std::array d_mack_message{}; // C: 480 b std::unique_ptr d_dsm_reader; // osnma parameters parser - std::unique_ptr d_crypto; // access to cryptographic functions std::unique_ptr d_helper; // helper class with auxiliary functions std::unique_ptr d_nav_data_manager; // refactor for holding and processing navigation data @@ -154,13 +154,19 @@ private: bool d_flag_NPK_set{false}; // Provide access to inner functions to Gtest + uint32_t d_count_successful_tags{0}; + uint32_t d_count_failed_tags{0}; + uint32_t d_count_failed_Kroot{0}; + uint32_t d_count_failed_pubKey{0}; // failed public key verifications against Merkle root + uint32_t d_count_failed_macseq{0}; FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); FRIEND_TEST(OsnmaMsgReceiverTest, TagVerification); FRIEND_TEST(OsnmaMsgReceiverTest, BuildTagMessageM0); FRIEND_TEST(OsnmaMsgReceiverTest, VerifyPublicKey); FRIEND_TEST(OsnmaMsgReceiverTest, ComputeBaseLeaf); FRIEND_TEST(OsnmaMsgReceiverTest, ComputeMerkleRoot); - FRIEND_TEST(OsnmaTestVectors, OsnmaTestVectorsSimulation); + FRIEND_TEST(OsnmaTestVectors, NominalTestConf1); + FRIEND_TEST(OsnmaTestVectors, NominalTestConf2); FRIEND_TEST(OsnmaTestVectors, PublicKeyRenewal); }; 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 d0a5ab0dd..cb6104102 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 @@ -17,7 +17,6 @@ */ #include "gnss_crypto.h" -#include "osnma_helper.h" #include "osnma_msg_receiver.h" #include #include @@ -41,302 +40,143 @@ struct TestVector class OsnmaTestVectors : public ::testing::Test { -public: - static std::vector parseNavBits(const std::string& hex); - static std::vector readTestVectorsFromFile(const std::string& filename); +protected: + std::vector parseNavBits(const std::string& hex); + std::vector readTestVectorsFromFile(const std::string& filename); std::string bytes_to_str(const std::vector& bytes); std::vector extract_page_bytes(const TestVector& tv, int byte_index, int num_bytes); + bool feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_object, std::vector> testVectors, std::vector startTimesFiles); + void set_time(std::tm& input); + void SetUp() override + { + } -protected: - Osnma_Helper helper; - osnma_msg_receiver_sptr osnma; - OSNMA_msg osnma_msg{}; - std::array nma_position_filled; uint32_t d_GST_SIS{}; uint32_t TOW{}; uint32_t WN{}; std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; // months start with 0 and years since 1900 in std::tm - const uint32_t LEAP_SECONDS = 0; // 13 + 5; - void set_time(std::tm& input); - - void SetUp() override - { - } + const uint32_t LEAP_SECONDS = 0; + const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page + const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe + const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds// 13 + 5; + + bool d_flag_NPK{false}; // flag for NPK, new MT will be set when the new Kroot is received. }; -// TODO - split this into configuration 1 and configuration 2 -TEST_F(OsnmaTestVectors, OsnmaTestVectorsSimulation) +TEST_F(OsnmaTestVectors, NominalTestConf1) { // Arrange - // std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 1 - std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 2 - set_time(input_time); - std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 - std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; - osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); - std::vector testVectors = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/configuration_2/27_JUL_2023_GST_00_00_01.csv"); // conf. 2 - if (testVectors.empty()) + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_1/PublicKey/OSNMA_PublicKey_20230803105952_newPKID_1.crt"; + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_1/MerkleTree/OSNMA_MerkleTree_20230803105953_newPKID_1.xml"; + osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + + std::tm input_time = {0, 0, 5, 16, 8 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::vector input_times = {input_time}; + + std::vector testVector = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/configuration_1/16_AUG_2023_GST_05_00_01.csv"); + if (testVector.empty()) { ASSERT_TRUE(false); } - - bool end_of_hex_stream{false}; - int offset_byte{0}; - int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size - const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page - const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe - const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds - - const int DUMMY_PAGE{63}; - bool flag_dummy_page{false}; - std::cout << "OsnmaTestVectorsSimulation:" - << " d_GST_SIS= " << d_GST_SIS - << ", TOW=" << TOW - << ", WN=" << WN << std::endl; + std::vector> testVectors = {testVector}; // Act - // loop over all bytes of data. Note: all TestVectors have same amount of data. - while (!end_of_hex_stream) - { - // loop over all SVs, extract a subframe - for (const TestVector& tv : testVectors) - { // loop over all SVs, extract a subframe - std::cout << "OsnmaTestVectorsSimulation: SVID (PRN_a) " << tv.svId << std::endl; - auto osnmaMsg_sptr = std::make_shared(); - std::array hkroot{}; - std::array mack{}; - byte_index = offset_byte; // reset byte_index to the offset position for the next test vector. Offset is updated at the end of each Subframe (every 30 s or 450 Bytes) - std::map> words_for_OSNMA; // structure containing and + bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); + ASSERT_TRUE(result); - for (int idx = 0; idx < SIZE_SUBFRAME_PAGES; ++idx) // extract all pages of a subframe - { - // extract bytes of complete page (odd+even) -- extract SIZE_PAGE from tv.navBits, starting from byte_index - std::vector page_bytes = extract_page_bytes(tv, byte_index, SIZE_PAGE_BYTES); - if (page_bytes.empty()) - { - std::cout << "OsnmaTestVectorsSimulation: end of TestVectors \n" - << "byte_index=" << byte_index << " expected= " << 432000 / 8 << std::endl; - end_of_hex_stream = true; - break; - } - // convert them to bitset representation using bytes_to_string - std::string page_bits = bytes_to_str(page_bytes); - // Extract the 40 OSNMA bits starting from the 18th bit - std::string even_page = page_bits.substr(0, page_bits.size() / 2); - std::string odd_page = page_bits.substr(page_bits.size() / 2); - if (even_page.size() < 120 || odd_page.size() < 120) - { - std::cout << "OsnmaTestVectorsSimulation: error parsing pages" << std::endl; - } - bool even_odd_OK = even_page[0] == '0' && odd_page[0] == '1'; - bool page_type_OK = even_page[1] == '0' && odd_page[1] == '0'; - bool tail_bits_OK = even_page.substr(even_page.size() - 6) == "000000" && odd_page.substr(odd_page.size() - 6) == "000000"; - if (!even_odd_OK || !page_type_OK || !tail_bits_OK) - std::cerr << "OsnmaTestVectorsSimulation: error parsing pages." << std::endl; - - std::bitset<112> data_k(even_page.substr(2, 112)); - std::bitset<16> data_j(odd_page.substr(2, 16)); - std::bitset<112> shifted_data_k = data_k; - uint8_t word_type = static_cast((shifted_data_k >>= 106).to_ulong()); // word type is the first 6 bits of the word - std::cout << "OsnmaTestVectorsSimulation: received Word " << static_cast(word_type) << std::endl; - if ((word_type >= 1 && word_type <= 5) || word_type == 6 || word_type == 10) - { - // store raw word - std::bitset<128> data_combined(data_k.to_string() + data_j.to_string()); - words_for_OSNMA[word_type] = data_combined; - } - if (word_type == DUMMY_PAGE) - flag_dummy_page = true; - - // place it into osnma object. - std::bitset<40> osnmaBits(odd_page.substr(18, 40)); - - // Extract bits for hkroot and mack - std::bitset<8> hkrootBits(osnmaBits.to_string().substr(0, 8)); - std::bitset<32> mackBits(osnmaBits.to_string().substr(8, 32)); - hkroot[idx] = static_cast(hkrootBits.to_ulong()); - mack[idx] = static_cast(mackBits.to_ulong()); - - byte_index += SIZE_PAGE_BYTES; - } - - std::cout << "----------" << std::endl; - if (end_of_hex_stream) - break; - if (flag_dummy_page) - { - flag_dummy_page = false; - continue; // skip this SV - } - - // Fill osnma object - osnmaMsg_sptr->hkroot = hkroot; - osnmaMsg_sptr->mack = mack; - - osnmaMsg_sptr->TOW_sf0 = d_GST_SIS & 0x000FFFFF; - osnmaMsg_sptr->WN_sf0 = (d_GST_SIS & 0xFFF00000) >> 20; - osnmaMsg_sptr->PRN = tv.svId; // PRNa - - // TODO - refactor this logic, currently it is split - - // check if words_for_OSNMA 1--> 5 words_for_OSNMA are received => fill EphClockStatus data vector - bool ephClockStatusWordsReceived = true; - for (int i = 1; i <= 5; ++i) - { - if (words_for_OSNMA.find(i) == words_for_OSNMA.end()) - { - ephClockStatusWordsReceived = false; - std::cerr << "OsnmaTestVectorsSimulation: error parsing words_for_OSNMA 1->5. " - "Word " - << i << " should be received for each subframe but was not." << std::endl; - } - } - // extract bits as needed by osnma block - if (ephClockStatusWordsReceived) - { - // Define the starting position and length of bits to extract for each word - std::map> extractionParams = { - {1, {6, 120}}, - {2, {6, 120}}, - {3, {6, 122}}, - {4, {6, 120}}, - {5, {6, 67}}, - }; - - // Fill NavData bits -- Iterate over the extraction parameters - std::string nav_data_ADKD_0_12 = ""; - for (const auto& param : extractionParams) - { - uint8_t wordKey = param.first; - uint8_t start = param.second.first; - uint8_t length = param.second.second; - - // Extract the required bits and fill osnma block - nav_data_ADKD_0_12 += words_for_OSNMA[wordKey].to_string().substr(start, length); - } - // send to osnma block - bool check_size_is_ok = nav_data_ADKD_0_12.size() == 549; - if (check_size_is_ok) - { - std::cout << "Galileo OSNMA: sending ADKD=0/12 navData, PRN_d (" << tv.svId << ") " - << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; - const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> - tv.svId, - nav_data_ADKD_0_12, - osnmaMsg_sptr->TOW_sf0); - LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12; - osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); - } - } - - // check w6 && w10 is received => fill TimingData data vector - bool timingWordsReceived = words_for_OSNMA.find(6) != words_for_OSNMA.end() && - words_for_OSNMA.find(10) != words_for_OSNMA.end(); - // extract bits as needed by osnma block - if (timingWordsReceived) - { - // Define the starting position and length of bits to extract for each word - std::map> extractionParams = { - {6, {6, 99}}, - {10, {86, 42}}}; - - std::string nav_data_ADKD_4 = ""; - // Fill NavData bits -- Iterate over the extraction parameters - for (const auto& param : extractionParams) - { - uint8_t wordKey = param.first; - uint8_t start = param.second.first; - uint8_t length = param.second.second; - - // Extract the required bits and fill osnma block - nav_data_ADKD_4 += words_for_OSNMA[wordKey].to_string().substr(start, length); - } - // send to osnma block - bool check_size_is_ok = nav_data_ADKD_4.size() == 141; - if (check_size_is_ok) - { - std::cout << "Galileo OSNMA: sending ADKD=04 navData, PRN_d (" << tv.svId << ") " - << "TOW_sf=" << osnmaMsg_sptr->TOW_sf0 << std::endl; - const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> - tv.svId, - nav_data_ADKD_4, - osnmaMsg_sptr->TOW_sf0); - LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4; - osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); - } - } - - // Call the handler, as if it came from telemetry decoder block - auto temp_obj = pmt::make_any(osnmaMsg_sptr); - - osnma->msg_handler_osnma(temp_obj); // osnma entry point - } - - if (!end_of_hex_stream) - { - offset_byte = byte_index; // update offset for the next subframe - d_GST_SIS += DURATION_SUBFRAME; - TOW = d_GST_SIS & 0x000FFFFF; - WN = (d_GST_SIS & 0xFFF00000) >> 20; - std::cout << "OsnmaTestVectorsSimulation:" - << " d_GST_SIS= " << d_GST_SIS - << ", TOW=" << TOW - << ", WN=" << WN << std::endl; - } - } // Assert + ASSERT_EQ(osnma->d_count_failed_tags, 0); + ASSERT_EQ(osnma->d_count_failed_Kroot, 0); + ASSERT_EQ(osnma->d_count_failed_pubKey, 0); + ASSERT_EQ(osnma->d_count_failed_macseq, 0); +} - // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) +TEST_F(OsnmaTestVectors, NominalTestConf2) +{ + // Arrange + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20230720113300_newPKID_2.crt"; // conf. 2 + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20230720113300_newPKID_2.xml"; + osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + + std::tm input_time = {0, 0, 0, 27, 7 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; // conf. 2 + std::vector input_times = {input_time}; + + std::vector testVector = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/configuration_2/27_JUL_2023_GST_00_00_01.csv"); + if (testVector.empty()) + { + ASSERT_TRUE(false); + } + std::vector> testVectors = {testVector}; + + // Act + bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); + ASSERT_TRUE(result); + + // Assert + ASSERT_EQ(osnma->d_count_failed_tags, 0); + ASSERT_EQ(osnma->d_count_failed_Kroot, 0); + ASSERT_EQ(osnma->d_count_failed_pubKey, 0); + ASSERT_EQ(osnma->d_count_failed_macseq, 0); } TEST_F(OsnmaTestVectors, PublicKeyRenewal) { // Arrange + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt"; + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml"; + osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + std::tm input_time_step1 = {0, 45, 2, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; std::tm input_time_step2 = {0, 45, 3, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; std::tm input_time_step3 = {0, 45, 4, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; std::vector input_times = {input_time_step1, input_time_step2, input_time_step3}; - std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt"; - std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml"; - osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); - std::vector testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step1/07_OCT_2023_GST_02_45_01.csv"); std::vector testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step2/07_OCT_2023_GST_03_45_01.csv"); std::vector testVectors_step3 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/npk_step3/07_OCT_2023_GST_04_45_01.csv"); - std::vector> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3}; - if (testVectors_step1.empty() || testVectors_step2.empty() || testVectors_step3.empty()) { ASSERT_TRUE(false); } + std::vector> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3}; + d_flag_NPK = true; + bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); + ASSERT_TRUE(result); + + // Assert + ASSERT_EQ(osnma->d_count_failed_tags, 0); + ASSERT_EQ(osnma->d_count_failed_Kroot, 0); + ASSERT_EQ(osnma->d_count_failed_pubKey, 0); + ASSERT_EQ(osnma->d_count_failed_macseq, 0); +} +// Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. +// Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. +bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_object, std::vector> testVectors, std::vector startTimesFiles){ bool end_of_hex_stream; int offset_byte{0}; int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size - const int SIZE_PAGE_BYTES{240 / 8}; // total bytes of a page - const int SIZE_SUBFRAME_PAGES{15}; // number of pages of a subframe - const int DURATION_SUBFRAME{30}; // duration of a subframe, in seconds const int DUMMY_PAGE{63}; bool flag_dummy_page{false}; // Act // loop over all bytes of data. Note: all TestVectors have same amount of data. - for (int test_step = 0; test_step < 3 ; test_step++) + // if needed, add global flags so that particular logic may be done at certain points in between files + for (size_t test_step = 0; test_step < testVectors.size() ; test_step++) { // set variables for each file end_of_hex_stream = false; offset_byte = 0; byte_index = 0; - set_time(input_times[test_step]); + set_time(startTimesFiles[test_step]); std::cout << "OsnmaTestVectorsSimulation:" << " d_GST_SIS= " << d_GST_SIS << ", TOW=" << TOW << ", WN=" << WN << std::endl; - if (test_step == 1 ){ + 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->d_crypto->read_merkle_xml( + osnma_object->d_crypto->read_merkle_xml( std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007081500_PKID_8.xml"); } @@ -468,7 +308,7 @@ TEST_F(OsnmaTestVectors, PublicKeyRenewal) nav_data_ADKD_0_12, osnmaMsg_sptr->TOW_sf0); LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12; - osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + osnma_object->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); } } @@ -505,16 +345,15 @@ TEST_F(OsnmaTestVectors, PublicKeyRenewal) nav_data_ADKD_4, osnmaMsg_sptr->TOW_sf0); LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4; - osnma->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); + osnma_object->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); } } // Call the handler, as if it came from telemetry decoder block auto temp_obj = pmt::make_any(osnmaMsg_sptr); - osnma->msg_handler_osnma(temp_obj); // osnma entry point + osnma_object->msg_handler_osnma(temp_obj); // osnma entry point } - if (!end_of_hex_stream) { offset_byte = byte_index; // update offset for the next subframe @@ -527,16 +366,12 @@ TEST_F(OsnmaTestVectors, PublicKeyRenewal) << ", WN=" << WN << std::endl; } } + if (end_of_hex_stream) + break; } - // Assert - - // TODO - create global vars with failed tags and compare to total tags (Tag Id for example) - - // Assert - +return true; } -// Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. -// Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. + std::vector OsnmaTestVectors::readTestVectorsFromFile(const std::string& filename) { std::ifstream file(filename); From 26f77a3c4279700b3789638b88464d2576582ba1 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 30 Jul 2024 12:25:22 +0200 Subject: [PATCH 194/219] [TAS-250] (x2) [FEAT] Implement PK renewal and revocation. * Revocation implemented and tested. DSM-KROOT appears to be corrupted because length check fails after start of step 1, during steps 2 and 3. --- src/core/libs/osnma_msg_receiver.cc | 92 +++++++++++++------ src/core/libs/osnma_msg_receiver.h | 3 +- .../osnma/osnma_test_vectors.cc | 35 ++++++- 3 files changed, 101 insertions(+), 29 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index ec8758fe7..308dd5a6d 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -77,6 +77,10 @@ osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, const std d_nav_data_manager = std::make_unique(); 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()){ LOG(WARNING) << "OSNMA DSM-KROOT and NMA Header successfully read from file " << KROOTFILE_DEFAULT; @@ -170,22 +174,47 @@ 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) { read_nma_header(osnma_msg->hkroot[0]); - if (d_osnma_data.d_nma_header.nmas == 0 || d_osnma_data.d_nma_header.nmas == 3) - { - LOG(WARNING) << "Galileo OSNMA: NMAS invalid, skipping osnma message"; + + // Check for corner cases: renewal, revocation + if (d_osnma_data.d_nma_header.nmas == 0 /* RES */){ + LOG(WARNING) << "Galileo OSNMA: NMAS invalid (RES), skipping osnma message"; return; } - if (d_osnma_data.d_nma_header.nmas == 2 /*OP*/ && d_osnma_data.d_nma_header.cpks == 4 /*NPK*/ && d_GST_PKR_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_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); - LOG(INFO) << "Galileo OSNMA: Public Key Renewal :: Start at GST=" << d_GST_PKR_start; - std::cout << "Galileo OSNMA: Public Key Renewal :: Start at GST=" << d_GST_PKR_start << std::endl; + 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; - LOG(INFO) << "Galileo OSNMA: Public Key Renewal :: Finished at GST=" << d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); - std::cout << "Galileo OSNMA: Public Key Renewal :: Finished at GST=" << d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0) << std::endl; + 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 Renewal :: Finished at GST=" << duration_hours << ", Duration=" << duration_hours << " h"; + 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){ + d_flag_PK_revocation = true; + d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; + d_public_key_verified = false; + d_kroot_verified = false; + d_tesla_key_verified = false; + d_GST_PKR_PKREV_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); + 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 */ ){ + // 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; + } + + 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 @@ -393,6 +422,7 @@ void osnma_msg_receiver::process_dsm_block(const std::shared_ptr& osn } d_dsm_message[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; d_dsm_id_received[d_osnma_data.d_dsm_header.dsm_id] = std::array{}; + LOG(INFO) << "Galileo OSNMA: DSM message completed :: start processing, GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]"; process_dsm_message(dsm_msg, osnma_msg->hkroot[0]); } } @@ -408,7 +438,7 @@ void osnma_msg_receiver::process_dsm_block(const std::shared_ptr& osn void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg, const uint8_t& nma_header) { // DSM-KROOT message - if (d_osnma_data.d_dsm_header.dsm_id < 12 || d_flag_hot_start) + if ((d_osnma_data.d_dsm_header.dsm_id < 12 || d_flag_hot_start) && d_public_key_verified) { // Parse Kroot message LOG(INFO) << "Galileo OSNMA: DSM-KROOT message received."; @@ -456,6 +486,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg if (l_dk_bits != check_l_dk) { LOG(WARNING) << "Galileo OSNMA: Failed length reading of DSM-KROOT message"; + d_count_failed_Kroot++; } else { @@ -498,7 +529,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) { LOG(INFO) << "Galileo OSNMA: DSM-KROOT message received ok."; - LOG(INFO) << "Galileo OSNMA: KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) + LOG(INFO) << "Galileo OSNMA: DSM-KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; @@ -519,22 +550,22 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } if (d_kroot_verified) { - std::cout << "Galileo OSNMA: KROOT authentication successful!" << std::endl; - LOG(INFO) << "Galileo OSNMA: KROOT authentication successful!"; + std::cout << "Galileo OSNMA: DSM-KROOT authentication successful!" << std::endl; + LOG(INFO) << "Galileo OSNMA: DSM-KROOT authentication successful!"; LOG(INFO) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " << "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; } - store_dsm_kroot(dsm_msg, nma_header); + store_dsm_kroot(dsm_msg, nma_header); // TODO - store it only if DSM-KROOT is new } else { - LOG(WARNING) << "Galileo OSNMA: KROOT authentication failed."; - std::cerr << "Galileo OSNMA: KROOT authentication failed." << std::endl; + LOG(WARNING) << "Galileo OSNMA: DSM-KROOT authentication failed."; + std::cerr << "Galileo OSNMA: DSM-KROOT authentication failed." << std::endl; d_count_failed_Kroot ++; } } @@ -546,9 +577,10 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } } } + // DSM-PKR message else if (d_osnma_data.d_dsm_header.dsm_id >= 12 && d_osnma_data.d_dsm_header.dsm_id < 16) { - LOG(INFO) << "Galileo OSNMA: DSM-PKR message received."; + LOG(INFO) << "Galileo OSNMA: DSM-PKR message received"; // Save DSM-PKR message d_osnma_data.d_dsm_pkr_message.nb_dp = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); d_osnma_data.d_dsm_pkr_message.mid = d_dsm_reader->get_mid(dsm_msg); @@ -606,7 +638,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg /*<< ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600*/ << " received"; - // C: NPK verification against Merkle tree root. + // Public key verification against Merkle tree root. bool verification = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message); if (verification) { @@ -634,13 +666,14 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg LOG(WARNING) << "Galileo OSNMA: Reserved message received"; std::cerr << "Galileo OSNMA: Reserved message received" << std::endl; } - d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; + d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; // TODO - reset during header parsing in PKREV? } /** - * @brief Reads the Mack message from the given OSNMA_msg object. + * @brief Reads the Mack message from the given OSNMA_msg object * + * @details Conditions for MACK processing: * @param osnma_msg The OSNMA_msg object containing the Mack message. */ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptr& osnma_msg) @@ -657,8 +690,10 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrTOW_sf0); - - if (d_kroot_verified || d_tesla_key_verified || d_osnma_data.d_dsm_kroot_message.ts != 0 /*mack parser needs to know the tag size, otherwise cannot parse mack messages*/) // C: 4 ts < ts < 10 + bool can_process_mack_block = d_osnma_data.d_nma_header.nmas != 3; // Don't Use + 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) { // TODO - correct? with this, MACK would not be processed unless a Kroot is available -- no, if TK available MACK sould go on, this has to change in future read_mack_header(); d_osnma_data.d_mack_message.PRNa = osnma_msg->PRN; // FIXME this is ugly. @@ -669,6 +704,12 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrd_count_failed_pubKey, 0); ASSERT_EQ(osnma->d_count_failed_macseq, 0); } + +TEST_F(OsnmaTestVectors, PublicKeyRevocation) +{ + // Arrange + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007081500_PKID_8.crt"; + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007081500_PKID_8.xml"; + osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + + std::tm input_time_step1 = {0, 45, 7, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::tm input_time_step2 = {0, 30, 9, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::tm input_time_step3 = {0, 30, 10, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::vector input_times = { input_time_step1, input_time_step2, input_time_step3 }; + + std::vector testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/pkrev_step1/07_OCT_2023_GST_07_45_01.csv"); + std::vector testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/pkrev_step2/07_OCT_2023_GST_09_30_01.csv"); + std::vector testVectors_step3 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/pkrev_step3/07_OCT_2023_GST_10_30_01.csv"); + if (testVectors_step1.empty() || testVectors_step2.empty() || testVectors_step3.empty()) + { + ASSERT_TRUE(false); + } + std::vector> testVectors = { testVectors_step1, testVectors_step2, testVectors_step3}; + + bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); + ASSERT_TRUE(result); + + // Assert + ASSERT_EQ(osnma->d_count_failed_tags, 0); + ASSERT_EQ(osnma->d_count_failed_Kroot, 0); + ASSERT_EQ(osnma->d_count_failed_pubKey, 0); + ASSERT_EQ(osnma->d_count_failed_macseq, 0); +} // Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. // Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_object, std::vector> testVectors, std::vector startTimesFiles){ @@ -367,7 +398,7 @@ bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_ob } } if (end_of_hex_stream) - break; + continue; } return true; } From 07cbf2c01f2eb194bef564cda3ac569616b29253 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 30 Jul 2024 18:00:41 +0200 Subject: [PATCH 195/219] Fixes for GnuTLS and OpenSSL < 3 (#14) * Fix set_public_key when using GnuTLS * Fix for OpenSSL 1.1.1 * Fix formatting * Fix formatting * Fix ECDSA-P521 signature verification when using GnuTLS * Improve finding of the GMP library in Debian-based systems * Improve finding of the GMP library in Debian-based systems * Keep GMP usage private --- cmake/Modules/FindGMP.cmake | 119 +++++++ cmake/Modules/GnssSdrCrypto.cmake | 14 + src/core/system_parameters/gnss_crypto.cc | 311 ++++++++++++++---- src/core/system_parameters/gnss_crypto.h | 3 + src/tests/test_main.cc | 2 +- .../osnma/gnss_crypto_test.cc | 50 +-- 6 files changed, 415 insertions(+), 84 deletions(-) create mode 100644 cmake/Modules/FindGMP.cmake diff --git a/cmake/Modules/FindGMP.cmake b/cmake/Modules/FindGMP.cmake new file mode 100644 index 000000000..f0648feb3 --- /dev/null +++ b/cmake/Modules/FindGMP.cmake @@ -0,0 +1,119 @@ +# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +# This file is part of GNSS-SDR. +# +# SPDX-FileCopyrightText: 2011-2024 C. Fernandez-Prades cfernandez(at)cttc.es +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT PKG_CONFIG_FOUND) + include(FindPkgConfig) +endif() +pkg_check_modules(PC_GMP "gmp") + +set(GMP_DEFINITIONS ${PC_GMP_CFLAGS_OTHER}) + +find_path( + GMP_INCLUDE_DIR + NAMES gmpxx.h + HINTS ${PC_GMP_INCLUDEDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/include + /usr/local/include + /usr/include + /opt/local/include +) + +set(GMP_INCLUDE_DIRS ${GMP_INCLUDE_DIR}) +set(GMP_PC_ADD_CFLAGS "-I${GMP_INCLUDE_DIR}") + +find_library( + GMPXX_LIBRARY + NAMES gmpxx + HINTS ${PC_GMP_LIBDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /usr/lib/x86_64-linux-gnu + /usr/lib/i386-linux-gnu + /usr/lib/arm-linux-gnueabihf + /usr/lib/arm-linux-gnueabi + /usr/lib/aarch64-linux-gnu + /usr/lib/mipsel-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/hppa-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/i386-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i386-kfreebsd-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/sh4-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/alpha-linux-gnu + /usr/lib/riscv64-linux-gnu + /usr/lib/loongarch64-linux-gnu + /opt/local/lib +) + +find_library( + GMP_LIBRARY + NAMES gmp + HINTS ${PC_GMP_LIBDIR} + PATHS ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 + /usr/lib/x86_64-linux-gnu + /usr/lib/i386-linux-gnu + /usr/lib/arm-linux-gnueabihf + /usr/lib/arm-linux-gnueabi + /usr/lib/aarch64-linux-gnu + /usr/lib/mipsel-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/hppa-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/i386-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/i386-kfreebsd-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/sh4-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib/alpha-linux-gnu + /usr/lib/riscv64-linux-gnu + /usr/lib/loongarch64-linux-gnu + /opt/local/lib +) + +set(GMP_LIBRARIES ${GMPXX_LIBRARY} ${GMP_LIBRARY}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GMP DEFAULT_MSG GMPXX_LIBRARY GMP_LIBRARY + GMP_INCLUDE_DIR) + +if(GMP_FOUND AND NOT TARGET Gmp::gmp) + add_library(Gmp::gmp SHARED IMPORTED) + set_target_properties(Gmp::gmp PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${GMPXX_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${GMP_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${GMP_LIBRARIES}" + ) +endif() + +mark_as_advanced(GMPXX_LIBRARY GMP_LIBRARY GMP_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index 5286c6d01..ac84260d1 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -13,6 +13,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") endif() unset(OPENSSL_FOUND CACHE) unset(GnuTLS_FOUND CACHE) +unset(GMP_FOUND CACHE) if(NOT ENABLE_GNUTLS) find_package(OpenSSL) endif() @@ -133,6 +134,17 @@ else() if("${gnutls_abstract_file_contents}" MATCHES "gnutls_pubkey_export2") set(GNUTLS_PUBKEY_EXPORT2 TRUE) endif() + + find_package(GMP) + set_package_properties(GMP PROPERTIES + URL "https://gmplib.org/" + PURPOSE "Required to decompress cryptographic keys." + DESCRIPTION "The GNU Multiple Precision Arithmetic Library" + TYPE REQUIRED + ) + if(NOT GMP_FOUND) + message(FATAL_ERROR "GMP is required by gnss-sdr if linking against GnuTLS") + endif() endif() ################################################################################ @@ -175,6 +187,8 @@ function(link_to_crypto_dependencies target) PUBLIC ${GNUTLS_LIBRARIES} ${GNUTLS_OPENSSL_LIBRARY} + PRIVATE + Gmp::gmp ) target_include_directories(${target} PUBLIC diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 86f1525f2..a2543d18a 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -27,6 +27,7 @@ #if USE_GNUTLS_FALLBACK #include +#include #include #include #else // OpenSSL @@ -158,7 +159,7 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const return false; } - pubKeyFile.write((const char*)pem_data.data, pem_data.size); + pubKeyFile.write(reinterpret_cast(pem_data.data), pem_data.size); pubKeyFile.close(); gnutls_free(pem_data.data); #else // OpenSSL @@ -195,14 +196,15 @@ bool Gnss_Crypto::store_public_key(const std::string& pubKeyFilePath) const return true; } + bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& message, const std::vector& signature) const { - std::vector digest = this->compute_SHA_256(message); if (!have_public_key()) { LOG(WARNING) << "Galileo OSNMA KROOT verification error: Public key is not available"; return false; } + std::vector digest = this->compute_SHA_256(message); bool success = false; #if USE_GNUTLS_FALLBACK #if HAVE_GNUTLS_SIGN_ECDSA_SHA256 @@ -843,33 +845,40 @@ std::vector Gnss_Crypto::get_merkle_root() const return d_x_4_0; } + void Gnss_Crypto::set_public_key(const std::vector& publicKey) { #if USE_GNUTLS_FALLBACK - // TODO - changed to import a compressed ECC key, either P256 or P521, but have not tested it yet gnutls_pubkey_t pubkey{}; - gnutls_datum_t x_coord = {(unsigned char*)&publicKey[1], 32}; - gnutls_datum_t y_coord = {NULL, 0}; gnutls_ecc_curve_t curve; + std::vector x; + std::vector y; gnutls_pubkey_init(&pubkey); - - if (publicKey.size() == 33) + const size_t size_pk = publicKey.size(); + if (size_pk == 33) { curve = GNUTLS_ECC_CURVE_SECP256R1; + decompress_public_key_secp256r1(publicKey, x, y); + } + else if (size_pk == 67) + { + curve = GNUTLS_ECC_CURVE_SECP521R1; + decompress_public_key_secp521r1(publicKey, x, y); } else { - curve = GNUTLS_ECC_CURVE_SECP521R1; + LOG(WARNING) << "GnuTLS: Invalid public key size"; + return; } + gnutls_datum_t x_coord = {x.data(), static_cast(x.size())}; + gnutls_datum_t y_coord = {y.data(), static_cast(y.size())}; int ret = gnutls_pubkey_import_ecc_raw(pubkey, curve, &x_coord, &y_coord); if (ret != GNUTLS_E_SUCCESS) { gnutls_pubkey_deinit(pubkey); - std::cerr << "GnuTLS: error setting the public key" << std::endl; - std::cerr << "GnuTLS error: " << gnutls_strerror(ret) << std::endl; LOG(WARNING) << "GnuTLS: error setting the OSNMA public key: " << gnutls_strerror(ret); return; } @@ -878,60 +887,59 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) #else // OpenSSL #if USE_OPENSSL_3 -// Uses the new EVP_PKEY envelope as well as the parameter builder functions -// generate the uncompressed key, then add it into the EVP_PKEY* struct -EVP_PKEY* pkey = NULL; -EVP_PKEY_CTX* ctx = NULL; -OSSL_PARAM_BLD *param_bld; -OSSL_PARAM *params = NULL; + // Uses the new EVP_PKEY envelope as well as the parameter builder functions + // generate the uncompressed key, then add it into the EVP_PKEY* struct + EVP_PKEY* pkey = nullptr; + EVP_PKEY_CTX* ctx = nullptr; + OSSL_PARAM_BLD* param_bld; + OSSL_PARAM* params = nullptr; -param_bld = OSSL_PARAM_BLD_new(); -if (param_bld != NULL - && 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); + 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); -ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); -if (ctx == NULL - || params == NULL - || EVP_PKEY_fromdata_init(ctx) <= 0 - || EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) { - return; - } else { - if (!pubkey_copy(pkey, &d_PublicKey)) - { - return; - } - } -EVP_PKEY_free(pkey); -EVP_PKEY_CTX_free(ctx); -OSSL_PARAM_free(params); -OSSL_PARAM_BLD_free(param_bld); -#else - EVP_PKEY* pkey = NULL; // Generic public key type - EC_KEY* ec_key = NULL; // ECC Key pair - EC_POINT* point = NULL; // Represents the point in the EC the public key belongs to - EC_GROUP* group = NULL; // Defines the curve the public key belongs + 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) + { + return; + } + + if (!pubkey_copy(pkey, &d_PublicKey)) + { + return; + } + + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(param_bld); +#else // OpenSSL 1.x + EC_KEY* ec_key = nullptr; // ECC Key pair + EC_POINT* point = nullptr; // Represents the point in the EC the public key belongs to + EC_GROUP* group = nullptr; // Defines the curve the public key belongs if (publicKey.size() == 33) // ECDSA-P-256 { group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); } - else // ECDSA-P-521 + else // ECDSA-P-521 { group = EC_GROUP_new_by_curve_name(NID_secp521r1); } - if(!group){ + if (!group) + { return; } point = EC_POINT_new(group); - if(!point){ + if (!point) + { return; } - if(!EC_POINT_oct2point(group, point, publicKey.data(), publicKey.size(), NULL)){ + if (!EC_POINT_oct2point(group, point, publicKey.data(), publicKey.size(), nullptr)) + { return; } @@ -939,22 +947,24 @@ OSSL_PARAM_BLD_free(param_bld); { ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); } - else // ECDSA-P-521 + else // ECDSA-P-521 { ec_key = EC_KEY_new_by_curve_name(NID_secp521r1); } - if(!ec_key){ - return; - } - - if(!EC_KEY_set_public_key(ec_key, point)){ - return; - } - if (!pubkey_copy(ec_pkey, &d_PublicKey)) + if (!ec_key) { return; } - EC_KEY_free(ec_pkey); + + if (!EC_KEY_set_public_key(ec_key, point)) + { + return; + } + if (!pubkey_copy(ec_key, &d_PublicKey)) + { + return; + } + EC_KEY_free(ec_key); EC_POINT_free(point); EC_GROUP_free(group); #endif // OpenSSL 1.x @@ -962,11 +972,13 @@ OSSL_PARAM_BLD_free(param_bld); DLOG(INFO) << "OSNMA Public Key successfully set up."; } + void Gnss_Crypto::set_merkle_root(const std::vector& v) { d_x_4_0 = v; } + void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) { pugi::xml_document doc; @@ -1206,6 +1218,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) return true; } + bool Gnss_Crypto::convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const { if (raw_signature.size() % 2 != 0) @@ -1312,6 +1325,188 @@ bool Gnss_Crypto::pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest) return true; } + + +bool tonelli_shanks(mpz_t& res, const mpz_t& n, const mpz_t& p) +{ + if (mpz_legendre(n, p) != 1) + { + return false; + } + mpz_t q; + mpz_t s; + mpz_t z; + mpz_t m; + mpz_t c; + mpz_t t; + mpz_t r; + mpz_t b; + mpz_t two; + mpz_t p_minus_one; + mpz_inits(q, s, z, m, c, t, r, b, two, p_minus_one, nullptr); + + mpz_set_ui(two, 2); + + mpz_sub_ui(q, p, 1); + mpz_set_ui(s, 0); + while (mpz_even_p(q)) + { + mpz_add_ui(s, s, 1); + mpz_divexact_ui(q, q, 2); + } + + mpz_set_ui(z, 2); + while (mpz_legendre(z, p) != -1) + { + mpz_add_ui(z, z, 1); + } + + mpz_powm(c, z, q, p); + + mpz_add_ui(p_minus_one, p, 1); + mpz_divexact_ui(p_minus_one, p_minus_one, 4); + mpz_powm(r, n, p_minus_one, p); + mpz_powm(t, n, q, p); + mpz_set(m, s); + + while (mpz_cmp_ui(t, 1) != 0) + { + mpz_set(b, t); + unsigned int i; + for (i = 0; mpz_cmp_ui(b, 1) != 0; i++) + { + mpz_powm_ui(b, b, 2, p); + } + if (i == mpz_get_ui(m)) + { + mpz_clears(q, s, z, m, c, t, r, b, two, p_minus_one, nullptr); + return false; + } + + mpz_powm_ui(b, two, mpz_get_ui(m) - i - 1, p); + mpz_powm(c, c, b, p); + mpz_mul(r, r, c); + mpz_mod(r, r, p); + mpz_powm_ui(c, c, 2, p); + mpz_mul(t, t, c); + mpz_mod(t, t, p); + mpz_set_ui(m, mpz_get_ui(m) - i - 1); + } + + mpz_set(res, r); + mpz_clears(q, s, z, m, c, t, r, b, two, p_minus_one, nullptr); + return true; +} + + +void Gnss_Crypto::decompress_public_key_secp256r1(const std::vector& compressed_key, std::vector& x, std::vector& y) const +{ + // Define curve parameters for secp256r1 + const char* p_str = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"; + const char* a_str = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"; + const char* b_str = "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"; + + mpz_t p; + mpz_t a; + mpz_t b; + mpz_t x_coord; + mpz_t y_coord; + mpz_t y_squared; + mpz_t tmp; + mpz_inits(p, a, b, x_coord, y_coord, y_squared, tmp, nullptr); + + // Initialize curve parameters + mpz_set_str(p, p_str, 16); + mpz_set_str(a, a_str, 16); + mpz_set_str(b, b_str, 16); + + // Set x coordinate + mpz_import(x_coord, 32, 1, 1, 1, 0, &compressed_key[1]); + + // Calculate y^2 = x^3 + ax + b (mod p) + mpz_powm_ui(y_squared, x_coord, 3, p); // y_squared = x^3 + mpz_mul(tmp, a, x_coord); // tmp = ax + mpz_add(y_squared, y_squared, tmp); // y_squared = x^3 + ax + mpz_add(y_squared, y_squared, b); // y_squared = x^3 + ax + b + mpz_mod(y_squared, y_squared, p); // y_squared = (x^3 + ax + b) % p + + // Calculate the square root of y_squared to get y + if (!tonelli_shanks(y_coord, y_squared, p)) + { + mpz_clears(p, a, b, x_coord, y_coord, y_squared, tmp, nullptr); + LOG(WARNING) << "GnuTLS: Failed to decompress public key: No valid y coordinate"; + return; + } + + // Select the correct y coordinate based on the parity bit + if ((compressed_key[0] & 1) != (mpz_tstbit(y_coord, 0) & 1)) + { + mpz_sub(y_coord, p, y_coord); // y = p - y + } + + // Export the x and y coordinates to vectors + x.resize(32); + y.resize(32); + mpz_export(x.data(), nullptr, 1, 1, 1, 0, x_coord); + mpz_export(y.data(), nullptr, 1, 1, 1, 0, y_coord); + + mpz_clears(p, a, b, x_coord, y_coord, y_squared, tmp, nullptr); +} + + +void Gnss_Crypto::decompress_public_key_secp521r1(const std::vector& compressed_key, std::vector& x, std::vector& y) const +{ + // Define curve parameters for secp521r1 + const char* p_str = "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + const char* a_str = "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"; + const char* b_str = "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"; + + mpz_t p; + mpz_t a; + mpz_t b; + mpz_t x_coord; + mpz_t y_coord; + mpz_t y_squared; + mpz_t tmp; + mpz_inits(p, a, b, x_coord, y_coord, y_squared, tmp, nullptr); + + // Initialize curve parameters + mpz_set_str(p, p_str, 16); + mpz_set_str(a, a_str, 16); + mpz_set_str(b, b_str, 16); + + // Set x coordinate + mpz_import(x_coord, 66, 1, 1, 1, 0, &compressed_key[1]); + + // Calculate y^2 = x^3 + ax + b (mod p) + mpz_powm_ui(y_squared, x_coord, 3, p); // y_squared = x^3 + mpz_mul(tmp, a, x_coord); // tmp = ax + mpz_add(y_squared, y_squared, tmp); // y_squared = x^3 + ax + mpz_add(y_squared, y_squared, b); // y_squared = x^3 + ax + b + mpz_mod(y_squared, y_squared, p); // y_squared = (x^3 + ax + b) % p + + // Calculate the square root of y_squared to get y + if (!tonelli_shanks(y_coord, y_squared, p)) + { + mpz_clears(p, a, b, x_coord, y_coord, y_squared, tmp, nullptr); + LOG(WARNING) << "GnuTLS: Failed to decompress public key: No valid y coordinate"; + return; + } + + // Select the correct y coordinate based on the parity bit + if ((compressed_key[0] & 1) != (mpz_tstbit(y_coord, 0) & 1)) + { + mpz_sub(y_coord, p, y_coord); // y = p - y + } + + // Export the x and y coordinates to vectors + x.resize(66, 0); // Ensure 66 bytes with leading zeros if necessary + y.resize(66, 0); + mpz_export(x.data() + 1, nullptr, 1, 1, 1, 0, x_coord); + mpz_export(y.data(), nullptr, 1, 1, 1, 0, y_coord); + + mpz_clears(p, a, b, x_coord, y_coord, y_squared, tmp, nullptr); +} #else // OpenSSL #if USE_OPENSSL_3 bool Gnss_Crypto::pubkey_copy(EVP_PKEY* src, EVP_PKEY** dest) diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 85993d063..c4e9f4e96 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -72,12 +72,15 @@ public: void set_public_key(const std::vector& publickey); //!< Sets the ECDSA Public Key (publickey compressed format) void set_merkle_root(const std::vector& v); //!< Sets the Merkle Tree root node x(\f$ x_{4,0} \f$) void read_merkle_xml(const std::string& merkleFilePath); + private: void readPublicKeyFromPEM(const std::string& pemFilePath); bool readPublicKeyFromCRT(const std::string& crtFilePath); bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; std::vector convert_from_hex_str(const std::string& input) const; #if USE_GNUTLS_FALLBACK + void decompress_public_key_secp256r1(const std::vector& compressed_key, std::vector& x, std::vector& y) const; + void decompress_public_key_secp521r1(const std::vector& compressed_key, std::vector& x, std::vector& y) const; bool pubkey_copy(gnutls_pubkey_t src, gnutls_pubkey_t* dest); gnutls_pubkey_t d_PublicKey{}; #else // OpenSSL diff --git a/src/tests/test_main.cc b/src/tests/test_main.cc index bcd2b7018..cf6dfbccc 100644 --- a/src/tests/test_main.cc +++ b/src/tests/test_main.cc @@ -183,8 +183,8 @@ private: #ifndef EXCLUDE_TESTS_REQUIRING_BINARIES #include "unit-tests/signal-processing-blocks/acquisition/glonass_l1_ca_pcps_acquisition_test.cc" #include "unit-tests/signal-processing-blocks/acquisition/gps_l2_m_pcps_acquisition_test.cc" -#include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc" #include "unit-tests/signal-processing-blocks/osnma/osnma_test_vectors.cc" +#include "unit-tests/signal-processing-blocks/tracking/gps_l2_m_dll_pll_tracking_test.cc" #endif // #include "unit-tests/signal-processing-blocks/pvt/rtklib_solver_test.cc" #include "unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test.cc" 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 a6429bc7b..6d645edb1 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 @@ -35,7 +35,7 @@ TEST(GnssCryptoTest, VerifyPubKeyImport) // compressed ECDSA P-256 format std::vector 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 }; + 0x32, 0x0D, 0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7, 0x79, 0x80, 0xEA}; ASSERT_FALSE(d_crypto->have_public_key()); @@ -56,7 +56,7 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) // compressed ECDSA P-256 format std::vector 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 }; + 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); @@ -255,7 +255,7 @@ TEST(GnssCryptoTest, VerifySignatureP256) // compressed ECDSA P-256 format std::vector 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 }; + 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); @@ -274,34 +274,34 @@ TEST(GnssCryptoTest, VerifySignatureP521) // Message to be verified std::vector message = { - 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A }; // "Hello world\n" + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // "Hello world\n" // Public key in compressed X format std::vector publicKey = { - 0x03, 0x00, 0x28, 0x35, 0xBB, 0xE9, 0x24, 0x59, 0x4E, 0xF0, - 0xE3, 0xA2, 0xDB, 0xC0, 0x49, 0x30, 0x60, 0x7C, 0x61, 0x90, - 0xE4, 0x03, 0xE0, 0xC7, 0xB8, 0xC2, 0x62, 0x37, 0xF7, 0x58, - 0x56, 0xBE, 0x63, 0x5C, 0x97, 0xF7, 0x53, 0x64, 0x7E, 0xE1, - 0x0C, 0x07, 0xD3, 0x97, 0x8D, 0x58, 0x46, 0xFD, 0x6E, 0x06, - 0x44, 0x01, 0xA7, 0xAA, 0xC4, 0x95, 0x13, 0x5D, 0xC9, 0x77, - 0x26, 0xE9, 0xF8, 0x72, 0x0C, 0xD3, 0x88 }; + 0x03, 0x00, 0x28, 0x35, 0xBB, 0xE9, 0x24, 0x59, 0x4E, 0xF0, + 0xE3, 0xA2, 0xDB, 0xC0, 0x49, 0x30, 0x60, 0x7C, 0x61, 0x90, + 0xE4, 0x03, 0xE0, 0xC7, 0xB8, 0xC2, 0x62, 0x37, 0xF7, 0x58, + 0x56, 0xBE, 0x63, 0x5C, 0x97, 0xF7, 0x53, 0x64, 0x7E, 0xE1, + 0x0C, 0x07, 0xD3, 0x97, 0x8D, 0x58, 0x46, 0xFD, 0x6E, 0x06, + 0x44, 0x01, 0xA7, 0xAA, 0xC4, 0x95, 0x13, 0x5D, 0xC9, 0x77, + 0x26, 0xE9, 0xF8, 0x72, 0x0C, 0xD3, 0x88}; // ECDSA P-521 signature, raw format std::vector signature = { - 0x01, 0x5C, 0x23, 0xC0, 0xBE, 0xAD, 0x1E, 0x44, 0x60, 0xD4, - 0xE0, 0x81, 0x38, 0xF2, 0xBA, 0xF5, 0xB5, 0x37, 0x5A, 0x34, - 0xB5, 0xCA, 0x6B, 0xC8, 0x0F, 0xCD, 0x75, 0x1D, 0x5E, 0xC0, - 0x8A, 0xD3, 0xD7, 0x79, 0xA7, 0xC1, 0xB8, 0xA2, 0xC6, 0xEA, - 0x5A, 0x7D, 0x60, 0x66, 0x50, 0x97, 0x37, 0x6C, 0xF9, 0x0A, - 0xF6, 0x3D, 0x77, 0x9A, 0xE2, 0x19, 0xF7, 0xF9, 0xDD, 0x52, - 0xC4, 0x0F, 0x98, 0xAA, 0xA2, 0xA4, 0x01, 0xC9, 0x41, 0x0B, - 0xD0, 0x25, 0xDD, 0xC9, 0x7C, 0x3F, 0x70, 0x32, 0x23, 0xCF, - 0xFE, 0x37, 0x67, 0x3A, 0xBC, 0x0B, 0x76, 0x16, 0x82, 0x83, - 0x27, 0x3D, 0x1D, 0x19, 0x15, 0x78, 0x08, 0x2B, 0xD4, 0xA7, - 0xC2, 0x0F, 0x11, 0xF4, 0xDD, 0xE5, 0x5A, 0x5D, 0x04, 0x8D, - 0x6D, 0x5E, 0xC4, 0x1F, 0x54, 0x44, 0xA9, 0x13, 0x34, 0x71, - 0x0F, 0xF7, 0x57, 0x9A, 0x9F, 0x2E, 0xF4, 0x97, 0x7D, 0xAE, - 0x28, 0xEF}; + 0x01, 0x5C, 0x23, 0xC0, 0xBE, 0xAD, 0x1E, 0x44, 0x60, 0xD4, + 0xE0, 0x81, 0x38, 0xF2, 0xBA, 0xF5, 0xB5, 0x37, 0x5A, 0x34, + 0xB5, 0xCA, 0x6B, 0xC8, 0x0F, 0xCD, 0x75, 0x1D, 0x5E, 0xC0, + 0x8A, 0xD3, 0xD7, 0x79, 0xA7, 0xC1, 0xB8, 0xA2, 0xC6, 0xEA, + 0x5A, 0x7D, 0x60, 0x66, 0x50, 0x97, 0x37, 0x6C, 0xF9, 0x0A, + 0xF6, 0x3D, 0x77, 0x9A, 0xE2, 0x19, 0xF7, 0xF9, 0xDD, 0x52, + 0xC4, 0x0F, 0x98, 0xAA, 0xA2, 0xA4, 0x01, 0xC9, 0x41, 0x0B, + 0xD0, 0x25, 0xDD, 0xC9, 0x7C, 0x3F, 0x70, 0x32, 0x23, 0xCF, + 0xFE, 0x37, 0x67, 0x3A, 0xBC, 0x0B, 0x76, 0x16, 0x82, 0x83, + 0x27, 0x3D, 0x1D, 0x19, 0x15, 0x78, 0x08, 0x2B, 0xD4, 0xA7, + 0xC2, 0x0F, 0x11, 0xF4, 0xDD, 0xE5, 0x5A, 0x5D, 0x04, 0x8D, + 0x6D, 0x5E, 0xC4, 0x1F, 0x54, 0x44, 0xA9, 0x13, 0x34, 0x71, + 0x0F, 0xF7, 0x57, 0x9A, 0x9F, 0x2E, 0xF4, 0x97, 0x7D, 0xAE, + 0x28, 0xEF}; d_crypto->set_public_key(publicKey); bool result = d_crypto->verify_signature_ecdsa_p521(message, signature); From 02c5d26dcc3c2e407180609149a586569a1ead40 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Tue, 30 Jul 2024 18:09:07 +0200 Subject: [PATCH 196/219] [TAS-250] (x3) [FEAT] Implement PK renewal and revocation. Bugfix for DS length computation. * it was based on the HF field, which is not correct. It was discovered when the PK was P521 instead of P256 then the Padding size check was failing due to this. * The solution is temporary: ** GNSS_Crypto: when reading the key, the type is inferred (only for OSSL for the moment) ** when PK comes through the satellites, the public key type is taken from the NPKT field. --- src/core/libs/osnma_msg_receiver.cc | 10 ++++++---- src/core/system_parameters/Galileo_OSNMA.h | 6 ++---- src/core/system_parameters/gnss_crypto.cc | 11 +++++++++++ src/core/system_parameters/gnss_crypto.h | 1 + 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 308dd5a6d..b7eb88af4 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -459,9 +459,8 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg const uint16_t l_lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; d_osnma_data.d_dsm_kroot_message.kroot = d_dsm_reader->get_kroot(dsm_msg, l_lk_bytes); // DS field - std::string hash_function = d_dsm_reader->get_hash_function(d_osnma_data.d_dsm_kroot_message.hf); uint16_t l_ds_bits = 0; - const auto it = OSNMA_TABLE_15.find(hash_function); + const auto it = OSNMA_TABLE_15.find(d_crypto->d_PublicKeyType); if (it != OSNMA_TABLE_15.cend()) { l_ds_bits = it->second; @@ -596,9 +595,11 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_osnma_data.d_dsm_pkr_message.npktid = npktid; uint32_t l_npk_bytes = 0; + std::string PKT; const auto it = OSNMA_TABLE_5.find(d_osnma_data.d_dsm_pkr_message.npkt); if (it != OSNMA_TABLE_5.cend()) { + PKT = it->second; const auto it2 = OSNMA_TABLE_6.find(it->second); if (it2 != OSNMA_TABLE_6.cend()) { @@ -648,6 +649,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_new_public_key = d_osnma_data.d_dsm_pkr_message.npk; } else { + d_crypto->d_PublicKeyType = PKT; d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk); d_crypto->store_public_key(PEMFILE_DEFAULT); } @@ -1159,8 +1161,8 @@ bool osnma_msg_receiver::verify_dsm_pkr(const DSM_PKR_message& message) const if (computed_merkle_root == d_crypto->get_merkle_root()) { - LOG(INFO) << "Galileo OSNMA: DSM-PKR verification for Message ID " << msg_id << " :: SUCCESS."; - std::cout << "Galileo OSNMA: DSM-PKR verification for Message ID " << msg_id << " :: SUCCESS." << std::endl; + LOG(INFO) << "Galileo OSNMA: DSM-PKR verification for Message ID " << msg_id << " :: SUCCESS. PKID=" << static_cast(message.npktid); + std::cout << "Galileo OSNMA: DSM-PKR verification for Message ID " << msg_id << " :: SUCCESS. PKID=" << static_cast(message.npktid) << std::endl; return true; } else diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index bdfc76a11..68c374a8b 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -92,7 +92,7 @@ const std::unordered_map OSNMA_TABLE_6 = { {std::string("ECDSA P-256"), 264}, {std::string("ECDSA P-521"), 536}}; -// OSNMA User ICD for the Test Phase, Issue 1.0, Table 7 +// OSNMA User ICD, Issue 1.1, Table 7 const std::unordered_map> OSNMA_TABLE_7 = { {0, {0, 0}}, {1, {7, 728}}, @@ -156,9 +156,7 @@ const std::unordered_map OSNMA_TABLE_11 = { const std::unordered_map OSNMA_TABLE_15 = { {std::string("ECDSA P-256"), 512}, - {std::string("ECDSA P-521"), 1056}, - {std::string("SHA-256"), 512}, - {std::string("SHA-512"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} + {std::string("ECDSA P-521"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} const std::string PEMFILE_DEFAULT("./data/OSNMA_PublicKey.pem"); const std::string CRTFILE_DEFAULT("./data/OSNMA_PublicKey_20240115100000_newPKID_1.crt"); diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index a2543d18a..4faa8a30a 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -1189,6 +1189,17 @@ 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 + auto 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) { diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index c4e9f4e96..6aa347bb0 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -72,6 +72,7 @@ public: void set_public_key(const std::vector& publickey); //!< Sets the ECDSA Public Key (publickey compressed format) void set_merkle_root(const std::vector& 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; private: void readPublicKeyFromPEM(const std::string& pemFilePath); From 2db37f384e50325a311b9a231878c619c2946746 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Wed, 31 Jul 2024 17:08:06 +0200 Subject: [PATCH 197/219] [TAS-242][FEAT] Implement alert message handling * Test show that behavior is as expected. * interestingly, the first batch of Tags after OAM received fail, then succeeds, until OAM is verified and OSNMA is disabled. --- .../galileo_telemetry_decoder_gs.cc | 28 +------- src/core/libs/osnma_msg_receiver.cc | 64 ++++++++++++++----- src/core/libs/osnma_msg_receiver.h | 7 +- .../osnma/osnma_test_vectors.cc | 40 +++++++++++- 4 files changed, 92 insertions(+), 47 deletions(-) diff --git a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc index e83bfb05c..6c72f1b8c 100644 --- a/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc +++ b/src/algorithms/telemetry_decoder/gnuradio_blocks/galileo_telemetry_decoder_gs.cc @@ -370,9 +370,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in // 1. De-interleave std::vector page_part_symbols_soft_value(frame_length); deinterleaver(GALILEO_INAV_INTERLEAVER_ROWS, GALILEO_INAV_INTERLEAVER_COLS, page_part_symbols, page_part_symbols_soft_value.data()); - bool flag_osnma_adkd_4_gst = false; - bool flag_osnma_adkd_4_utc = false; - // 2. Viterbi decoder // 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder) for (int32_t i = 0; i < frame_length; i++) @@ -443,8 +440,7 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in // 4. Push the new navigation data to the queues // extract OSNMA bits, reset container. - bool check_size_is_ok = d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549; - if (check_size_is_ok) + if (d_inav_nav.get_osnma_adkd_0_12_nav_bits().size() == 549) { DLOG(INFO) << "Galileo OSNMA: new ADKD=0/12 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW5() - 25; const auto tmp_obj_osnma = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> @@ -452,14 +448,9 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_inav_nav.get_osnma_adkd_0_12_nav_bits(), d_inav_nav.get_TOW5() - 25); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj_osnma)); - DLOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d=" - << static_cast(d_satellite.get_PRN()) - << ", TOW=" << static_cast(d_inav_nav.get_TOW5() - 25) << ")"; //: 0b" << d_inav_nav.get_osnma_adkd_0_12_nav_bits(); d_inav_nav.reset_osnma_nav_bits_adkd0_12(); } - - check_size_is_ok = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; - if (check_size_is_ok) + if (d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141) { DLOG(INFO) << "Galileo OSNMA: new ADKD=4 navData from " << d_satellite << " at TOW_sf=" << d_inav_nav.get_TOW6() - 5; const auto tmp_obj = std::make_shared>( // < PRNd , navDataBits, TOW_Sosf> // TODO conversion from W6 to W_Start_of_subframe @@ -467,9 +458,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_inav_nav.get_osnma_adkd_4_nav_bits(), d_inav_nav.get_TOW6() - 5); this->message_port_pub(pmt::mp("OSNMA_from_TLM"), pmt::make_any(tmp_obj)); - DLOG(INFO) << "|---> Galileo OSNMA :: Sending Telemetry Decoder NavData (PRN_d=" - << static_cast(d_satellite.get_PRN()) - << ", TOW=" << static_cast(d_inav_nav.get_TOW6() - 5) << ")"; //: 0b" << d_inav_nav.get_osnma_adkd_4_nav_bits(); d_inav_nav.reset_osnma_nav_bits_adkd4(); } @@ -588,8 +576,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in d_delta_t = tmp_obj->A_0G + tmp_obj->A_1G * (static_cast(d_TOW_at_current_symbol_ms) / 1000.0 - tmp_obj->t_0G + 604800 * (std::fmod(static_cast(d_inav_nav.get_Galileo_week() - tmp_obj->WN_0G), 64.0))); DLOG(INFO) << "delta_t=" << d_delta_t << "[s]"; - - flag_osnma_adkd_4_utc = true; } if (d_inav_nav.have_new_almanac() == true) // flag_almanac_4 tells if W10 available. @@ -623,16 +609,6 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in DLOG(INFO) << "Current parameters:"; DLOG(INFO) << "d_TOW_at_current_symbol_ms=" << d_TOW_at_current_symbol_ms; DLOG(INFO) << "d_nav.WN_0=" << d_inav_nav.get_Galileo_week(); - - flag_osnma_adkd_4_gst = true; - } - - // get osnma message if the needed nav data is available - bool adkd_4_nav_data_available = flag_osnma_adkd_4_utc && flag_osnma_adkd_4_gst; // supposition: data did not change bt. flags reset and now. - - // bool adkd_4_nav_data_available = d_inav_nav.get_osnma_adkd_4_nav_bits().size() == 141; // newApproach: let decoder decide when block starts and let it fill the data, and just check for length - if (adkd_4_nav_data_available /*&& d_inav_nav.is_TOW5_set() not needed cause W6 has TOW also.*/) - { } auto newOSNMA = d_inav_nav.have_new_nma(); if (d_band == '1' && newOSNMA) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index b7eb88af4..1e85e3a89 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -142,12 +142,11 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) } // OSNMA frame received else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) // Navigation data bits for OSNMA received { - // TODO - PRNa is a typo here, I think for d_satellite_nav_data, is PRN_d the name to use const auto inav_data = wht::any_cast>>(pmt::any_ref(msg)); - uint32_t PRNa = std::get<0>(*inav_data); + uint32_t PRNd = std::get<0>(*inav_data); std::string nav_data = std::get<1>(*inav_data); uint32_t TOW = std::get<2>(*inav_data); - d_nav_data_manager->add_navigation_data(nav_data, PRNa, TOW); + d_nav_data_manager->add_navigation_data(nav_data, PRNd, TOW); } else { @@ -173,6 +172,9 @@ 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) { + 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 @@ -180,7 +182,8 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& 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. 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); @@ -195,7 +198,7 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& 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; @@ -214,6 +217,14 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& 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){ + 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; + d_kroot_verified = false; + LOG(INFO) << "Galileo OSNMA: Alert message :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]"; + std::cout << "Galileo OSNMA: Alert message :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << std::endl; + } read_dsm_header(osnma_msg->hkroot[1]); read_dsm_block(osnma_msg); @@ -533,8 +544,9 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; // 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){ - // set new public key to be used. d_crypto->set_public_key(d_new_public_key); d_crypto->store_public_key(PEMFILE_DEFAULT); d_flag_NPK_set = true; @@ -551,9 +563,15 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg { std::cout << "Galileo OSNMA: DSM-KROOT authentication successful!" << std::endl; LOG(INFO) << "Galileo OSNMA: DSM-KROOT authentication successful!"; - LOG(INFO) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " - << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " - << "Chain and Public Key Status is " << d_dsm_reader->get_cpks_status(d_osnma_data.d_nma_header.cpks); + if (d_flag_alert_message){ + LOG(WARNING) << "Galileo OSNMA: DSM-KROOT :: Alert message verification :: SUCCESS. "; + } + else + { + LOG(INFO) << "Galileo OSNMA: NMA Status is " << d_dsm_reader->get_nmas_status(d_osnma_data.d_nma_header.nmas) << ", " + << "Chain in force is " << static_cast(d_osnma_data.d_nma_header.cid) << ", " + << "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){ d_flag_hot_start = false; @@ -565,6 +583,9 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& 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){ + d_flag_alert_message = false; + } d_count_failed_Kroot ++; } } @@ -607,9 +628,10 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } } uint32_t l_dp_bytes = dsm_msg.size(); - if (d_osnma_data.d_dsm_pkr_message.npkt == 4) + if (d_osnma_data.d_dsm_pkr_message.npkt == 4 && d_osnma_data.d_dsm_pkr_message.npktid == 0) { - LOG(WARNING) << "Galileo OSNMA: OAM received"; + LOG(WARNING) << "Galileo OSNMA: DSM-PKR :: Alert message received. Verifying it."; + std::cout << "Galileo OSNMA: DSM-PKR :: Alert message received. Verifying it." << std::endl; l_npk_bytes = l_dp_bytes - 130; // bytes } @@ -624,6 +646,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg if (l_dp_bytes != check_l_dp_bytes) { LOG(WARNING) << "Galileo OSNMA: Failed length reading of DSM-PKR message"; + d_flag_alert_message = false; } else { @@ -635,10 +658,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // TODO: kroot fields are 0 in case no DSM-KROOT received yet, need to take this into account. // std::vector mi; // (NPKT + NPKID + NPK) LOG(INFO) << "Galileo OSNMA: DSM-PKR with CID=" << static_cast(d_osnma_data.d_nma_header.cid) - << ", PKID=" << static_cast(d_osnma_data.d_dsm_pkr_message.npktid) - /*<< ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) - << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600*/ - << " received"; + << ", PKID=" << static_cast(d_osnma_data.d_dsm_pkr_message.npktid) << " received"; // Public key verification against Merkle tree root. bool verification = verify_dsm_pkr(d_osnma_data.d_dsm_pkr_message); if (verification) @@ -648,7 +668,12 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg if (d_flag_PK_renewal){ d_new_public_key = d_osnma_data.d_dsm_pkr_message.npk; } - else { + 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; d_crypto->set_public_key(d_osnma_data.d_dsm_pkr_message.npk); d_crypto->store_public_key(PEMFILE_DEFAULT); @@ -659,6 +684,10 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& 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_flag_alert_message = false; // disregard message as its authenticity could not be verified. + + } } } } @@ -692,7 +721,8 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrTOW_sf0); - bool can_process_mack_block = d_osnma_data.d_nma_header.nmas != 3; // Don't Use + 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) diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 97713a79a..59158ab4c 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -62,8 +62,8 @@ 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 + ~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 private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); @@ -134,6 +134,7 @@ private: uint32_t d_GST_0{}; uint32_t d_GST_SIS{}; uint32_t d_GST_PKR_PKREV_start{}; + uint32_t d_GST_PKR_AM_start{}; uint8_t d_Lt_min{}; // minimum equivalent tag length uint8_t d_Lt_verified_eph{0}; // verified tag bits - ephemeris @@ -152,6 +153,7 @@ private: uint8_t d_new_public_key_id{}; std::vector d_new_public_key; bool d_flag_NPK_set{false}; + bool d_flag_alert_message{false}; // Provide access to inner functions to Gtest uint32_t d_count_successful_tags{0}; @@ -169,6 +171,7 @@ private: FRIEND_TEST(OsnmaTestVectors, NominalTestConf2); FRIEND_TEST(OsnmaTestVectors, PublicKeyRenewal); FRIEND_TEST(OsnmaTestVectors, PublicKeyRevocation); + FRIEND_TEST(OsnmaTestVectors, AlertMessage); }; 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 e640e6b50..0b525805c 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 @@ -181,6 +181,42 @@ TEST_F(OsnmaTestVectors, PublicKeyRevocation) ASSERT_EQ(osnma->d_count_failed_pubKey, 0); ASSERT_EQ(osnma->d_count_failed_macseq, 0); } + +TEST_F(OsnmaTestVectors, AlertMessage){ + // Arrange + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_3/PublicKey/OSNMA_PublicKey_20231007201500_PKID_1.crt"; + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_3/MerkleTree/OSNMA_MerkleTree_20231007201500_PKID_1.xml"; + osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + + std::tm input_time_step1 = {0, 45, 18, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::tm input_time_step2 = {0, 45, 19, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::vector input_times = { input_time_step1, input_time_step2 }; + + std::vector testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/oam_step1/07_OCT_2023_GST_18_45_01.csv"); + std::vector testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/oam_step2/07_OCT_2023_GST_19_45_01.csv"); + if (testVectors_step1.empty() || testVectors_step2.empty()) + { + ASSERT_TRUE(false); + } + std::vector> testVectors = { testVectors_step1, testVectors_step2}; + + // Act + bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); + ASSERT_TRUE(result); + + // Assert + LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags; + LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags; + LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size(); + LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot; + LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey; + LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq; + ASSERT_EQ(osnma->d_count_failed_tags, 0); + ASSERT_EQ(osnma->d_count_failed_Kroot, 0); + ASSERT_EQ(osnma->d_count_failed_pubKey, 0); + ASSERT_EQ(osnma->d_count_failed_macseq, 0); +} + // Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. // Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_object, std::vector> testVectors, std::vector startTimesFiles){ @@ -338,7 +374,7 @@ bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_ob tv.svId, nav_data_ADKD_0_12, osnmaMsg_sptr->TOW_sf0); - LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12; + // LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_0_12; osnma_object->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); } } @@ -375,7 +411,7 @@ bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_ob tv.svId, nav_data_ADKD_4, osnmaMsg_sptr->TOW_sf0); - LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4; + // LOG(INFO) << "|---> Galileo OSNMA :: Telemetry Decoder NavData (PRN_d=" << static_cast(tv.svId) << ", TOW=" << static_cast(osnmaMsg_sptr->TOW_sf0) << "): 0b" << nav_data_ADKD_4; osnma_object->msg_handler_osnma(pmt::make_any(tmp_obj_osnma)); } } From a47cf1187c1983729ca627b1de63c52fccb0a468 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 1 Aug 2024 11:52:28 +0200 Subject: [PATCH 198/219] [TAS-255] [BUG] Assure time synch. is properly done if d_flag_debug=false, now system clock is used to for the receiver synchronisation. It uses the UTC time and the GST epoch start time (adjusted for local time zone difference) to create a local estimation of GST, then compares with GST_SIS (coming from NavData Words 5 and 6) --- src/core/libs/osnma_msg_receiver.cc | 185 ++++++++---------- src/core/libs/osnma_msg_receiver.h | 30 +-- src/core/system_parameters/osnma_helper.cc | 41 +++- src/core/system_parameters/osnma_helper.h | 8 + .../osnma/osnma_msg_receiver_test.cc | 5 +- 5 files changed, 141 insertions(+), 128 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 1e85e3a89..7035a9e08 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -112,6 +112,21 @@ osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, const std boost::bind(&osnma_msg_receiver::msg_handler_osnma, this, _1)); #endif #endif + std::chrono::time_point now; + 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{ + 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; } @@ -138,6 +153,50 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) LOG(INFO) << output_message.str(); std::cout << output_message.str() << std::endl; + // 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){ + d_last_received_GST = d_GST_SIS; + } + else if (d_GST_SIS > d_last_received_GST){ + d_last_received_GST = d_GST_SIS; + } + if (d_flag_debug){ + d_GST_Rx = d_last_received_GST; + } + 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) << "]"; + std::cout << "Galileo OSNMA: Receiver Time GST=[" << d_helper->get_WN(d_GST_Rx) << " " << d_helper->get_TOW(d_GST_Rx) << "]" << std::endl; + + // time constraint verification + std::time_t delta_T = std::abs(static_cast(d_GST_Rx - d_GST_SIS)); + if (delta_T <= d_T_L) + { + d_tags_to_verify = {0, 4, 12}; + LOG(INFO) << "Galileo OSNMA: time constraint OK ( delta_T=" << delta_T << " s)"; + std::cout << "Galileo OSNMA: time constraint OK ( delta_T=" << delta_T << " s)" << std::endl; + } + else if (delta_T > d_T_L && delta_T <= 10 * d_T_L) + { + d_tags_to_verify = {12}; + LOG(WARNING) << "Galileo OSNMA: time constraint allows only slow MACs to be verified"; + std::cout << "Galileo OSNMA: |local_t - GST_SIS| < T_L [ |" << static_cast(d_GST_Rx - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; + LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_GST_Rx << " d_GST_SIS: " << d_GST_SIS; + LOG(WARNING) << "Galileo OSNMA: |local_t - GST_SIS| < T_L [ |" << static_cast(d_GST_Rx - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; + } + else + { + d_tags_to_verify = {}; + LOG(WARNING) << "Galileo OSNMA: time constraint violation"; + std::cerr << "Galileo OSNMA: time constraint violation" << std::endl; + std::cerr << "Galileo OSNMA: | local_t - GST_SIS | < T_L [ | " << static_cast(d_GST_Rx - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]" << std::endl; + LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_GST_Rx << " d_GST_SIS: " << d_GST_SIS; + LOG(WARNING) << "Galileo OSNMA: | local_t - GST_SIS | < T_L [ | " << static_cast(d_GST_Rx - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; + return; + } + process_osnma_message(nma_msg); } // OSNMA frame received else if (msg_type_hash_code == typeid(std::shared_ptr>).hash_code()) // Navigation data bits for OSNMA received @@ -159,7 +218,7 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) } // Send the resulting decoded NMA data (if available) to PVT - if (d_new_data) // TODO where is it set to true? + if (d_new_data) { auto osnma_data_ptr = std::make_shared(d_osnma_data); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(osnma_data_ptr)); @@ -177,13 +236,14 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& } read_nma_header(osnma_msg->hkroot[0]); - // Check for corner cases: renewal, revocation + // Check for corner cases: renewal, revocation, alert message 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){ d_flag_PK_renewal = true; d_GST_PKR_PKREV_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); @@ -229,9 +289,9 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& 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) - { - local_time_verification(osnma_msg); + 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. } read_and_process_mack_block(osnma_msg); // only process them if at least 3 available. } @@ -350,63 +410,6 @@ void osnma_msg_receiver::read_dsm_block(const std::shared_ptr& osnma_ std::cout << available_blocks.str() << std::endl; } - -/** - * @brief Function to verify the local time based on GST_SIS and GST_0 - * - * @param osnma_msg Shared pointer to OSNMA message structure - */ -void osnma_msg_receiver::local_time_verification(const std::shared_ptr& osnma_msg) -{ - // compute local time based on GST_SIS and GST_0 - d_GST_SIS = (osnma_msg->WN_sf0 & 0x00000FFF) << 20 | (osnma_msg->TOW_sf0 & 0x000FFFFF); - // std::cout << "Galileo OSNMA: d_GST_SIS: " << d_GST_SIS << std::endl; - // d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; - d_GST_0 = ((d_osnma_data.d_dsm_kroot_message.wn_k & 0x00000FFF) << 20 | (d_osnma_data.d_dsm_kroot_message.towh_k * 3600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) - // d_GST_0 = d_osnma_data.d_dsm_kroot_message.towh_k + 604800 * d_osnma_data.d_dsm_kroot_message.wn_k + 30; - // TODO store list of SVs sending OSNMA and if received ID matches one stored, then just increment time 30s for that ID. - if (d_receiver_time != 0) - { - d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G. - // d_receiver_time += 30; - // std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; - } - else - { // local time not initialised -> compute it. - d_receiver_time = d_GST_0 + 30 * std::floor((d_GST_SIS - d_GST_0) / 30); // Eq. 3 R.G. - // std::cout << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << std::endl; - } - // verify time constraint - std::time_t delta_T = std::abs(static_cast(d_receiver_time - d_GST_SIS)); - if (delta_T <= d_T_L) - { - d_tags_allowed = tags_to_verify::all; - d_tags_to_verify = {0, 4, 12}; - LOG(INFO) << "Galileo OSNMA: time constraint OK ( delta_T=" << delta_T << " s)"; - // LOG(INFO) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS; - // std::cout << "( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS)<< " | < " << static_cast(d_T_L) << " ]" << std::endl; - - // TODO set flag to false to avoid processing dsm and MACK messages - } - else if (delta_T > d_T_L && delta_T <= 10 * d_T_L) - { - d_tags_allowed = tags_to_verify::slow_eph; - d_tags_to_verify = {12}; - LOG(WARNING) << "Galileo OSNMA: time constraint allows only slow MACs to be verified"; - LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS; - LOG(WARNING) << "Galileo OSNMA: ( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; - } - else - { - d_tags_allowed = tags_to_verify::none; - d_tags_to_verify = {}; - LOG(WARNING) << "Galileo OSNMA: time constraint violation"; - LOG(WARNING) << "Galileo OSNMA: d_receiver_time: " << d_receiver_time << " d_GST_SIS: " << d_GST_SIS; - LOG(WARNING) << "Galileo OSNMA: ( |local_t - GST_SIS| < T_L ) [ |" << static_cast(d_receiver_time - d_GST_SIS) << " | < " << static_cast(d_T_L) << " ]"; - } -} - - /** * @brief Process DSM block of an OSNMA message. * @@ -671,7 +674,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg 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; @@ -686,7 +688,6 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg d_count_failed_pubKey ++; if (d_flag_alert_message){ d_flag_alert_message = false; // disregard message as its authenticity could not be verified. - } } } @@ -697,7 +698,7 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg LOG(WARNING) << "Galileo OSNMA: Reserved message received"; std::cerr << "Galileo OSNMA: Reserved message received" << std::endl; } - d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; // TODO - reset during header parsing in PKREV? + d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; // TODO - reset during header parsing in PKREV? } @@ -725,8 +726,7 @@ void osnma_msg_receiver::read_and_process_mack_block(const std::shared_ptrPRN; // FIXME this is ugly. d_osnma_data.d_mack_message.TOW = osnma_msg->TOW_sf0; @@ -1012,14 +1012,8 @@ void osnma_msg_receiver::process_mack_message() { LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed, " << "no Kroot nor TESLA key available."; - if (!d_flag_debug) - { - return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. - } - else - { - LOG(WARNING) << "Galileo OSNMA: But it will be processed for debugging purposes."; - } + return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. + } // verify tesla key and add it to the container of verified keys if successful if (d_tesla_keys.find(d_osnma_data.d_nav_data.get_tow_sf0()) == d_tesla_keys.end()) // check if already available => no need to verify @@ -1425,14 +1419,14 @@ void osnma_msg_receiver::display_data() bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TOW) { uint32_t num_of_hashes_needed; - uint32_t GST_SFi = d_receiver_time - 30; // GST of target key is to be used. + uint32_t GST_SFi = d_GST_Sf - 30; // GST of target key is to be used. std::vector hash; const uint8_t lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; std::vector validated_key; if (d_tesla_key_verified) { // have to go up to last verified key validated_key = d_tesla_keys.rbegin()->second; - num_of_hashes_needed = (d_receiver_time - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified + num_of_hashes_needed = (d_GST_Sf - d_last_verified_key_GST) / 30; // Eq. 19 ICD modified LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to closest verified TESLA key"; hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); @@ -1440,7 +1434,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO else { // have to go until Kroot validated_key = d_osnma_data.d_dsm_kroot_message.kroot; - num_of_hashes_needed = (d_receiver_time - d_GST_0) / 30 + 1; // Eq. 19 IC + num_of_hashes_needed = (d_GST_Sf - d_GST_0) / 30 + 1; // Eq. 19 IC LOG(INFO) << "Galileo OSNMA: TESLA verification (" << num_of_hashes_needed << " hashes) need to be performed up to Kroot"; hash = hash_chain(num_of_hashes_needed, key, GST_SFi, lk_bytes); @@ -1458,24 +1452,16 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO std::cout << "Galileo OSNMA: TESLA key verification :: SUCCESS!" << std::endl; d_tesla_keys.insert(std::pair>(TOW, key)); d_tesla_key_verified = true; - d_last_verified_key_GST = d_receiver_time; + d_last_verified_key_GST = d_GST_Sf; } else if (num_of_hashes_needed > 0) { LOG(WARNING) << "Galileo OSNMA: TESLA key verification :: FAILED"; std::cerr << "Galileo OSNMA: TESLA key verification :: FAILED" << std::endl; - if (d_flag_debug) - { - d_tesla_keys.insert(std::pair>(TOW, key)); - d_last_verified_key_GST = d_receiver_time; - d_tesla_key_verified = true; - // TODO - if intermediate verification fails, can one still use the former verified tesla key or should go to Kroot or even retrieve new Kroot? - } } return d_tesla_key_verified; } - /** * @brief Removes the tags that have been verified from the multimap d_tags_awaiting_verify. * @@ -1582,7 +1568,7 @@ void osnma_msg_receiver::control_tags_awaiting_verify_size() bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) { // MACSEQ verification - d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received.. + uint32_t GST_SFi = d_GST_Sf - 30; // time of the start of SF containing MACSEQ std::vector applicable_key = d_tesla_keys[mack.TOW + 30]; // current tesla key ie transmitted in the next subframe std::vector sq1{}; std::vector sq2{}; @@ -1594,7 +1580,6 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) sq1 = it->second.sequence1; sq2 = it->second.sequence2; } - // Assign relevant sequence based on subframe time if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present. { @@ -1633,12 +1618,12 @@ 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 m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag - m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); // TODO d_GST_Sf left useless - m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); - m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); - m[4] = static_cast(d_GST_Sf & 0x000000FF); + m[1] = static_cast((GST_SFi & 0xFF000000) >> 24); + m[2] = static_cast((GST_SFi & 0x00FF0000) >> 16); + m[3] = static_cast((GST_SFi & 0x0000FF00) >> 8); + m[4] = static_cast(GST_SFi & 0x000000FF); // Case tags flexible - Eq. 21 ICD for (size_t i = 0; i < flxTags.size(); i++) { @@ -1823,7 +1808,7 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ std::vector verified_tags{}; // MACSEQ verification - d_GST_Sf = d_receiver_time - 30; // time of the start of SF containing MACSEQ // TODO buffer with times? since out of debug not every 30 s a Sf is necessarily received. + uint32_t GST_Sfi = d_GST_Sf - 30; // time of the start of SF containing MACSEQ std::vector applicable_key; const auto key_it = d_tesla_keys.find(mack.TOW + 30); // current tesla key ie transmitted in the next subframe if (key_it != d_tesla_keys.cend()) @@ -1889,12 +1874,12 @@ std::vector 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 m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag - m[1] = static_cast((d_GST_Sf & 0xFF000000) >> 24); // TODO d_GST_Sf left useless - m[2] = static_cast((d_GST_Sf & 0x00FF0000) >> 16); - m[3] = static_cast((d_GST_Sf & 0x0000FF00) >> 8); - m[4] = static_cast(d_GST_Sf & 0x000000FF); + m[1] = static_cast((GST_Sfi & 0xFF000000) >> 24); + m[2] = static_cast((GST_Sfi & 0x00FF0000) >> 16); + m[3] = static_cast((GST_Sfi & 0x0000FF00) >> 8); + m[4] = static_cast(GST_Sfi & 0x000000FF); // Case tags flexible - Eq. 21 ICD for (size_t i = 0; i < flxTags.size(); i++) { diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 59158ab4c..fb83f2b8c 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -73,7 +73,6 @@ private: void read_nma_header(uint8_t nma_header); void read_dsm_header(uint8_t dsm_header); void read_dsm_block(const std::shared_ptr& osnma_msg); - void local_time_verification(const std::shared_ptr& osnma_msg); void process_dsm_block(const std::shared_ptr& osnma_msg); void process_dsm_message(const std::vector& dsm_msg, const uint8_t& nma_header); void read_and_process_mack_block(const std::shared_ptr& osnma_msg); @@ -118,35 +117,24 @@ private: OSNMA_data d_osnma_data{}; - enum tags_to_verify - { - all, - utc, - slow_eph, - eph, - none - }; - tags_to_verify d_tags_allowed{tags_to_verify::all}; - std::time_t d_receiver_time{0}; - - uint32_t d_GST_Sf{}; // C: used for MACSEQ and Tesla Key verification TODO need really to be global var? - uint32_t d_last_verified_key_GST{0}; - uint32_t d_GST_0{}; - uint32_t d_GST_SIS{}; + uint32_t d_last_received_GST{0}; // latest GST received + uint32_t d_GST_Sf{}; // Scaled GST time for cryptographic computations + uint32_t d_GST_Rx{0}; // local GST receiver time + uint32_t d_last_verified_key_GST{0}; // GST for the latest verified TESLA key + uint32_t d_GST_0{}; // Time of applicability GST (KROOT + 30 s) + uint32_t d_GST_SIS{}; // GST coming from W6 and W5 of SIS uint32_t d_GST_PKR_PKREV_start{}; uint32_t d_GST_PKR_AM_start{}; + uint32_t d_WN{}; + uint32_t d_TOW{}; - uint8_t d_Lt_min{}; // minimum equivalent tag length - uint8_t d_Lt_verified_eph{0}; // verified tag bits - ephemeris - uint8_t d_Lt_verified_utc{0}; // verified tag bits - timing uint8_t const d_T_L{30}; // s RG Section 2.1 - uint8_t const d_delta_COP{30}; // s SIS ICD Table 14 bool d_new_data{false}; bool d_public_key_verified{false}; bool d_kroot_verified{false}; bool d_tesla_key_verified{false}; - bool d_flag_debug{false}; + bool d_flag_debug{true}; bool d_flag_hot_start{false}; bool d_flag_PK_renewal{false}; bool d_flag_PK_revocation{false}; diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index f8650ed3f..3ce589302 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -19,13 +19,37 @@ #include #include #include +#include // timezone -uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const -{ - uint32_t GST = (WN & 0x00000FFF) << 20 | (TOW & 0x000FFFFF); - return GST; +uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const{ + return (WN & 0x00000FFF) << 20 | (TOW & 0x000FFFFF); } +uint32_t Osnma_Helper::compute_gst(tm& input) +{ + auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH)); + auto input_time_point = std::chrono::system_clock::from_time_t(mktime(&input)); + + // Get the duration from epoch in seconds + auto duration_sec = std::chrono::duration_cast(input_time_point - epoch_time_point); + + // Calculate the week number (WN) and time of week (TOW) + uint32_t sec_in_week = 7 * 24 * 60 * 60; + uint32_t week_number = duration_sec.count() / sec_in_week; + uint32_t time_of_week = duration_sec.count() % sec_in_week; + return compute_gst(week_number, time_of_week); +} + +uint32_t Osnma_Helper::compute_gst_now() +{ + std::chrono::time_point epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH) - timezone); +// auto time_utc = std::chrono::time_point_cast(time).time_since_epoch(); + auto duration_sec = std::chrono::duration_cast(std::chrono::system_clock::now() - epoch_time_point); + uint32_t sec_in_week = 7 * 24 * 60 * 60; + uint32_t week_number = duration_sec.count() / sec_in_week; + uint32_t time_of_week = duration_sec.count() % sec_in_week; + return compute_gst(week_number, time_of_week); +} std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const { @@ -121,3 +145,12 @@ std::vector Osnma_Helper::convert_from_hex_string(const std::string& he return result; } +uint32_t Osnma_Helper::get_WN(uint32_t GST) +{ + return (GST & 0xFFF00000) >> 20; +} +uint32_t Osnma_Helper::get_TOW(uint32_t GST) +{ + return GST & 0x000FFFFF; +} + diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 1e0eae235..ea4e81313 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -18,6 +18,7 @@ #define GNSS_SDR_OSNMA_HELPER_H +#include #include #include #include @@ -27,11 +28,18 @@ public: Osnma_Helper() = default; ~Osnma_Helper() = default; uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; + uint32_t compute_gst(std::tm& input); + uint32_t compute_gst_now(); + uint32_t get_WN(uint32_t GST); + uint32_t get_TOW(uint32_t GST); std::vector gst_to_uint8(uint32_t GST) const; std::vector bytes(const std::string& binaryString) const; std::string verification_status_str(int status) const; std::string convert_to_hex_string(const std::vector& vector) const; std::vector convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto + + std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; + }; #endif // GNSS_SDR_OSNMA_HELPER_H diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 7dd2e7a8d..5d5e3819f 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -252,10 +252,9 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; - // local_time_verification would do this operation. TODO - eliminate duplication. osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); - osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) - osnma->d_receiver_time = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G.//345630; + osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + osnma->d_GST_Sf = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G. osnma->d_tesla_keys.insert((std::pair>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 From fcea84d875beef460dcea3831c72a20d082db481 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 1 Aug 2024 11:53:02 +0200 Subject: [PATCH 199/219] disable extra unit tests for the moment. --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e4bd9f38d..ea0a516da 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: run: cd build && ninja check && ../install/volk_gnsssdr_profile && ../install/run_tests - name: default position_test run: | - cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. && \ + cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=OFF .. && \ ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma* build-macos: @@ -69,7 +69,7 @@ jobs: run: cd build && ninja check && ../install/volk_gnsssdr_profile && ../install/run_tests - name: default position_test run: | - cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. && \ + cd build && cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=OFF .. && \ ninja && ../install/position_test && ../install/run_tests --gtest_filter=Osnma* build-macos-xcode: @@ -108,7 +108,7 @@ jobs: - name: default position_test run: | cd build - cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=ON .. + cmake -DENABLE_SYSTEM_TESTING_EXTRA=ON -DENABLE_UNIT_TESTING_EXTRA=OFF .. xcodebuild -configuration Release -target position_test ../install/position_test ../install/run_tests --gtest_filter=Osnma* From eefa3b3aa76f503c33da2be6302fdac74112bf86 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 1 Aug 2024 12:46:14 +0200 Subject: [PATCH 200/219] Update CMake scripts (#15) * Report GMP version if found * Bump local version of GoogleTest to 1.15.2 and Protocol Buffers to 27.3 * Avoid code duplication in CMake modules * Update CMake modules * Update clang-tidy job --- .github/workflows/main.yml | 2 +- CMakeLists.txt | 5 +- README.md | 8 +-- cmake/Modules/FindCPUFEATURES.cmake | 35 ++-------- cmake/Modules/FindGFLAGS.cmake | 35 ++-------- cmake/Modules/FindGFORTRAN.cmake | 33 ++------- cmake/Modules/FindGLOG.cmake | 35 ++-------- cmake/Modules/FindGMP.cmake | 104 +++++++++------------------- cmake/Modules/FindGNURADIO.cmake | 65 ++--------------- cmake/Modules/FindGRIIO.cmake | 35 ++-------- cmake/Modules/FindGRLIMESDR.cmake | 35 ++-------- cmake/Modules/FindGROSMOSDR.cmake | 35 ++-------- cmake/Modules/FindLIBAD9361.cmake | 35 ++-------- cmake/Modules/FindLIBIIO.cmake | 35 ++-------- cmake/Modules/FindLIBUNWIND.cmake | 5 ++ cmake/Modules/FindLOG4CPP.cmake | 34 ++------- cmake/Modules/FindMATIO.cmake | 32 ++------- cmake/Modules/FindORC.cmake | 46 ++---------- cmake/Modules/FindPCAP.cmake | 32 ++------- cmake/Modules/FindPUGIXML.cmake | 33 ++------- cmake/Modules/FindUHD.cmake | 35 ++-------- cmake/Modules/FindVOLK.cmake | 34 ++------- cmake/Modules/FindZEROMQ.cmake | 32 ++------- cmake/Modules/GnssSdrCrypto.cmake | 42 +++-------- cmake/Modules/GnsssdrLibPaths.cmake | 43 ++++++++++++ 25 files changed, 190 insertions(+), 675 deletions(-) create mode 100644 cmake/Modules/GnsssdrLibPaths.cmake diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ea0a516da..54a478cba 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -151,7 +151,7 @@ jobs: ln -s $(brew --prefix llvm)/bin/clang-apply-replacements /usr/local/bin ln -s $(brew --prefix llvm)/bin/run-clang-tidy.py /usr/local/bin - name: Prepare run - run: cd build && cmake .. && make volk_gnsssdr_module gtest-1.14.0 core_monitor core_libs pvt_libs + run: cd build && cmake .. && make volk_gnsssdr_module gtest-1.15.2 core_monitor core_libs pvt_libs - name: run clang-tidy run: cd build && /opt/homebrew/opt/llvm/bin/run-clang-tidy -fix - name: check diff --git a/CMakeLists.txt b/CMakeLists.txt index b56c29253..eb113bad3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ list(APPEND CMAKE_MODULE_PATH ${GNSSSDR_SOURCE_DIR}/cmake/Modules) # Enable them at the command line by doing 'cmake -DENABLE_XXX=ON ..' ################################################################################ include(FeatureSummary) +include(GnsssdrLibPaths) # Support of optional RF front-ends option(ENABLE_UHD "Enable the use of UHD (driver for all USRP devices)" ON) @@ -353,9 +354,9 @@ set(GNSSSDR_ARMADILLO_LOCAL_VERSION "14.0.x") set(GNSSSDR_GFLAGS_LOCAL_VERSION "2.2.2") set(GNSSSDR_GLOG_LOCAL_VERSION "0.7.1") set(GNSSSDR_MATIO_LOCAL_VERSION "1.5.27") -set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "27.2") +set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "27.3") set(GNSSSDR_PUGIXML_LOCAL_VERSION "1.14") -set(GNSSSDR_GTEST_LOCAL_VERSION "1.14.0") +set(GNSSSDR_GTEST_LOCAL_VERSION "1.15.2") set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "origin/master") set(GNSSSDR_GNSSTK_LOCAL_VERSION "14.3.0") set(GNSSSDR_BENCHMARK_LOCAL_VERSION "1.8.5") diff --git a/README.md b/README.md index 557b3686c..d5cbacc94 100644 --- a/README.md +++ b/README.md @@ -488,8 +488,8 @@ $ sudo ldconfig #### Download [GoogleTest](https://github.com/google/googletest "Googletest Homepage") ``` -$ wget https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip -$ unzip v1.14.0.zip +$ wget https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip +$ unzip v1.15.2.zip ``` Please **DO NOT build or install** Google Test. Every user needs to compile @@ -513,10 +513,10 @@ downloaded resides. Just type in your terminal (or add it to your `$HOME/.bashrc` file for a permanent solution) the following line: ``` -export GTEST_DIR=/home/username/googletest-1.14.0 +export GTEST_DIR=/home/username/googletest-1.15.2 ``` -changing `/home/username/googletest-1.14.0` by the actual path where you +changing `/home/username/googletest-1.15.2` by the actual path where you unpacked Google Test. If the CMake script does not find that folder, or the environment variable is not defined, or the source code is not installed by a package, then it will download a fresh copy of the Google Test source code and diff --git a/cmake/Modules/FindCPUFEATURES.cmake b/cmake/Modules/FindCPUFEATURES.cmake index 7c25e69c2..6f4f0e58f 100644 --- a/cmake/Modules/FindCPUFEATURES.cmake +++ b/cmake/Modules/FindCPUFEATURES.cmake @@ -6,38 +6,13 @@ set(FPHSA_NAME_MISMATCHED ON) +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + find_library(CPUFEATURES_LIBRARIES NAMES cpu_features - PATHS /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + PATHS ${GNSSSDR_LIB_PATHS} ) find_path(CPUFEATURES_INCLUDE_DIR cpu_features_macros.h diff --git a/cmake/Modules/FindGFLAGS.cmake b/cmake/Modules/FindGFLAGS.cmake index 08a5056b8..cbfa07cd3 100644 --- a/cmake/Modules/FindGFLAGS.cmake +++ b/cmake/Modules/FindGFLAGS.cmake @@ -25,6 +25,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT GFLAGS_ROOT) set(GFLAGS_ROOT_USER_PROVIDED /usr/local) else() @@ -52,36 +56,7 @@ else() PATHS ${GFLAGS_ROOT_USER_PROVIDED}/lib ${GFLAGS_ROOT_USER_PROVIDED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) endif() diff --git a/cmake/Modules/FindGFORTRAN.cmake b/cmake/Modules/FindGFORTRAN.cmake index 5a698ce89..26764a688 100644 --- a/cmake/Modules/FindGFORTRAN.cmake +++ b/cmake/Modules/FindGFORTRAN.cmake @@ -8,6 +8,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT GFORTRAN_ROOT) set(GFORTRAN_ROOT_USER_DEFINED /usr/lib) else() @@ -20,13 +24,12 @@ if(DEFINED ENV{GFORTRAN_ROOT}) ) endif() -set(GCC_MAJOR_SERIES 14 13 12 11 10 9 8 7 6 5) +set(GCC_MAJOR_SERIES 15 14 13 12 11 10 9 8 7 6 5) set(GCC4_SERIES 4.9.1 4.9 4.8.3 4.8.1 4.7.2 4.7 4.8.2 4.8 4.7 4.6 4.5 4.4.4 4.4) set(GCC_SERIES ${GCC_MAJOR_SERIES} ${GCC4_SERIES}) find_library(GFORTRAN NAMES gfortran PATHS ${GFORTRAN_ROOT_USER_DEFINED} - /usr/lib64 /usr/lib/gcc/x86_64-linux-gnu # Debian /usr/lib/gcc/i386-linux-gnu /usr/lib/gcc/i486-linux-gnu @@ -65,35 +68,13 @@ find_library(GFORTRAN NAMES gfortran /usr/lib/gcc/x86_64-suse-linux /usr/lib/gcc/armv6hl-suse-linux-gnueabi /usr/lib/gcc/armv7hl-suse-linux-gnueabi + /usr/lib/gcc/loongarch64-linux-gnu /usr/lib64/gcc/aarch64-suse-linux /usr/lib64/gcc/powerpc64-suse-linux /usr/lib64/gcc/powerpc64le-suse-linux /usr/lib64/gcc/riscv64-suse-linux /usr/lib64/gcc/s390x-suse-linux - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabi - /usr/lib/arm-linux-gnueabihf - /usr/lib/aarch64-linux-gnu - /usr/lib/i386-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /usr/local/lib/i386 + ${GNSSSDR_LIB_PATHS} PATH_SUFFIXES ${GCC_SERIES} ) diff --git a/cmake/Modules/FindGLOG.cmake b/cmake/Modules/FindGLOG.cmake index 6c506643e..8f6c880a0 100644 --- a/cmake/Modules/FindGLOG.cmake +++ b/cmake/Modules/FindGLOG.cmake @@ -24,6 +24,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -45,36 +49,7 @@ macro(_FIND_GLOG_LIBRARIES _var) NAMES ${ARGN} HINTS ${PC_GLOG_LIBDIR} PATHS ${LIB_PATHS} - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ${GLOG_ROOT}/lib $ENV{GLOG_ROOT}/lib ${GLOG_ROOT}/lib64 diff --git a/cmake/Modules/FindGMP.cmake b/cmake/Modules/FindGMP.cmake index f0648feb3..3f4db49c6 100644 --- a/cmake/Modules/FindGMP.cmake +++ b/cmake/Modules/FindGMP.cmake @@ -1,9 +1,17 @@ # GNSS-SDR is a Global Navigation Satellite System software-defined receiver. # This file is part of GNSS-SDR. # -# SPDX-FileCopyrightText: 2011-2024 C. Fernandez-Prades cfernandez(at)cttc.es +# SPDX-FileCopyrightText: 2024 C. Fernandez-Prades cfernandez(at)cttc.es # SPDX-License-Identifier: BSD-3-Clause +if(NOT COMMAND feature_summary) + include(FeatureSummary) +endif() + +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -11,8 +19,7 @@ pkg_check_modules(PC_GMP "gmp") set(GMP_DEFINITIONS ${PC_GMP_CFLAGS_OTHER}) -find_path( - GMP_INCLUDE_DIR +find_path(GMP_INCLUDE_DIR NAMES gmpxx.h HINTS ${PC_GMP_INCLUDEDIR} PATHS ${CMAKE_INSTALL_PREFIX}/include @@ -24,87 +31,26 @@ find_path( set(GMP_INCLUDE_DIRS ${GMP_INCLUDE_DIR}) set(GMP_PC_ADD_CFLAGS "-I${GMP_INCLUDE_DIR}") -find_library( - GMPXX_LIBRARY +find_library(GMPXX_LIBRARY NAMES gmpxx HINTS ${PC_GMP_LIBDIR} - PATHS ${CMAKE_INSTALL_PREFIX}/lib + PATHS ${GNSSSDR_LIB_PATHS} + ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib64 - /usr/local/lib - /usr/local/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /opt/local/lib ) -find_library( - GMP_LIBRARY +find_library(GMP_LIBRARY NAMES gmp HINTS ${PC_GMP_LIBDIR} - PATHS ${CMAKE_INSTALL_PREFIX}/lib + PATHS ${GNSSSDR_LIB_PATHS} + ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib64 - /usr/local/lib - /usr/local/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /opt/local/lib ) set(GMP_LIBRARIES ${GMPXX_LIBRARY} ${GMP_LIBRARY}) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(GMP DEFAULT_MSG GMPXX_LIBRARY GMP_LIBRARY - GMP_INCLUDE_DIR) +find_package_handle_standard_args(GMP DEFAULT_MSG GMPXX_LIBRARY GMP_LIBRARY GMP_INCLUDE_DIR) if(GMP_FOUND AND NOT TARGET Gmp::gmp) add_library(Gmp::gmp SHARED IMPORTED) @@ -116,4 +62,18 @@ if(GMP_FOUND AND NOT TARGET Gmp::gmp) ) endif() -mark_as_advanced(GMPXX_LIBRARY GMP_LIBRARY GMP_INCLUDE_DIR) \ No newline at end of file +set_package_properties(GMP PROPERTIES + URL "https://gmplib.org/" +) + +if(PC_GMP_VERSION) + set_package_properties(GMP PROPERTIES + DESCRIPTION "The GNU Multiple Precision Arithmetic Library (found: v.${PC_GMP_VERSION})" + ) +else() + set_package_properties(GMP PROPERTIES + DESCRIPTION "The GNU Multiple Precision Arithmetic Library" + ) +endif() + +mark_as_advanced(GMPXX_LIBRARY GMP_LIBRARY GMP_INCLUDE_DIR) diff --git a/cmake/Modules/FindGNURADIO.cmake b/cmake/Modules/FindGNURADIO.cmake index 9855ddc29..cfaf51764 100644 --- a/cmake/Modules/FindGNURADIO.cmake +++ b/cmake/Modules/FindGNURADIO.cmake @@ -12,6 +12,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -105,36 +109,7 @@ function(GR_MODULE EXTVAR PCNAME INCFILE LIBFILE) HINTS ${PC_LIBDIR} PATHS ${GNURADIO_INSTALL_PREFIX_USER_PROVIDED}/lib ${GNURADIO_INSTALL_PREFIX_USER_PROVIDED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) list(APPEND ${LIBVAR_NAME} ${${LIBVAR_NAME}_${libname}}) endforeach() @@ -314,35 +289,7 @@ if(GNURADIO_VERSION VERSION_GREATER 3.8.99) HINTS ${PC_GNURADIO_IIO_LIBDIR} PATHS ${GNURADIO_INSTALL_PREFIX_USER_PROVIDED}/lib ${GNURADIO_INSTALL_PREFIX_USER_PROVIDED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) if(GNURADIO_IIO_LIBRARIES) diff --git a/cmake/Modules/FindGRIIO.cmake b/cmake/Modules/FindGRIIO.cmake index 1abd5caf4..6a4352fc0 100644 --- a/cmake/Modules/FindGRIIO.cmake +++ b/cmake/Modules/FindGRIIO.cmake @@ -13,6 +13,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -70,36 +74,7 @@ find_library(IIO_LIBRARIES HINTS ${PC_IIO_LIBDIR} PATHS ${GRIIO_ROOT_USER_DEFINED}/lib ${GRIIO_ROOT_USER_DEFINED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabi - /usr/lib/arm-linux-gnueabihf - /usr/lib/hppa-linux-gnu - /usr/lib/i686-gnu - /usr/lib/i686-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i686-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/sh4-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) include(FindPackageHandleStandardArgs) diff --git a/cmake/Modules/FindGRLIMESDR.cmake b/cmake/Modules/FindGRLIMESDR.cmake index 2fb60cb3f..a0ca9a565 100644 --- a/cmake/Modules/FindGRLIMESDR.cmake +++ b/cmake/Modules/FindGRLIMESDR.cmake @@ -31,6 +31,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -70,36 +74,7 @@ find_library(GRLIMESDR_LIBRARIES PATHS ${GRLIMESDR_ROOT_USER_DEFINED}/lib ${GRLIMESDR_ROOT_USER_DEFINED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/riscv64-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) include(FindPackageHandleStandardArgs) diff --git a/cmake/Modules/FindGROSMOSDR.cmake b/cmake/Modules/FindGROSMOSDR.cmake index 22ee7d51e..15a36c32b 100644 --- a/cmake/Modules/FindGROSMOSDR.cmake +++ b/cmake/Modules/FindGROSMOSDR.cmake @@ -31,6 +31,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -70,36 +74,7 @@ find_library(GROSMOSDR_LIBRARIES PATHS ${GROSMOSDR_ROOT_USER_DEFINED}/lib ${GROSMOSDR_ROOT_USER_DEFINED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/riscv64-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) include(FindPackageHandleStandardArgs) diff --git a/cmake/Modules/FindLIBAD9361.cmake b/cmake/Modules/FindLIBAD9361.cmake index e1ff8e4a3..175a81af2 100644 --- a/cmake/Modules/FindLIBAD9361.cmake +++ b/cmake/Modules/FindLIBAD9361.cmake @@ -13,6 +13,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -49,36 +53,7 @@ find_library(LIBAD9361_LIBRARIES HINTS ${PC_LIBAD9361_LIBDIR} PATHS ${LIBAD9361_ROOT_USER_DEFINED}/lib ${LIBAD9361_ROOT_USER_DEFINED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabi - /usr/lib/arm-linux-gnueabihf - /usr/lib/hppa-linux-gnu - /usr/lib/i686-gnu - /usr/lib/i686-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i686-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/sh4-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} /Library/Frameworks/ad9361.framework ) diff --git a/cmake/Modules/FindLIBIIO.cmake b/cmake/Modules/FindLIBIIO.cmake index 44f4d367e..add9215de 100644 --- a/cmake/Modules/FindLIBIIO.cmake +++ b/cmake/Modules/FindLIBIIO.cmake @@ -13,6 +13,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -51,36 +55,7 @@ find_library( HINTS ${PC_LIBIIO_LIBDIR} PATHS ${LIBIIO_ROOT_USER_DEFINED}/lib ${LIBIIO_ROOT_USER_DEFINED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabi - /usr/lib/arm-linux-gnueabihf - /usr/lib/hppa-linux-gnu - /usr/lib/i686-gnu - /usr/lib/i686-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i686-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/sh4-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} /Library/Frameworks/iio.framework/ ) diff --git a/cmake/Modules/FindLIBUNWIND.cmake b/cmake/Modules/FindLIBUNWIND.cmake index f2c88b569..b5c6a68a8 100644 --- a/cmake/Modules/FindLIBUNWIND.cmake +++ b/cmake/Modules/FindLIBUNWIND.cmake @@ -17,6 +17,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + find_path(LIBUNWIND_INCLUDE_DIR NAMES libunwind.h @@ -41,6 +45,7 @@ find_library(LIBUNWIND_GENERIC_LIBRARY PATHS "${LIBUNWIND_ROOT}/lib" "${LIBUNWIND_ROOT}/lib64" + ${GNSSSDR_LIB_PATHS} ) if(LIBUNWIND_INCLUDE_DIR) diff --git a/cmake/Modules/FindLOG4CPP.cmake b/cmake/Modules/FindLOG4CPP.cmake index 95a14cf62..f351ebf3a 100644 --- a/cmake/Modules/FindLOG4CPP.cmake +++ b/cmake/Modules/FindLOG4CPP.cmake @@ -19,6 +19,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -74,35 +78,7 @@ find_library(LOG4CPP_LIBRARY HINTS ${PC_LOG4CPP_LIBDIR} PATHS ${LOG4CPP_ROOT_USER_PROVIDED}/lib ${LOG4CPP_ROOT_USER_PROVIDED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) if(LOG4CPP_INCLUDE_DIR AND LOG4CPP_LIBRARY) diff --git a/cmake/Modules/FindMATIO.cmake b/cmake/Modules/FindMATIO.cmake index d9a6cebd2..73f8d053d 100644 --- a/cmake/Modules/FindMATIO.cmake +++ b/cmake/Modules/FindMATIO.cmake @@ -55,6 +55,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT MATIO_ROOT) set(MATIO_ROOT_USER_DEFINED /usr) else() @@ -85,33 +89,7 @@ find_library(MATIO_LIBRARY PATHS ${MATIO_ROOT_USER_DEFINED}/lib ${MATIO_ROOT_USER_DEFINED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/alpha-linux-gnu - /usr/lib/x86_64-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabi - /usr/lib/arm-linux-gnueabihf - /usr/lib/hppa-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib DOC "The MATIO library" ) diff --git a/cmake/Modules/FindORC.cmake b/cmake/Modules/FindORC.cmake index b6a4ba364..600d0ac35 100644 --- a/cmake/Modules/FindORC.cmake +++ b/cmake/Modules/FindORC.cmake @@ -13,6 +13,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -65,26 +69,7 @@ find_path(ORC_LIBRARY_DIR ${ORC_ROOT_USER_PROVIDED}/lib64 ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) find_library(ORC_LIB orc-0.4 @@ -93,26 +78,7 @@ find_library(ORC_LIB orc-0.4 ${ORC_ROOT_USER_PROVIDED}/lib64 ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) find_library(ORC_LIBRARY_STATIC ${CMAKE_STATIC_LIBRARY_PREFIX}orc-0.4${CMAKE_STATIC_LIBRARY_SUFFIX} diff --git a/cmake/Modules/FindPCAP.cmake b/cmake/Modules/FindPCAP.cmake index 39a7aff15..2a3db3aff 100644 --- a/cmake/Modules/FindPCAP.cmake +++ b/cmake/Modules/FindPCAP.cmake @@ -23,6 +23,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -88,33 +92,7 @@ else() ${PC_PCAP_LIBDIR} PATHS ${PCAP_ROOT_USER_PROVIDED}/lib - /usr/lib - /usr/lib64 - /usr/lib/alpha-linux-gnu - /usr/lib/x86_64-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabi - /usr/lib/arm-linux-gnueabihf - /usr/lib/hppa-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) endif() diff --git a/cmake/Modules/FindPUGIXML.cmake b/cmake/Modules/FindPUGIXML.cmake index 5f7f5dcb2..4ff6419cc 100644 --- a/cmake/Modules/FindPUGIXML.cmake +++ b/cmake/Modules/FindPUGIXML.cmake @@ -20,6 +20,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -66,36 +70,9 @@ find_library(PUGIXML_LIBRARY ${PUGIXML_ROOT_USER_DEFINED}/lib64/pugixml-${PC_PUGIXML_VERSION} ${PUGIXML_ROOT_USER_DEFINED}}/lib/pugixml-1.9 ${PUGIXML_ROOT_USER_DEFINED}/lib64/pugixml-1.9 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabi - /usr/lib/arm-linux-gnueabihf - /usr/lib/i386-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/local/lib - /usr/local/lib64 + ${GNSSSDR_LIB_PATHS} /usr/local/lib/pugixml-${PC_PUGIXML_VERSION} /usr/local/lib/pugixml-1.9 - /opt/local/lib ) # Support the REQUIRED and QUIET arguments, and set PUGIXML_FOUND if found. diff --git a/cmake/Modules/FindUHD.cmake b/cmake/Modules/FindUHD.cmake index a6ed654a3..d30313535 100644 --- a/cmake/Modules/FindUHD.cmake +++ b/cmake/Modules/FindUHD.cmake @@ -16,6 +16,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -60,36 +64,7 @@ find_library(UHD_LIBRARIES HINTS ${PC_UHD_LIBDIR} PATHS ${UHD_ROOT_USER_PROVIDED}/lib ${UHD_ROOT_USER_PROVIDED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) include(FindPackageHandleStandardArgs) diff --git a/cmake/Modules/FindVOLK.cmake b/cmake/Modules/FindVOLK.cmake index bda662186..2247f8247 100644 --- a/cmake/Modules/FindVOLK.cmake +++ b/cmake/Modules/FindVOLK.cmake @@ -16,6 +16,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -58,35 +62,7 @@ find_library(VOLK_LIBRARIES HINTS ${PC_VOLK_LIBDIR} PATHS ${VOLK_ROOT_USER_PROVIDED}/lib ${VOLK_ROOT_USER_PROVIDED}/lib64 - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/aarch64-linux-gnu - /usr/lib/mipsel-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/hppa-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/i386-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/alpha-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + ${GNSSSDR_LIB_PATHS} ) include(FindPackageHandleStandardArgs) diff --git a/cmake/Modules/FindZEROMQ.cmake b/cmake/Modules/FindZEROMQ.cmake index 6579d9ed7..d42a68d2d 100644 --- a/cmake/Modules/FindZEROMQ.cmake +++ b/cmake/Modules/FindZEROMQ.cmake @@ -13,6 +13,10 @@ if(NOT COMMAND feature_summary) include(FeatureSummary) endif() +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() + if(NOT PKG_CONFIG_FOUND) include(FindPkgConfig) endif() @@ -29,33 +33,7 @@ find_path(ZEROMQ_INCLUDE_DIRS find_library(ZEROMQ_LIBRARIES NAMES zmq libzmq.so.5 ${ZEROMQ_LIBRARY_NAME} HINTS ${PC_ZEROMQ_LIBDIR} ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/lib64 - PATHS /usr/lib - /usr/lib64 - /usr/lib/alpha-linux-gnu - /usr/lib/x86_64-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabi - /usr/lib/arm-linux-gnueabihf - /usr/lib/hppa-linux-gnu - /usr/lib/i386-linux-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/sh4-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i386-kfreebsd-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + PATHS ${GNSSSDR_LIB_PATHS} ) include(FindPackageHandleStandardArgs) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnssSdrCrypto.cmake index ac84260d1..a9d89e6be 100644 --- a/cmake/Modules/GnssSdrCrypto.cmake +++ b/cmake/Modules/GnssSdrCrypto.cmake @@ -4,6 +4,13 @@ # SPDX-FileCopyrightText: 2024 C. Fernandez-Prades cfernandez(at)cttc.es # SPDX-License-Identifier: BSD-3-Clause +if(NOT COMMAND feature_summary) + include(FeatureSummary) +endif() + +if(NOT GNSSSDR_LIB_PATHS) + include(GnsssdrLibPaths) +endif() ################################################################################ # OpenSSL https://www.openssl.org/ @@ -53,38 +60,7 @@ else() endif() find_library(GNUTLS_OPENSSL_LIBRARY NAMES gnutls-openssl libgnutls-openssl.so.27 - PATHS - /usr/lib - /usr/lib64 - /usr/lib/x86_64-linux-gnu - /usr/lib/aarch64-linux-gnu - /usr/lib/arm-linux-gnueabihf - /usr/lib/arm-linux-gnueabi - /usr/lib/i386-linux-gnu - /usr/lib/alpha-linux-gnu - /usr/lib/hppa-linux-gnu - /usr/lib/i386-gnu - /usr/lib/i686-gnu - /usr/lib/i686-linux-gnu - /usr/lib/x86_64-kfreebsd-gnu - /usr/lib/i686-kfreebsd-gnu - /usr/lib/m68k-linux-gnu - /usr/lib/mips-linux-gnu - /usr/lib/mips64el-linux-gnuabi64 - /usr/lib/mipsel-linux-gnu - /usr/lib/powerpc-linux-gnu - /usr/lib/powerpc-linux-gnuspe - /usr/lib/powerpc64-linux-gnu - /usr/lib/powerpc64le-linux-gnu - /usr/lib/s390x-linux-gnu - /usr/lib/riscv64-linux-gnu - /usr/lib/sparc64-linux-gnu - /usr/lib/x86_64-linux-gnux32 - /usr/lib/sh4-linux-gnu - /usr/lib/loongarch64-linux-gnu - /usr/local/lib - /usr/local/lib64 - /opt/local/lib + PATHS ${GNSSSDR_LIB_PATHS} ) find_path(GNUTLS_INCLUDE_DIR NAMES gnutls/gnutls.h @@ -137,9 +113,7 @@ else() find_package(GMP) set_package_properties(GMP PROPERTIES - URL "https://gmplib.org/" PURPOSE "Required to decompress cryptographic keys." - DESCRIPTION "The GNU Multiple Precision Arithmetic Library" TYPE REQUIRED ) if(NOT GMP_FOUND) diff --git a/cmake/Modules/GnsssdrLibPaths.cmake b/cmake/Modules/GnsssdrLibPaths.cmake new file mode 100644 index 000000000..9f76e362f --- /dev/null +++ b/cmake/Modules/GnsssdrLibPaths.cmake @@ -0,0 +1,43 @@ +# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +# This file is part of GNSS-SDR. +# +# SPDX-FileCopyrightText: 2011-2024 C. Fernandez-Prades cfernandez(at)cttc.es +# SPDX-License-Identifier: BSD-3-Clause + +if(GNSSSDR_LIB_PATHS) + return() +endif() + +set(GNSSSDR_LIB_PATHS + /usr/lib + /usr/lib/aarch64-linux-gnu + /usr/lib/alpha-linux-gnu + /usr/lib/arm-linux-gnueabi + /usr/lib/arm-linux-gnueabihf + /usr/lib/hppa-linux-gnu + /usr/lib/hppa-linux-gnu + /usr/lib/i386-gnu + /usr/lib/i386-kfreebsd-gnu + /usr/lib/i386-linux-gnu + /usr/lib/loongarch64-linux-gnu + /usr/lib/m68k-linux-gnu + /usr/lib/mips-linux-gnu + /usr/lib/mips64el-linux-gnuabi64 + /usr/lib/mipsel-linux-gnu + /usr/lib/powerpc-linux-gnu + /usr/lib/powerpc-linux-gnuspe + /usr/lib/powerpc64-linux-gnu + /usr/lib/powerpc64le-linux-gnu + /usr/lib/riscv64-linux-gnu + /usr/lib/s390x-linux-gnu + /usr/lib/sh4-linux-gnu + /usr/lib/sparc64-linux-gnu + /usr/lib/x86_64-kfreebsd-gnu + /usr/lib/x86_64-linux-gnu + /usr/lib/x86_64-linux-gnux32 + /usr/lib64 + /usr/local/lib + /usr/local/lib/i386 + /usr/local/lib64 + /opt/local/lib +) From 1dec33dbf591455e021dd4efd4fa1a5c11a1922d Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 1 Aug 2024 18:45:03 +0200 Subject: [PATCH 201/219] Clang Tidy fixes --- src/core/libs/osnma_msg_receiver.cc | 5 +- src/core/system_parameters/gnss_crypto.cc | 5 +- src/core/system_parameters/osnma_data.cc | 2 +- src/core/system_parameters/osnma_data.h | 2 +- src/core/system_parameters/osnma_helper.h | 1 - .../osnma_nav_data_manager.cc | 53 ++++++++++--------- .../osnma_nav_data_manager.h | 4 +- 7 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 7035a9e08..4f984143f 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -1013,7 +1013,6 @@ void osnma_msg_receiver::process_mack_message() LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed, " << "no Kroot nor TESLA key available."; return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. - } // verify tesla key and add it to the container of verified keys if successful if (d_tesla_keys.find(d_osnma_data.d_nav_data.get_tow_sf0()) == d_tesla_keys.end()) // check if already available => no need to verify @@ -1925,9 +1924,9 @@ void osnma_msg_receiver::send_data_to_pvt(std::vector data) { if (!data.empty()) { - for (size_t i = 0; i < data.size(); i++) + for (auto & i : data) { - const auto tmp_obj = std::make_shared(data[i]); + const auto tmp_obj = std::make_shared(i); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(tmp_obj)); } } diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 4faa8a30a..a4f40a3e4 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -897,8 +897,9 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) 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())) + OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", publicKey.data(), publicKey.size())) { params = OSSL_PARAM_BLD_to_param(param_bld); + } 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) @@ -1192,7 +1193,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) // 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 - auto ec_key = EVP_PKEY_get0_EC_KEY(pubkey); + const auto 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) { diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index d19a30cab..6d969a7f0 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -19,7 +19,7 @@ uint32_t Tag::id_counter = 0; uint32_t OSNMA_NavData::id_counter = 0; -bool OSNMA_NavData::add_nav_data(std::string nav_data) +bool OSNMA_NavData::add_nav_data(const std::string& nav_data) { if (nav_data.size() == 549) { diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 46b54dcfe..052a23921 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -129,7 +129,7 @@ class OSNMA_NavData public: OSNMA_NavData(): nav_data_id(id_counter++){} bool have_this_bits(std::string nav_data); - bool add_nav_data(std::string nav_data); + bool add_nav_data(const std::string& nav_data); void update_last_received_timestamp(uint32_t TOW); const uint32_t nav_data_id; uint32_t verified_bits{0}; diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index ea4e81313..703a4fd0d 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -39,7 +39,6 @@ public: std::vector convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; - }; #endif // GNSS_SDR_OSNMA_HELPER_H diff --git a/src/core/system_parameters/osnma_nav_data_manager.cc b/src/core/system_parameters/osnma_nav_data_manager.cc index 5b42e799d..13aa96084 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.cc +++ b/src/core/system_parameters/osnma_nav_data_manager.cc @@ -29,7 +29,7 @@ * @param PRNd The satellite ID. * @param TOW The TOW of the received data. */ -void OSNMA_nav_data_Manager::add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW) +void OSNMA_nav_data_Manager::add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) { if (not have_nav_data(nav_bits, PRNd, TOW)) { @@ -52,18 +52,18 @@ void OSNMA_nav_data_Manager::update_nav_data(const std::multimap& if (have_PRNd_nav_data(tag.second.PRN_d)) { std::map tow_map = _satellite_nav_data.find(tag.second.PRN_d)->second; - for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + 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){ - nav_data = tow_it->second.get_ephemeris_data(); + nav_data = tow_it.second.get_ephemeris_data(); } else if (tag.second.ADKD == 4){ - nav_data = tow_it->second.get_utc_data(); + nav_data = tow_it.second.get_utc_data(); } // find associated OSNMA_NavData if (tag.second.nav_data == nav_data){ - _satellite_nav_data[tag.second.PRN_d][tow_it->first].verified_bits += tag_size; + _satellite_nav_data[tag.second.PRN_d][tow_it.first].verified_bits += tag_size; } } } @@ -99,7 +99,7 @@ bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t if (it != _satellite_nav_data.cend()) { const auto it2 = it->second.find(TOW); - if (it2 != it->second.cend() && it->second[TOW].get_ephemeris_data() != "") + if (it2 != it->second.cend() && !it->second[TOW].get_ephemeris_data().empty()) { return true; } @@ -111,7 +111,7 @@ bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t if (it != _satellite_nav_data.cend()) { const auto it2 = it->second.find(TOW); - if (it2 != it->second.cend() && it->second[TOW].get_utc_data() != "") + if (it2 != it->second.cend() && !it->second[TOW].get_utc_data().empty()) { return true; } @@ -140,13 +140,13 @@ 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() != ""){ + 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() != ""){ + if (!tow_it->second.get_utc_data().empty()){ return tow_it->second.get_utc_data(); } } @@ -161,7 +161,7 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) * @param PRNd * @return */ -bool OSNMA_nav_data_Manager::have_nav_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW) +bool OSNMA_nav_data_Manager::have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) { if (_satellite_nav_data.find(PRNd) != _satellite_nav_data.end()){ for (auto& data_timestamp : _satellite_nav_data[PRNd]) @@ -202,13 +202,13 @@ 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() != ""){ + if (!tow_it->second.get_ephemeris_data().empty()){ return true; } } else if (t.ADKD == 4) { - if (tow_it->second.get_utc_data() != ""){ + if (!tow_it->second.get_utc_data().empty()){ return true; } } @@ -220,19 +220,20 @@ void OSNMA_nav_data_Manager::print_status() { for (const auto& satellite : _satellite_nav_data){ LOG(INFO) << "Galileo OSNMA: NavData status :: SVID=" << satellite.first; - auto& tow_data = satellite.second; - for (const auto& nav_data : tow_data) - LOG(INFO) << "Galileo OSNMA: IOD_nav=0b" << std::uppercase - << std::bitset<10>(nav_data.second.IOD_nav) - << ", TOW_start=" - << nav_data.second.get_tow_sf0() - << ", TOW_last=" - << nav_data.second.last_received_TOW - << ", l_t=" - << nav_data.second.verified_bits - << ", PRNd=" - << nav_data.second.PRNd - << ", verified=" - << nav_data.second.verified; + const auto& tow_data = satellite.second; + for (const auto& nav_data : tow_data) { + LOG(INFO) << "Galileo OSNMA: IOD_nav=0b" << std::uppercase + << std::bitset<10>(nav_data.second.IOD_nav) + << ", TOW_start=" + << nav_data.second.get_tow_sf0() + << ", TOW_last=" + << nav_data.second.last_received_TOW + << ", l_t=" + << nav_data.second.verified_bits + << ", PRNd=" + << nav_data.second.PRNd + << ", verified=" + << nav_data.second.verified; + } } } diff --git a/src/core/system_parameters/osnma_nav_data_manager.h b/src/core/system_parameters/osnma_nav_data_manager.h index 2101bef3a..98b3d523f 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.h +++ b/src/core/system_parameters/osnma_nav_data_manager.h @@ -32,10 +32,10 @@ class OSNMA_nav_data_Manager{ public: OSNMA_nav_data_Manager() = default; - bool have_nav_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); + bool have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD); bool have_nav_data(const Tag& t) const; - void add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list + void add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list std::string get_navigation_data(const Tag& t); void update_nav_data(const std::multimap& tags_verified, const uint8_t tag_size); From 960e76e3a01551e6002aa74ef6b281f5403514f3 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 1 Aug 2024 18:45:03 +0200 Subject: [PATCH 202/219] Clang Tidy fixes --- src/core/libs/osnma_msg_receiver.cc | 7 +- src/core/libs/osnma_msg_receiver.h | 2 +- src/core/system_parameters/gnss_crypto.cc | 5 +- src/core/system_parameters/osnma_data.cc | 2 +- src/core/system_parameters/osnma_data.h | 2 +- src/core/system_parameters/osnma_helper.h | 1 - .../osnma_nav_data_manager.cc | 65 ++++++++++--------- .../osnma_nav_data_manager.h | 4 +- 8 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 7035a9e08..380d917f4 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -1013,7 +1013,6 @@ void osnma_msg_receiver::process_mack_message() LOG(WARNING) << "Galileo OSNMA: MACK cannot be processed, " << "no Kroot nor TESLA key available."; return; // early return, cannot proceed further without one of the two verified. this equals to having Kroot but no TESLa key yet. - } // verify tesla key and add it to the container of verified keys if successful if (d_tesla_keys.find(d_osnma_data.d_nav_data.get_tow_sf0()) == d_tesla_keys.end()) // check if already available => no need to verify @@ -1921,13 +1920,13 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ } } -void osnma_msg_receiver::send_data_to_pvt(std::vector data) +void osnma_msg_receiver::send_data_to_pvt(const std::vector& data) { if (!data.empty()) { - for (size_t i = 0; i < data.size(); i++) + for (auto & i : data) { - const auto tmp_obj = std::make_shared(data[i]); + const auto tmp_obj = std::make_shared(i); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(tmp_obj)); } } diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index fb83f2b8c..59d98e04a 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -82,7 +82,7 @@ private: void remove_verified_tags(); void control_tags_awaiting_verify_size(); void display_data(); - void send_data_to_pvt(std::vector); + void send_data_to_pvt(const std::vector& data); bool verify_tesla_key(std::vector& key, uint32_t TOW); bool verify_tag(Tag& tag) const; diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 4faa8a30a..e2c88faa4 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -897,8 +897,9 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) 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())) + OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", publicKey.data(), publicKey.size())) { params = OSSL_PARAM_BLD_to_param(param_bld); + } 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) @@ -1192,7 +1193,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) // 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 - auto ec_key = EVP_PKEY_get0_EC_KEY(pubkey); + 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) { diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index d19a30cab..6d969a7f0 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -19,7 +19,7 @@ uint32_t Tag::id_counter = 0; uint32_t OSNMA_NavData::id_counter = 0; -bool OSNMA_NavData::add_nav_data(std::string nav_data) +bool OSNMA_NavData::add_nav_data(const std::string& nav_data) { if (nav_data.size() == 549) { diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 46b54dcfe..052a23921 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -129,7 +129,7 @@ class OSNMA_NavData public: OSNMA_NavData(): nav_data_id(id_counter++){} bool have_this_bits(std::string nav_data); - bool add_nav_data(std::string nav_data); + bool add_nav_data(const std::string& nav_data); void update_last_received_timestamp(uint32_t TOW); const uint32_t nav_data_id; uint32_t verified_bits{0}; diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index ea4e81313..703a4fd0d 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -39,7 +39,6 @@ public: std::vector convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; - }; #endif // GNSS_SDR_OSNMA_HELPER_H diff --git a/src/core/system_parameters/osnma_nav_data_manager.cc b/src/core/system_parameters/osnma_nav_data_manager.cc index 5b42e799d..8fdd9ee6e 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.cc +++ b/src/core/system_parameters/osnma_nav_data_manager.cc @@ -29,7 +29,7 @@ * @param PRNd The satellite ID. * @param TOW The TOW of the received data. */ -void OSNMA_nav_data_Manager::add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW) +void OSNMA_nav_data_Manager::add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) { if (not have_nav_data(nav_bits, PRNd, TOW)) { @@ -52,18 +52,18 @@ void OSNMA_nav_data_Manager::update_nav_data(const std::multimap& if (have_PRNd_nav_data(tag.second.PRN_d)) { std::map tow_map = _satellite_nav_data.find(tag.second.PRN_d)->second; - for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + 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){ - nav_data = tow_it->second.get_ephemeris_data(); + nav_data = tow_it.second.get_ephemeris_data(); } else if (tag.second.ADKD == 4){ - nav_data = tow_it->second.get_utc_data(); + nav_data = tow_it.second.get_utc_data(); } // find associated OSNMA_NavData if (tag.second.nav_data == nav_data){ - _satellite_nav_data[tag.second.PRN_d][tow_it->first].verified_bits += tag_size; + _satellite_nav_data[tag.second.PRN_d][tow_it.first].verified_bits += tag_size; } } } @@ -99,7 +99,7 @@ bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t if (it != _satellite_nav_data.cend()) { const auto it2 = it->second.find(TOW); - if (it2 != it->second.cend() && it->second[TOW].get_ephemeris_data() != "") + if (it2 != it->second.cend() && !it->second[TOW].get_ephemeris_data().empty()) { return true; } @@ -111,7 +111,7 @@ bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t if (it != _satellite_nav_data.cend()) { const auto it2 = it->second.find(TOW); - if (it2 != it->second.cend() && it->second[TOW].get_utc_data() != "") + if (it2 != it->second.cend() && !it->second[TOW].get_utc_data().empty()) { return true; } @@ -133,21 +133,21 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) // satellite was found, check if TOW exists in inner map std::map tow_map = prn_it->second; - for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + for (auto & tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset { // Check if current key (TOW) fulfills condition - if ((tag.TOW - 30 * tag.cop) <= tow_it->first && tow_it->first <= tag.TOW - 30) + if ((tag.TOW - 30 * tag.cop) <= tow_it.first && tow_it.first <= tag.TOW - 30) { if (tag.ADKD == 0 || tag.ADKD == 12) { - if (tow_it->second.get_ephemeris_data() != ""){ - return tow_it->second.get_ephemeris_data(); + 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() != ""){ - return tow_it->second.get_utc_data(); + if (!tow_it.second.get_utc_data().empty()){ + return tow_it.second.get_utc_data(); } } } @@ -161,7 +161,7 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) * @param PRNd * @return */ -bool OSNMA_nav_data_Manager::have_nav_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW) +bool OSNMA_nav_data_Manager::have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) { if (_satellite_nav_data.find(PRNd) != _satellite_nav_data.end()){ for (auto& data_timestamp : _satellite_nav_data[PRNd]) @@ -195,20 +195,20 @@ bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const } // satellite was found, check if TOW exists in inner map std::map tow_map = prn_it->second; - for (auto tow_it = tow_map.begin(); tow_it != tow_map.end(); ++tow_it) // note: starts with smallest (i.e. oldest) navigation dataset + for (auto & tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset { // Check if current key (TOW) fulfills condition - if (t.TOW - 30 * t.cop <= tow_it->first && tow_it->first <= t.TOW - 30) + if (t.TOW - 30 * t.cop <= tow_it.first && tow_it.first <= t.TOW - 30) { if (t.ADKD == 0 || t.ADKD == 12) { - if (tow_it->second.get_ephemeris_data() != ""){ + if (!tow_it.second.get_ephemeris_data().empty()){ return true; } } else if (t.ADKD == 4) { - if (tow_it->second.get_utc_data() != ""){ + if (!tow_it.second.get_utc_data().empty()){ return true; } } @@ -220,19 +220,20 @@ void OSNMA_nav_data_Manager::print_status() { for (const auto& satellite : _satellite_nav_data){ LOG(INFO) << "Galileo OSNMA: NavData status :: SVID=" << satellite.first; - auto& tow_data = satellite.second; - for (const auto& nav_data : tow_data) - LOG(INFO) << "Galileo OSNMA: IOD_nav=0b" << std::uppercase - << std::bitset<10>(nav_data.second.IOD_nav) - << ", TOW_start=" - << nav_data.second.get_tow_sf0() - << ", TOW_last=" - << nav_data.second.last_received_TOW - << ", l_t=" - << nav_data.second.verified_bits - << ", PRNd=" - << nav_data.second.PRNd - << ", verified=" - << nav_data.second.verified; + const auto& tow_data = satellite.second; + for (const auto& nav_data : tow_data) { + LOG(INFO) << "Galileo OSNMA: IOD_nav=0b" << std::uppercase + << std::bitset<10>(nav_data.second.IOD_nav) + << ", TOW_start=" + << nav_data.second.get_tow_sf0() + << ", TOW_last=" + << nav_data.second.last_received_TOW + << ", l_t=" + << nav_data.second.verified_bits + << ", PRNd=" + << nav_data.second.PRNd + << ", verified=" + << nav_data.second.verified; + } } } diff --git a/src/core/system_parameters/osnma_nav_data_manager.h b/src/core/system_parameters/osnma_nav_data_manager.h index 2101bef3a..98b3d523f 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.h +++ b/src/core/system_parameters/osnma_nav_data_manager.h @@ -32,10 +32,10 @@ class OSNMA_nav_data_Manager{ public: OSNMA_nav_data_Manager() = default; - bool have_nav_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); + bool have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD); bool have_nav_data(const Tag& t) const; - void add_navigation_data(std::string nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list + void add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list std::string get_navigation_data(const Tag& t); void update_nav_data(const std::multimap& tags_verified, const uint8_t tag_size); From 6beb92278f562466e270c65981a5c14fdf7c7722 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 2 Aug 2024 09:38:37 +0200 Subject: [PATCH 203/219] 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 --- src/core/libs/osnma_msg_receiver.cc | 133 ++++++---- src/core/system_parameters/gnss_crypto.cc | 247 +++++++++++++----- src/core/system_parameters/gnss_crypto.h | 11 +- .../osnma_nav_data_manager.cc | 32 ++- .../osnma/gnss_crypto_test.cc | 30 ++- 5 files changed, 307 insertions(+), 146 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 380d917f4..d5cb1fcaa 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -29,6 +29,7 @@ #include #include #include +#include // for std::ifstream and std::ofstream #include // for std::setfill #include // for std::hex, std::uppercase #include @@ -37,7 +38,6 @@ #include #include // for typeid #include -#include // 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(); d_crypto = std::make_unique(crtFilePath, merkleFilePath); d_helper = std::make_unique(); d_nav_data_manager = std::make_unique(); - 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 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>).hash_code()) // Navigation data bits for OSNMA received { const auto inav_data = wht::any_cast>>(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) { - 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& 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& 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& 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& 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& dsm_msg const uint16_t size_m = 13 + l_lk_bytes; std::vector 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 message = MSG; // MSG = (M | DS) from ICD. Eq. 7 + std::vector 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& 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& 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& 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& 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& 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& 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& 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_ptrTOW_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 m(5 + 2 * flxTags.size()); // each flx tag brings two bytes - m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag m[1] = static_cast((GST_SFi & 0xFF000000) >> 24); m[2] = static_cast((GST_SFi & 0x00FF0000) >> 16); m[3] = static_cast((GST_SFi & 0x0000FF00) >> 8); @@ -1863,7 +1891,7 @@ std::vector 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 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 m(5 + 2 * flxTags.size()); // each flx tag brings two bytes - m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag + std::vector m(5 + 2 * flxTags.size()); // each flx tag brings two bytes + m[0] = static_cast(mack.PRNa); // PRN_A - SVID of the satellite transmiting the tag m[1] = static_cast((GST_Sfi & 0xFF000000) >> 24); m[2] = static_cast((GST_Sfi & 0x00FF0000) >> 16); m[3] = static_cast((GST_Sfi & 0x0000FF00) >> 8); @@ -1924,7 +1952,7 @@ void osnma_msg_receiver::send_data_to_pvt(const std::vector& data { if (!data.empty()) { - for (auto & i : data) + for (auto& i : data) { const auto tmp_obj = std::make_shared(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& 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& dsm, const std::pair, 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(), 0}; } @@ -1965,7 +1995,8 @@ std::pair, uint8_t> osnma_msg_receiver::parse_dsm_kroot() c file.close(); - if (file.bad()) { + if (file.bad()) + { return {std::vector(), 0}; } diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index e2c88faa4..ac8723ab5 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -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 Gnss_Crypto::compute_CMAC_AES(const std::vector& k return output; } -// TODO - deprecate: change return type to respective key type, PEM is not needed. -std::vector 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 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 - std::vector 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 Gnss_Crypto::get_merkle_root() const { @@ -846,8 +791,15 @@ std::vector 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& 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& 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& 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& 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& 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& 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(ret); + + 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); + + 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(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 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) { diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/system_parameters/gnss_crypto.h index 6aa347bb0..e197d61d0 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/system_parameters/gnss_crypto.h @@ -66,13 +66,13 @@ public: std::vector compute_HMAC_SHA_256(const std::vector& key, const std::vector& input) const; //!< Computes HMAC-SHA-256 message authentication code std::vector compute_CMAC_AES(const std::vector& key, const std::vector& input) const; //!< Computes CMAC-AES message authentication code - std::vector get_public_key() const; //!< Gets the ECDSA Public Key in PEM format std::vector 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& publickey); //!< Sets the ECDSA Public Key (publickey compressed format) - void set_merkle_root(const std::vector& 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& 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& 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 d_x_4_0; + std::string d_PublicKeyType; }; /** \} */ diff --git a/src/core/system_parameters/osnma_nav_data_manager.cc b/src/core/system_parameters/osnma_nav_data_manager.cc index 8fdd9ee6e..9d5017aec 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.cc +++ b/src/core/system_parameters/osnma_nav_data_manager.cc @@ -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& 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& } } } + + 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_nav_data_Manager::get_verified_data() { std::vector result; @@ -91,6 +98,8 @@ std::vector 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){ 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 6d645edb1..6b4813975 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 @@ -34,8 +34,10 @@ TEST(GnssCryptoTest, VerifyPubKeyImport) // Input taken from RG 1.3 A7.1 // compressed ECDSA P-256 format std::vector 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 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 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 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 output = d_crypto->compute_SHA_256(message); @@ -111,7 +112,8 @@ TEST(GnssCryptoTest, TestComputeSHA3_256) std::vector 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 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 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); From 3457b8ed3b7445dbfcff0c3d8c9d6a2656975493 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 3 Aug 2024 19:58:34 +0200 Subject: [PATCH 204/219] Get time zone offset in a more standard way (#17) * Clang Tidy fixes * Get time zone offset in a more standard way Account for leap seconds Use GNSS-SDR.osnma_mode=strict to check for local time * Fix for C++20 * Initialize tm in a more portable way * Remove unnecessary data members in osnma_msg_receiver --------- Co-authored-by: cesaaargm --- src/core/libs/osnma_msg_receiver.cc | 46 ++++++++------- src/core/libs/osnma_msg_receiver.h | 65 +++++++++++----------- src/core/receiver/gnss_flowgraph.cc | 8 ++- src/core/system_parameters/osnma_helper.cc | 45 ++++++++++----- src/core/system_parameters/osnma_helper.h | 19 +++++-- 5 files changed, 110 insertions(+), 73 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index d5cb1fcaa..16ade4101 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -61,15 +61,18 @@ namespace wht = std; #endif -osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath) +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode) { - return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath, merkleFilePath)); + return osnma_msg_receiver_sptr(new osnma_msg_receiver(pemFilePath, merkleFilePath, strict_mode)); } -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)) +osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, + const std::string& merkleFilePath, + bool strict_mode) : gr::block("osnma_msg_receiver", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)), + d_strict_mode(strict_mode) { d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(crtFilePath, merkleFilePath); @@ -114,23 +117,20 @@ osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, const std boost::bind(&osnma_msg_receiver::msg_handler_osnma, this, _1)); #endif #endif - std::chrono::time_point now; - if (d_flag_debug) + + if (d_strict_mode) { - // 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? + d_GST_Rx = d_helper->compute_gst_now(); + const auto WN = d_helper->get_WN(d_GST_Rx); + const auto TOW = d_helper->get_TOW(d_GST_Rx); + LOG(INFO) << "Galileo OSNMA: initial receiver time GST=[" << WN << " " << TOW << "]"; + std::cout << "Galileo OSNMA: initial receiver time GST=[" << WN << " " << TOW << "]" << std::endl; } else { - d_GST_Rx = d_helper->compute_gst_now(); + LOG(WARNING) << "Galileo OSNMA: in non-strict mode, local system time is not checked."; + std::cout << "Galileo OSNMA: in non-strict mode, local system time is not checked." << std::endl; } - - 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; } @@ -167,13 +167,13 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) { d_last_received_GST = d_GST_SIS; } - if (d_flag_debug) + if (d_strict_mode) { - d_GST_Rx = d_last_received_GST; + d_GST_Rx = d_helper->compute_gst_now(); } else { - d_GST_Rx = d_helper->compute_gst_now(); + d_GST_Rx = d_last_received_GST; } LOG(INFO) << "Galileo OSNMA: Receiver Time GST=[" << d_helper->get_WN(d_GST_Rx) << " " << d_helper->get_TOW(d_GST_Rx) << "]"; std::cout << "Galileo OSNMA: Receiver Time GST=[" << d_helper->get_WN(d_GST_Rx) << " " << d_helper->get_TOW(d_GST_Rx) << "]" << std::endl; @@ -1425,6 +1425,7 @@ std::vector osnma_msg_receiver::build_message(Tag& tag) const return m; } + void osnma_msg_receiver::display_data() { // if(d_satellite_nav_data.empty()) @@ -1489,6 +1490,7 @@ bool osnma_msg_receiver::verify_tesla_key(std::vector& key, uint32_t TO return d_tesla_key_verified; } + /** * @brief Removes the tags that have been verified from the multimap d_tags_awaiting_verify. * @@ -1560,6 +1562,7 @@ void osnma_msg_receiver::remove_verified_tags() } } + /** * @brief Control the size of the tags awaiting verification multimap. * @@ -1948,6 +1951,7 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ } } + void osnma_msg_receiver::send_data_to_pvt(const std::vector& data) { if (!data.empty()) @@ -1960,6 +1964,7 @@ void osnma_msg_receiver::send_data_to_pvt(const std::vector& data } } + bool osnma_msg_receiver::store_dsm_kroot(const std::vector& dsm, const uint8_t nma_header) const { std::ofstream file(KROOTFILE_DEFAULT, std::ios::binary | std::ios::out); @@ -1978,6 +1983,7 @@ bool osnma_msg_receiver::store_dsm_kroot(const std::vector& dsm, const return file.good(); } + std::pair, uint8_t> osnma_msg_receiver::parse_dsm_kroot() const { std::ifstream file(KROOTFILE_DEFAULT, std::ios::binary | std::ios::in); diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 59d98e04a..e48b6e5c3 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -28,16 +28,16 @@ #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::vector -#include // for std::pair +#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 * \{ */ @@ -51,7 +51,7 @@ class osnma_msg_receiver; using osnma_msg_receiver_sptr = gnss_shared_ptr; -osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); +osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode = false); /*! * \brief GNU Radio block that receives asynchronous OSNMA messages @@ -66,8 +66,8 @@ public: 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 private: - friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath); - osnma_msg_receiver(const std::string& crtFilePath, const std::string& merkleFilePath); + 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); void process_osnma_message(const std::shared_ptr& osnma_msg); void read_nma_header(uint8_t nma_header); @@ -103,6 +103,7 @@ private: std::map> d_tesla_keys; // tesla keys over time, sorted by TOW std::multimap d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW + std::vector d_new_public_key; std::vector d_tags_to_verify{0, 4, 12}; std::vector d_macks_awaiting_MACSEQ_verification; @@ -111,8 +112,8 @@ private: std::array d_number_of_blocks{}; std::array d_mack_message{}; // C: 480 b - std::unique_ptr d_dsm_reader; // osnma parameters parser - std::unique_ptr d_helper; // helper class with auxiliary 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 OSNMA_data d_osnma_data{}; @@ -125,30 +126,28 @@ private: uint32_t d_GST_SIS{}; // GST coming from W6 and W5 of SIS uint32_t d_GST_PKR_PKREV_start{}; uint32_t d_GST_PKR_AM_start{}; - uint32_t d_WN{}; - uint32_t d_TOW{}; - uint8_t const d_T_L{30}; // s RG Section 2.1 - - bool d_new_data{false}; - bool d_public_key_verified{false}; - bool d_kroot_verified{false}; - bool d_tesla_key_verified{false}; - bool d_flag_debug{true}; - bool d_flag_hot_start{false}; - bool d_flag_PK_renewal{false}; - bool d_flag_PK_revocation{false}; - uint8_t d_new_public_key_id{}; - std::vector d_new_public_key; - bool d_flag_NPK_set{false}; - bool d_flag_alert_message{false}; - - // Provide access to inner functions to Gtest uint32_t d_count_successful_tags{0}; uint32_t d_count_failed_tags{0}; uint32_t d_count_failed_Kroot{0}; uint32_t d_count_failed_pubKey{0}; // failed public key verifications against Merkle root uint32_t d_count_failed_macseq{0}; + + uint8_t const d_T_L{30}; // s RG Section 2.1 + uint8_t d_new_public_key_id{}; + + bool d_new_data{false}; + bool d_public_key_verified{false}; + bool d_kroot_verified{false}; + bool d_tesla_key_verified{false}; + bool d_strict_mode{false}; + bool d_flag_hot_start{false}; + bool d_flag_PK_renewal{false}; + bool d_flag_PK_revocation{false}; + bool d_flag_NPK_set{false}; + bool d_flag_alert_message{false}; + + // Provide access to inner functions to Gtest FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); FRIEND_TEST(OsnmaMsgReceiverTest, TagVerification); FRIEND_TEST(OsnmaMsgReceiverTest, BuildTagMessageM0); diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index af1795ee0..b0e3dc418 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -126,7 +126,13 @@ void GNSSFlowgraph::init() enable_osnma_rx_ = true; const auto certFilePath = configuration_->property("GNSS-SDR.osnma_public_key", CRTFILE_DEFAULT); const auto merKleTreePath = configuration_->property("GNSS-SDR.osnma_merkletree", MERKLEFILE_DEFAULT); - osnma_rx_ = osnma_msg_receiver_make(certFilePath, merKleTreePath); + std::string osnma_mode = configuration_->property("GNSS-SDR.osnma_mode", std::string("")); + bool strict_mode = false; + if (osnma_mode == "strict") + { + strict_mode = true; + } + osnma_rx_ = osnma_msg_receiver_make(certFilePath, merKleTreePath, strict_mode); } else { diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/system_parameters/osnma_helper.cc index 3ce589302..23b67707a 100644 --- a/src/core/system_parameters/osnma_helper.cc +++ b/src/core/system_parameters/osnma_helper.cc @@ -16,15 +16,26 @@ #include "osnma_helper.h" #include +#include #include #include #include -#include // timezone -uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const{ + +Osnma_Helper::Osnma_Helper() +{ + GST_START_EPOCH.tm_mday = 22; + GST_START_EPOCH.tm_mon = 7; // August (0-based) + GST_START_EPOCH.tm_year = 1999 - 1900; +} + + +uint32_t Osnma_Helper::compute_gst(uint32_t WN, uint32_t TOW) const +{ return (WN & 0x00000FFF) << 20 | (TOW & 0x000FFFFF); } + uint32_t Osnma_Helper::compute_gst(tm& input) { auto epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH)); @@ -34,23 +45,28 @@ uint32_t Osnma_Helper::compute_gst(tm& input) auto duration_sec = std::chrono::duration_cast(input_time_point - epoch_time_point); // Calculate the week number (WN) and time of week (TOW) - uint32_t sec_in_week = 7 * 24 * 60 * 60; - uint32_t week_number = duration_sec.count() / sec_in_week; - uint32_t time_of_week = duration_sec.count() % sec_in_week; + const uint32_t sec_in_week = 604800; + const uint32_t week_number = duration_sec.count() / sec_in_week; + const uint32_t time_of_week = duration_sec.count() % sec_in_week; return compute_gst(week_number, time_of_week); } + uint32_t Osnma_Helper::compute_gst_now() { - std::chrono::time_point epoch_time_point = std::chrono::system_clock::from_time_t(mktime(&GST_START_EPOCH) - timezone); -// auto time_utc = std::chrono::time_point_cast(time).time_since_epoch(); + time_t now = time(nullptr); + struct tm local_tm = *std::localtime(&now); + struct tm utc_tm = *std::gmtime(&now); + auto timezone_offset = std::mktime(&utc_tm) - std::mktime(&local_tm); + auto epoch_time_point = std::chrono::system_clock::from_time_t(std::mktime(&GST_START_EPOCH) - timezone_offset) + std::chrono::seconds(13); auto duration_sec = std::chrono::duration_cast(std::chrono::system_clock::now() - epoch_time_point); - uint32_t sec_in_week = 7 * 24 * 60 * 60; - uint32_t week_number = duration_sec.count() / sec_in_week; - uint32_t time_of_week = duration_sec.count() % sec_in_week; + const uint32_t sec_in_week = 604800; + const uint32_t week_number = duration_sec.count() / sec_in_week; + const uint32_t time_of_week = duration_sec.count() % sec_in_week; return compute_gst(week_number, time_of_week); } + std::vector Osnma_Helper::gst_to_uint8(uint32_t GST) const { std::vector res; @@ -145,12 +161,15 @@ std::vector Osnma_Helper::convert_from_hex_string(const std::string& he return result; } -uint32_t Osnma_Helper::get_WN(uint32_t GST) + + +uint32_t Osnma_Helper::get_WN(uint32_t GST) const { return (GST & 0xFFF00000) >> 20; } -uint32_t Osnma_Helper::get_TOW(uint32_t GST) + + +uint32_t Osnma_Helper::get_TOW(uint32_t GST) const { return GST & 0x000FFFFF; } - diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/system_parameters/osnma_helper.h index 703a4fd0d..c6b367664 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/system_parameters/osnma_helper.h @@ -18,27 +18,34 @@ #define GNSS_SDR_OSNMA_HELPER_H -#include #include +#include #include #include + +/** \addtogroup Core + * \{ */ +/** \addtogroup System_Parameters + * \{ */ + class Osnma_Helper { public: - Osnma_Helper() = default; + Osnma_Helper(); ~Osnma_Helper() = default; uint32_t compute_gst(uint32_t WN, uint32_t TOW) const; uint32_t compute_gst(std::tm& input); uint32_t compute_gst_now(); - uint32_t get_WN(uint32_t GST); - uint32_t get_TOW(uint32_t GST); + uint32_t get_WN(uint32_t GST) const; + uint32_t get_TOW(uint32_t GST) const; std::vector gst_to_uint8(uint32_t GST) const; std::vector bytes(const std::string& binaryString) const; std::string verification_status_str(int status) const; std::string convert_to_hex_string(const std::vector& vector) const; std::vector convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto - - std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; + std::tm GST_START_EPOCH{}; }; +/** \} */ +/** \} */ #endif // GNSS_SDR_OSNMA_HELPER_H From 8a45df29a88936cd24bed211717d5b4a82177a13 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 5 Aug 2024 10:29:01 +0200 Subject: [PATCH 205/219] Some API improvements and a bug fix (#18) * Clang Tidy fixes * Fix reading of .crt files with GnuTLS * Hide d_crypto pointer from public API * Read public key type also from .pem files --------- Co-authored-by: cesaaargm --- src/core/libs/CMakeLists.txt | 1 - src/core/libs/osnma_msg_receiver.cc | 12 +- src/core/libs/osnma_msg_receiver.h | 37 ++--- src/core/system_parameters/gnss_crypto.cc | 144 +++++++++++++++--- .../osnma/gnss_crypto_test.cc | 1 + .../osnma/osnma_test_vectors.cc | 2 +- 6 files changed, 157 insertions(+), 40 deletions(-) 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"); } From a1ef5639884c8a3e6f2929b11db4c884dce774b2 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Mon, 5 Aug 2024 13:06:28 +0200 Subject: [PATCH 206/219] Fix for OpenSSL 1.0 (#20) * Clang Tidy fixes * Fix for OpenSSL 1.0 --------- Co-authored-by: cesaaargm --- src/core/system_parameters/gnss_crypto.cc | 91 +++++++++++++++++++++-- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 9d7662d09..fd1403539 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -1210,15 +1210,38 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) } 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") + + if (nid == 0) { - d_PublicKeyType = "ECDSA P-256"; + BIGNUM* p = BN_new(); + if (EC_GROUP_get_curve_GFp(group, p, nullptr, nullptr, nullptr) == 1) + { + char* p_str = BN_bn2hex(p); + const std::string pcstr(p_str); + if (pcstr.size() == 64) + { + d_PublicKeyType = "ECDSA P-256"; + } + else if (pcstr.size() == 132) + { + d_PublicKeyType = "ECDSA P-521"; + } + OPENSSL_free(p_str); + } + BN_free(p); } - else if (curve_str == "secp521r1") + else { - d_PublicKeyType = "ECDSA P-521"; + 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); @@ -1410,9 +1433,16 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) pubkey_copy(pubkey, &d_PublicKey); EVP_PKEY_free(pubkey); #else // OpenSSL 1.x +#if USE_OPENSSL_111 // 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); + if (!group) + { + X509_free(cert); + EC_KEY_free(ec_key); + return false; + } const int nid = EC_GROUP_get_curve_name(group); if (nid == NID_X9_62_prime256v1) { @@ -1422,7 +1452,56 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { d_PublicKeyType = "ECDSA P-521"; } +#else + EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pubkey); + if (!ec_key) + { + X509_free(cert); + return false; + } + // Get the EC_GROUP from the EC_KEY + const EC_GROUP* group = EC_KEY_get0_group(ec_key); + if (!group) + { + X509_free(cert); + EC_KEY_free(ec_key); + return false; + } + const int nid = EC_GROUP_get_curve_name(group); + if (nid == 0) + { + BIGNUM* p = BN_new(); + if (EC_GROUP_get_curve_GFp(group, p, nullptr, nullptr, nullptr) == 1) + { + char* p_str = BN_bn2hex(p); + const std::string pcstr(p_str); + if (pcstr.size() == 64) + { + d_PublicKeyType = "ECDSA P-256"; + } + else if (pcstr.size() == 132) + { + d_PublicKeyType = "ECDSA P-521"; + } + OPENSSL_free(p_str); + } + BN_free(p); + } + else + { + 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"; + } + } +#endif EC_KEY* ec_pubkey = EVP_PKEY_get1_EC_KEY(pubkey); EVP_PKEY_free(pubkey); if (!ec_pubkey) From 7367b56725c2a9c00aa795c001b960ef2e529e09 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Tue, 6 Aug 2024 12:28:01 +0200 Subject: [PATCH 207/219] Improve test (#21) * Clang Tidy fixes * Improve GnssCryptoTest.VerifyPublicKeyStorage test --------- Co-authored-by: cesaaargm --- src/core/system_parameters/gnss_crypto.cc | 104 ++++++++++-------- .../osnma/gnss_crypto_test.cc | 57 +++++++--- 2 files changed, 99 insertions(+), 62 deletions(-) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index fd1403539..e664e4f50 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -794,13 +794,17 @@ std::vector Gnss_Crypto::get_merkle_root() const std::string Gnss_Crypto::get_public_key_type() const { + if (d_PublicKeyType.empty()) + { + return std::string("Unknown"); + } return d_PublicKeyType; } void Gnss_Crypto::set_public_key(const std::vector& publicKey) { - d_PublicKeyType = "Unknown"; + d_PublicKeyType = std::string("Unknown"); #if USE_GNUTLS_FALLBACK gnutls_pubkey_t pubkey{}; gnutls_ecc_curve_t curve; @@ -812,13 +816,13 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) if (size_pk == 33) { curve = GNUTLS_ECC_CURVE_SECP256R1; - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("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"; + d_PublicKeyType = std::string("ECDSA P-521"); decompress_public_key_secp521r1(publicKey, x, y); } else @@ -836,6 +840,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) { gnutls_pubkey_deinit(pubkey); LOG(WARNING) << "GnuTLS: error setting the OSNMA public key: " << gnutls_strerror(ret); + d_PublicKeyType = std::string("Unknown"); return; } pubkey_copy(pubkey, &d_PublicKey); @@ -861,11 +866,11 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) if (public_key_size == 33) { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (public_key_size == 67) { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } ctx = EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr); @@ -875,6 +880,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) EVP_PKEY_CTX_free(ctx); OSSL_PARAM_free(params); OSSL_PARAM_BLD_free(param_bld); + d_PublicKeyType = std::string("Unknown"); return; } @@ -884,6 +890,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) EVP_PKEY_CTX_free(ctx); OSSL_PARAM_free(params); OSSL_PARAM_BLD_free(param_bld); + d_PublicKeyType = std::string("Unknown"); return; } @@ -898,15 +905,16 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) if (publicKey.size() == 33) // ECDSA-P-256 { group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else // ECDSA-P-521 { group = EC_GROUP_new_by_curve_name(NID_secp521r1); - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-521"); } if (!group) { + d_PublicKeyType = std::string("Unknown"); return; } @@ -914,6 +922,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) if (!point) { EC_GROUP_free(group); + d_PublicKeyType = std::string("Unknown"); return; } @@ -921,6 +930,7 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) { EC_GROUP_free(group); EC_POINT_free(point); + d_PublicKeyType = std::string("Unknown"); return; } @@ -936,18 +946,23 @@ void Gnss_Crypto::set_public_key(const std::vector& publicKey) { EC_GROUP_free(group); EC_POINT_free(point); + d_PublicKeyType = std::string("Unknown"); return; } - if (!EC_KEY_set_public_key(ec_key, point)) { EC_KEY_free(ec_key); EC_POINT_free(point); EC_GROUP_free(group); + d_PublicKeyType = std::string("Unknown"); return; } if (!pubkey_copy(ec_key, &d_PublicKey)) { + EC_KEY_free(ec_key); + EC_POINT_free(point); + EC_GROUP_free(group); + d_PublicKeyType = std::string("Unknown"); return; } EC_KEY_free(ec_key); @@ -1034,11 +1049,11 @@ void Gnss_Crypto::read_merkle_xml(const std::string& merkleFilePath) LOG(INFO) << "OSNMA Merkletree - PK Type: " << pkType; if (pkType == "ECDSA P-256/SHA-256") { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (pkType == "ECDSA P-521/SHA-512") { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } } for (pugi::xml_node treeNode : merkleTree.children("TreeNode")) @@ -1075,7 +1090,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) { return; } - d_PublicKeyType = "Unknown"; + d_PublicKeyType = std::string("Unknown"); std::string pemContent((std::istreambuf_iterator(pemFile)), std::istreambuf_iterator()); #if USE_GNUTLS_FALLBACK // Import the PEM data @@ -1108,8 +1123,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) } pk_algorithm = static_cast(ret); - - if (pk_algorithm == GNUTLS_PK_ECDSA) + if (pk_algorithm == GNUTLS_PK_ECC) { gnutls_ecc_curve_t curve; ret = gnutls_pubkey_export_ecc_raw(pubkey, &curve, nullptr, nullptr); @@ -1122,11 +1136,11 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) if (curve == GNUTLS_ECC_CURVE_SECP256R1) { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (curve == GNUTLS_ECC_CURVE_SECP521R1) { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } else { @@ -1168,11 +1182,11 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) { if (strcmp(curve_name, "prime256v1") == 0 || strcmp(curve_name, "P-256") == 0) { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (strcmp(curve_name, "secp521r1") == 0 || strcmp(curve_name, "P-521") == 0) { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } else { @@ -1210,7 +1224,6 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) } const EC_GROUP* group = EC_KEY_get0_group(pubkey); int nid = EC_GROUP_get_curve_name(group); - if (nid == 0) { BIGNUM* p = BN_new(); @@ -1220,11 +1233,11 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) const std::string pcstr(p_str); if (pcstr.size() == 64) { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (pcstr.size() == 132) { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } OPENSSL_free(p_str); } @@ -1236,11 +1249,11 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) const std::string curve_str(curve_name); if (curve_str == "prime256v1") { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (curve_str == "secp521r1") { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } } @@ -1262,8 +1275,7 @@ void Gnss_Crypto::readPublicKeyFromPEM(const std::string& pemFilePath) bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { - d_PublicKeyType = "Unknown"; -#if USE_GNUTLS_FALLBACK + d_PublicKeyType = std::string("Unknown"); // Open the .crt file std::ifstream crtFile(crtFilePath, std::ios::binary); if (!crtFile.is_open()) @@ -1278,8 +1290,8 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) } const std::vector buffer((std::istreambuf_iterator(crtFile)), std::istreambuf_iterator()); +#if USE_GNUTLS_FALLBACK const gnutls_datum_t buffer_datum = {const_cast(buffer.data()), static_cast(buffer.size())}; - gnutls_x509_crt_t cert; gnutls_x509_crt_init(&cert); int ret = gnutls_x509_crt_import(cert, &buffer_datum, GNUTLS_X509_FMT_PEM); @@ -1316,8 +1328,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) } pk_algorithm = static_cast(ret); - - if (pk_algorithm == GNUTLS_PK_ECDSA) + if (pk_algorithm == GNUTLS_PK_ECC) { gnutls_ecc_curve_t curve; ret = gnutls_pubkey_export_ecc_raw(pubkey, &curve, nullptr, nullptr); @@ -1331,11 +1342,11 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) if (curve == GNUTLS_ECC_CURVE_SECP256R1) { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (curve == GNUTLS_ECC_CURVE_SECP521R1) { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } else { @@ -1357,16 +1368,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) gnutls_x509_crt_deinit(cert); gnutls_pubkey_deinit(pubkey); #else // OpenSSL - // Open the .crt file - std::ifstream crtFile(crtFilePath, std::ios::binary); - if (!crtFile.is_open()) - { - LOG(WARNING) << "OpenSSL: Unable to open file: " << crtFilePath; - return false; - } - // Read certificate - std::vector buffer((std::istreambuf_iterator(crtFile)), std::istreambuf_iterator()); BIO* bio = BIO_new_mem_buf(buffer.data(), buffer.size()); if (!bio) { @@ -1387,6 +1389,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { LOG(WARNING) << "OpenSSL: Failed to extract the public key"; X509_free(cert); + BIO_free(bio); return false; } #if USE_OPENSSL_3 @@ -1403,24 +1406,25 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { if (strcmp(curve_name, "prime256v1") == 0 || strcmp(curve_name, "P-256") == 0) { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (strcmp(curve_name, "secp521r1") == 0 || strcmp(curve_name, "P-521") == 0) { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } else { LOG(WARNING) << "OpenSSL: Trying to read an unknown EC curve"; X509_free(cert); + BIO_free(bio); return false; } } else { - d_PublicKeyType = "Unknown EC curve"; LOG(WARNING) << "OpenSSL: Trying to read an unknown EC curve"; X509_free(cert); + BIO_free(bio); return false; } } @@ -1428,6 +1432,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { LOG(WARNING) << "OpenSSL: Trying to read an unknown key type"; X509_free(cert); + BIO_free(bio); return false; } pubkey_copy(pubkey, &d_PublicKey); @@ -1441,22 +1446,25 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { X509_free(cert); EC_KEY_free(ec_key); + BIO_free(bio); return false; } const int nid = EC_GROUP_get_curve_name(group); if (nid == NID_X9_62_prime256v1) { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (nid == NID_secp521r1) { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } + EC_KEY_free(ec_key); #else EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(pubkey); if (!ec_key) { X509_free(cert); + BIO_free(bio); return false; } @@ -1466,6 +1474,7 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) { X509_free(cert); EC_KEY_free(ec_key); + BIO_free(bio); return false; } const int nid = EC_GROUP_get_curve_name(group); @@ -1478,11 +1487,11 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) const std::string pcstr(p_str); if (pcstr.size() == 64) { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (pcstr.size() == 132) { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } OPENSSL_free(p_str); } @@ -1494,13 +1503,14 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) const std::string curve_str(curve_name); if (curve_str == "prime256v1") { - d_PublicKeyType = "ECDSA P-256"; + d_PublicKeyType = std::string("ECDSA P-256"); } else if (curve_str == "secp521r1") { - d_PublicKeyType = "ECDSA P-521"; + d_PublicKeyType = std::string("ECDSA P-521"); } } + EC_KEY_free(ec_key); #endif EC_KEY* ec_pubkey = EVP_PKEY_get1_EC_KEY(pubkey); EVP_PKEY_free(pubkey); 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 1904a16e9..2e536fb73 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 @@ -49,10 +49,9 @@ TEST(GnssCryptoTest, VerifyPubKeyImport) TEST(GnssCryptoTest, VerifyPublicKeyStorage) { - auto d_crypto = std::make_unique(); - const std::string f1("./osnma_test_file1.pem"); const std::string f2("./osnma_test_file2.pem"); + const std::string f3("./osnma_test_file3.pem"); // Input taken from RG 1.3 A7.1 // compressed ECDSA P-256 format @@ -62,15 +61,17 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) 0x63, 0xFF, 0xA0, 0x91, 0x41, 0x0F, 0xC1, 0x58, 0xFB, 0xB7, 0x79, 0x80, 0xEA}; + auto d_crypto = std::make_unique(); + ASSERT_FALSE(d_crypto->have_public_key()); + ASSERT_TRUE(d_crypto->get_public_key_type() == "Unknown"); d_crypto->set_public_key(publicKey); - bool result = d_crypto->store_public_key(f1); - - ASSERT_TRUE(result); + ASSERT_TRUE(d_crypto->have_public_key()); + ASSERT_TRUE(d_crypto->store_public_key(f1)); auto d_crypto2 = std::make_unique(f1, ""); - bool result2 = d_crypto2->store_public_key(f2); - ASSERT_TRUE(result2); + ASSERT_TRUE(d_crypto2->have_public_key()); ASSERT_TRUE(d_crypto2->get_public_key_type() == "ECDSA P-256"); + ASSERT_TRUE(d_crypto2->store_public_key(f2)); std::ifstream t(f1); std::string content_file((std::istreambuf_iterator(t)), std::istreambuf_iterator()); @@ -80,9 +81,39 @@ TEST(GnssCryptoTest, VerifyPublicKeyStorage) ASSERT_EQ(content_file, content_file2); + // P-521 Public key in compressed X format + std::vector publicKey_P521 = { + 0x03, 0x00, 0x28, 0x35, 0xBB, 0xE9, 0x24, 0x59, 0x4E, 0xF0, + 0xE3, 0xA2, 0xDB, 0xC0, 0x49, 0x30, 0x60, 0x7C, 0x61, 0x90, + 0xE4, 0x03, 0xE0, 0xC7, 0xB8, 0xC2, 0x62, 0x37, 0xF7, 0x58, + 0x56, 0xBE, 0x63, 0x5C, 0x97, 0xF7, 0x53, 0x64, 0x7E, 0xE1, + 0x0C, 0x07, 0xD3, 0x97, 0x8D, 0x58, 0x46, 0xFD, 0x6E, 0x06, + 0x44, 0x01, 0xA7, 0xAA, 0xC4, 0x95, 0x13, 0x5D, 0xC9, 0x77, + 0x26, 0xE9, 0xF8, 0x72, 0x0C, 0xD3, 0x88}; + + d_crypto->set_public_key(publicKey_P521); + ASSERT_TRUE(d_crypto->have_public_key()); + ASSERT_TRUE(d_crypto->get_public_key_type() == "ECDSA P-521"); + ASSERT_TRUE(d_crypto->store_public_key(f3)); + + auto d_crypto3 = std::make_unique(f3, ""); + ASSERT_TRUE(d_crypto3->have_public_key()); + ASSERT_TRUE(d_crypto3->get_public_key_type() == "ECDSA P-521"); + + std::vector wrong_publicKey = { + 0x03, 0x03, 0xB2, 0xCE, 0x64, 0xBC, 0x20, 0x7B, 0xDD, 0x8B, + 0xC4, 0xDF, 0x85, 0x91, 0x87, 0xFC, 0xB6, 0x86, 0x32, 0x0D, + 0x63, 0xFF, 0xA0}; + + auto d_crypto4 = std::make_unique(); + d_crypto4->set_public_key(wrong_publicKey); + ASSERT_FALSE(d_crypto4->have_public_key()); + ASSERT_TRUE(d_crypto4->get_public_key_type() == "Unknown"); + errorlib::error_code ec; ASSERT_TRUE(fs::remove(fs::path(f1), ec)); ASSERT_TRUE(fs::remove(fs::path(f2), ec)); + ASSERT_TRUE(fs::remove(fs::path(f3), ec)); } @@ -263,13 +294,11 @@ TEST(GnssCryptoTest, VerifySignatureP256) 0x79, 0x80, 0xEA}; d_crypto->set_public_key(publicKey); - bool result = d_crypto->verify_signature_ecdsa_p256(message, signature); - ASSERT_TRUE(result); + ASSERT_TRUE(d_crypto->verify_signature_ecdsa_p256(message, signature)); std::vector wrong_signature = signature; wrong_signature[1] = 1; - bool result2 = d_crypto->verify_signature_ecdsa_p256(message, wrong_signature); - ASSERT_TRUE(!result2); + ASSERT_FALSE(d_crypto->verify_signature_ecdsa_p256(message, wrong_signature)); } @@ -309,11 +338,9 @@ TEST(GnssCryptoTest, VerifySignatureP521) 0x28, 0xEF}; d_crypto->set_public_key(publicKey); - bool result = d_crypto->verify_signature_ecdsa_p521(message, signature); - ASSERT_TRUE(result); + ASSERT_TRUE(d_crypto->verify_signature_ecdsa_p521(message, signature)); std::vector wrong_signature = signature; wrong_signature[1] = 1; - bool result2 = d_crypto->verify_signature_ecdsa_p521(message, wrong_signature); - ASSERT_TRUE(!result2); + ASSERT_FALSE(d_crypto->verify_signature_ecdsa_p521(message, wrong_signature)); } From 5a6d19be702b99a299ab5c5a8f61214dc48ce0f8 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Wed, 7 Aug 2024 09:13:13 +0200 Subject: [PATCH 208/219] Fix some defects detected by Coverity Scan (#22) * Clang Tidy fixes * Fix defects detected by Coverity Scan --------- Co-authored-by: cesaaargm --- src/core/libs/osnma_msg_receiver.cc | 12 ++++++------ src/core/system_parameters/gnss_crypto.cc | 5 +++-- .../osnma/gnss_crypto_test.cc | 5 +++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index e77260be5..ec58a3eef 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -271,7 +271,7 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& { 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; + double duration_hours = (final_GST - d_GST_PKR_PKREV_start) / 3600.0; LOG(INFO) << "Galileo OSNMA: Public Key Renewal :: Finished at GST=" << duration_hours << ", Duration=" << duration_hours << " h"; std::cout << "Galileo OSNMA: Public Key Renewal :: Finished at GST=" << duration_hours << ", Duration=" << duration_hours << " h" << std::endl; } @@ -1400,7 +1400,7 @@ std::vector osnma_msg_receiver::build_message(Tag& tag) const // Add applicable NavData bits to message std::string applicable_nav_data = d_nav_data_manager->get_navigation_data(tag); std::vector applicable_nav_data_bytes = d_helper->bytes(applicable_nav_data); - tag.nav_data = applicable_nav_data; // update tag with applicable data + tag.nav_data = std::move(applicable_nav_data); // update tag with applicable data // Convert and add OSNMA_NavData bytes into the message, taking care of that NMAS has only 2 bits for (uint8_t byte : applicable_nav_data_bytes) @@ -1619,11 +1619,11 @@ bool osnma_msg_receiver::verify_macseq(const MACK_message& mack) // Assign relevant sequence based on subframe time if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present. { - applicable_sequence = sq1; + applicable_sequence = std::move(sq1); } else if (mack.TOW % 60 >= 30) { - applicable_sequence = sq2; + applicable_sequence = std::move(sq2); } if (mack.tag_and_info.size() != applicable_sequence.size() - 1) { @@ -1864,11 +1864,11 @@ std::vector osnma_msg_receiver::verify_macseq_new(const MACK_ // Assign relevant sequence based on subframe time if (mack.TOW % 60 < 30) // tried GST_Sf and it does not support the data present. { - applicable_sequence = sq1; + applicable_sequence = std::move(sq1); } else if (mack.TOW % 60 >= 30) { - applicable_sequence = sq2; + applicable_sequence = std::move(sq2); } if (mack.tag_and_info.size() != applicable_sequence.size() - 1) { diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index e664e4f50..27251a5a7 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -25,6 +25,7 @@ #include #include #include +#include #if USE_GNUTLS_FALLBACK #include @@ -625,7 +626,7 @@ std::vector Gnss_Crypto::compute_HMAC_SHA_256(const std::vector Gnss_Crypto::compute_CMAC_AES(const std::vector& k EVP_MAC_free(mac); aux.resize(output_length); - output = aux; + output = std::move(aux); #else // OpenSSL 1.x size_t mac_length = 0; // to hold the length of the MAC output 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 2e536fb73..58dcc3f2f 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 @@ -22,6 +22,7 @@ #include #include #include +#include class GnssCryptoTest : public ::testing::Test { @@ -296,7 +297,7 @@ TEST(GnssCryptoTest, VerifySignatureP256) d_crypto->set_public_key(publicKey); ASSERT_TRUE(d_crypto->verify_signature_ecdsa_p256(message, signature)); - std::vector wrong_signature = signature; + std::vector wrong_signature = std::move(signature); wrong_signature[1] = 1; ASSERT_FALSE(d_crypto->verify_signature_ecdsa_p256(message, wrong_signature)); } @@ -340,7 +341,7 @@ TEST(GnssCryptoTest, VerifySignatureP521) d_crypto->set_public_key(publicKey); ASSERT_TRUE(d_crypto->verify_signature_ecdsa_p521(message, signature)); - std::vector wrong_signature = signature; + std::vector wrong_signature = std::move(signature); wrong_signature[1] = 1; ASSERT_FALSE(d_crypto->verify_signature_ecdsa_p521(message, wrong_signature)); } From 98f1cdfb6bf31bcc0243e5fabe2b48684f111482 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Thu, 8 Aug 2024 09:33:48 +0200 Subject: [PATCH 209/219] More minor fixes (#23) * Clang Tidy fixes * Fix defects detected by Coverity Scan * Fix for OpenSSL 1.0 --------- Co-authored-by: cesaaargm --- src/core/libs/osnma_msg_receiver.cc | 8 ++++---- src/core/system_parameters/gnss_crypto.cc | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index ec58a3eef..46aca3fd0 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -292,7 +292,7 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& // 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; + double duration_hours = (final_GST - d_GST_PKR_PKREV_start) / 3600.0; 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 << "]" @@ -797,9 +797,9 @@ void osnma_msg_receiver::read_mack_header() { lt_bits = it->second; } - if (lt_bits == 0) + if (lt_bits < 16) { - return; // C: TODO if Tag length is 0, what is the action? no verification possible of NavData for sure. + return; // The 16 is to avoid negative shifts if shorter tags were defined } uint16_t macseq = 0; uint8_t cop = 0; @@ -1330,7 +1330,7 @@ bool osnma_msg_receiver::verify_tag(Tag& tag) const { lt_bits = it2->second; } - if (lt_bits == 0) + if (lt_bits < 16) { return false; } diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/system_parameters/gnss_crypto.cc index 27251a5a7..d92a62224 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/system_parameters/gnss_crypto.cc @@ -1370,7 +1370,11 @@ bool Gnss_Crypto::readPublicKeyFromCRT(const std::string& crtFilePath) gnutls_pubkey_deinit(pubkey); #else // OpenSSL // Read certificate +#if !(USE_OPENSSL_3 || USE_OPENSSL_111) + BIO* bio = BIO_new_mem_buf(const_cast(buffer.data()), buffer.size()); +#else BIO* bio = BIO_new_mem_buf(buffer.data(), buffer.size()); +#endif if (!bio) { LOG(WARNING) << "OpenSSL: Unable to create BIO for file: " << crtFilePath; From 79da7787ffa3ac852f81fc1b672c04a641b36492 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 10 Aug 2024 11:31:15 +0200 Subject: [PATCH 210/219] Move files (#24) * Bump local version of GoogleTest to 1.15.2 and Protocol Buffers to 27.3 * Avoid code duplication in CMake modules * Update clang-tidy job * Clang Tidy fixes * Improve efficiency of Concurrent_Map and Concurrent_Queue classes * Fix segmentation fault if the SignalSource implementation is not available * Moved decimation factor count variable to the class * Avoid possible runtime error when PVT.enable_rx_clock_correction=true * Fix formatting * Fix clang-tidy job * Move receiver-related classes to src/core/libs * Uniformize cmake module names * Fix formatting * Make clang-tidy happy * Fix crypto benchmarks * Fixes for old systems * Instantiate sources only once --------- Co-authored-by: cesaaargm Co-authored-by: Xavier Guerrero-Pau --- .gitignore | 10 ++- CMakeLists.txt | 2 +- cmake/Modules/FindGNURADIO.cmake | 2 + ...nssSdrCrypto.cmake => GnsssdrCrypto.cmake} | 0 .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 2 +- .../signal_source/libs/ad936x_iio_custom.cc | 40 +++++---- src/core/libs/CMakeLists.txt | 43 ++++++---- .../gnss_crypto.cc | 6 +- .../{system_parameters => libs}/gnss_crypto.h | 2 +- .../osnma_helper.cc | 0 .../osnma_helper.h | 2 +- .../osnma_nav_data_manager.cc | 75 +++++++++------- .../osnma_nav_data_manager.h | 46 ++++++---- src/core/monitor/gnss_synchro_monitor.cc | 2 +- src/core/monitor/gnss_synchro_monitor.h | 3 +- src/core/receiver/concurrent_map.h | 40 ++++----- src/core/receiver/concurrent_queue.h | 61 ++++++------- src/core/receiver/gnss_block_factory.cc | 1 + src/core/receiver/gnss_flowgraph.cc | 13 ++- src/core/system_parameters/CMakeLists.txt | 10 --- src/core/system_parameters/osnma_data.h | 44 ++++++---- src/tests/benchmarks/CMakeLists.txt | 2 +- src/tests/benchmarks/benchmark_crypto.cc | 86 ++++++------------- 23 files changed, 260 insertions(+), 232 deletions(-) rename cmake/Modules/{GnssSdrCrypto.cmake => GnsssdrCrypto.cmake} (100%) rename src/core/{system_parameters => libs}/gnss_crypto.cc (99%) rename src/core/{system_parameters => libs}/gnss_crypto.h (99%) rename src/core/{system_parameters => libs}/osnma_helper.cc (100%) rename src/core/{system_parameters => libs}/osnma_helper.h (97%) rename src/core/{system_parameters => libs}/osnma_nav_data_manager.cc (83%) rename src/core/{system_parameters => libs}/osnma_nav_data_manager.h (61%) diff --git a/.gitignore b/.gitignore index dd9645f6d..4a50387fa 100644 --- a/.gitignore +++ b/.gitignore @@ -15,11 +15,17 @@ src/utils/nav-listener/build .cproject .idea cmake-build-debug/ +cmake-build-release/ /install .DS_Store .pydevproject .vscode/ .vs/ Testing/ -/build/* -/cmake-build-release/* \ No newline at end of file +GSDR* +PVT_* +HAS_* +gnss_sdr_pvt.nmea +build-debug/ +build-release/ + diff --git a/CMakeLists.txt b/CMakeLists.txt index eb113bad3..e8dfc5825 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2215,7 +2215,7 @@ endif() ################################################################################ # OpenSSL https://www.openssl.org/ or GnuTLS - https://www.gnutls.org/ ################################################################################ -include(GnssSdrCrypto) +include(GnsssdrCrypto) diff --git a/cmake/Modules/FindGNURADIO.cmake b/cmake/Modules/FindGNURADIO.cmake index cfaf51764..d976d0e28 100644 --- a/cmake/Modules/FindGNURADIO.cmake +++ b/cmake/Modules/FindGNURADIO.cmake @@ -366,8 +366,10 @@ if(GNURADIO_RUNTIME_INCLUDE_DIRS) ) if(CMAKE_VERSION VERSION_GREATER 3.13) target_link_libraries(Gnuradio::filter INTERFACE Log4cpp::log4cpp) + target_link_libraries(Gnuradio::runtime INTERFACE Log4cpp::log4cpp) else() set_target_properties(Gnuradio::filter PROPERTIES INTERFACE_LINK_LIBRARIES Log4cpp::log4cpp) + set_target_properties(Gnuradio::runtime PROPERTIES INTERFACE_LINK_LIBRARIES Log4cpp::log4cpp) endif() endif() if(${_uses_spdlog}) diff --git a/cmake/Modules/GnssSdrCrypto.cmake b/cmake/Modules/GnsssdrCrypto.cmake similarity index 100% rename from cmake/Modules/GnssSdrCrypto.cmake rename to cmake/Modules/GnsssdrCrypto.cmake diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 109b935c7..2ffe95d24 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -2228,7 +2228,7 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item d_gnss_observables_map_t1 = d_gnss_observables_map; // ### select the rx_time and interpolate observables at that time - if (!d_gnss_observables_map_t0.empty()) + if (!d_gnss_observables_map_t0.empty() && !d_gnss_observables_map_t1.empty()) { const auto t0_int_ms = static_cast(d_gnss_observables_map_t0.cbegin()->second.RX_time * 1000.0); const uint32_t adjust_next_obs_interval_ms = d_observable_interval_ms - t0_int_ms % d_observable_interval_ms; diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index 2869081f2..72461bafd 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -13,6 +13,7 @@ * ----------------------------------------------------------------------------- */ #include "ad936x_iio_custom.h" +#include "display.h" #include #include #include @@ -44,6 +45,7 @@ ad936x_iio_custom::ad936x_iio_custom(int debug_level_, int log_level_) n_channels = 0; } + ad936x_iio_custom::~ad936x_iio_custom() { // disable TX @@ -59,11 +61,13 @@ void ad936x_iio_custom::set_gnsstime_queue(std::shared_ptr> queue) { Pps_queue = std::move(queue); } + bool ad936x_iio_custom::initialize_device(std::string pluto_device_uri, std::string board_type) { // Find devices @@ -125,7 +129,6 @@ bool ad936x_iio_custom::initialize_device(std::string pluto_device_uri, std::str return false; } - phy = iio_context_find_device(ctx, "ad9361-phy"); if (phy == NULL) @@ -328,7 +331,6 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, configure_params(dds_dev, params_dds); } - return true; } @@ -345,6 +347,7 @@ bool ad936x_iio_custom::check_device() } } + bool ad936x_iio_custom::get_iio_param(iio_device *dev, const std::string ¶m, std::string &value) { struct iio_channel *chn = 0; @@ -386,6 +389,7 @@ bool ad936x_iio_custom::get_iio_param(iio_device *dev, const std::string ¶m, } } + bool ad936x_iio_custom::read_die_temp(double &temp_c) { std::string temp_mC_str; @@ -410,6 +414,8 @@ bool ad936x_iio_custom::read_die_temp(double &temp_c) return false; } } + + bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, long long sample_rate_, long long freq_, @@ -425,7 +431,6 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, double lo_attenuation_db_, bool high_side_lo_, int tx_lo_channel_) - { if (check_device() == false) return false; @@ -610,14 +615,12 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, std::cerr << "Warning: rf_port_select write returned: " << ret << "\n"; no_errors = false; } - // ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); // if (ret < 0) // { // std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; // no_errors = false; // } - long long set_rf_bw; ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); if (ret < 0) @@ -630,7 +633,6 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, std::cerr << "Info: rf_bandwidth read returned: " << set_rf_bw << " Hz \n"; } - if (setRXGain(0, gain_mode_rx0_, rf_gain_rx0_) == false) { std::cerr << "Info: setRXGain read returned false \n"; @@ -662,14 +664,12 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, std::cerr << "Warning: rf_port_select write returned: " << ret << "\n"; no_errors = false; } - // ret = iio_channel_attr_write_longlong(phy_ch, "rf_bandwidth", bandwidth_); // if (ret < 0) // { // std::cerr << "Warning: rf_bandwidth write returned: " << ret << "\n"; // no_errors = false; // } - long long set_rf_bw; ret = iio_channel_attr_read_longlong(phy_ch, "rf_bandwidth", &set_rf_bw); if (ret < 0) @@ -702,6 +702,7 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, return no_errors; } + bool ad936x_iio_custom::set_rx_frequency(long long freq_hz) { if (check_device() == false) return false; @@ -747,6 +748,7 @@ bool ad936x_iio_custom::get_rx_frequency(long long &freq_hz) return true; } + bool ad936x_iio_custom::setRXGain(int ch_num, std::string gain_mode, double gain_dB) { if (check_device() == false) return false; @@ -779,6 +781,7 @@ bool ad936x_iio_custom::setRXGain(int ch_num, std::string gain_mode, double gain } } + double ad936x_iio_custom::get_rx_gain(int ch_num) { if (check_device() == false) return -1; @@ -817,6 +820,7 @@ bool ad936x_iio_custom::calibrate([[maybe_unused]] int ch, [[maybe_unused]] doub return true; } + void ad936x_iio_custom::monitor_thread_fn() { uint32_t val; @@ -849,11 +853,12 @@ void ad936x_iio_custom::monitor_thread_fn() // } else { if (val & 4) { - std::cout << "WARNING: IIO status register reported overflow!\n"; - LOG(INFO) << "WARNING: IIO status register reported overflow!"; + std::cout + << TEXT_BOLD_RED + << "WARNING: IIO status register reported overflow!\n"; + LOG(WARNING) << "WARNING: IIO status register reported overflow!"; } - /* Clear bits */ if (val) { @@ -867,6 +872,7 @@ void ad936x_iio_custom::monitor_thread_fn() return; } + void ad936x_iio_custom::stop_record() { receive_samples = false; @@ -915,6 +921,7 @@ void ad936x_iio_custom::PlutoTxEnable(bool txon) } } + void ad936x_iio_custom::setPlutoGpo(int p) { char pins[11]; @@ -953,7 +960,6 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) // 1 Enable // X Enable Mask if Identifier=0xF - if (check_device() == false) return false; // int plutoGpo = 0; int ret; @@ -1006,6 +1012,8 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) return true; } + + void ad936x_iio_custom::get_PPS_timestamp() { GnssTime tow; @@ -1042,7 +1050,6 @@ void ad936x_iio_custom::get_PPS_timestamp() // record pps rise samplestamp associated to the absolute sample counter // PPS rising edge must be associated with the corresponding uBlox time message (tx once a second) - if (GnssTime_queue->timed_wait_and_pop(tow, 2000) == false) { if (receive_samples == true) @@ -1073,6 +1080,8 @@ void ad936x_iio_custom::get_PPS_timestamp() } } } + + bool ad936x_iio_custom::start_sample_rx(bool ppsmode) { // using queues of smart pointers to preallocated buffers @@ -1118,9 +1127,7 @@ bool ad936x_iio_custom::start_sample_rx(bool ppsmode) // start sample overflow detector overflow_monitor_thread = std::thread(&ad936x_iio_custom::monitor_thread_fn, this); - // start PPS and GNSS Time capture thread - if (ppsmode == true) { capture_time_thread = std::thread(&ad936x_iio_custom::get_PPS_timestamp, this); @@ -1128,16 +1135,19 @@ bool ad936x_iio_custom::start_sample_rx(bool ppsmode) return true; } + void ad936x_iio_custom::pop_sample_buffer(std::shared_ptr ¤t_buffer) { used_buffers.wait_and_pop(current_buffer); } + void ad936x_iio_custom::push_sample_buffer(std::shared_ptr ¤t_buffer) { free_buffers.push(current_buffer); } + void ad936x_iio_custom::capture(const std::vector &channels) { if (check_device() == false) return; diff --git a/src/core/libs/CMakeLists.txt b/src/core/libs/CMakeLists.txt index 0396b1e25..cb77ec515 100644 --- a/src/core/libs/CMakeLists.txt +++ b/src/core/libs/CMakeLists.txt @@ -9,36 +9,42 @@ protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${GNSSSDR_SOURCE_DIR}/docs/protobuf/ add_subdirectory(supl) set(CORE_LIBS_SOURCES - ini.cc - INIReader.cc - string_converter.cc - gnss_sdr_supl_client.cc - gnss_sdr_sample_counter.cc - channel_status_msg_receiver.cc channel_event.cc + channel_status_msg_receiver.cc command_event.cc galileo_e6_has_msg_receiver.cc + galileo_tow_map.cc + gnss_crypto.cc + gnss_sdr_sample_counter.cc + gnss_sdr_supl_client.cc + ini.cc + INIReader.cc nav_message_monitor.cc nav_message_udp_sink.cc - galileo_tow_map.cc + osnma_helper.cc osnma_msg_receiver.cc + osnma_nav_data_manager.cc + string_converter.cc ) set(CORE_LIBS_HEADERS + channel_event.h + channel_status_msg_receiver.h + command_event.h + galileo_tow_map.h + gnss_crypto.h + gnss_sdr_sample_counter.h + gnss_sdr_supl_client.h ini.h INIReader.h - string_converter.h - gnss_sdr_supl_client.h - gnss_sdr_sample_counter.h - channel_status_msg_receiver.h - channel_event.h - command_event.h + nav_message_monitor.h nav_message_packet.h nav_message_udp_sink.h - serdes_nav_message.h - nav_message_monitor.h - galileo_tow_map.h + osnma_helper.h osnma_msg_receiver.h + osnma_nav_data_manager.h + serdes_nav_message.h + string_converter.h ) if(ENABLE_FPGA) @@ -96,6 +102,7 @@ target_link_libraries(core_libs PRIVATE algorithms_libs Boost::serialization + Boost::system Pugixml::pugixml ) @@ -123,6 +130,10 @@ target_include_directories(core_libs ${GNSSSDR_SOURCE_DIR}/src/core/interfaces ) +# links to the appropriate library and defines +# USE_GNUTLS_FALLBACK, USE_OPENSSL_3, or USE_OPENSSL_111 accordingly. +link_to_crypto_dependencies(core_libs) + if(USE_GENERIC_LAMBDAS) set(has_generic_lambdas HAS_GENERIC_LAMBDA=1) set(no_has_generic_lambdas HAS_GENERIC_LAMBDA=0) diff --git a/src/core/system_parameters/gnss_crypto.cc b/src/core/libs/gnss_crypto.cc similarity index 99% rename from src/core/system_parameters/gnss_crypto.cc rename to src/core/libs/gnss_crypto.cc index d92a62224..cbe4785ff 100644 --- a/src/core/system_parameters/gnss_crypto.cc +++ b/src/core/libs/gnss_crypto.cc @@ -205,7 +205,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p256(const std::vector& messag { if (!have_public_key()) { - LOG(WARNING) << "Galileo OSNMA KROOT verification error: Public key is not available"; + LOG(WARNING) << "Signature verification error: Public key is not available"; return false; } std::vector digest = this->compute_SHA_256(message); @@ -344,7 +344,7 @@ bool Gnss_Crypto::verify_signature_ecdsa_p521(const std::vector& messag { if (!have_public_key()) { - LOG(WARNING) << "Galileo OSNMA KROOT verification error: Public key is not available"; + LOG(WARNING) << "Signature verification error: Public key is not available"; return false; } @@ -797,7 +797,7 @@ std::string Gnss_Crypto::get_public_key_type() const { if (d_PublicKeyType.empty()) { - return std::string("Unknown"); + return {"Unknown"}; } return d_PublicKeyType; } diff --git a/src/core/system_parameters/gnss_crypto.h b/src/core/libs/gnss_crypto.h similarity index 99% rename from src/core/system_parameters/gnss_crypto.h rename to src/core/libs/gnss_crypto.h index e197d61d0..b308f820b 100644 --- a/src/core/system_parameters/gnss_crypto.h +++ b/src/core/libs/gnss_crypto.h @@ -31,7 +31,7 @@ /** \addtogroup Core * \{ */ -/** \addtogroup System_Parameters +/** \addtogroup Core_Receiver_Library * \{ */ /*! diff --git a/src/core/system_parameters/osnma_helper.cc b/src/core/libs/osnma_helper.cc similarity index 100% rename from src/core/system_parameters/osnma_helper.cc rename to src/core/libs/osnma_helper.cc diff --git a/src/core/system_parameters/osnma_helper.h b/src/core/libs/osnma_helper.h similarity index 97% rename from src/core/system_parameters/osnma_helper.h rename to src/core/libs/osnma_helper.h index c6b367664..a7b2cc332 100644 --- a/src/core/system_parameters/osnma_helper.h +++ b/src/core/libs/osnma_helper.h @@ -25,7 +25,7 @@ /** \addtogroup Core * \{ */ -/** \addtogroup System_Parameters +/** \addtogroup Core_Receiver_Library * \{ */ class Osnma_Helper diff --git a/src/core/system_parameters/osnma_nav_data_manager.cc b/src/core/libs/osnma_nav_data_manager.cc similarity index 83% rename from src/core/system_parameters/osnma_nav_data_manager.cc rename to src/core/libs/osnma_nav_data_manager.cc index 9d5017aec..6d8a16113 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.cc +++ b/src/core/libs/osnma_nav_data_manager.cc @@ -1,23 +1,22 @@ /*! -* \file osnma_nav_data_manager.cc -* \brief Class for Galileo OSNMA navigation data management -* \author Cesare Ghionoiu-Martinez, 2020-2023 cesare.martinez(at)proton.me -* -* ----------------------------------------------------------------------------- -* -* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -* This file is part of GNSS-SDR. -* -* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) -* SPDX-License-Identifier: GPL-3.0-or-later -* -* ----------------------------------------------------------------------------- -*/ + * \file osnma_nav_data_manager.cc + * \brief Class for Galileo OSNMA navigation data management + * \author Cesare Ghionoiu-Martinez, 2020-2023 cesare.martinez(at)proton.me + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ #include "osnma_nav_data_manager.h" #if USE_GLOG_AND_GFLAGS #include // for DLOG -#include #else #include #endif @@ -54,18 +53,20 @@ void OSNMA_nav_data_Manager::update_nav_data(const std::multimap& if (have_PRNd_nav_data(tag.second.PRN_d)) { std::map tow_map = _satellite_nav_data.find(tag.second.PRN_d)->second; - for (auto & tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset + 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) { nav_data = tow_it.second.get_ephemeris_data(); } - else if (tag.second.ADKD == 4){ + else if (tag.second.ADKD == 4) + { nav_data = tow_it.second.get_utc_data(); } // find associated OSNMA_NavData - if (tag.second.nav_data == nav_data){ + if (tag.second.nav_data == nav_data) + { _satellite_nav_data[tag.second.PRN_d][tow_it.first].verified_bits += tag_size; } } @@ -138,16 +139,17 @@ bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) { auto prn_it = _satellite_nav_data.find(tag.PRN_d); - if (prn_it == _satellite_nav_data.end()){ + if (prn_it == _satellite_nav_data.end()) + { return ""; } // satellite was found, check if TOW exists in inner map std::map tow_map = prn_it->second; - for (auto & tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset + for (auto& tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset { // Check if current key (TOW) fulfills condition - if ((tag.TOW - 30 * tag.cop) <= tow_it.first && tow_it.first <= tag.TOW - 30) + if ((tag.TOW - 30 * tag.cop) <= tow_it.first && tow_it.first <= tag.TOW - 30) { if (tag.ADKD == 0 || tag.ADKD == 12) { @@ -156,9 +158,8 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) return tow_it.second.get_ephemeris_data(); } } - else if(tag.ADKD == 4) + else if (tag.ADKD == 4) { - if (!tow_it.second.get_utc_data().empty()) { return tow_it.second.get_utc_data(); @@ -179,17 +180,22 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) */ bool OSNMA_nav_data_Manager::have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) { - if (_satellite_nav_data.find(PRNd) != _satellite_nav_data.end()){ + if (_satellite_nav_data.find(PRNd) != _satellite_nav_data.end()) + { for (auto& data_timestamp : _satellite_nav_data[PRNd]) { - if (nav_bits.size() == EPH_SIZE){ - if (data_timestamp.second.get_ephemeris_data() == nav_bits){ + if (nav_bits.size() == EPH_SIZE) + { + if (data_timestamp.second.get_ephemeris_data() == nav_bits) + { data_timestamp.second.update_last_received_timestamp(TOW); return true; } } - else if (nav_bits.size() == UTC_SIZE){ - if (data_timestamp.second.get_utc_data() == nav_bits){ + else if (nav_bits.size() == UTC_SIZE) + { + if (data_timestamp.second.get_utc_data() == nav_bits) + { data_timestamp.second.update_last_received_timestamp(TOW); return true; } @@ -208,15 +214,16 @@ bool OSNMA_nav_data_Manager::have_nav_data(const std::string& nav_bits, uint32_t bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const { auto prn_it = _satellite_nav_data.find(t.PRN_d); - if (prn_it == _satellite_nav_data.end()){ + if (prn_it == _satellite_nav_data.end()) + { return false; } // satellite was found, check if TOW exists in inner map std::map tow_map = prn_it->second; - for (auto & tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset + for (auto& tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset { // Check if current key (TOW) fulfills condition - if (t.TOW - 30 * t.cop <= tow_it.first && tow_it.first <= t.TOW - 30) + if (t.TOW - 30 * t.cop <= tow_it.first && tow_it.first <= t.TOW - 30) { if (t.ADKD == 0 || t.ADKD == 12) { @@ -240,10 +247,12 @@ bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const void OSNMA_nav_data_Manager::print_status() { - for (const auto& satellite : _satellite_nav_data){ + for (const auto& satellite : _satellite_nav_data) + { LOG(INFO) << "Galileo OSNMA: NavData status :: SVID=" << satellite.first; const auto& tow_data = satellite.second; - for (const auto& nav_data : tow_data) { + for (const auto& nav_data : tow_data) + { LOG(INFO) << "Galileo OSNMA: IOD_nav=0b" << std::uppercase << std::bitset<10>(nav_data.second.IOD_nav) << ", TOW_start=" diff --git a/src/core/system_parameters/osnma_nav_data_manager.h b/src/core/libs/osnma_nav_data_manager.h similarity index 61% rename from src/core/system_parameters/osnma_nav_data_manager.h rename to src/core/libs/osnma_nav_data_manager.h index 98b3d523f..6a64416d1 100644 --- a/src/core/system_parameters/osnma_nav_data_manager.h +++ b/src/core/libs/osnma_nav_data_manager.h @@ -1,27 +1,32 @@ /*! -* \file osnma_nav_data_manager.h -* \brief Class for Galileo OSNMA navigation data management -* \author Cesare Ghionoiu-Martinez, 2020-2023 cesare.martinez(at)proton.me -* -* ----------------------------------------------------------------------------- -* -* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -* This file is part of GNSS-SDR. -* -* Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) -* SPDX-License-Identifier: GPL-3.0-or-later -* -* ----------------------------------------------------------------------------- -*/ + * \file osnma_nav_data_manager.h + * \brief Class for Galileo OSNMA navigation data management + * \author Cesare Ghionoiu-Martinez, 2020-2023 cesare.martinez(at)proton.me + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2023 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ #ifndef GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H #define GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H #include "osnma_data.h" // NavData -#include // uint32_t +#include // uint32_t #include -#include #include +#include + +/** \addtogroup Core + * \{ */ +/** \addtogroup Core_Receiver_Library + * \{ */ /** * @class OSNMA_nav_data_Manager @@ -29,11 +34,12 @@ * @details It does good stuff * @remarks throw it whatever, it will improve it. Does good stuff */ -class OSNMA_nav_data_Manager{ +class OSNMA_nav_data_Manager +{ public: OSNMA_nav_data_Manager() = default; bool have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); - bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD); + bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD); bool have_nav_data(const Tag& t) const; void add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list std::string get_navigation_data(const Tag& t); @@ -41,6 +47,7 @@ public: void update_nav_data(const std::multimap& tags_verified, const uint8_t tag_size); std::vector get_verified_data(); void print_status(); + private: bool have_PRNd_nav_data(uint32_t PRNd); @@ -50,4 +57,7 @@ private: const uint16_t UTC_SIZE{141}; const uint16_t MAX_ALLOWED_SIZE{150}; // arbitrary maximum for the navigation data container }; + +/** \} */ +/** \} */ #endif // GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H diff --git a/src/core/monitor/gnss_synchro_monitor.cc b/src/core/monitor/gnss_synchro_monitor.cc index 502a5ed48..98526fe60 100644 --- a/src/core/monitor/gnss_synchro_monitor.cc +++ b/src/core/monitor/gnss_synchro_monitor.cc @@ -46,6 +46,7 @@ gnss_synchro_monitor::gnss_synchro_monitor(int n_channels, : gr::block("gnss_synchro_monitor", gr::io_signature::make(n_channels, n_channels, sizeof(Gnss_Synchro)), gr::io_signature::make(0, 0, 0)), + count(0), d_nchannels(n_channels), d_decimation_factor(decimation_factor) { @@ -73,7 +74,6 @@ int gnss_synchro_monitor::general_work(int noutput_items __attribute__((unused)) for (int channel_index = 0; channel_index < d_nchannels; channel_index++) { // Loop through each item in each input stream channel - int count = 0; for (int item_index = 0; item_index < ninput_items[channel_index]; item_index++) { // Use the count variable to limit how many items are sent per channel diff --git a/src/core/monitor/gnss_synchro_monitor.h b/src/core/monitor/gnss_synchro_monitor.h index b45b7cc5b..64749a001 100644 --- a/src/core/monitor/gnss_synchro_monitor.h +++ b/src/core/monitor/gnss_synchro_monitor.h @@ -71,9 +71,10 @@ private: const std::vector& udp_addresses, bool enable_protobuf); + std::unique_ptr udp_sink_ptr; + int count; int d_nchannels; int d_decimation_factor; - std::unique_ptr udp_sink_ptr; }; diff --git a/src/core/receiver/concurrent_map.h b/src/core/receiver/concurrent_map.h index 330ab02ef..d16a963d7 100644 --- a/src/core/receiver/concurrent_map.h +++ b/src/core/receiver/concurrent_map.h @@ -36,52 +36,48 @@ template */ class Concurrent_Map { - typedef typename std::map::iterator Data_iterator; // iterator is scope dependent public: void write(int key, Data const& data) { - std::unique_lock lock(the_mutex); - Data_iterator data_iter; - data_iter = the_map.find(key); + std::lock_guard lock(the_mutex); + auto data_iter = the_map.find(key); if (data_iter != the_map.end()) { data_iter->second = data; // update } else { - the_map.insert(std::pair(key, data)); // insert SILENTLY fails if the item already exists in the map! + the_map.insert(std::pair(key, data)); // insert does not overwrite if the item already exists in the map! } - lock.unlock(); } - std::map get_map_copy() + std::map get_map_copy() const& { - std::unique_lock lock(the_mutex); - std::map map_aux = the_map; - lock.unlock(); - return map_aux; + std::lock_guard lock(the_mutex); + return the_map; // This implicitly creates a copy } - size_t size() + std::map get_map_copy() && { - std::unique_lock lock(the_mutex); - size_t size_ = the_map.size(); - lock.unlock(); - return size_; + std::lock_guard lock(the_mutex); + return std::move(the_map); } - bool read(int key, Data& p_data) + size_t size() const { - std::unique_lock lock(the_mutex); - Data_iterator data_iter; - data_iter = the_map.find(key); + std::lock_guard lock(the_mutex); + return the_map.size(); + } + + bool read(int key, Data& p_data) const + { + std::lock_guard lock(the_mutex); + auto data_iter = the_map.find(key); if (data_iter != the_map.end()) { p_data = data_iter->second; - lock.unlock(); return true; } - lock.unlock(); return false; } diff --git a/src/core/receiver/concurrent_queue.h b/src/core/receiver/concurrent_queue.h index ac7be0f17..ed4e68b0a 100644 --- a/src/core/receiver/concurrent_queue.h +++ b/src/core/receiver/concurrent_queue.h @@ -19,9 +19,10 @@ #include #include +#include #include #include -#include +#include /** \addtogroup Core * \{ */ @@ -33,48 +34,53 @@ template /*! * \brief This class implements a thread-safe std::queue - * - * Thread-safe object queue which uses the library - * boost_thread to perform MUTEX based on the code available at - * https://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html */ class Concurrent_Queue { public: - void push(Data const& data) + void push(const Data& data) { - std::unique_lock lock(the_mutex); - the_queue.push(data); - lock.unlock(); + { + std::lock_guard lock(the_mutex); + the_queue.push(data); + } the_condition_variable.notify_one(); } - bool empty() const + void push(Data&& data) { - std::unique_lock lock(the_mutex); - return the_queue.empty(); + { + std::lock_guard lock(the_mutex); + the_queue.push(std::move(data)); + } + the_condition_variable.notify_one(); } - size_t size() const + bool empty() const noexcept { - std::unique_lock lock(the_mutex); + return size() == 0; + } + + size_t size() const noexcept + { + std::lock_guard lock(the_mutex); return the_queue.size(); } void clear() { - std::unique_lock lock(the_mutex); - the_queue = std::queue(); + std::lock_guard lock(the_mutex); + std::queue().swap(the_queue); } bool try_pop(Data& popped_value) { - std::unique_lock lock(the_mutex); + std::lock_guard lock(the_mutex); if (the_queue.empty()) { return false; } - popped_value = the_queue.front(); + popped_value = std::move(the_queue.front()); the_queue.pop(); return true; } @@ -82,26 +88,21 @@ public: void wait_and_pop(Data& popped_value) { std::unique_lock lock(the_mutex); - while (the_queue.empty()) - { - the_condition_variable.wait(lock); - } - popped_value = the_queue.front(); + the_condition_variable.wait(lock, [this] { return !the_queue.empty(); }); + popped_value = std::move(the_queue.front()); the_queue.pop(); } bool timed_wait_and_pop(Data& popped_value, int wait_ms) { std::unique_lock lock(the_mutex); - if (the_queue.empty()) + if (!the_condition_variable.wait_for(lock, + std::chrono::milliseconds(wait_ms), + [this] { return !the_queue.empty(); })) { - the_condition_variable.wait_for(lock, std::chrono::milliseconds(wait_ms)); - if (the_queue.empty()) - { - return false; - } + return false; } - popped_value = the_queue.front(); + popped_value = std::move(the_queue.front()); the_queue.pop(); return true; } diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index 1a48e0a7f..dda8452a8 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -113,6 +113,7 @@ #include "tracking_interface.h" #include "two_bit_cpx_file_signal_source.h" #include "two_bit_packed_file_signal_source.h" +#include // for exit #include // for exception #include // for cerr #include // for move diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index b0e3dc418..0d1606924 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -49,6 +49,7 @@ #include // for transform, sort, unique #include // for floor #include // for size_t +#include // for exit #include // for exception #include // for operator<< #include // for insert_iterator, inserter @@ -144,9 +145,9 @@ void GNSSFlowgraph::init() sources_count_ = configuration_->property("GNSS-SDR.num_sources", sources_count_deprecated); // Avoid segmentation fault caused by wrong configuration - if (sources_count_ == 2 && block_factory->GetSignalSource(configuration_.get(), queue_.get(), 0)->implementation() == "Multichannel_File_Signal_Source") + if (sources_count_ == 2 && configuration_->property("SignalSource.implementation", std::string("")) == "Multichannel_File_Signal_Source") { - std::cout << " * Please set GNSS-SDR.num_sources=1 in your configuraiion file\n"; + std::cout << " * Please set GNSS-SDR.num_sources=1 in your configuration file\n"; std::cout << " if you are using the Multichannel_File_Signal_Source implementation.\n"; sources_count_ = 1; } @@ -156,7 +157,13 @@ void GNSSFlowgraph::init() for (int i = 0; i < sources_count_; i++) { DLOG(INFO) << "Creating source " << i; - sig_source_.push_back(block_factory->GetSignalSource(configuration_.get(), queue_.get(), i)); + auto check_not_nullptr = block_factory->GetSignalSource(configuration_.get(), queue_.get(), i); + if (!check_not_nullptr) + { + std::cout << "GNSS-SDR program ended.\n"; + exit(1); + } + sig_source_.push_back(std::move(check_not_nullptr)); if (enable_fpga_offloading_ == false) { auto& src = sig_source_.back(); diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt index 5e42732c7..f2c5efce1 100644 --- a/src/core/system_parameters/CMakeLists.txt +++ b/src/core/system_parameters/CMakeLists.txt @@ -7,7 +7,6 @@ set(SYSTEM_PARAMETERS_SOURCES gnss_almanac.cc - gnss_crypto.cc gnss_ephemeris.cc gnss_satellite.cc gnss_signal.cc @@ -31,13 +30,10 @@ set(SYSTEM_PARAMETERS_SOURCES reed_solomon.cc osnma_data.cc osnma_dsm_reader.cc - osnma_helper.cc - osnma_nav_data_manager.cc ) set(SYSTEM_PARAMETERS_HEADERS gnss_almanac.h - gnss_crypto.h gnss_ephemeris.h gnss_satellite.h gnss_signal.h @@ -98,8 +94,6 @@ set(SYSTEM_PARAMETERS_HEADERS Galileo_OSNMA.h osnma_data.h osnma_dsm_reader.h - osnma_helper.h - osnma_nav_data_manager.h ) list(SORT SYSTEM_PARAMETERS_HEADERS) @@ -142,10 +136,6 @@ target_include_directories(core_system_parameters ${GNSSSDR_SOURCE_DIR}/src/algorithms/libs ) -# links to the appropriate library and defines -# USE_GNUTLS_FALLBACK, USE_OPENSSL_3, or USE_OPENSSL_111 accordingly. -link_to_crypto_dependencies(core_system_parameters) - if(ENABLE_CLANG_TIDY) if(CLANG_TIDY_EXE) set_target_properties(core_system_parameters diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 052a23921..7bf85862c 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -40,6 +40,7 @@ public: bool reserved{}; }; + class DSM_dsm_header { public: @@ -48,6 +49,7 @@ public: uint8_t dsm_block_id{}; }; + class MACK_header { public: @@ -57,6 +59,7 @@ public: uint8_t cop{}; }; + class MACK_tag_info { public: @@ -66,6 +69,7 @@ public: uint8_t cop{}; }; + class MACK_tag_and_info { public: @@ -75,6 +79,7 @@ public: uint32_t counter; // CTR }; + class DSM_PKR_message { public: @@ -89,6 +94,7 @@ public: uint8_t npktid{}; }; + class DSM_KROOT_message { public: @@ -112,6 +118,7 @@ public: uint8_t towh_k{}; }; + class MACK_message { public: @@ -124,33 +131,38 @@ public: uint32_t PRNa; }; + class OSNMA_NavData { public: - OSNMA_NavData(): nav_data_id(id_counter++){} - bool have_this_bits(std::string nav_data); - bool add_nav_data(const std::string& nav_data); - void update_last_received_timestamp(uint32_t TOW); - const uint32_t nav_data_id; - uint32_t verified_bits{0}; - uint32_t get_tow_sf0() const {return TOW_sf0;} - void set_tow_sf0(int value) {TOW_sf0 = value;} - uint32_t last_received_TOW{0}; - uint32_t IOD_nav{0}; + OSNMA_NavData() : nav_data_id(id_counter++) {} + std::string get_utc_data() const; std::string get_ephemeris_data() const; - void set_ephemeris_data(std::string value) {d_ephemeris_iono = value;} - void set_utc_data(std::string value) {d_utc = value;} + uint32_t get_tow_sf0() const { return TOW_sf0; } + + const uint32_t nav_data_id; + + bool have_this_bits(std::string nav_data); + bool add_nav_data(const std::string& nav_data); bool verified{false}; + + void update_last_received_timestamp(uint32_t TOW); + void set_tow_sf0(int value) { TOW_sf0 = value; } + void set_ephemeris_data(std::string value) { d_ephemeris_iono = value; } + void set_utc_data(std::string value) { d_utc = value; } + + uint32_t verified_bits{0}; + uint32_t last_received_TOW{0}; + uint32_t IOD_nav{0}; uint32_t PRNd{0}; uint32_t ADKD{}; + private: std::string d_ephemeris_iono{""}; std::string d_utc{""}; uint32_t TOW_sf0{0}; - - - uint32_t static id_counter; + static uint32_t id_counter; }; /*! @@ -224,6 +236,8 @@ public: uint32_t skipped; std::string nav_data; }; + /** \} */ /** \} */ + #endif // GNSS_SDR_OSNMA_DATA_H diff --git a/src/tests/benchmarks/CMakeLists.txt b/src/tests/benchmarks/CMakeLists.txt index 74607d1a1..2d79f4d06 100644 --- a/src/tests/benchmarks/CMakeLists.txt +++ b/src/tests/benchmarks/CMakeLists.txt @@ -111,7 +111,7 @@ endif() add_benchmark(benchmark_atan2 Gnuradio::runtime) add_benchmark(benchmark_copy) -add_benchmark(benchmark_crypto core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) +add_benchmark(benchmark_crypto core_libs Boost::headers ${EXTRA_BENCHMARK_DEPENDENCIES}) add_benchmark(benchmark_detector core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) add_benchmark(benchmark_preamble core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) add_benchmark(benchmark_reed_solomon core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) diff --git a/src/tests/benchmarks/benchmark_crypto.cc b/src/tests/benchmarks/benchmark_crypto.cc index 2adc95348..ec1945ab9 100644 --- a/src/tests/benchmarks/benchmark_crypto.cc +++ b/src/tests/benchmarks/benchmark_crypto.cc @@ -106,26 +106,12 @@ void bm_verify_ecdsa_p256(benchmark::State& state) 0x6B, 0xFF, 0x70, 0x06, 0xE0, 0xC4, 0x51, 0xEE, 0x3F, 0x87, 0x28, 0xC1, 0x77, 0xFB}; - // PEM format + // compressed ECDSA P-256 format std::vector 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}; + 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); @@ -146,50 +132,34 @@ void bm_verify_ecdsa_p521(benchmark::State& state) // Message to be verified std::vector message = { - 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64}; + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x0A}; // "Hello world\n" - // Public key in PEM format + // Public key in compressed X format std::vector 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, 0x49, 0x47, 0x62, 0x4D, 0x42, 0x41, 0x47, 0x42, - 0x79, 0x71, 0x47, 0x53, 0x4D, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x42, - 0x53, 0x75, 0x42, 0x42, 0x41, 0x41, 0x6A, 0x41, 0x34, 0x47, 0x47, 0x41, - 0x41, 0x51, 0x41, 0x6F, 0x35, 0x76, 0x77, 0x66, 0x6E, 0x47, 0x57, 0x47, - 0x33, 0x44, 0x63, 0x59, 0x75, 0x2B, 0x2F, 0x61, 0x58, 0x47, 0x32, 0x7A, - 0x74, 0x65, 0x41, 0x46, 0x50, 0x54, 0x33, 0x0A, 0x48, 0x36, 0x4C, 0x76, - 0x4F, 0x4C, 0x76, 0x49, 0x51, 0x6A, 0x61, 0x2B, 0x6A, 0x74, 0x57, 0x73, - 0x70, 0x4F, 0x38, 0x37, 0x6F, 0x50, 0x32, 0x4E, 0x6D, 0x72, 0x34, 0x6E, - 0x50, 0x68, 0x76, 0x62, 0x53, 0x58, 0x52, 0x4D, 0x37, 0x6A, 0x49, 0x69, - 0x46, 0x38, 0x47, 0x70, 0x6B, 0x75, 0x58, 0x6A, 0x75, 0x4E, 0x7A, 0x34, - 0x72, 0x61, 0x56, 0x4F, 0x65, 0x49, 0x4D, 0x42, 0x77, 0x45, 0x2B, 0x61, - 0x0A, 0x30, 0x4C, 0x76, 0x7A, 0x37, 0x69, 0x54, 0x4D, 0x5A, 0x46, 0x41, - 0x41, 0x51, 0x64, 0x2B, 0x70, 0x47, 0x72, 0x56, 0x54, 0x47, 0x77, 0x66, - 0x53, 0x48, 0x49, 0x72, 0x49, 0x49, 0x45, 0x78, 0x74, 0x5A, 0x35, 0x77, - 0x30, 0x38, 0x51, 0x4F, 0x43, 0x58, 0x2F, 0x75, 0x46, 0x65, 0x2B, 0x30, - 0x78, 0x52, 0x78, 0x4C, 0x64, 0x2F, 0x33, 0x36, 0x42, 0x4E, 0x74, 0x63, - 0x74, 0x69, 0x2F, 0x45, 0x4C, 0x0A, 0x4B, 0x31, 0x35, 0x67, 0x2B, 0x4B, - 0x32, 0x71, 0x67, 0x2F, 0x6C, 0x39, 0x46, 0x42, 0x47, 0x67, 0x4D, 0x2B, - 0x51, 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}; + 0x03, 0x00, 0x28, 0x35, 0xBB, 0xE9, 0x24, 0x59, 0x4E, 0xF0, + 0xE3, 0xA2, 0xDB, 0xC0, 0x49, 0x30, 0x60, 0x7C, 0x61, 0x90, + 0xE4, 0x03, 0xE0, 0xC7, 0xB8, 0xC2, 0x62, 0x37, 0xF7, 0x58, + 0x56, 0xBE, 0x63, 0x5C, 0x97, 0xF7, 0x53, 0x64, 0x7E, 0xE1, + 0x0C, 0x07, 0xD3, 0x97, 0x8D, 0x58, 0x46, 0xFD, 0x6E, 0x06, + 0x44, 0x01, 0xA7, 0xAA, 0xC4, 0x95, 0x13, 0x5D, 0xC9, 0x77, + 0x26, 0xE9, 0xF8, 0x72, 0x0C, 0xD3, 0x88}; // ECDSA P-521 signature, raw format std::vector signature = { - 0x01, 0x7B, 0x59, 0xAC, 0x3A, 0x03, 0x5C, 0xB4, 0x07, 0xCD, - 0xC1, 0xEB, 0xBE, 0xE5, 0xA6, 0xCB, 0xDA, 0x0A, 0xFF, 0x4D, - 0x38, 0x61, 0x16, 0x0F, 0xB3, 0x77, 0xE5, 0x8A, 0xDC, 0xF3, - 0xFD, 0x79, 0x38, 0x1E, 0xE8, 0x08, 0x3D, 0x5D, 0xBC, 0xC2, - 0x80, 0x6E, 0xE9, 0x2B, 0xC3, 0xEF, 0x07, 0x3D, 0x0C, 0x82, - 0x4C, 0x9B, 0x7A, 0x5C, 0x2E, 0xD5, 0x46, 0xBD, 0x22, 0x21, - 0x13, 0x8A, 0xB2, 0xCA, 0x96, 0x3D, 0x01, 0xBA, 0x2A, 0xC4, - 0x3F, 0xDB, 0x66, 0x3C, 0x40, 0x26, 0xD9, 0xBC, 0x26, 0xD5, - 0x57, 0xD4, 0xBD, 0x15, 0x16, 0x88, 0x21, 0x3B, 0xAA, 0x07, - 0x89, 0xEF, 0x29, 0x8F, 0x2F, 0x85, 0x76, 0x58, 0x9D, 0xCA, - 0x00, 0xCC, 0xC8, 0x30, 0x88, 0x31, 0x99, 0xC1, 0x94, 0xB9, - 0xAF, 0x91, 0xDC, 0xC4, 0x6F, 0x19, 0x2B, 0x12, 0xA2, 0x82, - 0xA5, 0x66, 0x5E, 0x4B, 0xBB, 0xDF, 0x65, 0x81, 0x52, 0x14, - 0x01, 0xD7}; + 0x01, 0x5C, 0x23, 0xC0, 0xBE, 0xAD, 0x1E, 0x44, 0x60, 0xD4, + 0xE0, 0x81, 0x38, 0xF2, 0xBA, 0xF5, 0xB5, 0x37, 0x5A, 0x34, + 0xB5, 0xCA, 0x6B, 0xC8, 0x0F, 0xCD, 0x75, 0x1D, 0x5E, 0xC0, + 0x8A, 0xD3, 0xD7, 0x79, 0xA7, 0xC1, 0xB8, 0xA2, 0xC6, 0xEA, + 0x5A, 0x7D, 0x60, 0x66, 0x50, 0x97, 0x37, 0x6C, 0xF9, 0x0A, + 0xF6, 0x3D, 0x77, 0x9A, 0xE2, 0x19, 0xF7, 0xF9, 0xDD, 0x52, + 0xC4, 0x0F, 0x98, 0xAA, 0xA2, 0xA4, 0x01, 0xC9, 0x41, 0x0B, + 0xD0, 0x25, 0xDD, 0xC9, 0x7C, 0x3F, 0x70, 0x32, 0x23, 0xCF, + 0xFE, 0x37, 0x67, 0x3A, 0xBC, 0x0B, 0x76, 0x16, 0x82, 0x83, + 0x27, 0x3D, 0x1D, 0x19, 0x15, 0x78, 0x08, 0x2B, 0xD4, 0xA7, + 0xC2, 0x0F, 0x11, 0xF4, 0xDD, 0xE5, 0x5A, 0x5D, 0x04, 0x8D, + 0x6D, 0x5E, 0xC4, 0x1F, 0x54, 0x44, 0xA9, 0x13, 0x34, 0x71, + 0x0F, 0xF7, 0x57, 0x9A, 0x9F, 0x2E, 0xF4, 0x97, 0x7D, 0xAE, + 0x28, 0xEF}; d_crypto->set_public_key(publicKey); From 5a634f7332f915a0a1d7b3ee2d455a02872573b4 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sun, 11 Aug 2024 12:44:18 +0200 Subject: [PATCH 211/219] More fixes (#25) * Clang Tidy fixes * Fix some potential defects and be more consistent in class name. Improve const correctness * Fix formatting --------- Co-authored-by: cesaaargm --- src/core/libs/osnma_msg_receiver.cc | 4 +- src/core/libs/osnma_msg_receiver.h | 10 +- src/core/libs/osnma_nav_data_manager.cc | 133 ++++++++---------- src/core/libs/osnma_nav_data_manager.h | 32 ++--- src/core/system_parameters/osnma_data.cc | 8 +- src/core/system_parameters/osnma_data.h | 19 ++- .../osnma/osnma_msg_receiver_test.cc | 12 +- .../osnma/osnma_test_vectors.cc | 23 +-- 8 files changed, 118 insertions(+), 123 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 46aca3fd0..72e6d7ef0 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -77,7 +77,7 @@ osnma_msg_receiver::osnma_msg_receiver(const std::string& crtFilePath, d_dsm_reader = std::make_unique(); d_crypto = std::make_unique(crtFilePath, merkleFilePath); d_helper = std::make_unique(); - d_nav_data_manager = std::make_unique(); + d_nav_data_manager = std::make_unique(); if (d_crypto->have_public_key()) { // Hot start is enabled @@ -1192,7 +1192,7 @@ void osnma_msg_receiver::process_mack_message() } d_nav_data_manager->update_nav_data(d_tags_awaiting_verify, tag_size); auto data_to_send = d_nav_data_manager->get_verified_data(); - d_nav_data_manager->print_status(); + d_nav_data_manager->log_status(); send_data_to_pvt(data_to_send); remove_verified_tags(); diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 7039889ef..4f3b0107b 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -26,7 +26,7 @@ #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 "osnma_nav_data_manager.h" // for OSNMA_NavDataManager #include // for gr::block #include // for pmt::pmt_t #include // for std::array @@ -112,10 +112,10 @@ 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 + 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 OSNMA_data d_osnma_data{}; diff --git a/src/core/libs/osnma_nav_data_manager.cc b/src/core/libs/osnma_nav_data_manager.cc index 6d8a16113..5a9331dae 100644 --- a/src/core/libs/osnma_nav_data_manager.cc +++ b/src/core/libs/osnma_nav_data_manager.cc @@ -28,13 +28,13 @@ * @param PRNd The satellite ID. * @param TOW The TOW of the received data. */ -void OSNMA_nav_data_Manager::add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) +void OSNMA_NavDataManager::add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) { if (not have_nav_data(nav_bits, PRNd, TOW)) { - _satellite_nav_data[PRNd][TOW].add_nav_data(nav_bits); - _satellite_nav_data[PRNd][TOW].PRNd = PRNd; - _satellite_nav_data[PRNd][TOW].set_tow_sf0(TOW); + d_satellite_nav_data[PRNd][TOW].add_nav_data(nav_bits); + d_satellite_nav_data[PRNd][TOW].PRNd = PRNd; + d_satellite_nav_data[PRNd][TOW].set_tow_sf0(TOW); } } @@ -42,33 +42,39 @@ void OSNMA_nav_data_Manager::add_navigation_data(const std::string& nav_bits, ui /** * @brief loops over the verified tags and updates the navigation data tag length */ -void OSNMA_nav_data_Manager::update_nav_data(const std::multimap& tags_verified, const uint8_t tag_size) +void OSNMA_NavDataManager::update_nav_data(const std::multimap& tags_verified, uint8_t tag_size) { + if (d_satellite_nav_data.empty()) + { + return; + } // loop through all tags for (const auto& tag : tags_verified) { // if tag status is verified, look for corresponding OSNMA_NavData and add increase verified tag bits. if (tag.second.status == Tag::e_verification_status::SUCCESS) { - if (have_PRNd_nav_data(tag.second.PRN_d)) + auto sat_it = d_satellite_nav_data.find(tag.second.PRN_d); + if (sat_it == d_satellite_nav_data.end()) { - std::map tow_map = _satellite_nav_data.find(tag.second.PRN_d)->second; - for (auto& tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset + continue; + } + auto& tow_map = sat_it->second; + 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) { - std::string nav_data; - if (tag.second.ADKD == 0 || tag.second.ADKD == 12) - { - nav_data = tow_it.second.get_ephemeris_data(); - } - else if (tag.second.ADKD == 4) - { - nav_data = tow_it.second.get_utc_data(); - } - // find associated OSNMA_NavData - if (tag.second.nav_data == nav_data) - { - _satellite_nav_data[tag.second.PRN_d][tow_it.first].verified_bits += tag_size; - } + nav_data = tow_it.second.get_ephemeris_data(); + } + else if (tag.second.ADKD == 4) + { + nav_data = tow_it.second.get_utc_data(); + } + // find associated OSNMA_NavData + if (tag.second.nav_data == nav_data) + { + d_satellite_nav_data[tag.second.PRN_d][tow_it.first].verified_bits += tag_size; } } } @@ -76,24 +82,17 @@ void OSNMA_nav_data_Manager::update_nav_data(const std::multimap& } -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_nav_data_Manager::get_verified_data() +std::vector OSNMA_NavDataManager::get_verified_data() { std::vector result; - for (const auto& prna : _satellite_nav_data) + for (const auto& prna : d_satellite_nav_data) { for (const auto& tow_navdata : prna.second) { if (tow_navdata.second.verified_bits >= L_t_min) { result.push_back(tow_navdata.second); - _satellite_nav_data[prna.first][tow_navdata.first].verified = true; + d_satellite_nav_data[prna.first][tow_navdata.first].verified = true; } } } @@ -101,45 +100,37 @@ std::vector OSNMA_nav_data_Manager::get_verified_data() } -bool OSNMA_nav_data_Manager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD) +bool OSNMA_NavDataManager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD) const { - if (ADKD == 0 || ADKD == 12) + const auto sat_it = d_satellite_nav_data.find(PRNd); + if (sat_it == d_satellite_nav_data.cend()) { - const auto it = _satellite_nav_data.find(PRNd); - if (it != _satellite_nav_data.cend()) - { - const auto it2 = it->second.find(TOW); - if (it2 != it->second.cend() && !it->second[TOW].get_ephemeris_data().empty()) - { - return true; - } - } + return false; } - else if (ADKD == 4) + + const auto tow_it = sat_it->second.find(TOW); + if (tow_it == sat_it->second.cend()) { - const auto it = _satellite_nav_data.find(PRNd); - if (it != _satellite_nav_data.cend()) - { - const auto it2 = it->second.find(TOW); - if (it2 != it->second.cend() && !it->second[TOW].get_utc_data().empty()) - { - return true; - } - } + return false; + } + + switch (ADKD) + { + case 0: + case 12: + return !tow_it->second.get_ephemeris_data().empty(); + case 4: + return !tow_it->second.get_utc_data().empty(); + default: + return false; } - return false; } -/** - * @brief returns OSNMA_NavData object. - * @remarks assumes it exists (called have_nav_data before), otherwise undefined behavior - * TODO - maybe add const promise and use find() instead? this is kinda sensitive topic. - */ -std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) +std::string OSNMA_NavDataManager::get_navigation_data(const Tag& tag) const { - auto prn_it = _satellite_nav_data.find(tag.PRN_d); - if (prn_it == _satellite_nav_data.end()) + auto prn_it = d_satellite_nav_data.find(tag.PRN_d); + if (prn_it == d_satellite_nav_data.end()) { return ""; } @@ -178,11 +169,11 @@ std::string OSNMA_nav_data_Manager::get_navigation_data(const Tag& tag) * @param PRNd * @return */ -bool OSNMA_nav_data_Manager::have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) +bool OSNMA_NavDataManager::have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW) { - if (_satellite_nav_data.find(PRNd) != _satellite_nav_data.end()) + if (d_satellite_nav_data.find(PRNd) != d_satellite_nav_data.end()) { - for (auto& data_timestamp : _satellite_nav_data[PRNd]) + for (auto& data_timestamp : d_satellite_nav_data[PRNd]) { if (nav_bits.size() == EPH_SIZE) { @@ -211,10 +202,10 @@ bool OSNMA_nav_data_Manager::have_nav_data(const std::string& nav_bits, uint32_t * @param t Tag object * @return True if the needed navigation data for the tag is available (oldest possible OSNMA_NavData available) */ -bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const +bool OSNMA_NavDataManager::have_nav_data(const Tag& t) const { - auto prn_it = _satellite_nav_data.find(t.PRN_d); - if (prn_it == _satellite_nav_data.end()) + auto prn_it = d_satellite_nav_data.find(t.PRN_d); + if (prn_it == d_satellite_nav_data.end()) { return false; } @@ -245,9 +236,9 @@ bool OSNMA_nav_data_Manager::have_nav_data(const Tag& t) const } -void OSNMA_nav_data_Manager::print_status() +void OSNMA_NavDataManager::log_status() const { - for (const auto& satellite : _satellite_nav_data) + for (const auto& satellite : d_satellite_nav_data) { LOG(INFO) << "Galileo OSNMA: NavData status :: SVID=" << satellite.first; const auto& tow_data = satellite.second; @@ -258,7 +249,7 @@ void OSNMA_nav_data_Manager::print_status() << ", TOW_start=" << nav_data.second.get_tow_sf0() << ", TOW_last=" - << nav_data.second.last_received_TOW + << nav_data.second.get_last_received_TOW() << ", l_t=" << nav_data.second.verified_bits << ", PRNd=" diff --git a/src/core/libs/osnma_nav_data_manager.h b/src/core/libs/osnma_nav_data_manager.h index 6a64416d1..6beaa907d 100644 --- a/src/core/libs/osnma_nav_data_manager.h +++ b/src/core/libs/osnma_nav_data_manager.h @@ -17,8 +17,8 @@ #ifndef GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H #define GNSS_SDR_OSNMA_NAV_DATA_MANAGER_H -#include "osnma_data.h" // NavData -#include // uint32_t +#include "osnma_data.h" // for OSNMA_NavData, Tag +#include // for uint32_t #include #include #include @@ -29,33 +29,29 @@ * \{ */ /** - * @class OSNMA_nav_data_Manager + * @class OSNMA_NavDataManager * @brief Class for managing OSNMA navigation data - * @details It does good stuff - * @remarks throw it whatever, it will improve it. Does good stuff */ -class OSNMA_nav_data_Manager +class OSNMA_NavDataManager { public: - OSNMA_nav_data_Manager() = default; - bool have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); - bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD); - bool have_nav_data(const Tag& t) const; - void add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); // gets the bits and adds them to the list - std::string get_navigation_data(const Tag& t); + OSNMA_NavDataManager() = default; - void update_nav_data(const std::multimap& tags_verified, const uint8_t tag_size); + void log_status() const; + bool have_nav_data(const Tag& t) const; + bool have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t ADKD) const; + std::string get_navigation_data(const Tag& t) const; + + void add_navigation_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); + void update_nav_data(const std::multimap& tags_verified, uint8_t tag_size); + bool have_nav_data(const std::string& nav_bits, uint32_t PRNd, uint32_t TOW); std::vector get_verified_data(); - void print_status(); private: - bool have_PRNd_nav_data(uint32_t PRNd); - - std::map> _satellite_nav_data{}; // NavData sorted by [PRNd][TOW_start] + std::map> d_satellite_nav_data{}; // NavData sorted by [PRNd][TOW_start] const uint32_t L_t_min{40}; const uint16_t EPH_SIZE{549}; const uint16_t UTC_SIZE{141}; - const uint16_t MAX_ALLOWED_SIZE{150}; // arbitrary maximum for the navigation data container }; /** \} */ diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index 6d969a7f0..b5355113f 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -35,19 +35,25 @@ bool OSNMA_NavData::add_nav_data(const std::string& nav_data) } return false; } + + std::string OSNMA_NavData::get_utc_data() const { return d_utc; } + + std::string OSNMA_NavData::get_ephemeris_data() const { return d_ephemeris_iono; } + + /** * Updates the last TOW the NavData bits were received. * @param TOW */ void OSNMA_NavData::update_last_received_timestamp(uint32_t TOW) { - last_received_TOW = TOW; + d_last_received_TOW = TOW; } diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 7bf85862c..e3c78cdc4 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -136,35 +136,34 @@ class OSNMA_NavData { public: OSNMA_NavData() : nav_data_id(id_counter++) {} + const uint32_t nav_data_id; std::string get_utc_data() const; std::string get_ephemeris_data() const; - uint32_t get_tow_sf0() const { return TOW_sf0; } + uint32_t get_last_received_TOW() const { return d_last_received_TOW; } + uint32_t get_tow_sf0() const { return d_TOW_sf0; } - const uint32_t nav_data_id; - - bool have_this_bits(std::string nav_data); bool add_nav_data(const std::string& nav_data); - bool verified{false}; - - void update_last_received_timestamp(uint32_t TOW); - void set_tow_sf0(int value) { TOW_sf0 = value; } + void set_tow_sf0(int value) { d_TOW_sf0 = value; } void set_ephemeris_data(std::string value) { d_ephemeris_iono = value; } void set_utc_data(std::string value) { d_utc = value; } + void update_last_received_timestamp(uint32_t TOW); uint32_t verified_bits{0}; - uint32_t last_received_TOW{0}; uint32_t IOD_nav{0}; uint32_t PRNd{0}; uint32_t ADKD{}; + bool verified{false}; private: std::string d_ephemeris_iono{""}; std::string d_utc{""}; - uint32_t TOW_sf0{0}; + uint32_t d_TOW_sf0{0}; + uint32_t d_last_received_TOW{0}; static uint32_t id_counter; }; + /*! * \brief This class handles ONSMA data * See https://www.gsc-europa.eu/sites/default/files/sites/all/files/Galileo_OSNMA_User_ICD_for_Test_Phase_v1.0.pdf diff --git a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc index 5d5e3819f..7bbdd4e16 100644 --- a/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc +++ b/src/tests/unit-tests/signal-processing-blocks/osnma/osnma_msg_receiver_test.cc @@ -16,15 +16,15 @@ * ----------------------------------------------------------------------------- */ +#include "Galileo_OSNMA.h" +#include "gnss_crypto.h" +#include "osnma_helper.h" +#include "osnma_msg_receiver.h" #include #include #include #include #include -#include "Galileo_OSNMA.h" -#include "gnss_crypto.h" -#include "osnma_helper.h" -#include "osnma_msg_receiver.h" #if USE_GLOG_AND_GFLAGS #include // for LOG @@ -43,7 +43,7 @@ protected: uint32_t TOW{}; uint32_t WN{}; std::tm GST_START_EPOCH = {0, 0, 0, 22, 8 - 1, 1999 - 1900, 0, 0, 0, 0, 0}; // months start with 0 and years since 1900 in std::tm - const uint32_t LEAP_SECONDS = 0; // tried with 13 + 5, which is the official count, but won't parse correctly + const uint32_t LEAP_SECONDS = 0; // tried with 13 + 5, which is the official count, but won't parse correctly void set_time(std::tm& input); void SetUp() override @@ -253,7 +253,7 @@ TEST_F(OsnmaMsgReceiverTest, TeslaKeyVerification) osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); - osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) osnma->d_GST_Sf = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G. osnma->d_tesla_keys.insert((std::pair>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. 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 73e5eb25c..5c097e10b 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 @@ -161,7 +161,7 @@ TEST_F(OsnmaTestVectors, PublicKeyRevocation) std::tm input_time_step1 = {0, 45, 7, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; std::tm input_time_step2 = {0, 30, 9, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; std::tm input_time_step3 = {0, 30, 10, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; - std::vector input_times = { input_time_step1, input_time_step2, input_time_step3 }; + std::vector input_times = {input_time_step1, input_time_step2, input_time_step3}; std::vector testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/pkrev_step1/07_OCT_2023_GST_07_45_01.csv"); std::vector testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/pkrev_step2/07_OCT_2023_GST_09_30_01.csv"); @@ -170,7 +170,7 @@ TEST_F(OsnmaTestVectors, PublicKeyRevocation) { ASSERT_TRUE(false); } - std::vector> testVectors = { testVectors_step1, testVectors_step2, testVectors_step3}; + std::vector> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3}; bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); ASSERT_TRUE(result); @@ -182,7 +182,8 @@ TEST_F(OsnmaTestVectors, PublicKeyRevocation) ASSERT_EQ(osnma->d_count_failed_macseq, 0); } -TEST_F(OsnmaTestVectors, AlertMessage){ +TEST_F(OsnmaTestVectors, AlertMessage) +{ // Arrange std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_3/PublicKey/OSNMA_PublicKey_20231007201500_PKID_1.crt"; std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_3/MerkleTree/OSNMA_MerkleTree_20231007201500_PKID_1.xml"; @@ -190,7 +191,7 @@ TEST_F(OsnmaTestVectors, AlertMessage){ std::tm input_time_step1 = {0, 45, 18, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; std::tm input_time_step2 = {0, 45, 19, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; - std::vector input_times = { input_time_step1, input_time_step2 }; + std::vector input_times = {input_time_step1, input_time_step2}; std::vector testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/oam_step1/07_OCT_2023_GST_18_45_01.csv"); std::vector testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/oam_step2/07_OCT_2023_GST_19_45_01.csv"); @@ -198,7 +199,7 @@ TEST_F(OsnmaTestVectors, AlertMessage){ { ASSERT_TRUE(false); } - std::vector> testVectors = { testVectors_step1, testVectors_step2}; + std::vector> testVectors = {testVectors_step1, testVectors_step2}; // Act bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); @@ -219,17 +220,18 @@ TEST_F(OsnmaTestVectors, AlertMessage){ // Auxiliary functions for the OsnmaTestVectorsSimulation test fixture. // Essentially, they perform same work as the telemetry decoder block, but adapted to the osnma-test-vector files. -bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_object, std::vector> testVectors, std::vector startTimesFiles){ +bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_object, std::vector> testVectors, std::vector startTimesFiles) +{ bool end_of_hex_stream; int offset_byte{0}; - int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size + int byte_index{0}; // index containing the last byte position of the hex stream that was retrieved. Takes advantage that all TVs have same size const int DUMMY_PAGE{63}; bool flag_dummy_page{false}; // Act // loop over all bytes of data. Note: all TestVectors have same amount of data. // if needed, add global flags so that particular logic may be done at certain points in between files - for (size_t test_step = 0; test_step < testVectors.size() ; test_step++) + for (size_t test_step = 0; test_step < testVectors.size(); test_step++) { // set variables for each file end_of_hex_stream = false; @@ -241,7 +243,8 @@ bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_ob << ", TOW=" << TOW << ", WN=" << WN << std::endl; - if (test_step == 1 && d_flag_NPK == true ){ + 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->read_merkle_xml( std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007081500_PKID_8.xml"); @@ -436,7 +439,7 @@ bool OsnmaTestVectors::feedOsnmaWithTestVectors(osnma_msg_receiver_sptr osnma_ob if (end_of_hex_stream) continue; } -return true; + return true; } std::vector OsnmaTestVectors::readTestVectorsFromFile(const std::string& filename) From 794bd614195485175df32ba7af1187c2edad1c6b Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Sun, 11 Aug 2024 13:44:20 +0200 Subject: [PATCH 212/219] [TAS-249][Bug][Tag] new NavDataManager causes less tags to be verified [TAS-234][Feature] Dummy tags verification * Fixed the navData retrieval which caused many tags to be skipped * Dummy tags verification added. * Replaced direct field access with getters/setters for OSNMA navigation data. --- src/core/libs/gnss_crypto.h | 2 +- src/core/libs/osnma_msg_receiver.cc | 28 ++-- src/core/libs/osnma_nav_data_manager.cc | 129 +++++++++++++----- .../system_parameters/galileo_inav_message.cc | 7 +- .../system_parameters/galileo_inav_message.h | 13 +- src/core/system_parameters/osnma_data.cc | 14 -- src/core/system_parameters/osnma_data.h | 24 ++-- .../osnma/osnma_test_vectors.cc | 24 ++++ 8 files changed, 158 insertions(+), 83 deletions(-) diff --git a/src/core/libs/gnss_crypto.h b/src/core/libs/gnss_crypto.h index b308f820b..9fb16f96e 100644 --- a/src/core/libs/gnss_crypto.h +++ b/src/core/libs/gnss_crypto.h @@ -78,7 +78,7 @@ private: void readPublicKeyFromPEM(const std::string& pemFilePath); bool readPublicKeyFromCRT(const std::string& crtFilePath); bool convert_raw_to_der_ecdsa(const std::vector& raw_signature, std::vector& der_signature) const; - std::vector convert_from_hex_str(const std::string& input) const; + std::vector convert_from_hex_str(const std::string& input) const; // TODO - deprecate if OSNMA helper is to do this operation #if USE_GNUTLS_FALLBACK void decompress_public_key_secp256r1(const std::vector& compressed_key, std::vector& x, std::vector& y) const; void decompress_public_key_secp521r1(const std::vector& compressed_key, std::vector& x, std::vector& y) const; diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 72e6d7ef0..ace7dc40e 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -183,8 +183,8 @@ void osnma_msg_receiver::msg_handler_osnma(const pmt::pmt_t& msg) if (delta_T <= d_T_L) { d_tags_to_verify = {0, 4, 12}; - LOG(INFO) << "Galileo OSNMA: time constraint OK ( delta_T=" << delta_T << " s)"; - std::cout << "Galileo OSNMA: time constraint OK ( delta_T=" << delta_T << " s)" << std::endl; + LOG(INFO) << "Galileo OSNMA: time constraint OK (delta_T=" << delta_T << " s)"; + std::cout << "Galileo OSNMA: time constraint OK (delta_T=" << delta_T << " s)" << std::endl; } else if (delta_T > d_T_L && delta_T <= 10 * d_T_L) { @@ -1067,7 +1067,18 @@ void osnma_msg_receiver::process_mack_message() // add tag0 first Tag tag0(*mack); d_tags_awaiting_verify.insert(std::pair(mack->TOW, tag0)); - // bool ret = verify_macseq(*mack); + LOG(INFO) << "Galileo OSNMA: Add Tag0 Id= " + << tag0.tag_id + << ", value=0x" << std::setfill('0') << std::setw(10) << std::hex << std::uppercase + << tag0.received_tag << std::dec + << ", TOW=" + << tag0.TOW + << ", ADKD=" + << static_cast(tag0.ADKD) + << ", PRNa=" + << static_cast(tag0.PRNa) + << ", PRNd=" + << static_cast(tag0.PRN_d); std::vector macseq_verified_tags = verify_macseq_new(*mack); for (auto& tag_and_info : macseq_verified_tags) { @@ -1521,11 +1532,11 @@ void osnma_msg_receiver::remove_verified_tags() << static_cast(it->second.PRNa) << ", PRNd=" << static_cast(it->second.PRN_d) - << ", status= " + << ", status=" << d_helper->verification_status_str(it->second.status); it = d_tags_awaiting_verify.erase(it); } - else if (it->second.skipped >= 20) + else if ((it->second.ADKD != 12 && !d_nav_data_manager->have_nav_data(it->second)) || (it->second.ADKD == 12 && (it->second.TOW + 30 * 11 < d_helper->get_TOW(d_last_verified_key_GST)))) { LOG(INFO) << "Galileo OSNMA: Tag verification :: DELETE tag Id=" << it->second.tag_id @@ -1539,8 +1550,9 @@ void osnma_msg_receiver::remove_verified_tags() << static_cast(it->second.PRNa) << ", PRNd=" << static_cast(it->second.PRN_d) - << ", status= " - << d_helper->verification_status_str(it->second.status); + << ", status=" + << d_helper->verification_status_str(it->second.status) + << ". SV out of sight / NavData unavailable."; it = d_tags_awaiting_verify.erase(it); } else @@ -1563,7 +1575,7 @@ void osnma_msg_receiver::remove_verified_tags() << static_cast(it.second.PRNa) << ", PRNd=" << static_cast(it.second.PRN_d) - << ", status= " + << ", status=" << d_helper->verification_status_str(it.second.status); } } diff --git a/src/core/libs/osnma_nav_data_manager.cc b/src/core/libs/osnma_nav_data_manager.cc index 5a9331dae..03d5a4442 100644 --- a/src/core/libs/osnma_nav_data_manager.cc +++ b/src/core/libs/osnma_nav_data_manager.cc @@ -33,8 +33,9 @@ void OSNMA_NavDataManager::add_navigation_data(const std::string& nav_bits, uint if (not have_nav_data(nav_bits, PRNd, TOW)) { d_satellite_nav_data[PRNd][TOW].add_nav_data(nav_bits); - d_satellite_nav_data[PRNd][TOW].PRNd = PRNd; + d_satellite_nav_data[PRNd][TOW].set_prn_d(PRNd); d_satellite_nav_data[PRNd][TOW].set_tow_sf0(TOW); + d_satellite_nav_data[PRNd][TOW].set_last_received_TOW(TOW); } } @@ -74,7 +75,7 @@ void OSNMA_NavDataManager::update_nav_data(const std::multimap& t // find associated OSNMA_NavData if (tag.second.nav_data == nav_data) { - d_satellite_nav_data[tag.second.PRN_d][tow_it.first].verified_bits += tag_size; + d_satellite_nav_data[tag.second.PRN_d][tow_it.first].set_update_verified_bits(tag_size); } } } @@ -89,10 +90,10 @@ std::vector OSNMA_NavDataManager::get_verified_data() { for (const auto& tow_navdata : prna.second) { - if (tow_navdata.second.verified_bits >= L_t_min) + if (tow_navdata.second.get_verified_bits() >= L_t_min) { result.push_back(tow_navdata.second); - d_satellite_nav_data[prna.first][tow_navdata.first].verified = true; + d_satellite_nav_data[prna.first][tow_navdata.first].set_verified_status(true); } } } @@ -129,31 +130,62 @@ bool OSNMA_NavDataManager::have_nav_data(uint32_t PRNd, uint32_t TOW, uint8_t AD std::string OSNMA_NavDataManager::get_navigation_data(const Tag& tag) const { + // Check if Dummy Tag, navData is all zeros + if (tag.cop == 0) + { + if (tag.ADKD == 0 || tag.ADKD == 12) + { + return std::string(549, '0'); + } + else if (tag.ADKD == 4) + { + return std::string(141, '0'); + } + } auto prn_it = d_satellite_nav_data.find(tag.PRN_d); if (prn_it == d_satellite_nav_data.end()) { return ""; } - // satellite was found, check if TOW exists in inner map - std::map tow_map = prn_it->second; - for (auto& tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset + auto nav_data = prn_it->second.find(tag.TOW - 30); + if (nav_data != prn_it->second.end()) { - // Check if current key (TOW) fulfills condition - if ((tag.TOW - 30 * tag.cop) <= tow_it.first && tow_it.first <= tag.TOW - 30) + if (tag.ADKD == 0 || tag.ADKD == 12) { - if (tag.ADKD == 0 || tag.ADKD == 12) + if (!nav_data->second.get_ephemeris_data().empty()) { - if (!tow_it.second.get_ephemeris_data().empty()) - { - return tow_it.second.get_ephemeris_data(); - } + return nav_data->second.get_ephemeris_data(); } - else if (tag.ADKD == 4) + } + else if (tag.ADKD == 4) + { + if (!nav_data->second.get_utc_data().empty()) { - if (!tow_it.second.get_utc_data().empty()) + return nav_data->second.get_utc_data(); + } + } + } + else + { + for (auto rev_it = prn_it->second.rbegin(); rev_it != prn_it->second.rend(); ++rev_it) // note: starts with largest (i.e. newest) navigation dataset + { + // Check if current key (TOW) fulfills condition + if ((tag.TOW - 30 * tag.cop <= rev_it->first || tag.TOW - 30 * tag.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < tag.TOW) + { + if (tag.ADKD == 0 || tag.ADKD == 12) { - return tow_it.second.get_utc_data(); + if (!rev_it->second.get_ephemeris_data().empty()) + { + return rev_it->second.get_ephemeris_data(); + } + } + else if (tag.ADKD == 4) + { + if (!rev_it->second.get_utc_data().empty()) + { + return rev_it->second.get_utc_data(); + } } } } @@ -179,7 +211,7 @@ bool OSNMA_NavDataManager::have_nav_data(const std::string& nav_bits, uint32_t P { if (data_timestamp.second.get_ephemeris_data() == nav_bits) { - data_timestamp.second.update_last_received_timestamp(TOW); + data_timestamp.second.set_last_received_TOW(TOW); return true; } } @@ -187,7 +219,7 @@ bool OSNMA_NavDataManager::have_nav_data(const std::string& nav_bits, uint32_t P { if (data_timestamp.second.get_utc_data() == nav_bits) { - data_timestamp.second.update_last_received_timestamp(TOW); + data_timestamp.second.set_last_received_TOW(TOW); return true; } } @@ -204,30 +236,57 @@ bool OSNMA_NavDataManager::have_nav_data(const std::string& nav_bits, uint32_t P */ bool OSNMA_NavDataManager::have_nav_data(const Tag& t) const { + if (t.cop == 0) + { + return true; + } auto prn_it = d_satellite_nav_data.find(t.PRN_d); if (prn_it == d_satellite_nav_data.end()) { return false; } // satellite was found, check if TOW exists in inner map - std::map tow_map = prn_it->second; - for (auto& tow_it : tow_map) // note: starts with smallest (i.e. oldest) navigation dataset + // try find target TOW directly first + auto nav_data = prn_it->second.find(t.TOW - 30); + if (nav_data != prn_it->second.end()) { - // Check if current key (TOW) fulfills condition - if (t.TOW - 30 * t.cop <= tow_it.first && tow_it.first <= t.TOW - 30) + if (t.ADKD == 0 || t.ADKD == 12) { - if (t.ADKD == 0 || t.ADKD == 12) + if (!nav_data->second.get_ephemeris_data().empty()) { - if (!tow_it.second.get_ephemeris_data().empty()) - { - return true; - } + return true; } - else if (t.ADKD == 4) + } + else if (t.ADKD == 4) + { + if (!nav_data->second.get_utc_data().empty()) { - if (!tow_it.second.get_utc_data().empty()) + return true; + } + } + } + else + { + // iterate in reverse order to find matching TOW with Tag's COP value + std::map tow_map = prn_it->second; + for (auto rev_it = tow_map.rbegin(); rev_it != tow_map.rend(); ++rev_it) // note: starts with largest (i.e. newest) navigation dataset + { + // Check if current key (TOW) fulfills cut-off point and is not received after the tag + if ((t.TOW - 30 * t.cop <= rev_it->first || t.TOW - 30 * t.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < t.TOW) + { + if (t.ADKD == 0 || t.ADKD == 12) { - return true; + if (!rev_it->second.get_ephemeris_data().empty()) + { + return true; + } + } + else if (t.ADKD == 4) + { + if (!rev_it->second.get_utc_data().empty()) + { + return true; + } } } } @@ -245,17 +304,17 @@ void OSNMA_NavDataManager::log_status() const for (const auto& nav_data : tow_data) { LOG(INFO) << "Galileo OSNMA: IOD_nav=0b" << std::uppercase - << std::bitset<10>(nav_data.second.IOD_nav) + << std::bitset<10>(nav_data.second.get_IOD_nav()) << ", TOW_start=" << nav_data.second.get_tow_sf0() << ", TOW_last=" << nav_data.second.get_last_received_TOW() << ", l_t=" - << nav_data.second.verified_bits + << nav_data.second.get_verified_bits() << ", PRNd=" - << nav_data.second.PRNd + << nav_data.second.get_prn_d() << ", verified=" - << nav_data.second.verified; + << nav_data.second.get_verified_status(); } } } diff --git a/src/core/system_parameters/galileo_inav_message.cc b/src/core/system_parameters/galileo_inav_message.cc index ab62b684c..cb23ddac3 100644 --- a/src/core/system_parameters/galileo_inav_message.cc +++ b/src/core/system_parameters/galileo_inav_message.cc @@ -1413,20 +1413,15 @@ int32_t Galileo_Inav_Message::page_jk_decoder(const char* data_jk) */ OSNMA_msg Galileo_Inav_Message::get_osnma_msg() { - // TODO - why PRN of word 4 is done separately? nma_position_filled = std::array{}; // Fill TOW and WN nma_msg.WN_sf0 = WN_0; - int32_t TOW_sf0 = TOW_5 - 25; //- 24; // according to OS SIS ICD, TOW of word 5 is 25 seconds after Sf start TODO review + int32_t TOW_sf0 = TOW_5 - 25; if (TOW_sf0 < 0) { TOW_sf0 += 604800; } nma_msg.TOW_sf0 = static_cast(TOW_sf0); - // get ephemeris, clock and iono correction datn and GST-UTC and GST-GPS converstion parameters (may be incomplete) - nma_msg.EphemerisData = get_ephemeris(); - nma_msg.IonoData = get_iono(); - nma_msg.UtcModelData = get_utc_model(); return nma_msg; } diff --git a/src/core/system_parameters/galileo_inav_message.h b/src/core/system_parameters/galileo_inav_message.h index 6eeffddaf..92f3963a1 100644 --- a/src/core/system_parameters/galileo_inav_message.h +++ b/src/core/system_parameters/galileo_inav_message.h @@ -48,16 +48,9 @@ public: OSNMA_msg() = default; std::array mack{}; std::array hkroot{}; - uint32_t PRN{}; - uint32_t WN_sf0{}; - uint32_t TOW_sf0{}; - std::vector EphemerisClockAndStatusData{}; // TODO _2 rename and substitute this - std::string EphemerisClockAndStatusData_2{}; - std::vector TimingData{}; - std::string TimingData_2{}; - Galileo_Ephemeris EphemerisData{}; - Galileo_Iono IonoData{}; - Galileo_Utc_Model UtcModelData{}; + uint32_t PRN{}; // PRN_a authentication data PRN + uint32_t WN_sf0{}; // Week number at the start of OSNMA subframe + uint32_t TOW_sf0{}; // TOW at the start of OSNMA subframe }; /*! diff --git a/src/core/system_parameters/osnma_data.cc b/src/core/system_parameters/osnma_data.cc index b5355113f..b56d3b940 100644 --- a/src/core/system_parameters/osnma_data.cc +++ b/src/core/system_parameters/osnma_data.cc @@ -35,25 +35,11 @@ bool OSNMA_NavData::add_nav_data(const std::string& nav_data) } return false; } - - std::string OSNMA_NavData::get_utc_data() const { return d_utc; } - - std::string OSNMA_NavData::get_ephemeris_data() const { return d_ephemeris_iono; } - - -/** - * Updates the last TOW the NavData bits were received. - * @param TOW - */ -void OSNMA_NavData::update_last_received_timestamp(uint32_t TOW) -{ - d_last_received_TOW = TOW; -} diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index e3c78cdc4..0816abda6 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -137,30 +137,36 @@ class OSNMA_NavData public: OSNMA_NavData() : nav_data_id(id_counter++) {} const uint32_t nav_data_id; - std::string get_utc_data() const; std::string get_ephemeris_data() const; + uint32_t get_verified_bits() const { return verified_bits; } + uint32_t get_prn_d() const { return PRNd; } + uint32_t get_IOD_nav() const { return IOD_nav; } uint32_t get_last_received_TOW() const { return d_last_received_TOW; } uint32_t get_tow_sf0() const { return d_TOW_sf0; } - + bool have_this_bits(std::string nav_data); + bool get_verified_status() const { return verified; } bool add_nav_data(const std::string& nav_data); void set_tow_sf0(int value) { d_TOW_sf0 = value; } void set_ephemeris_data(std::string value) { d_ephemeris_iono = value; } void set_utc_data(std::string value) { d_utc = value; } void update_last_received_timestamp(uint32_t TOW); - - uint32_t verified_bits{0}; - uint32_t IOD_nav{0}; - uint32_t PRNd{0}; - uint32_t ADKD{}; - bool verified{false}; + void set_prn_d(uint32_t value) { PRNd = value; } + void set_last_received_TOW(uint32_t TOW) { d_last_received_TOW = TOW; }; + void set_update_verified_bits(uint32_t morebits) { verified_bits += morebits; } + void set_verified_status(bool value) { verified = value; } + void set_IOD_nav(uint32_t value) { IOD_nav = value; } private: + static uint32_t id_counter; std::string d_ephemeris_iono{""}; std::string d_utc{""}; uint32_t d_TOW_sf0{0}; uint32_t d_last_received_TOW{0}; - static uint32_t id_counter; + uint32_t PRNd{0}; + uint32_t verified_bits{0}; + uint32_t IOD_nav{0}; + bool verified{false}; }; 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 5c097e10b..755725d98 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 @@ -85,6 +85,12 @@ TEST_F(OsnmaTestVectors, NominalTestConf1) ASSERT_TRUE(result); // Assert + LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags; + LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags; + LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size(); + LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot; + LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey; + LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq; ASSERT_EQ(osnma->d_count_failed_tags, 0); ASSERT_EQ(osnma->d_count_failed_Kroot, 0); ASSERT_EQ(osnma->d_count_failed_pubKey, 0); @@ -113,6 +119,12 @@ TEST_F(OsnmaTestVectors, NominalTestConf2) ASSERT_TRUE(result); // Assert + LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags; + LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags; + LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size(); + LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot; + LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey; + LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq; ASSERT_EQ(osnma->d_count_failed_tags, 0); ASSERT_EQ(osnma->d_count_failed_Kroot, 0); ASSERT_EQ(osnma->d_count_failed_pubKey, 0); @@ -145,6 +157,12 @@ TEST_F(OsnmaTestVectors, PublicKeyRenewal) ASSERT_TRUE(result); // Assert + LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags; + LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags; + LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size(); + LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot; + LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey; + LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq; ASSERT_EQ(osnma->d_count_failed_tags, 0); ASSERT_EQ(osnma->d_count_failed_Kroot, 0); ASSERT_EQ(osnma->d_count_failed_pubKey, 0); @@ -176,6 +194,12 @@ TEST_F(OsnmaTestVectors, PublicKeyRevocation) ASSERT_TRUE(result); // Assert + LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags; + LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags; + LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size(); + LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot; + LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey; + LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq; ASSERT_EQ(osnma->d_count_failed_tags, 0); ASSERT_EQ(osnma->d_count_failed_Kroot, 0); ASSERT_EQ(osnma->d_count_failed_pubKey, 0); From e4f4c335bcc0375de374ef8cb8ac81f6f0188d74 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Mon, 12 Aug 2024 12:50:17 +0200 Subject: [PATCH 213/219] [TAS-257][TEST] add osnma benchmarking * Introduced new benchmarks to assess the performance of various OSNMA related functions, such as public key verification. * Mostly recycled code from testing codebase. * TODO: methods are private, could not find a MACRO like FRIEND_TEST to allow for it. Result of this, only one benchmark test is active. --- src/core/libs/osnma_msg_receiver.cc | 5 + src/core/libs/osnma_msg_receiver.h | 10 +- src/tests/benchmarks/CMakeLists.txt | 1 + src/tests/benchmarks/benchmark_osnma.cc | 126 ++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/tests/benchmarks/benchmark_osnma.cc diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index ace7dc40e..f5f8d4c0a 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -2026,3 +2026,8 @@ std::pair, uint8_t> osnma_msg_receiver::parse_dsm_kroot() c return {dsm_msg, nma_header}; } + +void osnma_msg_receiver::set_merkle_root(const std::vector& v) +{ + d_crypto->set_merkle_root(v); +} diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 4f3b0107b..8327709da 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -61,9 +61,11 @@ 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 - void msg_handler_osnma(const pmt::pmt_t& msg); //!< For testing purposes - void read_merkle_xml(const std::string& merklepath); //!< Public for testing purposes + ~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 + bool verify_dsm_pkr(const DSM_PKR_message& message) const; //!< Public for benchmarking purposes + void set_merkle_root(const std::vector& v); //!< Public for benchmarking purposes private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode); @@ -89,7 +91,7 @@ private: bool tag_has_nav_data_available(const Tag& t) const; bool tag_has_key_available(const Tag& t) const; bool verify_macseq(const MACK_message& mack); - bool verify_dsm_pkr(const DSM_PKR_message& message) const; + bool store_dsm_kroot(const std::vector& dsm, const uint8_t nma_header) const; std::pair, uint8_t> parse_dsm_kroot() const; diff --git a/src/tests/benchmarks/CMakeLists.txt b/src/tests/benchmarks/CMakeLists.txt index 2d79f4d06..31ebf9f82 100644 --- a/src/tests/benchmarks/CMakeLists.txt +++ b/src/tests/benchmarks/CMakeLists.txt @@ -112,6 +112,7 @@ endif() add_benchmark(benchmark_atan2 Gnuradio::runtime) add_benchmark(benchmark_copy) add_benchmark(benchmark_crypto core_libs Boost::headers ${EXTRA_BENCHMARK_DEPENDENCIES}) +add_benchmark(benchmark_osnma core_libs Boost::headers ${EXTRA_BENCHMARK_DEPENDENCIES}) add_benchmark(benchmark_detector core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) add_benchmark(benchmark_preamble core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) add_benchmark(benchmark_reed_solomon core_system_parameters ${EXTRA_BENCHMARK_DEPENDENCIES}) diff --git a/src/tests/benchmarks/benchmark_osnma.cc b/src/tests/benchmarks/benchmark_osnma.cc new file mode 100644 index 000000000..727c11e70 --- /dev/null +++ b/src/tests/benchmarks/benchmark_osnma.cc @@ -0,0 +1,126 @@ +/*! +* \file benchmark_osnma.cc +* \brief Benchmarks for osnma functions +* \author Carles Fernandez-Prades, 2024. cfernandez(at)cttc.es +* +* +* ----------------------------------------------------------------------------- +* +* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +* This file is part of GNSS-SDR. +* +* Copyright (C) 2024 (see AUTHORS file for a list of contributors) +* SPDX-License-Identifier: GPL-3.0-or-later +* +* ----------------------------------------------------------------------------- +*/ +#include "osnma_msg_receiver.h" +#include "Galileo_OSNMA.h" +#include "gnss_crypto.h" +#include "osnma_helper.h" +#include +#include + +void bm_verify_public_key(benchmark::State& state) +{ + osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT); + Osnma_Helper helper; + osnma->set_merkle_root(helper.convert_from_hex_string("A10C440F3AA62453526DB4AF76DF8D9410D35D8277397D7053C700D192702B0D")); + DSM_PKR_message dsm_pkr_message; + dsm_pkr_message.npkt = 0x01; + dsm_pkr_message.npktid = 0x2; + dsm_pkr_message.mid = 0x01; + std::vector vec = helper.convert_from_hex_string( + "7CBE05D9970CFC9E22D0A43A340EF557624453A2E821AADEAC989C405D78BA06" + "956380BAB0D2C939EC6208151040CCFFCF1FB7156178FD1255BA0AECAAA253F7" + "407B6C5DD4DF059FF8789474061301E1C34881DB7A367A913A3674300E21EAB1" + "24EF508389B7D446C3E2ECE8D459FBBD3239A794906F5B1F92469C640164FD87"); + std::copy(vec.begin(), vec.end(), dsm_pkr_message.itn.begin()); + dsm_pkr_message.npk = helper.convert_from_hex_string("0303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA"); + + while (state.KeepRunning()) + { + osnma->verify_dsm_pkr(dsm_pkr_message); + } +} + +void bm_verify_tesla_key(benchmark::State& state) +{ + // osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT); + // Osnma_Helper helper; + // osnma->d_tesla_key_verified = false; + // osnma->d_osnma_data.d_dsm_kroot_message.kroot = {0x5B, 0xF8, 0xC9, 0xCB, 0xFC, 0xF7, 0x04, 0x22, 0x08, 0x14, 0x75, 0xFD, 0x44, 0x5D, 0xF0, 0xFF}; // Kroot, TOW 345570 GST_0 - 30 + // osnma->d_osnma_data.d_dsm_kroot_message.ks = 4; // TABLE 10 --> 128 bits + // osnma->d_osnma_data.d_dsm_kroot_message.alpha = 0x610BDF26D77B; + // osnma->d_GST_SIS = (1248 & 0x00000FFF) << 20 | (345630 & 0x000FFFFF); + // osnma->d_GST_0 = ((1248 & 0x00000FFF) << 20 | (345600 & 0x000FFFFF)); // applicable time (GST_Kroot + 30) + // osnma->d_GST_Sf = osnma->d_GST_0 + 30 * std::floor((osnma->d_GST_SIS - osnma->d_GST_0) / 30); // Eq. 3 R.G. + // + // osnma->d_tesla_keys.insert((std::pair>(345600, {0xEF, 0xF9, 0x99, 0x04, 0x0E, 0x19, 0xB5, 0x70, 0x83, 0x50, 0x60, 0xBE, 0xBD, 0x23, 0xED, 0x92}))); // K1, not needed, just for reference. + // std::vector key = {0x2D, 0xC3, 0xA3, 0xCD, 0xB1, 0x17, 0xFA, 0xAD, 0xB8, 0x3B, 0x5F, 0x0B, 0x6F, 0xEA, 0x88, 0xEB}; // K2 + // uint32_t TOW = 345630; + // + // while (state.KeepRunning()) + // { + // osnma->verify_tesla_key(key, TOW); + // } +} + +void bm_verify_tesla_key_24h(benchmark::State& state) +{ + // TODO - copy of normal tesla verification but with 2800 steps instead of only two (max Kroot time is 1 day as per spec.) +} + +void bm_tag_verification(benchmark::State& state) +{ + // osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(CRTFILE_DEFAULT, MERKLEFILE_DEFAULT); + // Osnma_Helper helper; + // uint32_t TOW_Tag0 = 345660; + // uint32_t TOW_NavData = TOW_Tag0 - 30; + // uint32_t TOW_Key_Tag0 = TOW_Tag0 + 30; + // uint32_t WN = 1248; + // uint32_t PRNa = 2; + // uint8_t CTR = 1; + // + // osnma->d_osnma_data.d_dsm_kroot_message.ts = 9; // 40 bit + // osnma->d_tesla_keys[TOW_Key_Tag0] = {0x69, 0xC0, 0x0A, 0xA7, 0x36, 0x42, 0x37, 0xA6, 0x5E, 0xBF, 0x00, 0x6A, 0xD8, 0xDD, 0xBC, 0x73}; // K4 + // osnma->d_osnma_data.d_dsm_kroot_message.mf = 0; + // osnma->d_nav_data_manager->add_navigation_data( + // "000011101001011001000100000101000111010110100100100101100000000000" + // "011101101011001111101110101010000001010000011011111100000011101011" + // "011100101101011010101011011011001001110111101011110110111111001111" + // "001000011111101110011000111111110111111010000011101011111111110000" + // "110111000000100000001110110000110110001110000100001110101100010100" + // "110100010001000110001110011010110000111010000010000000000001101000" + // "000000000011100101100100010000000000000110110100110001111100000000" + // "000000100110100000000101010010100000001011000010001001100000011111" + // "110111111111000000000", + // PRNa, TOW_NavData); + // osnma->d_osnma_data.d_nma_header.nmas = 0b10; + // + // MACK_tag_and_info MTI; + // MTI.tag = static_cast(0xE37BC4F858); + // MTI.tag_info.PRN_d = 0x02; + // MTI.tag_info.ADKD = 0x00; + // MTI.tag_info.cop = 0x0F; + // Tag t0(MTI, TOW_Tag0, WN, PRNa, CTR); + // + // while (state.KeepRunning()) + // { + // osnma->verify_tag(t0); + // } +} + +void bm_kroot_verification(benchmark::State& state) +{ + // TODO - this is essentially the signature verification, maybe could implement it for comparison purposes +} + +BENCHMARK(bm_verify_public_key); +BENCHMARK(bm_verify_tesla_key); +BENCHMARK(bm_verify_tesla_key_24h); +BENCHMARK(bm_tag_verification); +BENCHMARK(bm_kroot_verification); + + +BENCHMARK_MAIN(); \ No newline at end of file From 2e867f2dac0c2a398cbe331dc88685ec1e29e7d5 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Wed, 14 Aug 2024 13:14:23 +0200 Subject: [PATCH 214/219] [TAS-240][FEAT] Implement TESLA Chain Renewal and Revocation I * Implemented a new chain renewal mechanism for OSNMA data structure updates and key management. * Added related flags and data fields. * tested successfully with test vectors. --- src/core/libs/osnma_msg_receiver.cc | 94 ++++++++++++------- src/core/libs/osnma_msg_receiver.h | 3 + src/core/system_parameters/osnma_data.h | 2 + .../osnma/osnma_test_vectors.cc | 38 ++++++++ 4 files changed, 105 insertions(+), 32 deletions(-) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index f5f8d4c0a..b4fb6a29d 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -258,7 +258,7 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& 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. + // 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) { @@ -309,6 +309,27 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& std::cout << "Galileo OSNMA: Alert message :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << std::endl; } + if (d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 2 /* EOC */ && d_GST_chain_renewal_start == 0) + { + d_flag_chain_renewal = true; + d_GST_chain_renewal_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); + LOG(INFO) << "Galileo OSNMA: Chain renewal :: Start at at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]"; + std::cout << "Galileo OSNMA: Chain renewal :: Start at at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << std::endl; + } + if (d_flag_chain_renewal && d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 1 /* Nominal */) + { + // Step 2, start using the new kroot + d_flag_chain_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_chain_renewal_start) / 3600.0; + LOG(INFO) << "Galileo OSNMA: Chain renewal :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" + << ", Duration=" << duration_hours << "h"; + std::cout << "Galileo OSNMA: Chain renewal :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" + << ", Duration=" << duration_hours << "h" << std::endl; + d_osnma_data.d_dsm_kroot_message = d_osnma_data.d_dsm_kroot_new_message; // set new kroot as the one to use from now on + d_tesla_key_verified = false; // force the verification up to the Kroot due to chain change + } + 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 @@ -478,24 +499,27 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg // DSM-KROOT message if ((d_osnma_data.d_dsm_header.dsm_id < 12 || d_flag_hot_start) && d_public_key_verified) { + bool new_chain = (d_dsm_reader->get_cidkr(dsm_msg) != d_osnma_data.d_nma_header.cid) && d_flag_chain_renewal; + DSM_KROOT_message& applicable_kroot_msg = new_chain ? d_osnma_data.d_dsm_kroot_new_message : d_osnma_data.d_dsm_kroot_message; + // Parse Kroot message LOG(INFO) << "Galileo OSNMA: DSM-KROOT message received."; - d_osnma_data.d_dsm_kroot_message.nb_dk = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); - d_osnma_data.d_dsm_kroot_message.pkid = d_dsm_reader->get_pkid(dsm_msg); - d_osnma_data.d_dsm_kroot_message.cidkr = d_dsm_reader->get_cidkr(dsm_msg); - d_osnma_data.d_dsm_kroot_message.reserved1 = d_dsm_reader->get_dsm_reserved1(dsm_msg); - d_osnma_data.d_dsm_kroot_message.hf = d_dsm_reader->get_hf(dsm_msg); - d_osnma_data.d_dsm_kroot_message.mf = d_dsm_reader->get_mf(dsm_msg); - d_osnma_data.d_dsm_kroot_message.ks = d_dsm_reader->get_ks(dsm_msg); - d_osnma_data.d_dsm_kroot_message.ts = d_dsm_reader->get_ts(dsm_msg); - d_osnma_data.d_dsm_kroot_message.maclt = d_dsm_reader->get_maclt(dsm_msg); - d_osnma_data.d_dsm_kroot_message.reserved = d_dsm_reader->get_dsm_reserved(dsm_msg); - d_osnma_data.d_dsm_kroot_message.wn_k = d_dsm_reader->get_wn_k(dsm_msg); - d_osnma_data.d_dsm_kroot_message.towh_k = d_dsm_reader->get_towh_k(dsm_msg); - d_osnma_data.d_dsm_kroot_message.alpha = d_dsm_reader->get_alpha(dsm_msg); + applicable_kroot_msg.nb_dk = d_dsm_reader->get_number_blocks_index(dsm_msg[0]); + applicable_kroot_msg.pkid = d_dsm_reader->get_pkid(dsm_msg); + applicable_kroot_msg.cidkr = d_dsm_reader->get_cidkr(dsm_msg); + applicable_kroot_msg.reserved1 = d_dsm_reader->get_dsm_reserved1(dsm_msg); + applicable_kroot_msg.hf = d_dsm_reader->get_hf(dsm_msg); + applicable_kroot_msg.mf = d_dsm_reader->get_mf(dsm_msg); + applicable_kroot_msg.ks = d_dsm_reader->get_ks(dsm_msg); + applicable_kroot_msg.ts = d_dsm_reader->get_ts(dsm_msg); + applicable_kroot_msg.maclt = d_dsm_reader->get_maclt(dsm_msg); + applicable_kroot_msg.reserved = d_dsm_reader->get_dsm_reserved(dsm_msg); + applicable_kroot_msg.wn_k = d_dsm_reader->get_wn_k(dsm_msg); + applicable_kroot_msg.towh_k = d_dsm_reader->get_towh_k(dsm_msg); + applicable_kroot_msg.alpha = d_dsm_reader->get_alpha(dsm_msg); // Kroot field - const uint16_t l_lk_bytes = d_dsm_reader->get_lk_bits(d_osnma_data.d_dsm_kroot_message.ks) / 8; - d_osnma_data.d_dsm_kroot_message.kroot = d_dsm_reader->get_kroot(dsm_msg, l_lk_bytes); + const uint16_t l_lk_bytes = d_dsm_reader->get_lk_bits(applicable_kroot_msg.ks) / 8; + applicable_kroot_msg.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->get_public_key_type()); @@ -504,19 +528,19 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg l_ds_bits = it->second; } const uint16_t l_ds_bytes = l_ds_bits / 8; - d_osnma_data.d_dsm_kroot_message.ds = std::vector(l_ds_bytes, 0); // C: this accounts for padding in case needed. + applicable_kroot_msg.ds = std::vector(l_ds_bytes, 0); // C: this accounts for padding in case needed. for (uint16_t k = 0; k < l_ds_bytes; k++) { - d_osnma_data.d_dsm_kroot_message.ds[k] = dsm_msg[13 + l_lk_bytes + k]; + applicable_kroot_msg.ds[k] = dsm_msg[13 + l_lk_bytes + k]; } // Padding - const uint16_t l_dk_bits = d_dsm_reader->get_l_dk_bits(d_osnma_data.d_dsm_kroot_message.nb_dk); + const uint16_t l_dk_bits = d_dsm_reader->get_l_dk_bits(applicable_kroot_msg.nb_dk); const uint16_t l_dk_bytes = l_dk_bits / 8; const uint16_t l_pdk_bytes = (l_dk_bytes - 13 - l_lk_bytes - l_ds_bytes); - d_osnma_data.d_dsm_kroot_message.p_dk = std::vector(l_pdk_bytes, 0); + applicable_kroot_msg.p_dk = std::vector(l_pdk_bytes, 0); for (uint16_t k = 0; k < l_pdk_bytes; k++) { - d_osnma_data.d_dsm_kroot_message.p_dk[k] = dsm_msg[13 + l_lk_bytes + l_ds_bytes + k]; + applicable_kroot_msg.p_dk[k] = dsm_msg[13 + l_lk_bytes + l_ds_bytes + k]; } const uint16_t check_l_dk = 104 * std::ceil(1.0 + static_cast((l_lk_bytes * 8.0) + l_ds_bits) / 104.0); @@ -539,15 +563,15 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg std::vector 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]); + MSG.push_back(applicable_kroot_msg.ds[k]); } std::vector hash; - if (d_osnma_data.d_dsm_kroot_message.hf == 0) // Table 8. + if (applicable_kroot_msg.hf == 0) // Table 8. { hash = d_crypto->compute_SHA_256(MSG); } - else if (d_osnma_data.d_dsm_kroot_message.hf == 2) + else if (applicable_kroot_msg.hf == 2) { hash = d_crypto->compute_SHA3_256(MSG); } @@ -563,17 +587,16 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg p_dk_truncated.push_back(hash[i]); } // Check that the padding bits received match the computed values - if (d_osnma_data.d_dsm_kroot_message.p_dk == p_dk_truncated) + if (applicable_kroot_msg.p_dk == p_dk_truncated) { LOG(INFO) << "Galileo OSNMA: DSM-KROOT message received ok."; LOG(INFO) << "Galileo OSNMA: DSM-KROOT with CID=" << static_cast(d_osnma_data.d_nma_header.cid) - << ", PKID=" << static_cast(d_osnma_data.d_dsm_kroot_message.pkid) - << ", WN=" << static_cast(d_osnma_data.d_dsm_kroot_message.wn_k) - << ", TOW=" << static_cast(d_osnma_data.d_dsm_kroot_message.towh_k) * 3600; - // local_time_verification(osnma_msg); // FIXME TODO: real time verification needed + << ", PKID=" << static_cast(applicable_kroot_msg.pkid) + << ", WN=" << static_cast(applicable_kroot_msg.wn_k) + << ", TOW=" << static_cast(applicable_kroot_msg.towh_k) * 3600; // 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 && applicable_kroot_msg.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); @@ -581,14 +604,15 @@ void osnma_msg_receiver::process_dsm_message(const std::vector& dsm_msg } if (l_ds_bits == 512) { - d_kroot_verified = d_crypto->verify_signature_ecdsa_p256(message, d_osnma_data.d_dsm_kroot_message.ds); + d_kroot_verified = d_crypto->verify_signature_ecdsa_p256(message, applicable_kroot_msg.ds); } else if (l_ds_bits == 1056) { - d_kroot_verified = d_crypto->verify_signature_ecdsa_p521(message, d_osnma_data.d_dsm_kroot_message.ds); + d_kroot_verified = d_crypto->verify_signature_ecdsa_p521(message, applicable_kroot_msg.ds); } if (d_kroot_verified) { + applicable_kroot_msg.verified = true; std::cout << "Galileo OSNMA: DSM-KROOT authentication successful!" << std::endl; LOG(INFO) << "Galileo OSNMA: DSM-KROOT authentication successful!"; if (d_flag_alert_message) @@ -1271,6 +1295,12 @@ std::vector osnma_msg_receiver::compute_merkle_root(const DSM_PKR_messa } +/** + * @brief Get the Merkle tree base leave from a DSM_PKR_message. + * + * @param dsm_pkr_message The DSM_PKR_message object from which to retrieve the Merkle tree leave. + * @return std::vector The Merkle tree base leave from the DSM_PKR_message object. + */ std::vector osnma_msg_receiver::get_merkle_tree_leaves(const DSM_PKR_message& dsm_pkr_message) const { // build base leaf m_i according to OSNMA SIS ICD v1.1, section 6.2 DSM-PKR Verification diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 8327709da..56d104cf4 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -129,6 +129,7 @@ private: uint32_t d_GST_SIS{}; // GST coming from W6 and W5 of SIS uint32_t d_GST_PKR_PKREV_start{}; uint32_t d_GST_PKR_AM_start{}; + uint32_t d_GST_chain_renewal_start{}; uint32_t d_count_successful_tags{0}; uint32_t d_count_failed_tags{0}; @@ -149,6 +150,7 @@ private: bool d_flag_PK_revocation{false}; bool d_flag_NPK_set{false}; bool d_flag_alert_message{false}; + bool d_flag_chain_renewal{false}; // Provide access to inner functions to Gtest FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); @@ -161,6 +163,7 @@ private: FRIEND_TEST(OsnmaTestVectors, NominalTestConf2); FRIEND_TEST(OsnmaTestVectors, PublicKeyRenewal); FRIEND_TEST(OsnmaTestVectors, PublicKeyRevocation); + FRIEND_TEST(OsnmaTestVectors, ChainRenewal); FRIEND_TEST(OsnmaTestVectors, AlertMessage); }; diff --git a/src/core/system_parameters/osnma_data.h b/src/core/system_parameters/osnma_data.h index 0816abda6..7e6d03b42 100644 --- a/src/core/system_parameters/osnma_data.h +++ b/src/core/system_parameters/osnma_data.h @@ -116,6 +116,7 @@ public: uint8_t maclt{}; uint8_t reserved{}; uint8_t towh_k{}; + bool verified{false}; }; @@ -182,6 +183,7 @@ public: DSM_dsm_header d_dsm_header; DSM_PKR_message d_dsm_pkr_message; DSM_KROOT_message d_dsm_kroot_message; + DSM_KROOT_message d_dsm_kroot_new_message; MACK_message d_mack_message; OSNMA_NavData d_nav_data; }; 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 755725d98..494103499 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 @@ -152,6 +152,7 @@ TEST_F(OsnmaTestVectors, PublicKeyRenewal) } std::vector> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3}; + // Act d_flag_NPK = true; bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); ASSERT_TRUE(result); @@ -190,6 +191,43 @@ TEST_F(OsnmaTestVectors, PublicKeyRevocation) } std::vector> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3}; + // Act + bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); + ASSERT_TRUE(result); + + // Assert + LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags; + LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags; + LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size(); + LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot; + LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey; + LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq; + ASSERT_EQ(osnma->d_count_failed_tags, 0); + ASSERT_EQ(osnma->d_count_failed_Kroot, 0); + ASSERT_EQ(osnma->d_count_failed_pubKey, 0); + ASSERT_EQ(osnma->d_count_failed_macseq, 0); +} + +TEST_F(OsnmaTestVectors, ChainRenewal) +{ + // Arrange + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt"; + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml"; + osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + + std::tm input_time_step1 = {0, 45, 16, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::tm input_time_step2 = {0, 30, 18, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::vector input_times = {input_time_step1, input_time_step2}; + + std::vector testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/eoc_step1/06_OCT_2023_GST_16_45_01.csv"); + std::vector testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/eoc_step2/06_OCT_2023_GST_18_30_01.csv"); + if (testVectors_step1.empty() || testVectors_step2.empty()) + { + ASSERT_TRUE(false); + } + std::vector> testVectors = {testVectors_step1, testVectors_step2}; + + // Act bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); ASSERT_TRUE(result); From 092a78f580b0e3109fa53a08ea43be6cfdf3bdfe Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 15 Aug 2024 13:10:04 +0200 Subject: [PATCH 215/219] [TAS-145][Feat][PVT] Implement PVT logic for osnma data * Created a map with PRN-> set * osnma transmits every 30 s the list of authenticated PRNs along with the IOD authenticated * PVT takes this into account to consider the observable valid (only strict mode) * ""successfully"" tested. Osnma first tag authenticated: 1:36, TTFAF 2:06 => most of the time the PVT has authenticated solution, except two 30s gaps in which there is no PVT computed. (3-4' firs gap and second from 13:30-14:06) * TODOs: find out reason and improve size management of the maps. --- .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 18 +++++++++++------- .../PVT/gnuradio_blocks/rtklib_pvt_gs.h | 2 ++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 2ffe95d24..23fd9605d 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -1658,13 +1658,10 @@ void rtklib_pvt_gs::msg_handler_osnma(const pmt::pmt_t& msg) // so with ADKD0 and ADKD12 validated), their corresponding TOW at the beginning // of the authenticated subframe, and maybe the COP. const size_t msg_type_hash_code = pmt::any_ref(msg).type().hash_code(); - if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) + if (msg_type_hash_code == typeid(std::shared_ptr).hash_code()) { - // Act according to NMA data - if (d_osnma_strict) - { - // TODO - } + const auto osnma_data = wht::any_cast>(pmt::any_ref(msg)); + d_auth_nav_data_map[osnma_data->get_prn_d()].insert(osnma_data->get_IOD_nav()); } } catch (const wht::bad_any_cast& e) @@ -2051,7 +2048,14 @@ int rtklib_pvt_gs::work(int noutput_items, gr_vector_const_void_star& input_item if (d_osnma_strict && ((std::string(in[i][epoch].Signal, 2) == std::string("1B")) || ((std::string(in[i][epoch].Signal, 2) == std::string("7X"))))) { // Pick up only authenticated satellites - // TODO + auto IOD_nav_list = d_auth_nav_data_map.find(tmp_eph_iter_gal->second.PRN); + if (IOD_nav_list != d_auth_nav_data_map.cend()) + { + if (IOD_nav_list->second.find(tmp_eph_iter_gal->second.IOD_nav) != IOD_nav_list->second.cend()) + { + store_valid_observable = true; + } + } } else { diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h index 4acc14728..d6f61f1c6 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h @@ -20,6 +20,7 @@ #include "gnss_block_interface.h" #include "gnss_synchro.h" #include "gnss_time.h" +#include "osnma_data.h" #include "rtklib.h" #include #include @@ -203,6 +204,7 @@ private: std::map d_gnss_observables_map; std::map d_gnss_observables_map_t0; std::map d_gnss_observables_map_t1; + std::map> d_auth_nav_data_map; std::queue d_TimeChannelTagTimestamps; From ea0684d64019e114b44112ca287420a817e47ec4 Mon Sep 17 00:00:00 2001 From: cesaaargm Date: Thu, 15 Aug 2024 21:48:29 +0200 Subject: [PATCH 216/219] [TAS-240][FEAT] Implement TESLA Chain Renewal and Revocation II * revocation sucessfully tested. * Diagram of step 1 is wrong in that KROOT with CID=0 also received after entering step 1. * Duration of CREV=2.75h * All tags verified succesffully. --- src/core/libs/osnma_msg_receiver.cc | 22 +++++++++++ src/core/libs/osnma_msg_receiver.h | 3 ++ .../osnma/osnma_test_vectors.cc | 39 +++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index b4fb6a29d..556f3fddf 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -330,6 +330,28 @@ void osnma_msg_receiver::process_osnma_message(const std::shared_ptr& d_tesla_key_verified = false; // force the verification up to the Kroot due to chain change } + if (d_osnma_data.d_nma_header.nmas == 3 /* DU */ && d_osnma_data.d_nma_header.cpks == 3 /* CREV */ && d_GST_chain_revocation_start == 0) + { + d_flag_chain_revocation = true; + d_number_of_blocks[d_osnma_data.d_dsm_header.dsm_id] = 0; // delete blocks received up to now, new chain must be received. + // d_public_key_verified = false; + d_kroot_verified = false; + d_tesla_key_verified = false; + d_GST_chain_revocation_start = d_helper->compute_gst(osnma_msg->WN_sf0, osnma_msg->TOW_sf0); + LOG(INFO) << "Galileo OSNMA: Chain revocation :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]"; + std::cout << "Galileo OSNMA: Chain revocation :: Start at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" << std::endl; + } + if (d_flag_chain_revocation && d_osnma_data.d_nma_header.nmas == 2 /* OP */ && d_osnma_data.d_nma_header.cpks == 1 /* Nominal */) + { + d_flag_chain_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_chain_revocation_start) / 3600.0; + LOG(INFO) << "Galileo OSNMA: Chain revocation :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" + << ", Duration=" << duration_hours << "h"; + std::cout << "Galileo OSNMA: Chain revocation :: Finished at GST=[" << osnma_msg->WN_sf0 << " " << osnma_msg->TOW_sf0 << "]" + << ", Duration=" << duration_hours << "h" << std::endl; + } + 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 diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 56d104cf4..1598e23c2 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -130,6 +130,7 @@ private: uint32_t d_GST_PKR_PKREV_start{}; uint32_t d_GST_PKR_AM_start{}; uint32_t d_GST_chain_renewal_start{}; + uint32_t d_GST_chain_revocation_start{}; uint32_t d_count_successful_tags{0}; uint32_t d_count_failed_tags{0}; @@ -151,6 +152,7 @@ private: bool d_flag_NPK_set{false}; bool d_flag_alert_message{false}; bool d_flag_chain_renewal{false}; + bool d_flag_chain_revocation{false}; // Provide access to inner functions to Gtest FRIEND_TEST(OsnmaMsgReceiverTest, TeslaKeyVerification); @@ -164,6 +166,7 @@ private: FRIEND_TEST(OsnmaTestVectors, PublicKeyRenewal); FRIEND_TEST(OsnmaTestVectors, PublicKeyRevocation); FRIEND_TEST(OsnmaTestVectors, ChainRenewal); + FRIEND_TEST(OsnmaTestVectors, ChainRevocation); FRIEND_TEST(OsnmaTestVectors, AlertMessage); }; 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 494103499..7ac04d3c7 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 @@ -244,6 +244,45 @@ TEST_F(OsnmaTestVectors, ChainRenewal) ASSERT_EQ(osnma->d_count_failed_macseq, 0); } +TEST_F(OsnmaTestVectors, ChainRevocation) +{ + // Arrange + std::string crtFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/PublicKey/OSNMA_PublicKey_20231007041500_PKID_7.crt"; + std::string merkleFilePath = std::string(BASE_OSNMA_TEST_VECTORS) + "cryptographic_material/Merkle_tree_2/MerkleTree/OSNMA_MerkleTree_20231007041500_PKID_7.xml"; + osnma_msg_receiver_sptr osnma = osnma_msg_receiver_make(crtFilePath, merkleFilePath); + + std::tm input_time_step1 = {0, 45, 21, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::tm input_time_step2 = {0, 30, 23, 6, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + std::tm input_time_step3 = {0, 30, 00, 7, 10 - 1, 2023 - 1900, 0, 0, 0, 0, 0}; + + std::vector input_times = {input_time_step1, input_time_step2, input_time_step3}; + + std::vector testVectors_step1 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step1/06_OCT_2023_GST_21_45_01.csv"); + std::vector testVectors_step2 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step2/06_OCT_2023_GST_23_30_01.csv"); + std::vector testVectors_step3 = readTestVectorsFromFile(std::string(BASE_OSNMA_TEST_VECTORS) + "osnma_test_vectors/crev_step3/07_OCT_2023_GST_00_30_01.csv"); + if (testVectors_step1.empty() || testVectors_step2.empty() || testVectors_step3.empty()) + { + ASSERT_TRUE(false); + } + std::vector> testVectors = {testVectors_step1, testVectors_step2, testVectors_step3}; + + // Act + bool result = feedOsnmaWithTestVectors(osnma, testVectors, input_times); + ASSERT_TRUE(result); + + // Assert + LOG(INFO) << "Successful tags count= " << osnma->d_count_successful_tags; + LOG(INFO) << "Failed tags count= " << osnma->d_count_failed_tags; + LOG(INFO) << "Unverified tags count= " << osnma->d_tags_awaiting_verify.size(); + LOG(INFO) << "Failed Kroot count= " << osnma->d_count_failed_Kroot; + LOG(INFO) << "Failed PK count= " << osnma->d_count_failed_pubKey; + LOG(INFO) << "Failed MACSEQ count= " << osnma->d_count_failed_macseq; + ASSERT_EQ(osnma->d_count_failed_tags, 0); + ASSERT_EQ(osnma->d_count_failed_Kroot, 0); + ASSERT_EQ(osnma->d_count_failed_pubKey, 0); + ASSERT_EQ(osnma->d_count_failed_macseq, 0); +} + TEST_F(OsnmaTestVectors, AlertMessage) { // Arrange From 94d76356128972e8d50b1c10cb213026b3e43847 Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Fri, 16 Aug 2024 09:40:45 +0200 Subject: [PATCH 217/219] Small fixes (#26) * Decouple the FPGA DMA signal source from the AD9361 FPGA signal source. * Add the MAX2771_EVKIT FPGA signal source and the ENABLE_FPGA_MAX2771_EVKIT flag to enable it. * Adjust cross-compilation flags to properly support FPGA signal sources * fix signal source names for consistency * Detect if the spidev driver is installed when the ENABLE_MAX2771 flag is set. Detect if the DMA proxy driver is installed when the ENABLE_DMA_PROXY flag is set. Check if ENABLE_FPGA is set when either ENABLE_MAX2771 or ENABLE_DMA_PROXY is set. * fix FPGA signal source names for consistency * Fix FPGA-related CMakefile flags * make cpplint happy * make cpplint happy * make cmakelint happy * make clang-format happy * Replaced the AD9361 FPGA signal source with the ADRV9361_Z7035 FPGA and the FMCOMMS5 FPGA signal sources. * Bump local version of GoogleTest to 1.15.2 and Protocol Buffers to 27.3 * Avoid code duplication in CMake modules * Update clang-tidy job * Clang Tidy fixes * Improve efficiency of Concurrent_Map and Concurrent_Queue classes * Fix segmentation fault if the SignalSource implementation is not available * Moved decimation factor count variable to the class * Avoid possible runtime error when PVT.enable_rx_clock_correction=true * Fix formatting * Fix clang-tidy job * Capitalize FPGA in class implementation names * Capitalize acronyms in FPGA-related class names * Instantiate sources only once * Update changelog * Fix building in some environments and fix CI jobs * Fix clang-tidy complain --------- Co-authored-by: Marc Majoral Co-authored-by: cesaaargm Co-authored-by: Xavier Guerrero-Pau --- CMakeLists.txt | 107 +++ docs/CHANGELOG.md | 19 + .../PVT/gnuradio_blocks/rtklib_pvt_gs.h | 3 +- ...lileo_e1_pcps_ambiguous_acquisition_fpga.h | 4 +- .../galileo_e5a_pcps_acquisition_fpga.h | 4 +- .../galileo_e5b_pcps_acquisition_fpga.h | 2 +- .../gps_l1_ca_pcps_acquisition_fpga.h | 4 +- .../adapters/gps_l2_m_pcps_acquisition_fpga.h | 4 +- .../adapters/gps_l5i_pcps_acquisition_fpga.h | 4 +- .../signal_source/adapters/CMakeLists.txt | 22 +- .../adapters/ad9361_fpga_signal_source.cc | 885 ------------------ .../adrv9361_z7035_signal_source_fpga.cc | 398 ++++++++ ....h => adrv9361_z7035_signal_source_fpga.h} | 50 +- .../adapters/dma_signal_source_fpga.cc | 581 ++++++++++++ .../adapters/dma_signal_source_fpga.h | 118 +++ .../adapters/fmcomms5_signal_source_fpga.cc | 347 +++++++ .../adapters/fmcomms5_signal_source_fpga.h | 135 +++ .../max2771_evkit_signal_source_fpga.cc | 467 +++++++++ .../max2771_evkit_signal_source_fpga.h | 164 ++++ .../signal_source/libs/CMakeLists.txt | 16 +- .../signal_source/libs/fpga_buffer_monitor.cc | 18 +- .../signal_source/libs/fpga_buffer_monitor.h | 8 +- .../libs/fpga_dynamic_bit_selection.h | 1 - .../signal_source/libs/fpga_spidev.cc | 131 +++ .../signal_source/libs/fpga_spidev.h | 61 ++ .../signal_source/libs/fpga_switch.cc | 15 +- .../signal_source/libs/fpga_switch.h | 4 +- .../galileo_e1_dll_pll_veml_tracking_fpga.h | 4 +- .../galileo_e5a_dll_pll_tracking_fpga.h | 4 +- .../gps_l1_ca_dll_pll_tracking_fpga.h | 4 +- .../adapters/gps_l2_m_dll_pll_tracking_fpga.h | 4 +- .../adapters/gps_l5_dll_pll_tracking_fpga.h | 4 +- src/core/libs/osnma_msg_receiver.cc | 2 +- src/core/libs/osnma_msg_receiver.h | 10 +- src/core/libs/osnma_nav_data_manager.cc | 10 +- src/core/receiver/CMakeLists.txt | 8 + src/core/receiver/gnss_block_factory.cc | 85 +- src/core/receiver/gnss_flowgraph.cc | 2 +- src/tests/benchmarks/benchmark_osnma.cc | 33 +- ...e1_pcps_ambiguous_acquisition_test_fpga.cc | 6 +- .../gps_l1_ca_pcps_acquisition_test_fpga.cc | 6 +- .../hybrid_observables_test_fpga.cc | 36 +- .../gps_l1_ca_dll_pll_tracking_test_fpga.cc | 2 +- .../tracking/tracking_pull-in_test_fpga.cc | 38 +- 44 files changed, 2769 insertions(+), 1061 deletions(-) delete mode 100644 src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc create mode 100644 src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc rename src/algorithms/signal_source/adapters/{ad9361_fpga_signal_source.h => adrv9361_z7035_signal_source_fpga.h} (70%) create mode 100644 src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc create mode 100644 src/algorithms/signal_source/adapters/dma_signal_source_fpga.h create mode 100644 src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc create mode 100644 src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h create mode 100644 src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc create mode 100644 src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h create mode 100644 src/algorithms/signal_source/libs/fpga_spidev.cc create mode 100644 src/algorithms/signal_source/libs/fpga_spidev.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e8dfc5825..c10936ca1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,10 @@ option(ENABLE_AD936X_SDR "Enable the use of AD936X front-ends using libiio, requ option(ENABLE_AD9361 "Enable the use of AD9361 direct to FPGA hardware, requires libiio" OFF) +option(ENABLE_MAX2771 "Enable the use of MAX2771 direct to FPGA hardware, requires the spidev driver" OFF) + +option(ENABLE_DMA_PROXY "Enable the use of the DMA direct to FPGA hardware, requires the DMA Proxy driver" OFF) + option(ENABLE_RAW_UDP "Enable the use of high-optimized custom UDP packet sample source, requires libpcap" OFF) option(ENABLE_FLEXIBAND "Enable the use of the signal source adater for the Teleorbit Flexiband GNU Radio driver" OFF) @@ -3267,6 +3271,107 @@ endif() +##################################################################### +# Check signal sources related to FPGA only. +##################################################################### +if(ENABLE_MAX2771 AND NOT ENABLE_FPGA) + message(STATUS "The SPIdev driver is enabled, but the FPGA is not enabled. The FPGA is required when using the SPIdev driver.") + if(ENABLE_PACKAGING) + set(ENABLE_MAX2771 OFF) + else() + message(FATAL_ERROR "ENABLE_MAX2771 can only be set when ENABLE_FPGA is also set.") + endif() +endif() +if(ENABLE_DMA_PROXY AND NOT ENABLE_FPGA) + message(STATUS "The DMA Proxy driver is enabled, but the FPGA is not enabled. The FPGA is required when using the DMA Proxy driver.") + if(ENABLE_PACKAGING) + set(ENABLE_DMA_PROXY OFF) + else() + message(FATAL_ERROR "ENABLE_DMA_PROXY can only be set when ENABLE_FPGA is also set.") + endif() +endif() + + + +##################################################################### +# spidev driver - OPTIONAL +# Linux kernel driver that provides user-space access to Serial +# Peripheral Interface) +##################################################################### +if(ENABLE_MAX2771) + if(DEFINED ENV{SDKTARGETSYSROOT}) + set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT}) + else() + set(TARGET_ROOTFS_PATH "") + endif() + find_program(STRINGS_EXECUTABLE strings) + if(NOT STRINGS_EXECUTABLE) + message(STATUS "The 'strings' command could not be found. See https://www.gnu.org/software/binutils/") + message(STATUS " You can try to install it by typing:") + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|kFreeBSD|GNU") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(STATUS " sudo yum install binutils") + elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") + message(STATUS " sudo zypper install binutils") + else() + message(STATUS " sudo apt-get install binutils") + endif() + endif() + message(FATAL_ERROR "Binutils are required to build GNSS-SDR for SoC FPGA devices using the MAX2771 option.") + endif() + set(DTB_FILE "${TARGET_ROOTFS_PATH}/boot/devicetree/system-top.dtb") + if(EXISTS "${DTB_FILE}") + message(STATUS "Found DTB file: ${DTB_FILE}") + # Run the strings command and grep for "spidev" + execute_process( + COMMAND ${STRINGS_EXECUTABLE} ${DTB_FILE} + COMMAND grep "spidev" + OUTPUT_VARIABLE GREP_OUTPUT + RESULT_VARIABLE GREP_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(GREP_RESULT EQUAL 0) + message(STATUS "Found spidev-compatible peripheral in ${DTB_FILE}.") + else() + message(STATUS "SPIdev driver not found, its installation is required.") + if(ENABLE_PACKAGING) + set(ENABLE_MAX2771 OFF) + else() + message(FATAL_ERROR "SPIdev driver is required for building gnss-sdr with -DENABLE_MAX2271=ON.") + endif() + endif() + else() + message(FATAL_ERROR "The device tree (DTB) file ${DTB_FILE} cannot be found.") + endif() +endif() + + + +##################################################################### +# DMA Proxy driver - OPTIONAL +# Simplified and efficient interface for user-space applications +# to leverage DMA capabilities for Xilinx FPGA and SoC systems +##################################################################### +if(ENABLE_DMA_PROXY) + if(DEFINED ENV{SDKTARGETSYSROOT}) + set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT}) + else() + set(TARGET_ROOTFS_PATH "") + endif() + set(DMA_PROXY_FILE "${TARGET_ROOTFS_PATH}/lib/modules/5.10.0-xilinx-v2021.2/extra/dma-proxy.ko") + if(EXISTS "${DMA_PROXY_FILE}") + message(STATUS "Found dma-proxy.ko file: ${DMA_PROXY_FILE}") + else() + if(ENABLE_PACKAGING) + set(ENABLE_DMA_PROXY OFF) + else() + message(FATAL_ERROR "DMA Proxy driver is required for building gnss-sdr with -DENABLE_DMA_PROXY=ON.") + endif() + endif() +endif() + + + ############################################## # TELEORBIT FLEXIBAND FRONTEND - OPTIONAL ############################################## @@ -3471,6 +3576,8 @@ add_feature_info(ENABLE_LIMESDR ENABLE_LIMESDR "Enables Limesdr_Signal_Source. R add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.") add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.") add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.") +add_feature_info(ENABLE_MAX2771 ENABLE_MAX2771 "Enables FPGA_MAX2771_EVKIT_Signal_Source for devices with the MAX2771 chipset. Requires the spidev driver") +add_feature_info(ENABLE_DMA_PROXY ENABLE_DMA_PROXY "Enables DMA Signal_Source. Requires the DMA Proxy driver") add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.") add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.") add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.") diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 1812c76b7..3963e0b20 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -21,6 +21,25 @@ All notable changes to GNSS-SDR will be documented in this file. wideband device (HackRF/LimeSDR/USRP). Demonstration: https://www.youtube.com/watch?v=ZQs2sFchJ6w https://www.youtube.com/watch?v=HnZkKj9a-QM +- Add the following signal sources for use when GNSS-SDR is operating on SoC + FPGA boards (`-DENABLE_FPGA=ON`): + + - `ADRV9361_Z7035_Signal_Source_FPGA`: Analog Devices ADRV9361-Z7035 board. + - `FMCOMMS5_Signal_Source_FPGA`: FMCOMMS5 analog front-end. + - `MAX2771_EVKIT_Signal_Source_FPGA`: MAX2771 evaluation kit analog front-end. + - `DMA_Signal_Source_FPGA`: FPGA DMA working in post-processing mode. + + When building GNSS-SDR for the SoC FPGA, the following options can be passed + to CMake with possible values of `ON` or `OFF`, and their default value is + `OFF`: + + - `-DENABLE_AD9361`: Checks if the IIO driver is installed and builds the + `ADRV9361_Z7035_Signal_Source_FPGA` and the `FMCOMMS5_Signal_Source_FPGA` + sources. + - `-DENABLE_MAX2771`: Checks if the SPIdev driver is installed and builds the + `MAX2771_EVKIT_Signal_Source_FPGA` source. + - `-DENABLE_DMA_PROXY`: Checks if the DMA proxy driver is installed for + controlling the DMA in the FPGA and enables its usage. ### Improvements in Portability: diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h index d6f61f1c6..65f7bd548 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.h @@ -35,6 +35,7 @@ #include // for map #include // for shared_ptr, unique_ptr #include // for std::queue +#include // for std::set #include // for string #include // for key_t #include // for vector @@ -204,7 +205,7 @@ private: std::map d_gnss_observables_map; std::map d_gnss_observables_map_t0; std::map d_gnss_observables_map_t1; - std::map> d_auth_nav_data_map; + std::map> d_auth_nav_data_map; std::queue d_TimeChannelTagTimestamps; diff --git a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h index 09829267c..b28d63422 100644 --- a/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/galileo_e1_pcps_ambiguous_acquisition_fpga.h @@ -66,11 +66,11 @@ public: } /*! - * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga" + * \brief Returns "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA" */ inline std::string implementation() override { - return "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"; + return "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA"; } /*! diff --git a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h index 12d38bf34..14dae0230 100644 --- a/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/galileo_e5a_pcps_acquisition_fpga.h @@ -66,11 +66,11 @@ public: } /*! - * \brief Returns "Galileo_E5a_Pcps_Acquisition_Fpga" + * \brief Returns "Galileo_E5a_Pcps_Acquisition_FPGA" */ inline std::string implementation() override { - return "Galileo_E5a_Pcps_Acquisition_Fpga"; + return "Galileo_E5a_Pcps_Acquisition_FPGA"; } /*! diff --git a/src/algorithms/acquisition/adapters/galileo_e5b_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/galileo_e5b_pcps_acquisition_fpga.h index 8ae54e46a..d67bfd4a6 100644 --- a/src/algorithms/acquisition/adapters/galileo_e5b_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/galileo_e5b_pcps_acquisition_fpga.h @@ -65,7 +65,7 @@ public: } /*! - * \brief Returns "Galileo_E5b_Pcps_Acquisition_Fpga" + * \brief Returns "Galileo_E5b_Pcps_Acquisition_FPGA" */ inline std::string implementation() override { diff --git a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h index cfc483cda..2b7bfd3f9 100644 --- a/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/gps_l1_ca_pcps_acquisition_fpga.h @@ -67,11 +67,11 @@ public: } /*! - * \brief Returns "GPS_L1_CA_PCPS_Acquisition_Fpga" + * \brief Returns "GPS_L1_CA_PCPS_Acquisition_FPGA" */ inline std::string implementation() override { - return "GPS_L1_CA_PCPS_Acquisition_Fpga"; + return "GPS_L1_CA_PCPS_Acquisition_FPGA"; } /*! diff --git a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h index 19acec8cb..81f4d342c 100644 --- a/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/gps_l2_m_pcps_acquisition_fpga.h @@ -60,11 +60,11 @@ public: } /*! - * \brief Returns "GPS_L2_M_PCPS_Acquisition_Fpga" + * \brief Returns "GPS_L2_M_PCPS_Acquisition_FPGA" */ inline std::string implementation() override { - return "GPS_L2_M_PCPS_Acquisition_Fpga"; + return "GPS_L2_M_PCPS_Acquisition_FPGA"; } inline size_t item_size() override diff --git a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h index 497ab9b90..bf2bfafcf 100644 --- a/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h +++ b/src/algorithms/acquisition/adapters/gps_l5i_pcps_acquisition_fpga.h @@ -69,11 +69,11 @@ public: } /*! - * \brief Returns "GPS_L5i_PCPS_Acquisition_Fpga" + * \brief Returns "GPS_L5i_PCPS_Acquisition_FPGA" */ inline std::string implementation() override { - return "GPS_L5i_PCPS_Acquisition_Fpga"; + return "GPS_L5i_PCPS_Acquisition_FPGA"; } /*! diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index e4ead311b..0aa745101 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -37,8 +37,26 @@ if(ENABLE_AD9361) ############################################### # AD9361 DIRECT TO FPGA Hardware ############################################### - list(APPEND OPT_DRIVER_SOURCES ad9361_fpga_signal_source.cc) - list(APPEND OPT_DRIVER_HEADERS ad9361_fpga_signal_source.h) + list(APPEND OPT_DRIVER_SOURCES adrv9361_z7035_signal_source_fpga.cc) + list(APPEND OPT_DRIVER_HEADERS adrv9361_z7035_signal_source_fpga.h) + list(APPEND OPT_DRIVER_SOURCES fmcomms5_signal_source_fpga.cc) + list(APPEND OPT_DRIVER_HEADERS fmcomms5_signal_source_fpga.h) +endif() + +if(ENABLE_MAX2771) + ############################################### + # MAX2771 EVKIT DIRECT TO FPGA Hardware + ############################################### + list(APPEND OPT_DRIVER_SOURCES max2771_evkit_signal_source_fpga.cc) + list(APPEND OPT_DRIVER_HEADERS max2771_evkit_signal_source_fpga.h) +endif() + +if(ENABLE_DMA_PROXY) + ############################################### + # FPGA DMA source + ############################################### + list(APPEND OPT_DRIVER_SOURCES dma_signal_source_fpga.cc) + list(APPEND OPT_DRIVER_HEADERS dma_signal_source_fpga.h) endif() if(ENABLE_FLEXIBAND AND TELEORBIT_FOUND) diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc b/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc deleted file mode 100644 index 3a3360bed..000000000 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.cc +++ /dev/null @@ -1,885 +0,0 @@ -/*! - * \file ad9361_fpga_signal_source.cc - * \brief signal source for Analog Devices front-end AD9361 connected directly - * to FPGA accelerators. - * This source implements only the AD9361 control. It is NOT compatible with - * conventional SDR acquisition and tracking blocks. - * Please use the fmcomms2 source if conventional SDR acquisition and tracking - * is selected in the configuration file. - * \authors
    - *
  • Javier Arribas, jarribas(at)cttc.es - *
  • Marc Majoral, mmajoral(at)cttc.es - *
- * - * ----------------------------------------------------------------------------- - * - * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. - * This file is part of GNSS-SDR. - * - * Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors) - * SPDX-License-Identifier: GPL-3.0-or-later - * - * ----------------------------------------------------------------------------- - */ - -#include "ad9361_fpga_signal_source.h" -#include "GPS_L1_CA.h" -#include "GPS_L5.h" -#include "ad9361_manager.h" -#include "command_event.h" -#include "configuration_interface.h" -#include "gnss_sdr_flags.h" -#include "gnss_sdr_string_literals.h" -#include "uio_fpga.h" -#include -#include // for std::max -#include // for std::chrono -#include // for std::floor -#include // for std::exception -#include // for open, O_WRONLY -#include // for std::ifstream -#include // for std::setprecision -#include // for std::cout -#include // for write -#include // fr std::vector - -#if USE_GLOG_AND_GFLAGS -#include -#else -#include -#include -#endif - -using namespace std::string_literals; - -Ad9361FpgaSignalSource::Ad9361FpgaSignalSource(const ConfigurationInterface *configuration, - const std::string &role, unsigned int in_stream, unsigned int out_stream, - Concurrent_Queue *queue __attribute__((unused))) - : SignalSourceBase(configuration, role, "Ad9361_Fpga_Signal_Source"s), - queue_(queue), - gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), - gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), - rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), - filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), - filename0_(configuration->property(role + ".filename", empty_string)), - rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), - rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), - scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)), - phase_dds_deg_(configuration->property(role + ".phase_dds_deg", 0.0)), - tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", default_tx_attenuation_db)), - freq0_(configuration->property(role + ".freq", 0)), - freq1_(configuration->property(role + ".freq1", static_cast(GPS_L5_FREQ_HZ))), - sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), - bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), - samples_to_skip_(0), - samples_(configuration->property(role + ".samples", static_cast(0))), - freq_dds_tx_hz_(configuration->property(role + ".freq_dds_tx_hz", uint64_t(10000))), - freq_rf_tx_hz_(configuration->property(role + ".freq_rf_tx_hz", static_cast(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))), - tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast(500000))), - Fpass_(configuration->property(role + ".Fpass", static_cast(0.0))), - Fstop_(configuration->property(role + ".Fstop", static_cast(0.0))), - num_input_files_(1), - dma_buff_offset_pos_(0), - in_stream_(in_stream), - out_stream_(out_stream), - switch_position_(configuration->property(role + ".switch_position", 0)), - item_size_(sizeof(int8_t)), - enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)), - filter_auto_(configuration->property(role + ".filter_auto", false)), - quadrature_(configuration->property(role + ".quadrature", true)), - rf_dc_(configuration->property(role + ".rf_dc", true)), - bb_dc_(configuration->property(role + ".bb_dc", true)), - rx1_enable_(configuration->property(role + ".rx1_enable", true)), - rx2_enable_(configuration->property(role + ".rx2_enable", true)), - enable_DMA_(false), - enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), - enable_ovf_check_buffer_monitor_active_(false), - dump_(configuration->property(role + ".dump", false)), -#if USE_GLOG_AND_GFLAGS - rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)), -#else - rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))), -#endif - repeat_(configuration->property(role + ".repeat", false)) -{ - const double seconds_to_skip = configuration->property(role + ".seconds_to_skip", 0.0); - const size_t header_size = configuration->property(role + ".header_size", 0); - - const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || - (configuration->property("Channels_1B.count", 0) > 0)); - const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || - (configuration->property("Channels_L5.count", 0) > 0) || - (configuration->property("Channels_5X.count", 0) > 0)); - - const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1; - if (freq0_ == 0) - { - // use ".freq0" - freq0_ = configuration->property(role + ".freq0", static_cast(GPS_L1_FREQ_HZ)); - } - - if (filter_auto_) - { - filter_source_ = configuration->property(role + ".filter_source", std::string("Auto")); - } - else - { - filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); - } -#if USE_GLOG_AND_GFLAGS - // override value with commandline flag, if present - if (FLAGS_signal_source != "-") - { - filename0_ = FLAGS_signal_source; - } - if (FLAGS_s != "-") - { - filename0_ = FLAGS_s; - } -#else - if (absl::GetFlag(FLAGS_signal_source) != "-") - { - filename0_ = absl::GetFlag(FLAGS_signal_source); - } - if (absl::GetFlag(FLAGS_s) != "-") - { - filename0_ = absl::GetFlag(FLAGS_s); - } -#endif - if (filename0_.empty()) - { - num_input_files_ = 2; - filename0_ = configuration->property(role + ".filename0", empty_string); - filename1_ = configuration->property(role + ".filename1", empty_string); - } - // if only one input file is specified in the configuration file then: - // if there is at least one channel assigned to frequency band 1 then the DMA transfers the samples to the L1 frequency band channels - // otherwise the DMA transfers the samples to the L2/L5 frequency band channels - // if more than one input file are specified then the DMA transfer the samples to both the L1 and the L2/L5 frequency channels. - if (filename1_.empty()) - { - if (enable_rx1_band) - { - dma_buff_offset_pos_ = 2; - } - } - else - { - dma_buff_offset_pos_ = 2; - } - - if (seconds_to_skip > 0) - { - samples_to_skip_ = static_cast(seconds_to_skip * sample_rate_) * 2; - } - if (header_size > 0) - { - samples_to_skip_ += header_size; - } - - std::string device_io_name; // Switch UIO device file - // find the uio device file corresponding to the switch. - if (find_uio_dev_file_name(device_io_name, switch_device_name, 0) < 0) - { - std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << switch_device_name << '\n'; - return; - } - - if (switch_position_ != 0 && switch_position_ != 2) - { - std::cout << "SignalSource.switch_position configuration parameter must be either 0: read from file(s) via DMA, or 2: read from AD9361\n"; - std::cout << "SignalSource.switch_position configuration parameter set to its default value switch_position=0 - read from file(s)\n"; - switch_position_ = 0; - } - - switch_fpga = std::make_shared(device_io_name); - switch_fpga->set_switch_position(switch_position_); - - if (switch_position_ == 0) // Inject file(s) via DMA - { - enable_DMA_ = true; - - if (samples_ == 0) // read all file - { - /*! - * BUG workaround: The GNU Radio file source does not stop the receiver after reaching the End of File. - * A possible solution is to compute the file length in samples using file size, excluding the last 100 milliseconds, and enable always the - * valve block - */ - std::ifstream file(filename0_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); - std::ifstream::pos_type size; - - if (file.is_open()) - { - size = file.tellg(); - DLOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size_)); - } - else - { - std::cerr << "SignalSource: Unable to open the samples file " << filename0_.c_str() << '\n'; - return; - } - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(16); - std::cout << "Processing file " << filename0_ << ", which contains " << static_cast(size) << " [bytes]\n"; - std::cout.precision(ss); - - if (size > 0) - { - const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; - const uint64_t bytes_to_process = static_cast(size) - bytes_to_skip; - samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(sample_rate_))); // process all the samples available in the file excluding at least the last 1 ms - } - - if (!filename1_.empty()) - { - std::ifstream file(filename1_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); - std::ifstream::pos_type size; - - if (file.is_open()) - { - size = file.tellg(); - DLOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size_)); - } - else - { - std::cerr << "SignalSource: Unable to open the samples file " << filename1_.c_str() << '\n'; - return; - } - std::streamsize ss = std::cout.precision(); - std::cout << std::setprecision(16); - std::cout << "Processing file " << filename1_ << ", which contains " << static_cast(size) << " [bytes]\n"; - std::cout.precision(ss); - - int64_t samples_rx2 = 0; - if (size > 0) - { - const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; - const uint64_t bytes_to_process = static_cast(size) - bytes_to_skip; - samples_rx2 = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(sample_rate_))); // process all the samples available in the file excluding at least the last 1 ms - } - samples_ = std::min(samples_, samples_rx2); - } - } - - CHECK(samples_ > 0) << "File does not contain enough samples to process."; - double signal_duration_s = (static_cast(samples_) * (1 / static_cast(sample_rate_))) / 2.0; - - DLOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; - std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]\n"; - - if (filename1_.empty()) - { - DLOG(INFO) << "File source filename " << filename0_; - } - else - { - DLOG(INFO) << "File source filename rx1 " << filename0_; - DLOG(INFO) << "File source filename rx2 " << filename1_; - } - DLOG(INFO) << "Samples " << samples_; - DLOG(INFO) << "Sampling frequency " << sample_rate_; - DLOG(INFO) << "Item type " << std::string("ibyte"); - DLOG(INFO) << "Item size " << item_size_; - DLOG(INFO) << "Repeat " << repeat_; - } - if (switch_position_ == 2) // Real-time via AD9361 - { - std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; - - enable_ovf_check_buffer_monitor_active_ = false; // check buffer overflow and buffer monitor disabled by default - - // some basic checks - if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2")) - { - std::cout << "Configuration parameter rf_port_select should take one of these values:\n"; - std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n"; - std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n'; - rf_port_select_ = default_rf_port_select; - LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select; - } - - if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid")) - { - std::cout << "Configuration parameter gain_mode_rx1 should take one of these values:\n"; - std::cout << " manual, slow_attack, fast_attack, hybrid\n"; - std::cout << "Error: provided value gain_mode_rx1=" << gain_mode_rx1_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value gain_mode_rx1=" << default_gain_mode << '\n'; - gain_mode_rx1_ = default_gain_mode; - LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << default_gain_mode; - } - - if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid")) - { - std::cout << "Configuration parameter gain_mode_rx2 should take one of these values:\n"; - std::cout << " manual, slow_attack, fast_attack, hybrid\n"; - std::cout << "Error: provided value gain_mode_rx2=" << gain_mode_rx2_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value gain_mode_rx2=" << default_gain_mode << '\n'; - gain_mode_rx2_ = default_gain_mode; - LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << default_gain_mode; - } - - if (gain_mode_rx1_ == "manual") - { - if (rf_gain_rx1_ > 73.0 || rf_gain_rx1_ < -1.0) - { - std::cout << "Configuration parameter rf_gain_rx1 should take values between -1.0 and 73 dB\n"; - std::cout << "Error: provided value rf_gain_rx1=" << rf_gain_rx1_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_gain_rx1=" << default_manual_gain_rx1 << '\n'; - rf_gain_rx1_ = default_manual_gain_rx1; - LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << default_manual_gain_rx1; - } - } - - if (gain_mode_rx2_ == "manual") - { - if (rf_gain_rx2_ > 73.0 || rf_gain_rx2_ < -1.0) - { - std::cout << "Configuration parameter rf_gain_rx2 should take values between -1.0 and 73 dB\n"; - std::cout << "Error: provided value rf_gain_rx2=" << rf_gain_rx2_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value rf_gain_rx2=" << default_manual_gain_rx2 << '\n'; - rf_gain_rx2_ = default_manual_gain_rx2; - LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << default_manual_gain_rx2; - } - } - - if ((filter_source_ != "Off") && (filter_source_ != "Auto") && (filter_source_ != "File") && (filter_source_ != "Design")) - { - std::cout << "Configuration parameter filter_source should take one of these values:\n"; - std::cout << " Off: Disable filter\n"; - std::cout << " Auto: Use auto-generated filters\n"; - std::cout << " File: User-provided filter in filter_filename parameter\n"; - std::cout << " Design: Create filter from Fpass, Fstop, sampling_frequency and bandwidth parameters\n"; - std::cout << "Error: provided value filter_source=" << filter_source_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value filter_source=Off\n"; - filter_source_ = std::string("Off"); - LOG(WARNING) << "Invalid configuration value for filter_source parameter. Set to filter_source=Off"; - } - - if (bandwidth_ < 200000 || bandwidth_ > 56000000) - { - std::cout << "Configuration parameter bandwidth should take values between 200000 and 56000000 Hz\n"; - std::cout << "Error: provided value bandwidth=" << bandwidth_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value bandwidth=" << default_bandwidth << '\n'; - bandwidth_ = default_bandwidth; - LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << default_bandwidth; - } - - std::cout << "LO frequency : " << freq0_ << " Hz\n"; - try - { - config_ad9361_rx_local(bandwidth_, - sample_rate_, - freq0_, - freq1_, - rf_port_select_, - rx1_enable_, - rx2_enable_, - gain_mode_rx1_, - gain_mode_rx2_, - rf_gain_rx1_, - rf_gain_rx2_, - quadrature_, - rf_dc_, - bb_dc_, - filter_source_, - filter_filename_, - Fpass_, - Fstop_); - } - catch (const std::runtime_error &e) - { - std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n'; - return; - } - // LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION - if (enable_dds_lo_ == true) - { - if (tx_bandwidth_ < static_cast(std::floor(static_cast(freq_dds_tx_hz_) * 1.1)) || (tx_bandwidth_ < 200000) || (tx_bandwidth_ > 1000000)) - { - std::cout << "Configuration parameter tx_bandwidth value should be between " << std::max(static_cast(freq_dds_tx_hz_) * 1.1, 200000.0) << " and 1000000 Hz\n"; - std::cout << "Error: provided value tx_bandwidth=" << tx_bandwidth_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value tx_bandwidth=500000\n"; - tx_bandwidth_ = 500000; - LOG(WARNING) << "Invalid configuration value for tx_bandwidth parameter. Set to tx_bandwidth=500000"; - } - if (tx_attenuation_db_ > 0.0 || tx_attenuation_db_ < -89.75) - { - std::cout << "Configuration parameter tx_attenuation_db should take values between 0.0 and -89.95 in 0.25 dB steps\n"; - std::cout << "Error: provided value tx_attenuation_db=" << tx_attenuation_db_ << " is not among valid values\n"; - std::cout << " This parameter has been set to its default value tx_attenuation_db=" << default_tx_attenuation_db << '\n'; - tx_attenuation_db_ = default_tx_attenuation_db; - LOG(WARNING) << "Invalid configuration value for tx_attenuation_db parameter. Set to tx_attenuation_db=" << default_tx_attenuation_db; - } - try - { - config_ad9361_lo_local(tx_bandwidth_, - sample_rate_, - freq_rf_tx_hz_, - tx_attenuation_db_, - freq_dds_tx_hz_, - scale_dds_dbfs_, - phase_dds_deg_); - } - catch (const std::runtime_error &e) - { - std::cerr << "Exception cached when configuring the TX carrier: " << e.what() << '\n'; - return; - } - } - - // when the receiver is working in real-time mode via AD9361 perform buffer overflow checking, - // and if dump is enabled perform buffer monitoring - enable_ovf_check_buffer_monitor_active_ = true; - - std::string device_io_name_buffer_monitor; - - std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); - - // find the uio device file corresponding to the buffer monitor - if (find_uio_dev_file_name(device_io_name_buffer_monitor, buffer_monitor_device_name, 0) < 0) - { - std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << buffer_monitor_device_name << '\n'; - return; - } - - buffer_monitor_fpga = std::make_shared(device_io_name_buffer_monitor, num_freq_bands, dump_, dump_filename); - thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); - } - - // dynamic bits selection - if (enable_dynamic_bit_selection_) - { - dynamic_bit_selection_fpga = std::make_shared(enable_rx1_band, enable_rx2_band); - thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); - } - - if (in_stream_ > 0) - { - LOG(ERROR) << "A signal source does not have an input stream"; - } - if (out_stream_ > 1) - { - LOG(ERROR) << "This implementation only supports one output stream"; - } -} - - -Ad9361FpgaSignalSource::~Ad9361FpgaSignalSource() -{ - /* cleanup and exit */ - if (switch_position_ == 0) // read samples from a file via DMA - { - std::unique_lock lock(dma_mutex); - enable_DMA_ = false; // disable the DMA - lock.unlock(); - if (thread_file_to_dma.joinable()) - { - thread_file_to_dma.join(); - } - } - - if (switch_position_ == 2) // Real-time via AD9361 - { - if (rf_shutdown_) - { - std::cout << "* AD9361 Disabling RX streaming channels\n"; - if (!disable_ad9361_rx_local()) - { - LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; - } - if (enable_dds_lo_) - { - try - { - ad9361_disable_lo_local(); - } - catch (const std::exception &e) - { - LOG(WARNING) << "Problem shutting down the AD9361 TX stream: " << e.what(); - } - } - } - - // disable buffer overflow checking and buffer monitoring - std::unique_lock lock(buffer_monitor_mutex); - enable_ovf_check_buffer_monitor_active_ = false; - lock.unlock(); - - if (thread_buffer_monitor.joinable()) - { - thread_buffer_monitor.join(); - } - } - - std::unique_lock lock(dynamic_bit_selection_mutex); - bool bit_selection_enabled = enable_dynamic_bit_selection_; - lock.unlock(); - - if (bit_selection_enabled == true) - { - std::unique_lock lock(dynamic_bit_selection_mutex); - enable_dynamic_bit_selection_ = false; - lock.unlock(); - - if (thread_dynamic_bit_selection.joinable()) - { - thread_dynamic_bit_selection.join(); - } - } -} - - -void Ad9361FpgaSignalSource::start() -{ - thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); }); -} - - -void Ad9361FpgaSignalSource::run_DMA_process(const std::string &filename0_, const std::string &filename1_, uint64_t &samples_to_skip, size_t &item_size, int64_t &samples, bool &repeat, uint32_t &dma_buff_offset_pos, Concurrent_Queue *queue) -{ - std::ifstream infile1; - infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit); - - - // FPGA DMA control - dma_fpga = std::make_shared(); - - // open the files - try - { - infile1.open(filename0_, std::ios::binary); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception opening file " << filename0_ << '\n'; - // stop the receiver - queue->push(pmt::make_any(command_event_make(200, 0))); - return; - } - - std::ifstream infile2; - if (!filename1_.empty()) - { - infile2.exceptions(std::ifstream::failbit | std::ifstream::badbit); - try - { - infile2.open(filename1_, std::ios::binary); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception opening file " << filename1_ << '\n'; - // stop the receiver - queue->push(pmt::make_any(command_event_make(200, 0))); - return; - } - } - - // skip the initial samples if needed - uint64_t bytes_to_skeep = samples_to_skip * item_size; - try - { - infile1.ignore(bytes_to_skeep); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception skipping initial samples file " << filename0_ << '\n'; - // stop the receiver - queue->push(pmt::make_any(command_event_make(200, 0))); - return; - } - - if (!filename1_.empty()) - { - try - { - infile2.ignore(bytes_to_skeep); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception skipping initial samples file " << filename1_ << '\n'; - // stop the receiver - queue->push(pmt::make_any(command_event_make(200, 0))); - return; - } - } - - // rx signal vectors - std::vector input_samples(sample_block_size * 2); // complex samples - // pointer to DMA buffer - int8_t *dma_buffer; - int nread_elements = 0; // num bytes read from the file corresponding to frequency band 1 - bool run_DMA = true; - - // Open DMA device - if (dma_fpga->DMA_open()) - { - std::cerr << "Cannot open loop device\n"; - // stop the receiver - queue->push(pmt::make_any(command_event_make(200, 0))); - return; - } - dma_buffer = dma_fpga->get_buffer_address(); - - // if only one frequency band is used then clear the samples corresponding to the unused frequency band - uint32_t dma_index = 0; - if (num_input_files_ == 1) - { - // if only one file is enabled then clear the samples corresponding to the frequency band that is not used. - for (int index0 = 0; index0 < (nread_elements); index0 += 2) - { - dma_buffer[dma_index + (2 - dma_buff_offset_pos)] = 0; - dma_buffer[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0; - dma_index += 4; - } - } - - uint64_t nbytes_remaining = samples * item_size; - uint32_t read_buffer_size = sample_block_size * 2; // complex samples - - // run the DMA - while (run_DMA) - { - dma_index = 0; - if (nbytes_remaining < read_buffer_size) - { - read_buffer_size = nbytes_remaining; - } - nbytes_remaining = nbytes_remaining - read_buffer_size; - - // read filename 0 - try - { - infile1.read(reinterpret_cast(input_samples.data()), read_buffer_size); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception reading file " << filename0_ << '\n'; - break; - } - if (infile1) - { - nread_elements = read_buffer_size; - } - else - { - // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN - nread_elements = infile1.gcount(); - } - - for (int index0 = 0; index0 < (nread_elements); index0 += 2) - { - // dma_buff_offset_pos is 1 for the L1 band and 0 for the other bands - dma_buffer[dma_index + dma_buff_offset_pos] = input_samples[index0]; - dma_buffer[dma_index + 1 + dma_buff_offset_pos] = input_samples[index0 + 1]; - dma_index += 4; - } - - // read filename 1 (if enabled) - if (num_input_files_ > 1) - { - dma_index = 0; - try - { - infile2.read(reinterpret_cast(input_samples.data()), read_buffer_size); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception reading file " << filename1_ << '\n'; - break; - } - if (infile2) - { - nread_elements = read_buffer_size; - } - else - { - // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN - nread_elements = infile2.gcount(); - } - - for (int index0 = 0; index0 < (nread_elements); index0 += 2) - { - // filename2 is never the L1 band - dma_buffer[dma_index] = input_samples[index0]; - dma_buffer[dma_index + 1] = input_samples[index0 + 1]; - dma_index += 4; - } - } - - if (nread_elements > 0) - { - if (dma_fpga->DMA_write(nread_elements * 2)) - { - std::cerr << "Error: DMA could not send all the required samples\n"; - break; - } - // Throttle the DMA - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - if (nbytes_remaining == 0) - { - if (repeat) - { - // read the file again - nbytes_remaining = samples * item_size; - read_buffer_size = sample_block_size * 2; - try - { - infile1.seekg(0); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception resetting the position of the next byte to be extracted to zero " << filename0_ << '\n'; - break; - } - - // skip the initial samples if needed - uint64_t bytes_to_skeep = samples_to_skip * item_size; - try - { - infile1.ignore(bytes_to_skeep); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception skipping initial samples file " << filename0_ << '\n'; - break; - } - - if (!filename1_.empty()) - { - try - { - infile2.seekg(0); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception setting the position of the next byte to be extracted to zero " << filename1_ << '\n'; - break; - } - - try - { - infile2.ignore(bytes_to_skeep); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception skipping initial samples file " << filename1_ << '\n'; - break; - } - } - } - else - { - // the input file is completely processed. Stop the receiver. - run_DMA = false; - } - } - std::unique_lock lock(dma_mutex); - if (enable_DMA_ == false) - { - run_DMA = false; - } - lock.unlock(); - } - - if (dma_fpga->DMA_close()) - { - std::cerr << "Error closing loop device " << '\n'; - } - try - { - infile1.close(); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception closing file " << filename0_ << '\n'; - } - - if (num_input_files_ > 1) - { - try - { - infile2.close(); - } - catch (const std::ifstream::failure &e) - { - std::cerr << "Exception closing file " << filename1_ << '\n'; - } - } - - // Stop the receiver - queue->push(pmt::make_any(command_event_make(200, 0))); -} - - -void Ad9361FpgaSignalSource::run_dynamic_bit_selection_process() -{ - bool dynamic_bit_selection_active = true; - - while (dynamic_bit_selection_active) - { - // setting the bit selection to the top bits - dynamic_bit_selection_fpga->bit_selection(); - std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); - std::unique_lock lock(dynamic_bit_selection_mutex); - if (enable_dynamic_bit_selection_ == false) - { - dynamic_bit_selection_active = false; - } - lock.unlock(); - } -} - - -void Ad9361FpgaSignalSource::run_buffer_monitor_process() -{ - bool enable_ovf_check_buffer_monitor_active = true; - - std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); - - while (enable_ovf_check_buffer_monitor_active) - { - buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); - std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); - std::unique_lock lock(buffer_monitor_mutex); - if (enable_ovf_check_buffer_monitor_active_ == false) - { - enable_ovf_check_buffer_monitor_active = false; - } - lock.unlock(); - } -} - - -void Ad9361FpgaSignalSource::connect(gr::top_block_sptr top_block) -{ - if (top_block) - { /* top_block is not null */ - }; - DLOG(INFO) << "AD9361 FPGA source nothing to connect"; -} - - -void Ad9361FpgaSignalSource::disconnect(gr::top_block_sptr top_block) -{ - if (top_block) - { /* top_block is not null */ - }; - DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; -} - - -gr::basic_block_sptr Ad9361FpgaSignalSource::get_left_block() -{ - LOG(WARNING) << "Trying to get signal source left block."; - return {}; -} - - -gr::basic_block_sptr Ad9361FpgaSignalSource::get_right_block() -{ - return {}; -} diff --git a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc new file mode 100644 index 000000000..9d29e2de2 --- /dev/null +++ b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc @@ -0,0 +1,398 @@ +/*! + * \file adrv9361_z7035_signal_source_fpga.cc + * \brief signal source for the Analog Devices ADRV9361-Z7035 evaluation board + * directly connected to the FPGA accelerators. + * This source implements only the AD9361 control. It is NOT compatible with + * conventional SDR acquisition and tracking blocks. + * Please use the fmcomms2 source if conventional SDR acquisition and tracking + * is selected in the configuration file. + * \authors
    + *
  • Javier Arribas, jarribas(at)cttc.es + *
  • Marc Majoral, mmajoral(at)cttc.es + *
+ * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "adrv9361_z7035_signal_source_fpga.h" +#include "GPS_L1_CA.h" +#include "GPS_L5.h" +#include "ad9361_manager.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_string_literals.h" +#include // for std::max +#include // for std::chrono +#include // for std::floor +#include // for std::exception +#include // for std::cout + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#include +#endif + +using namespace std::string_literals; + +Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const ConfigurationInterface *configuration, + const std::string &role, unsigned int in_stream, unsigned int out_stream, + Concurrent_Queue *queue __attribute__((unused))) + : SignalSourceBase(configuration, role, "ADRV9361_Z7035_Signal_Source_FPGA"s), + gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), + gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), + rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), + filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), + rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), + rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), + scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)), + phase_dds_deg_(configuration->property(role + ".phase_dds_deg", 0.0)), + tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", default_tx_attenuation_db)), + freq0_(configuration->property(role + ".freq", 0)), + freq1_(configuration->property(role + ".freq1", static_cast(GPS_L5_FREQ_HZ))), + sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), + bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), + freq_dds_tx_hz_(configuration->property(role + ".freq_dds_tx_hz", uint64_t(10000))), + freq_rf_tx_hz_(configuration->property(role + ".freq_rf_tx_hz", static_cast(GPS_L1_FREQ_HZ - GPS_L5_FREQ_HZ - freq_dds_tx_hz_))), + tx_bandwidth_(configuration->property(role + ".tx_bandwidth", static_cast(500000))), + Fpass_(configuration->property(role + ".Fpass", static_cast(0.0))), + Fstop_(configuration->property(role + ".Fstop", static_cast(0.0))), + in_stream_(in_stream), + out_stream_(out_stream), + item_size_(sizeof(int8_t)), + enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)), + filter_auto_(configuration->property(role + ".filter_auto", false)), + quadrature_(configuration->property(role + ".quadrature", true)), + rf_dc_(configuration->property(role + ".rf_dc", true)), + bb_dc_(configuration->property(role + ".bb_dc", true)), + rx1_enable_(configuration->property(role + ".rx1_enable", true)), + rx2_enable_(configuration->property(role + ".rx2_enable", true)), + enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), + enable_ovf_check_buffer_monitor_active_(true), + dump_(configuration->property(role + ".dump", false)), +#if USE_GLOG_AND_GFLAGS + rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)) +#else + rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) +#endif +{ + const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || + (configuration->property("Channels_1B.count", 0) > 0)); + const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || + (configuration->property("Channels_L5.count", 0) > 0) || + (configuration->property("Channels_5X.count", 0) > 0)); + + const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1; + if (freq0_ == 0) + { + // use ".freq0" + freq0_ = configuration->property(role + ".freq0", static_cast(GPS_L1_FREQ_HZ)); + } + + if (filter_auto_) + { + filter_source_ = configuration->property(role + ".filter_source", std::string("Auto")); + } + else + { + filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); + } + + switch_fpga = std::make_shared(); + switch_fpga->set_switch_position(switch_to_real_time_mode); + + std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; + + // some basic checks + if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2")) + { + std::cout << "Configuration parameter rf_port_select should take one of these values:\n"; + std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n"; + std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n'; + rf_port_select_ = default_rf_port_select; + LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select; + } + + if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid")) + { + std::cout << "Configuration parameter gain_mode_rx1 should take one of these values:\n"; + std::cout << " manual, slow_attack, fast_attack, hybrid\n"; + std::cout << "Error: provided value gain_mode_rx1=" << gain_mode_rx1_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value gain_mode_rx1=" << default_gain_mode << '\n'; + gain_mode_rx1_ = default_gain_mode; + LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << default_gain_mode; + } + + if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid")) + { + std::cout << "Configuration parameter gain_mode_rx2 should take one of these values:\n"; + std::cout << " manual, slow_attack, fast_attack, hybrid\n"; + std::cout << "Error: provided value gain_mode_rx2=" << gain_mode_rx2_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value gain_mode_rx2=" << default_gain_mode << '\n'; + gain_mode_rx2_ = default_gain_mode; + LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << default_gain_mode; + } + + if (gain_mode_rx1_ == "manual") + { + if (rf_gain_rx1_ > 73.0 || rf_gain_rx1_ < -1.0) + { + std::cout << "Configuration parameter rf_gain_rx1 should take values between -1.0 and 73 dB\n"; + std::cout << "Error: provided value rf_gain_rx1=" << rf_gain_rx1_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value rf_gain_rx1=" << default_manual_gain_rx1 << '\n'; + rf_gain_rx1_ = default_manual_gain_rx1; + LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << default_manual_gain_rx1; + } + } + + if (gain_mode_rx2_ == "manual") + { + if (rf_gain_rx2_ > 73.0 || rf_gain_rx2_ < -1.0) + { + std::cout << "Configuration parameter rf_gain_rx2 should take values between -1.0 and 73 dB\n"; + std::cout << "Error: provided value rf_gain_rx2=" << rf_gain_rx2_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value rf_gain_rx2=" << default_manual_gain_rx2 << '\n'; + rf_gain_rx2_ = default_manual_gain_rx2; + LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << default_manual_gain_rx2; + } + } + + if ((filter_source_ != "Off") && (filter_source_ != "Auto") && (filter_source_ != "File") && (filter_source_ != "Design")) + { + std::cout << "Configuration parameter filter_source should take one of these values:\n"; + std::cout << " Off: Disable filter\n"; + std::cout << " Auto: Use auto-generated filters\n"; + std::cout << " File: User-provided filter in filter_filename parameter\n"; + std::cout << " Design: Create filter from Fpass, Fstop, sampling_frequency and bandwidth parameters\n"; + std::cout << "Error: provided value filter_source=" << filter_source_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value filter_source=Off\n"; + filter_source_ = std::string("Off"); + LOG(WARNING) << "Invalid configuration value for filter_source parameter. Set to filter_source=Off"; + } + + if (bandwidth_ < 200000 || bandwidth_ > 56000000) + { + std::cout << "Configuration parameter bandwidth should take values between 200000 and 56000000 Hz\n"; + std::cout << "Error: provided value bandwidth=" << bandwidth_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value bandwidth=" << default_bandwidth << '\n'; + bandwidth_ = default_bandwidth; + LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << default_bandwidth; + } + + std::cout << "LO frequency : " << freq0_ << " Hz\n"; + try + { + config_ad9361_rx_local(bandwidth_, + sample_rate_, + freq0_, + freq1_, + rf_port_select_, + rx1_enable_, + rx2_enable_, + gain_mode_rx1_, + gain_mode_rx2_, + rf_gain_rx1_, + rf_gain_rx2_, + quadrature_, + rf_dc_, + bb_dc_, + filter_source_, + filter_filename_, + Fpass_, + Fstop_); + } + catch (const std::runtime_error &e) + { + std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n'; + return; + } + // LOCAL OSCILLATOR DDS GENERATOR FOR DUAL FREQUENCY OPERATION + if (enable_dds_lo_ == true) + { + if (tx_bandwidth_ < static_cast(std::floor(static_cast(freq_dds_tx_hz_) * 1.1)) || (tx_bandwidth_ < 200000) || (tx_bandwidth_ > 1000000)) + { + std::cout << "Configuration parameter tx_bandwidth value should be between " << std::max(static_cast(freq_dds_tx_hz_) * 1.1, 200000.0) << " and 1000000 Hz\n"; + std::cout << "Error: provided value tx_bandwidth=" << tx_bandwidth_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value tx_bandwidth=500000\n"; + tx_bandwidth_ = 500000; + LOG(WARNING) << "Invalid configuration value for tx_bandwidth parameter. Set to tx_bandwidth=500000"; + } + if (tx_attenuation_db_ > 0.0 || tx_attenuation_db_ < -89.75) + { + std::cout << "Configuration parameter tx_attenuation_db should take values between 0.0 and -89.95 in 0.25 dB steps\n"; + std::cout << "Error: provided value tx_attenuation_db=" << tx_attenuation_db_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value tx_attenuation_db=" << default_tx_attenuation_db << '\n'; + tx_attenuation_db_ = default_tx_attenuation_db; + LOG(WARNING) << "Invalid configuration value for tx_attenuation_db parameter. Set to tx_attenuation_db=" << default_tx_attenuation_db; + } + try + { + config_ad9361_lo_local(tx_bandwidth_, + sample_rate_, + freq_rf_tx_hz_, + tx_attenuation_db_, + freq_dds_tx_hz_, + scale_dds_dbfs_, + phase_dds_deg_); + } + catch (const std::runtime_error &e) + { + std::cerr << "Exception cached when configuring the TX carrier: " << e.what() << '\n'; + return; + } + } + + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + + buffer_monitor_fpga = std::make_shared(num_freq_bands, dump_, dump_filename); + thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); + + + // dynamic bits selection + if (enable_dynamic_bit_selection_) + { + dynamic_bit_selection_fpga = std::make_shared(enable_rx1_band, enable_rx2_band); + thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); + } + + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +Adrv9361z7035SignalSourceFPGA::~Adrv9361z7035SignalSourceFPGA() +{ + /* cleanup and exit */ + + if (rf_shutdown_) + { + std::cout << "* AD9361 Disabling RX streaming channels\n"; + if (!disable_ad9361_rx_local()) + { + LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; + } + if (enable_dds_lo_) + { + try + { + ad9361_disable_lo_local(); + } + catch (const std::exception &e) + { + LOG(WARNING) << "Problem shutting down the AD9361 TX stream: " << e.what(); + } + } + } + + // disable buffer overflow checking and buffer monitoring + std::unique_lock lock_buffer_monitor(buffer_monitor_mutex); + enable_ovf_check_buffer_monitor_active_ = false; + lock_buffer_monitor.unlock(); + + if (thread_buffer_monitor.joinable()) + { + thread_buffer_monitor.join(); + } + + std::unique_lock lock_dyn_bit_sel(dynamic_bit_selection_mutex); + bool bit_selection_enabled = enable_dynamic_bit_selection_; + lock_dyn_bit_sel.unlock(); + + if (bit_selection_enabled == true) + { + std::unique_lock lock(dynamic_bit_selection_mutex); + enable_dynamic_bit_selection_ = false; + lock.unlock(); + + if (thread_dynamic_bit_selection.joinable()) + { + thread_dynamic_bit_selection.join(); + } + } +} + + +void Adrv9361z7035SignalSourceFPGA::run_dynamic_bit_selection_process() +{ + bool dynamic_bit_selection_active = true; + + while (dynamic_bit_selection_active) + { + // setting the bit selection to the top bits + dynamic_bit_selection_fpga->bit_selection(); + std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); + std::unique_lock lock(dynamic_bit_selection_mutex); + if (enable_dynamic_bit_selection_ == false) + { + dynamic_bit_selection_active = false; + } + lock.unlock(); + } +} + + +void Adrv9361z7035SignalSourceFPGA::run_buffer_monitor_process() +{ + bool enable_ovf_check_buffer_monitor_active = true; + + std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); + + while (enable_ovf_check_buffer_monitor_active) + { + buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); + std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); + std::unique_lock lock(buffer_monitor_mutex); + if (enable_ovf_check_buffer_monitor_active_ == false) + { + enable_ovf_check_buffer_monitor_active = false; + } + lock.unlock(); + } +} + + +void Adrv9361z7035SignalSourceFPGA::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to connect"; +} + + +void Adrv9361z7035SignalSourceFPGA::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; +} + + +gr::basic_block_sptr Adrv9361z7035SignalSourceFPGA::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return {}; +} + + +gr::basic_block_sptr Adrv9361z7035SignalSourceFPGA::get_right_block() +{ + return {}; +} diff --git a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h similarity index 70% rename from src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h rename to src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h index bedd25ad5..5e7e8b7e4 100644 --- a/src/algorithms/signal_source/adapters/ad9361_fpga_signal_source.h +++ b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h @@ -1,7 +1,7 @@ /*! - * \file ad9361_fpga_signal_source.h - * \brief signal source for Analog Devices front-end AD9361 connected directly - * to FPGA accelerators. + * \file adrv9361_z7035_signal_source_fpga.h + * \brief signal source for the Analog Devices ADRV9361-Z7035 evaluation board + * directly connected to the FPGA accelerators. * This source implements only the AD9361 control. It is NOT compatible with * conventional SDR acquisition and tracking blocks. * Please use the fmcomms2 source if conventional SDR acquisition and tracking @@ -12,14 +12,14 @@ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. * This file is part of GNSS-SDR. * - * Copyright (C) 2010-2020 (see AUTHORS file for a list of contributors) + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) * SPDX-License-Identifier: GPL-3.0-or-later * * ----------------------------------------------------------------------------- */ -#ifndef GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H -#define GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H +#ifndef GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H +#define GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H #include "concurrent_queue.h" #include "fpga_buffer_monitor.h" @@ -44,16 +44,14 @@ class ConfigurationInterface; -class Ad9361FpgaSignalSource : public SignalSourceBase +class Adrv9361z7035SignalSourceFPGA : public SignalSourceBase { public: - Ad9361FpgaSignalSource(const ConfigurationInterface *configuration, + Adrv9361z7035SignalSourceFPGA(const ConfigurationInterface *configuration, const std::string &role, unsigned int in_stream, unsigned int out_stream, Concurrent_Queue *queue); - ~Ad9361FpgaSignalSource(); - - void start() override; + ~Adrv9361z7035SignalSourceFPGA(); inline size_t item_size() override { @@ -66,13 +64,9 @@ public: gr::basic_block_sptr get_right_block() override; private: - const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name - const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name - const std::string buffer_monitor_device_name = std::string("buffer_monitor"); // buffer monitor device name const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); const std::string default_rf_port_select = std::string("A_BALANCED"); const std::string default_gain_mode = std::string("slow_attack"); - const std::string empty_string; const double default_tx_attenuation_db = -10.0; const double default_manual_gain_rx1 = 64.0; const double default_manual_gain_rx2 = 64.0; @@ -86,42 +80,27 @@ private: const uint32_t buffer_monitoring_initial_delay_ms = 2000; // sample block size when running in post-processing mode const int sample_block_size = 16384; - - void run_DMA_process(const std::string &filename0, - const std::string &filename1, - uint64_t &samples_to_skip, - size_t &item_size, - int64_t &samples, - bool &repeat, - uint32_t &dma_buff_offset_pos, - Concurrent_Queue *queue); + const int32_t switch_to_real_time_mode = 2; void run_dynamic_bit_selection_process(); void run_buffer_monitor_process(); - std::thread thread_file_to_dma; std::thread thread_dynamic_bit_selection; std::thread thread_buffer_monitor; std::shared_ptr switch_fpga; std::shared_ptr dynamic_bit_selection_fpga; std::shared_ptr buffer_monitor_fpga; - std::shared_ptr dma_fpga; - std::mutex dma_mutex; std::mutex dynamic_bit_selection_mutex; std::mutex buffer_monitor_mutex; - Concurrent_Queue *queue_; - std::string gain_mode_rx1_; std::string gain_mode_rx2_; std::string rf_port_select_; std::string filter_file_; std::string filter_source_; std::string filter_filename_; - std::string filename0_; - std::string filename1_; double rf_gain_rx1_; double rf_gain_rx2_; @@ -133,19 +112,14 @@ private: uint64_t freq1_; // frequency of local oscillator for ADRV9361-B (if present) uint64_t sample_rate_; uint64_t bandwidth_; - uint64_t samples_to_skip_; - int64_t samples_; uint64_t freq_dds_tx_hz_; uint64_t freq_rf_tx_hz_; uint64_t tx_bandwidth_; float Fpass_; float Fstop_; - uint32_t num_input_files_; - uint32_t dma_buff_offset_pos_; uint32_t in_stream_; uint32_t out_stream_; - int32_t switch_position_; size_t item_size_; @@ -156,15 +130,13 @@ private: bool bb_dc_; bool rx1_enable_; bool rx2_enable_; - bool enable_DMA_; bool enable_dynamic_bit_selection_; bool enable_ovf_check_buffer_monitor_active_; bool dump_; bool rf_shutdown_; - bool repeat_; }; /** \} */ /** \} */ -#endif // GNSS_SDR_AD9361_FPGA_SIGNAL_SOURCE_H +#endif // GNSS_SDR_ADRV9361_Z7035_SIGNAL_SOURCE_FPGA_H diff --git a/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc new file mode 100644 index 000000000..6d4f91b03 --- /dev/null +++ b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.cc @@ -0,0 +1,581 @@ +/*! + * \file dma_signal_source_fpga.cc + * \brief signal source for a DMA connected directly to FPGA accelerators. + * This source implements only the DMA control. It is NOT compatible with + * conventional SDR acquisition and tracking blocks. + * \author Marc Majoral, mmajoral(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "dma_signal_source_fpga.h" +#include "command_event.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_string_literals.h" +#include // for std::min +#include // for std::chrono +#include // for open, O_WRONLY +#include // for std::ifstream +#include // for std::setprecision +#include // for std::cout +#include // fr std::vector + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#include +#endif + +using namespace std::string_literals; + +DMASignalSourceFPGA::DMASignalSourceFPGA(const ConfigurationInterface *configuration, + const std::string &role, unsigned int in_stream, unsigned int out_stream, + Concurrent_Queue *queue __attribute__((unused))) + : SignalSourceBase(configuration, role, "DMA_Signal_Source_FPGA"s), + queue_(queue), + filename0_(configuration->property(role + ".filename", empty_string)), + sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), + samples_to_skip_(0), + samples_(configuration->property(role + ".samples", static_cast(0))), + num_input_files_(1), + dma_buff_offset_pos_(0), + in_stream_(in_stream), + out_stream_(out_stream), + item_size_(sizeof(int8_t)), + enable_DMA_(false), + enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), + repeat_(configuration->property(role + ".repeat", false)) +{ + const double seconds_to_skip = configuration->property(role + ".seconds_to_skip", 0.0); + const size_t header_size = configuration->property(role + ".header_size", 0); + + const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || + (configuration->property("Channels_1B.count", 0) > 0)); + const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || + (configuration->property("Channels_L5.count", 0) > 0) || + (configuration->property("Channels_5X.count", 0) > 0)); + +#if USE_GLOG_AND_GFLAGS + // override value with commandline flag, if present + if (FLAGS_signal_source != "-") + { + filename0_ = FLAGS_signal_source; + } + if (FLAGS_s != "-") + { + filename0_ = FLAGS_s; + } +#else + if (absl::GetFlag(FLAGS_signal_source) != "-") + { + filename0_ = absl::GetFlag(FLAGS_signal_source); + } + if (absl::GetFlag(FLAGS_s) != "-") + { + filename0_ = absl::GetFlag(FLAGS_s); + } +#endif + if (filename0_.empty()) + { + num_input_files_ = 2; + filename0_ = configuration->property(role + ".filename0", empty_string); + filename1_ = configuration->property(role + ".filename1", empty_string); + } + // if only one input file is specified in the configuration file then: + // if there is at least one channel assigned to frequency band 1 then the DMA transfers the samples to the L1 frequency band channels + // otherwise the DMA transfers the samples to the L2/L5 frequency band channels + // if more than one input file are specified then the DMA transfer the samples to both the L1 and the L2/L5 frequency channels. + if (filename1_.empty()) + { + if (enable_rx1_band) + { + dma_buff_offset_pos_ = 2; + } + } + else + { + dma_buff_offset_pos_ = 2; + } + + if (seconds_to_skip > 0) + { + samples_to_skip_ = static_cast(seconds_to_skip * sample_rate_) * 2; + } + if (header_size > 0) + { + samples_to_skip_ += header_size; + } + + switch_fpga = std::make_shared(); + switch_fpga->set_switch_position(switch_to_DMA); + + enable_DMA_ = true; + + if (samples_ == 0) // read all file + { + std::ifstream file(filename0_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream::pos_type size; + + if (file.is_open()) + { + size = file.tellg(); + DLOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size_)); + } + else + { + std::cerr << "SignalSource: Unable to open the samples file " << filename0_.c_str() << '\n'; + return; + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(16); + std::cout << "Processing file " << filename0_ << ", which contains " << static_cast(size) << " [bytes]\n"; + std::cout.precision(ss); + + if (size > 0) + { + const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; + const uint64_t bytes_to_process = static_cast(size) - bytes_to_skip; + samples_ = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(sample_rate_))); // process all the samples available in the file excluding at least the last 1 ms + } + + if (!filename1_.empty()) + { + std::ifstream file(filename1_.c_str(), std::ios::in | std::ios::binary | std::ios::ate); + std::ifstream::pos_type size; + + if (file.is_open()) + { + size = file.tellg(); + DLOG(INFO) << "Total samples in the file= " << floor(static_cast(size) / static_cast(item_size_)); + } + else + { + std::cerr << "SignalSource: Unable to open the samples file " << filename1_.c_str() << '\n'; + return; + } + std::streamsize ss = std::cout.precision(); + std::cout << std::setprecision(16); + std::cout << "Processing file " << filename1_ << ", which contains " << static_cast(size) << " [bytes]\n"; + std::cout.precision(ss); + + int64_t samples_rx2 = 0; + if (size > 0) + { + const uint64_t bytes_to_skip = samples_to_skip_ * item_size_; + const uint64_t bytes_to_process = static_cast(size) - bytes_to_skip; + samples_rx2 = floor(static_cast(bytes_to_process) / static_cast(item_size_) - ceil(0.002 * static_cast(sample_rate_))); // process all the samples available in the file excluding at least the last 1 ms + } + samples_ = std::min(samples_, samples_rx2); + } + } + + CHECK(samples_ > 0) << "File does not contain enough samples to process."; + double signal_duration_s = (static_cast(samples_) * (1 / static_cast(sample_rate_))) / 2.0; + + DLOG(INFO) << "Total number samples to be processed= " << samples_ << " GNSS signal duration= " << signal_duration_s << " [s]"; + std::cout << "GNSS signal recorded time to be processed: " << signal_duration_s << " [s]\n"; + + if (filename1_.empty()) + { + DLOG(INFO) << "File source filename " << filename0_; + } + else + { + DLOG(INFO) << "File source filename rx1 " << filename0_; + DLOG(INFO) << "File source filename rx2 " << filename1_; + } + DLOG(INFO) << "Samples " << samples_; + DLOG(INFO) << "Sampling frequency " << sample_rate_; + DLOG(INFO) << "Item type " << std::string("ibyte"); + DLOG(INFO) << "Item size " << item_size_; + DLOG(INFO) << "Repeat " << repeat_; + // } + + // dynamic bits selection + if (enable_dynamic_bit_selection_) + { + dynamic_bit_selection_fpga = std::make_shared(enable_rx1_band, enable_rx2_band); + thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); + } + + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +DMASignalSourceFPGA::~DMASignalSourceFPGA() +{ + std::unique_lock lock_DMA(dma_mutex); + enable_DMA_ = false; // disable the DMA + lock_DMA.unlock(); + if (thread_file_to_dma.joinable()) + { + thread_file_to_dma.join(); + } + + std::unique_lock lock_dyn_bit_sel(dynamic_bit_selection_mutex); + bool bit_selection_enabled = enable_dynamic_bit_selection_; + lock_dyn_bit_sel.unlock(); + + if (bit_selection_enabled == true) + { + std::unique_lock lock(dynamic_bit_selection_mutex); + enable_dynamic_bit_selection_ = false; + lock.unlock(); + + if (thread_dynamic_bit_selection.joinable()) + { + thread_dynamic_bit_selection.join(); + } + } +} + + +void DMASignalSourceFPGA::start() +{ + thread_file_to_dma = std::thread([&] { run_DMA_process(filename0_, filename1_, samples_to_skip_, item_size_, samples_, repeat_, dma_buff_offset_pos_, queue_); }); +} + + +void DMASignalSourceFPGA::run_DMA_process(const std::string &filename0_, const std::string &filename1_, uint64_t &samples_to_skip, size_t &item_size, int64_t &samples, bool &repeat, uint32_t &dma_buff_offset_pos, Concurrent_Queue *queue) +{ + std::ifstream infile1; + infile1.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + + // FPGA DMA control + dma_fpga = std::make_shared(); + + // open the files + try + { + infile1.open(filename0_, std::ios::binary); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception opening file " << filename0_ << '\n'; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + + std::ifstream infile2; + if (!filename1_.empty()) + { + infile2.exceptions(std::ifstream::failbit | std::ifstream::badbit); + try + { + infile2.open(filename1_, std::ios::binary); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception opening file " << filename1_ << '\n'; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + } + + // skip the initial samples if needed + uint64_t bytes_to_skeep = samples_to_skip * item_size; + try + { + infile1.ignore(bytes_to_skeep); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception skipping initial samples file " << filename0_ << '\n'; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + + if (!filename1_.empty()) + { + try + { + infile2.ignore(bytes_to_skeep); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception skipping initial samples file " << filename1_ << '\n'; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + } + + // rx signal vectors + std::vector input_samples(sample_block_size * 2); // complex samples + // pointer to DMA buffer + int8_t *dma_buffer; + int nread_elements = 0; // num bytes read from the file corresponding to frequency band 1 + bool run_DMA = true; + + // Open DMA device + if (dma_fpga->DMA_open()) + { + std::cerr << "Cannot open loop device\n"; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + dma_buffer = dma_fpga->get_buffer_address(); + + // if only one frequency band is used then clear the samples corresponding to the unused frequency band + uint32_t dma_index = 0; + if (num_input_files_ == 1) + { + // if only one file is enabled then clear the samples corresponding to the frequency band that is not used. + for (int index0 = 0; index0 < (nread_elements); index0 += 2) + { + dma_buffer[dma_index + (2 - dma_buff_offset_pos)] = 0; + dma_buffer[dma_index + 1 + (2 - dma_buff_offset_pos)] = 0; + dma_index += 4; + } + } + + uint64_t nbytes_remaining = samples * item_size; + uint32_t read_buffer_size = sample_block_size * 2; // complex samples + + // run the DMA + while (run_DMA) + { + dma_index = 0; + if (nbytes_remaining < read_buffer_size) + { + read_buffer_size = nbytes_remaining; + } + nbytes_remaining = nbytes_remaining - read_buffer_size; + + // read filename 0 + try + { + infile1.read(reinterpret_cast(input_samples.data()), read_buffer_size); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception reading file " << filename0_ << '\n'; + break; + } + if (infile1) + { + nread_elements = read_buffer_size; + } + else + { + // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN + nread_elements = infile1.gcount(); + } + + for (int index0 = 0; index0 < (nread_elements); index0 += 2) + { + // dma_buff_offset_pos is 1 for the L1 band and 0 for the other bands + dma_buffer[dma_index + dma_buff_offset_pos] = input_samples[index0]; + dma_buffer[dma_index + 1 + dma_buff_offset_pos] = input_samples[index0 + 1]; + dma_index += 4; + } + + // read filename 1 (if enabled) + if (num_input_files_ > 1) + { + dma_index = 0; + try + { + infile2.read(reinterpret_cast(input_samples.data()), read_buffer_size); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception reading file " << filename1_ << '\n'; + break; + } + if (infile2) + { + nread_elements = read_buffer_size; + } + else + { + // FLAG AS ERROR !! IT SHOULD NEVER HAPPEN + nread_elements = infile2.gcount(); + } + + for (int index0 = 0; index0 < (nread_elements); index0 += 2) + { + // filename2 is never the L1 band + dma_buffer[dma_index] = input_samples[index0]; + dma_buffer[dma_index + 1] = input_samples[index0 + 1]; + dma_index += 4; + } + } + + if (nread_elements > 0) + { + if (dma_fpga->DMA_write(nread_elements * 2)) + { + std::cerr << "Error: DMA could not send all the required samples\n"; + break; + } + // Throttle the DMA + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + if (nbytes_remaining == 0) + { + if (repeat) + { + // read the file again + nbytes_remaining = samples * item_size; + read_buffer_size = sample_block_size * 2; + try + { + infile1.seekg(0); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception resetting the position of the next byte to be extracted to zero " << filename0_ << '\n'; + break; + } + + // skip the initial samples if needed + uint64_t bytes_to_skeep = samples_to_skip * item_size; + try + { + infile1.ignore(bytes_to_skeep); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception skipping initial samples file " << filename0_ << '\n'; + break; + } + + if (!filename1_.empty()) + { + try + { + infile2.seekg(0); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception setting the position of the next byte to be extracted to zero " << filename1_ << '\n'; + break; + } + + try + { + infile2.ignore(bytes_to_skeep); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception skipping initial samples file " << filename1_ << '\n'; + break; + } + } + } + else + { + // the input file is completely processed. Stop the receiver. + run_DMA = false; + } + } + std::unique_lock lock_DMA(dma_mutex); + if (enable_DMA_ == false) + { + run_DMA = false; + } + lock_DMA.unlock(); + } + + if (dma_fpga->DMA_close()) + { + std::cerr << "Error closing loop device " << '\n'; + } + try + { + infile1.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception closing file " << filename0_ << '\n'; + } + + if (num_input_files_ > 1) + { + try + { + infile2.close(); + } + catch (const std::ifstream::failure &e) + { + std::cerr << "Exception closing file " << filename1_ << '\n'; + } + } + + // Stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); +} + + +void DMASignalSourceFPGA::run_dynamic_bit_selection_process() +{ + bool dynamic_bit_selection_active = true; + + while (dynamic_bit_selection_active) + { + // setting the bit selection to the top bits + dynamic_bit_selection_fpga->bit_selection(); + std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); + std::unique_lock lock_dyn_bit_sel(dynamic_bit_selection_mutex); + if (enable_dynamic_bit_selection_ == false) + { + dynamic_bit_selection_active = false; + } + lock_dyn_bit_sel.unlock(); + } +} + + +void DMASignalSourceFPGA::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to connect"; +} + + +void DMASignalSourceFPGA::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; +} + + +gr::basic_block_sptr DMASignalSourceFPGA::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return {}; +} + + +gr::basic_block_sptr DMASignalSourceFPGA::get_right_block() +{ + return {}; +} diff --git a/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h new file mode 100644 index 000000000..efbad3b23 --- /dev/null +++ b/src/algorithms/signal_source/adapters/dma_signal_source_fpga.h @@ -0,0 +1,118 @@ +/*! + * \file dma_signal_source_fpga.h + * \brief signal source for a DMA connected directly to FPGA accelerators. + * This source implements only the DMA control. It is NOT compatible with + * conventional SDR acquisition and tracking blocks. + * \author Marc Majoral, mmajoral(at)cttc.es + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_DMA_SIGNAL_SOURCE_FPGA_H +#define GNSS_SDR_DMA_SIGNAL_SOURCE_FPGA_H + +#include "concurrent_queue.h" +#include "fpga_dma-proxy.h" +#include "fpga_dynamic_bit_selection.h" +#include "fpga_switch.h" +#include "gnss_block_interface.h" +#include "signal_source_base.h" +#include +#include +#include +#include +#include +#include + + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_adapters + * \{ */ + + +class ConfigurationInterface; + +class DMASignalSourceFPGA : public SignalSourceBase +{ +public: + DMASignalSourceFPGA(const ConfigurationInterface *configuration, + const std::string &role, unsigned int in_stream, + unsigned int out_stream, Concurrent_Queue *queue); + + ~DMASignalSourceFPGA(); + + void start() override; + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name + const std::string empty_string; + const uint64_t default_bandwidth = 12500000; + // perform dynamic bit selection every 500 ms by default + const uint32_t Gain_control_period_ms = 500; + // sample block size when running in post-processing mode + const int sample_block_size = 16384; + const int32_t switch_to_DMA = 0; + + void run_DMA_process(const std::string &filename0, + const std::string &filename1, + uint64_t &samples_to_skip, + size_t &item_size, + int64_t &samples, + bool &repeat, + uint32_t &dma_buff_offset_pos, + Concurrent_Queue *queue); + + void run_dynamic_bit_selection_process(); + + std::thread thread_file_to_dma; + std::thread thread_dynamic_bit_selection; + + std::shared_ptr switch_fpga; + std::shared_ptr dynamic_bit_selection_fpga; + std::shared_ptr dma_fpga; + + std::mutex dma_mutex; + std::mutex dynamic_bit_selection_mutex; + + Concurrent_Queue *queue_; + + std::string filename0_; + std::string filename1_; + + uint64_t sample_rate_; + uint64_t samples_to_skip_; + int64_t samples_; + uint32_t num_input_files_; + uint32_t dma_buff_offset_pos_; + uint32_t in_stream_; + uint32_t out_stream_; + size_t item_size_; + + bool enable_DMA_; + bool enable_dynamic_bit_selection_; + bool repeat_; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_DMA_SIGNAL_SOURCE_FPGA_H diff --git a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc new file mode 100644 index 000000000..d8c5a65c0 --- /dev/null +++ b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc @@ -0,0 +1,347 @@ +/*! + * \file fmcomms5_signal_source_fpga.cc + * \brief signal source for the Analog Devices FMCOMMS5 directly connected + * to the FPGA accelerators. + * This source implements only the AD9361 control. It is NOT compatible with + * conventional SDR acquisition and tracking blocks. + * Please use the fmcomms2 source if conventional SDR acquisition and tracking + * is selected in the configuration file. + * \authors
    + *
  • Javier Arribas, jarribas(at)cttc.es + *
  • Marc Majoral, mmajoral(at)cttc.es + *
+ * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "fmcomms5_signal_source_fpga.h" +#include "GPS_L1_CA.h" +#include "GPS_L5.h" +#include "ad9361_manager.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_string_literals.h" +#include // for std::max +#include // for std::chrono +#include // for std::floor +#include // for std::exception +#include // for std::cout + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#include +#endif + +using namespace std::string_literals; + +Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface *configuration, + const std::string &role, unsigned int in_stream, unsigned int out_stream, + Concurrent_Queue *queue __attribute__((unused))) + : SignalSourceBase(configuration, role, "FMCOMMS5_Signal_Source_FPGA"s), + gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), + gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), + rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), + filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), + rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), + rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), + freq0_(configuration->property(role + ".freq0", static_cast(GPS_L1_FREQ_HZ))), + freq1_(configuration->property(role + ".freq1", static_cast(GPS_L5_FREQ_HZ))), + sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), + bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), + Fpass_(configuration->property(role + ".Fpass", static_cast(0.0))), + Fstop_(configuration->property(role + ".Fstop", static_cast(0.0))), + in_stream_(in_stream), + out_stream_(out_stream), + item_size_(sizeof(int8_t)), + filter_auto_(configuration->property(role + ".filter_auto", false)), + quadrature_(configuration->property(role + ".quadrature", true)), + rf_dc_(configuration->property(role + ".rf_dc", true)), + bb_dc_(configuration->property(role + ".bb_dc", true)), + rx1_enable_(configuration->property(role + ".rx1_enable", true)), + rx2_enable_(configuration->property(role + ".rx2_enable", true)), + enable_dynamic_bit_selection_(configuration->property(role + ".enable_dynamic_bit_selection", true)), + enable_ovf_check_buffer_monitor_active_(true), + dump_(configuration->property(role + ".dump", false)), +#if USE_GLOG_AND_GFLAGS + rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)) +#else + rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) +#endif +{ + const bool enable_rx1_band((configuration->property("Channels_1C.count", 0) > 0) || + (configuration->property("Channels_1B.count", 0) > 0)); + const bool enable_rx2_band((configuration->property("Channels_L2.count", 0) > 0) || + (configuration->property("Channels_L5.count", 0) > 0) || + (configuration->property("Channels_5X.count", 0) > 0)); + + const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1; + + if (filter_auto_) + { + filter_source_ = configuration->property(role + ".filter_source", std::string("Auto")); + } + else + { + filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); + } + + switch_fpga = std::make_shared(); + switch_fpga->set_switch_position(switch_to_real_time_mode); + + std::cout << "Sample rate: " << sample_rate_ << " Sps\n"; + + // some basic checks + if ((rf_port_select_ != "A_BALANCED") && (rf_port_select_ != "B_BALANCED") && (rf_port_select_ != "A_N") && (rf_port_select_ != "B_N") && (rf_port_select_ != "B_P") && (rf_port_select_ != "C_N") && (rf_port_select_ != "C_P") && (rf_port_select_ != "TX_MONITOR1") && (rf_port_select_ != "TX_MONITOR2") && (rf_port_select_ != "TX_MONITOR1_2")) + { + std::cout << "Configuration parameter rf_port_select should take one of these values:\n"; + std::cout << " A_BALANCED, B_BALANCED, A_N, B_N, B_P, C_N, C_P, TX_MONITOR1, TX_MONITOR2, TX_MONITOR1_2\n"; + std::cout << "Error: provided value rf_port_select=" << rf_port_select_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value rf_port_select=" << default_rf_port_select << '\n'; + rf_port_select_ = default_rf_port_select; + LOG(WARNING) << "Invalid configuration value for rf_port_select parameter. Set to rf_port_select=" << default_rf_port_select; + } + + if ((gain_mode_rx1_ != "manual") && (gain_mode_rx1_ != "slow_attack") && (gain_mode_rx1_ != "fast_attack") && (gain_mode_rx1_ != "hybrid")) + { + std::cout << "Configuration parameter gain_mode_rx1 should take one of these values:\n"; + std::cout << " manual, slow_attack, fast_attack, hybrid\n"; + std::cout << "Error: provided value gain_mode_rx1=" << gain_mode_rx1_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value gain_mode_rx1=" << default_gain_mode << '\n'; + gain_mode_rx1_ = default_gain_mode; + LOG(WARNING) << "Invalid configuration value for gain_mode_rx1 parameter. Set to gain_mode_rx1=" << default_gain_mode; + } + + if ((gain_mode_rx2_ != "manual") && (gain_mode_rx2_ != "slow_attack") && (gain_mode_rx2_ != "fast_attack") && (gain_mode_rx2_ != "hybrid")) + { + std::cout << "Configuration parameter gain_mode_rx2 should take one of these values:\n"; + std::cout << " manual, slow_attack, fast_attack, hybrid\n"; + std::cout << "Error: provided value gain_mode_rx2=" << gain_mode_rx2_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value gain_mode_rx2=" << default_gain_mode << '\n'; + gain_mode_rx2_ = default_gain_mode; + LOG(WARNING) << "Invalid configuration value for gain_mode_rx2 parameter. Set to gain_mode_rx2=" << default_gain_mode; + } + + if (gain_mode_rx1_ == "manual") + { + if (rf_gain_rx1_ > 73.0 || rf_gain_rx1_ < -1.0) + { + std::cout << "Configuration parameter rf_gain_rx1 should take values between -1.0 and 73 dB\n"; + std::cout << "Error: provided value rf_gain_rx1=" << rf_gain_rx1_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value rf_gain_rx1=" << default_manual_gain_rx1 << '\n'; + rf_gain_rx1_ = default_manual_gain_rx1; + LOG(WARNING) << "Invalid configuration value for rf_gain_rx1 parameter. Set to rf_gain_rx1=" << default_manual_gain_rx1; + } + } + + if (gain_mode_rx2_ == "manual") + { + if (rf_gain_rx2_ > 73.0 || rf_gain_rx2_ < -1.0) + { + std::cout << "Configuration parameter rf_gain_rx2 should take values between -1.0 and 73 dB\n"; + std::cout << "Error: provided value rf_gain_rx2=" << rf_gain_rx2_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value rf_gain_rx2=" << default_manual_gain_rx2 << '\n'; + rf_gain_rx2_ = default_manual_gain_rx2; + LOG(WARNING) << "Invalid configuration value for rf_gain_rx2 parameter. Set to rf_gain_rx2=" << default_manual_gain_rx2; + } + } + + if ((filter_source_ != "Off") && (filter_source_ != "Auto") && (filter_source_ != "File") && (filter_source_ != "Design")) + { + std::cout << "Configuration parameter filter_source should take one of these values:\n"; + std::cout << " Off: Disable filter\n"; + std::cout << " Auto: Use auto-generated filters\n"; + std::cout << " File: User-provided filter in filter_filename parameter\n"; + std::cout << " Design: Create filter from Fpass, Fstop, sampling_frequency and bandwidth parameters\n"; + std::cout << "Error: provided value filter_source=" << filter_source_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value filter_source=Off\n"; + filter_source_ = std::string("Off"); + LOG(WARNING) << "Invalid configuration value for filter_source parameter. Set to filter_source=Off"; + } + + if (bandwidth_ < 200000 || bandwidth_ > 56000000) + { + std::cout << "Configuration parameter bandwidth should take values between 200000 and 56000000 Hz\n"; + std::cout << "Error: provided value bandwidth=" << bandwidth_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value bandwidth=" << default_bandwidth << '\n'; + bandwidth_ = default_bandwidth; + LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth=" << default_bandwidth; + } + + if (enable_rx1_band) + { + std::cout << "LO 0 frequency : " << freq0_ << " Hz\n"; + } + if (enable_rx2_band) + { + std::cout << "LO 1 frequency : " << freq1_ << " Hz\n"; + } + try + { + config_ad9361_rx_local(bandwidth_, + sample_rate_, + freq0_, + freq1_, + rf_port_select_, + rx1_enable_, + rx2_enable_, + gain_mode_rx1_, + gain_mode_rx2_, + rf_gain_rx1_, + rf_gain_rx2_, + quadrature_, + rf_dc_, + bb_dc_, + filter_source_, + filter_filename_, + Fpass_, + Fstop_); + } + catch (const std::runtime_error &e) + { + std::cerr << "Exception cached when configuring the RX chain: " << e.what() << '\n'; + return; + } + + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + + buffer_monitor_fpga = std::make_shared(num_freq_bands, dump_, dump_filename); + thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); + + + // dynamic bits selection + if (enable_dynamic_bit_selection_) + { + dynamic_bit_selection_fpga = std::make_shared(enable_rx1_band, enable_rx2_band); + thread_dynamic_bit_selection = std::thread([&] { run_dynamic_bit_selection_process(); }); + } + + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + + +Fmcomms5SignalSourceFPGA::~Fmcomms5SignalSourceFPGA() +{ + /* cleanup and exit */ + + if (rf_shutdown_) + { + std::cout << "* Disabling RX streaming channels\n"; + if (!disable_ad9361_rx_local()) + { + LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; + } + } + + // disable buffer overflow checking and buffer monitoring + std::unique_lock lock_buffer_monitor(buffer_monitor_mutex); + enable_ovf_check_buffer_monitor_active_ = false; + lock_buffer_monitor.unlock(); + + if (thread_buffer_monitor.joinable()) + { + thread_buffer_monitor.join(); + } + + std::unique_lock lock_dyn_bit_sel(dynamic_bit_selection_mutex); + bool bit_selection_enabled = enable_dynamic_bit_selection_; + lock_dyn_bit_sel.unlock(); + + if (bit_selection_enabled == true) + { + std::unique_lock lock(dynamic_bit_selection_mutex); + enable_dynamic_bit_selection_ = false; + lock.unlock(); + + if (thread_dynamic_bit_selection.joinable()) + { + thread_dynamic_bit_selection.join(); + } + } +} + + +void Fmcomms5SignalSourceFPGA::run_dynamic_bit_selection_process() +{ + bool dynamic_bit_selection_active = true; + + while (dynamic_bit_selection_active) + { + // setting the bit selection to the top bits + dynamic_bit_selection_fpga->bit_selection(); + std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); + std::unique_lock lock(dynamic_bit_selection_mutex); + if (enable_dynamic_bit_selection_ == false) + { + dynamic_bit_selection_active = false; + } + lock.unlock(); + } +} + + +void Fmcomms5SignalSourceFPGA::run_buffer_monitor_process() +{ + bool enable_ovf_check_buffer_monitor_active = true; + + std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); + + while (enable_ovf_check_buffer_monitor_active) + { + buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); + std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); + std::unique_lock lock(buffer_monitor_mutex); + if (enable_ovf_check_buffer_monitor_active_ == false) + { + enable_ovf_check_buffer_monitor_active = false; + } + lock.unlock(); + } +} + + +void Fmcomms5SignalSourceFPGA::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to connect"; +} + + +void Fmcomms5SignalSourceFPGA::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; +} + + +gr::basic_block_sptr Fmcomms5SignalSourceFPGA::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return {}; +} + + +gr::basic_block_sptr Fmcomms5SignalSourceFPGA::get_right_block() +{ + return {}; +} diff --git a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h new file mode 100644 index 000000000..1bdcf4e6f --- /dev/null +++ b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h @@ -0,0 +1,135 @@ +/*! + * \file fmcomms5_signal_source_fpga.h + * \brief signal source for the Analog Devices FMCOMMS5 directly connected + * to the FPGA accelerators. + * This source implements only the AD9361 control. It is NOT compatible with + * conventional SDR acquisition and tracking blocks. + * Please use the fmcomms2 source if conventional SDR acquisition and tracking + * is selected in the configuration file. + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_FMCOMMS5_SIGNAL_SOURCE_FPGA_H +#define GNSS_SDR_FMCOMMS5_SIGNAL_SOURCE_FPGA_H + +#include "concurrent_queue.h" +#include "fpga_buffer_monitor.h" +#include "fpga_dma-proxy.h" +#include "fpga_dynamic_bit_selection.h" +#include "fpga_switch.h" +#include "gnss_block_interface.h" +#include "signal_source_base.h" +#include +#include +#include +#include +#include +#include + + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_adapters + * \{ */ + + +class ConfigurationInterface; + +class Fmcomms5SignalSourceFPGA : public SignalSourceBase +{ +public: + Fmcomms5SignalSourceFPGA(const ConfigurationInterface *configuration, + const std::string &role, unsigned int in_stream, + unsigned int out_stream, Concurrent_Queue *queue); + + ~Fmcomms5SignalSourceFPGA(); + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); + const std::string default_rf_port_select = std::string("A_BALANCED"); + const std::string default_gain_mode = std::string("slow_attack"); + const double default_tx_attenuation_db = -10.0; + const double default_manual_gain_rx1 = 64.0; + const double default_manual_gain_rx2 = 64.0; + const uint64_t default_bandwidth = 12500000; + + // perform dynamic bit selection every 500 ms by default + const uint32_t Gain_control_period_ms = 500; + // check buffer overflow and perform buffer monitoring every 1s by default + const uint32_t buffer_monitor_period_ms = 1000; + // buffer overflow and buffer monitoring initial delay + const uint32_t buffer_monitoring_initial_delay_ms = 2000; + // sample block size when running in post-processing mode + const int sample_block_size = 16384; + const int32_t switch_to_real_time_mode = 2; + + void run_dynamic_bit_selection_process(); + void run_buffer_monitor_process(); + + std::thread thread_dynamic_bit_selection; + std::thread thread_buffer_monitor; + + std::shared_ptr switch_fpga; + std::shared_ptr dynamic_bit_selection_fpga; + std::shared_ptr buffer_monitor_fpga; + + std::mutex dynamic_bit_selection_mutex; + std::mutex buffer_monitor_mutex; + + std::string gain_mode_rx1_; + std::string gain_mode_rx2_; + std::string rf_port_select_; + std::string filter_file_; + std::string filter_source_; + std::string filter_filename_; + + double rf_gain_rx1_; + double rf_gain_rx2_; + + uint64_t freq0_; // frequency of local oscillator for ADRV9361-A + uint64_t freq1_; // frequency of local oscillator for ADRV9361-B + uint64_t sample_rate_; + uint64_t bandwidth_; + + float Fpass_; + float Fstop_; + uint32_t in_stream_; + uint32_t out_stream_; + + size_t item_size_; + + bool filter_auto_; + bool quadrature_; + bool rf_dc_; + bool bb_dc_; + bool rx1_enable_; + bool rx2_enable_; + bool enable_dynamic_bit_selection_; + bool enable_ovf_check_buffer_monitor_active_; + bool dump_; + bool rf_shutdown_; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_FMCOMMS5_SIGNAL_SOURCE_FPGA_H diff --git a/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc new file mode 100644 index 000000000..788b50e77 --- /dev/null +++ b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc @@ -0,0 +1,467 @@ +/*! + * \file max2771_evkit_signal_source_fpga.cc + * \brief Signal source for the MAX2771EVKIT evaluation board connected directly + * to FPGA accelerators. + * This source implements only the MAX2771 control. It is NOT compatible with + * conventional SDR acquisition and tracking blocks. + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "max2771_evkit_signal_source_fpga.h" +#include "GPS_L1_CA.h" +#include "GPS_L2C.h" +#include "GPS_L5.h" +#include "configuration_interface.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_string_literals.h" +#include // for std::max +#include // for std::chrono +#include // for std::floor +#include // for std::exception +#include // for std::cout +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#include +#endif + +using namespace std::string_literals; + +MAX2771EVKITSignalSourceFPGA::MAX2771EVKITSignalSourceFPGA(const ConfigurationInterface *configuration, + const std::string &role, unsigned int in_stream, unsigned int out_stream, + Concurrent_Queue *queue __attribute__((unused))) + : SignalSourceBase(configuration, role, "MAX2771_EVKIT_Signal_Source_FPGA"s), + freq_(configuration->property(role + ".freq", static_cast(GPS_L1_FREQ_HZ))), + sample_rate_(configuration->property(role + ".sampling_frequency", default_sampling_rate)), + in_stream_(in_stream), + out_stream_(out_stream), + bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), + filter_order_(configuration->property(role + ".filter_order", default_filter_order)), + gain_in_(configuration->property(role + ".PGA_gain", default_PGA_gain_value)), + item_size_(sizeof(int8_t)), + chipen_(true), + if_filter_gain_(configuration->property(role + ".enable_IF_filter_gain", true)), + LNA_active_(configuration->property(role + ".LNA_active", false)), + enable_agc_(configuration->property(role + ".enable_AGC", true)), + enable_ovf_check_buffer_monitor_active_(true), + dump_(configuration->property(role + ".dump", false)), +#if USE_GLOG_AND_GFLAGS + rf_shutdown_(configuration->property(role + ".rf_shutdown", FLAGS_rf_shutdown)) +#else + rf_shutdown_(configuration->property(role + ".rf_shutdown", absl::GetFlag(FLAGS_rf_shutdown))) +#endif +{ + // some basic checks + if (freq_ != GPS_L1_FREQ_HZ and freq_ != GPS_L2_FREQ_HZ and freq_ != GPS_L5_FREQ_HZ) + { + std::cout << "Configuration parameter freq should take values " << GPS_L1_FREQ_HZ << ", " << GPS_L2_FREQ_HZ << ", or " << GPS_L5_FREQ_HZ << "\n"; + std::cout << "Error: provided value freq = " << freq_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value freq = " << GPS_L1_FREQ_HZ << '\n'; + LOG(WARNING) << "Invalid configuration value for freq parameter. Set to freq = " << GPS_L1_FREQ_HZ; + freq_ = GPS_L1_FREQ_HZ; + } + if (sample_rate_ != 4092000 and sample_rate_ != 8184000 and sample_rate_ != 16368000 and sample_rate_ != 32736000) + { + std::cout << "Configuration parameter sampling_frequency should take values 4092000, 8184000, 16368000, or 32736000\n"; + std::cout << "Error: provided value sampling_frequency = " << sample_rate_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value sampling_frequency = " << default_sampling_rate << '\n'; + LOG(WARNING) << "Invalid configuration value for sampling_frequency parameter. Set to sampling_frequency = " << default_sampling_rate; + sample_rate_ = default_sampling_rate; + } + if (bandwidth_ != 2500000 and bandwidth_ != 4200000 and bandwidth_ != 8700000 and bandwidth_ != 16400000 and bandwidth_ != 23400000 and bandwidth_ != 36000000) + { + std::cout << "Configuration parameter bandwidth can only take the following values: 2500000, 4200000, 8700000, 16400000, 23400000, and 36000000 Hz\n"; + std::cout << "Error: provided value bandwidth = " << bandwidth_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value bandwidth = " << default_bandwidth << '\n'; + LOG(WARNING) << "Invalid configuration value for bandwidth parameter. Set to bandwidth = " << default_bandwidth; + bandwidth_ = default_bandwidth; + } + if (filter_order_ != 3 and filter_order_ != 5) + { + std::cout << "Configuration parameter filter_order should take values 3 or 5\n"; + std::cout << "Error: provided value filter_order = " << filter_order_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value filter_order = " << default_filter_order << '\n'; + LOG(WARNING) << "Invalid configuration value for filter_order parameter. Set to filter_order = " << default_filter_order; + filter_order_ = default_filter_order; + } + if (gain_in_ > max_PGA_gain_value) + { + std::cout << "Configuration parameter PGA_gain should be up to " << max_PGA_gain_value << "\n"; + std::cout << "Error: provided value PGA_gain = " << gain_in_ << " is not among valid values\n"; + std::cout << " This parameter has been set to its default value PGA_gain = " << default_PGA_gain_value << '\n'; + LOG(WARNING) << "Invalid configuration value for PGA_gain parameter. Set to PGA_gain = " << default_PGA_gain_value; + gain_in_ = default_PGA_gain_value; + } + + std::vector register_values = setup_regs(); + + spidev_fpga = std::make_shared(); + + if (spidev_fpga->SPI_open()) + { + std::cerr << "Cannot open SPI device\n"; + // stop the receiver + queue->push(pmt::make_any(command_event_make(200, 0))); + return; + } + + if (configure(register_values)) + { + std::cerr << "Error configuring the MAX2771 device " << '\n'; + } + + if (spidev_fpga->SPI_close()) + { + std::cerr << "Error closing SPI device " << '\n'; + } + + std::string dump_filename = configuration->property(role + ".dump_filename", default_dump_filename); + + buffer_monitor_fpga = std::make_shared(NUM_FREQ_BANDS, dump_, dump_filename); + thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); + + if (in_stream_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_stream_ > 1) + { + LOG(ERROR) << "This implementation only supports one output stream"; + } +} + +std::vector MAX2771EVKITSignalSourceFPGA::setup_regs(void) +{ + std::vector register_values = std::vector(MAX2771_NUM_REGS); + + + uint32_t LNA_mode = (LNA_active_) ? 0x0 : 0x2; + + uint32_t Filter_Bandwidth; + + switch (bandwidth_) + { + case 2500000: + Filter_Bandwidth = 0x0; + break; + case 4200000: + Filter_Bandwidth = 0x2; + break; + case 8700000: + Filter_Bandwidth = 0x1; + break; + case 16400000: + Filter_Bandwidth = 0x7; + break; + case 23400000: + Filter_Bandwidth = 0x3; + break; + case 36000000: + Filter_Bandwidth = 0x4; + break; + default: + Filter_Bandwidth = 0x0; // default bandwidth + } + + uint32_t chipen_select = (chipen_) ? 0x1 : 0x0; + uint32_t Filter_order_sel = (filter_order_ == 5) ? 0x0 : 0x1; + uint32_t IF_filter_gain_sel = (if_filter_gain_) ? 0x1 : 0x0; + + register_values[0] = // configuration 1 register + (chipen_select << 31) + + (IDLE << 30) + + (0x8 << 26) + // reserved + (0x8 << 22) + // reserved + (0x2 << 20) + // reserved + (0x1 << 18) + // reserved + (MIXPOLE << 17) + + (LNA_mode << 15) + + (MIXERMODE << 13) + + (FCEN << 6) + + (Filter_Bandwidth << 3) + + (Filter_order_sel << 2) + + (FCENX << 1) + + IF_filter_gain_sel; + + uint32_t AGC_mode = (enable_agc_) ? 0x0 : 0x2; + + register_values[1] = // configuration 2 register + (0x0 << 31) + // reserved + (0x1 << 29) + // reserved + (ANAIMON << 28) + + (IQEN << 27) + + (GAINREF << 15) + + (SPI_SDIO_CONFIG << 13) + + (AGC_mode << 11) + + (FORMAT << 9) + + (BITS << 6) + + (DRVCFG << 4) + + (0x1 << 3) + // reserved + (0x0 << 2) + // reserved + DIEID; + + register_values[2] = // configuration 3 register + (0x0 << 28) + // reserved + (gain_in_ << 22) + + (0x1 << 21) + // reserved + (HILOADEN << 20) + + (0x1 << 19) + // reserved + (0x1 << 18) + // reserved + (0x1 << 17) + // reserved + (0x1 << 16) + // reserved + (FHIPEN << 15) + + (0x0 << 14) + // reserved + (PGAIEN << 13) + + (PGAQEN << 12) + + (STRMEN << 11) + + (STRMSTART << 10) + + (STRMSTOP << 9) + + (0x7 << 6) + // reserved + (STRMBITS << 4) + + (STAMPEN << 3) + + (TIMESYNCEN << 2) + + (DATASYNCEN << 1) + + STRMRST; + + uint32_t clock_out_div_ratio; + + switch (sample_rate_) + { + case 4092000: + clock_out_div_ratio = 0x1; // XTAL frequency /4 + break; + case 8184000: + clock_out_div_ratio = 0x2; // XTAL frequency /2 + break; + case 16368000: + clock_out_div_ratio = 0x3; // XTAL frequency + break; + case 32736000: + clock_out_div_ratio = 0x0; // XTAL Frequency x2 + break; + default: + clock_out_div_ratio = 0x1; // default XTAL frequency + } + + register_values[3] = // PLL configuration register + (clock_out_div_ratio << 29) + + (LOBAND << 28) + + (0x1 << 27) + // reserved + (0x0 << 26) + // reserved + (0x0 << 25) + // reserved + (REFOUTEN << 24) + + (0x1 << 23) + // reserved + (0x0 << 21) + // reserved + (IXTAL << 19) + + (0x10 << 14) + // reserved + (0x0 << 13) + // reserved + (0x0 << 10) + // reserved + (ICP << 9) + + (0x0 << 8) + // reserved + (0x0 << 7) + // reserved + (0x0 << 4) + // reserved + (INT_PLL << 3) + + (PWRSAV << 2) + + (0x0 << 1) + // reserved + 0x0; // reserved + + uint32_t freq_sel; + switch (freq_) + { + case static_cast(GPS_L1_FREQ_HZ): + freq_sel = 0x604; + break; + case static_cast(GPS_L2_FREQ_HZ): + freq_sel = 0x4B0; + break; + case static_cast(GPS_L5_FREQ_HZ): + freq_sel = 0x47E; + break; + default: + freq_sel = 0x604; + } + + register_values[4] = // PLL integer division register + (0x0 << 28) + // reserved + (freq_sel << 13) + + (RDIV << 3) + + 0x0; // reserved + + register_values[5] = // PLL fractional division register + (0x0 << 28) + // reserved + (FDIV << 8) + + (0x7 << 4) + // reserved + (0x0 << 3) + // reserved + (0x0 << 2) + // reserved + (0x0 << 1) + // reserved + 0x0; // reserved + + register_values[6] = // DSP interface register + (0x0 << 28) + // reserved + 0x8000000; // reserved + + register_values[7] = // clock configuration 1 register + (0x0 << 29) + // reserved + (EXTADCCLK << 28) + + (REFCLK_L_CNT << 16) + + (REFCLK_M_CNT << 4) + + (FCLKIN << 3) + + (ADCCLK << 2) + + (0x1 << 1) + // reserved + MODE; + + register_values[8] = TEST_MODE_1_REG_VAL; // test mode 1 register + + register_values[9] = TEST_MODE_2_REG_VAL; // test mode 2 register + + register_values[10] = // clock configuration 2 register + (0x0 << 29) + // reserved + (0x0 << 28) + // reserved + (ADCCLK_L_CNT << 16) + + (ADCCLK_M_CNT << 4) + + (PRE_FRACDIV_SEL << 3) + + (CLKOUT_SEL << 2) + + 0x0; // reserved + + return register_values; +} + + +bool MAX2771EVKITSignalSourceFPGA::configure(std::vector register_values) +{ + // write the registers + std::cerr << "Configuring MAX2771 registers" << std::endl; + uint32_t status = 0; + for (uint32_t k = 0; k < register_values.size(); k++) + { + status = spidev_fpga->write_reg32(k, register_values[k]); + if (status) + { + std::cerr << "Error writing the MAX2771 registers" << std::endl; + break; + } + } + + // Read the registers and verify that the values are correctly written + std::vector reg_read = std::vector(register_values.size()); + + for (uint8_t n = 0; n < register_values.size(); ++n) + { + status = spidev_fpga->read_reg32(n, ®_read[n]); + if (status) + { + std::cerr << "Error reading the MAX2771 registers" << std::endl; + return status; + } + else + { + if (reg_read[n] != register_values[n]) + { + std::cerr << "Error: Failed to verify the MAX2771 registers " << std::endl; + return -1; + } + } + } + + return 0; +} + +MAX2771EVKITSignalSourceFPGA::~MAX2771EVKITSignalSourceFPGA() +{ + /* cleanup and exit */ + + if (rf_shutdown_) + { + chipen_ = false; + std::cout << "* MAX2771 Disabling RX streaming channels\n"; + std::vector register_values = setup_regs(); + + if (spidev_fpga->SPI_open()) + { + std::cerr << "Cannot open SPI device\n"; + return; + } + + + if (configure(register_values)) + { + std::cerr << "Error disabling the MAX2771 device " << '\n'; + } + + if (spidev_fpga->SPI_close()) + { + std::cerr << "Error closing SPI device " << '\n'; + } + } + + // disable buffer overflow checking and buffer monitoring + std::unique_lock lock_buffer_monitor(buffer_monitor_mutex); + enable_ovf_check_buffer_monitor_active_ = false; + lock_buffer_monitor.unlock(); + + if (thread_buffer_monitor.joinable()) + { + thread_buffer_monitor.join(); + } +} + + +void MAX2771EVKITSignalSourceFPGA::run_buffer_monitor_process() +{ + bool enable_ovf_check_buffer_monitor_active = true; + + std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitoring_initial_delay_ms)); + + while (enable_ovf_check_buffer_monitor_active) + { + buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); + std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); + std::unique_lock lock(buffer_monitor_mutex); + if (enable_ovf_check_buffer_monitor_active_ == false) + { + enable_ovf_check_buffer_monitor_active = false; + } + lock.unlock(); + } +} + + +void MAX2771EVKITSignalSourceFPGA::connect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to connect"; +} + + +void MAX2771EVKITSignalSourceFPGA::disconnect(gr::top_block_sptr top_block) +{ + if (top_block) + { /* top_block is not null */ + }; + DLOG(INFO) << "AD9361 FPGA source nothing to disconnect"; +} + + +gr::basic_block_sptr MAX2771EVKITSignalSourceFPGA::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + return {}; +} + + +gr::basic_block_sptr MAX2771EVKITSignalSourceFPGA::get_right_block() +{ + return {}; +} diff --git a/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h new file mode 100644 index 000000000..3008aa384 --- /dev/null +++ b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h @@ -0,0 +1,164 @@ +/*! + * \file max2771_evkit_signal_source_fpga.h + * \brief Signal source for the MAX2771EVKIT evaluation board connected directly + * to FPGA accelerators. + * This source implements only the MAX2771 control. It is NOT compatible with + * conventional SDR acquisition and tracking blocks. + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H +#define GNSS_SDR_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H + +#include "command_event.h" +#include "concurrent_queue.h" +#include "fpga_buffer_monitor.h" +#include "fpga_spidev.h" +#include "gnss_block_interface.h" +#include "signal_source_base.h" +#include // for pmt::pmt_t +#include // for fixed-width integer types +#include // for smart pointers +#include // for mutex +#include // for strings +#include // for threads +#include // for std::vector + + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_adapters + * \{ */ + + +class ConfigurationInterface; + +class MAX2771EVKITSignalSourceFPGA : public SignalSourceBase +{ +public: + MAX2771EVKITSignalSourceFPGA(const ConfigurationInterface *configuration, + const std::string &role, unsigned int in_stream, + unsigned int out_stream, Concurrent_Queue *queue); + + ~MAX2771EVKITSignalSourceFPGA(); + + std::vector setup_regs(void); + + + inline size_t item_size() override + { + return item_size_; + } + + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + +private: + const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); + const uint64_t default_bandwidth = 2500000; + const uint32_t default_filter_order = 5; + const uint64_t default_sampling_rate = 4092000; + const uint32_t default_PGA_gain_value = 0x3A; // default PGA gain when AGC is off + // max PGA gain value + const uint32_t max_PGA_gain_value = 0x3F; + // check buffer overflow and perform buffer monitoring every 1s by default + const uint32_t buffer_monitor_period_ms = 1000; + // buffer overflow and buffer monitoring initial delay + const uint32_t buffer_monitoring_initial_delay_ms = 2000; + // MAX2771 number of configuration registers + const uint32_t MAX2771_NUM_REGS = 11; + // MAX2771 configuration register fields + const uint32_t NUM_FREQ_BANDS = 1; + const uint32_t IDLE = 0x0; // Idle mode disabled + const uint32_t MIXPOLE = 0x0; // set the passive filter pole at mixer output at 13 MHz. + const uint32_t MIXERMODE = 0x0; // L1 band enabled + const uint32_t FCEN = 0x58; // Center frequency not used when in low-pass filter mode. Set to default value. + const uint32_t FCENX = 0x0; // POlyphase filter selection set to Lowpass filter + const uint32_t ANAIMON = 0x0; // analog monitor disabled + const uint32_t IQEN = 0x1; // I and Q channels enable + const uint32_t GAINREF = 0xAA; // AGC Gain ref + const uint32_t SPI_SDIO_CONFIG = 0x0; // SPI SDIO config when tri-stated: nothing applied + const uint32_t FORMAT = 0x1; // sign and magnitude + const uint32_t BITS = 0x2; // number of bits in the ADC = 2 + const uint32_t DRVCFG = 0x0; // output driver configuration = CMOS Logic + const uint32_t DIEID = 0x0; // identifies version of IC + const uint32_t HILOADEN = 0x0; // disable output driver for high loads + const uint32_t FHIPEN = 0x1; // enable highpass coupling between filter and PGA. + const uint32_t PGAIEN = 0x1; // I-Channel PGA Enable + const uint32_t PGAQEN = 0x1; // Q-Channel PGA Enable + const uint32_t STRMEN = 0x0; // disable DSP interface for serial streaming of data + const uint32_t STRMSTART = 0x0; // the rising edge of this bit enables data streaming to the output, clock, data, sync and frame sync outputs. + const uint32_t STRMSTOP = 0x0; // the rising edge of this bit disables data streaming to the output, clock, data sync and frame sync outputs. + const uint32_t STRMBITS = 0x1; // number of bits to be streamed: I MSB, I LSB + const uint32_t STAMPEN = 0x1; // enable frame number insertion + const uint32_t TIMESYNCEN = 0x1; // enable the output of the time sync pulses at all times when streaming is enabled. + const uint32_t DATASYNCEN = 0x0; // disable the sync pulses at the DATASYNC output + const uint32_t STRMRST = 0x0; // counter reset not active + const uint32_t LOBAND = 0x0; // L1 band + const uint32_t REFOUTEN = 0x1; // Output clock buffer enable + const uint32_t IXTAL = 0x1; // XTAL osscillator/buffer set to normal current + const uint32_t ICP = 0x0; // charge pump current selection set to 0.5 mA + const uint32_t INT_PLL = 0x1; // PLL mode set to integer-N PLL + const uint32_t PWRSAV = 0x0; // PLL power save mode disabled + const uint32_t RDIV = 0x10; // Set the PLL reference division ratio such that the L1 band is tuned to 1575.42 Mhz + const uint32_t FDIV = 0x80000; // PLL fractional division ratio not used. Set to default value + const uint32_t EXTADCCLK = 0x0; // use internally generated clock + const uint32_t REFCLK_L_CNT = 0x100; // set the L counter of the reference clock configuration to its default value + const uint32_t REFCLK_M_CNT = 0x61B; // set the M counter of the reference clock configuration to its default value + const uint32_t FCLKIN = 0x0; // fractional clock divider set to default value + const uint32_t ADCCLK = 0x0; // ADC clock selection set to reference clock divider/multiplier + const uint32_t MODE = 0x0; // DSP interface mode selection + const uint32_t ADCCLK_L_CNT = 0x100; // set the L counter of the ADC clock configuration to its default value + const uint32_t ADCCLK_M_CNT = 0x61B; // set the M counter of the ADC clock configuration to its default value + const uint32_t PRE_FRACDIV_SEL = 0x0; // bypass fractional clock divider + const uint32_t CLKOUT_SEL = 0x1; // CLKOUT selection set to ADC clock + // MAX2771 configuration register registers + const uint32_t TEST_MODE_1_REG_VAL = 0x01E0F401; // reserved + const uint32_t TEST_MODE_2_REG_VAL = 0x00000002; + + bool configure(std::vector register_values); + void run_buffer_monitor_process(); + + + std::thread thread_buffer_monitor; + + std::shared_ptr buffer_monitor_fpga; + std::shared_ptr spidev_fpga; + + std::mutex buffer_monitor_mutex; + + uint64_t freq_; // frequency of local oscillator + uint64_t sample_rate_; + + uint32_t in_stream_; + uint32_t out_stream_; + uint32_t bandwidth_; // 2500000, 4200000, 8700000, 16400000, 23400000, 36000000 + uint32_t filter_order_; // 3, 5 + uint32_t gain_in_; // 0 to 0x3F + + size_t item_size_; // 1 + + bool chipen_; // chip enable + bool if_filter_gain_; // true, false + bool LNA_active_; // true, false + bool enable_agc_; // true, false + bool enable_ovf_check_buffer_monitor_active_; + bool dump_; + bool rf_shutdown_; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_MAX2771_EVKIT_SIGNAL_SOURCE_FPGA_H diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt index 2b0eb6a86..3506dc4f7 100644 --- a/src/algorithms/signal_source/libs/CMakeLists.txt +++ b/src/algorithms/signal_source/libs/CMakeLists.txt @@ -12,17 +12,27 @@ if(ENABLE_FMCOMMS2 OR ENABLE_AD9361) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h) endif() -if(ENABLE_FPGA OR ENABLE_AD9361) +if(ENABLE_MAX2771) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.h) +endif() + +if(ENABLE_FPGA) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_switch.cc) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_switch.h) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dynamic_bit_selection.cc) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dynamic_bit_selection.h) - set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h) +endif() + +if(ENABLE_DMA_PROXY) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_dma-proxy.cc) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_dma-proxy.h) endif() +if((ENABLE_FPGA AND ENABLE_AD9361) OR ENABLE_MAX2771) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_buffer_monitor.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h) +endif() if(ENABLE_PLUTOSDR) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc) diff --git a/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc b/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc index 0b250d131..1f56afbf4 100644 --- a/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc +++ b/src/algorithms/signal_source/libs/fpga_buffer_monitor.cc @@ -25,6 +25,7 @@ #include "fpga_buffer_monitor.h" #include "gnss_sdr_create_directory.h" #include "gnss_sdr_filesystem.h" +#include "uio_fpga.h" #include // for time, localtime #include // for open, O_RDWR, O_SYNC #include // for string, ofstream @@ -40,7 +41,7 @@ #endif -Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name, +Fpga_buffer_monitor::Fpga_buffer_monitor( uint32_t num_freq_bands, bool dump, std::string dump_filename) @@ -50,10 +51,19 @@ Fpga_buffer_monitor::Fpga_buffer_monitor(const std::string &device_name, d_max_buff_occ_freq_band_1(0), d_dump(dump) { - // open device descriptor - if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) + std::string device_io_name; + + // find the uio device file corresponding to the buffer monitor + if (find_uio_dev_file_name(device_io_name, BUFFER_MONITOR_DEVICE_NAME, 0) < 0) { - LOG(WARNING) << "Cannot open deviceio" << device_name; + std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << BUFFER_MONITOR_DEVICE_NAME << '\n'; + return; + } + + // open device descriptor + if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << device_io_name; } // device memory map diff --git a/src/algorithms/signal_source/libs/fpga_buffer_monitor.h b/src/algorithms/signal_source/libs/fpga_buffer_monitor.h index 00b413e30..7231c5ae3 100644 --- a/src/algorithms/signal_source/libs/fpga_buffer_monitor.h +++ b/src/algorithms/signal_source/libs/fpga_buffer_monitor.h @@ -45,10 +45,13 @@ public: /*! * \brief Constructor */ - explicit Fpga_buffer_monitor(const std::string& device_name, - uint32_t num_freq_bands, + explicit Fpga_buffer_monitor(uint32_t num_freq_bands, bool dump, std::string dump_filename); + // explicit Fpga_buffer_monitor(const std::string& device_name, + // uint32_t num_freq_bands, + // bool dump, + // std::string dump_filename); /*! * \brief Destructor @@ -61,6 +64,7 @@ public: void check_buffer_overflow_and_monitor_buffer_status(); private: + const std::string BUFFER_MONITOR_DEVICE_NAME = std::string("buffer_monitor"); // buffer monitor device name static const size_t FPGA_PAGE_SIZE = 0x1000; static const uint32_t test_register_writeval = 0x55AA; static const uint32_t num_sapmples_per_buffer_element = 2; diff --git a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h index 3f4b73a5a..53729b265 100644 --- a/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h +++ b/src/algorithms/signal_source/libs/fpga_dynamic_bit_selection.h @@ -56,7 +56,6 @@ public: void bit_selection(void); private: - const std::string switch_device_name = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name const std::string dyn_bit_sel_device_name = std::string("dynamic_bits_selector"); // Switch dhnamic bit selector device name static const size_t FPGA_PAGE_SIZE = 0x1000; static const uint32_t Num_bits_ADC = 12; // Number of bits in the ADC diff --git a/src/algorithms/signal_source/libs/fpga_spidev.cc b/src/algorithms/signal_source/libs/fpga_spidev.cc new file mode 100644 index 000000000..f90cf4ac9 --- /dev/null +++ b/src/algorithms/signal_source/libs/fpga_spidev.cc @@ -0,0 +1,131 @@ +/*! + * \file fpga_spidev.cc + * \brief FPGA SPI control. + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "fpga_spidev.h" +#include // for memset() +#include // for open(), O_RDWR +#include // for std::cerr +#include // spidev driver +#include // for ioctl() +#include // for close() + + +int Fpga_spidev::SPI_open() +{ + if ((d_fd = open(SPI_DEVICE_NAME.c_str(), O_RDWR)) < 0) + { + std::cerr << "Failed to open the " << SPI_DEVICE_NAME << " device file \n"; + return -1; + } + + int ret; + int32_t mode = 0; + + ret = ioctl(d_fd, SPI_IOC_WR_MODE32, &mode); + if (ret == -1) + { + std::cerr << "can't set spi mode\n"; + return -1; + } + + ret = ioctl(d_fd, SPI_IOC_RD_MODE32, &mode); // le digo al spi "algo" + if (ret == -1) + { + std::cerr << "can't set spi mode\n"; + return -1; + } + + return 0; +} + +int Fpga_spidev::write_reg32(char addr, uint32_t data) +{ + uint8_t data_buffer[2]; + uint8_t recv_buffer[4]; + int res = 0; + struct spi_ioc_transfer xfer[2]; + memset(xfer, 0, sizeof(xfer)); + xfer[0].bits_per_word = 8; + xfer[0].speed_hz = SPI_SPEED; + xfer[1].bits_per_word = 8; + xfer[1].speed_hz = SPI_SPEED; + + memset(&recv_buffer, 0, sizeof(recv_buffer)); + memset(&data_buffer, 0, sizeof(data_buffer)); + + data_buffer[1] = addr << 4 | 0 << 3; + xfer[0].tx_buf = (unsigned long)data_buffer; + xfer[0].len = 2; + + // Would use memcpy but 'data' is in little endian + ((char*)recv_buffer)[0] = ((char*)&data)[3]; + ((char*)recv_buffer)[1] = ((char*)&data)[2]; + ((char*)recv_buffer)[2] = ((char*)&data)[1]; + ((char*)recv_buffer)[3] = ((char*)&data)[0]; + + xfer[1].tx_buf = (unsigned long)recv_buffer; + xfer[1].len = 4; + res = ioctl(d_fd, SPI_IOC_MESSAGE(2), xfer); + if (res < 0) + { + std::cout << "Error sending SPI message\n"; + return res; + } + return 0; +} + +int Fpga_spidev::read_reg32(uint8_t addr, uint32_t* copy_to) +{ + uint8_t data_buffer[2]; + uint8_t recv_buffer[4]; + int res; + struct spi_ioc_transfer xfer[2]; + memset(xfer, 0, sizeof(xfer)); + xfer[0].bits_per_word = 8; + xfer[0].speed_hz = SPI_SPEED; + xfer[1].bits_per_word = 8; + xfer[1].speed_hz = SPI_SPEED; + + memset(&recv_buffer, 0, sizeof(recv_buffer)); + memset(&data_buffer, 0, sizeof(data_buffer)); + + data_buffer[1] = addr << 4 | 1 << 3; + xfer[0].tx_buf = (unsigned long)data_buffer; + xfer[0].len = 2; + + xfer[1].rx_buf = (unsigned long)recv_buffer; + xfer[1].len = 4; + res = ioctl(d_fd, SPI_IOC_MESSAGE(2), xfer); + if (res < 0) + { + std::cout << "Error sending SPI message\n"; + return res; + } + + // the register data is received in the reverse order + uint32_t tmp_result = 0; + for (uint32_t k = 0; k < 4; ++k) + { + tmp_result = tmp_result + ((recv_buffer[3 - k]) << 8 * k); + } + *copy_to = tmp_result; + + return 0; +} + +int Fpga_spidev::SPI_close() const +{ + return close(d_fd); +} diff --git a/src/algorithms/signal_source/libs/fpga_spidev.h b/src/algorithms/signal_source/libs/fpga_spidev.h new file mode 100644 index 000000000..5fbe2f41c --- /dev/null +++ b/src/algorithms/signal_source/libs/fpga_spidev.h @@ -0,0 +1,61 @@ +/*! + * \file fpga_spidev.h + * \brief FPGA SPI control. + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_FPGA_SPIDEV_H +#define GNSS_SDR_FPGA_SPIDEV_H + +#include + +class Fpga_spidev +{ +public: + /*! + * \brief Default constructor. + */ + Fpga_spidev() = default; + + /*! + * \brief Default destructor. + */ + ~Fpga_spidev() = default; + + /*! + * \brief write a register through the SPI. + */ + int write_reg32(char addr, uint32_t data); + + /*! + * \brief read a register through the SPI. + */ + int read_reg32(uint8_t addr, uint32_t* copy_to); + /*! + * \brief Open the SPI device driver. + */ + int SPI_open(void); + + /*! + * \brief Close the SPI device driver + */ + int SPI_close(void) const; + +private: + static const uint32_t SPI_SPEED = 250000; + const std::string SPI_DEVICE_NAME = std::string("/dev/spidev2.0"); // Switch UIO device name + + int d_fd; +}; + + +#endif // GNSS_SDR_FPGA_SPIDEV_H diff --git a/src/algorithms/signal_source/libs/fpga_switch.cc b/src/algorithms/signal_source/libs/fpga_switch.cc index f2d51c2fb..2730bdf36 100644 --- a/src/algorithms/signal_source/libs/fpga_switch.cc +++ b/src/algorithms/signal_source/libs/fpga_switch.cc @@ -21,6 +21,7 @@ */ #include "fpga_switch.h" +#include "uio_fpga.h" #include // for open, O_RDWR, O_SYNC #include // for cout #include // for mmap @@ -32,11 +33,19 @@ #include #endif -Fpga_Switch::Fpga_Switch(const std::string &device_name) +Fpga_Switch::Fpga_Switch(void) { - if ((d_device_descriptor = open(device_name.c_str(), O_RDWR | O_SYNC)) == -1) + std::string device_io_name; // Switch UIO device file + // find the uio device file corresponding to the switch. + if (find_uio_dev_file_name(device_io_name, SWITCH_DEVICE_NAME, 0) < 0) { - LOG(WARNING) << "Cannot open deviceio" << device_name; + std::cerr << "Cannot find the FPGA uio device file corresponding to device name " << SWITCH_DEVICE_NAME << '\n'; + return; + } + + if ((d_device_descriptor = open(device_io_name.c_str(), O_RDWR | O_SYNC)) == -1) + { + LOG(WARNING) << "Cannot open deviceio" << device_io_name; } d_map_base = reinterpret_cast(mmap(nullptr, FPGA_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, d_device_descriptor, 0)); diff --git a/src/algorithms/signal_source/libs/fpga_switch.h b/src/algorithms/signal_source/libs/fpga_switch.h index b4a73cb4f..8a46c214d 100644 --- a/src/algorithms/signal_source/libs/fpga_switch.h +++ b/src/algorithms/signal_source/libs/fpga_switch.h @@ -42,8 +42,7 @@ public: /*! * \brief Constructor */ - explicit Fpga_Switch(const std::string& device_name); - + Fpga_Switch(void); /*! * \brief Destructor */ @@ -55,6 +54,7 @@ public: void set_switch_position(int32_t switch_position); private: + const std::string SWITCH_DEVICE_NAME = std::string("AXIS_Switch_v1_0_0"); // Switch UIO device name static const size_t FPGA_PAGE_SIZE = 0x1000; static const uint32_t TEST_REGISTER_TRACK_WRITEVAL = 0x55AA; static const uint32_t MAX_LENGTH_DEVICEIO_NAME = 50; diff --git a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h index 722440f32..8de75e087 100644 --- a/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/galileo_e1_dll_pll_veml_tracking_fpga.h @@ -65,11 +65,11 @@ public: } /*! - * \brief Returns "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga" + * \brief Returns "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA" */ inline std::string implementation() override { - return "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga"; + return "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA"; } /*! diff --git a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h index 510df45ea..1b3c8f52b 100644 --- a/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/galileo_e5a_dll_pll_tracking_fpga.h @@ -59,11 +59,11 @@ public: } /*! - * \brief Returns "Galileo_E5a_DLL_PLL_Tracking_Fpga" + * \brief Returns "Galileo_E5a_DLL_PLL_Tracking_FPGA" */ inline std::string implementation() override { - return "Galileo_E5a_DLL_PLL_Tracking_Fpga"; + return "Galileo_E5a_DLL_PLL_Tracking_FPGA"; } /*! diff --git a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h index dedefd7c5..ed3b23f4a 100644 --- a/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/gps_l1_ca_dll_pll_tracking_fpga.h @@ -64,11 +64,11 @@ public: } /*! - * \brief Returns "GPS_L1_CA_DLL_PLL_Tracking_Fpga" + * \brief Returns "GPS_L1_CA_DLL_PLL_Tracking_FPGA" */ inline std::string implementation() override { - return "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; + return "GPS_L1_CA_DLL_PLL_Tracking_FPGA"; } /*! diff --git a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h index 506e8fec6..a89dd5d55 100644 --- a/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/gps_l2_m_dll_pll_tracking_fpga.h @@ -57,10 +57,10 @@ public: return role_; } - //! Returns "GPS_L2_M_DLL_PLL_Tracking_Fpga" + //! Returns "GPS_L2_M_DLL_PLL_Tracking_FPGA" inline std::string implementation() override { - return "GPS_L2_M_DLL_PLL_Tracking_Fpga"; + return "GPS_L2_M_DLL_PLL_Tracking_FPGA"; } inline size_t item_size() override diff --git a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h index 24fc37a14..ed85735b2 100644 --- a/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h +++ b/src/algorithms/tracking/adapters/gps_l5_dll_pll_tracking_fpga.h @@ -65,11 +65,11 @@ public: } /*! - * \brief Returns "GPS_L5_DLL_PLL_Tracking_Fpga" + * \brief Returns "GPS_L5_DLL_PLL_Tracking_FPGA" */ inline std::string implementation() override { - return "GPS_L5_DLL_PLL_Tracking_Fpga"; + return "GPS_L5_DLL_PLL_Tracking_FPGA"; } /*! diff --git a/src/core/libs/osnma_msg_receiver.cc b/src/core/libs/osnma_msg_receiver.cc index 556f3fddf..9e07f998c 100644 --- a/src/core/libs/osnma_msg_receiver.cc +++ b/src/core/libs/osnma_msg_receiver.cc @@ -2026,7 +2026,7 @@ void osnma_msg_receiver::send_data_to_pvt(const std::vector& data { if (!data.empty()) { - for (auto& i : data) + for (const auto& i : data) { const auto tmp_obj = std::make_shared(i); this->message_port_pub(pmt::mp("OSNMA_to_PVT"), pmt::make_any(tmp_obj)); diff --git a/src/core/libs/osnma_msg_receiver.h b/src/core/libs/osnma_msg_receiver.h index 1598e23c2..4240d7df8 100644 --- a/src/core/libs/osnma_msg_receiver.h +++ b/src/core/libs/osnma_msg_receiver.h @@ -61,11 +61,11 @@ 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 - void msg_handler_osnma(const pmt::pmt_t& msg); //!< For testing purposes - void read_merkle_xml(const std::string& merklepath); //!< Public for testing purposes - bool verify_dsm_pkr(const DSM_PKR_message& message) const; //!< Public for benchmarking purposes - void set_merkle_root(const std::vector& v); //!< Public for benchmarking purposes + ~osnma_msg_receiver() = default; //!< Default destructor + bool verify_dsm_pkr(const DSM_PKR_message& message) const; //!< Public for benchmarking purposes + void msg_handler_osnma(const pmt::pmt_t& msg); //!< For testing purposes + void read_merkle_xml(const std::string& merklepath); //!< Public for testing purposes + void set_merkle_root(const std::vector& v); //!< Public for benchmarking purposes private: friend osnma_msg_receiver_sptr osnma_msg_receiver_make(const std::string& pemFilePath, const std::string& merkleFilePath, bool strict_mode); diff --git a/src/core/libs/osnma_nav_data_manager.cc b/src/core/libs/osnma_nav_data_manager.cc index 03d5a4442..73392db5b 100644 --- a/src/core/libs/osnma_nav_data_manager.cc +++ b/src/core/libs/osnma_nav_data_manager.cc @@ -135,11 +135,11 @@ std::string OSNMA_NavDataManager::get_navigation_data(const Tag& tag) const { if (tag.ADKD == 0 || tag.ADKD == 12) { - return std::string(549, '0'); + return {std::string(549, '0')}; } else if (tag.ADKD == 4) { - return std::string(141, '0'); + return {std::string(141, '0')}; } } auto prn_it = d_satellite_nav_data.find(tag.PRN_d); @@ -168,8 +168,9 @@ std::string OSNMA_NavDataManager::get_navigation_data(const Tag& tag) const } else { - for (auto rev_it = prn_it->second.rbegin(); rev_it != prn_it->second.rend(); ++rev_it) // note: starts with largest (i.e. newest) navigation dataset + for (auto rev_it = prn_it->second.rbegin(); rev_it != prn_it->second.rend(); ++rev_it) // NOLINT(modernize-loop-convert) { + // note: starts with largest (i.e. newest) navigation dataset // Check if current key (TOW) fulfills condition if ((tag.TOW - 30 * tag.cop <= rev_it->first || tag.TOW - 30 * tag.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < tag.TOW) { @@ -269,8 +270,9 @@ bool OSNMA_NavDataManager::have_nav_data(const Tag& t) const { // iterate in reverse order to find matching TOW with Tag's COP value std::map tow_map = prn_it->second; - for (auto rev_it = tow_map.rbegin(); rev_it != tow_map.rend(); ++rev_it) // note: starts with largest (i.e. newest) navigation dataset + for (auto rev_it = tow_map.rbegin(); rev_it != tow_map.rend(); ++rev_it) // NOLINT(modernize-loop-convert) { + // note: starts with largest (i.e. newest) navigation dataset // Check if current key (TOW) fulfills cut-off point and is not received after the tag if ((t.TOW - 30 * t.cop <= rev_it->first || t.TOW - 30 * t.cop <= rev_it->second.get_last_received_TOW()) && rev_it->first < t.TOW) { diff --git a/src/core/receiver/CMakeLists.txt b/src/core/receiver/CMakeLists.txt index 0dfc09a84..cacef7f6f 100644 --- a/src/core/receiver/CMakeLists.txt +++ b/src/core/receiver/CMakeLists.txt @@ -98,6 +98,14 @@ if(ENABLE_AD9361) target_compile_definitions(core_receiver PRIVATE -DAD9361_DRIVER=1) endif() +if(ENABLE_MAX2771) + target_compile_definitions(core_receiver PRIVATE -DMAX2771_DRIVER=1) +endif() + +if(ENABLE_DMA_PROXY) + target_compile_definitions(core_receiver PRIVATE -DDMA_PROXY_DRIVER=1) +endif() + if(ENABLE_OSMOSDR) if(GROSMOSDR_FOUND) target_compile_definitions(core_receiver PRIVATE -DOSMOSDR_DRIVER=1) diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index dda8452a8..ce77442ee 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -167,8 +167,17 @@ #include "fmcomms2_signal_source.h" #endif -#if AD9361_DRIVER -#include "ad9361_fpga_signal_source.h" +#if ENABLE_FPGA and AD9361_DRIVER +#include "adrv9361_z7035_signal_source_fpga.h" +#include "fmcomms5_signal_source_fpga.h" +#endif + +#if MAX2771_DRIVER +#include "max2771_evkit_signal_source_fpga.h" +#endif + +#if DMA_PROXY_DRIVER +#include "dma_signal_source_fpga.h" #endif #if LIMESDR_DRIVER @@ -812,12 +821,34 @@ std::unique_ptr GNSSBlockFactory::GetBlock( } #endif -#if AD9361_DRIVER - // The AD9361_DRIVER Driver must be instantiated last. In this way, when using the FPGA, and when using the GNSS receiver - // in post-processing mode, the receiver is configured and ready when the DMA starts sending samples to the receiver. - else if (implementation == "Ad9361_Fpga_Signal_Source") +#if ENABLE_FPGA and AD9361_DRIVER + else if (implementation == "ADRV9361_Z7035_Signal_Source_FPGA") { - std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, + std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, + out_streams, queue); + block = std::move(block_); + } + else if (implementation == "FMCOMMS5_Signal_Source_FPGA") + { + std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, + out_streams, queue); + block = std::move(block_); + } +#endif + +#if ENABLE_FPGA and MAX2771_DRIVER + else if (implementation == "MAX2771_EVKIT_Signal_Source_FPGA") + { + std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, + out_streams, queue); + block = std::move(block_); + } +#endif + +#if ENABLE_FPGA and DMA_PROXY_DRIVER + else if (implementation == "DMA_Signal_Source_FPGA") + { + std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams, queue); block = std::move(block_); } @@ -1054,31 +1085,31 @@ std::unique_ptr GNSSBlockFactory::GetBlock( } #endif #if ENABLE_FPGA - else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga") + else if (implementation == "GPS_L1_CA_PCPS_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga") + else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "GPS_L2_M_PCPS_Acquisition_Fpga") + else if (implementation == "GPS_L2_M_PCPS_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga") + else if (implementation == "GPS_L5i_PCPS_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga") + else if (implementation == "Galileo_E5a_Pcps_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); @@ -1204,31 +1235,31 @@ std::unique_ptr GNSSBlockFactory::GetBlock( } #endif #if ENABLE_FPGA - else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) + else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_FPGA") or (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")) { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); @@ -1492,31 +1523,31 @@ std::unique_ptr GNSSBlockFactory::GetAcqBlock( } #endif #if ENABLE_FPGA - else if (implementation == "GPS_L1_CA_PCPS_Acquisition_Fpga") + else if (implementation == "GPS_L1_CA_PCPS_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga") + else if (implementation == "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "GPS_L2_M_PCPS_Acquisition_Fpga") + else if (implementation == "GPS_L2_M_PCPS_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "GPS_L5i_PCPS_Acquisition_Fpga") + else if (implementation == "GPS_L5i_PCPS_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E5a_Pcps_Acquisition_Fpga") + else if (implementation == "Galileo_E5a_Pcps_Acquisition_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); @@ -1660,31 +1691,31 @@ std::unique_ptr GNSSBlockFactory::GetTrkBlock( } #endif #if ENABLE_FPGA - else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L2_M_DLL_PLL_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_Fpga") or (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga")) + else if ((implementation == "GPS_L5i_DLL_PLL_Tracking_FPGA") or (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA")) { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); block = std::move(block_); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, out_streams); diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 0d1606924..593c9912c 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -582,7 +582,7 @@ int GNSSFlowgraph::connect_fpga_flowgraph() if (src == nullptr) { help_hint_ += " * Check implementation name for SignalSource block.\n"; - help_hint_ += " Signal Source block implementation for FPGA off-loading should be Ad9361_Fpga_Signal_Source\n"; + help_hint_ += " Signal Source block implementation for FPGA off-loading should be Ad9361_Signal_Source_Fpga or Fpga_DMA_2Signal_Source\n"; return 1; } if (src->item_size() == 0) diff --git a/src/tests/benchmarks/benchmark_osnma.cc b/src/tests/benchmarks/benchmark_osnma.cc index 727c11e70..b99c3efd0 100644 --- a/src/tests/benchmarks/benchmark_osnma.cc +++ b/src/tests/benchmarks/benchmark_osnma.cc @@ -1,23 +1,24 @@ /*! -* \file benchmark_osnma.cc -* \brief Benchmarks for osnma functions -* \author Carles Fernandez-Prades, 2024. cfernandez(at)cttc.es -* -* -* ----------------------------------------------------------------------------- -* -* GNSS-SDR is a Global Navigation Satellite System software-defined receiver. -* This file is part of GNSS-SDR. -* -* Copyright (C) 2024 (see AUTHORS file for a list of contributors) -* SPDX-License-Identifier: GPL-3.0-or-later -* -* ----------------------------------------------------------------------------- -*/ -#include "osnma_msg_receiver.h" + * \file benchmark_osnma.cc + * \brief Benchmarks for osnma functions + * \author Carles Fernandez-Prades, 2024. cfernandez(at)cttc.es + * + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + #include "Galileo_OSNMA.h" #include "gnss_crypto.h" #include "osnma_helper.h" +#include "osnma_msg_receiver.h" #include #include diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc index 816dbfe1a..4d68363f8 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/galileo_e1_pcps_ambiguous_acquisition_test_fpga.cc @@ -67,7 +67,7 @@ class GalileoE1PcpsAmbiguousAcquisitionTestFpga : public ::testing::Test { public: bool acquire_signal(); - std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; + std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_FPGA"; std::vector gnss_synchro_vec; const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; @@ -321,7 +321,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal() // instantiate the FPGA switch and set the // switch position to DMA. std::shared_ptr switch_fpga; - switch_fpga = std::make_shared("/dev/uio1"); + switch_fpga = std::make_shared(); switch_fpga->set_switch_position(0); // set switch position to DMA // create the correspondign acquisition block according to the desired tracking signal @@ -397,7 +397,7 @@ bool GalileoE1PcpsAmbiguousAcquisitionTestFpga::acquire_signal() void GalileoE1PcpsAmbiguousAcquisitionTestFpga::init() { config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); - config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition_Fpga"); + config->set_property("Acquisition.implementation", "Galileo_E1_PCPS_Ambiguous_Acquisition_FPGA"); config->set_property("Acquisition.threshold", "0.00001"); config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); diff --git a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc index ee06f57ce..47ddc54aa 100644 --- a/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/acquisition/gps_l1_ca_pcps_acquisition_test_fpga.cc @@ -66,7 +66,7 @@ class GpsL1CaPcpsAcquisitionTestFpga : public ::testing::Test { public: bool acquire_signal(); - std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_Fpga"; + std::string implementation = "GPS_L1_CA_DLL_PLL_Tracking_FPGA"; std::vector gnss_synchro_vec; const int32_t TEST_ACQ_SKIP_SAMPLES = 1024; @@ -320,7 +320,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal() // instantiate the FPGA switch and set the // switch position to DMA. std::shared_ptr switch_fpga; - switch_fpga = std::make_shared("/dev/uio1"); + switch_fpga = std::make_shared(); switch_fpga->set_switch_position(0); // set switch position to DMA // create the correspondign acquisition block according to the desired tracking signal @@ -396,7 +396,7 @@ bool GpsL1CaPcpsAcquisitionTestFpga::acquire_signal() void GpsL1CaPcpsAcquisitionTestFpga::init() { config->set_property("GNSS-SDR.internal_fs_sps", "4000000"); - config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition_Fpga"); + config->set_property("Acquisition.implementation", "GPS_L1_CA_PCPS_Acquisition_FPGA"); config->set_property("Acquisition.threshold", "0.00001"); config->set_property("Acquisition.doppler_max", std::to_string(doppler_max)); config->set_property("Acquisition.doppler_step", std::to_string(doppler_step)); diff --git a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc index 9824e1d17..c466a277b 100644 --- a/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/observables/hybrid_observables_test_fpga.cc @@ -638,11 +638,11 @@ bool HybridObservablesTestFpga::acquire_signal() // instantiate the FPGA switch and set the // switch position to DMA. std::shared_ptr switch_fpga; - switch_fpga = std::make_shared("/dev/uio1"); + switch_fpga = std::make_shared(); switch_fpga->set_switch_position(0); // set switch position to DMA // create the correspondign acquisition block according to the desired tracking signal - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'G'; signal = "1C"; @@ -654,7 +654,7 @@ bool HybridObservablesTestFpga::acquire_signal() args.freq_band = 0; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { tmp_gnss_synchro.System = 'E'; signal = "1B"; @@ -666,7 +666,7 @@ bool HybridObservablesTestFpga::acquire_signal() args.freq_band = 0; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'E'; signal = "5X"; @@ -678,7 +678,7 @@ bool HybridObservablesTestFpga::acquire_signal() args.freq_band = 1; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'G'; signal = "L5"; @@ -732,19 +732,19 @@ bool HybridObservablesTestFpga::acquire_signal() // number of samples that the DMA has to transfer unsigned int nsamples_to_transfer; - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); } - else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) + else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0)) { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); } @@ -762,7 +762,7 @@ bool HybridObservablesTestFpga::acquire_signal() acquisition->init(); acquisition->set_local_code(); - if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) + if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")) { // Skip the first TEST_OBS_SKIP_SAMPLES samples args.skip_used_samples = 0; @@ -910,7 +910,7 @@ void HybridObservablesTestFpga::configure_receiver( config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); std::string System_and_Signal; - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { gnss_synchro_master.System = 'G'; std::string signal = "1C"; @@ -923,7 +923,7 @@ void HybridObservablesTestFpga::configure_receiver( config->set_property("TelemetryDecoder.implementation", "GPS_L1_CA_Telemetry_Decoder"); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { gnss_synchro_master.System = 'E'; std::string signal = "1B"; @@ -939,7 +939,7 @@ void HybridObservablesTestFpga::configure_receiver( config->set_property("TelemetryDecoder.implementation", "Galileo_E1B_Telemetry_Decoder"); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") // or implementation.compare("Galileo_E5a_DLL_PLL_Tracking_b") == 0) { gnss_synchro_master.System = 'E'; std::string signal = "5X"; @@ -953,7 +953,7 @@ void HybridObservablesTestFpga::configure_receiver( config->set_property("TelemetryDecoder.implementation", "Galileo_E5a_Telemetry_Decoder"); } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { gnss_synchro_master.System = 'G'; std::string signal = "L5"; @@ -2031,22 +2031,22 @@ TEST_F(HybridObservablesTestFpga, ValidationOfResults) args.scaling_factor = DMA_SIGNAL_SCALING_FACTOR; // reset the HW to clear the sample counters: the acquisition constructor generates a reset - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 0; } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 0; } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 1; } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 1; diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc index 4bd43fc30..d5f2348af 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/gps_l1_ca_dll_pll_tracking_test_fpga.cc @@ -355,7 +355,7 @@ void GpsL1CADllPllTrackingTestFpga::configure_receiver() std::to_string(baseband_sampling_freq)); // Set Tracking config->set_property("Tracking_1C.implementation", - "GPS_L1_CA_DLL_PLL_Tracking_Fpga"); + "GPS_L1_CA_DLL_PLL_Tracking_FPGA"); config->set_property("Tracking_1C.item_type", "cshort"); config->set_property("Tracking_1C.dump", "true"); config->set_property("Tracking_1C.dump_filename", "./tracking_ch_"); diff --git a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc index 39f87bdfa..a2f27204e 100644 --- a/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc +++ b/src/tests/unit-tests/signal-processing-blocks/tracking/tracking_pull-in_test_fpga.cc @@ -536,7 +536,7 @@ void TrackingPullInTestFpga::configure_receiver( config->set_property("GNSS-SDR.internal_fs_sps", std::to_string(baseband_sampling_freq)); std::string System_and_Signal; - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { gnss_synchro.System = 'G'; std::string signal = "1C"; @@ -545,7 +545,7 @@ void TrackingPullInTestFpga::configure_receiver( config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.early_late_space_narrow_chips", "0.5"); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { gnss_synchro.System = 'E'; std::string signal = "1B"; @@ -557,7 +557,7 @@ void TrackingPullInTestFpga::configure_receiver( config->set_property("Tracking.very_early_late_space_narrow_chips", "0.6"); config->set_property("Tracking.track_pilot", "true"); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga" or implementation == "Galileo_E5a_DLL_PLL_Tracking_b_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA" or implementation == "Galileo_E5a_DLL_PLL_Tracking_b_Fpga") { gnss_synchro.System = 'E'; std::string signal = "5X"; @@ -565,13 +565,13 @@ void TrackingPullInTestFpga::configure_receiver( signal.copy(gnss_synchro.Signal, 2, 0); if (implementation == "Galileo_E5a_DLL_PLL_Tracking_b") { - config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking_Fpga")); + config->supersede_property("Tracking.implementation", std::string("Galileo_E5a_DLL_PLL_Tracking_FPGA")); } config->set_property("Tracking.early_late_space_chips", "0.5"); config->set_property("Tracking.track_pilot", "true"); config->set_property("Tracking.order", "2"); } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { gnss_synchro.System = 'G'; std::string signal = "L5"; @@ -634,11 +634,11 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) // instantiate the FPGA switch and set the // switch position to DMA. std::shared_ptr switch_fpga; - switch_fpga = std::make_shared("/dev/uio1"); + switch_fpga = std::make_shared(); switch_fpga->set_switch_position(0); // set switch position to DMA // create the correspondign acquisition block according to the desired tracking signal - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'G'; signal = "1C"; @@ -650,7 +650,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) args.freq_band = 0; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { tmp_gnss_synchro.System = 'E'; signal = "1B"; @@ -662,7 +662,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) args.freq_band = 0; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'E'; signal = "5X"; @@ -674,7 +674,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) args.freq_band = 1; // frequency band on which the DMA has to transfer the samples } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { tmp_gnss_synchro.System = 'G'; signal = "L5"; @@ -732,19 +732,19 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) // number of samples that the DMA has to transfer unsigned int nsamples_to_transfer; - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L1_CA_CODE_RATE_CPS / GPS_L1_CA_CODE_LENGTH_CHIPS))); } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E1_CODE_CHIP_RATE_CPS / GALILEO_E1_B_CODE_LENGTH_CHIPS))); } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GALILEO_E5A_CODE_CHIP_RATE_CPS / GALILEO_E5A_CODE_LENGTH_CHIPS))); } - else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_Fpga") == 0)) + else // (if (implementation.compare("GPS_L5_DLL_PLL_Tracking_FPGA") == 0)) { nsamples_to_transfer = static_cast(std::round(static_cast(baseband_sampling_freq) / (GPS_L5I_CODE_RATE_CPS / GPS_L5I_CODE_LENGTH_CHIPS))); } @@ -762,7 +762,7 @@ bool TrackingPullInTestFpga::acquire_signal(int SV_ID) acquisition->init(); acquisition->set_local_code(); - if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga")) + if ((implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") or (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA")) { // Configure the DMA to send TEST_TRK_PULL_IN_TEST_SKIP_SAMPLES in order to initialize the internal // states of the downsampling filter in the FPGA @@ -1079,22 +1079,22 @@ TEST_F(TrackingPullInTestFpga, ValidationOfResults) std::shared_ptr acquisition; // reset the HW to clear the sample counters: the acquisition constructor generates a reset - if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_Fpga") + if (implementation == "GPS_L1_CA_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 0; } - else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_Fpga") + else if (implementation == "Galileo_E1_DLL_PLL_VEML_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 0; } - else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_Fpga") + else if (implementation == "Galileo_E5a_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 1; } - else if (implementation == "GPS_L5_DLL_PLL_Tracking_Fpga") + else if (implementation == "GPS_L5_DLL_PLL_Tracking_FPGA") { acquisition = std::make_shared(config.get(), "Acquisition", 0, 0); args.freq_band = 1; From 3ec25f2347fc7db1c39d7f916c624ac61ae3edde Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 31 Aug 2024 10:07:44 +0200 Subject: [PATCH 218/219] Merge from upstream next (#27) * Decouple the FPGA DMA signal source from the AD9361 FPGA signal source. * Add the MAX2771_EVKIT FPGA signal source and the ENABLE_FPGA_MAX2771_EVKIT flag to enable it. * Adjust cross-compilation flags to properly support FPGA signal sources * fix signal source names for consistency * Detect if the spidev driver is installed when the ENABLE_MAX2771 flag is set. Detect if the DMA proxy driver is installed when the ENABLE_DMA_PROXY flag is set. Check if ENABLE_FPGA is set when either ENABLE_MAX2771 or ENABLE_DMA_PROXY is set. * fix FPGA signal source names for consistency * Fix FPGA-related CMakefile flags * make cpplint happy * make cpplint happy * make cmakelint happy * make clang-format happy * Replaced the AD9361 FPGA signal source with the ADRV9361_Z7035 FPGA and the FMCOMMS5 FPGA signal sources. * Bump local version of GoogleTest to 1.15.2 and Protocol Buffers to 27.3 * Avoid code duplication in CMake modules * Update clang-tidy job * Clang Tidy fixes * Improve efficiency of Concurrent_Map and Concurrent_Queue classes * Fix segmentation fault if the SignalSource implementation is not available * Moved decimation factor count variable to the class * Avoid possible runtime error when PVT.enable_rx_clock_correction=true * Fix formatting * Fix clang-tidy job * Capitalize FPGA in class implementation names * Capitalize acronyms in FPGA-related class names * Instantiate sources only once * Update changelog * Bump version of google benchmark to 1.9.0 * Fix CMakeLists header file list in signal source libs Header file paths were being appended to the source files list. This is not that important since, in general, you don't need to add the header files to the cmake target. * Added ION GNSS SDR Metadata Standard signal source * Only specify outputs for the requested streams * Fixed block iteration withing a file The `File` object only holds a shallow reference to its `Lane` (without the list of blocks). So we must retrieve the full reference manually. * Treat data file paths as relative to the metadata file The data file paths are actually not native paths but URLs, this covers most cases but not all of them. * Fixed decoding errors and refactored each class into its own file * Fixed sample count error & refactored * Bufferef IO & propagate configuration inside ION source * Reset sample value before writing new one Sample values are ORed into the output buffer because they may need a few read/write operations depending on alignment. So, if we don't set the value to 0 before doing this, all samples quickly become 0xFF after a few cycles of the output buffer. * Simpler handling of simpler bit formats If a sample is the same size as a word, it is much easier to read. * Less callback shenanigans * Fix wrong buffer size * Fixed conditional compilation issues And added a comment * Linting fixes * Fixed arithmetic operations on pointers * Fix formatting * Use lock_guard instead of unique_lock * Create a CMake target for the ION dependency for consistency * Improve formatting, add missing include * Fixes for C++ standards older than 20. Avoid C++20-specific lambda templates * Update changelog * Add Victor to the list of authors * Fix CMake error * Fix building error * Fix building * Add -DENABLE_ION=ON to CI jobs * Fix CMake lists * Catch all exceptions * Fix building for -DENABLE_PLUTOSDR=ON * Removed unused member fields and function parameters * Use std::ifstream instead of FILE for reading sample data * Fixed includes and code style * Simplified disconnect() function We can disconnect the sources directly instead of disconnecting each of their outputs. * Implemented range check in `IONGSMSSignalSource::get_right_block(int)` * Moved ION GSMS file source to `gnuradio_blocks/` directory Also fixed some header guards. * Fixed ION GNSS Metadata Standard dependency version * Simplified by removing a very shallow class `ion_gnss_metadata_handler` was only reading the metadata file, which can easily be done in `ion_gsms_signal_source`. * Added valves to properly handle end of samples * Cleaner exit if the data file is not found * Fix uninitialized warning * Remove unused configuration parameter. Uniformize guard names * Fix for CMake < 3.14 * fix configuration options for the FPGA-based AD9361-based boards * Put the global function into an anonymous namespace Use emplace_back instead of push_back * Make private member metadata_ a std::shared_pointer * Simplify code * Remove ION source from CI * Apply clang-tidy fixes * Initialize the receiver local oscillator frequency to GPS_L5_FREQ_HZ by default in the ADRV9361Z7035 FPGA signal source and remove unnecessary include files. * Sort out building flags and improve their reporting * Allow building Ad936x_Custom_Signal_Source when gnuradio-iio is not available * Bump local version of Protocol Buffers to v28.0 * Update AArch64 features to Linux 6.10.6 * Update AArch64 features to Linux 6.10.6 * Fix merging --------- Co-authored-by: Marc Majoral Co-authored-by: cesaaargm Co-authored-by: Xavier Guerrero-Pau Co-authored-by: Victor Castillo --- .gitignore | 1 - AUTHORS | 1 + CITATION.cff | 5 + CMakeLists.txt | 178 +++++++++++- docs/CHANGELOG.md | 5 + .../include/cpu_features_macros.h | 4 +- .../cpu_features/include/cpuinfo_aarch64.h | 43 +++ .../cpu_features/include/internal/hwcaps.h | 18 ++ .../src/impl_aarch64__base_implementation.inl | 23 +- .../cpu_features/test/cpuinfo_aarch64_test.cc | 18 ++ .../signal_source/adapters/CMakeLists.txt | 19 +- .../adapters/ad936x_custom_signal_source.cc | 17 +- .../adrv9361_z7035_signal_source_fpga.cc | 67 ++--- .../adrv9361_z7035_signal_source_fpga.h | 13 +- .../adapters/fmcomms5_signal_source_fpga.cc | 57 ++-- .../adapters/fmcomms5_signal_source_fpga.h | 13 +- .../adapters/ion_gsms_signal_source.cc | 239 +++++++++++++++ .../adapters/ion_gsms_signal_source.h | 85 ++++++ .../max2771_evkit_signal_source_fpga.cc | 21 +- .../max2771_evkit_signal_source_fpga.h | 4 +- .../gnuradio_blocks/CMakeLists.txt | 13 +- .../gnuradio_blocks/ad936x_iio_source.cc | 114 +++++--- .../gnuradio_blocks/ad936x_iio_source.h | 70 ++--- .../signal_source/gnuradio_blocks/ion_gsms.cc | 202 +++++++++++++ .../signal_source/gnuradio_blocks/ion_gsms.h | 74 +++++ .../signal_source/libs/CMakeLists.txt | 28 +- .../signal_source/libs/ad9361_manager.cc | 4 +- .../signal_source/libs/ad936x_iio_custom.cc | 214 ++++++++------ .../signal_source/libs/ad936x_iio_custom.h | 64 ++--- .../signal_source/libs/ad936x_iio_samples.cc | 25 -- .../signal_source/libs/ad936x_iio_samples.h | 24 +- .../signal_source/libs/ion_gsms_chunk_data.cc | 271 ++++++++++++++++++ .../signal_source/libs/ion_gsms_chunk_data.h | 188 ++++++++++++ .../libs/ion_gsms_chunk_unpacking_ctx.h | 184 ++++++++++++ .../libs/ion_gsms_stream_encodings.h | 170 +++++++++++ src/algorithms/signal_source/libs/ppstcprx.cc | 25 +- src/algorithms/signal_source/libs/ppstcprx.h | 12 +- src/core/receiver/CMakeLists.txt | 8 + src/core/receiver/gnss_block_factory.cc | 20 +- 39 files changed, 2153 insertions(+), 388 deletions(-) create mode 100644 src/algorithms/signal_source/adapters/ion_gsms_signal_source.cc create mode 100644 src/algorithms/signal_source/adapters/ion_gsms_signal_source.h create mode 100644 src/algorithms/signal_source/gnuradio_blocks/ion_gsms.cc create mode 100644 src/algorithms/signal_source/gnuradio_blocks/ion_gsms.h delete mode 100644 src/algorithms/signal_source/libs/ad936x_iio_samples.cc create mode 100644 src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc create mode 100644 src/algorithms/signal_source/libs/ion_gsms_chunk_data.h create mode 100644 src/algorithms/signal_source/libs/ion_gsms_chunk_unpacking_ctx.h create mode 100644 src/algorithms/signal_source/libs/ion_gsms_stream_encodings.h diff --git a/.gitignore b/.gitignore index 4a50387fa..4afd17279 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,3 @@ HAS_* gnss_sdr_pvt.nmea build-debug/ build-release/ - diff --git a/AUTHORS b/AUTHORS index ad0660662..7df41ed17 100644 --- a/AUTHORS +++ b/AUTHORS @@ -64,6 +64,7 @@ Marc Sales marcsales92@gmail.com Contributor Piyush Gupta piyush04111999@gmail.com Contributor Rodrigo Muñoz rodrigo.munoz@proteinlab.cl Contributor Stefan van der Linden spvdlinden@gmail.com Contributor +Víctor Castillo-Agüero victorcastilloaguero@gmail.com Contributor Will Silberman wsilberm@google.com Contributor Carlos Paniego carpanie@hotmail.com Artwork diff --git a/CITATION.cff b/CITATION.cff index 0f11b55f1..4bf27081f 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -34,6 +34,11 @@ authors: email: mara.branzanti@gmail.com family-names: Branzanti given-names: Mara + - alias: castle055 + affiliation: "Instituto Nacional de Técnica Aeroespacial" + email: victorcastilloaguero@gmail.com + family-names: "Castillo-Agüero" + given-names: Víctor - alias: acebrianjuan email: acebrianjuan@gmail.com family-names: "Cebrián-Juan" diff --git a/CMakeLists.txt b/CMakeLists.txt index c10936ca1..39132e9cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,8 @@ option(ENABLE_ARRAY "Enable the use of CTTC's antenna array front-end as signal option(ENABLE_ZMQ "Enable GNU Radio ZeroMQ Messaging, requires gr-zeromq" ON) +option(ENABLE_ION "Enable ION GNSS-SDR Metadata Standard signal source" OFF) + # Performance analysis tools option(ENABLE_GPERFTOOLS "Enable linking to Gperftools libraries (tcmalloc and profiler)" OFF) @@ -358,12 +360,12 @@ set(GNSSSDR_ARMADILLO_LOCAL_VERSION "14.0.x") set(GNSSSDR_GFLAGS_LOCAL_VERSION "2.2.2") set(GNSSSDR_GLOG_LOCAL_VERSION "0.7.1") set(GNSSSDR_MATIO_LOCAL_VERSION "1.5.27") -set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "27.3") +set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "28.0") set(GNSSSDR_PUGIXML_LOCAL_VERSION "1.14") set(GNSSSDR_GTEST_LOCAL_VERSION "1.15.2") set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "origin/master") set(GNSSSDR_GNSSTK_LOCAL_VERSION "14.3.0") -set(GNSSSDR_BENCHMARK_LOCAL_VERSION "1.8.5") +set(GNSSSDR_BENCHMARK_LOCAL_VERSION "1.9.0") set(GNSSSDR_MATHJAX_EXTERNAL_VERSION "2.7.7") set(GNSSSDR_ABSL_LOCAL_VERSION "origin/master") # live at head (see https://abseil.io/about/releases) @@ -3252,7 +3254,7 @@ set_package_properties(LIBIIO PROPERTIES PURPOSE "Used for communication with the AD9361 chipset." TYPE OPTIONAL ) -if(ENABLE_AD9361 OR ENABLE_FMCOMMS2) +if(ENABLE_AD9361 OR ENABLE_FMCOMMS2 OR ENABLE_PLUTOSDR) if(NOT LIBIIO_FOUND) message(STATUS "libiio not found, its installation is required.") message(STATUS "Please build and install the following projects:") @@ -3270,6 +3272,161 @@ if(ENABLE_AD9361 OR ENABLE_FMCOMMS2) endif() +################################################################################ +# ION GNSS-SDR Metadata Standard https://sdr.ion.org/ (OPTIONAL) +################################################################################ +if(CMAKE_VERSION VERSION_LESS 3.14) + set(ENABLE_ION OFF) # FetchContent_MakeAvailable is available from CMake 3.14 +endif() +if(ENABLE_ION) + include(FetchContent) + set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) + FetchContent_Declare( + gnss_metadata_standard + GIT_REPOSITORY https://github.com/IonMetadataWorkingGroup/GNSS-Metadata-Standard + GIT_TAG 220d116e10db5e403e21b77a1fa25aa35feda198 + SOURCE_DIR ${GNSSSDR_BINARY_DIR}/thirdparty/gnss-metadata-standard + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${GNSSSDR_BINARY_DIR}/gnss-metadata-standard + BINARY_DIR ${GNSSSDR_BINARY_DIR}/gnss-metadata-standard + ) + FetchContent_MakeAvailable(gnss_metadata_standard) + + if(NOT TARGET ION::ion) + add_library(ION::ion STATIC IMPORTED) + add_dependencies(ION::ion gnss_metadata_standard) + if(CMAKE_GENERATOR STREQUAL "Xcode") + set_target_properties(ION::ion PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION_DEBUG "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}" + IMPORTED_LOCATION_RELEASE "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Release/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}" + IMPORTED_LOCATION_RELWITHDEBINFO "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}" + IMPORTED_LOCATION_MINSIZEREL "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/MinSizeRel/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}" + INTERFACE_INCLUDE_DIRECTORIES "${GNSSSDR_BINARY_DIR}/thirdparty/gnss-metadata-standard/source/api/inc" + ) + set_property(TARGET ION::ion APPEND PROPERTY + INTERFACE_LINK_LIBRARIES + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Release/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Release/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/MinSizeRel/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/MinSizeRel/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/RelWithDebInfo/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + "$<$:${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/Debug/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}>" + ) + else() + set_target_properties(ION::ion PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX}" + INTERFACE_INCLUDE_DIRECTORIES "${GNSSSDR_BINARY_DIR}/thirdparty/gnss-metadata-standard/source/api/inc" + INTERFACE_LINK_LIBRARIES "${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/GnssMetadata/${CMAKE_FIND_LIBRARY_PREFIXES}api${CMAKE_STATIC_LIBRARY_SUFFIX};${GNSSSDR_BINARY_DIR}/gnss-metadata-standard/source/api/lib/tinyxml2/${CMAKE_FIND_LIBRARY_PREFIXES}xml${CMAKE_STATIC_LIBRARY_SUFFIX}" + ) + endif() + endif() +endif() + + +##################################################################### +# Check signal sources related to FPGA only. +##################################################################### +if(ENABLE_MAX2771 AND NOT ENABLE_FPGA) + message(STATUS "The SPIdev driver is enabled, but the FPGA is not enabled. The FPGA is required when using the SPIdev driver.") + if(ENABLE_PACKAGING) + set(ENABLE_MAX2771 OFF) + else() + message(FATAL_ERROR "ENABLE_MAX2771 can only be set when ENABLE_FPGA is also set.") + endif() +endif() +if(ENABLE_DMA_PROXY AND NOT ENABLE_FPGA) + message(STATUS "The DMA Proxy driver is enabled, but the FPGA is not enabled. The FPGA is required when using the DMA Proxy driver.") + if(ENABLE_PACKAGING) + set(ENABLE_DMA_PROXY OFF) + else() + message(FATAL_ERROR "ENABLE_DMA_PROXY can only be set when ENABLE_FPGA is also set.") + endif() +endif() + + + +##################################################################### +# spidev driver - OPTIONAL +# Linux kernel driver that provides user-space access to Serial +# Peripheral Interface) +##################################################################### +if(ENABLE_MAX2771) + if(DEFINED ENV{SDKTARGETSYSROOT}) + set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT}) + else() + set(TARGET_ROOTFS_PATH "") + endif() + find_program(STRINGS_EXECUTABLE strings) + if(NOT STRINGS_EXECUTABLE) + message(STATUS "The 'strings' command could not be found. See https://www.gnu.org/software/binutils/") + message(STATUS " You can try to install it by typing:") + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|kFreeBSD|GNU") + if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") + message(STATUS " sudo yum install binutils") + elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") + message(STATUS " sudo zypper install binutils") + else() + message(STATUS " sudo apt-get install binutils") + endif() + endif() + message(FATAL_ERROR "Binutils are required to build GNSS-SDR for SoC FPGA devices using the MAX2771 option.") + endif() + set(DTB_FILE "${TARGET_ROOTFS_PATH}/boot/devicetree/system-top.dtb") + if(EXISTS "${DTB_FILE}") + message(STATUS "Found DTB file: ${DTB_FILE}") + # Run the strings command and grep for "spidev" + execute_process( + COMMAND ${STRINGS_EXECUTABLE} ${DTB_FILE} + COMMAND grep "spidev" + OUTPUT_VARIABLE GREP_OUTPUT + RESULT_VARIABLE GREP_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(GREP_RESULT EQUAL 0) + message(STATUS "Found spidev-compatible peripheral in ${DTB_FILE}.") + else() + message(STATUS "SPIdev driver not found, its installation is required.") + if(ENABLE_PACKAGING) + set(ENABLE_MAX2771 OFF) + else() + message(FATAL_ERROR "SPIdev driver is required for building gnss-sdr with -DENABLE_MAX2271=ON.") + endif() + endif() + else() + message(FATAL_ERROR "The device tree (DTB) file ${DTB_FILE} cannot be found.") + endif() +endif() + + + +##################################################################### +# DMA Proxy driver - OPTIONAL +# Simplified and efficient interface for user-space applications +# to leverage DMA capabilities for Xilinx FPGA and SoC systems +##################################################################### +if(ENABLE_DMA_PROXY) + if(DEFINED ENV{SDKTARGETSYSROOT}) + set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT}) + else() + set(TARGET_ROOTFS_PATH "") + endif() + set(DMA_PROXY_FILE "${TARGET_ROOTFS_PATH}/lib/modules/5.10.0-xilinx-v2021.2/extra/dma-proxy.ko") + if(EXISTS "${DMA_PROXY_FILE}") + message(STATUS "Found dma-proxy.ko file: ${DMA_PROXY_FILE}") + else() + if(ENABLE_PACKAGING) + set(ENABLE_DMA_PROXY OFF) + else() + message(FATAL_ERROR "DMA Proxy driver is required for building gnss-sdr with -DENABLE_DMA_PROXY=ON.") + endif() + endif() +endif() + + ##################################################################### # Check signal sources related to FPGA only. @@ -3573,23 +3730,24 @@ add_subdirectory(src) add_feature_info(ENABLE_UHD ENABLE_UHD "Enables UHD_Signal_Source for using RF front-ends from the USRP family. Requires gr-uhd.") add_feature_info(ENABLE_OSMOSDR ENABLE_OSMOSDR "Enables Osmosdr_Signal_Source and RtlTcp_Signal_Source for using RF front-ends compatible with the OsmoSDR driver. Requires gr-osmosdr.") add_feature_info(ENABLE_LIMESDR ENABLE_LIMESDR "Enables Limesdr_Signal_Source. Requires gr-limesdr.") -add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires gr-iio and libad9361-dev.") -add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source for using ADALM-PLUTO boards. Requires gr-iio.") -add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables Ad9361_Fpga_Signal_Source for devices with the AD9361 chipset. Requires libiio and libad9361-dev.") -add_feature_info(ENABLE_MAX2771 ENABLE_MAX2771 "Enables FPGA_MAX2771_EVKIT_Signal_Source for devices with the MAX2771 chipset. Requires the spidev driver") -add_feature_info(ENABLE_DMA_PROXY ENABLE_DMA_PROXY "Enables DMA Signal_Source. Requires the DMA Proxy driver") -add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Iio_Signal_Source to access AD936X front-ends using libiio. Requires libiio and libad9361-dev.") +add_feature_info(ENABLE_FMCOMMS2 ENABLE_FMCOMMS2 "Enables Fmcomms2_Signal_Source for FMCOMMS2/3/4 devices. Requires libiio, libad9361-dev, and gr-iio.") +add_feature_info(ENABLE_PLUTOSDR ENABLE_PLUTOSDR "Enables Plutosdr_Signal_Source and Ad936x_Custom_Signal_Source for using ADALM-PLUTO boards. Requires libiio, libad9361-dev, and gr-iio.") +add_feature_info(ENABLE_AD936X_SDR ENABLE_AD936X_SDR "Enables Ad936x_Custom_Signal_Source for using ADALM-PLUTO boards with custom firmware. Requires libiio and libad9361-dev.") +add_feature_info(ENABLE_FPGA ENABLE_FPGA "Enables building of processing blocks for FPGA offloading.") +add_feature_info(ENABLE_AD9361 ENABLE_AD9361 "Enables ADRV9361_Z7035_Signal_Source_FPGA and the FMCOMMS5_Signal_Source_FPGA for FPGA SoC devices with the AD9361 chipset. Requires libiio, libad9361-dev, and -DENABLE_FPGA=ON.") +add_feature_info(ENABLE_MAX2771 ENABLE_MAX2771 "Enables FPGA_MAX2771_EVKIT_Signal_Source for FPGA SoC devices with the with the MAX2771 chipset. Requires the spidev driver and -DENABLE_FPGA=ON.") +add_feature_info(ENABLE_DMA_PROXY ENABLE_DMA_PROXY "Enables DMA_Signal_Source_FPGA for file post-processing in FPGA SoC devices. Requires the DMA Proxy driver and -DENABLE_FPGA=ON.") add_feature_info(ENABLE_RAW_UDP ENABLE_RAW_UDP "Enables Custom_UDP_Signal_Source for custom UDP packet sample source. Requires libpcap.") add_feature_info(ENABLE_FLEXIBAND ENABLE_FLEXIBAND "Enables Flexiband_Signal_Source for using Teleorbit's Flexiband RF front-end. Requires gr-teleorbit.") add_feature_info(ENABLE_ARRAY ENABLE_ARRAY "Enables Raw_Array_Signal_Source and Array_Signal_Conditioner for using CTTC's antenna array. Requires gr-dbfcttc.") add_feature_info(ENABLE_ZMQ ENABLE_ZMQ "Enables ZMQ_Signal_Source for GNU Radio ZeroMQ messages. Requires gr-zeromq.") +add_feature_info(ENABLE_ION ENABLE_ION "Enables ION_GSMS_Signal_Source for the ION Metadata Standard.") add_feature_info(ENABLE_GPERFTOOLS ENABLE_GPERFTOOLS "Enables performance analysis. Requires Gperftools.") add_feature_info(ENABLE_GPROF ENABLE_GPROF "Enables performance analysis with 'gprof'.") add_feature_info(ENABLE_CLANG_TIDY ENABLE_CLANG_TIDY "Runs clang-tidy along with the compiler. Requires Clang.") add_feature_info(ENABLE_PROFILING ENABLE_PROFILING "Runs volk_gnsssdr_profile at the end of the building.") add_feature_info(ENABLE_OPENCL ENABLE_OPENCL "Enables GPS_L1_CA_PCPS_OpenCl_Acquisition (experimental). Requires OpenCL.") add_feature_info(ENABLE_CUDA ENABLE_CUDA "Enables GPS_L1_CA_DLL_PLL_Tracking_GPU (experimental). Requires CUDA.") -add_feature_info(ENABLE_FPGA ENABLE_FPGA "Enables building of processing blocks for FPGA offloading.") add_feature_info(ENABLE_ARMA_NO_DEBUG ENABLE_ARMA_NO_DEBUG "Enables passing the ARMA_NO_DEBUG macro to Armadillo, hence disabling bound checking.") add_feature_info(ENABLE_PACKAGING ENABLE_PACKAGING "Enables software packaging.") add_feature_info(ENABLE_OWN_GLOG ENABLE_OWN_GLOG "Forces the downloading and building of Google glog.") diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3963e0b20..327b26a8d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -41,6 +41,11 @@ All notable changes to GNSS-SDR will be documented in this file. - `-DENABLE_DMA_PROXY`: Checks if the DMA proxy driver is installed for controlling the DMA in the FPGA and enables its usage. +- Add the `ION_GSMS_Signal_Source`, which is able to process raw data files + described with the + [ION GNSS Software Defined Receiver Metadata Standard](https://sdr.ion.org/). + It requires the `-DENABLE_ION=ON` building configuration option. + ### Improvements in Portability: - Fix building against google-glog 0.7.x. diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpu_features_macros.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpu_features_macros.h index 42b4e55b1..c800d0c32 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpu_features_macros.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpu_features_macros.h @@ -227,11 +227,11 @@ #endif // defined(CPU_FEATURES_ARCH_X86) #if defined(CPU_FEATURES_ARCH_ANY_ARM) -#if defined(__ARM_NEON__) +#if defined(__ARM_NEON) #define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1 #else #define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0 -#endif // defined(__ARM_NEON__) +#endif // defined(__ARM_NEON) #endif // defined(CPU_FEATURES_ARCH_ANY_ARM) #if defined(CPU_FEATURES_ARCH_MIPS) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_aarch64.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_aarch64.h index a8cb0d41a..41108b6ec 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_aarch64.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpuinfo_aarch64.h @@ -182,6 +182,31 @@ typedef struct int smef16f16 : 1; // FP16 to FP16 outer product. int mops : 1; // Standardized memory operations. int hbc : 1; // Hinted conditional branches. + int sveb16b16 : 1; // Non-widening BFloat16 to BFloat16 arithmetic for SVE2 + // and SME2. + int lrcpc3 : 1; // Load-Acquire RCpc instructions version 3. + int lse128 : 1; // 128-bit Atomics. + int fpmr : 1; // Floating-point Mode Register. + int lut : 1; // Lookup table instructions with 2-bit and 4-bit indices. + int faminmax : 1; // Maximum and minimum absolute value instructions. + int f8cvt : 1; // FP scaling instructions and FP8 convert instructions. + int f8fma : 1; // FP8 to single-precision and half-precision + // multiply-accumulate instructions. + int f8dp4 : 1; // FP8 to single-precision 4-way dot product FDOT (4-way) + // instructions. + int f8dp2 : 1; // FP8 to half-precision 2-way dot product FDOT (2-way) + // instructions. + int f8e4m3 : 1; // Arm FP8 E4M3 format. + int f8e5m2 : 1; // Arm FP8 E5M2 format. + int smelutv2 : 1; // SME2 lookup table LUTI4 and MOVT instructions. + int smef8f16 : 1; // SME2 F8F16 instructions. + int smef8f32 : 1; // SME2 F8F32 instructions. + int smesf8fma : 1; // SVE2 FP8 to single-precision and half-precision + // multiply-accumulate instructions. + int smesf8dp4 : 1; // SVE2 FP8 to single-precision 4-way dot product FDOT + // (4-way) instructions. + int smesf8dp2 : 1; // SVE2 FP8 to half-precision 2-way dot product FDOT + // (2-way) instructions. // Make sure to update Aarch64FeaturesEnum below if you add a field here. } Aarch64Features; @@ -280,6 +305,24 @@ typedef enum AARCH64_SME_F16F16, AARCH64_MOPS, AARCH64_HBC, + AARCH64_SVE_B16B16, + AARCH64_LRCPC3, + AARCH64_LSE128, + AARCH64_FPMR, + AARCH64_LUT, + AARCH64_FAMINMAX, + AARCH64_F8CVT, + AARCH64_F8FMA, + AARCH64_F8DP4, + AARCH64_F8DP2, + AARCH64_F8E4M3, + AARCH64_F8E5M2, + AARCH64_SME_LUTV2, + AARCH64_SME_F8F16, + AARCH64_SME_F8F32, + AARCH64_SME_SF8FMA, + AARCH64_SME_SF8DP4, + AARCH64_SME_SF8DP2, AARCH64_LAST_, } Aarch64FeaturesEnum; diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/internal/hwcaps.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/internal/hwcaps.h index 63baa1fff..3f500f606 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/internal/hwcaps.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/internal/hwcaps.h @@ -94,6 +94,24 @@ CPU_FEATURES_START_CPP_NAMESPACE #define AARCH64_HWCAP2_SME_F16F16 (1UL << 42) #define AARCH64_HWCAP2_MOPS (1UL << 43) #define AARCH64_HWCAP2_HBC (1UL << 44) +#define AARCH64_HWCAP2_SVE_B16B16 (1UL << 45) +#define AARCH64_HWCAP2_LRCPC3 (1UL << 46) +#define AARCH64_HWCAP2_LSE128 (1UL << 47) +#define AARCH64_HWCAP2_FPMR (1UL << 48) +#define AARCH64_HWCAP2_LUT (1UL << 49) +#define AARCH64_HWCAP2_FAMINMAX (1UL << 50) +#define AARCH64_HWCAP2_F8CVT (1UL << 51) +#define AARCH64_HWCAP2_F8FMA (1UL << 52) +#define AARCH64_HWCAP2_F8DP4 (1UL << 53) +#define AARCH64_HWCAP2_F8DP2 (1UL << 54) +#define AARCH64_HWCAP2_F8E4M3 (1UL << 55) +#define AARCH64_HWCAP2_F8E5M2 (1UL << 56) +#define AARCH64_HWCAP2_SME_LUTV2 (1UL << 57) +#define AARCH64_HWCAP2_SME_F8F16 (1UL << 58) +#define AARCH64_HWCAP2_SME_F8F32 (1UL << 59) +#define AARCH64_HWCAP2_SME_SF8FMA (1UL << 60) +#define AARCH64_HWCAP2_SME_SF8DP4 (1UL << 61) +#define AARCH64_HWCAP2_SME_SF8DP2 (1UL << 62) // http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h #define ARM_HWCAP_SWP (1UL << 0) diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/impl_aarch64__base_implementation.inl b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/impl_aarch64__base_implementation.inl index 14be5a726..d0057ee10 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/impl_aarch64__base_implementation.inl +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/src/impl_aarch64__base_implementation.inl @@ -103,7 +103,28 @@ LINE(AARCH64_SME_F16F16, smef16f16, "smef16f16", 0, \ AARCH64_HWCAP2_SME_F16F16) \ LINE(AARCH64_MOPS, mops, "mops", 0, AARCH64_HWCAP2_MOPS) \ - LINE(AARCH64_HBC, hbc, "hbc", 0, AARCH64_HWCAP2_HBC) + LINE(AARCH64_HBC, hbc, "hbc", 0, AARCH64_HWCAP2_HBC) \ + LINE(AARCH64_SVE_B16B16, sveb16b16, "sveb16b16", 0, \ + AARCH64_HWCAP2_SVE_B16B16) \ + LINE(AARCH64_LRCPC3, lrcpc3, "lrcpc3", 0, AARCH64_HWCAP2_LRCPC3) \ + LINE(AARCH64_LSE128, lse128, "lse128", 0, AARCH64_HWCAP2_LSE128) \ + LINE(AARCH64_FPMR, fpmr, "fpmr", 0, AARCH64_HWCAP2_FPMR) \ + LINE(AARCH64_LUT, lut, "lut", 0, AARCH64_HWCAP2_LUT) \ + LINE(AARCH64_FAMINMAX, faminmax, "faminmax", 0, AARCH64_HWCAP2_FAMINMAX) \ + LINE(AARCH64_F8CVT, f8cvt, "f8cvt", 0, AARCH64_HWCAP2_F8CVT) \ + LINE(AARCH64_F8FMA, f8fma, "f8fma", 0, AARCH64_HWCAP2_F8FMA) \ + LINE(AARCH64_F8DP4, f8dp4, "f8dp4", 0, AARCH64_HWCAP2_F8DP4) \ + LINE(AARCH64_F8DP2, f8dp2, "f8dp2", 0, AARCH64_HWCAP2_F8DP2) \ + LINE(AARCH64_F8E4M3, f8e4m3, "f8e4m3", 0, AARCH64_HWCAP2_F8E4M3) \ + LINE(AARCH64_F8E5M2, f8e5m2, "f8e5m2", 0, AARCH64_HWCAP2_F8E5M2) \ + LINE(AARCH64_SME_LUTV2, smelutv2, "smelutv1", 0, AARCH64_HWCAP2_SME_LUTV2) \ + LINE(AARCH64_SME_F8F16, smef8f16, "smef8f16", 0, AARCH64_HWCAP2_SME_F8F16) \ + LINE(AARCH64_SME_F8F32, smef8f32, "smef8f32", 0, AARCH64_HWCAP2_SME_F8F32) \ + LINE(AARCH64_SME_SF8FMA, smesf8fma, "smesf8fma", 0, \ + AARCH64_HWCAP2_SME_SF8FMA) \ + LINE(AARCH64_SME_SF8DP4, smesf8dp4, "smesf8dp4", 0, \ + AARCH64_HWCAP2_SME_SF8DP4) \ + LINE(AARCH64_SME_SF8DP2, smesf8dp2, "smesf8dp2", 0, AARCH64_HWCAP2_SME_SF8DP2) #define INTROSPECTION_PREFIX Aarch64 #define INTROSPECTION_ENUM_PREFIX AARCH64 #include "define_introspection_and_hwcaps.inl" \ No newline at end of file diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_aarch64_test.cc b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_aarch64_test.cc index fc8abf8fe..e69c5ef78 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_aarch64_test.cc +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/test/cpuinfo_aarch64_test.cc @@ -326,6 +326,24 @@ CPU revision : 3)"); EXPECT_FALSE(info.features.smef16f16); EXPECT_FALSE(info.features.mops); EXPECT_FALSE(info.features.hbc); + EXPECT_FALSE(info.features.sveb16b16); + EXPECT_FALSE(info.features.lrcpc3); + EXPECT_FALSE(info.features.lse128); + EXPECT_FALSE(info.features.fpmr); + EXPECT_FALSE(info.features.lut); + EXPECT_FALSE(info.features.faminmax); + EXPECT_FALSE(info.features.f8cvt); + EXPECT_FALSE(info.features.f8fma); + EXPECT_FALSE(info.features.f8dp4); + EXPECT_FALSE(info.features.f8dp2); + EXPECT_FALSE(info.features.f8e4m3); + EXPECT_FALSE(info.features.f8e5m2); + EXPECT_FALSE(info.features.smelutv2); + EXPECT_FALSE(info.features.smef8f16); + EXPECT_FALSE(info.features.smef8f32); + EXPECT_FALSE(info.features.smesf8fma); + EXPECT_FALSE(info.features.smesf8dp4); + EXPECT_FALSE(info.features.smesf8dp2); } #elif defined(CPU_FEATURES_OS_MACOS) TEST_F(CpuidAarch64Test, FromDarwinSysctlFromName) diff --git a/src/algorithms/signal_source/adapters/CMakeLists.txt b/src/algorithms/signal_source/adapters/CMakeLists.txt index 0aa745101..48e18e5f3 100644 --- a/src/algorithms/signal_source/adapters/CMakeLists.txt +++ b/src/algorithms/signal_source/adapters/CMakeLists.txt @@ -25,6 +25,14 @@ if(ENABLE_PLUTOSDR) set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_custom_signal_source.h) endif() +if(ENABLE_AD936X_SDR AND NOT ENABLE_PLUTOSDR) + ############################################## + # CUSTOM AD936X IIO SOURCE + ############################################## + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_custom_signal_source.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_custom_signal_source.h) +endif() + if(ENABLE_FMCOMMS2) ############################################### # FMCOMMS2 based SDR Hardware @@ -103,6 +111,11 @@ if(ENABLE_ZMQ) list(APPEND OPT_DRIVER_HEADERS zmq_signal_source.h) endif() +if(ENABLE_ION) + list(APPEND OPT_DRIVER_SOURCES ion_gsms_signal_source.cc) + list(APPEND OPT_DRIVER_HEADERS ion_gsms_signal_source.h) +endif() + set(SIGNAL_SOURCE_ADAPTER_SOURCES signal_source_base.cc file_source_base.cc @@ -169,7 +182,7 @@ target_include_directories(signal_source_adapters ${GNSSSDR_SOURCE_DIR}/src/core/interfaces ) -if(ENABLE_FPGA OR ENABLE_AD9361) +if(ENABLE_FPGA OR ENABLE_AD9361 OR ENABLE_ION) target_link_libraries(signal_source_adapters PUBLIC signal_source_libs @@ -239,14 +252,14 @@ if(ENABLE_LIMESDR AND GRLIMESDR_FOUND) ) endif() -if(ENABLE_AD9361 AND LIBIIO_FOUND) +if(LIBIIO_FOUND) target_link_libraries(signal_source_adapters PRIVATE Iio::iio ) endif() -if(ENABLE_AD9361 OR ENABLE_FMCOMMS2 OR ENABLE_PLUTOSDR) +if(ENABLE_AD9361 OR ENABLE_FMCOMMS2 OR ENABLE_PLUTOSDR OR ENABLE_AD936X_SDR) if(LIBAD9361_VERSION) if(LIBAD9361_VERSION VERSION_GREATER 0.1) target_compile_definitions(signal_source_adapters diff --git a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc index b93dc9344..b824a250d 100644 --- a/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc +++ b/src/algorithms/signal_source/adapters/ad936x_custom_signal_source.cc @@ -76,8 +76,11 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* item_size_ = sizeof(gr_complex); // 1. Make the driver instance bool customsamplesize = false; - if (ssize_ != 12 or spattern_ == true) customsamplesize = true; // custom FPGA DMA firmware - if (ssize_ == 12) // default original FPGA DMA firmware + if (ssize_ != 12 || spattern_ == true) + { + customsamplesize = true; // custom FPGA DMA firmware + } + if (ssize_ == 12) // default original FPGA DMA firmware { ssize_ = 16; // set to 16 bits and do not try to change sample size } @@ -153,8 +156,14 @@ Ad936xCustomSignalSource::Ad936xCustomSignalSource(const ConfigurationInterface* for (int n = 0; n < n_channels; n++) { - if (n == 0) inverted_spectrum_vec.push_back(inverted_spectrum_ch0_); - if (n == 1) inverted_spectrum_vec.push_back(inverted_spectrum_ch1_); + if (n == 0) + { + inverted_spectrum_vec.push_back(inverted_spectrum_ch0_); + } + if (n == 1) + { + inverted_spectrum_vec.push_back(inverted_spectrum_ch1_); + } } for (int n = 0; n < n_channels; n++) diff --git a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc index 9d29e2de2..897dd7777 100644 --- a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc +++ b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.cc @@ -1,6 +1,6 @@ /*! * \file adrv9361_z7035_signal_source_fpga.cc - * \brief signal source for the Analog Devices ADRV9361-Z7035 evaluation board + * \brief Signal source for the Analog Devices ADRV9361-Z7035 evaluation board * directly connected to the FPGA accelerators. * This source implements only the AD9361 control. It is NOT compatible with * conventional SDR acquisition and tracking blocks. @@ -51,14 +51,14 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), + filter_source_(configuration->property(role + ".filter_source", std::string("Off"))), filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), scale_dds_dbfs_(configuration->property(role + ".scale_dds_dbfs", -3.0)), phase_dds_deg_(configuration->property(role + ".phase_dds_deg", 0.0)), tx_attenuation_db_(configuration->property(role + ".tx_attenuation_db", default_tx_attenuation_db)), - freq0_(configuration->property(role + ".freq", 0)), - freq1_(configuration->property(role + ".freq1", static_cast(GPS_L5_FREQ_HZ))), + freq0_(configuration->property(role + ".freq", GPS_L5_FREQ_HZ)), sample_rate_(configuration->property(role + ".sampling_frequency", default_bandwidth)), bandwidth_(configuration->property(role + ".bandwidth", default_bandwidth)), freq_dds_tx_hz_(configuration->property(role + ".freq_dds_tx_hz", uint64_t(10000))), @@ -70,7 +70,6 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration out_stream_(out_stream), item_size_(sizeof(int8_t)), enable_dds_lo_(configuration->property(role + ".enable_dds_lo", false)), - filter_auto_(configuration->property(role + ".filter_auto", false)), quadrature_(configuration->property(role + ".quadrature", true)), rf_dc_(configuration->property(role + ".rf_dc", true)), bb_dc_(configuration->property(role + ".bb_dc", true)), @@ -98,15 +97,6 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration freq0_ = configuration->property(role + ".freq0", static_cast(GPS_L1_FREQ_HZ)); } - if (filter_auto_) - { - filter_source_ = configuration->property(role + ".filter_source", std::string("Auto")); - } - else - { - filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); - } - switch_fpga = std::make_shared(); switch_fpga->set_switch_position(switch_to_real_time_mode); @@ -190,12 +180,15 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration } std::cout << "LO frequency : " << freq0_ << " Hz\n"; + + uint64_t freq1 = 0; // The local oscillator frequency of the ADRV9361-B is not used when using the ADRV9361-Z7035 board. + try { config_ad9361_rx_local(bandwidth_, sample_rate_, freq0_, - freq1_, + freq1, rf_port_select_, rx1_enable_, rx2_enable_, @@ -257,7 +250,6 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration buffer_monitor_fpga = std::make_shared(num_freq_bands, dump_, dump_filename); thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); - // dynamic bits selection if (enable_dynamic_bit_selection_) { @@ -278,15 +270,23 @@ Adrv9361z7035SignalSourceFPGA::Adrv9361z7035SignalSourceFPGA(const Configuration Adrv9361z7035SignalSourceFPGA::~Adrv9361z7035SignalSourceFPGA() { - /* cleanup and exit */ - + // cleanup and exit if (rf_shutdown_) { std::cout << "* AD9361 Disabling RX streaming channels\n"; - if (!disable_ad9361_rx_local()) + try { - LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; + if (!disable_ad9361_rx_local()) + { + LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; + } } + catch (const std::exception &e) + { + LOG(WARNING) << "Problem shutting down the AD9361 RX channels: " << e.what(); + std::cerr << "Problem shutting down the AD9361 RX channels: " << e.what() << '\n'; + } + if (enable_dds_lo_) { try @@ -301,24 +301,27 @@ Adrv9361z7035SignalSourceFPGA::~Adrv9361z7035SignalSourceFPGA() } // disable buffer overflow checking and buffer monitoring - std::unique_lock lock_buffer_monitor(buffer_monitor_mutex); - enable_ovf_check_buffer_monitor_active_ = false; - lock_buffer_monitor.unlock(); + { + std::lock_guard lock_buffer_monitor(buffer_monitor_mutex); + enable_ovf_check_buffer_monitor_active_ = false; + } if (thread_buffer_monitor.joinable()) { thread_buffer_monitor.join(); } - - std::unique_lock lock_dyn_bit_sel(dynamic_bit_selection_mutex); - bool bit_selection_enabled = enable_dynamic_bit_selection_; - lock_dyn_bit_sel.unlock(); + bool bit_selection_enabled = false; + { + std::lock_guard lock_dyn_bit_sel(dynamic_bit_selection_mutex); + bit_selection_enabled = enable_dynamic_bit_selection_; + } if (bit_selection_enabled == true) { - std::unique_lock lock(dynamic_bit_selection_mutex); - enable_dynamic_bit_selection_ = false; - lock.unlock(); + { + std::lock_guard lock(dynamic_bit_selection_mutex); + enable_dynamic_bit_selection_ = false; + } if (thread_dynamic_bit_selection.joinable()) { @@ -337,12 +340,11 @@ void Adrv9361z7035SignalSourceFPGA::run_dynamic_bit_selection_process() // setting the bit selection to the top bits dynamic_bit_selection_fpga->bit_selection(); std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); - std::unique_lock lock(dynamic_bit_selection_mutex); + std::lock_guard lock(dynamic_bit_selection_mutex); if (enable_dynamic_bit_selection_ == false) { dynamic_bit_selection_active = false; } - lock.unlock(); } } @@ -357,12 +359,11 @@ void Adrv9361z7035SignalSourceFPGA::run_buffer_monitor_process() { buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); - std::unique_lock lock(buffer_monitor_mutex); + std::lock_guard lock(buffer_monitor_mutex); if (enable_ovf_check_buffer_monitor_active_ == false) { enable_ovf_check_buffer_monitor_active = false; } - lock.unlock(); } } diff --git a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h index 5e7e8b7e4..286cde2d5 100644 --- a/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h +++ b/src/algorithms/signal_source/adapters/adrv9361_z7035_signal_source_fpga.h @@ -1,6 +1,6 @@ /*! * \file adrv9361_z7035_signal_source_fpga.h - * \brief signal source for the Analog Devices ADRV9361-Z7035 evaluation board + * \brief Signal source for the Analog Devices ADRV9361-Z7035 evaluation board * directly connected to the FPGA accelerators. * This source implements only the AD9361 control. It is NOT compatible with * conventional SDR acquisition and tracking blocks. @@ -23,7 +23,6 @@ #include "concurrent_queue.h" #include "fpga_buffer_monitor.h" -#include "fpga_dma-proxy.h" #include "fpga_dynamic_bit_selection.h" #include "fpga_switch.h" #include "gnss_block_interface.h" @@ -78,13 +77,14 @@ private: const uint32_t buffer_monitor_period_ms = 1000; // buffer overflow and buffer monitoring initial delay const uint32_t buffer_monitoring_initial_delay_ms = 2000; - // sample block size when running in post-processing mode - const int sample_block_size = 16384; const int32_t switch_to_real_time_mode = 2; void run_dynamic_bit_selection_process(); void run_buffer_monitor_process(); + mutable std::mutex dynamic_bit_selection_mutex; + mutable std::mutex buffer_monitor_mutex; + std::thread thread_dynamic_bit_selection; std::thread thread_buffer_monitor; @@ -92,9 +92,6 @@ private: std::shared_ptr dynamic_bit_selection_fpga; std::shared_ptr buffer_monitor_fpga; - std::mutex dynamic_bit_selection_mutex; - std::mutex buffer_monitor_mutex; - std::string gain_mode_rx1_; std::string gain_mode_rx2_; std::string rf_port_select_; @@ -109,7 +106,6 @@ private: double tx_attenuation_db_; uint64_t freq0_; // frequency of local oscillator for ADRV9361-A 0 - uint64_t freq1_; // frequency of local oscillator for ADRV9361-B (if present) uint64_t sample_rate_; uint64_t bandwidth_; uint64_t freq_dds_tx_hz_; @@ -124,7 +120,6 @@ private: size_t item_size_; bool enable_dds_lo_; - bool filter_auto_; bool quadrature_; bool rf_dc_; bool bb_dc_; diff --git a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc index d8c5a65c0..f52c67425 100644 --- a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc +++ b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.cc @@ -1,6 +1,6 @@ /*! * \file fmcomms5_signal_source_fpga.cc - * \brief signal source for the Analog Devices FMCOMMS5 directly connected + * \brief Signal source for the Analog Devices FMCOMMS5 directly connected * to the FPGA accelerators. * This source implements only the AD9361 control. It is NOT compatible with * conventional SDR acquisition and tracking blocks. @@ -51,6 +51,7 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface gain_mode_rx1_(configuration->property(role + ".gain_mode_rx1", default_gain_mode)), gain_mode_rx2_(configuration->property(role + ".gain_mode_rx2", default_gain_mode)), rf_port_select_(configuration->property(role + ".rf_port_select", default_rf_port_select)), + filter_source_(configuration->property(role + ".filter_source", std::string("Off"))), filter_filename_(configuration->property(role + ".filter_filename", filter_file_)), rf_gain_rx1_(configuration->property(role + ".gain_rx1", default_manual_gain_rx1)), rf_gain_rx2_(configuration->property(role + ".gain_rx2", default_manual_gain_rx2)), @@ -63,7 +64,6 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface in_stream_(in_stream), out_stream_(out_stream), item_size_(sizeof(int8_t)), - filter_auto_(configuration->property(role + ".filter_auto", false)), quadrature_(configuration->property(role + ".quadrature", true)), rf_dc_(configuration->property(role + ".rf_dc", true)), bb_dc_(configuration->property(role + ".bb_dc", true)), @@ -86,15 +86,6 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface const uint32_t num_freq_bands = ((enable_rx1_band == true) and (enable_rx2_band == true)) ? 2 : 1; - if (filter_auto_) - { - filter_source_ = configuration->property(role + ".filter_source", std::string("Auto")); - } - else - { - filter_source_ = configuration->property(role + ".filter_source", std::string("Off")); - } - switch_fpga = std::make_shared(); switch_fpga->set_switch_position(switch_to_real_time_mode); @@ -217,7 +208,6 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface buffer_monitor_fpga = std::make_shared(num_freq_bands, dump_, dump_filename); thread_buffer_monitor = std::thread([&] { run_buffer_monitor_process(); }); - // dynamic bits selection if (enable_dynamic_bit_selection_) { @@ -238,36 +228,45 @@ Fmcomms5SignalSourceFPGA::Fmcomms5SignalSourceFPGA(const ConfigurationInterface Fmcomms5SignalSourceFPGA::~Fmcomms5SignalSourceFPGA() { - /* cleanup and exit */ - + // cleanup and exit if (rf_shutdown_) { std::cout << "* Disabling RX streaming channels\n"; - if (!disable_ad9361_rx_local()) + try { - LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; + if (!disable_ad9361_rx_local()) + { + LOG(WARNING) << "Problem shutting down the AD9361 RX channels"; + } + } + catch (const std::exception &e) + { + std::cerr << "Problem shutting down the AD9361 RX channels: " << e.what() << '\n'; } } // disable buffer overflow checking and buffer monitoring - std::unique_lock lock_buffer_monitor(buffer_monitor_mutex); - enable_ovf_check_buffer_monitor_active_ = false; - lock_buffer_monitor.unlock(); + { + std::lock_guard lock_buffer_monitor(buffer_monitor_mutex); + enable_ovf_check_buffer_monitor_active_ = false; + } if (thread_buffer_monitor.joinable()) { thread_buffer_monitor.join(); } - - std::unique_lock lock_dyn_bit_sel(dynamic_bit_selection_mutex); - bool bit_selection_enabled = enable_dynamic_bit_selection_; - lock_dyn_bit_sel.unlock(); + bool bit_selection_enabled = false; + { + std::lock_guard lock_dyn_bit_sel(dynamic_bit_selection_mutex); + bit_selection_enabled = enable_dynamic_bit_selection_; + } if (bit_selection_enabled == true) { - std::unique_lock lock(dynamic_bit_selection_mutex); - enable_dynamic_bit_selection_ = false; - lock.unlock(); + { + std::lock_guard lock(dynamic_bit_selection_mutex); + enable_dynamic_bit_selection_ = false; + } if (thread_dynamic_bit_selection.joinable()) { @@ -286,12 +285,11 @@ void Fmcomms5SignalSourceFPGA::run_dynamic_bit_selection_process() // setting the bit selection to the top bits dynamic_bit_selection_fpga->bit_selection(); std::this_thread::sleep_for(std::chrono::milliseconds(Gain_control_period_ms)); - std::unique_lock lock(dynamic_bit_selection_mutex); + std::lock_guard lock(dynamic_bit_selection_mutex); if (enable_dynamic_bit_selection_ == false) { dynamic_bit_selection_active = false; } - lock.unlock(); } } @@ -306,12 +304,11 @@ void Fmcomms5SignalSourceFPGA::run_buffer_monitor_process() { buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); - std::unique_lock lock(buffer_monitor_mutex); + std::lock_guard lock(buffer_monitor_mutex); if (enable_ovf_check_buffer_monitor_active_ == false) { enable_ovf_check_buffer_monitor_active = false; } - lock.unlock(); } } diff --git a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h index 1bdcf4e6f..fbb10bf67 100644 --- a/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h +++ b/src/algorithms/signal_source/adapters/fmcomms5_signal_source_fpga.h @@ -1,6 +1,6 @@ /*! * \file fmcomms5_signal_source_fpga.h - * \brief signal source for the Analog Devices FMCOMMS5 directly connected + * \brief Signal source for the Analog Devices FMCOMMS5 directly connected * to the FPGA accelerators. * This source implements only the AD9361 control. It is NOT compatible with * conventional SDR acquisition and tracking blocks. @@ -23,7 +23,6 @@ #include "concurrent_queue.h" #include "fpga_buffer_monitor.h" -#include "fpga_dma-proxy.h" #include "fpga_dynamic_bit_selection.h" #include "fpga_switch.h" #include "gnss_block_interface.h" @@ -67,7 +66,6 @@ private: const std::string default_dump_filename = std::string("FPGA_buffer_monitor_dump.dat"); const std::string default_rf_port_select = std::string("A_BALANCED"); const std::string default_gain_mode = std::string("slow_attack"); - const double default_tx_attenuation_db = -10.0; const double default_manual_gain_rx1 = 64.0; const double default_manual_gain_rx2 = 64.0; const uint64_t default_bandwidth = 12500000; @@ -78,13 +76,14 @@ private: const uint32_t buffer_monitor_period_ms = 1000; // buffer overflow and buffer monitoring initial delay const uint32_t buffer_monitoring_initial_delay_ms = 2000; - // sample block size when running in post-processing mode - const int sample_block_size = 16384; const int32_t switch_to_real_time_mode = 2; void run_dynamic_bit_selection_process(); void run_buffer_monitor_process(); + mutable std::mutex dynamic_bit_selection_mutex; + mutable std::mutex buffer_monitor_mutex; + std::thread thread_dynamic_bit_selection; std::thread thread_buffer_monitor; @@ -92,9 +91,6 @@ private: std::shared_ptr dynamic_bit_selection_fpga; std::shared_ptr buffer_monitor_fpga; - std::mutex dynamic_bit_selection_mutex; - std::mutex buffer_monitor_mutex; - std::string gain_mode_rx1_; std::string gain_mode_rx2_; std::string rf_port_select_; @@ -117,7 +113,6 @@ private: size_t item_size_; - bool filter_auto_; bool quadrature_; bool rf_dc_; bool bb_dc_; diff --git a/src/algorithms/signal_source/adapters/ion_gsms_signal_source.cc b/src/algorithms/signal_source/adapters/ion_gsms_signal_source.cc new file mode 100644 index 000000000..00f2be229 --- /dev/null +++ b/src/algorithms/signal_source/adapters/ion_gsms_signal_source.cc @@ -0,0 +1,239 @@ +/*! + * \file ion_gsms_signal_source.h + * \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "ion_gsms_signal_source.h" +#include "gnss_sdr_flags.h" +#include "gnss_sdr_string_literals.h" +#include "gnss_sdr_valve.h" +#include +#include +#include +#include + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#endif + +using namespace std::string_literals; + +namespace +{ +std::vector parse_comma_list(const std::string& str) +{ + std::vector list{}; + std::size_t prev_comma_at{0}; + + while (prev_comma_at < str.size()) + { + std::size_t comma_at = str.find_first_of(',', prev_comma_at); + if (comma_at == std::string::npos) + { + comma_at = str.size(); + } + list.emplace_back(str.substr(prev_comma_at, (comma_at - prev_comma_at))); + prev_comma_at = comma_at + 1; + } + + return list; +} +} // anonymous namespace + + +IONGSMSSignalSource::IONGSMSSignalSource(const ConfigurationInterface* configuration, + const std::string& role, + unsigned int in_streams, + unsigned int out_streams, + Concurrent_Queue* queue) + : SignalSourceBase(configuration, role, "ION_GSMS_Signal_Source"s), + stream_ids_(parse_comma_list(configuration->property(role + ".streams"s, ""s))), + metadata_filepath_(configuration->property(role + ".metadata_filename"s, "../data/example_capture_metadata.sdrx"s)), + in_streams_(in_streams), + out_streams_(out_streams) +{ + if (in_streams_ > 0) + { + LOG(ERROR) << "A signal source does not have an input stream"; + } + if (out_streams_ <= 0) + { + LOG(ERROR) << "A signal source does not have an output stream"; + } + + // Parse XML metadata file + load_metadata(); + + // Make source vector + sources_ = make_stream_sources(stream_ids_); + + for (const auto& source : sources_) + { + for (std::size_t i = 0; i < source->output_stream_count(); ++i) + { + copy_blocks_.emplace_back(gr::blocks::copy::make(source->output_stream_item_size(i))); + valves_.emplace_back(gnss_sdr_make_valve(source->output_stream_item_size(i), source->output_stream_total_sample_count(i), queue)); + } + } +} + + +void IONGSMSSignalSource::load_metadata() +{ + metadata_ = std::make_shared(); + try + { + GnssMetadata::XmlProcessor xml_proc; + if (!xml_proc.Load(metadata_filepath_.c_str(), false, *metadata_)) + { + LOG(WARNING) << "Could not load XML metadata file " << metadata_filepath_; + std::cerr << "Could not load XML metadata file " << metadata_filepath_ << std::endl; + std::cout << "GNSS-SDR program ended.\n"; + exit(1); + } + } + catch (GnssMetadata::ApiException& e) + { + LOG(WARNING) << "API Exception while loading XML metadata file: " << std::to_string(e.Error()); + std::cerr << "Could not load XML metadata file " << metadata_filepath_ << " : " << std::to_string(e.Error()) << std::endl; + std::cout << "GNSS-SDR program ended.\n"; + exit(1); + } + catch (std::exception& e) + { + LOG(WARNING) << "Exception while loading XML metadata file: " << e.what(); + std::cerr << "Could not load XML metadata file " << metadata_filepath_ << " : " << e.what() << std::endl; + std::cout << "GNSS-SDR program ended.\n"; + exit(1); + } +} + + +std::vector IONGSMSSignalSource::make_stream_sources(const std::vector& stream_ids) const +{ + std::vector sources{}; + for (const auto& file : metadata_->Files()) + { + for (const auto& lane : metadata_->Lanes()) + { + if (lane.Id() == file.Lane().Id()) + { + for (const auto& block : lane.Blocks()) + { + bool block_done = false; + for (const auto& chunk : block.Chunks()) + { + for (const auto& lump : chunk.Lumps()) + { + for (const auto& stream : lump.Streams()) + { + bool found = false; + for (const auto& stream_id : stream_ids) + { + if (stream_id == stream.Id()) + { + found = true; + break; + } + } + if (found) + { + auto source = gnss_make_shared( + metadata_filepath_, + file, + block, + stream_ids); + + sources.push_back(source); + + // This file source will take care of any other matching streams in this block + // We can skip the rest of this block + block_done = true; + break; + } + } + + if (block_done) + { + break; + } + } + if (block_done) + { + break; + } + } + } + break; + } + } + } + + return sources; +} + + +void IONGSMSSignalSource::connect(gr::top_block_sptr top_block) +{ + std::size_t cumulative_index = 0; + for (const auto& source : sources_) + { + for (std::size_t i = 0; i < source->output_stream_count(); ++i, ++cumulative_index) + { + top_block->connect(source, i, copy_blocks_[cumulative_index], 0); + top_block->connect(copy_blocks_[cumulative_index], 0, valves_[cumulative_index], 0); + } + } +} + + +void IONGSMSSignalSource::disconnect(gr::top_block_sptr top_block) +{ + std::size_t cumulative_index = 0; + for (const auto& source : sources_) + { + for (std::size_t i = 0; i < source->output_stream_count(); ++i, ++cumulative_index) + { + top_block->disconnect(source, i, copy_blocks_[cumulative_index], 0); + top_block->disconnect(copy_blocks_[cumulative_index], 0, valves_[cumulative_index], 0); + } + } +} + + +gr::basic_block_sptr IONGSMSSignalSource::get_left_block() +{ + LOG(WARNING) << "Trying to get signal source left block."; + // return gr_basic_block_sptr(); + return IONGSMSFileSource::sptr(); +} + + +gr::basic_block_sptr IONGSMSSignalSource::get_right_block() +{ + return get_right_block(0); +} + + +gr::basic_block_sptr IONGSMSSignalSource::get_right_block(int RF_channel) +{ + if (RF_channel < 0 || RF_channel >= static_cast(copy_blocks_.size())) + { + LOG(WARNING) << "'RF_channel' out of bounds while trying to get signal source right block."; + return valves_[0]; + } + return valves_[RF_channel]; +} diff --git a/src/algorithms/signal_source/adapters/ion_gsms_signal_source.h b/src/algorithms/signal_source/adapters/ion_gsms_signal_source.h new file mode 100644 index 000000000..bcdedbc3d --- /dev/null +++ b/src/algorithms/signal_source/adapters/ion_gsms_signal_source.h @@ -0,0 +1,85 @@ +/*! + * \file ion_gsms_signal_source.h + * \brief GNSS-SDR Signal Source that reads sample streams following ION's GNSS-SDR metadata standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + + +#ifndef GNSS_SDR_ION_GSMS_SIGNAL_SOURCE_H +#define GNSS_SDR_ION_GSMS_SIGNAL_SOURCE_H + +#include "configuration_interface.h" +#include "file_source_base.h" +#include "gnss_sdr_timestamp.h" +#include "ion_gsms.h" +#include +#include +#include +#include +#include + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_adapters + * \{ */ + +/*! + * \brief Class that reads signals samples from a file + * and adapts it to a SignalSourceInterface + */ +class IONGSMSSignalSource : public SignalSourceBase +{ +public: + IONGSMSSignalSource(const ConfigurationInterface* configuration, const std::string& role, + unsigned int in_streams, unsigned int out_streams, + Concurrent_Queue* queue); + + ~IONGSMSSignalSource() override = default; + +protected: + void connect(gr::top_block_sptr top_block) override; + void disconnect(gr::top_block_sptr top_block) override; + + gr::basic_block_sptr get_left_block() override; + gr::basic_block_sptr get_right_block() override; + gr::basic_block_sptr get_right_block(int RF_channel) override; + + inline size_t item_size() override + { + return (*sources_.begin())->output_stream_item_size(0); + } + +private: + std::vector make_stream_sources(const std::vector& stream_ids) const; + + void load_metadata(); + + std::vector stream_ids_; + std::vector sources_; + std::vector> copy_blocks_; + std::vector> valves_; + + std::string metadata_filepath_; + std::shared_ptr metadata_; + + gnss_shared_ptr timestamp_block_; + std::string timestamp_file_; + + uint32_t in_streams_; + uint32_t out_streams_; +}; + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_ION_GSMS_SIGNAL_SOURCE_H diff --git a/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc index 788b50e77..80b310034 100644 --- a/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc +++ b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.cc @@ -140,13 +140,11 @@ MAX2771EVKITSignalSourceFPGA::MAX2771EVKITSignalSourceFPGA(const ConfigurationIn } } + std::vector MAX2771EVKITSignalSourceFPGA::setup_regs(void) { - std::vector register_values = std::vector(MAX2771_NUM_REGS); - - + auto register_values = std::vector(MAX2771_NUM_REGS); uint32_t LNA_mode = (LNA_active_) ? 0x0 : 0x2; - uint32_t Filter_Bandwidth; switch (bandwidth_) @@ -376,10 +374,10 @@ bool MAX2771EVKITSignalSourceFPGA::configure(std::vector register_valu return 0; } + MAX2771EVKITSignalSourceFPGA::~MAX2771EVKITSignalSourceFPGA() { - /* cleanup and exit */ - + // cleanup and exit if (rf_shutdown_) { chipen_ = false; @@ -392,7 +390,6 @@ MAX2771EVKITSignalSourceFPGA::~MAX2771EVKITSignalSourceFPGA() return; } - if (configure(register_values)) { std::cerr << "Error disabling the MAX2771 device " << '\n'; @@ -405,9 +402,10 @@ MAX2771EVKITSignalSourceFPGA::~MAX2771EVKITSignalSourceFPGA() } // disable buffer overflow checking and buffer monitoring - std::unique_lock lock_buffer_monitor(buffer_monitor_mutex); - enable_ovf_check_buffer_monitor_active_ = false; - lock_buffer_monitor.unlock(); + { + std::lock_guard lock_buffer_monitor(buffer_monitor_mutex); + enable_ovf_check_buffer_monitor_active_ = false; + } if (thread_buffer_monitor.joinable()) { @@ -426,12 +424,11 @@ void MAX2771EVKITSignalSourceFPGA::run_buffer_monitor_process() { buffer_monitor_fpga->check_buffer_overflow_and_monitor_buffer_status(); std::this_thread::sleep_for(std::chrono::milliseconds(buffer_monitor_period_ms)); - std::unique_lock lock(buffer_monitor_mutex); + std::lock_guard lock(buffer_monitor_mutex); if (enable_ovf_check_buffer_monitor_active_ == false) { enable_ovf_check_buffer_monitor_active = false; } - lock.unlock(); } } diff --git a/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h index 3008aa384..5ba036ca3 100644 --- a/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h +++ b/src/algorithms/signal_source/adapters/max2771_evkit_signal_source_fpga.h @@ -53,7 +53,6 @@ public: std::vector setup_regs(void); - inline size_t item_size() override { return item_size_; @@ -130,14 +129,13 @@ private: bool configure(std::vector register_values); void run_buffer_monitor_process(); + mutable std::mutex buffer_monitor_mutex; std::thread thread_buffer_monitor; std::shared_ptr buffer_monitor_fpga; std::shared_ptr spidev_fpga; - std::mutex buffer_monitor_mutex; - uint64_t freq_; // frequency of local oscillator uint64_t sample_rate_; diff --git a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt index 24f067be6..2eca5157a 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt +++ b/src/algorithms/signal_source/gnuradio_blocks/CMakeLists.txt @@ -10,17 +10,16 @@ if(ENABLE_RAW_UDP AND PCAP_FOUND) list(APPEND OPT_DRIVER_HEADERS gr_complex_ip_packet_source.h) endif() -if(ENABLE_AD936X_SDR) - set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} gr_complex_ip_packet_source.cc) - set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} gr_complex_ip_packet_source.h) -endif() - - -if(ENABLE_PLUTOSDR) +if(ENABLE_PLUTOSDR OR ENABLE_AD936X_SDR) set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ad936x_iio_source.cc) set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ad936x_iio_source.h) endif() +if(ENABLE_ION) + set(OPT_DRIVER_SOURCES ${OPT_DRIVER_SOURCES} ion_gsms.cc) + set(OPT_DRIVER_HEADERS ${OPT_DRIVER_HEADERS} ion_gsms.h) +endif() + set(SIGNAL_SOURCE_GR_BLOCKS_SOURCES fifo_reader.cc unpack_byte_2bit_samples.cc diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc index 0cf885fe2..c87006bd5 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.cc @@ -1,6 +1,7 @@ /*! * \file ad936x_iio_source.cc - * \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities. + * \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the + * AD936x AD front-end family with special FPGA custom functionalities. * \author Javier Arribas, jarribas(at)cttc.es * * ----------------------------------------------------------------------------- @@ -33,23 +34,23 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr( - std::string pluto_uri_, - std::string board_type_, - long long bandwidth_, - long long sample_rate_, - long long freq_, - std::string rf_port_select_, - std::string rf_filter, - std::string gain_mode_rx0_, - std::string gain_mode_rx1_, + const std::string& pluto_uri_, + const std::string& board_type_, + int64_t bandwidth_, + int64_t sample_rate_, + int64_t freq_, + const std::string& rf_port_select_, + const std::string& rf_filter, + const std::string& gain_mode_rx0_, + const std::string& gain_mode_rx1_, double rf_gain_rx0_, double rf_gain_rx1_, bool enable_ch0, bool enable_ch1, - long long freq_2ch, + int64_t freq_2ch, bool ppsmode_, bool customsamplesize_, - std::string fe_ip_, + const std::string& fe_ip_, int fe_ctlport_, int ssize_, int bshift_, @@ -85,9 +86,10 @@ ad936x_iio_source_sptr ad936x_iio_make_source_sptr( tx_lo_channel_)); } -void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples *samples_in, int nchannels, std::vector *files_out) + +void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples* samples_in, int nchannels, std::vector* files_out) { - int32_t current_byte = 0; + uint32_t current_byte = 0; int16_t ch = 0; // std::cout << "nbytes: " << samples_in->n_bytes << " nsamples: " << samples_in->n_samples << " nch: " << nchannels << "\n"; while (current_byte < samples_in->n_bytes) @@ -101,24 +103,25 @@ void ad936x_iio_source::ad9361_channel_demux_and_record(ad936x_iio_samples *samp } } + ad936x_iio_source::ad936x_iio_source( - std::string pluto_uri_, - std::string board_type_, - long long bandwidth_, - long long sample_rate_, - long long freq_, - std::string rf_port_select_, - std::string rf_filter, - std::string gain_mode_rx0_, - std::string gain_mode_rx1_, + const std::string& pluto_uri_, + const std::string& board_type_, + int64_t bandwidth_, + int64_t sample_rate_, + int64_t freq_, + const std::string& rf_port_select_, + const std::string& rf_filter, + const std::string& gain_mode_rx0_, + const std::string& gain_mode_rx1_, double rf_gain_rx0_, double rf_gain_rx1_, bool enable_ch0, bool enable_ch1, - long long freq_2ch, + int64_t freq_2ch, bool ppsmode_, bool customsamplesize_, - std::string fe_ip_, + const std::string& fe_ip_, int fe_ctlport_, int ssize_, int bshift_, @@ -171,54 +174,81 @@ ad936x_iio_source::ad936x_iio_source( case 16: { std::cout << "FPGA sample size set to 16 bits per sample.\n"; - if (pps_rx->send_cmd("ssize=16\n") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("ssize=16\n") == false) + { + std::cout << "cmd send error!\n"; + } break; } case 8: { std::cout << "FPGA sample size set to 8 bits per sample.\n"; - if (pps_rx->send_cmd("ssize=8\n") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("ssize=8\n") == false) + { + std::cout << "cmd send error!\n"; + } break; } case 4: { std::cout << "FPGA sample size set to 4 bits per sample.\n"; - if (pps_rx->send_cmd("ssize=4\n") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("ssize=4\n") == false) + { + std::cout << "cmd send error!\n"; + } break; } case 2: { std::cout << "FPGA sample size set to 2 bits per sample.\n"; - if (pps_rx->send_cmd("ssize=2\n") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("ssize=2\n") == false) + { + std::cout << "cmd send error!\n"; + } break; } default: { std::cout << "WARNING: Unsupported ssize. FPGA sample size set to 16 bits per sample.\n"; - if (pps_rx->send_cmd("ssize=16") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("ssize=16") == false) + { + std::cout << "cmd send error!\n"; + } } } if (bshift_ >= 0 and bshift_ <= 14) { std::cout << "FPGA sample bits shift left set to " + std::to_string(bshift_) + " positions.\n"; - if (pps_rx->send_cmd("bshift=" + std::to_string(bshift_) + "\n") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("bshift=" + std::to_string(bshift_) + "\n") == false) + { + std::cout << "cmd send error!\n"; + } } else { std::cout << "WARNING: Unsupported bshift. FPGA sample bits shift left set to 0.\n"; - if (pps_rx->send_cmd("bshift=0\n") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("bshift=0\n") == false) + { + std::cout << "cmd send error!\n"; + } } if (spattern_ == true) { std::cout << "FPGA debug sample pattern is active!.\n"; - if (pps_rx->send_cmd("spattern=1\n") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("spattern=1\n") == false) + { + std::cout << "cmd send error!\n"; + } } else { std::cout << "FPGA debug sample pattern disabled.\n"; - if (pps_rx->send_cmd("spattern=0\n") == false) std::cout << "cmd send error!\n"; + if (pps_rx->send_cmd("spattern=0\n") == false) + { + std::cout << "cmd send error!\n"; + } } } else @@ -238,7 +268,7 @@ ad936x_iio_source::ad936x_iio_source( exit(1); } } - catch (std::exception const &ex) + catch (std::exception const& ex) { std::cerr << "STD exception: " << ex.what() << std::endl; exit(1); @@ -267,6 +297,7 @@ ad936x_iio_source::ad936x_iio_source( // } } + ad936x_iio_source::~ad936x_iio_source() { // Terminate PPS thread @@ -284,6 +315,7 @@ bool ad936x_iio_source::start() return ad936x_custom->start_sample_rx(false); } + bool ad936x_iio_source::stop() { std::cout << "stopping ad936x_iio_source...\n"; @@ -291,17 +323,17 @@ bool ad936x_iio_source::stop() return true; } + int ad936x_iio_source::general_work(int noutput_items, - __attribute__((unused)) gr_vector_int &ninput_items, - __attribute__((unused)) gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + __attribute__((unused)) gr_vector_int& ninput_items, + __attribute__((unused)) gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) { std::shared_ptr current_buffer; - ad936x_iio_samples *current_samples; + ad936x_iio_samples* current_samples; ad936x_custom->pop_sample_buffer(current_buffer); current_samples = current_buffer.get(); - // I and Q samples are interleaved in buffer: IQIQIQ... int32_t n_interleaved_iq_samples_per_channel = current_samples->n_bytes / (ad936x_custom->n_channels * 2); if (noutput_items < n_interleaved_iq_samples_per_channel) @@ -312,7 +344,7 @@ int ad936x_iio_source::general_work(int noutput_items, else { // ad9361_channel_demux_and_record(current_samples, ad936x_custom->n_channels, &samplesfile); - auto **out = reinterpret_cast(&output_items[0]); + auto** out = reinterpret_cast(&output_items[0]); uint32_t current_byte = 0; uint32_t current_byte_in_gr = 0; int16_t ch = 0; diff --git a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h index 411906a3e..8f5a34c7c 100644 --- a/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h +++ b/src/algorithms/signal_source/gnuradio_blocks/ad936x_iio_source.h @@ -1,6 +1,7 @@ /*! * \file ad936x_iio_source.h - * \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the AD936x AD front-end family with special FPGA custom functionalities. + * \brief A direct IIO custom front-end gnss-sdr signal gnuradio block for the + * AD936x AD front-end family with special FPGA custom functionalities. * \author Javier Arribas, jarribas(at)cttc.es * * ----------------------------------------------------------------------------- @@ -44,23 +45,23 @@ class ad936x_iio_source; using ad936x_iio_source_sptr = gnss_shared_ptr; ad936x_iio_source_sptr ad936x_iio_make_source_sptr( - std::string pluto_uri_, - std::string board_type_, - long long bandwidth_, - long long sample_rate_, - long long freq_, - std::string rf_port_select_, - std::string rf_filter, - std::string gain_mode_rx0_, - std::string gain_mode_rx1_, + const std::string &pluto_uri_, + const std::string &board_type_, + int64_t bandwidth_, + int64_t sample_rate_, + int64_t freq_, + const std::string &rf_port_select_, + const std::string &rf_filter, + const std::string &gain_mode_rx0_, + const std::string &gain_mode_rx1_, double rf_gain_rx0_, double rf_gain_rx1_, bool enable_ch0, bool enable_ch1, - long long freq_2ch, + int64_t freq_2ch, bool ppsmode_, bool customsamplesize_, - std::string fe_ip_, + const std::string &fe_ip_, int fe_ctlport_, int ssize_, int bshift_, @@ -90,23 +91,23 @@ public: private: friend ad936x_iio_source_sptr ad936x_iio_make_source_sptr( - std::string pluto_uri_, - std::string board_type_, - long long bandwidth_, - long long sample_rate_, - long long freq_, - std::string rf_port_select_, - std::string rf_filter, - std::string gain_mode_rx0_, - std::string gain_mode_rx1_, + const std::string &pluto_uri_, + const std::string &board_type_, + int64_t bandwidth_, + int64_t sample_rate_, + int64_t freq_, + const std::string &rf_port_select_, + const std::string &rf_filter, + const std::string &gain_mode_rx0_, + const std::string &gain_mode_rx1_, double rf_gain_rx0_, double rf_gain_rx1_, bool enable_ch0, bool enable_ch1, - long long freq_2ch, + int64_t freq_2ch, bool ppsmode_, bool customsamplesize_, - std::string fe_ip_, + const std::string &fe_ip_, int fe_ctlport_, int ssize_, int bshift_, @@ -116,23 +117,23 @@ private: int tx_lo_channel_); ad936x_iio_source( - std::string pluto_uri_, - std::string board_type_, - long long bandwidth_, - long long sample_rate_, - long long freq_, - std::string rf_port_select_, - std::string rf_filter, - std::string gain_mode_rx0_, - std::string gain_mode_rx1_, + const std::string &pluto_uri_, + const std::string &board_type_, + int64_t bandwidth_, + int64_t sample_rate_, + int64_t freq_, + const std::string &rf_port_select_, + const std::string &rf_filter, + const std::string &gain_mode_rx0_, + const std::string &gain_mode_rx1_, double rf_gain_rx0_, double rf_gain_rx1_, bool enable_ch0, bool enable_ch1, - long long freq_2ch, + int64_t freq_2ch, bool ppsmode_, bool customsamplesize_, - std::string fe_ip_, + const std::string &fe_ip_, int fe_ctlport_, int ssize_, int bshift_, @@ -141,7 +142,6 @@ private: bool high_side_lo_, int tx_lo_channel_); - void ad9361_channel_demux_to_buffer(ad936x_iio_samples *samples_in, int nchannels, gr_vector_void_star &output_items); void ad9361_channel_demux_and_record(ad936x_iio_samples *samples_in, int nchannels, std::vector *files_out); diff --git a/src/algorithms/signal_source/gnuradio_blocks/ion_gsms.cc b/src/algorithms/signal_source/gnuradio_blocks/ion_gsms.cc new file mode 100644 index 000000000..22a25868c --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/ion_gsms.cc @@ -0,0 +1,202 @@ +/*! + * \file ion_gsms.cc + * \brief GNU Radio block that reads a Block from a file following ION's GNSS-SDR metadata standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "ion_gsms.h" +#include "gnuradio/block.h" +#include +#include +#include +#include + +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#endif + +IONGSMSFileSource::IONGSMSFileSource( + const fs::path& metadata_filepath, + const GnssMetadata::File& file, + const GnssMetadata::Block& block, + const std::vector& stream_ids) + : gr::sync_block( + "ion_gsms_file_source", + gr::io_signature::make(0, 0, 0), + make_output_signature(block, stream_ids)), + file_stream_(metadata_filepath.parent_path() / file.Url().Value(), std::ios::in | std::ios::binary), + io_buffer_offset_(0), + maximum_item_rate_(0), + chunk_cycle_length_(0) +{ + fs::path data_filepath = metadata_filepath.parent_path() / file.Url().Value(); + std::size_t block_offset = file.Offset(); + + if (!file_stream_.is_open()) + { + LOG(WARNING) << "ION_GSMS_Signal_Source - Unable to open the samples file: " << (data_filepath).c_str(); + std::cerr << "ION_GSMS_Signal_Source - Unable to open the samples file: " << (data_filepath).c_str() << std::endl; + std::cout << "GNSS-SDR program ended.\n"; + exit(1); + } + + // Skip offset and block header + file_stream_.seekg(file.Offset() + block_offset + block.SizeHeader()); + + std::size_t output_stream_offset = 0; + for (const auto& chunk : block.Chunks()) + { + chunk_data_.emplace_back(std::make_shared(chunk, stream_ids, output_stream_offset)); + chunk_cycle_length_ += chunk.CountWords() * chunk.SizeWord(); + const std::size_t out_count = chunk_data_.back()->output_stream_count(); + output_stream_offset += out_count; + for (std::size_t i = 0; i < out_count; ++i) + { + output_stream_item_sizes_.push_back(chunk_data_.back()->output_stream_item_size(i)); + output_stream_item_rates_.push_back(chunk_data_.back()->output_stream_item_rate(i)); + maximum_item_rate_ = std::max(chunk_data_.back()->output_stream_item_rate(i), maximum_item_rate_); + } + } + output_stream_count_ = output_stream_offset; + + output_stream_total_sample_counts_.resize(output_stream_count_); + + std::size_t cycle_count = block.Cycles(); + if (cycle_count == 0) + { + // Read the whole file + const std::size_t file_size = fs::file_size(data_filepath); + cycle_count = std::floor((file_size - block_offset - block.SizeHeader()) / chunk_cycle_length_); + } + + for (std::size_t i = 0; i < output_stream_count_; ++i) + { + output_stream_total_sample_counts_[i] = cycle_count * output_stream_item_rates_[i]; + } +} + + +std::size_t IONGSMSFileSource::output_stream_count() const +{ + return output_stream_count_; +} + + +std::size_t IONGSMSFileSource::output_stream_item_size(std::size_t stream_index) const +{ + return output_stream_item_sizes_[stream_index]; +} + + +std::size_t IONGSMSFileSource::output_stream_total_sample_count(std::size_t stream_index) const +{ + return output_stream_total_sample_counts_[stream_index]; +} + + +gr::io_signature::sptr IONGSMSFileSource::make_output_signature(const GnssMetadata::Block& block, const std::vector& stream_ids) +{ + int nstreams = 0; + std::vector item_sizes{}; + + for (const auto& chunk : block.Chunks()) + { + for (const auto& lump : chunk.Lumps()) + { + for (const auto& stream : lump.Streams()) + { + bool found = false; + for (const auto& stream_id : stream_ids) + { + if (stream_id == stream.Id()) + { + found = true; + break; + } + } + if (found) + { + ++nstreams; + std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor(); + if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization()) + { + // Samples have 'Complex' format + sample_bitsize /= 2; + } + item_sizes.push_back(bits_to_item_size(sample_bitsize)); + } + } + } + } + + return gr::io_signature::makev( + nstreams, + nstreams, + item_sizes); +} + + +int IONGSMSFileSource::work( + int noutput_items, + gr_vector_const_void_star& input_items __attribute__((unused)), + gr_vector_void_star& output_items) +{ + // Compute the maximum number of samples that will be copied across all output buffer. + // If there are more than one output buffer (multichannel set up), the one with the most samples will be used as the maximum. + // + // Complex samples produce 2 items each (I and Q). In order to account for them, we subtract 1 from `noutput_items` and + // then floor the division. During testing, not doing this caused `max_sample_output` to oscillate between two values, thus + // resizing the `io_buffer_` on each call to `work()`. + const std::size_t max_sample_output = std::floor((noutput_items - 1.0) / maximum_item_rate_); + + // Resize the IO buffer to fit exactly the maximum amount of samples that will be outputted. + io_buffer_.resize(max_sample_output * chunk_cycle_length_); + + // We will be walking the IO buffer with this variable. + io_buffer_offset_ = 0; + + // Read samples from file into IO buffer + const std::size_t bytes_to_read = io_buffer_.size(); + file_stream_.read(io_buffer_.data(), bytes_to_read); + + // Reset `items_produced_` vector. This vector will accumulate the amount of items produced for each output stream. + items_produced_.clear(); + items_produced_.resize(output_items.size()); + + // Walk the IO buffer one chunk cycle at a time. See ION documentation for a definition of chunk and chunk cycle. + while (io_buffer_offset_ < bytes_to_read) + { + // Iterate chunks within a chunk cycle + for (auto& chunk : chunk_data_) + { + // Copy chunk into a separate buffer where the samples will be shifted from. + const std::size_t bytes_copied = chunk->read_from_buffer(reinterpret_cast(io_buffer_.data()), io_buffer_offset_); + + // Advance IO buffer offset + io_buffer_offset_ += bytes_copied; + + // Shift samples into output buffers following the appropriate unpacking strategy for this chunk. + chunk->write_to_output(output_items, items_produced_); + } + } + + // Call `produce(int, int)` with the appropriate item count for each output stream. + for (std::size_t i = 0; i < items_produced_.size(); ++i) + { + produce(i, items_produced_[i]); + } + + return WORK_CALLED_PRODUCE; +} diff --git a/src/algorithms/signal_source/gnuradio_blocks/ion_gsms.h b/src/algorithms/signal_source/gnuradio_blocks/ion_gsms.h new file mode 100644 index 000000000..4a6baa7e9 --- /dev/null +++ b/src/algorithms/signal_source/gnuradio_blocks/ion_gsms.h @@ -0,0 +1,74 @@ +/*! + * \file ion_gsms.h + * \brief GNU Radio block that reads a Block from a file following ION's GNSS-SDR metadata standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_ION_GSMS_H +#define GNSS_SDR_ION_GSMS_H + +#include "gnss_block_interface.h" +#include "gnss_sdr_filesystem.h" +#include "ion_gsms_chunk_data.h" +#include +#include +#include +#include +#include +#include +#include + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_gnuradio_blocks + * \{ */ + +class IONGSMSFileSource : public gr::sync_block +{ +public: + using sptr = gnss_shared_ptr; + + IONGSMSFileSource( + const fs::path& metadata_filepath, + const GnssMetadata::File& file, + const GnssMetadata::Block& block, + const std::vector& stream_ids); + + int work( + int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) override; + + std::size_t output_stream_count() const; + std::size_t output_stream_item_size(std::size_t stream_index) const; + std::size_t output_stream_total_sample_count(std::size_t stream_index) const; + +private: + static gr::io_signature::sptr make_output_signature(const GnssMetadata::Block& block, const std::vector& stream_ids); + + std::ifstream file_stream_; + std::vector io_buffer_; + std::size_t io_buffer_offset_; + std::vector items_produced_; + std::size_t output_stream_count_; + std::vector output_stream_item_sizes_; + std::vector output_stream_item_rates_; + std::vector output_stream_total_sample_counts_; + std::size_t maximum_item_rate_; + std::vector> chunk_data_; + std::size_t chunk_cycle_length_; +}; + +/** \} */ +/** \} */ +#endif // GNSS_SDR_ION_GSMS_H diff --git a/src/algorithms/signal_source/libs/CMakeLists.txt b/src/algorithms/signal_source/libs/CMakeLists.txt index 3506dc4f7..0df4f3303 100644 --- a/src/algorithms/signal_source/libs/CMakeLists.txt +++ b/src/algorithms/signal_source/libs/CMakeLists.txt @@ -7,14 +7,15 @@ set(OPT_SIGNAL_SOURCE_LIB_SOURCES "") set(OPT_SIGNAL_SOURCE_LIB_HEADERS "") + if(ENABLE_FMCOMMS2 OR ENABLE_AD9361) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.cc) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad9361_manager.h) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad9361_manager.h) endif() if(ENABLE_MAX2771) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.cc) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} fpga_spidev.h) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_spidev.h) endif() if(ENABLE_FPGA) @@ -34,16 +35,21 @@ if((ENABLE_FPGA AND ENABLE_AD9361) OR ENABLE_MAX2771) set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} fpga_buffer_monitor.h) endif() -if(ENABLE_PLUTOSDR) - set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.cc) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_samples.h) +if(ENABLE_PLUTOSDR OR ENABLE_AD936X_SDR) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad936x_iio_samples.h) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.cc) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ad936x_iio_custom.h) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} pps_samplestamp.h) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ad936x_iio_custom.h) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} pps_samplestamp.h) set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.cc) - set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ppstcprx.h) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ppstcprx.h) endif() +if(ENABLE_ION) + set(OPT_SIGNAL_SOURCE_LIB_SOURCES ${OPT_SIGNAL_SOURCE_LIB_SOURCES} ion_gsms_chunk_data.cc) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_chunk_data.h) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_stream_encodings.h) + set(OPT_SIGNAL_SOURCE_LIB_HEADERS ${OPT_SIGNAL_SOURCE_LIB_HEADERS} ion_gsms_chunk_unpacking_ctx.h) +endif() set(SIGNAL_SOURCE_LIB_SOURCES rtl_tcp_commands.cc @@ -107,7 +113,7 @@ if(GNURADIO_USES_STD_POINTERS) ) endif() -if(ENABLE_FMCOMMS2 OR ENABLE_AD9361 OR ENABLE_PLUTOSDR) +if(ENABLE_FMCOMMS2 OR ENABLE_AD9361 OR ENABLE_PLUTOSDR OR ENABLE_AD936X_SDR) target_link_libraries(signal_source_libs PUBLIC Iio::iio @@ -130,6 +136,10 @@ if(ENABLE_FPGA OR ENABLE_AD9361) ) endif() +if(ENABLE_ION) + target_link_libraries(signal_source_libs PUBLIC ION::ion algorithms_libs) +endif() + if(ENABLE_CLANG_TIDY) if(CLANG_TIDY_EXE) set_target_properties(signal_source_libs diff --git a/src/algorithms/signal_source/libs/ad9361_manager.cc b/src/algorithms/signal_source/libs/ad9361_manager.cc index 913488287..025f97627 100644 --- a/src/algorithms/signal_source/libs/ad9361_manager.cc +++ b/src/algorithms/signal_source/libs/ad9361_manager.cc @@ -349,7 +349,7 @@ bool config_ad9361_rx_local(uint64_t bandwidth_, #ifndef LIBAD9361_VERSION_GREATER_THAN_01 if (filter_source_ == "Design") { - std::cout << "Option filter_source=Design is not available in this version. Set to filter_source=Off\n"; + std::cout << "Option filter_source=Design is not available in this version of libad9361. Set to filter_source=Off\n"; filter_source_ = std::string("Off"); } if (Fpass_ != 0.0 or Fstop_ != 0.0) @@ -636,7 +636,7 @@ bool config_ad9361_rx_remote(const std::string &remote_host, { return false; } - if (setup_filter(std::move(filter_source_), bandwidth_, sample_rate_, freq_, rf_port_select_, ad9361_phy, rx_chan0, chn, 0, std::move(filter_filename_), Fpass_, Fstop_) == -1) + if (setup_filter(filter_source_, bandwidth_, sample_rate_, freq_, rf_port_select_, ad9361_phy, rx_chan0, chn, 0, std::move(filter_filename_), Fpass_, Fstop_) == -1) { return false; } diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc index 72461bafd..c41d74b9a 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.cc +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.cc @@ -1,6 +1,7 @@ /*! * \file ad936x_iio_custom.cc - * \brief A direct IIO custom front-end driver for the AD936x AD front-end family with special FPGA custom functionalities. + * \brief A direct IIO custom front-end driver for the AD936x AD front-end + * family with special FPGA custom functionalities. * \author Javier Arribas, jarribas(at)cttc.es * ----------------------------------------------------------------------------- * @@ -30,29 +31,36 @@ #include #endif -ad936x_iio_custom::ad936x_iio_custom(int debug_level_, int log_level_) +ad936x_iio_custom::ad936x_iio_custom( + int debug_level_, + int log_level_) : n_channels(0), + ctx(nullptr), + phy(nullptr), + stream_dev(nullptr), + dds_dev(nullptr), + receive_samples(false), + fpga_overflow(false), + sample_rate_sps(0), + debug_level(debug_level_), + log_level(log_level_), + PPS_mode(false) { - receive_samples = false; - fpga_overflow = false; - sample_rate_sps = 0; - ctx = NULL; - phy = NULL; - dds_dev = NULL; - stream_dev = NULL; - debug_level = debug_level_; - log_level = log_level_; - PPS_mode = false; - n_channels = 0; } ad936x_iio_custom::~ad936x_iio_custom() { // disable TX - if (phy != NULL) PlutoTxEnable(false); + if (phy != nullptr) + { + PlutoTxEnable(false); + } // Close device - if (ctx != NULL) iio_context_destroy(ctx); + if (ctx != nullptr) + { + iio_context_destroy(ctx); + } } @@ -68,7 +76,7 @@ void ad936x_iio_custom::set_pps_samplestamp_queue(std::shared_ptr ¶ms) { - for (std::vector::const_iterator it = params.begin(); - it != params.end(); ++it) + for (const auto ¶m : params) { - struct iio_channel *chn = NULL; - const char *attr = NULL; + struct iio_channel *chn = nullptr; + const char *attr = nullptr; size_t pos; int ret; - pos = it->find('='); + pos = param.find('='); if (pos == std::string::npos) { - std::cerr << "Malformed line: " << *it << std::endl; + std::cerr << "Malformed line: " << param << std::endl; continue; } - std::string key = it->substr(0, pos); - std::string val = it->substr(pos + 1, std::string::npos); + std::string key = param.substr(0, pos); + std::string val = param.substr(pos + 1, std::string::npos); ret = iio_device_identify_filename(phy, key.c_str(), &chn, &attr); @@ -196,13 +203,19 @@ void ad936x_iio_custom::configure_params(struct iio_device *phy, } if (chn) - ret = iio_channel_attr_write(chn, - attr, val.c_str()); + { + ret = iio_channel_attr_write(chn, + attr, val.c_str()); + } else if (iio_device_find_attr(phy, attr)) - ret = iio_device_attr_write(phy, attr, val.c_str()); + { + ret = iio_device_attr_write(phy, attr, val.c_str()); + } else - ret = iio_device_debug_attr_write(phy, - attr, val.c_str()); + { + ret = iio_device_debug_attr_write(phy, + attr, val.c_str()); + } if (ret < 0) { std::cerr << "Unable to write attribute " << key @@ -216,9 +229,9 @@ void ad936x_iio_custom::set_params_rx(struct iio_device *phy_device, unsigned long long frequency, unsigned long samplerate, unsigned long bandwidth, bool quadrature, bool rfdc, bool bbdc, - std::string gain1, double gain1_value, - std::string gain2, double gain2_value, - std::string port_select) + const std::string &gain1, double gain1_value, + const std::string &gain2, double gain2_value, + const std::string &port_select) { std::vector params; @@ -289,7 +302,7 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, std::to_string(phase_dds_deg_ * 1000.0)); params_dds.push_back("out_altvoltage0_TX1_I_F1_scale=" + std::to_string(scale_dds_)); - params_dds.push_back("out_altvoltage0_TX1_I_F1_raw=1"); + params_dds.emplace_back("out_altvoltage0_TX1_I_F1_raw=1"); // DDS TX CH1 Q (tone #1) params_dds.push_back("out_altvoltage2_TX1_Q_F1_frequency=" + std::to_string(freq_dds_tx_hz_)); @@ -297,7 +310,7 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, std::to_string(phase_dds_deg_ * 1000.0 + 270000.0)); params_dds.push_back("out_altvoltage2_TX1_Q_F1_scale=" + std::to_string(scale_dds_)); - params_dds.push_back("out_altvoltage2_TX1_Q_F1_raw=1"); + params_dds.emplace_back("out_altvoltage2_TX1_Q_F1_raw=1"); configure_params(dds_dev, params_dds); } @@ -318,7 +331,7 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, std::to_string(phase_dds_deg_ * 1000.0)); params_dds.push_back("out_altvoltage4_TX2_I_F1_scale=" + std::to_string(scale_dds_)); - params_dds.push_back("out_altvoltage4_TX2_I_F1_raw=1"); + params_dds.emplace_back("out_altvoltage4_TX2_I_F1_raw=1"); // DDS TX CH2 Q (tone #1) params_dds.push_back("out_altvoltage6_TX2_Q_F1_frequency=" + std::to_string(freq_dds_tx_hz_)); @@ -326,7 +339,7 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, std::to_string(phase_dds_deg_ * 1000.0 + 270000.0)); params_dds.push_back("out_altvoltage6_TX2_Q_F1_scale=" + std::to_string(scale_dds_)); - params_dds.push_back("out_altvoltage6_TX2_Q_F1_raw=1"); + params_dds.emplace_back("out_altvoltage6_TX2_Q_F1_raw=1"); configure_params(dds_dev, params_dds); } @@ -337,7 +350,7 @@ bool ad936x_iio_custom::config_ad9361_dds(uint64_t freq_rf_tx_hz_, bool ad936x_iio_custom::check_device() { - if (stream_dev != NULL) + if (stream_dev != nullptr) { return true; } @@ -350,8 +363,8 @@ bool ad936x_iio_custom::check_device() bool ad936x_iio_custom::get_iio_param(iio_device *dev, const std::string ¶m, std::string &value) { - struct iio_channel *chn = 0; - const char *attr = 0; + struct iio_channel *chn = nullptr; + const char *attr = nullptr; char valuestr[256]; int ret; ssize_t nchars; @@ -398,9 +411,12 @@ bool ad936x_iio_custom::read_die_temp(double &temp_c) { try { - uint32_t temp_mC = boost::lexical_cast(temp_mC_str); + auto temp_mC = boost::lexical_cast(temp_mC_str); temp_c = static_cast(temp_mC) / 1000.0; - if (temp_c > 120) temp_c = -1; + if (temp_c > 120) + { + temp_c = -1; + } return true; } catch (const boost::bad_lexical_cast &e) @@ -419,10 +435,10 @@ bool ad936x_iio_custom::read_die_temp(double &temp_c) bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, long long sample_rate_, long long freq_, - std::string rf_port_select_, - std::string rf_filter, - std::string gain_mode_rx0_, - std::string gain_mode_rx1_, + const std::string &rf_port_select_, + const std::string &rf_filter, + const std::string &gain_mode_rx0_, + const std::string &gain_mode_rx1_, double rf_gain_rx0_, double rf_gain_rx1_, bool enable_ch0, @@ -432,16 +448,19 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, bool high_side_lo_, int tx_lo_channel_) { - if (check_device() == false) return false; + if (check_device() == false) + { + return false; + } bool no_errors = true; std::cout << "Configuring phy device parameters...\n"; int ret; - if (rf_filter.compare("Disabled") == 0) + if (rf_filter == "Disabled") { std::cout << "LNA Filter switch is disabled.\n"; } - else if (rf_filter.compare("Auto") == 0) + else if (rf_filter == "Auto") { std::cout << "Selecting LNA RF filter based on the selected RF frequency... \n"; if (freq_ == 1575420000) @@ -498,9 +517,9 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, params.push_back("out_voltage_rf_bandwidth=" + std::to_string(bandwidth_)); - params.push_back("in_voltage_quadrature_tracking_en=1"); - params.push_back("in_voltage_rf_dc_offset_tracking_en=1"); - params.push_back("in_voltage_bb_dc_offset_tracking_en=1"); + params.emplace_back("in_voltage_quadrature_tracking_en=1"); + params.emplace_back("in_voltage_rf_dc_offset_tracking_en=1"); + params.emplace_back("in_voltage_bb_dc_offset_tracking_en=1"); configure_params(phy, params); @@ -705,7 +724,10 @@ bool ad936x_iio_custom::init_config_ad9361_rx(long long bandwidth_, bool ad936x_iio_custom::set_rx_frequency(long long freq_hz) { - if (check_device() == false) return false; + if (check_device() == false) + { + return false; + } // Configure RX LO channel (NOTICE that altvoltage0 is the RX LO oscillator!, altvoltage1 is the TX oscillator) struct iio_channel *lo_ch; @@ -728,7 +750,10 @@ bool ad936x_iio_custom::set_rx_frequency(long long freq_hz) bool ad936x_iio_custom::get_rx_frequency(long long &freq_hz) { - if (check_device() == false) return false; + if (check_device() == false) + { + return false; + } // Configure RX LO channel (NOTICE that altvoltage0 is the RX LO oscillator!, altvoltage1 is the TX oscillator) struct iio_channel *lo_ch; @@ -749,9 +774,12 @@ bool ad936x_iio_custom::get_rx_frequency(long long &freq_hz) } -bool ad936x_iio_custom::setRXGain(int ch_num, std::string gain_mode, double gain_dB) +bool ad936x_iio_custom::setRXGain(int ch_num, const std::string &gain_mode, double gain_dB) { - if (check_device() == false) return false; + if (check_device() == false) + { + return false; + } std::vector params; if (ch_num == 0) { @@ -784,7 +812,10 @@ bool ad936x_iio_custom::setRXGain(int ch_num, std::string gain_mode, double gain double ad936x_iio_custom::get_rx_gain(int ch_num) { - if (check_device() == false) return -1; + if (check_device() == false) + { + return -1; + } double gain_dB; // gain in dB int ret = 0; if (ch_num == 0) @@ -815,7 +846,10 @@ double ad936x_iio_custom::get_rx_gain(int ch_num) bool ad936x_iio_custom::calibrate([[maybe_unused]] int ch, [[maybe_unused]] double bw_hz) { - if (check_device() == false) return false; + if (check_device() == false) + { + return false; + } // todo return true; } @@ -864,12 +898,13 @@ void ad936x_iio_custom::monitor_thread_fn() { ret = iio_device_reg_write(stream_dev, 0x80000088, val); if (ret) - fprintf(stderr, "Failed to clearn DMA status register: %s\n", - strerror(-ret)); + { + fprintf(stderr, "Failed to clearn DMA status register: %s\n", + strerror(-ret)); + } } sleep(1); } - return; } @@ -940,7 +975,7 @@ void ad936x_iio_custom::setPlutoGpo(int p) } -bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) +bool ad936x_iio_custom::select_rf_filter(const std::string &rf_filter) { // adi,gpo-manual-mode-enable Enables GPO manual mode, this will conflict with automatic ENSM slave and eLNA mode // adi,gpo-manual-mode-enable-mask Enable bit mask, setting or clearing bits will change the level of the corresponding output. Bit0 → GPO, Bit1 → GPO1, Bit2 → GPO2, Bit3 → GP03 @@ -960,7 +995,10 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) // 1 Enable // X Enable Mask if Identifier=0xF - if (check_device() == false) return false; + if (check_device() == false) + { + return false; + } // int plutoGpo = 0; int ret; ret = iio_device_debug_attr_write(phy, "adi,gpo-manual-mode-enable", "1"); @@ -971,7 +1009,7 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) return false; } - if (rf_filter.compare("E1") == 0) + if (rf_filter == "E1") { // set gpio0 to switch L1 filter // setPlutoGpo(plutoGpo); @@ -982,7 +1020,7 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) return false; } } - else if (rf_filter.compare("E5E6") == 0) + else if (rf_filter == "E5E6") { // set gpio0 to switch L5/L6 filter (GPO0) // plutoGpo = plutoGpo | 0x10; @@ -994,7 +1032,7 @@ bool ad936x_iio_custom::select_rf_filter(std::string rf_filter) return false; } } - if (rf_filter.compare("none") == 0) + if (rf_filter == "none") { std::cout << "RF external filter not selected\n"; } @@ -1107,18 +1145,18 @@ bool ad936x_iio_custom::start_sample_rx(bool ppsmode) switch (n_channels) { case 1: - channels.push_back("voltage0"); // Channel 0 I - channels.push_back("voltage1"); // Channel 0 Q + channels.emplace_back("voltage0"); // Channel 0 I + channels.emplace_back("voltage1"); // Channel 0 Q break; case 2: - channels.push_back("voltage0"); // Channel 0 I - channels.push_back("voltage1"); // Channel 0 Q - channels.push_back("voltage2"); // Channel 1 I - channels.push_back("voltage3"); // Channel 1 Q + channels.emplace_back("voltage0"); // Channel 0 I + channels.emplace_back("voltage1"); // Channel 0 Q + channels.emplace_back("voltage2"); // Channel 1 I + channels.emplace_back("voltage3"); // Channel 1 Q break; default: - channels.push_back("voltage0"); // Channel 0 I - channels.push_back("voltage1"); // Channel 0 Q + channels.emplace_back("voltage0"); // Channel 0 I + channels.emplace_back("voltage1"); // Channel 0 Q } receive_samples = true; @@ -1150,7 +1188,10 @@ void ad936x_iio_custom::push_sample_buffer(std::shared_ptr & void ad936x_iio_custom::capture(const std::vector &channels) { - if (check_device() == false) return; + if (check_device() == false) + { + return; + } struct iio_buffer *rxbuf; @@ -1178,16 +1219,14 @@ void ad936x_iio_custom::capture(const std::vector &channels) } else { - for (std::vector::const_iterator it = - channels.begin(); - it != channels.end(); ++it) + for (const auto &channel : channels) { struct iio_channel *chn = iio_device_find_channel(stream_dev, - it->c_str(), false); + channel.c_str(), false); if (!chn) { - std::cerr << "Channel " << it->c_str() << " not found\n"; + std::cerr << "Channel " << channel.c_str() << " not found\n"; return; } else @@ -1246,7 +1285,10 @@ void ad936x_iio_custom::capture(const std::vector &channels) items_in_buffer = static_cast(ret) / bytes_to_interleaved_iq_samples; - if (items_in_buffer == 0) return; + if (items_in_buffer == 0) + { + return; + } current_samples->n_channels = n_channels; current_samples->n_interleaved_iq_samples = items_in_buffer; diff --git a/src/algorithms/signal_source/libs/ad936x_iio_custom.h b/src/algorithms/signal_source/libs/ad936x_iio_custom.h index 83a61282a..0c6199968 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_custom.h +++ b/src/algorithms/signal_source/libs/ad936x_iio_custom.h @@ -1,6 +1,7 @@ /*! * \file ad936x_iio_custom.h - * \brief A direct IIO custom front-end driver for the AD936x AD front-end family with special FPGA custom functionalities. + * \brief A direct IIO custom front-end driver for the AD936x AD front-end + * family with special FPGA custom functionalities. * \author Javier Arribas, jarribas(at)cttc.es * ----------------------------------------------------------------------------- * @@ -14,41 +15,41 @@ */ -#ifndef SRC_LIBS_ad936x_iio_custom_H_ -#define SRC_LIBS_ad936x_iio_custom_H_ +#ifndef GNSS_SDR_AD936X_IIO_CUSTOM_H +#define GNSS_SDR_AD936X_IIO_CUSTOM_H +#include "ad936x_iio_samples.h" #include "concurrent_queue.h" #include "gnss_time.h" #include "pps_samplestamp.h" #include +#include +#include // multichip sync and high level functions #include #include - -#ifdef __APPLE__ -#include -#else -#include -#endif - -#include "ad936x_iio_samples.h" -#include // multichip sync and high level functions #include #include +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_libs + * \{ */ + + class ad936x_iio_custom { public: ad936x_iio_custom(int debug_level_, int log_level_); virtual ~ad936x_iio_custom(); - bool initialize_device(std::string pluto_device_uri, std::string board_type); + bool initialize_device(const std::string &pluto_device_uri, const std::string &board_type); bool init_config_ad9361_rx(long long bandwidth_, long long sample_rate_, long long freq_, - std::string rf_port_select_, - std::string rf_filter, - std::string gain_mode_rx0_, - std::string gain_mode_rx1_, + const std::string &rf_port_select_, + const std::string &rf_filter, + const std::string &gain_mode_rx0_, + const std::string &gain_mode_rx1_, double rf_gain_rx0_, double rf_gain_rx1_, bool enable_ch0, @@ -61,7 +62,7 @@ public: bool calibrate(int ch, double bw_hz); double get_rx_gain(int ch_num); - bool setRXGain(int ch_num, std::string gain_mode, double gain_dB); + bool setRXGain(int ch_num, const std::string &gain_mode, double gain_dB); bool set_antenna_port(int ch, int antenna_idx); double get_frequency(int ch); @@ -93,9 +94,9 @@ private: unsigned long long frequency, unsigned long samplerate, unsigned long bandwidth, bool quadrature, bool rfdc, bool bbdc, - std::string gain1, double gain1_value, - std::string gain2, double gain2_value, - std::string port_select); + const std::string &gain1, double gain1_value, + const std::string &gain2, double gain2_value, + const std::string &port_select); bool config_ad9361_dds(uint64_t freq_rf_tx_hz_, double tx_attenuation_db_, @@ -107,7 +108,7 @@ private: void get_PPS_timestamp(); void capture(const std::vector &channels); - bool select_rf_filter(std::string rf_filter); + bool select_rf_filter(const std::string &rf_filter); void monitor_thread_fn(); @@ -120,15 +121,6 @@ private: struct iio_device *stream_dev; struct iio_device *dds_dev; - // stream - - uint64_t sample_rate_sps; - - - int debug_level; - int log_level; - bool PPS_mode; - std::mutex mtx; std::condition_variable cv; @@ -142,6 +134,14 @@ private: std::thread capture_samples_thread; std::thread overflow_monitor_thread; std::thread capture_time_thread; + + // stream + uint64_t sample_rate_sps; + int debug_level; + int log_level; + bool PPS_mode; }; -#endif /* SRC_LIBS_ad936x_iio_custom_H_ */ +/** \} */ +/** \} */ +#endif // GNSS_SDR_AD936X_IIO_CUSTOM_H diff --git a/src/algorithms/signal_source/libs/ad936x_iio_samples.cc b/src/algorithms/signal_source/libs/ad936x_iio_samples.cc deleted file mode 100644 index b9b7b505a..000000000 --- a/src/algorithms/signal_source/libs/ad936x_iio_samples.cc +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * \file ad936x_iio_samples.cc - * \brief A class that holds a custom sample buffer for Analog Devices AD936x family front-ends. - * \author Javier Arribas, jarribas(at)cttc.es - * - * ----------------------------------------------------------------------------- - * - * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. - * This file is part of GNSS-SDR. - * - * Copyright (C) 2010-2022 (see AUTHORS file for a list of contributors) - * SPDX-License-Identifier: GPL-3.0-or-later - * - * ----------------------------------------------------------------------------- - */ - -#include "ad936x_iio_samples.h" - -ad936x_iio_samples::ad936x_iio_samples() -{ - n_bytes = 0; - n_interleaved_iq_samples = 0; - step_bytes = 0; - n_channels = 0; -} diff --git a/src/algorithms/signal_source/libs/ad936x_iio_samples.h b/src/algorithms/signal_source/libs/ad936x_iio_samples.h index 63d30545b..5ff43d065 100644 --- a/src/algorithms/signal_source/libs/ad936x_iio_samples.h +++ b/src/algorithms/signal_source/libs/ad936x_iio_samples.h @@ -15,26 +15,32 @@ */ -#ifndef SRC_LIBS_ad936x_iio_samples_H_ -#define SRC_LIBS_ad936x_iio_samples_H_ +#ifndef GNSS_SDR_AD936X_IIO_SAMPLES_H +#define GNSS_SDR_AD936X_IIO_SAMPLES_H #define IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES 32768 * 4 - #define IIO_INPUTRAMFIFOSIZE 256 +#include #include -#include #include +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_libs + * \{ */ + class ad936x_iio_samples { public: - ad936x_iio_samples(); - uint32_t n_bytes; - uint32_t n_interleaved_iq_samples; - uint16_t n_channels; - uint16_t step_bytes; + ad936x_iio_samples() = default; + uint32_t n_bytes{0}; + uint32_t n_interleaved_iq_samples{0}; + uint16_t n_channels{0}; + uint16_t step_bytes{0}; char buffer[IIO_DEFAULTAD936XAPIFIFOSIZE_SAMPLES * 4 * 4]; // max 16 bits samples per buffer (4 channels, 2-bytes per I + 2-bytes per Q) }; +/** \} */ +/** \} */ #endif diff --git a/src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc b/src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc new file mode 100644 index 000000000..5a8cd823c --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms_chunk_data.cc @@ -0,0 +1,271 @@ +/*! + * \file ion_gsms_chunk_data.cc + * \brief Holds logic for reading and decoding samples from a chunk + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#include "ion_gsms_chunk_data.h" +#include +#if USE_GLOG_AND_GFLAGS +#include +#else +#include +#endif + + +IONGSMSChunkData::IONGSMSChunkData(const GnssMetadata::Chunk& chunk, const std::vector& stream_ids, std::size_t output_stream_offset) + : chunk_(chunk), + sizeword_(chunk_.SizeWord()), + countwords_(chunk_.CountWords()) +{ + // Instantiate the Allocator functor + Allocator allocator(countwords_, buffer_); + // Call with_word_type with the Allocator functor + with_word_type(sizeword_, allocator); + + const std::size_t total_bitsize = sizeword_ * countwords_ * 8; + std::size_t used_bitsize = 0; + std::size_t output_streams = 0; + for (const auto& lump : chunk.Lumps()) + { + for (const auto& stream : lump.Streams()) + { + used_bitsize += stream.Packedbits(); + + bool found = false; + for (const auto& stream_id : stream_ids) + { + if (stream_id == stream.Id()) + { + found = true; + break; + } + } + if (found) + { + streams_.emplace_back(lump, stream, GnssMetadata::encoding_from_string(stream.Encoding()), output_streams + output_stream_offset); + ++output_streams; + std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor(); + std::size_t sample_rate = stream.RateFactor(); + if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization()) + { + // Samples have 'Complex' format + sample_bitsize /= 2; + sample_rate *= 2; + } + output_stream_item_size_.push_back(bits_to_item_size(sample_bitsize)); + output_stream_item_rate_.push_back(sample_rate); + } + else + { + streams_.emplace_back(lump, stream, GnssMetadata::encoding_from_string(stream.Encoding()), -1); + } + } + } + + output_stream_count_ = output_streams; + padding_bitsize_ = total_bitsize - used_bitsize; +} + + +IONGSMSChunkData::~IONGSMSChunkData() +{ + Deleter deleter(static_cast(buffer_)); + with_word_type(sizeword_, deleter); +} + + +std::size_t IONGSMSChunkData::read_from_buffer(uint8_t* buffer, std::size_t offset) +{ + memset(buffer_, 0, sizeword_ * countwords_); + memcpy(buffer_, &buffer[offset], sizeword_ * countwords_); + return sizeword_ * countwords_; +} + + +void IONGSMSChunkData::write_to_output(gr_vector_void_star& outputs, std::vector& output_items) +{ + switch (sizeword_) + { + case 1: + unpack_words(outputs, output_items); + break; + case 2: + unpack_words(outputs, output_items); + break; + case 4: + unpack_words(outputs, output_items); + break; + case 8: + unpack_words(outputs, output_items); + break; + default: + LOG(ERROR) << "Unknown word size (" << std::to_string(sizeword_) << "), unpacking nothing."; + break; + } +} + + +std::size_t IONGSMSChunkData::output_stream_count() const +{ + return output_stream_count_; +} + + +std::size_t IONGSMSChunkData::output_stream_item_size(std::size_t stream_index) const +{ + return output_stream_item_size_[stream_index]; +} + + +std::size_t IONGSMSChunkData::output_stream_item_rate(std::size_t stream_index) const +{ + return output_stream_item_rate_[stream_index]; +} + + +template +void IONGSMSChunkData::unpack_words(gr_vector_void_star& outputs, std::vector& output_items) +{ + WT* data = static_cast(buffer_); + // TODO - Swap endiannes if needed + + IONGSMSChunkUnpackingCtx ctx{ + chunk_.Shift(), + data, + countwords_, + }; + + // Head padding + if (padding_bitsize_ > 0 && chunk_.Padding() == GnssMetadata::Chunk::Head) + { + ctx.shift_padding(padding_bitsize_); + } + + // Samples + for (const auto& [lump, stream, encoding, output_index] : streams_) + { + if (output_index == -1) + { + // skip stream + ctx.shift_padding(stream.Packedbits()); + } + else + { + output_items[output_index] += write_stream_samples(ctx, lump, stream, encoding, &outputs[output_index]); + } + } +} + + +template +std::size_t IONGSMSChunkData::write_stream_samples( + IONGSMSChunkUnpackingCtx& ctx, + const GnssMetadata::Lump& lump, + const GnssMetadata::IonStream& stream, + const GnssMetadata::StreamEncoding stream_encoding, + void** out) +{ + std::size_t sample_bitsize = stream.Packedbits() / stream.RateFactor(); + std::size_t sample_count = stream.RateFactor(); + + if (stream.Packedbits() >= 2 * stream.RateFactor() * stream.Quantization()) + { + // Samples have 'Complex' format + sample_bitsize /= 2; + sample_count *= 2; + } + + if (sample_bitsize <= 8) + { + write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast(out)); + } + else if (sample_bitsize <= 16) + { + write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast(out)); + } + else if (sample_bitsize <= 32) + { + write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast(out)); + } + else if (sample_bitsize <= 64) + { + write_n_samples(ctx, lump.Shift(), sample_bitsize, sample_count, stream_encoding, reinterpret_cast(out)); + } + + return sample_count; +} + + +template +void IONGSMSChunkData::write_n_samples( + IONGSMSChunkUnpackingCtx& ctx, + GnssMetadata::Lump::LumpShift lump_shift, + uint8_t sample_bitsize, + std::size_t sample_count, + GnssMetadata::StreamEncoding stream_encoding, + OT** out) +{ + if (lump_shift == GnssMetadata::Lump::shiftRight) + { + auto* sample = static_cast(*out); + sample += sample_count; + for (std::size_t i = 0; i < sample_count; ++i) + { + *sample = 0; + ctx.shift_sample(sample_bitsize, sample); + decode_sample(sample_bitsize, sample, stream_encoding); + --sample; + } + } + else // if (lump_shift == GnssMetadata::Lump::shiftLeft || lump_shift == GnssMetadata::Lump::shiftUndefined) + { + auto* sample = static_cast(*out); + for (std::size_t i = 0; i < sample_count; ++i) + { + *sample = 0; + ctx.shift_sample(sample_bitsize, sample); + decode_sample(sample_bitsize, sample, stream_encoding); + ++sample; + } + } + + (*out) += sample_count; +} + + +// Static utilities +template +void IONGSMSChunkData::decode_sample(const uint8_t sample_bitsize, Sample* sample, const GnssMetadata::StreamEncoding encoding) +{ + // using SampleType = std::remove_pointer_t; + switch (sample_bitsize) + { + case 2: + *sample = GnssMetadata::two_bit_look_up[encoding][*sample]; + break; + case 3: + *sample = GnssMetadata::three_bit_look_up[encoding][*sample]; + break; + case 4: + *sample = GnssMetadata::four_bit_look_up[encoding][*sample]; + break; + case 5: + *sample = GnssMetadata::five_bit_look_up[encoding][*sample]; + break; + default: + // TODO - Is this an error that can happen? + // for now we'll just do nothing, if the sample is this wide it may need no decoding + break; + } +} diff --git a/src/algorithms/signal_source/libs/ion_gsms_chunk_data.h b/src/algorithms/signal_source/libs/ion_gsms_chunk_data.h new file mode 100644 index 000000000..5170af848 --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms_chunk_data.h @@ -0,0 +1,188 @@ +/*! + * \file ion_gsms_chunk_data.h + * \brief Holds logic for reading and decoding samples from a chunk + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_ION_GSMS_CHUNK_DATA_H +#define GNSS_SDR_ION_GSMS_CHUNK_DATA_H + +#include "ion_gsms_chunk_unpacking_ctx.h" +#include "ion_gsms_stream_encodings.h" +#include +#include +#include +#include +#include +#include +#include + + +inline std::size_t bits_to_item_size(std::size_t bit_count) +{ + if (bit_count <= 8) + { + return 1; + } + if (bit_count <= 16) + { + return 2; + } + if (bit_count <= 32) + { + return 4; + } + if (bit_count <= 64) + { + return 8; + } + + // You are asking too much of this humble processor + std::cerr << "Item size too large (" << std::to_string(bit_count) << "), returning nonsense.\n"; + return 1; +} + + +// Define a functor that has a templated operator() +struct Allocator +{ + size_t countwords_; + void*& buffer_; // Using void* to hold any type of pointer + + Allocator(size_t countwords, void*& buffer) + : countwords_(countwords), buffer_(buffer) {} + + template + void operator()() const + { + buffer_ = new WordType[countwords_]; + } +}; + + +// Define a functor to delete the allocated memory +struct Deleter +{ + void* buffer_; + + explicit Deleter(void* buffer) + : buffer_(buffer) {} + + template + void operator()() const + { + delete[] static_cast(buffer_); + } +}; + + +template +void with_word_type(uint8_t word_size, Callback callback) +{ + switch (word_size) + { + case 1: + callback.template operator()(); + break; + case 2: + callback.template operator()(); + break; + case 4: + callback.template operator()(); + break; + case 8: + callback.template operator()(); + break; + default: + std::cerr << "Unknown word size (" << std::to_string(word_size) << "), returning nonsense.\n"; + break; + } +} + +class IONGSMSChunkData +{ +public: + IONGSMSChunkData(const GnssMetadata::Chunk& chunk, const std::vector& stream_ids, std::size_t output_stream_offset); + + ~IONGSMSChunkData(); + + IONGSMSChunkData(const IONGSMSChunkData& rhl) = delete; + IONGSMSChunkData& operator=(const IONGSMSChunkData& rhl) = delete; + + IONGSMSChunkData(IONGSMSChunkData&& rhl) = delete; + IONGSMSChunkData& operator=(IONGSMSChunkData&& rhl) = delete; + + std::size_t read_from_buffer(uint8_t* buffer, std::size_t offset); + + void write_to_output(gr_vector_void_star& outputs, std::vector& output_items); + + std::size_t output_stream_count() const; + std::size_t output_stream_item_size(std::size_t stream_index) const; + std::size_t output_stream_item_rate(std::size_t stream_index) const; + +private: + template + void unpack_words(gr_vector_void_star& outputs, std::vector& output_items); + + template + std::size_t write_stream_samples( + IONGSMSChunkUnpackingCtx& ctx, + const GnssMetadata::Lump& lump, + const GnssMetadata::IonStream& stream, + GnssMetadata::StreamEncoding stream_encoding, + void** out); + + template + void write_n_samples( + IONGSMSChunkUnpackingCtx& ctx, + GnssMetadata::Lump::LumpShift lump_shift, + uint8_t sample_bitsize, + std::size_t sample_count, + GnssMetadata::StreamEncoding stream_encoding, + OT** out); + + template + static void decode_sample(uint8_t sample_bitsize, Sample* sample, GnssMetadata::StreamEncoding encoding); + + const GnssMetadata::Chunk& chunk_; + uint8_t sizeword_; + uint8_t countwords_; + uint8_t padding_bitsize_; + std::size_t output_stream_count_; + std::vector output_stream_item_size_; + std::vector output_stream_item_rate_; + + struct stream_metadata_t + { + const GnssMetadata::Lump& lump; + const GnssMetadata::IonStream& stream; + GnssMetadata::StreamEncoding stream_encoding; + int output_index = -1; + + stream_metadata_t( + const GnssMetadata::Lump& lump_, + const GnssMetadata::IonStream& stream_, + GnssMetadata::StreamEncoding stream_encoding_, + int output_index_ = -1) : lump(lump_), + stream(stream_), + stream_encoding(stream_encoding_), + output_index(output_index_) + { + } + }; + std::vector streams_; + + void* buffer_; +}; + +#endif // GNSS_SDR_ION_GSMS_CHUNK_DATA_H diff --git a/src/algorithms/signal_source/libs/ion_gsms_chunk_unpacking_ctx.h b/src/algorithms/signal_source/libs/ion_gsms_chunk_unpacking_ctx.h new file mode 100644 index 000000000..6799f1080 --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms_chunk_unpacking_ctx.h @@ -0,0 +1,184 @@ +/*! + * \file ion_gsms_chunk_unpacking_ctx.h + * \brief Holds state and provides utilities for unpacking samples from a chunk + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * This is a template class, and thus, its member functions must be defined in the header file. + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_ION_GSMS_CHUNK_UNPACKING_CTX_H +#define GNSS_SDR_ION_GSMS_CHUNK_UNPACKING_CTX_H + +#include +#include +#include + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_libs + * \{ */ + +template +struct IONGSMSChunkUnpackingCtx +{ + static constexpr uint8_t word_bitsize_ = sizeof(WT) * 8; + + const GnssMetadata::Chunk::WordShift word_shift_direction_; + WT* iterator_ = nullptr; // Not owned by this class, MUST NOT destroy + WT current_word_{}; + uint8_t bitshift_ = 0; + + IONGSMSChunkUnpackingCtx( + const GnssMetadata::Chunk::WordShift word_shift, + WT* data_buffer, + uint8_t data_buffer_word_count) : word_shift_direction_(word_shift) + { + if (word_shift_direction_ == GnssMetadata::Chunk::Left) + { + iterator_ = data_buffer; + } + else if (word_shift_direction_ == GnssMetadata::Chunk::Right) + { + iterator_ = &data_buffer[data_buffer_word_count]; + } + if (iterator_) + { + advance_word(); // Initializes current_word_ + } + } + + void advance_word() + { + WT word = *iterator_; + if (word_shift_direction_ == GnssMetadata::Chunk::Left) + { + ++iterator_; + } + else if (word_shift_direction_ == GnssMetadata::Chunk::Right) + { + --iterator_; + } + + current_word_ = word; + } + + void shift_current_word(uint8_t n) + { + if ((n % word_bitsize_) == 0) + { + for (uint8_t i = 0; i < (n / word_bitsize_); ++i) + { + advance_word(); + } + return; + } + + if (word_shift_direction_ == GnssMetadata::Chunk::Left) + { + current_word_ <<= n; + } + else if (word_shift_direction_ == GnssMetadata::Chunk::Right) + { + current_word_ >>= n; + } + + bitshift_ += n; + if (bitshift_ >= word_bitsize_) + { + advance_word(); + bitshift_ -= word_bitsize_; + } + } + + void shift_padding(uint8_t n_bits) + { + if (n_bits == 0) + { + return; + } + + if ((n_bits + (bitshift_ % word_bitsize_)) >= word_bitsize_) + { + const uint8_t bits_shifted = word_bitsize_ - (bitshift_ % word_bitsize_); + + shift_current_word(bits_shifted); + shift_padding(n_bits - bits_shifted); + } + else + { + shift_current_word(n_bits); + } + } + + template + void shift_sample(uint8_t sample_bitsize, OT* output, uint8_t output_bit_offset = 0) + { + if (sample_bitsize % word_bitsize_ == 0) + { + const uint8_t words_per_sample = sample_bitsize / word_bitsize_; + for (uint8_t i = 0; i < words_per_sample; ++i) + { + if (word_shift_direction_ == GnssMetadata::Chunk::Left) + { + *output |= (current_word_ << ((words_per_sample - 1 - i) * word_bitsize_)); + } + else if (word_shift_direction_ == GnssMetadata::Chunk::Right) + { + *output |= (current_word_ << (i * word_bitsize_)); + // TODO - reverse bit order of sample? maybe? + } + advance_word(); + } + } + else if ((sample_bitsize + (bitshift_ % word_bitsize_)) > word_bitsize_) + { + const uint8_t bits_shifted = word_bitsize_ - (bitshift_ % word_bitsize_); + + if (word_shift_direction_ == GnssMetadata::Chunk::Left) + { + WT mask = ~((1 << (word_bitsize_ - bits_shifted)) - 1); + *output |= ((current_word_ & mask) >> output_bit_offset); + } + else if (word_shift_direction_ == GnssMetadata::Chunk::Right) + { + WT mask = ((1 << (bits_shifted)) - 1); + *output |= (current_word_ & mask) << output_bit_offset; + // TODO - reverse bit order of sample? maybe? + } + + shift_current_word(bits_shifted); + shift_sample(sample_bitsize - bits_shifted, output, bits_shifted); + } + else + { + if (word_shift_direction_ == GnssMetadata::Chunk::Left) + { + WT mask = ~((1 << (word_bitsize_ - sample_bitsize)) - 1); + OT sample = (current_word_ & mask) >> (word_bitsize_ - sample_bitsize); + *output |= (sample) >> output_bit_offset; + } + else if (word_shift_direction_ == GnssMetadata::Chunk::Right) + { + WT mask = ((1 << (sample_bitsize)) - 1); + *output |= (current_word_ & mask) << output_bit_offset; + // TODO - reverse bit order of sample? maybe? + } + + shift_current_word(sample_bitsize); + } + } +}; + +/** \} */ +/** \} */ +#endif // GNSS_SDR_ION_GSMS_CHUNK_UNPACKING_CTX_H diff --git a/src/algorithms/signal_source/libs/ion_gsms_stream_encodings.h b/src/algorithms/signal_source/libs/ion_gsms_stream_encodings.h new file mode 100644 index 000000000..5b39e6497 --- /dev/null +++ b/src/algorithms/signal_source/libs/ion_gsms_stream_encodings.h @@ -0,0 +1,170 @@ +/*! + * \file ion_gsms_stream_encodings.h + * \brief Implements look up tables for all encodings in the standard + * \author Víctor Castillo Agüero, 2024. victorcastilloaguero(at)gmail.com + * + * These tables are taken from the stardard's official document. + * + * ----------------------------------------------------------------------------- + * + * GNSS-SDR is a Global Navigation Satellite System software-defined receiver. + * This file is part of GNSS-SDR. + * + * Copyright (C) 2010-2024 (see AUTHORS file for a list of contributors) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * ----------------------------------------------------------------------------- + */ + +#ifndef GNSS_SDR_ION_GSMS_STREAM_ENCODINGS_H +#define GNSS_SDR_ION_GSMS_STREAM_ENCODINGS_H + +#include + +/** \addtogroup Signal_Source + * \{ */ +/** \addtogroup Signal_Source_libs + * \{ */ + +namespace GnssMetadata +{ + +using StreamEncoding = unsigned char; + +namespace StreamEncodings +{ + +constexpr unsigned char SIGN = 0; +constexpr unsigned char OB = 1; +constexpr unsigned char SM = 2; +constexpr unsigned char MS = 3; +constexpr unsigned char TC = 4; +constexpr unsigned char OG = 5; +constexpr unsigned char OBA = 6; +constexpr unsigned char SMA = 7; +constexpr unsigned char MSA = 8; +constexpr unsigned char TCA = 9; +constexpr unsigned char OGA = 10; +constexpr unsigned char FP = 11; + +} // namespace StreamEncodings + +inline StreamEncoding encoding_from_string(const std::string& str) +{ + if (str == "SIGN") + { + return StreamEncodings::SIGN; + } + if (str == "OB") + { + return StreamEncodings::OB; + } + if (str == "SM") + { + return StreamEncodings::SM; + } + if (str == "MS") + { + return StreamEncodings::MS; + } + if (str == "TC") + { + return StreamEncodings::TC; + } + if (str == "OG") + { + return StreamEncodings::OG; + } + if (str == "OBA") + { + return StreamEncodings::OBA; + } + if (str == "SMA") + { + return StreamEncodings::SMA; + } + if (str == "MSA") + { + return StreamEncodings::MSA; + } + if (str == "TCA") + { + return StreamEncodings::TCA; + } + if (str == "OGA") + { + return StreamEncodings::OGA; + } + if (str == "FP") + { + return StreamEncodings::FP; + } + return 0; +} + +template +inline T two_bit_look_up[11][4]{ + {}, // [0] + {-2, -1, 0, 1}, // [1 /*OB*/] + {0, 1, 0, -1}, // [2 /*SM*/] + {0, 0, 1, -1}, // [3 /*MS*/] + {0, 1, -2, -1}, // [4 /*TC*/] + {-2, -1, 1, 0}, // [5 /*OG*/] + {-3, -1, 1, 3}, // [6 /*OBA*/] + {1, 3, -1, -3}, // [7 /*SMA*/] + {1, -1, 3, -3}, // [8 /*MSA*/] + {1, 3, -3, -1}, // [9 /*TCA*/] + {-3, -1, 3, 1}, // [10 /*OGA*/] +}; + +template +inline T three_bit_look_up[11][8]{ + {}, // [0] + {-4, -3, -2, -1, 0, 1, 2, 3}, // [1 /*OB*/] + {0, 1, 2, 3, 0, -1, -2, -3}, // [2 /*SM*/] + {0, 0, 1, -1, 0, 0, 1, -1}, // [3 /*MS*/] + {0, 1, 2, 3, -4, -3, -2, -1}, // [4 /*TC*/] + {-4, -3, -1, -2, 3, 2, 0, 1}, // [5 /*OG*/] + {-7, -5, -3, -1, 1, 3, 5, 7}, // [6 /*OBA*/] + {1, 3, 5, 7, -1, -3, -5, -7}, // [7 /*SMA*/] + {1, -1, 3, -3, 5, -5, 7, -7}, // [8 /*MSA*/] + {1, 3, 5, 7, -7, -5, -3, -1}, // [9 /*TCA*/] + {-7, -5, -1, -3, 7, 5, 1, 3}, // [10 /*OGA*/] +}; + +template +inline T four_bit_look_up[11][16]{ + {}, // [0] + {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}, // [1 /*OB*/] + {0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7}, // [2 /*SM*/] + {0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1}, // [3 /*MS*/] + {0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1}, // [4 /*TC*/] + {-8, -7, -5, -6, -1, -2, -4, -3, 7, 6, 4, 5, 0, 1, 3, 2}, // [5 /*OG*/] + {-15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15}, // [6 /*OBA*/] + {1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15}, // [7 /*SMA*/] + {1, -1, 3, -3, 5, -5, 7, -7, 9, -9, 11, -11, 13, -13, 15, -15}, // [8 /*MSA*/] + {1, 3, 5, 7, 9, 11, 13, 15, -15, -13, -11, -9, -7, -5, -3, -1}, // [9 /*TCA*/] + {-15, -13, -9, -11, -1, -3, -7, -5, 15, 13, 9, 11, 1, 3, 7, 5}, // [10 /*OGA*/] +}; + +template +inline T five_bit_look_up[11][32]{ + {}, // [0] + {-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, // [1 /*OB*/] + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15}, // [2 /*SM*/] + {0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1, 0, 0, 1, -1}, // [3 /*MS*/] + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1}, // [4 /*TC*/] + {-16, -15, -13, -14, -9, -10, -12, -11, -1, -2, -4, -3, -8, -7, -5, -6, 15, 14, 12, 13, 8, 9, 11, 10, 0, 1, 3, 2, 7, 6, 4, 5}, // [5 /*OG*/] + {-31, -29, -27, -25, -23, -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, // [6 /*OBA*/] + {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, -1, -3, -5, -7, -9, -11, -13, -15, -17, -19, -21, -23, -25, -27, -29, -31}, // [7 /*SMA*/] + {1, -1, 3, -3, 5, -5, 7, -7, 9, -9, 11, -11, 13, -13, 15, -15, 17, -17, 19, -19, 21, -21, 23, -23, 25, -25, 27, -27, 29, -29, 31, -31}, // [8 /*MSA*/] + {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, -31, -29, -27, -25, -23, -21, -19, -17, -15, -13, -11, -9, -7, -5, -3, -1}, // [9 /*TCA*/] + {-31, -29, -25, -27, -17, -19, -23, -21, -1, -3, -7, -5, -15, -13, -9, -11, 31, 29, 25, 27, 17, 19, 23, 21, 1, 3, 7, 5, 15, 13, 9, 11}, // [10 /*OGA*/] +}; + +} // namespace GnssMetadata + + +/** \} */ +/** \} */ +#endif // GNSS_SDR_ION_GSMS_STREAM_ENCODINGS_H diff --git a/src/algorithms/signal_source/libs/ppstcprx.cc b/src/algorithms/signal_source/libs/ppstcprx.cc index c23261aff..94dda2052 100644 --- a/src/algorithms/signal_source/libs/ppstcprx.cc +++ b/src/algorithms/signal_source/libs/ppstcprx.cc @@ -20,19 +20,6 @@ #include #include -pps_tcp_rx::pps_tcp_rx() -{ - // TODO Auto-generated constructor stub - is_connected = false; - clientSd = -1; -} - - -pps_tcp_rx::~pps_tcp_rx() -{ - // TODO Auto-generated destructor stub -} - void pps_tcp_rx::set_pps_samplestamp_queue(std::shared_ptr> queue) { @@ -40,7 +27,7 @@ void pps_tcp_rx::set_pps_samplestamp_queue(std::shared_ptr> Pps_queue; - int clientSd; + int clientSd{-1}; public: - volatile bool is_connected; - pps_tcp_rx(); - virtual ~pps_tcp_rx(); + volatile bool is_connected{false}; + pps_tcp_rx() = default; + virtual ~pps_tcp_rx() = default; - void receive_pps(std::string ip_address, int port); - bool send_cmd(std::string cmd); + void receive_pps(const std::string& ip_address, int port); + bool send_cmd(std::string cmd) const; void set_pps_samplestamp_queue(std::shared_ptr> queue); }; diff --git a/src/core/receiver/CMakeLists.txt b/src/core/receiver/CMakeLists.txt index cacef7f6f..ba945f69b 100644 --- a/src/core/receiver/CMakeLists.txt +++ b/src/core/receiver/CMakeLists.txt @@ -70,6 +70,10 @@ if(ENABLE_FPGA) target_compile_definitions(core_receiver PUBLIC -DENABLE_FPGA=1) endif() +if(ENABLE_ION) + target_compile_definitions(core_receiver PRIVATE -DENABLE_ION_SOURCE=1) +endif() + if(GNURADIO_USES_STD_POINTERS) target_compile_definitions(core_receiver PUBLIC -DGNURADIO_USES_STD_POINTERS=1) endif() @@ -90,6 +94,10 @@ if(ENABLE_PLUTOSDR) target_compile_definitions(core_receiver PRIVATE -DPLUTOSDR_DRIVER=1) endif() +if(ENABLE_AD936X_SDR) + target_compile_definitions(core_receiver PRIVATE -DAD936X_SDR_DRIVER=1) +endif() + if(ENABLE_FMCOMMS2) target_compile_definitions(core_receiver PRIVATE -DFMCOMMS2_DRIVER=1) endif() diff --git a/src/core/receiver/gnss_block_factory.cc b/src/core/receiver/gnss_block_factory.cc index ce77442ee..fceadefb9 100644 --- a/src/core/receiver/gnss_block_factory.cc +++ b/src/core/receiver/gnss_block_factory.cc @@ -163,6 +163,10 @@ #include "plutosdr_signal_source.h" #endif +#if AD936X_SDR_DRIVER +#include "ad936x_custom_signal_source.h" +#endif + #if FMCOMMS2_DRIVER #include "fmcomms2_signal_source.h" #endif @@ -196,6 +200,11 @@ #include "gps_l1_ca_dll_pll_tracking_gpu.h" #endif +#if ENABLE_ION_SOURCE +#undef Owner +#include "ion_gsms_signal_source.h" +#endif + using namespace std::string_literals; namespace @@ -759,7 +768,14 @@ std::unique_ptr GNSSBlockFactory::GetBlock( block = std::move(block_); } #endif - +#if ENABLE_ION_SOURCE + else if (implementation == "ION_GSMS_Signal_Source") + { + std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, + out_streams, queue); + block = std::move(block_); + } +#endif #if RAW_ARRAY_DRIVER else if (implementation == "Raw_Array_Signal_Source") { @@ -795,6 +811,8 @@ std::unique_ptr GNSSBlockFactory::GetBlock( out_streams, queue); block = std::move(block_); } +#endif +#if PLUTOSDR_DRIVER || AD936X_SDR_DRIVER else if (implementation == "Ad936x_Custom_Signal_Source") { std::unique_ptr block_ = std::make_unique(configuration, role, in_streams, From abc07e414b85bd37771a0a8231e12ea0bea56f9a Mon Sep 17 00:00:00 2001 From: Carles Fernandez Date: Sat, 21 Sep 2024 11:40:17 +0200 Subject: [PATCH 219/219] Merging next, solving conflicts (#28) * Decouple the FPGA DMA signal source from the AD9361 FPGA signal source. * Add the MAX2771_EVKIT FPGA signal source and the ENABLE_FPGA_MAX2771_EVKIT flag to enable it. * Adjust cross-compilation flags to properly support FPGA signal sources * fix signal source names for consistency * Detect if the spidev driver is installed when the ENABLE_MAX2771 flag is set. Detect if the DMA proxy driver is installed when the ENABLE_DMA_PROXY flag is set. Check if ENABLE_FPGA is set when either ENABLE_MAX2771 or ENABLE_DMA_PROXY is set. * fix FPGA signal source names for consistency * Fix FPGA-related CMakefile flags * make cpplint happy * make cpplint happy * make cmakelint happy * make clang-format happy * Replaced the AD9361 FPGA signal source with the ADRV9361_Z7035 FPGA and the FMCOMMS5 FPGA signal sources. * Bump local version of GoogleTest to 1.15.2 and Protocol Buffers to 27.3 * Avoid code duplication in CMake modules * Update clang-tidy job * Clang Tidy fixes * Improve efficiency of Concurrent_Map and Concurrent_Queue classes * Fix segmentation fault if the SignalSource implementation is not available * Moved decimation factor count variable to the class * Avoid possible runtime error when PVT.enable_rx_clock_correction=true * Fix formatting * Fix clang-tidy job * Capitalize FPGA in class implementation names * Capitalize acronyms in FPGA-related class names * Instantiate sources only once * Update changelog * Bump version of google benchmark to 1.9.0 * Fix CMakeLists header file list in signal source libs Header file paths were being appended to the source files list. This is not that important since, in general, you don't need to add the header files to the cmake target. * Added ION GNSS SDR Metadata Standard signal source * Only specify outputs for the requested streams * Fixed block iteration withing a file The `File` object only holds a shallow reference to its `Lane` (without the list of blocks). So we must retrieve the full reference manually. * Treat data file paths as relative to the metadata file The data file paths are actually not native paths but URLs, this covers most cases but not all of them. * Fixed decoding errors and refactored each class into its own file * Fixed sample count error & refactored * Bufferef IO & propagate configuration inside ION source * Reset sample value before writing new one Sample values are ORed into the output buffer because they may need a few read/write operations depending on alignment. So, if we don't set the value to 0 before doing this, all samples quickly become 0xFF after a few cycles of the output buffer. * Simpler handling of simpler bit formats If a sample is the same size as a word, it is much easier to read. * Less callback shenanigans * Fix wrong buffer size * Fixed conditional compilation issues And added a comment * Linting fixes * Fixed arithmetic operations on pointers * Fix formatting * Use lock_guard instead of unique_lock * Create a CMake target for the ION dependency for consistency * Improve formatting, add missing include * Fixes for C++ standards older than 20. Avoid C++20-specific lambda templates * Update changelog * Add Victor to the list of authors * Fix CMake error * Fix building error * Fix building * Add -DENABLE_ION=ON to CI jobs * Fix CMake lists * Catch all exceptions * Fix building for -DENABLE_PLUTOSDR=ON * Removed unused member fields and function parameters * Use std::ifstream instead of FILE for reading sample data * Fixed includes and code style * Simplified disconnect() function We can disconnect the sources directly instead of disconnecting each of their outputs. * Implemented range check in `IONGSMSSignalSource::get_right_block(int)` * Moved ION GSMS file source to `gnuradio_blocks/` directory Also fixed some header guards. * Fixed ION GNSS Metadata Standard dependency version * Simplified by removing a very shallow class `ion_gnss_metadata_handler` was only reading the metadata file, which can easily be done in `ion_gsms_signal_source`. * Added valves to properly handle end of samples * Cleaner exit if the data file is not found * Fix uninitialized warning * Remove unused configuration parameter. Uniformize guard names * Fix for CMake < 3.14 * fix configuration options for the FPGA-based AD9361-based boards * Put the global function into an anonymous namespace Use emplace_back instead of push_back * Make private member metadata_ a std::shared_pointer * Simplify code * Remove ION source from CI * Apply clang-tidy fixes * Initialize the receiver local oscillator frequency to GPS_L5_FREQ_HZ by default in the ADRV9361Z7035 FPGA signal source and remove unnecessary include files. * Sort out building flags and improve their reporting * Allow building Ad936x_Custom_Signal_Source when gnuradio-iio is not available * Bump local version of Protocol Buffers to v28.0 * Update AArch64 features to Linux 6.10.6 * Update AArch64 features to Linux 6.10.6 * Fix: Windows does not define __ARM_NEON * Improve detection of the dma_proxy module and the spidev driver * Add missing include (fixes building with modern GCC) * Adapted udp_port to multiple ports * Fixed typo * Fixed clang format * Update changelog * Add Xavier Guerrero to the authors list * Update changelog * Bump local version of Protocol Buffers to 28.1 * Add install and uninstall targets to nav_msg_listener * Add Cesare to the authors list * Add OSNMA to changelog * Leave OSNMA files in the same folder for consistency * Fix conflict --------- Co-authored-by: Marc Majoral Co-authored-by: cesaaargm Co-authored-by: Xavier Guerrero-Pau Co-authored-by: Victor Castillo --- .gitignore | 1 + AUTHORS | 70 +++++++++--------- CITATION.cff | 10 +++ CMakeLists.txt | 71 ++++++++----------- docs/CHANGELOG.md | 13 ++++ src/algorithms/PVT/adapters/rtklib_pvt.cc | 2 +- .../PVT/gnuradio_blocks/rtklib_pvt_gs.cc | 7 +- .../PVT/libs/monitor_pvt_udp_sink.cc | 13 ++-- .../PVT/libs/monitor_pvt_udp_sink.h | 5 +- src/algorithms/PVT/libs/pvt_conf.h | 2 +- .../include/cpu_features_macros.h | 9 +-- .../signal_source/libs/fpga_spidev.h | 1 + src/core/monitor/gnss_synchro_monitor.cc | 9 ++- src/core/monitor/gnss_synchro_monitor.h | 6 +- src/core/monitor/gnss_synchro_udp_sink.cc | 15 ++-- src/core/monitor/gnss_synchro_udp_sink.h | 2 +- src/core/receiver/gnss_flowgraph.cc | 30 ++++++-- src/core/system_parameters/Galileo_OSNMA.h | 8 +-- src/utils/nav-listener/CMakeLists.txt | 16 +++++ src/utils/nav-listener/README.md | 12 ++++ .../cmake/cmake_uninstall.cmake.in | 35 +++++++++ 21 files changed, 226 insertions(+), 111 deletions(-) create mode 100644 src/utils/nav-listener/cmake/cmake_uninstall.cmake.in diff --git a/.gitignore b/.gitignore index 4afd17279..1d7a03d59 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ cmake-build-release/ .vscode/ .vs/ Testing/ + GSDR* PVT_* HAS_* diff --git a/AUTHORS b/AUTHORS index 7df41ed17..eda9cc06f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,40 +33,42 @@ Contact Information List of authors -------------------------------------------------------------------------------- -Carles Fernández-Prades carles.fernandez@cttc.cat Project manager -Javier Arribas javier.arribas@cttc.es Developer -Luis Esteve Elfau luis@epsilon-formacion.com Developer -Marc Majoral marc.majoral@cttc.cat Developer -Jordi Vilà-Valls jordi.vila-valls@isae-supaero.fr Consultant -Pau Closas pau.closas@northeastern.edu Consultant -Álvaro Cebrián Juan acebrianjuan@gmail.com Contributor -Andres Cecilia Luque a.cecilia.luque@gmail.com Contributor -Anthony Arnold anthony.arnold@uqconnect.edu.au Contributor -Antonio Ramos antonio.ramosdet@gmail.com Contributor -Carlos Avilés carlos.avilesr@googlemail.com Contributor -Cillian O'Driscoll cillian.odriscoll@gmail.com Contributor -Damian Miralles dmiralles2009@gmail.com Contributor -Daniel Fehr daniel.co@bluewin.ch Contributor -David Pubill david.pubill@cttc.cat Contributor -En Shin seanstone5923@gmail.com Contributor -Fran Fabra fabra@ice.csic.es Contributor -Gabriel Araujo gabriel.araujo.5000@gmail.com Contributor -Gerald LaMountain gerald@gece.neu.edu Contributor -Into Pääkkönen into.paakkonen@aalto.fi Contributor -Irene Pérez Riega iperrie@inta.es Contributor -Jim Melton jim.melton@sncorp.com Contributor -Josh Schindehette jschindehette@geontech.com Contributor -Leonardo Tonetto tonetto.dev@gmail.com Contributor -Malte Lenhart malte.lenhart@mailbox.org Contributor -Mara Branzanti mara.branzanti@gmail.com Contributor -Marc Molina marc.molina.pena@gmail.com Contributor -Marc Sales marcsales92@gmail.com Contributor -Piyush Gupta piyush04111999@gmail.com Contributor -Rodrigo Muñoz rodrigo.munoz@proteinlab.cl Contributor -Stefan van der Linden spvdlinden@gmail.com Contributor -Víctor Castillo-Agüero victorcastilloaguero@gmail.com Contributor -Will Silberman wsilberm@google.com Contributor -Carlos Paniego carpanie@hotmail.com Artwork +Carles Fernández-Prades carles.fernandez@cttc.cat Project manager +Javier Arribas javier.arribas@cttc.es Developer +Luis Esteve Elfau luis@epsilon-formacion.com Developer +Marc Majoral marc.majoral@cttc.cat Developer +Xavier Guerrero xavier.guerrero@cttc.es Developer +Jordi Vilà-Valls jordi.vila-valls@isae-supaero.fr Consultant +Pau Closas pau.closas@northeastern.edu Consultant +Álvaro Cebrián Juan acebrianjuan@gmail.com Contributor +Andres Cecilia Luque a.cecilia.luque@gmail.com Contributor +Anthony Arnold anthony.arnold@uqconnect.edu.au Contributor +Antonio Ramos antonio.ramosdet@gmail.com Contributor +Carlos Avilés carlos.avilesr@googlemail.com Contributor +Cesare Ghionoiu Martinez c.ghionoiu-martinez@tu-braunschweig.de Contributor +Cillian O'Driscoll cillian.odriscoll@gmail.com Contributor +Damian Miralles dmiralles2009@gmail.com Contributor +Daniel Fehr daniel.co@bluewin.ch Contributor +David Pubill david.pubill@cttc.cat Contributor +En Shin seanstone5923@gmail.com Contributor +Fran Fabra fabra@ice.csic.es Contributor +Gabriel Araujo gabriel.araujo.5000@gmail.com Contributor +Gerald LaMountain gerald@gece.neu.edu Contributor +Into Pääkkönen into.paakkonen@aalto.fi Contributor +Irene Pérez Riega iperrie@inta.es Contributor +Jim Melton jim.melton@sncorp.com Contributor +Josh Schindehette jschindehette@geontech.com Contributor +Leonardo Tonetto tonetto.dev@gmail.com Contributor +Malte Lenhart malte.lenhart@mailbox.org Contributor +Mara Branzanti mara.branzanti@gmail.com Contributor +Marc Molina marc.molina.pena@gmail.com Contributor +Marc Sales marcsales92@gmail.com Contributor +Piyush Gupta piyush04111999@gmail.com Contributor +Rodrigo Muñoz rodrigo.munoz@proteinlab.cl Contributor +Stefan van der Linden spvdlinden@gmail.com Contributor +Víctor Castillo-Agüero victorcastilloaguero@gmail.com Contributor +Will Silberman wsilberm@google.com Contributor +Carlos Paniego carpanie@hotmail.com Artwork # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2011-2024 Carles Fernandez-Prades diff --git a/CITATION.cff b/CITATION.cff index 4bf27081f..337e4d42a 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -20,6 +20,11 @@ authors: family-names: Majoral given-names: Marc orcid: "https://orcid.org/0000-0001-6161-6747" + - affiliation: "Centre Tecnològic de Telecomunicacions de Catalunya (CTTC)" + alias: xguerreropau + email: xavier.guerrero@cttc.es + family-names: Guerrero + given-names: Xavier - alias: Gastd email: gabriel.araujo.5000@gmail.com family-names: Araujo @@ -56,6 +61,11 @@ authors: - email: daniel.co@bluewin.ch family-names: Fehr given-names: Daniel + - alias: cesaaargm + affiliation: "Technische Universität Braunschweig" + email: c.ghionoiu-martinez@tu-braunschweig.de + family-names: "Ghionoiu Martinez" + given-names: Cesare - alias: piyush0411 email: piyush04111999@gmail.com family-names: Gupta diff --git a/CMakeLists.txt b/CMakeLists.txt index 39132e9cf..adad30676 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -360,7 +360,7 @@ set(GNSSSDR_ARMADILLO_LOCAL_VERSION "14.0.x") set(GNSSSDR_GFLAGS_LOCAL_VERSION "2.2.2") set(GNSSSDR_GLOG_LOCAL_VERSION "0.7.1") set(GNSSSDR_MATIO_LOCAL_VERSION "1.5.27") -set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "28.0") +set(GNSSSDR_PROTOCOLBUFFERS_LOCAL_VERSION "28.1") set(GNSSSDR_PUGIXML_LOCAL_VERSION "1.14") set(GNSSSDR_GTEST_LOCAL_VERSION "1.15.2") set(GNSSSDR_GNSS_SIM_LOCAL_VERSION "origin/master") @@ -3358,46 +3358,23 @@ if(ENABLE_MAX2771) if(DEFINED ENV{SDKTARGETSYSROOT}) set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT}) else() - set(TARGET_ROOTFS_PATH "") - endif() - find_program(STRINGS_EXECUTABLE strings) - if(NOT STRINGS_EXECUTABLE) - message(STATUS "The 'strings' command could not be found. See https://www.gnu.org/software/binutils/") - message(STATUS " You can try to install it by typing:") - if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|kFreeBSD|GNU") - if(${LINUX_DISTRIBUTION} MATCHES "Fedora" OR ${LINUX_DISTRIBUTION} MATCHES "Red Hat") - message(STATUS " sudo yum install binutils") - elseif(${LINUX_DISTRIBUTION} MATCHES "openSUSE") - message(STATUS " sudo zypper install binutils") - else() - message(STATUS " sudo apt-get install binutils") - endif() - endif() - message(FATAL_ERROR "Binutils are required to build GNSS-SDR for SoC FPGA devices using the MAX2771 option.") - endif() - set(DTB_FILE "${TARGET_ROOTFS_PATH}/boot/devicetree/system-top.dtb") - if(EXISTS "${DTB_FILE}") - message(STATUS "Found DTB file: ${DTB_FILE}") - # Run the strings command and grep for "spidev" - execute_process( - COMMAND ${STRINGS_EXECUTABLE} ${DTB_FILE} - COMMAND grep "spidev" - OUTPUT_VARIABLE GREP_OUTPUT - RESULT_VARIABLE GREP_RESULT - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(GREP_RESULT EQUAL 0) - message(STATUS "Found spidev-compatible peripheral in ${DTB_FILE}.") + string(REGEX MATCH "(.*/tmp-glibc)" MATCHED_PATH "${GNURADIO_RUNTIME_INCLUDE_DIRS}") + if(MATCHED_PATH) + set(TARGET_ROOTFS_PATH "${MATCHED_PATH}/sysroots-components") else() - message(STATUS "SPIdev driver not found, its installation is required.") - if(ENABLE_PACKAGING) - set(ENABLE_MAX2771 OFF) - else() - message(FATAL_ERROR "SPIdev driver is required for building gnss-sdr with -DENABLE_MAX2271=ON.") - endif() + set(TARGET_ROOTFS_PATH "") endif() + endif() + file(GLOB_RECURSE SPIDEV_FILE "${TARGET_ROOTFS_PATH}/*/spidev.h") + if(EXISTS "${SPIDEV_FILE}") + message(STATUS "SPIdev driver found: ${SPIDEV_FILE}") else() - message(FATAL_ERROR "The device tree (DTB) file ${DTB_FILE} cannot be found.") + message(STATUS "SPIdev driver not found, its installation is required.") + if(ENABLE_PACKAGING) + set(ENABLE_MAX2771 OFF) + else() + message(FATAL_ERROR "SPIdev driver is required for building gnss-sdr with -DENABLE_MAX2271=ON.") + endif() endif() endif() @@ -3412,9 +3389,14 @@ if(ENABLE_DMA_PROXY) if(DEFINED ENV{SDKTARGETSYSROOT}) set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT}) else() - set(TARGET_ROOTFS_PATH "") + string(REGEX MATCH "(.*/tmp-glibc)" MATCHED_PATH "${GNURADIO_RUNTIME_INCLUDE_DIRS}") + if(MATCHED_PATH) + set(TARGET_ROOTFS_PATH "${MATCHED_PATH}/sysroots-components") + else() + set(TARGET_ROOTFS_PATH "") + endif() endif() - set(DMA_PROXY_FILE "${TARGET_ROOTFS_PATH}/lib/modules/5.10.0-xilinx-v2021.2/extra/dma-proxy.ko") + file(GLOB_RECURSE DMA_PROXY_FILE "${TARGET_ROOTFS_PATH}/*/dma-proxy.ko") if(EXISTS "${DMA_PROXY_FILE}") message(STATUS "Found dma-proxy.ko file: ${DMA_PROXY_FILE}") else() @@ -3513,9 +3495,14 @@ if(ENABLE_DMA_PROXY) if(DEFINED ENV{SDKTARGETSYSROOT}) set(TARGET_ROOTFS_PATH $ENV{SDKTARGETSYSROOT}) else() - set(TARGET_ROOTFS_PATH "") + string(REGEX MATCH "(.*/tmp-glibc)" MATCHED_PATH "${GNURADIO_RUNTIME_INCLUDE_DIRS}") + if(MATCHED_PATH) + set(TARGET_ROOTFS_PATH "${MATCHED_PATH}/sysroots-components") + else() + set(TARGET_ROOTFS_PATH "") + endif() endif() - set(DMA_PROXY_FILE "${TARGET_ROOTFS_PATH}/lib/modules/5.10.0-xilinx-v2021.2/extra/dma-proxy.ko") + file(GLOB_RECURSE DMA_PROXY_FILE "${TARGET_ROOTFS_PATH}/*/dma-proxy.ko") if(EXISTS "${DMA_PROXY_FILE}") message(STATUS "Found dma-proxy.ko file: ${DMA_PROXY_FILE}") else() diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 327b26a8d..d18c58ffe 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -45,6 +45,8 @@ All notable changes to GNSS-SDR will be documented in this file. described with the [ION GNSS Software Defined Receiver Metadata Standard](https://sdr.ion.org/). It requires the `-DENABLE_ION=ON` building configuration option. +- The `Monitor` and `PVT` blocks are now able to send data to multiple UDP + ports. ### Improvements in Portability: @@ -89,9 +91,20 @@ All notable changes to GNSS-SDR will be documented in this file. Accordingly, the GNSS-SDR building system now looks for OpenSSL in the first place and, if not found, then it looks for GnuTLS as a fallback. +### Reliability + +- Implementation of the Galileo Open Service Navigation Message Authentication + (OSNMA), a data authentication function for the Galileo Open Service worldwide + users, freely accessible to all. OSNMA provides receivers with the assurance + that the received Galileo navigation message is coming from the system itself + and has not been modified. OSNMA is enabled by default if the receiver + configuration defines Galileo E1 OS channels. More details can be found in + [Introducing GNSS Navigation Message Authentication](https://gnss-sdr.org/osnma). + ### Improvements in Usability: - Tidy up the `conf/` folder. +- Add `install` and `uninstall` targets to the `nav_msg_listener` utility. See the definitions of concepts and metrics at https://gnss-sdr.org/design-forces/ diff --git a/src/algorithms/PVT/adapters/rtklib_pvt.cc b/src/algorithms/PVT/adapters/rtklib_pvt.cc index e964cf5a6..529c330f3 100644 --- a/src/algorithms/PVT/adapters/rtklib_pvt.cc +++ b/src/algorithms/PVT/adapters/rtklib_pvt.cc @@ -887,7 +887,7 @@ Rtklib_Pvt::Rtklib_Pvt(const ConfigurationInterface* configuration, // Read PVT MONITOR Configuration pvt_output_parameters.monitor_enabled = configuration->property(role + ".enable_monitor", false); pvt_output_parameters.udp_addresses = configuration->property(role + ".monitor_client_addresses", std::string("127.0.0.1")); - pvt_output_parameters.udp_port = configuration->property(role + ".monitor_udp_port", 1234); + pvt_output_parameters.udp_ports = configuration->property(role + ".monitor_udp_port", std::string("1234")); pvt_output_parameters.protobuf_enabled = configuration->property(role + ".enable_protobuf", true); if (configuration->property("Monitor.enable_protobuf", false) == true) { diff --git a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc index 23fd9605d..33db19222 100644 --- a/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc +++ b/src/algorithms/PVT/gnuradio_blocks/rtklib_pvt_gs.cc @@ -482,7 +482,12 @@ rtklib_pvt_gs::rtklib_pvt_gs(uint32_t nchannels, std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); - d_udp_sink_ptr = std::make_unique(udp_addr_vec, conf_.udp_port, conf_.protobuf_enabled); + std::string port_string = conf_.udp_ports; + std::vector udp_port_vec = split_string(port_string, '_'); + std::sort(udp_port_vec.begin(), udp_port_vec.end()); + udp_port_vec.erase(std::unique(udp_port_vec.begin(), udp_port_vec.end()), udp_port_vec.end()); + + d_udp_sink_ptr = std::make_unique(udp_addr_vec, udp_port_vec, conf_.protobuf_enabled); } else { diff --git a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc index 9caef6f4d..f9a60e0ac 100644 --- a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc +++ b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.cc @@ -17,19 +17,24 @@ #include "monitor_pvt_udp_sink.h" #include +#include #include #include -Monitor_Pvt_Udp_Sink::Monitor_Pvt_Udp_Sink(const std::vector& addresses, - const uint16_t& port, +Monitor_Pvt_Udp_Sink::Monitor_Pvt_Udp_Sink( + const std::vector& addresses, + const std::vector& ports, bool protobuf_enabled) : socket{io_context}, use_protobuf(protobuf_enabled) { for (const auto& address : addresses) { - boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(address, error), port); - endpoints.push_back(endpoint); + for (const auto& port : ports) + { + boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(address, error), boost::lexical_cast(port)); + endpoints.push_back(endpoint); + } } if (use_protobuf) diff --git a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.h b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.h index 1fbe3219d..393e4e5e2 100644 --- a/src/algorithms/PVT/libs/monitor_pvt_udp_sink.h +++ b/src/algorithms/PVT/libs/monitor_pvt_udp_sink.h @@ -40,7 +40,10 @@ using b_io_context = boost::asio::io_service; class Monitor_Pvt_Udp_Sink { public: - Monitor_Pvt_Udp_Sink(const std::vector& addresses, const uint16_t& port, bool protobuf_enabled); + Monitor_Pvt_Udp_Sink( + const std::vector& addresses, + const std::vector& ports, + bool protobuf_enabled); bool write_monitor_pvt(const Monitor_Pvt* const monitor_pvt); private: diff --git a/src/algorithms/PVT/libs/pvt_conf.h b/src/algorithms/PVT/libs/pvt_conf.h index 19d0a2e8d..f014325ba 100644 --- a/src/algorithms/PVT/libs/pvt_conf.h +++ b/src/algorithms/PVT/libs/pvt_conf.h @@ -48,6 +48,7 @@ public: std::string rtcm_output_file_path = std::string("."); std::string has_output_file_path = std::string("."); std::string udp_addresses; + std::string udp_ports; std::string udp_eph_addresses; std::string log_source_timetag_file; @@ -64,7 +65,6 @@ public: int32_t rinexobs_rate_ms = 0; int32_t an_rate_ms = 20; int32_t max_obs_block_rx_clock_offset_ms = 40; - int udp_port = 0; int udp_eph_port = 0; int rtk_trace_level = 0; diff --git a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpu_features_macros.h b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpu_features_macros.h index c800d0c32..b595a22f2 100644 --- a/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpu_features_macros.h +++ b/src/algorithms/libs/volk_gnsssdr_module/volk_gnsssdr/cpu_features/include/cpu_features_macros.h @@ -226,13 +226,14 @@ #endif // defined(CPU_FEATURES_ARCH_X86) -#if defined(CPU_FEATURES_ARCH_ANY_ARM) -#if defined(__ARM_NEON) +// Note: MSVC targeting ARM does not define `__ARM_NEON` but Windows on ARM +// requires it. In that case we force NEON detection. +#if defined(__ARM_NEON) || \ + (defined(CPU_FEATURES_COMPILER_MSC) && defined(CPU_FEATURES_ARCH_ANY_ARM)) #define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1 #else #define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0 -#endif // defined(__ARM_NEON) -#endif // defined(CPU_FEATURES_ARCH_ANY_ARM) +#endif #if defined(CPU_FEATURES_ARCH_MIPS) #if defined(__mips_msa) diff --git a/src/algorithms/signal_source/libs/fpga_spidev.h b/src/algorithms/signal_source/libs/fpga_spidev.h index 5fbe2f41c..ccef015d2 100644 --- a/src/algorithms/signal_source/libs/fpga_spidev.h +++ b/src/algorithms/signal_source/libs/fpga_spidev.h @@ -16,6 +16,7 @@ #ifndef GNSS_SDR_FPGA_SPIDEV_H #define GNSS_SDR_FPGA_SPIDEV_H +#include #include class Fpga_spidev diff --git a/src/core/monitor/gnss_synchro_monitor.cc b/src/core/monitor/gnss_synchro_monitor.cc index 98526fe60..f63811a73 100644 --- a/src/core/monitor/gnss_synchro_monitor.cc +++ b/src/core/monitor/gnss_synchro_monitor.cc @@ -26,21 +26,20 @@ gnss_synchro_monitor_sptr gnss_synchro_make_monitor(int n_channels, int decimation_factor, - int udp_port, + const std::vector& udp_ports, const std::vector& udp_addresses, bool enable_protobuf) { return gnss_synchro_monitor_sptr(new gnss_synchro_monitor(n_channels, decimation_factor, - udp_port, + udp_ports, udp_addresses, enable_protobuf)); } - gnss_synchro_monitor::gnss_synchro_monitor(int n_channels, int decimation_factor, - int udp_port, + const std::vector& udp_ports, const std::vector& udp_addresses, bool enable_protobuf) : gr::block("gnss_synchro_monitor", @@ -50,7 +49,7 @@ gnss_synchro_monitor::gnss_synchro_monitor(int n_channels, d_nchannels(n_channels), d_decimation_factor(decimation_factor) { - udp_sink_ptr = std::make_unique(udp_addresses, udp_port, enable_protobuf); + udp_sink_ptr = std::make_unique(udp_addresses, udp_ports, enable_protobuf); } diff --git a/src/core/monitor/gnss_synchro_monitor.h b/src/core/monitor/gnss_synchro_monitor.h index 64749a001..4edd012e1 100644 --- a/src/core/monitor/gnss_synchro_monitor.h +++ b/src/core/monitor/gnss_synchro_monitor.h @@ -41,7 +41,7 @@ using gnss_synchro_monitor_sptr = gnss_shared_ptr; gnss_synchro_monitor_sptr gnss_synchro_make_monitor(int n_channels, int decimation_factor, - int udp_port, + const std::vector& udp_ports, const std::vector& udp_addresses, bool enable_protobuf); @@ -61,13 +61,13 @@ public: private: friend gnss_synchro_monitor_sptr gnss_synchro_make_monitor(int n_channels, int decimation_factor, - int udp_port, + const std::vector& udp_ports, const std::vector& udp_addresses, bool enable_protobuf); gnss_synchro_monitor(int n_channels, int decimation_factor, - int udp_port, + const std::vector& udp_ports, const std::vector& udp_addresses, bool enable_protobuf); diff --git a/src/core/monitor/gnss_synchro_udp_sink.cc b/src/core/monitor/gnss_synchro_udp_sink.cc index 336f834cb..45a6e441e 100644 --- a/src/core/monitor/gnss_synchro_udp_sink.cc +++ b/src/core/monitor/gnss_synchro_udp_sink.cc @@ -17,12 +17,14 @@ #include "gnss_synchro_udp_sink.h" #include +#include #include #include #include -Gnss_Synchro_Udp_Sink::Gnss_Synchro_Udp_Sink(const std::vector& addresses, - const uint16_t& port, +Gnss_Synchro_Udp_Sink::Gnss_Synchro_Udp_Sink( + const std::vector& addresses, + const std::vector& ports, bool enable_protobuf) : socket{io_context}, use_protobuf(enable_protobuf) @@ -33,8 +35,13 @@ Gnss_Synchro_Udp_Sink::Gnss_Synchro_Udp_Sink(const std::vector& add } for (const auto& address : addresses) { - boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(address, error), port); - endpoints.push_back(endpoint); + for (const auto& port : ports) + { + boost::asio::ip::udp::endpoint endpoint( + boost::asio::ip::address::from_string(address, error), + boost::lexical_cast(port)); + endpoints.push_back(endpoint); + } } } diff --git a/src/core/monitor/gnss_synchro_udp_sink.h b/src/core/monitor/gnss_synchro_udp_sink.h index cf777cc12..699a6043f 100644 --- a/src/core/monitor/gnss_synchro_udp_sink.h +++ b/src/core/monitor/gnss_synchro_udp_sink.h @@ -45,7 +45,7 @@ using b_io_context = boost::asio::io_service; class Gnss_Synchro_Udp_Sink { public: - Gnss_Synchro_Udp_Sink(const std::vector& addresses, const uint16_t& port, bool enable_protobuf); + Gnss_Synchro_Udp_Sink(const std::vector& addresses, const std::vector& ports, bool enable_protobuf); bool write_gnss_synchro(const std::vector& stocks); private: diff --git a/src/core/receiver/gnss_flowgraph.cc b/src/core/receiver/gnss_flowgraph.cc index 593c9912c..785672670 100644 --- a/src/core/receiver/gnss_flowgraph.cc +++ b/src/core/receiver/gnss_flowgraph.cc @@ -237,11 +237,17 @@ void GNSSFlowgraph::init() std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); + std::string udp_port_string = configuration_->property("Monitor.udp_port", std::string("1234")); + std::vector udp_port_vec = split_string(udp_port_string, '_'); + std::sort(udp_port_vec.begin(), udp_port_vec.end()); + udp_port_vec.erase(std::unique(udp_port_vec.begin(), udp_port_vec.end()), udp_port_vec.end()); + // Instantiate monitor object GnssSynchroMonitor_ = gnss_synchro_make_monitor(channels_count_, configuration_->property("Monitor.decimation_factor", 1), - configuration_->property("Monitor.udp_port", 1234), - udp_addr_vec, enable_protobuf); + udp_port_vec, + udp_addr_vec, + enable_protobuf); } /* @@ -261,10 +267,16 @@ void GNSSFlowgraph::init() std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); + std::string udp_port_string = configuration_->property("AcquisitionMonitor.udp_port", std::string("1235")); + std::vector udp_port_vec = split_string(udp_port_string, '_'); + std::sort(udp_port_vec.begin(), udp_port_vec.end()); + udp_port_vec.erase(std::unique(udp_port_vec.begin(), udp_port_vec.end()), udp_port_vec.end()); + GnssSynchroAcquisitionMonitor_ = gnss_synchro_make_monitor(channels_count_, configuration_->property("AcquisitionMonitor.decimation_factor", 1), - configuration_->property("AcquisitionMonitor.udp_port", 1235), - udp_addr_vec, enable_protobuf); + udp_port_vec, + udp_addr_vec, + enable_protobuf); } /* @@ -284,10 +296,16 @@ void GNSSFlowgraph::init() std::sort(udp_addr_vec.begin(), udp_addr_vec.end()); udp_addr_vec.erase(std::unique(udp_addr_vec.begin(), udp_addr_vec.end()), udp_addr_vec.end()); + std::string udp_port_string = configuration_->property("TrackingMonitor.udp_port", std::string("1236")); + std::vector udp_port_vec = split_string(udp_port_string, '_'); + std::sort(udp_port_vec.begin(), udp_port_vec.end()); + udp_port_vec.erase(std::unique(udp_port_vec.begin(), udp_port_vec.end()), udp_port_vec.end()); + GnssSynchroTrackingMonitor_ = gnss_synchro_make_monitor(channels_count_, configuration_->property("TrackingMonitor.decimation_factor", 1), - configuration_->property("TrackingMonitor.udp_port", 1236), - udp_addr_vec, enable_protobuf); + udp_port_vec, + udp_addr_vec, + enable_protobuf); } /* diff --git a/src/core/system_parameters/Galileo_OSNMA.h b/src/core/system_parameters/Galileo_OSNMA.h index 68c374a8b..b394781cd 100644 --- a/src/core/system_parameters/Galileo_OSNMA.h +++ b/src/core/system_parameters/Galileo_OSNMA.h @@ -158,10 +158,10 @@ const std::unordered_map OSNMA_TABLE_15 = { {std::string("ECDSA P-256"), 512}, {std::string("ECDSA P-521"), 1056}}; // key: ECDSA Curve and hash function, value: {l_ds_bits} -const std::string PEMFILE_DEFAULT("./data/OSNMA_PublicKey.pem"); -const std::string CRTFILE_DEFAULT("./data/OSNMA_PublicKey_20240115100000_newPKID_1.crt"); -const std::string MERKLEFILE_DEFAULT("./data/OSNMA_MerkleTree_20240115100000_newPKID_1.xml"); -const std::string KROOTFILE_DEFAULT("./data/OSNMA_DSM_KROOT_NMAHeader.bin"); +const std::string PEMFILE_DEFAULT("./OSNMA_PublicKey.pem"); +const std::string CRTFILE_DEFAULT("./OSNMA_PublicKey_20240115100000_newPKID_1.crt"); +const std::string MERKLEFILE_DEFAULT("./OSNMA_MerkleTree_20240115100000_newPKID_1.xml"); +const std::string KROOTFILE_DEFAULT("./OSNMA_DSM_KROOT_NMAHeader.bin"); class Mack_lookup { diff --git a/src/utils/nav-listener/CMakeLists.txt b/src/utils/nav-listener/CMakeLists.txt index cc86a7bf4..ea9c5d36e 100644 --- a/src/utils/nav-listener/CMakeLists.txt +++ b/src/utils/nav-listener/CMakeLists.txt @@ -39,3 +39,19 @@ target_include_directories(navmsg_lib add_executable(nav_msg_listener ${NAVLISTENER_SOURCE_DIR}/main.cc) target_link_libraries(nav_msg_listener PUBLIC navmsg_lib) + +install(TARGETS nav_msg_listener + RUNTIME DESTINATION bin + COMPONENT "nav_msg_listener" +) + +if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY + ) + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake + ) +endif() diff --git a/src/utils/nav-listener/README.md b/src/utils/nav-listener/README.md index 76b2aedaf..4bd90658e 100644 --- a/src/utils/nav-listener/README.md +++ b/src/utils/nav-listener/README.md @@ -27,6 +27,18 @@ $ cmake .. $ make ``` +Optionally, you can install it: + +``` +$ sudo make install +``` + +and uninstall it later with: + +``` +$ sudo make uninstall +``` + ## Usage In order to tell GNSS-SDR to generate those messages, you need to include the diff --git a/src/utils/nav-listener/cmake/cmake_uninstall.cmake.in b/src/utils/nav-listener/cmake/cmake_uninstall.cmake.in new file mode 100644 index 000000000..fc57491c4 --- /dev/null +++ b/src/utils/nav-listener/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,35 @@ +# GNSS-SDR is a Global Navigation Satellite System software-defined receiver. +# This file is part of GNSS-SDR. +# +# SPDX-FileCopyrightText: 2011-2020 C. Fernandez-Prades cfernandez(at)cttc.es +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif() + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + if(CMAKE_VERSION VERSION_LESS 3.17) + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + else() + execute_process( + COMMAND @CMAKE_COMMAND@ -E rm "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + endif() + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif() + else() + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif() +endforeach()