mirror of
https://github.com/gnss-sdr/gnss-sdr
synced 2024-12-12 19:20:32 +00:00
[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
This commit is contained in:
parent
aede664b5a
commit
f534ef859c
@ -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<uint8_t> computed_merkle_root; // x_4_0
|
||||
std::vector<uint8_t> base_leaf = compute_base_leaf(message); // m_i
|
||||
|
||||
// build base leaf m_i
|
||||
std::vector<uint8_t> 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<uint8_t> x_0,x_1,x_2,x_3,x_4;
|
||||
LOG(INFO) << "Galileo OSNMA: DSM-PKR :: leaf provided: m_" << static_cast<int>(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<uint8_t> osnma_msg_receiver::compute_merke_root(const DSM_PKR_message& dsm_pkr_message, const std::vector<uint8_t>& m_i) const
|
||||
{
|
||||
std::vector<uint8_t> 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<uint8_t> osnma_msg_receiver::compute_base_leaf(const DSM_PKR_message& dsm_pkr_message) const
|
||||
{ // build base leaf m_i
|
||||
std::vector<uint8_t> 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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,26 +69,35 @@ private:
|
||||
void local_time_verification(const std::shared_ptr<OSNMA_msg>& osnma_msg);
|
||||
void process_dsm_block(const std::shared_ptr<OSNMA_msg>& osnma_msg);
|
||||
void process_dsm_message(const std::vector<uint8_t>& dsm_msg, const std::shared_ptr<OSNMA_msg>& osnma_msg);
|
||||
bool verify_dsm_pkr(DSM_PKR_message message);
|
||||
void read_and_process_mack_block(const std::shared_ptr<OSNMA_msg>& 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<uint8_t>& key, uint32_t TOW);
|
||||
void remove_verified_tags();
|
||||
void control_tags_awaiting_verify_size();
|
||||
std::vector<uint8_t> build_message(const Tag& tag);
|
||||
std::vector<uint8_t> hash_chain(uint32_t num_of_hashes_needed, std::vector<uint8_t> 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<uint8_t>& applicable_key, NavData applicable_NavData);
|
||||
std::vector<uint8_t> compute_base_leaf(const DSM_PKR_message& dsm_pkr_message) const;
|
||||
std::vector<uint8_t> compute_merke_root(const DSM_PKR_message& dsm_pkr_message, const std::vector<uint8_t>& 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<uint8_t>& applicable_key, NavData applicable_NavData);
|
||||
bool verify_tesla_key(std::vector<uint8_t>& 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<uint32_t, std::map<uint32_t, NavData>> d_satellite_nav_data; // map holding NavData sorted by SVID (first key) and TOW (second key).
|
||||
std::map<uint32_t, std::vector<uint8_t>> d_tesla_keys; // tesla keys over time, sorted by TOW
|
||||
std::vector<MACK_message> d_macks_awaiting_MACSEQ_verification;
|
||||
std::multimap<uint32_t, Tag> d_tags_awaiting_verify; // container with tags to verify from arbitrary SVIDs, sorted by TOW
|
||||
std::unique_ptr<OSNMA_DSM_Reader> d_dsm_reader;
|
||||
std::unique_ptr<Gnss_Crypto> d_crypto;
|
||||
std::unique_ptr<OSNMA_DSM_Reader> d_dsm_reader; // osnma parameters parser
|
||||
std::unique_ptr<Gnss_Crypto> d_crypto; // access to cryptographic functions
|
||||
std::unique_ptr<Osnma_Helper> d_helper;
|
||||
|
||||
std::array<std::array<uint8_t, 256>, 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<uint8_t> d_tags_to_verify{0,4,12};
|
||||
std::vector<uint8_t> 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<uint8_t> build_message(const Tag& tag);
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, VerifyPublicKey);
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, ComputeBaseLeaf);
|
||||
FRIEND_TEST(OsnmaMsgReceiverTest, ComputeMerkleRoot);
|
||||
};
|
||||
|
||||
|
||||
|
@ -54,6 +54,9 @@ public:
|
||||
{
|
||||
return d_x_4_0;
|
||||
}
|
||||
inline void setMerkleRoot(std::vector<uint8_t> v){
|
||||
d_x_4_0 = v;
|
||||
}
|
||||
|
||||
private:
|
||||
void read_merkle_xml(const std::string& merkleFilePath);
|
||||
|
@ -47,7 +47,7 @@ std::vector<uint8_t> 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<uint8_t> Osnma_Helper::bytes(const std::string& binaryString) {
|
||||
std::vector<uint8_t> Osnma_Helper::bytes(const std::string& binaryString) const {
|
||||
std::vector<uint8_t> bytes;
|
||||
|
||||
// Determine the size of the padding needed.
|
||||
@ -68,7 +68,7 @@ std::vector<uint8_t> 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<uint8_t>& vector)
|
||||
std::string Osnma_Helper::convert_to_hex_string(const std::vector<uint8_t>& 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<uint8_t>& vect
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Osnma_Helper::convert_from_hex_string(const std::string& hex_string) const
|
||||
{
|
||||
std::vector<uint8_t> 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<uint8_t>(std::stoul(byte_string, nullptr, 16));
|
||||
result.push_back(byte);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -28,9 +28,10 @@ public:
|
||||
~Osnma_Helper() = default;
|
||||
uint32_t compute_gst(uint32_t WN, uint32_t TOW) const;
|
||||
std::vector<uint8_t> gst_to_uint8(uint32_t GST) const;
|
||||
std::vector<uint8_t> bytes(const std::string& binaryString);
|
||||
std::string verification_status_str(int status);
|
||||
std::string convert_to_hex_string(const std::vector<uint8_t>& vector);
|
||||
std::vector<uint8_t> bytes(const std::string& binaryString) const;
|
||||
std::string verification_status_str(const int& status) const;
|
||||
std::string convert_to_hex_string(const std::vector<uint8_t>& vector) const ;
|
||||
std::vector<uint8_t> convert_from_hex_string(const std::string& hex_string) const; // TODO remove similar function in gnss_crypto
|
||||
};
|
||||
|
||||
#endif // GNSS_SDR_OSNMA_HELPER_H
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <vector>
|
||||
|
||||
#if USE_GLOG_AND_GFLAGS
|
||||
#include "osnma_helper.h"
|
||||
#include "gnss_crypto.h"
|
||||
#include <glog/logging.h> // for LOG
|
||||
#include <filesystem>
|
||||
#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<int8_t, 15> nma_position_filled;
|
||||
@ -59,6 +62,77 @@ public:
|
||||
std::vector<uint8_t> extract_page_bytes(const TestVector& tv, const int byte_index, const int num_bytes);
|
||||
};
|
||||
|
||||
TEST_F(OsnmaMsgReceiverTest, ComputeMerkleRoot)
|
||||
{
|
||||
// Arrange
|
||||
// ----------
|
||||
std::vector<uint8_t> computed_merkle_root;
|
||||
std::vector<uint8_t> 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<uint8_t> base_leaf = helper.convert_from_hex_string("120303B2CE64BC207BDD8BC4DF859187FCB686320D63FFA091410FC158FBB77980EA");
|
||||
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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())
|
||||
{
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user