Keep the colleague's microbu-esp32c5 tree in this repository

obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but
that tree was gitignored, so a clone of this repository could not build the
firmware it ships. It is now committed here as ordinary files in its own
folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP
bridge's signature verification (--trust) used on the bench. Nothing is
fetched from or pushed to the colleague's repository; this repository and
its remotes carry everything. The folder's own .gitignore keeps build output,
downloaded components and private key material out, as it did there; the
committed file set is identical to that repository's tracked files.

The ESP32-C5 is still flashed from obu-firmware/, which only takes
vanetza-idf from microbu-esp32c5/, so the two stay separate folders.
FLASHING.md says how to take a newer version of the colleague's tree (copy
it over the folder, rebuild, test, commit).
This commit is contained in:
Ashin Walpola
2026-09-23 17:46:40 +02:00
parent 2f60623e18
commit 0e9525162d
9881 changed files with 1582523 additions and 17 deletions
@@ -0,0 +1,44 @@
include(UseGTest)
add_library(security_test_v2 STATIC
check_basic_elements.cpp
check_certificate.cpp
check_encryption_parameter.cpp
check_header_field.cpp
check_public_key.cpp
check_recipient_info.cpp
check_region.cpp
check_secured_message.cpp
check_signature.cpp
check_signer_info.cpp
check_subject_attribute.cpp
check_trailer_field.cpp
check_validity_restriction.cpp
)
target_include_directories(security_test_v2 PUBLIC $<TARGET_PROPERTY:security,INTERFACE_INCLUDE_DIRECTORIES>)
target_link_libraries(security_test_v2 PUBLIC ${GTest_LIBRARY})
configure_gtest_directory(LINK_LIBRARIES Boost::boost security security_test security_test_v2
COMPILE_DEFINITIONS ASSET_DIR="${SECURITY_TEST_ASSET_DIR}")
add_gtest(Certificate certificate.cpp)
add_gtest(CertificateCache certificate_cache.cpp)
add_gtest(DefaultCertificateValidator default_certificate_validator.cpp)
add_gtest(EccPoint ecc_point.cpp)
add_gtest(EncryptionParameter encryption_parameter.cpp)
add_gtest(HeaderField header_field.cpp)
add_gtest(IntX int_x.cpp)
add_gtest(LengthEncoding length_encoding.cpp)
add_gtest(NaiveCertificateProvider naive_certificate_provider.cpp)
add_gtest(Payload payload.cpp)
add_gtest(PersistenceV2 persistence.cpp COMPILE_DEFINITIONS WORK_DIR="${CMAKE_CURRENT_BINARY_DIR}")
add_gtest(PublicKeyV2 public_key.cpp)
add_gtest(RecipientInfo recipient_info.cpp)
add_gtest(Region region.cpp)
add_gtest(SecuredMessage secured_message.cpp)
add_gtest(SecurityEntity security_entity.cpp)
add_gtest(Signature signature.cpp)
add_gtest(SignerInfo signer_info.cpp)
add_gtest(SubjectAttribute subject_attribute.cpp)
add_gtest(SubjectInfo subject_info.cpp)
add_gtest(TrailerField trailer_field.cpp)
add_gtest(TrustStore trust_store.cpp)
add_gtest(ValidityRestriction validity_restriction.cpp)
@@ -0,0 +1,66 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/certificate.hpp>
#include <vanetza/security/v2/tests/check_certificate.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza::security::v2;
using vanetza::security::deserialize_from_hexstring;
TEST(Certificate, WebValidator_RootCA_v2)
{
const char str[] =
"0200040C547275737465645F526F6F74808D000004F1817DD05116B855A853F80DB171A3A470D431"
"70EA7EEFD8EF392D66ECEFBE501CEBA19963C9B6447574424FFF1BB89485743F4D09A72B715FC73C"
"87E5F70A110101000441279A383B80C812B72B1A5F5C3C590E5041C634A1ADCC4CE58393CA046D3C"
"619717AEF634F7D80D5F6A29FA7F86EBF823ACE0097A71EE0DF0793034B0D3797C02E0200224250B"
"0114B12B03154E0D83030000007D12BADF99D7070BCB237ED1FA7A5D86FD47E6ABA8E616B35E95A2"
"856FC6E26A493E1215BCEE8BEA18B8ED52FB240716C4D4EC7D7C0167F0F032CBB87DF611D9";
Certificate c;
deserialize_from_hexstring(str, c);
check(c, serialize_roundtrip(c));
}
TEST(Certificate, WebValidator_AuthorizationAuthority1_v2)
{
const char str[] =
"0201F5425279310C0379020A547275737465645F4141808D00000432B9C37AC51D25863A7872EF40"
"5DB43DF37FA73411B2C0539FD39DF38828F86C946CB09039C0A9694A650D9104BA62C5A7588AEF8F"
"68935F0D170373968131CD01010004E6C956FBEDCC969935BE832E4DE599CBFD687D81495C58B3C1"
"2028F92489D4AF76B64D340BE2ACE8D7E2A789FE09A5F3B84F5E65BF54A07FAF74696131E762E302"
"E0200224250B0114B12B03154E0D8303000000CC6255F38BC8844FAC2A31DE3420E65F23DBC97DC8"
"66C840516328F27850B3520FC2A812A49DD989BFB0ECE408E53B375006974D1DA4EFD6FC5465B3F8"
"946183";
Certificate c;
deserialize_from_hexstring(str, c);
check(c, serialize_roundtrip(c));
}
TEST(Certificate, WebValidator_AuthorizationAuthority2_v2)
{
const char str[] =
"0201F5425279310C0379020A547275737465645F4141808D00000401418E994657434A71E034E530"
"B1E77A8AFAC37561132C83D45C442499228CA78573F14BE034A4958108A654CAC60F15BB35907E33"
"D0E97F8D7EAF64A1F43547010100047C5C8D8B86CF8A00A53F3CD23FCCF13D078555CC8EF27DC439"
"780EB8EF376237FF668055DA476CC82956F6FEBFA051A6D927E70D826DB0338E42819F026AEBAA02"
"E0200224250B0114B12B03154E0D83030000005145571104D52DD7094C577719C7CA430D59608D5F"
"EFD10DB3E61B7C5FD3E4716224F96ED5AB4EB7F860C15347B66E23EA12E0A186A1A80B96C6E5DE05"
"416A87";
Certificate c;
deserialize_from_hexstring(str, c);
check(c, serialize_roundtrip(c));
}
TEST(Certificate, WebValidator_AuthorizationTicket1_v2)
{
const char str[] =
"02015388DEC640C6E19E010052000004B27D4D442F58E065F8D500478929BC843940F3C34D46C547"
"5803C03594E35BD7E0132FD01634E86D4F50F7F2366988E12525232D00D03E98FC21CA8E5D0AF370"
"02E0210B24030100002504010000000B0114E9DB83154CBC0203000000553C8D2B8A4E53F3D84A88"
"37BEEBE83D5C7F68484AC5EFCEEFCC7B0BC5E9531754AAF58BF90790A10F2FD11796A85E13DFFAAC"
"6073D2068465DA733994CD0C71";
Certificate c;
deserialize_from_hexstring(str, c);
check(c, serialize_roundtrip(c));
}
@@ -0,0 +1,135 @@
#include <gtest/gtest.h>
#include <vanetza/common/manual_runtime.hpp>
#include <vanetza/security/v2/certificate.hpp>
#include <vanetza/security/v2/certificate_cache.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza;
using namespace vanetza::security;
using namespace vanetza::security::v2;
class CertificateCacheTest : public ::testing::Test
{
public:
CertificateCacheTest() :
runtime(Clock::at("2018-01-03 17:15")),
cache(runtime)
{
}
Certificate build_certificate(SubjectType subject_type, uint8_t id = 0)
{
Certificate cert;
cert.subject_info.subject_type = subject_type;
cert.signer_info = HashedId8 {{ id, id, id, id, id, id, id, id }};
EcdsaSignature signature;
X_Coordinate_Only x_only;;
x_only.x.insert(x_only.x.end(), 32, 0x22);
signature.R = std::move(x_only);
signature.s.insert(signature.s.end(), 32, 0x11);
cert.signature = std::move(signature);
return cert;
}
protected:
ManualRuntime runtime;
CertificateCache cache;
};
static const HashedId8 zero_id = {{ 0, 0, 0, 0, 0, 0, 0, 0 }};
TEST_F(CertificateCacheTest, lookup)
{
const Certificate cert = build_certificate(SubjectType::Authorization_Ticket);
const HashedId8 cert_id = calculate_hash(cert);
// empty cache
EXPECT_EQ(0, cache.lookup(cert_id, SubjectType::Authorization_Ticket).size());
cache.insert(cert);
// cache only contains 'cert' and must be able to find it
EXPECT_EQ(1, cache.lookup(cert_id, SubjectType::Authorization_Ticket).size());
// cache only contains 'cert' and must not return it for other types
EXPECT_EQ(0, cache.lookup(cert_id, SubjectType::Authorization_Authority).size());
// but nothing else
HashedId8 other_id = cert_id;
other_id[3] = cert_id[3] + 1;
EXPECT_EQ(0, cache.lookup(other_id, SubjectType::Authorization_Ticket).size());
}
TEST_F(CertificateCacheTest, insert_only_some_subject_type)
{
cache.insert(build_certificate(SubjectType::Enrollment_Credential));
EXPECT_EQ(0, cache.size());
cache.insert(build_certificate(SubjectType::Authorization_Ticket));
EXPECT_EQ(1, cache.size());
cache.insert(build_certificate(SubjectType::Authorization_Authority));
EXPECT_EQ(2, cache.size());
cache.insert(build_certificate(SubjectType::Enrollment_Authority));
EXPECT_EQ(2, cache.size());
cache.insert(build_certificate(SubjectType::Root_CA));
EXPECT_EQ(2, cache.size());
cache.insert(build_certificate(SubjectType::CRL_Signer));
EXPECT_EQ(2, cache.size());
}
TEST_F(CertificateCacheTest, drop_expired)
{
const Certificate cert1 = build_certificate(SubjectType::Authorization_Ticket); // 2 seconds
const Certificate cert2 = build_certificate(SubjectType::Authorization_Authority); // 1 hour
ASSERT_NE(calculate_hash(cert1), calculate_hash(cert2));
cache.insert(cert1);
cache.insert(cert2);
ASSERT_EQ(2, cache.size());
runtime.trigger(std::chrono::seconds(3));
EXPECT_EQ(2, cache.size());
cache.lookup(zero_id, SubjectType::Authorization_Ticket); // any lookup drops expired cache entries
EXPECT_EQ(1, cache.size());
runtime.trigger(std::chrono::minutes(60));
cache.lookup(zero_id, SubjectType::Authorization_Ticket);
EXPECT_EQ(0, cache.size());
}
TEST_F(CertificateCacheTest, lookup_match_extends_lifetime)
{
const Certificate cert1 = build_certificate(SubjectType::Authorization_Ticket);
const Certificate cert2 = build_certificate(SubjectType::Authorization_Authority);
const HashedId8 id_cert2 = calculate_hash(cert2);
cache.insert(cert1);
cache.insert(cert2);
EXPECT_EQ(2, cache.size());
for (unsigned i = 0; i < 3601; ++i) {
runtime.trigger(std::chrono::seconds(1));
cache.lookup(id_cert2, SubjectType::Authorization_Authority);
}
EXPECT_EQ(1, cache.size());
EXPECT_EQ(1, cache.lookup(id_cert2, SubjectType::Authorization_Authority).size());
}
TEST_F(CertificateCacheTest, insert_extends_lifetime)
{
const Certificate cert = build_certificate(SubjectType::Authorization_Ticket);
const HashedId8 id = calculate_hash(cert);
EXPECT_NE(zero_id, id);
cache.insert(cert);
EXPECT_EQ(1, cache.size());
runtime.trigger(std::chrono::seconds(1));
cache.insert(cert);
EXPECT_EQ(1, cache.size());
cache.lookup(zero_id, SubjectType::Authorization_Ticket);
EXPECT_EQ(1, cache.size());
runtime.trigger(std::chrono::seconds(2));
cache.lookup(id, SubjectType::Authorization_Ticket);
EXPECT_EQ(1, cache.size());
}
@@ -0,0 +1,23 @@
#include <vanetza/security/v2/tests/check_basic_elements.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const Time64WithStandardDeviation& expected, const Time64WithStandardDeviation& actual)
{
EXPECT_EQ(expected.time64, actual.time64);
EXPECT_EQ(expected.log_std_dev, actual.log_std_dev);
}
void check(const IntX& expected, const IntX& actual)
{
EXPECT_EQ(expected, actual);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,46 @@
#ifndef CHECK_BASIC_ELEMENTS_HPP_XLHVYJ0S
#define CHECK_BASIC_ELEMENTS_HPP_XLHVYJ0S
#include <gtest/gtest.h>
#include <vanetza/security/v2/basic_elements.hpp>
#include <vanetza/security/v2/int_x.hpp>
#include <boost/format.hpp>
#include <type_traits>
namespace vanetza
{
namespace security
{
namespace v2
{
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
void check(const T& expected, const T& actual)
{
EXPECT_EQ(expected, actual);
}
template<typename T, size_t N>
void check(const std::array<T, N>& expected, const std::array<T, N>& actual)
{
SCOPED_TRACE("array<T, N>");
for (unsigned i = 0; i < N; ++i) {
SCOPED_TRACE(boost::format("element index #%1%") % i);
check(expected[i], actual[i]);
}
}
void check(const Time64WithStandardDeviation&, const Time64WithStandardDeviation&);
void check(const IntX&, const IntX&);
// explicit template instantiations
template void check<uint8_t, 3>(const HashedId3&, const HashedId3&);
template void check<uint8_t, 8>(const HashedId8&, const HashedId8&);
template void check<Time64>(const Time64&, const Time64&);
template void check<Time32>(const Time32&, const Time32&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_BASIC_ELEMENTS_HPP_XLHVYJ0S */
@@ -0,0 +1,29 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/tests/check_certificate.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
#include <vanetza/security/v2/tests/check_signature.hpp>
#include <vanetza/security/v2/tests/check_signer_info.hpp>
#include <vanetza/security/v2/tests/check_subject_attribute.hpp>
#include <vanetza/security/v2/tests/check_subject_info.hpp>
#include <vanetza/security/v2/tests/check_validity_restriction.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const Certificate& expected, const Certificate& actual)
{
// certificate version is static, no check required
check(expected.signer_info, actual.signer_info);
check(expected.subject_info, actual.subject_info);
check(expected.subject_attributes, actual.subject_attributes, "SubjectAttribute");
check(expected.validity_restriction, actual.validity_restriction, "ValidityRestriction");
check(expected.signature, actual.signature);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,20 @@
#ifndef CHECK_CERTIFICATE_HPP_ICIHS76C
#define CHECK_CERTIFICATE_HPP_ICIHS76C
#include <vanetza/security/v2/certificate.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const Certificate&, const Certificate&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_CERTIFICATE_HPP_ICIHS76C */
@@ -0,0 +1,69 @@
#ifndef CHECK_ECC_POINT_HPP_UQH2R8WK
#define CHECK_ECC_POINT_HPP_UQH2R8WK
#include <gtest/gtest.h>
#include <vanetza/security/v2/ecc_point.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
namespace vanetza
{
namespace security
{
/**
* \brief check two X_Coordinate_Only
* \param expected the expected value
* \param actual the actual value
*/
inline void check(const X_Coordinate_Only& expected, const X_Coordinate_Only& actual)
{
EXPECT_EQ(expected.x, actual.x);
}
/**
* \brief check two Compressed_Lsb_Y_0
* \param expected the expected value
* \param actual the actual value
*/
inline void check(const Compressed_Lsb_Y_0& expected, const Compressed_Lsb_Y_0& actual)
{
EXPECT_EQ(expected.x, actual.x);
}
/**
* \brief check two Compressed_Lsb_Y_1
* \param expected the expected value
* \param actual the actual value
*/
inline void check(const Compressed_Lsb_Y_1& expected, const Compressed_Lsb_Y_1& actual)
{
EXPECT_EQ(expected.x, actual.x);
}
/**
* \brief check two Uncompressed
* \param expected the expected value
* \param actual the actual value
*/
inline void check(const Uncompressed& expected, const Uncompressed& actual)
{
EXPECT_EQ(expected.x, actual.x);
EXPECT_EQ(expected.y, actual.y);
}
/**
* \brief check two EccPoints
* \param expected the expected value
* \param actual the actual value
*/
inline void check(const EccPoint& expected, const EccPoint& actual)
{
ASSERT_EQ(v2::get_type(expected), v2::get_type(actual));
boost::apply_visitor(check_visitor<EccPoint>(), expected, actual);
}
} // namespace security
} // namespace vanetza
#endif /* CHECK_ECC_POINT_HPP_UQH2R8WK */
@@ -0,0 +1,21 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/tests/check_encryption_parameter.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const EncryptionParameter& expected, const EncryptionParameter& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
EXPECT_EQ(get_size(expected), get_size(actual));
boost::apply_visitor(check_visitor<EncryptionParameter>(), expected, actual);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,25 @@
#ifndef CHECK_ENCRYPTION_PARAMETER_HPP_5UDSKSNK
#define CHECK_ENCRYPTION_PARAMETER_HPP_5UDSKSNK
#include <vanetza/security/v2/encryption_parameter.hpp>
#include <vanetza/security/v2/tests/check_basic_elements.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
/**
* \brief check if the two EncryptionParameter are equal
* \param expected the expected value
* \param actual the actual value
*/
void check(const EncryptionParameter& expected, const EncryptionParameter& actual);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_ENCRYPTION_PARAMETER_HPP_5UDSKSNK */
@@ -0,0 +1,21 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/tests/check_basic_elements.hpp>
#include <vanetza/security/v2/tests/check_header_field.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const HeaderField& expected, const HeaderField& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
boost::apply_visitor(check_visitor<HeaderField>(), expected, actual);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,26 @@
#ifndef CHECK_HEADER_FIELD_HPP_DNSZT9E2
#define CHECK_HEADER_FIELD_HPP_DNSZT9E2
#include <vanetza/security/v2/header_field.hpp>
#include <vanetza/security/v2/tests/check_basic_elements.hpp>
#include <vanetza/security/v2/tests/check_encryption_parameter.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
#include <vanetza/security/v2/tests/check_recipient_info.hpp>
#include <vanetza/security/v2/tests/check_region.hpp>
#include <vanetza/security/v2/tests/check_signer_info.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const HeaderField&, const HeaderField&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_HEADER_FIELD_HPP_DNSZT9E2 */
@@ -0,0 +1,35 @@
#ifndef CHECK_LIST_HPP_1ONCXSED
#define CHECK_LIST_HPP_1ONCXSED
#include <gtest/gtest.h>
#include <boost/format.hpp>
#include <list>
#include <typeinfo>
namespace vanetza
{
namespace security
{
namespace v2
{
template<typename T>
void check(std::list<T> expected, std::list<T> actual, const char* type = typeid(T).name())
{
SCOPED_TRACE(boost::format("list<%1%>") % type);
ASSERT_EQ(expected.size(), actual.size());
std::size_t i = 0;
while (!expected.empty() && !actual.empty()) {
SCOPED_TRACE(boost::format("%1% #%2%") % type % i);
check(expected.front(), actual.front());
expected.pop_front();
actual.pop_front();
++i;
}
}
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_LIST_HPP_1ONCXSED */
@@ -0,0 +1,34 @@
#ifndef CHECK_PAYLOAD_HPP_YNRGOKGC
#define CHECK_PAYLOAD_HPP_YNRGOKGC
#include <gtest/gtest.h>
#include <vanetza/common/byte_buffer.hpp>
#include <vanetza/common/serialization_buffer.hpp>
#include <vanetza/security/v2/payload.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
inline void check(const PacketVariant& expected, const PacketVariant& actual)
{
ByteBuffer expected_buf, actual_buf;
serialize_into_buffer(expected, expected_buf);
serialize_into_buffer(actual, actual_buf);
EXPECT_EQ(expected_buf, actual_buf);
}
inline void check(const Payload& expected, const Payload& actual)
{
EXPECT_EQ(expected.type, actual.type);
check(expected.data, actual.data);
}
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_PAYLOAD_HPP_YNRGOKGC */
@@ -0,0 +1,45 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/tests/check_ecc_point.hpp>
#include <vanetza/security/v2/tests/check_public_key.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const ecdsa_nistp256_with_sha256& expected, const ecdsa_nistp256_with_sha256& actual)
{
check(expected.public_key, actual.public_key);
}
void check(const ecies_nistp256& expected, const ecies_nistp256& actual)
{
EXPECT_EQ(expected.supported_symm_alg, actual.supported_symm_alg);
check(expected.public_key, actual.public_key);
}
void check(const PublicKey& expected, const PublicKey& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
boost::apply_visitor(check_visitor<PublicKey>(), expected, actual);
}
PublicKey create_random_public_key(int seed)
{
const std::size_t size = field_size(PublicKeyAlgorithm::ECIES_NISTP256);
EccPoint point = Uncompressed { random_byte_sequence(size, seed),
random_byte_sequence(size, seed + 1) };
ecies_nistp256 ecies;
ecies.public_key = point;
ecies.supported_symm_alg = SymmetricAlgorithm::AES128_CCM;
return ecies;
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,24 @@
#ifndef CHECK_PUBLIC_KEY_HPP_3HUSMPTE
#define CHECK_PUBLIC_KEY_HPP_3HUSMPTE
#include <vanetza/security/v2/public_key.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const ecdsa_nistp256_with_sha256&, const ecdsa_nistp256_with_sha256&);
void check(const ecies_nistp256&, const ecies_nistp256&);
void check(const PublicKey&, const PublicKey&);
PublicKey create_random_public_key(int seed = 0);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_PUBLIC_KEY_HPP_3HUSMPTE */
@@ -0,0 +1,39 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/tests/check_ecc_point.hpp>
#include <vanetza/security/v2/tests/check_recipient_info.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const RecipientInfo& expected, const RecipientInfo& actual)
{
EXPECT_EQ(expected.cert_id, actual.cert_id);
check(expected.enc_key, actual.enc_key);
}
void check(const EciesEncryptedKey& expected, const EciesEncryptedKey& actual)
{
check(expected.v, actual.v);
EXPECT_EQ(expected.c, actual.c);
EXPECT_EQ(expected.t, actual.t);
}
void check(const OpaqueKey& expected, const OpaqueKey& actual)
{
EXPECT_EQ(expected.data, actual.data);
}
void check(const Key& expected, const Key& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
boost::apply_visitor(check_visitor<Key>(), expected, actual);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,22 @@
#ifndef CHECK_RECIPIENT_INFO_HPP_NMX7BFYV
#define CHECK_RECIPIENT_INFO_HPP_NMX7BFYV
#include <vanetza/security/v2/recipient_info.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const EciesEncryptedKey&, const EciesEncryptedKey&);
void check(const OpaqueKey&, const OpaqueKey&);
void check(const Key&, const Key&);
void check(const RecipientInfo&, const RecipientInfo&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_RECIPIENT_INFO_HPP_NMX7BFYV */
@@ -0,0 +1,87 @@
#include <gtest/gtest.h>
#include <vanetza/common/annotation.hpp>
#include <vanetza/security/v2/tests/check_region.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
#include <boost/format.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const ThreeDLocation& expected, const ThreeDLocation& actual)
{
EXPECT_EQ(expected.latitude, actual.latitude);
EXPECT_EQ(expected.longitude, actual.longitude);
EXPECT_EQ(expected.elevation, actual.elevation);
}
void check(const TwoDLocation& expected, const TwoDLocation& actual)
{
EXPECT_EQ(expected.longitude, actual.longitude);
EXPECT_EQ(expected.latitude, actual.latitude);
}
void check(const NoneRegion& expected, const NoneRegion& actual)
{
mark_unused(expected);
mark_unused(actual);
SCOPED_TRACE("None");
}
void check(const CircularRegion& expected, const CircularRegion& actual)
{
SCOPED_TRACE("CiruclarRegion");
check(expected.center, actual.center);
EXPECT_EQ(expected.radius, actual.radius);
}
void check(const RectangularRegion& expected, const RectangularRegion& actual)
{
SCOPED_TRACE("RectangularRegion");
check(expected.northwest, actual.northwest);
check(expected.southeast, actual.southeast);
}
void check(std::list<RectangularRegion> expected, std::list<RectangularRegion> actual)
{
SCOPED_TRACE("list<RectangularRegion>");
ASSERT_EQ(expected.size(), actual.size());
for (std::size_t i = 0, j = expected.size(); i < j; ++i) {
SCOPED_TRACE(boost::format("Rectangle #%1%") % i);
check(expected.front(), actual.front());
expected.pop_front();
actual.pop_front();
}
}
void check(PolygonalRegion expected, PolygonalRegion actual)
{
SCOPED_TRACE("PolygonalRegion");
ASSERT_EQ(expected.size(), actual.size());
for (std::size_t i = 0, j = expected.size(); i < j; ++i) {
SCOPED_TRACE(boost::format("Coordinate #%1%") % i);
check(expected.front(), actual.front());
expected.pop_front();
actual.pop_front();
}
}
void check(const IdentifiedRegion& expected, const IdentifiedRegion& actual)
{
EXPECT_EQ(expected.region_dictionary, actual.region_dictionary);
EXPECT_EQ(expected.region_identifier, actual.region_identifier);
EXPECT_EQ(expected.local_region, actual.local_region);
}
void check(const GeographicRegion& expected, const GeographicRegion& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
boost::apply_visitor(check_visitor<GeographicRegion>(), expected, actual);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,65 @@
#ifndef CHECK_REGION_HPP_UFSV2RZ5
#define CHECK_REGION_HPP_UFSV2RZ5
#include <vanetza/security/v2/region.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
/** \brief check two TwoDLocations
* \param expected the expected value
* \param actual the actual value
*/
void check(const TwoDLocation& expected, const TwoDLocation& actual);
/** \brief check two ThreeDLocations
* \param expected the expected value
* \param actual the actual value
*/
void check(const ThreeDLocation&, const ThreeDLocation&);
/** \brief check two CircularRegions
* \param expected the expected value
* \param actual the actual value
*/
void check(const CircularRegion& expected, const CircularRegion& actual);
/** \brief check two RectangularRegions
* \param expected the expected value
* \param actual the actual value
*/
void check(const RectangularRegion& expected, const RectangularRegion& actual);
/** \brief check two std::list<RectangularRegion>
* \param expected the expected list
* \param actual the actual value
*/
void check(std::list<RectangularRegion> expected, std::list<RectangularRegion> actual);
/** \brief check two PolygonalRegions
* \param expected the expected value
* \param actual the actual value
*/
void check(PolygonalRegion expected, PolygonalRegion actual);
/** \brief check two IdentifiedRegions
* \param expected the expected value
* \param actual the actual value
*/
void check(const IdentifiedRegion& expected, const IdentifiedRegion& actual);
/** \brief check two GeographicRegion
* \param expected the expected value
* \param actual the actual value
*/
void check(const GeographicRegion& expected, const GeographicRegion& actual);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_REGION_HPP_UFSV2RZ5 */
@@ -0,0 +1,25 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/tests/check_header_field.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
#include <vanetza/security/v2/tests/check_payload.hpp>
#include <vanetza/security/v2/tests/check_secured_message.hpp>
#include <vanetza/security/v2/tests/check_trailer_field.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const SecuredMessage& expected, const SecuredMessage& actual)
{
SCOPED_TRACE("v2::SecuredMessage");
check(expected.header_fields, actual.header_fields);
check(expected.trailer_fields, actual.trailer_fields);
check(expected.payload, actual.payload);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,19 @@
#ifndef CHECK_SECURED_MESSAGE_HPP_1YPFNXQA
#define CHECK_SECURED_MESSAGE_HPP_1YPFNXQA
#include <vanetza/security/v2/secured_message.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const SecuredMessage&, const SecuredMessage&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_SECURED_MESSAGE_HPP_1YPFNXQA */
@@ -0,0 +1,45 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/signature.hpp>
#include <vanetza/security/v2/tests/check_ecc_point.hpp>
#include <vanetza/security/v2/tests/check_signature.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
namespace vanetza
{
namespace security
{
void check(const EcdsaSignature& expected, const EcdsaSignature& actual)
{
check(expected.R, actual.R);
EXPECT_EQ(expected.s, actual.s);
}
void check(const EcdsaSignatureFuture& expected, const EcdsaSignatureFuture& actual)
{
check(expected.get(), actual.get());
}
EcdsaSignature create_random_ecdsa_signature(int seed)
{
const std::size_t field = v2::field_size(v2::PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256);
EcdsaSignature signature;
signature.s = random_byte_sequence(field, seed);
signature.R = X_Coordinate_Only { random_byte_sequence(field, ~seed) };
return signature;
}
namespace v2
{
void check(const Signature& expected, const Signature& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
// TODO boost::apply_visitor(check_visitor<Signature>(), expected, actual);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,30 @@
#ifndef CHECK_SIGNATURE_HPP_7RESWTUO
#define CHECK_SIGNATURE_HPP_7RESWTUO
#include <vanetza/security/v2/signature.hpp>
namespace vanetza
{
namespace security
{
void check(const EcdsaSignature&, const EcdsaSignature&);
void check(const EcdsaSignatureFuture&, const EcdsaSignatureFuture&);
/**
* \brief create a random EcdsaSignature
* \param seed the optional seed for the RNG
* \return created signature
*/
EcdsaSignature create_random_ecdsa_signature(int seed = 0);
namespace v2
{
void check(const Signature&, const Signature&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_SIGNATURE_HPP_7RESWTUO */
@@ -0,0 +1,38 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/tests/check_basic_elements.hpp>
#include <vanetza/security/v2/tests/check_certificate.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
#include <vanetza/security/v2/tests/check_signer_info.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const std::nullptr_t&, const std::nullptr_t&)
{
}
void check(const CertificateDigestWithOtherAlgorithm& expected, const CertificateDigestWithOtherAlgorithm& actual)
{
EXPECT_EQ(expected.algorithm, actual.algorithm);
EXPECT_EQ(expected.digest, actual.digest);
}
void check(const boost::recursive_wrapper<Certificate>& expected, const boost::recursive_wrapper<Certificate>& actual)
{
check(expected.get(), actual.get());
}
void check(const SignerInfo& expected, const SignerInfo& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
boost::apply_visitor(check_visitor<SignerInfo>(), expected, actual);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,22 @@
#ifndef CHECK_SIGNER_INFO_HPP_S2AYJSYC
#define CHECK_SIGNER_INFO_HPP_S2AYJSYC
#include <vanetza/security/v2/signer_info.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const std::nullptr_t&, const std::nullptr_t&);
void check(const CertificateDigestWithOtherAlgorithm&, const CertificateDigestWithOtherAlgorithm&);
void check(const boost::recursive_wrapper<Certificate>&, const boost::recursive_wrapper<Certificate>&);
void check(const SignerInfo&, const SignerInfo&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_SIGNER_INFO_HPP_S2AYJSYC */
@@ -0,0 +1,76 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
#include <vanetza/security/v2/tests/check_public_key.hpp>
#include <vanetza/security/v2/tests/check_subject_attribute.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const VerificationKey& expected, const VerificationKey& actual)
{
SCOPED_TRACE("VerificationKey");
check(expected.key, actual.key);
}
void check(const EncryptionKey& expected, const EncryptionKey& actual)
{
SCOPED_TRACE("EncryptionKey");
check(expected.key, actual.key);
}
void check(const SubjectAssurance& expected, const SubjectAssurance& actual)
{
EXPECT_EQ(expected.raw, actual.raw);
}
void check(const ItsAidSsp& expected, const ItsAidSsp& actual)
{
SCOPED_TRACE("ItsAidSsp");
EXPECT_EQ(expected.its_aid, actual.its_aid);
EXPECT_EQ(expected.service_specific_permissions, actual.service_specific_permissions);
}
void check(const SubjectAttribute& expected, const SubjectAttribute& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
boost::apply_visitor(check_visitor<SubjectAttribute>(), expected, actual);
}
VerificationKey create_random_verification_key(int seed)
{
VerificationKey key;
key.key = create_random_public_key(seed);
return key;
}
EncryptionKey create_random_encryption_key(int seed)
{
EncryptionKey key;
key.key = create_random_public_key(seed);
return key;
}
IntX create_random_its_aid(int seed)
{
IntX result;
result.set((seed ^ (seed >> 23)) & 0xffffff);
return result;
}
ItsAidSsp create_random_its_aid_ssp(int seed)
{
ItsAidSsp result;
result.its_aid.set(~seed & 0xffffff);
result.service_specific_permissions = random_byte_sequence(10, seed);
return result;
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,32 @@
#ifndef CHECK_SUBJECT_ATTRIBUTE_HPP_40Z9HDV2
#define CHECK_SUBJECT_ATTRIBUTE_HPP_40Z9HDV2
#include <vanetza/security/v2/subject_attribute.hpp>
#include <vanetza/security/v2/tests/check_basic_elements.hpp>
#include <vanetza/security/v2/tests/check_ecc_point.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const VerificationKey&, const VerificationKey&);
void check(const EncryptionKey&, const EncryptionKey&);
void check(const SubjectAssurance&, const SubjectAssurance&);
void check(const ItsAidSsp&, const ItsAidSsp&);
void check(const SubjectAttribute&, const SubjectAttribute&);
VerificationKey create_random_verification_key(int seed = 0);
EncryptionKey create_random_encryption_key(int seed = 0);
IntX create_random_its_aid(int seed = 0);
ItsAidSsp create_random_its_aid_ssp(int seed = 0);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_SUBJECT_ATTRIBUTE_HPP_40Z9HDV2 */
@@ -0,0 +1,25 @@
#ifndef CHECK_SUBJECT_INFO_HPP_LCHGB2G3
#define CHECK_SUBJECT_INFO_HPP_LCHGB2G3
#include <gtest/gtest.h>
#include <vanetza/security/v2/subject_info.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
inline void check(const SubjectInfo& expected, const SubjectInfo& actual)
{
EXPECT_EQ(expected.subject_type, actual.subject_type);
EXPECT_EQ(expected.subject_name, actual.subject_name);
}
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_SUBJECT_INFO_HPP_LCHGB2G3 */
@@ -0,0 +1,24 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/tests/check_signature.hpp>
#include <vanetza/security/v2/tests/check_trailer_field.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
#include <boost/mpl/size.hpp>
#include <boost/variant/get.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const TrailerField& expected, const TrailerField& actual)
{
static_assert(boost::mpl::size<typename TrailerField::types>::value == 1,
"Simple check works only for TrailerField variant with one possible type");
check(boost::get<Signature>(expected), boost::get<Signature>(actual));
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,19 @@
#ifndef CHECK_TRAILER_FIELD_HPP_5LY4T0VT
#define CHECK_TRAILER_FIELD_HPP_5LY4T0VT
#include <vanetza/security/v2/trailer_field.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(const TrailerField&, const TrailerField&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_TRAILER_FIELD_HPP_5LY4T0VT */
@@ -0,0 +1,42 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/tests/check_region.hpp>
#include <vanetza/security/v2/tests/check_validity_restriction.hpp>
#include <vanetza/security/v2/tests/check_visitor.hpp>
#include <boost/format.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(EndValidity expected, EndValidity actual)
{
SCOPED_TRACE("EndValidity");
EXPECT_EQ(expected, actual);
}
void check(const StartAndEndValidity& expected, const StartAndEndValidity& actual)
{
SCOPED_TRACE("StartAndEndValidity");
EXPECT_EQ(expected.start_validity, actual.start_validity);
EXPECT_EQ(expected.end_validity, actual.end_validity);
}
void check(const StartAndDurationValidity& expected, const StartAndDurationValidity& actual)
{
SCOPED_TRACE("StartAndDurationValidity");
EXPECT_EQ(expected.start_validity, actual.start_validity);
EXPECT_EQ(expected.duration.raw(), actual.duration.raw());
}
void check(const ValidityRestriction& expected, const ValidityRestriction& actual)
{
ASSERT_EQ(get_type(expected), get_type(actual));
boost::apply_visitor(check_visitor<ValidityRestriction>(), expected, actual);
}
} // namespace v2
} // namespace security
} // namespace vanetza
@@ -0,0 +1,23 @@
#ifndef CHECK_VALIDITY_RESTRICTION_HPP_W8OY9526
#define CHECK_VALIDITY_RESTRICTION_HPP_W8OY9526
#include <vanetza/security/v2/validity_restriction.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
namespace vanetza
{
namespace security
{
namespace v2
{
void check(EndValidity, EndValidity);
void check(const StartAndEndValidity&, const StartAndEndValidity&);
void check(const StartAndDurationValidity&, const StartAndDurationValidity&);
void check(const ValidityRestriction&, const ValidityRestriction&);
} // namespace v2
} // namespace security
} // namespace vanetza
#endif /* CHECK_VALIDITY_RESTRICTION_HPP_W8OY9526 */
@@ -0,0 +1,33 @@
#ifndef CHECK_VISITOR_HPP_YJ7UPXCB
#define CHECK_VISITOR_HPP_YJ7UPXCB
#include <gtest/gtest.h>
#include <boost/variant/static_visitor.hpp>
#include <typeinfo>
namespace vanetza
{
namespace security
{
template<class VARIANT>
struct check_visitor : public boost::static_visitor<>
{
template<typename R, typename S>
void operator()(const R&, const S&) const
{
FAIL() << typeid(R).name() << " differs from " << typeid(S).name();
}
template<typename R>
void operator()(const R& lhs, const R& rhs) const
{
using namespace vanetza::security::v2;
check(lhs, rhs);
}
};
} // namespace security
} // namespace vanetza
#endif /* CHECK_VISITOR_HPP_YJ7UPXCB */
@@ -0,0 +1,244 @@
#include <vanetza/common/manual_runtime.hpp>
#include <vanetza/security/v2/certificate_cache.hpp>
#include <vanetza/security/v2/default_certificate_validator.hpp>
#include <vanetza/security/v2/naive_certificate_provider.hpp>
#include <vanetza/security/v2/trust_store.hpp>
#include <vanetza/units/angle.hpp>
#include <boost/variant/get.hpp>
#include <gtest/gtest.h>
using namespace vanetza;
using namespace vanetza::security;
using namespace vanetza::security::v2;
class DefaultCertificateValidatorTest : public ::testing::Test
{
public:
DefaultCertificateValidatorTest() :
runtime(Clock::at("2016-08-01 00:00")),
backend(create_backend("default")),
cert_provider(runtime),
cert_cache(runtime),
cert_validator(*backend, cert_cache, trust_store)
{
trust_store.insert(cert_provider.root_certificate());
cert_cache.insert(cert_provider.aa_certificate());
}
protected:
ManualRuntime runtime;
std::unique_ptr<Backend> backend;
NaiveCertificateProvider cert_provider;
std::vector<Certificate> roots;
TrustStore trust_store;
CertificateCache cert_cache;
DefaultCertificateValidator cert_validator;
};
TEST_F(DefaultCertificateValidatorTest, invalid_signer_info)
{
Certificate cert = cert_provider.generate_authorization_ticket();
cert.signer_info = cert_provider.own_chain().front();
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Invalid_Signer, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, missing_subject_assurance)
{
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_attribute(SubjectAttributeType::Assurance_Level);
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Missing_Subject_Assurance, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, inconsistent_subject_assurance)
{
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_attribute(SubjectAttributeType::Assurance_Level);
cert.subject_attributes.push_back(SubjectAssurance(0xE0)); // higher level
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Inconsistent_With_Signer, validity.reason());
cert.remove_attribute(SubjectAttributeType::Assurance_Level);
cert.subject_attributes.push_back(SubjectAssurance(0x03)); // same level, higher confidence
cert_provider.sign_authorization_ticket(cert);
validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Inconsistent_With_Signer, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, validity_time_no_constraint)
{
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_restriction(ValidityRestrictionType::Time_Start_And_End);
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Broken_Time_Period, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, validity_time_start_and_end)
{
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_restriction(ValidityRestrictionType::Time_Start_And_End);
StartAndEndValidity restriction;
restriction.start_validity = convert_time32(runtime.now() - std::chrono::hours(1));
restriction.end_validity = convert_time32(runtime.now() + std::chrono::hours(23));
cert.validity_restriction.push_back(restriction);
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_TRUE(validity);
}
TEST_F(DefaultCertificateValidatorTest, validity_time_start_and_duration)
{
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_restriction(ValidityRestrictionType::Time_Start_And_End);
StartAndDurationValidity restriction;
restriction.start_validity = convert_time32(runtime.now() - std::chrono::hours(1));
restriction.duration = Duration(23, Duration::Units::Hours);
cert.validity_restriction.push_back(restriction);
cert_provider.sign_authorization_ticket(cert);
// all certificates must use time_start_and_end as restriction
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
ASSERT_EQ(CertificateInvalidReason::Broken_Time_Period, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, validity_time_end)
{
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_restriction(ValidityRestrictionType::Time_Start_And_End);
EndValidity restriction = convert_time32(runtime.now() + std::chrono::hours(23));
cert.validity_restriction.push_back(restriction);
cert_provider.sign_authorization_ticket(cert);
// all certificates must use time_start_and_end as restriction
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
ASSERT_EQ(CertificateInvalidReason::Broken_Time_Period, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, validity_time_two_constraints)
{
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_restriction(ValidityRestrictionType::Time_Start_And_End);
// add first constraint
StartAndEndValidity start_and_end_validity;
start_and_end_validity.start_validity = convert_time32(runtime.now() - std::chrono::hours(1));
start_and_end_validity.end_validity = convert_time32(runtime.now() + std::chrono::hours(23));
cert.validity_restriction.push_back(start_and_end_validity);
// add second constraint
StartAndDurationValidity start_and_duration_validity;
start_and_duration_validity.start_validity = convert_time32(runtime.now() - std::chrono::hours(1));
start_and_duration_validity.duration = Duration(23, Duration::Units::Hours);
cert.validity_restriction.push_back(start_and_duration_validity);
// re-sign certificate
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Broken_Time_Period, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, validity_time_consistency_with_parent)
{
// The generated authorization ticket's start time is prior to the AA certificate's start time
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_restriction(ValidityRestrictionType::Time_Start_And_End);
StartAndEndValidity restriction;
restriction.start_validity = convert_time32(runtime.now() - std::chrono::hours(3));
restriction.end_validity = convert_time32(runtime.now() + std::chrono::hours(23));
cert.validity_restriction.push_back(restriction);
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Inconsistent_With_Signer, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, validity_time_consistency_start_and_end)
{
// The generated authorization ticket's start time is prior to the AA certificate's start time
Certificate cert = cert_provider.generate_authorization_ticket();
cert.remove_restriction(ValidityRestrictionType::Time_Start_And_End);
StartAndEndValidity restriction;
restriction.start_validity = convert_time32(runtime.now() + std::chrono::hours(3));
restriction.end_validity = convert_time32(runtime.now() - std::chrono::hours(23));
cert.validity_restriction.push_back(restriction);
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Broken_Time_Period, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, reject_additional_permissions)
{
Certificate cert = cert_provider.generate_authorization_ticket();
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_TRUE(validity);
cert.add_permission(16513 /* deprecated, so won't be used */, ByteBuffer({}));
cert_provider.sign_authorization_ticket(cert);
validity = cert_validator.check_certificate(cert);
ASSERT_FALSE(validity);
EXPECT_EQ(CertificateInvalidReason::Inconsistent_With_Signer, validity.reason());
}
TEST_F(DefaultCertificateValidatorTest, accept_permission_subset_permutation)
{
// We test both orders here, so we're not dependent on changes to the certificate provider order.
Certificate cert = cert_provider.generate_authorization_ticket();
// Order 1
cert.remove_attribute(SubjectAttributeType::ITS_AID_SSP_List);
cert.add_permission(aid::GN_MGMT, ByteBuffer({}));
cert.add_permission(aid::CA, ByteBuffer({ 1, 0, 0 }));
cert_provider.sign_authorization_ticket(cert);
CertificateValidity validity = cert_validator.check_certificate(cert);
ASSERT_TRUE(validity);
// Order 2
cert.remove_attribute(SubjectAttributeType::ITS_AID_SSP_List);
cert.add_permission(aid::CA, ByteBuffer({ 1, 0, 0 }));
cert.add_permission(aid::GN_MGMT, ByteBuffer({}));
cert_provider.sign_authorization_ticket(cert);
validity = cert_validator.check_certificate(cert);
ASSERT_TRUE(validity);
// Definite subset
cert.remove_attribute(SubjectAttributeType::ITS_AID_SSP_List);
cert.add_permission(aid::CA, ByteBuffer({ 1, 0, 0 }));
cert_provider.sign_authorization_ticket(cert);
validity = cert_validator.check_certificate(cert);
ASSERT_TRUE(validity);
}
@@ -0,0 +1,49 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/ecc_point.hpp>
#include <vanetza/security/v2/public_key.hpp>
#include <vanetza/security/v2/tests/check_ecc_point.hpp>
using vanetza::ByteBuffer;
using namespace vanetza::security;
using namespace vanetza::security::v2;
using namespace vanetza;
using namespace std;
static const std::size_t length = field_size(PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256);
EccPoint serialize_roundtrip(const EccPoint& point)
{
EccPoint outPoint;
std::stringstream stream;
OutputArchive oa(stream);
serialize(oa, point, PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256);
InputArchive ia(stream);
deserialize(ia, outPoint, PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256);
return outPoint;
}
TEST(EccPoint, uncompressed)
{
EccPoint point = Uncompressed { random_byte_sequence(length, 1), random_byte_sequence(length, 2) };
EccPoint outPoint = serialize_roundtrip(point);
check(point, outPoint);
EXPECT_EQ(EccPointType::Uncompressed, get_type(outPoint));
}
TEST(EccPoint, Compressed_Lsb_Y_0)
{
EccPoint point = Compressed_Lsb_Y_0 { random_byte_sequence(length, 3) };
EccPoint outPoint = serialize_roundtrip(point);
check(point, outPoint);
EXPECT_EQ(EccPointType::Compressed_Lsb_Y_0, get_type(outPoint));
}
TEST(EccPoint, X_Coordinate_Only)
{
EccPoint point = X_Coordinate_Only { random_byte_sequence(length, 4) };
EccPoint outPoint = serialize_roundtrip(point);
check(point, outPoint);
EXPECT_EQ(EccPointType::X_Coordinate_Only, get_type(outPoint));
}
@@ -0,0 +1,17 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/encryption_parameter.hpp>
#include <vanetza/security/v2/tests/check_encryption_parameter.hpp>
#include <vanetza/security/tests/serialization.hpp>
#include <algorithm>
using namespace vanetza::security::v2;
TEST(EncryptionParameter, Nonce)
{
Nonce nonce;
auto random = vanetza::random_byte_sequence(nonce.size());
std::copy_n(random.begin(), nonce.size(), nonce.begin());
EncryptionParameter param = nonce;
check(param, serialize_roundtrip(param));
}
@@ -0,0 +1,94 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/header_field.hpp>
#include <vanetza/security/v2/tests/check_header_field.hpp>
#include <vanetza/security/v2/tests/check_signature.hpp>
#include <vanetza/security/tests/serialization.hpp>
#include <algorithm>
using namespace vanetza;
using namespace vanetza::security;
using namespace vanetza::security::v2;
TEST(HeaderField, Serialize)
{
std::list<HeaderField> list;
std::list<Certificate> certificates;
for (unsigned i = 0; i < 2; ++i) {
auto rand_gen = random_byte_generator(i + 8 * 3);
Certificate cert;
HashedId8 cert_digest;
std::generate(cert_digest.begin(), cert_digest.end(), rand_gen);
cert.signer_info = cert_digest;
cert.subject_info = { SubjectType::Enrollment_Credential, random_byte_sequence(28, i) };
cert.signature = create_random_ecdsa_signature(i + 8);
certificates.push_back(cert);
}
list.push_back(SignerInfo { certificates });
list.push_back(Time64 { 983 });
Time64WithStandardDeviation time_dev;
time_dev.log_std_dev = 1;
time_dev.time64 = 2000;
list.push_back(time_dev);
list.push_back(Time32 { 434 });
ThreeDLocation loc;
loc.latitude.from_value(838);
loc.longitude.from_value(37);
loc.elevation = {{ 83, 17 }};
list.push_back(loc);
std::list<HashedId3> hashed;
for (unsigned i = 0; i < 3; ++i) {
HashedId3 id;
std::generate(id.begin(), id.end(), random_byte_generator(i + 8943));
hashed.push_back(id);
}
list.push_back(hashed);
list.push_back(IntX { 43 });
Nonce nonce;
std::generate(nonce.begin(), nonce.end(), random_byte_generator(22));
list.push_back(EncryptionParameter { nonce });
std::list<RecipientInfo> recipients;
for (unsigned i = 0; i < 2; ++i) {
const std::size_t length = field_size(PublicKeyAlgorithm::ECIES_NISTP256);
auto rand_gen = random_byte_generator(i + 93);
RecipientInfo info;
EciesEncryptedKey key;
std::generate(info.cert_id.begin(), info.cert_id.end(), rand_gen);
key.c = random_byte_sequence(field_size(SymmetricAlgorithm::AES128_CCM), rand_gen());
std::generate(key.t.begin(), key.t.end(), rand_gen);
key.v = Uncompressed {
random_byte_sequence(length, rand_gen()),
random_byte_sequence(length, rand_gen()) };
info.enc_key = key;
recipients.push_back(info);
}
list.push_back(recipients);
check(list, serialize_roundtrip(list));
}
TEST(HeaderField, WebValidator_SecuredMessage3_adapted)
{
const char str[] =
"810180020201A8ED6DF65B0E6D6A010080940000040209B0434163CCBAFDD34A45333E418FB96C"
"05BBE0E7E1D755D40D0B4BBE8DA508EC2F2723B7ADF0F27C39F3AECFF0783C196F9961F8821E6294"
"375D9294CD6A01000452113CE698DB081491675DF8FFE81C23EA5D0071B2D2BF0E0DA4ADA0CDA582"
"59CA5D999200B6565E194EDAB8BD3DCA863F2DDF39C13E7A0375ECE2566C5EB8C60200210AC04080"
"0101C0408101010F01099EB20109B1270003040100960000008DA1F3F9F35E04C3DE77D7438988A8"
"D57EBE44DAA021A4269E297C177C9CFE458E128EC290785D6631961625020943B6D87DAA54919A98"
"F7865709929A7C6E480000009373CF482D400502";
std::list<HeaderField> list;
const size_t deserialize_length = deserialize_from_hexstring(str, list);
EXPECT_EQ(257, deserialize_length);
EXPECT_EQ(257, get_size(list));
EXPECT_EQ(3, list.size());
}
@@ -0,0 +1,107 @@
#include <vanetza/security/v2/int_x.hpp>
#include <vanetza/security/v2/length_coding.hpp>
#include <vanetza/security/tests/serialization.hpp>
#include <gtest/gtest.h>
using vanetza::ByteBuffer;
using vanetza::security::v2::IntX;
TEST(IntX, set_and_get)
{
IntX a;
EXPECT_EQ(0, a.get());
a.set(static_cast<int8_t>(89));
EXPECT_EQ(89, a.get());
a.set(static_cast<uint32_t>(0x12345678));
EXPECT_EQ(0x12345678, a.get());
}
TEST(IntX, get_size)
{
IntX a;
EXPECT_EQ(1, get_size(a));
a.set(static_cast<int8_t>(89));
EXPECT_EQ(1, get_size(a));
a.set(127);
EXPECT_EQ(1, get_size(a));
a.set(128);
EXPECT_EQ(2, get_size(a));
a.set(0x23);
EXPECT_EQ(1, get_size(a));
a.set(static_cast<uint32_t>(0x00130033));
EXPECT_EQ(3, get_size(a));
a.set(static_cast<uint32_t>(0x00230033));
EXPECT_EQ(4, get_size(a));
a.set(static_cast<uint32_t>(0x33003300));
EXPECT_EQ(5, get_size(a));
}
TEST(IntX, encode)
{
IntX a;
EXPECT_EQ((ByteBuffer { 0x00 }), a.encode());
a.set(127);
EXPECT_EQ((ByteBuffer { 127 }), a.encode());
a.set(128);
EXPECT_EQ((ByteBuffer { 0x80, 128 }), a.encode());
a.set(0x00120034);
EXPECT_EQ((ByteBuffer { 0xd2, 0x00, 0x34 }), a.encode());
a.set(0x00320034);
EXPECT_EQ((ByteBuffer { 0xe0, 0x32, 0x00, 0x34 }), a.encode());
}
TEST(IntX, decode)
{
ByteBuffer buf { 0xe0, 0x32, 0x00, 0x34 };
auto decoded = IntX::decode(buf);
ASSERT_TRUE(!!decoded);
EXPECT_EQ(0x320034, decoded->get());
}
TEST(IntX, decode_one_null_byte)
{
ByteBuffer buf { 0x00 };
auto decoded = IntX::decode(buf);
ASSERT_TRUE(!!decoded);
EXPECT_EQ(0, decoded->get());
}
TEST(IntX, decode_empty)
{
ByteBuffer buf;
auto decoded = IntX::decode(buf);
EXPECT_FALSE(!!decoded);
}
TEST(IntX, decode_broken)
{
ByteBuffer buf { 0xff, 0xff };
auto decoded = IntX::decode(buf);
EXPECT_FALSE(!!decoded);
}
TEST(IntX, serialization)
{
IntX x;
x.set(0);
EXPECT_EQ(x, serialize_roundtrip(x));
x.set(255);
EXPECT_EQ(x, serialize_roundtrip(x));
x.set(0x123456);
EXPECT_EQ(x, serialize_roundtrip(x));
}
@@ -0,0 +1,128 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_buffer_sink.hpp>
#include <vanetza/common/byte_buffer_source.hpp>
#include <vanetza/security/v2/length_coding.hpp>
#include <vanetza/security/v2/serialization.hpp>
#include <boost/iostreams/stream_buffer.hpp>
using vanetza::ByteBuffer;
using vanetza::InputArchive;
using vanetza::OutputArchive;
using namespace vanetza::security::v2;
TEST(LengthEncoding, count_leading_ones)
{
EXPECT_EQ(0, count_leading_ones(0x00));
EXPECT_EQ(1, count_leading_ones(0x80));
EXPECT_EQ(1, count_leading_ones(0x81));
EXPECT_EQ(1, count_leading_ones(0xa0));
EXPECT_EQ(1, count_leading_ones(0xa1));
EXPECT_EQ(2, count_leading_ones(0xd3));
EXPECT_EQ(3, count_leading_ones(0xe8));
EXPECT_EQ(7, count_leading_ones(0xfe));
EXPECT_EQ(8, count_leading_ones(0xff));
}
TEST(LengthEncoding, encode_length)
{
EXPECT_EQ(ByteBuffer { 0x00 }, encode_length(0));
EXPECT_EQ(ByteBuffer { 5 }, encode_length(5));
EXPECT_EQ(ByteBuffer { 123 }, encode_length(123));
EXPECT_EQ(ByteBuffer { 127 }, encode_length(127));
EXPECT_EQ((ByteBuffer { 0x80, 128 }), encode_length(128));
EXPECT_EQ((ByteBuffer { 0xbf, 0xff }), encode_length(0x3fff));
EXPECT_EQ((ByteBuffer { 0x81, 0xff }), encode_length(0x01ff));
EXPECT_EQ((ByteBuffer { 0xdf, 0xff, 0xff }), encode_length(0x1fffff));
EXPECT_EQ((ByteBuffer { 0xe0, 0x20, 0x00, 0x00 }), encode_length(0x200000));
EXPECT_EQ(ByteBuffer { 0x0a }, encode_length(10));
EXPECT_EQ((ByteBuffer { 0x88, 0x88 }), encode_length(2184));
}
TEST(LengthEncoding, decode_length_empty_buffer)
{
ByteBuffer buffer;
auto decoded = decode_length(buffer);
EXPECT_EQ(buffer.end(), std::get<0>(decoded));
EXPECT_EQ(0, std::get<1>(decoded));
}
TEST(LengthEncoding, decode_length_zero_size)
{
ByteBuffer buffer { 0x00, 0xC0, 0xFF, 0xEE };
auto decoded = decode_length(buffer);
EXPECT_EQ(std::next(buffer.begin()), std::get<0>(decoded));
EXPECT_EQ(0, std::get<1>(decoded));
}
TEST(LengthEncoding, decode_length_prefix_too_long)
{
ByteBuffer buffer { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xba, 0xbe };
auto decoded = decode_length(buffer);
EXPECT_EQ(buffer.begin(), std::get<0>(decoded));
EXPECT_EQ(0, std::get<1>(decoded));
}
TEST(LengthEncoding, decode_length_buffer_too_short)
{
ByteBuffer buffer { 0x02, 0xde };
auto decoded_tuple = decode_length(buffer);
EXPECT_EQ(std::next(buffer.begin()), std::get<0>(decoded_tuple));
EXPECT_EQ(2, std::get<1>(decoded_tuple));
}
TEST(LengthEncoding, decode_length_good)
{
ByteBuffer buffer { 0xe0, 0x00, 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde };
auto decoded_tuple = decode_length(buffer);
EXPECT_EQ(std::next(buffer.begin(), 4), std::get<0>(decoded_tuple));
EXPECT_EQ(4, std::get<1>(decoded_tuple));
}
TEST(LengthEncoding, serialize_length)
{
ByteBuffer buf;
auto serialize_length_into_buffer = [&buf](std::size_t length) {
vanetza::byte_buffer_sink sink(buf);
boost::iostreams::stream_buffer<vanetza::byte_buffer_sink> stream(sink);
OutputArchive oa(stream);
serialize_length(oa, length);
};
serialize_length_into_buffer(0x200000);
ASSERT_EQ(4, buf.size());
EXPECT_EQ(0xE0, buf[0]);
EXPECT_EQ(0x20, buf[1]);
EXPECT_EQ(0x00, buf[2]);
EXPECT_EQ(0x00, buf[3]);
buf.clear();
serialize_length_into_buffer(128);
ASSERT_EQ(2, buf.size());
EXPECT_EQ(0x80, buf[0]);
EXPECT_EQ(0x80, buf[1]);
}
TEST(LengthEncoding, length_coding_size)
{
EXPECT_EQ(1, length_coding_size(0x3f));
EXPECT_EQ(1, length_coding_size(0x20));
EXPECT_EQ(1, length_coding_size(0x7f));
EXPECT_EQ(1, length_coding_size(0x40));
EXPECT_EQ(2, length_coding_size(0x3fff));
EXPECT_EQ(2, length_coding_size(0x2000));
EXPECT_EQ(3, length_coding_size(0x7fff));
EXPECT_EQ(3, length_coding_size(0x4000));
EXPECT_EQ(3, length_coding_size(0x1fffff));
EXPECT_EQ(4, length_coding_size(0x3fffff));
}
TEST(LengthEncoding, WebValidator_length)
{
ByteBuffer buf {{ 0x81, 0x03 }};
vanetza::byte_buffer_source source(buf);
boost::iostreams::stream_buffer<vanetza::byte_buffer_source> stream(source);
InputArchive ia(stream);
size_t length = deserialize_length(ia);
EXPECT_EQ(259, length);
}
@@ -0,0 +1,91 @@
#include <vanetza/common/clock.hpp>
#include <vanetza/common/manual_runtime.hpp>
#include <vanetza/security/v2/default_certificate_validator.hpp>
#include <vanetza/security/v2/naive_certificate_provider.hpp>
#include <boost/variant/get.hpp>
#include <gtest/gtest.h>
using namespace vanetza;
using namespace vanetza::security;
using namespace vanetza::security::v2;
using boost::get;
class NaiveCertificateProviderTest : public ::testing::Test
{
public:
NaiveCertificateProviderTest() : runtime(Clock::at("2016-08-01 00:00")), cert_provider(runtime)
{
}
protected:
ManualRuntime runtime;
NaiveCertificateProvider cert_provider;
};
TEST_F(NaiveCertificateProviderTest, own_certificate)
{
Certificate signed_certificate = cert_provider.own_certificate();
// Check signature
EXPECT_EQ(2 * field_size(PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256),
extract_signature_buffer(signed_certificate.signature.some_ecdsa).size());
EXPECT_EQ(PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256, get_type(signed_certificate.signature));
// Check signer_info and subject_info
EXPECT_EQ(2, signed_certificate.version());
EXPECT_EQ(SignerInfoType::Certificate_Digest_With_SHA256, get_type(signed_certificate.signer_info));
EXPECT_EQ(SubjectType::Authorization_Ticket, signed_certificate.subject_info.subject_type);
EXPECT_TRUE(signed_certificate.subject_info.subject_name.empty());
// Check subject attributes
int verification_key_counter = 0;
SubjectAssurance test_assurance_level;
int assurance_level_counter = 0;
using subject_type_int = std::underlying_type<SubjectAttributeType>::type;
subject_type_int last_subject_type = 0;
for (auto& subject_attribute : signed_certificate.subject_attributes) {
// Verify that fields are in ascending order
subject_type_int subject_type = static_cast<subject_type_int>(get_type(subject_attribute));
EXPECT_LE(last_subject_type, subject_type);
last_subject_type = subject_type;
if (SubjectAttributeType::Verification_Key == get_type(subject_attribute)) {
verification_key_counter++;
} else if (SubjectAttributeType::Assurance_Level == get_type(subject_attribute)) {
test_assurance_level = get<SubjectAssurance>(subject_attribute);
assurance_level_counter++;
} else if (SubjectAttributeType::ITS_AID_SSP_List == get_type(subject_attribute)) {
// TODO: check aid permissions
}
}
EXPECT_EQ(1, verification_key_counter);
ASSERT_EQ(1, assurance_level_counter);
EXPECT_EQ(0, test_assurance_level.raw);
// Check validity restrictions
Time32 start_time;
Time32 end_time;
using restriction_type_int = std::underlying_type<ValidityRestrictionType>::type;
restriction_type_int last_restriction_type = 0;
for (ValidityRestriction restriction : signed_certificate.validity_restriction) {
// Verify that fields are in ascending order
restriction_type_int restriction_type = static_cast<restriction_type_int>(get_type(restriction));
EXPECT_LE(last_restriction_type, restriction_type);
last_restriction_type = restriction_type;
if (ValidityRestrictionType::Time_Start_And_End == get_type(restriction)) {
StartAndEndValidity& time_validation = get<StartAndEndValidity>(restriction);
start_time = time_validation.start_validity;
end_time = time_validation.end_validity;
} else if (ValidityRestrictionType::Region == get_type(restriction)) {
// TODO: Region not specified yet
}
}
EXPECT_LT(start_time, end_time);
}
@@ -0,0 +1,38 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/payload.hpp>
#include <vanetza/security/v2/tests/check_payload.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza;
using namespace vanetza::security::v2;
TEST(Payload, serialize_cohesive)
{
Payload p;
p.type = PayloadType::Unsecured;
p.data = CohesivePacket({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }, OsiLayer::Application);
check(p, serialize_roundtrip(p));
}
TEST(Payload, serialize_chunk)
{
Payload p;
p.type = PayloadType::Encrypted;
ChunkPacket packet;
packet[OsiLayer::Network] = ByteBuffer { 1, 2, 3, 4 };
packet[OsiLayer::Transport] = ByteBuffer { 5, 6, 7, 8 };
packet[OsiLayer::Application] = ByteBuffer { 9, 10, 11, 12 };
p.data = packet;
check(p, serialize_roundtrip(p));
}
TEST(Payload, size)
{
Payload p;
p.type = PayloadType::Signed;
p.data = CohesivePacket({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, OsiLayer::Session);
EXPECT_EQ(1 /* type */ + 1 /* length coding */ + 10 /* bytes */, get_size(p));
}
@@ -0,0 +1,90 @@
#include <vanetza/security/v2/persistence.hpp>
#include <gtest/gtest.h>
#include <array>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <iterator>
#include <sstream>
using namespace vanetza::security;
#define WRITEABLE(path) WORK_DIR "/" path
#define ASSET(path) ASSET_DIR "/" path
namespace
{
const std::array<uint8_t, 32> expected_private_key = {
0x53, 0xb7, 0x7e, 0xb8, 0x48, 0x2e, 0x3c, 0x1a,
0xd3, 0x36, 0x70, 0xc0, 0xc6, 0xc4, 0x6b, 0xc0,
0x36, 0x90, 0xd4, 0x00, 0x59, 0xd3, 0xcb, 0xb5,
0x81, 0xb3, 0x36, 0xaf, 0x8a, 0x98, 0x93, 0xf4
};
const std::array<uint8_t, 32> expected_public_x = {
0x1c, 0x85, 0x0d, 0xc7, 0x45, 0x63, 0x29, 0x3c,
0xb0, 0xf3, 0xe5, 0x5e, 0xda, 0x7b, 0x10, 0xec,
0xb4, 0xe9, 0x74, 0x6f, 0x83, 0x6f, 0x84, 0x76,
0x96, 0xc3, 0x1e, 0xe8, 0x68, 0x4e, 0x37, 0x76
};
const std::array<uint8_t, 32> expected_public_y = {
0x28, 0xf1, 0x67, 0xfb, 0x64, 0xce, 0x7b, 0x79,
0xa6, 0x02, 0x06, 0x2a, 0xac, 0x11, 0x7f, 0x59,
0x6b, 0xac, 0x77, 0xc7, 0x1c, 0xd6, 0xf4, 0xca,
0xa7, 0x08, 0x7a, 0xcc, 0xcd, 0xab, 0x91, 0xab
};
void check_key_pair(const ecdsa256::KeyPair& kp)
{
EXPECT_EQ(kp.private_key.key, expected_private_key);
EXPECT_EQ(kp.public_key.x, expected_public_x);
EXPECT_EQ(kp.public_key.y, expected_public_y);
}
ecdsa256::KeyPair make_test_key_pair()
{
ecdsa256::KeyPair kp;
kp.private_key.key = expected_private_key;
kp.public_key.x = expected_public_x;
kp.public_key.y = expected_public_y;
return kp;
}
std::string read_file_bytes(const std::string& path)
{
std::ifstream file(path, std::ios::binary);
return {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
}
} // namespace
#if defined VANETZA_WITH_OPENSSL || defined VANETZA_WITH_CRYPTOPP
TEST(Persistence, load_private_key_from_file)
{
check_key_pair(v2::load_private_key_from_file(ASSET("test_key.der")));
}
TEST(Persistence, save_and_load_pkcs8_der)
{
auto kp = make_test_key_pair();
const std::string path = WRITEABLE("test_save.der");
std::ofstream ofs(path, std::ios::binary);
EXPECT_TRUE(v2::save_private_key_pkcs8_der(ofs, kp));
ofs.flush();
check_key_pair(v2::load_private_key_from_file(path));
std::remove(path.c_str());
}
TEST(Persistence, save_der_matches_reference_file)
{
auto kp = make_test_key_pair();
std::ostringstream oss(std::ios::binary);
EXPECT_TRUE(v2::save_private_key_pkcs8_der(oss, kp));
auto reference = read_file_bytes(ASSET("test_key.der"));
EXPECT_EQ(oss.str(), reference);
}
#endif /* VANETZA_WITH_OPENSSL || VANETZA_WITH_CRYPTOPP */
@@ -0,0 +1,52 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/public_key.hpp>
#include <vanetza/security/v2/public_key.hpp>
#include <vanetza/security/v2/tests/check_public_key.hpp>
using namespace vanetza;
using namespace vanetza::security;
using namespace std;
v2::PublicKey serialize(v2::PublicKey key)
{
std::stringstream stream;
OutputArchive oa(stream);
serialize(oa, key);
v2::PublicKey deKey;
InputArchive ia(stream);
deserialize(ia, deKey);
return deKey;
}
TEST(PublicKey, Field_Size)
{
EXPECT_EQ(32, field_size(v2::PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256));
EXPECT_EQ(32, field_size(v2::PublicKeyAlgorithm::ECIES_NISTP256));
}
TEST(PublicKey, ECIES_NISTP256)
{
v2::ecies_nistp256 ecies;
ecies.public_key = Uncompressed { random_byte_sequence(32, 1), random_byte_sequence(32, 2) };
ecies.supported_symm_alg = v2::SymmetricAlgorithm::AES128_CCM;
v2::PublicKey key = ecies;
v2::PublicKey deKey = serialize(key);
check(key, deKey);
EXPECT_EQ(v2::PublicKeyAlgorithm::ECIES_NISTP256, get_type(deKey));
EXPECT_EQ(67, get_size(deKey));
}
TEST(PublicKey, ECDSA_NISTP256_With_SHA256)
{
v2::ecdsa_nistp256_with_sha256 ecdsa;
ecdsa.public_key = X_Coordinate_Only { random_byte_sequence(32, 1) };
v2::PublicKey key = ecdsa;
v2::PublicKey deKey = serialize(key);
check(key, deKey);
EXPECT_EQ(v2::PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256, get_type(deKey));
EXPECT_EQ(34, get_size(deKey));
}
@@ -0,0 +1,25 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/recipient_info.hpp>
#include <vanetza/security/v2/tests/check_recipient_info.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza;
using namespace vanetza::security;
using namespace vanetza::security::v2;
TEST(RecipientInfo, Serialize)
{
EciesEncryptedKey ecies;
ecies.v = Compressed_Lsb_Y_0 { random_byte_sequence(field_size(PublicKeyAlgorithm::ECIES_NISTP256), 1337) };
auto cbuf = random_byte_sequence(field_size(SymmetricAlgorithm::AES128_CCM), 7331);
ecies.c = { cbuf.begin(), cbuf.end() };
auto tbuf = random_byte_sequence(ecies.t.size(), 1234);
std::copy_n(tbuf.begin(), ecies.t.size(), ecies.t.data());
RecipientInfo info;
info.enc_key = ecies;
auto certbuf = random_byte_sequence(info.cert_id.size(), 4321);
std::copy_n(certbuf.begin(), info.cert_id.size(), info.cert_id.data());
check(info, serialize_roundtrip(info, SymmetricAlgorithm::AES128_CCM));
}
@@ -0,0 +1,261 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/region.hpp>
#include <vanetza/security/v2/tests/check_region.hpp>
#include <vanetza/security/tests/serialization.hpp>
#include <vanetza/units/angle.hpp>
#include <vanetza/units/length.hpp>
#include <limits>
using namespace vanetza::security::v2;
using vanetza::geonet::distance_u16t;
using vanetza::geonet::geo_angle_i32t;
using vanetza::units::degrees;
using vanetza::units::si::meter;
TEST(Region, Serialize_CircularRegion)
{
CircularRegion reg;
reg.center.latitude = static_cast<geo_angle_i32t>(12564 * degrees);
reg.center.longitude = static_cast<geo_angle_i32t>(654321 * degrees);
reg.radius = static_cast<distance_u16t>(1337 * meter);
check(reg, serialize_roundtrip(reg));
}
TEST(Region, Serialize_IdentifiedRegion)
{
IdentifiedRegion reg;
reg.region_dictionary = RegionDictionary::ISO_3166_1;
reg.region_identifier = 12345;
reg.local_region.set(546);
check(reg, serialize_roundtrip(reg));
}
TEST(Region, Serialize_PolygonalRegion)
{
PolygonalRegion reg;
for (std::size_t i = 0; i < 3; ++i) {
reg.push_back(TwoDLocation {
geo_angle_i32t::from_value(25 + i),
geo_angle_i32t::from_value(26 + i)
});
}
check(reg, serialize_roundtrip(reg));
}
TEST(Region, Serialize_RectangularRegion_list)
{
std::list<RectangularRegion> reg;
for (std::size_t i = 0; i < 5; ++i) {
reg.push_back(RectangularRegion {
TwoDLocation {
geo_angle_i32t::from_value(1000000 + i),
geo_angle_i32t::from_value(1010000 + i)
},
TwoDLocation {
geo_angle_i32t::from_value(1020000 + i),
geo_angle_i32t::from_value(1030000 + i)
}
});
}
check(reg, serialize_roundtrip(reg));
}
TEST(Region, TwoDLocation_Within_Circle)
{
CircularRegion region;
region.radius = static_cast<distance_u16t>(400 * meter);
region.center = TwoDLocation {
geo_angle_i32t::from_value(490139190),
geo_angle_i32t::from_value(84044460)
};
EXPECT_TRUE(is_within(region.center, region));
EXPECT_TRUE(is_within(TwoDLocation {
geo_angle_i32t::from_value(490143170),
geo_angle_i32t::from_value(83995470)
}, region));
EXPECT_FALSE(is_within(TwoDLocation {
geo_angle_i32t::from_value(490145910),
geo_angle_i32t::from_value(83984740)
}, region));
EXPECT_FALSE(is_within(TwoDLocation {
geo_angle_i32t::from_value(490137060),
geo_angle_i32t::from_value(84120020)
}, region));
}
TEST(Region, Circle_Within_Circle)
{
CircularRegion outer;
outer.radius = static_cast<distance_u16t>(400 * meter);
outer.center = TwoDLocation {
geo_angle_i32t::from_value(490139190),
geo_angle_i32t::from_value(84044460)
};
CircularRegion inner;
inner.center = outer.center;
for (int i = 0; i <= 400; i += 10) {
inner.radius = static_cast<distance_u16t>(i * meter);
EXPECT_TRUE(is_within(inner, outer));
}
inner.radius = static_cast<distance_u16t>(401 * meter);
EXPECT_FALSE(is_within(inner, outer));
inner.center = TwoDLocation {
geo_angle_i32t::from_value(490143170),
geo_angle_i32t::from_value(83995470)
};
inner.radius = static_cast<distance_u16t>(38 * meter);
EXPECT_TRUE(is_within(inner, outer));
inner.radius = static_cast<distance_u16t>(40 * meter);
EXPECT_FALSE(is_within(inner, outer));
}
TEST(Region, TwoDLocation_Within_None)
{
NoneRegion region;
EXPECT_TRUE(is_within(TwoDLocation {
geo_angle_i32t::from_value(490143170),
geo_angle_i32t::from_value(83995470)
}, region));
}
TEST(Region, Circle_Within_None)
{
NoneRegion outer;
CircularRegion inner;
inner.radius = static_cast<distance_u16t>(400 * meter);
inner.center = TwoDLocation {
geo_angle_i32t::from_value(490139190),
geo_angle_i32t::from_value(84044460)
};
EXPECT_TRUE(is_within(inner, outer));
EXPECT_FALSE(is_within(outer, inner));
}
TEST(Region, TwoDLocation_Within_Rectangles)
{
TwoDLocation northwest {
static_cast<geo_angle_i32t>(20 * degrees),
static_cast<geo_angle_i32t>(10 * degrees)
};
TwoDLocation southeast {
static_cast<geo_angle_i32t>(10 * degrees),
static_cast<geo_angle_i32t>(20 * degrees)
};
RectangularRegion region { northwest, southeast };
std::list<RectangularRegion> regions({ region });
// inside
EXPECT_TRUE(is_within(TwoDLocation {
static_cast<geo_angle_i32t>(15 * degrees),
static_cast<geo_angle_i32t>(15 * degrees)
}, regions));
// outside - left
EXPECT_FALSE(is_within(TwoDLocation {
static_cast<geo_angle_i32t>(15 * degrees),
static_cast<geo_angle_i32t>(9 * degrees)
}, regions));
// outside - right
EXPECT_FALSE(is_within(TwoDLocation {
static_cast<geo_angle_i32t>(15 * degrees),
static_cast<geo_angle_i32t>(21 * degrees)
}, regions));
// outside - top
EXPECT_FALSE(is_within(TwoDLocation {
static_cast<geo_angle_i32t>(21 * degrees),
static_cast<geo_angle_i32t>(15 * degrees)
}, regions));
// outside - down
EXPECT_FALSE(is_within(TwoDLocation {
static_cast<geo_angle_i32t>(9 * degrees),
static_cast<geo_angle_i32t>(15 * degrees)
}, regions));
}
TEST(Region, Rectangles_Within_None)
{
TwoDLocation northwest {
static_cast<geo_angle_i32t>(20 * degrees),
static_cast<geo_angle_i32t>(10 * degrees)
};
TwoDLocation southeast {
static_cast<geo_angle_i32t>(10 * degrees),
static_cast<geo_angle_i32t>(20 * degrees)
};
RectangularRegion region { northwest, southeast };
std::list<RectangularRegion> regions({ region });
EXPECT_TRUE(is_within(regions, NoneRegion()));
EXPECT_FALSE(is_within(NoneRegion(), regions));
}
TEST(Region, Rectangle_Within_Rectangle_Exact)
{
TwoDLocation northwest_a {
static_cast<geo_angle_i32t>(10 * degrees),
static_cast<geo_angle_i32t>(10 * degrees)
};
TwoDLocation southeast_a {
static_cast<geo_angle_i32t>(20 * degrees),
static_cast<geo_angle_i32t>(20 * degrees)
};
TwoDLocation northwest_b {
static_cast<geo_angle_i32t>(10 * degrees),
static_cast<geo_angle_i32t>(10 * degrees)
};
TwoDLocation southeast_b {
static_cast<geo_angle_i32t>(20 * degrees),
static_cast<geo_angle_i32t>(20 * degrees)
};
RectangularRegion a { northwest_a, southeast_a };
RectangularRegion b { northwest_b, southeast_b };
std::list<RectangularRegion> region_a({ a });
std::list<RectangularRegion> region_b({ b });
EXPECT_TRUE(is_within(region_a, region_b));
EXPECT_TRUE(is_within(region_b, region_a));
}
TEST(Region, Altitude_To_Elevation)
{
using Elevation = ThreeDLocation::Elevation;
auto altitude_empty = std::numeric_limits<double>::quiet_NaN() * meter;
EXPECT_EQ(to_elevation(altitude_empty), ThreeDLocation::unknown_elevation);
auto altitude_positive = 2843.6 * meter;
EXPECT_EQ(to_elevation(altitude_positive), (Elevation { 0x6F, 0x14 }));
auto altitude_negative = -170.2 * meter;
EXPECT_EQ(to_elevation(altitude_negative), (Elevation { 0xF9, 0x5A }));
auto altitude_below_min = -420.0 * meter;
EXPECT_EQ(to_elevation(altitude_below_min), ThreeDLocation::min_elevation);
auto altitude_above_max = 6150.0 * meter;
EXPECT_EQ(to_elevation(altitude_above_max), ThreeDLocation::max_elevation);
// examples given in TS 103 097 V1.2.1 (section 4.2.19)
EXPECT_EQ(to_elevation(0.0 * meter), (Elevation { 0x00, 0x00 }));
EXPECT_EQ(to_elevation(100.0 * meter), (Elevation { 0x03, 0xe8 }));
EXPECT_EQ(to_elevation(-209.5 * meter), (Elevation { 0xf7, 0xd1 }));
}
@@ -0,0 +1,134 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/secured_message.hpp>
#include <vanetza/security/v2/tests/check_secured_message.hpp>
#include <vanetza/security/v2/tests/check_signature.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza;
using namespace vanetza::security;
// Note: WebValidator refers to https://werkzeug.dcaiti.tu-berlin.de/etsi/ts103097/
TEST(SecuredMessage, Serialization)
{
v2::SecuredMessage m;
m.header_fields.push_back(v2::Time64 { 0x4711 });
m.payload = { v2::PayloadType::Unsecured, CohesivePacket({ 5, 10, 15, 25, 40 }, OsiLayer::Application) };
std::list<v2::TrailerField> list;
list.push_back(v2::Signature { create_random_ecdsa_signature(44) });
list.push_back(v2::Signature { create_random_ecdsa_signature(45) });
m.trailer_fields = list;
check(m, serialize_roundtrip(m));
}
TEST(SecuredMessage, header_field_extractor)
{
v2::SecuredMessage m;
auto empty = m.header_field(v2::HeaderFieldType::Generation_Time);
EXPECT_FALSE(empty);
m.header_fields.push_back(v2::Time64 { 25 });
m.header_fields.push_back(v2::IntX { 23 });
auto time = m.header_field(v2::HeaderFieldType::Generation_Time);
ASSERT_TRUE(time);
EXPECT_EQ(25, boost::get<v2::Time64>(*time));
auto msg = m.header_field(v2::HeaderFieldType::Its_Aid);
ASSERT_TRUE(msg);
EXPECT_EQ(23, boost::get<v2::IntX>(*msg).get());
// field modifications should pass through
boost::get<v2::Time64>(*time) = 26;
auto time2 = m.header_field(v2::HeaderFieldType::Generation_Time);
ASSERT_TRUE(time2);
EXPECT_EQ(v2::Time64 { 26 }, boost::get<v2::Time64>(*time2));
}
TEST(SecuredMessage, trailer_field_extractor)
{
v2::SecuredMessage m;
auto empty = m.trailer_field(v2::TrailerFieldType::Signature);
EXPECT_FALSE(!!empty);
m.trailer_fields.push_back(v2::Signature {});
m.trailer_fields.push_back(v2::Signature {});
auto first = m.trailer_field(v2::TrailerFieldType::Signature);
ASSERT_TRUE(!!first);
EXPECT_EQ(&m.trailer_fields.front(), first);
}
TEST(SecuredMessage, WebValidator_Serialize_SecuredMessageV2_1)
{
// SecuredMessage/v1 from FOKUS WebValidator adapted for v2
const char str[] =
"02810180020201A8ED6DF65B0E6D6A0100809400000418929DB6A9E452223062C52028E956BF98"
"74E0A40D21D5F9F56564F39C5DD187C922F2E5F0630373879A43393373B9F6205BF01FBD9C1F1131"
"65C291C376F535010004EABA91A915D81807E910FD292D99DF8B401EED88CF7F031412D5ED9905F9"
"996469798C412FC8F7237A3AB3469795E2DEF5E1B783EA4F6B6A2359D21772B2EA9D0200210AC040"
"800101C0408101010F01099EB20109B1270003040100960000004B2E6D0D0EE9BC4AD9CD087B601E"
"9AF06031995443D652763455FBB794B33982889260740EF64CFA8C6808A58F98E06CE42A1E9C22A0"
"785D7242647F7895ABFC0000009373931CD7580502011C983E690E5F6D755BD4871578A9427E7B"
"C383903DC7DA3B560384013643010000FE8566BEA87B39E6411F80226E792D6E01E77B598F2BB1FC"
"E7F2DD441185C07CEF0573FBFB9876B99FE811486F6F5D499E6114FC0724A67F8D71D2A897A7EB34";
v2::SecuredMessage m;
deserialize_from_hexstring(str, m);
EXPECT_EQ(358, get_size(m));
EXPECT_EQ(2, m.protocol_version());
EXPECT_EQ(3, m.header_fields.size());
auto signer_info = m.header_field(v2::HeaderFieldType::Signer_Info);
ASSERT_TRUE(!!signer_info);
auto generation_time = m.header_field(v2::HeaderFieldType::Generation_Time);
ASSERT_TRUE(!!generation_time);
auto its_aid = m.header_field(v2::HeaderFieldType::Its_Aid);
ASSERT_TRUE(!!its_aid);
EXPECT_EQ(v2::IntX {2}, boost::get<v2::IntX>(*its_aid));
EXPECT_EQ(v2::PayloadType::Signed, m.payload.type);
EXPECT_EQ(28, size(m.payload.data, min_osi_layer(), max_osi_layer()));
EXPECT_EQ(1, m.trailer_fields.size());
EXPECT_TRUE(!!m.trailer_field(v2::TrailerFieldType::Signature));
}
TEST(SecuredMessage, WebValidator_Serialize_SecuredMessageV2_2)
{
// SecuredMessage/v1 from FOKUS WebValidator adapted for v2
const char str[] =
"02810180020201A8ED6DF65B0E6D6A01008094000004C4EC137145DD4F450145DE530CCA36E73A"
"B3D87FC8275847CDAD8248C1CD20879BD6A8CB54EA9E05D3B41376CE2F24789AEF82836CA818D568"
"ADF4A140E96E48010004D6C268EE68B5B8B387B2312B7E1D21CE0C366D251A32431508B96EB6A347"
"9CCF96A8738F30ED451F00DA8DDE84367C7EB16727D14FF14F5DD8F9791FE0A12A640200210AC040"
"800101C0408101010F01099EB20109B1270003040100960000001EB035FE8E51DCDD8558DE0BE9B8"
"7895B36B420583A5C6B2B8B2EAB7F3D3C99163638FA025A0033D4BD80BBA02B8E3DE1B55766459D4"
"94677AF24917E51B80AC0000009373CC5F22C805020120F29384759027349075829034707ABABA"
"BABABAABAB98437985739845783974954301000081E7CDB6D2C741C1700822305C39E8E809622AF9"
"FCA1C0786F762D08E80580C42F1FCC1D5499577210834C390BB4613E102DECB14F575A2820743DC9"
"A66BBD7A";
v2::SecuredMessage m;
deserialize_from_hexstring(str, m);
check(m, serialize_roundtrip(m));
}
TEST(SecuredMessage, WebValidator_Serialize_SecuredMessageV2_3)
{
// SecuredMessage/v1 from FOKUS WebValidator adapted for v2
const char str[] =
"02810180020201A8ED6DF65B0E6D6A010080940000040209B0434163CCBAFDD34A45333E418FB9"
"6C05BBE0E7E1D755D40D0B4BBE8DA508EC2F2723B7ADF0F27C39F3AECFF0783C196F9961F8821E62"
"94375D9294CD6A01000452113CE698DB081491675DF8FFE81C23EA5D0071B2D2BF0E0DA4ADA0CDA5"
"8259CA5D999200B6565E194EDAB8BD3DCA863F2DDF39C13E7A0375ECE2566C5EB8C60200210AC040"
"800101C0408101010F01099EB20109B1270003040100960000008DA1F3F9F35E04C3DE77D7438988"
"A8D57EBE44DAA021A4269E297C177C9CFE458E128EC290785D6631961625020943B6D87DAA54919A"
"98F7865709929A7C6E480000009373CF482D40050201080123456789ABCDEF43010000371423BB"
"A0902D8AF2FB2226D73A7781D4D6B6772650A8BEE5A1AF198CEDABA2C9BF57540C629E6A1E629B88"
"12AEBDDDBCAF472F6586F16C14B3DEFBE9B6ADB2";
v2::SecuredMessage m;
deserialize_from_hexstring(str, m);
check(m, serialize_roundtrip(m));
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,27 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/public_key.hpp>
#include <vanetza/security/v2/signature.hpp>
#include <vanetza/security/v2/tests/check_signature.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza::security;
TEST(Signature, serialize)
{
v2::Signature signature = create_random_ecdsa_signature(42);
check(signature, v2::serialize_roundtrip(signature));
}
TEST(Signature, WebValidator_Size)
{
v2::Signature sig;
EcdsaSignature eSig;
X_Coordinate_Only x;
x.x = buffer_from_hexstring("8DA1F3F9F35E04C3DE77D7438988A8D57EBE44DAA021A4269E297C177C9CFE45");
eSig.R = x;
eSig.s = buffer_from_hexstring("8E128EC290785D6631961625020943B6D87DAA54919A98F7865709929A7C6E48");
sig = eSig;
EXPECT_EQ(66, get_size(sig));
}
@@ -0,0 +1,35 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/certificate.hpp>
#include <vanetza/security/v2/signer_info.hpp>
#include <vanetza/security/v2/tests/check_signature.hpp>
#include <vanetza/security/v2/tests/check_signer_info.hpp>
#include <vanetza/security/tests/serialization.hpp>
using vanetza::random_byte_sequence;
using vanetza::security::create_random_ecdsa_signature;
using vanetza::security::HashedId8;
using namespace vanetza::security::v2;
TEST(SignerInfo, Serialization)
{
std::list<Certificate> certificates;
Certificate a;
a.signature = create_random_ecdsa_signature(28);
Certificate b;
b.signature = create_random_ecdsa_signature(29);
certificates.push_back(a);
certificates.push_back(b);
SignerInfo info { certificates };
check(info, serialize_roundtrip(info));
}
TEST(SignerInfo, WebValidator_Size)
{
SignerInfo info;
HashedId8 id {{ 0xA8, 0xED, 0x6D, 0xF6, 0x5B, 0x0E, 0x6D, 0x6A }};
info = id;
EXPECT_EQ(9, get_size(info));
}
@@ -0,0 +1,47 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/subject_attribute.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
#include <vanetza/security/v2/tests/check_subject_attribute.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza::security::v2;
using vanetza::security::deserialize_from_hexstring;
TEST(SubjectAttribute, serialize)
{
std::list<SubjectAttribute> list;
list.push_back(create_random_verification_key(33));
list.push_back(create_random_encryption_key(34));
list.push_back(SubjectAssurance { 124 });
std::list<IntX> its_aid;
for (int i = 0; i < 4; ++i) {
its_aid.push_back(create_random_its_aid(i + 66));
}
list.push_back(its_aid);
std::list<ItsAidSsp> its_aid_ssp;
for (int i = 0; i < 1; ++i) {
its_aid_ssp.push_back(create_random_its_aid_ssp(i + 67));
}
list.push_back(its_aid_ssp);
check(list, serialize_roundtrip(list));
}
TEST(SubjectAttribute, WebValidator_ItsAidSsp)
{
std::list<ItsAidSsp> list;
ItsAidSsp its1;
its1.its_aid.set(16512);
its1.service_specific_permissions = {0x01};
list.push_back(its1);
ItsAidSsp its2;
its2.its_aid.set(16513);
its2.service_specific_permissions = {0x01};
list.push_back(its2);
EXPECT_EQ(10, get_size(list));
std::list<ItsAidSsp> other_list;
deserialize_from_hexstring("0AC040800101C040810101", other_list);
check(list, other_list);
}
@@ -0,0 +1,23 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/subject_info.hpp>
#include <vanetza/security/v2/tests/check_subject_info.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza::security::v2;
TEST(SubjectInfo, Serialization)
{
SubjectInfo sub;
sub.subject_type = SubjectType::Root_CA;
sub.subject_name = vanetza::random_byte_sequence(40);
check(sub, serialize_roundtrip(sub));
}
TEST(SubjectInfo, WebValidator_Size)
{
SubjectInfo info;
info.subject_type = SubjectType::Authorization_Ticket;
EXPECT_EQ(2, get_size(info));
}
@@ -0,0 +1,47 @@
#include <gtest/gtest.h>
#include <vanetza/common/byte_sequence.hpp>
#include <vanetza/security/v2/trailer_field.hpp>
#include <vanetza/security/v2/tests/check_list.hpp>
#include <vanetza/security/v2/tests/check_signature.hpp>
#include <vanetza/security/v2/tests/check_trailer_field.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza;
using namespace vanetza::security::v2;
using vanetza::security::buffer_from_hexstring;
using vanetza::security::create_random_ecdsa_signature;
using vanetza::security::EccPoint;
using vanetza::security::EcdsaSignature;
using vanetza::security::X_Coordinate_Only;
TEST(TrailerField, Serialization)
{
std::list<TrailerField> list;
EcdsaSignature a = create_random_ecdsa_signature(8);
EcdsaSignature b = create_random_ecdsa_signature(9);
list.push_back(TrailerField { a });
list.push_back(TrailerField { b });
check(list, serialize_roundtrip(list));
}
TEST(TrailerField, WebValidator_Size)
{
TrailerField field;
Signature sig;
EcdsaSignature ecdsa;
EccPoint point;
X_Coordinate_Only x;
x.x = buffer_from_hexstring("371423BBA0902D8AF2FB2226D73A7781D4D6B6772650A8BEE5A1AF198CEDABA2");
point = x;
ecdsa.R = point;
ecdsa.s = buffer_from_hexstring("C9BF57540C629E6A1E629B8812AEBDDDBCAF472F6586F16C14B3DEFBE9B6ADB2");
sig = ecdsa;
field = sig;
std::list<TrailerField> list;
list.push_back(field);
EXPECT_EQ(67, get_size(list));
EXPECT_EQ(67, get_size(field));
}
@@ -0,0 +1,29 @@
#include <gtest/gtest.h>
#include <vanetza/security/v2/certificate.hpp>
#include <vanetza/security/v2/trust_store.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza::security::v2;
using vanetza::security::HashedId8;
using vanetza::security::deserialize_from_hexstring;
TEST(TrustStoreTest, lookup)
{
const char cert_hex[] =
"0200040C547275737465645F526F6F74808D000004F1817DD05116B855A853F80DB171A3A470D431"
"70EA7EEFD8EF392D66ECEFBE501CEBA19963C9B6447574424FFF1BB89485743F4D09A72B715FC73C"
"87E5F70A110101000441279A383B80C812B72B1A5F5C3C590E5041C634A1ADCC4CE58393CA046D3C"
"619717AEF634F7D80D5F6A29FA7F86EBF823ACE0097A71EE0DF0793034B0D3797C02E0200224250B"
"0114B12B03154E0D83030000007D12BADF99D7070BCB237ED1FA7A5D86FD47E6ABA8E616B35E95A2"
"856FC6E26A493E1215BCEE8BEA18B8ED52FB240716C4D4EC7D7C0167F0F032CBB87DF611D9";
Certificate c;
deserialize_from_hexstring(cert_hex, c);
const HashedId8 cert_id = calculate_hash(c);
const HashedId8 zero_id {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }};
TrustStore trust_store;
EXPECT_EQ(0, trust_store.lookup(cert_id).size());
trust_store.insert(c);
EXPECT_EQ(0, trust_store.lookup(zero_id).size());
EXPECT_EQ(1, trust_store.lookup(cert_id).size());
}
@@ -0,0 +1,130 @@
#include <gtest/gtest.h>
#include <vanetza/common/bit_number.hpp>
#include <vanetza/security/v2/validity_restriction.hpp>
#include <vanetza/security/v2/tests/check_validity_restriction.hpp>
#include <vanetza/security/tests/serialization.hpp>
using namespace vanetza::security::v2;
TEST(Duration, Raw)
{
uint16_t a = 0x8007;
uint16_t b = 7;
Duration dur1(b, Duration::Units::Years);
Duration dur2(a);
EXPECT_EQ(dur1.raw(), a);
EXPECT_EQ(dur2.raw(), a);
}
TEST(Duration, Unit)
{
const uint16_t raw = 0x8007;
Duration duration(raw);
EXPECT_EQ(duration.raw(), raw);
EXPECT_EQ(duration.unit(), Duration::Units::Years);
}
TEST(Duration, Value)
{
const uint16_t raw = 0x8007;
Duration duration(raw);
EXPECT_EQ(duration.raw(), raw);
EXPECT_EQ(duration.value(), 7);
}
TEST(Duration, ToSeconds_Seconds)
{
const uint16_t raw = 0x0007;
Duration duration(raw);
EXPECT_EQ(duration.raw(), raw);
EXPECT_EQ(duration.value(), 7);
EXPECT_EQ(duration.to_seconds(), std::chrono::seconds(7));
}
TEST(Duration, ToSeconds_Minutes)
{
const uint16_t raw = 0x2007;
Duration duration(raw);
EXPECT_EQ(duration.raw(), raw);
EXPECT_EQ(duration.value(), 7);
EXPECT_EQ(duration.to_seconds(), std::chrono::minutes(7));
}
TEST(Duration, ToSeconds_Hours)
{
const uint16_t raw = 0x4007;
Duration duration(raw);
EXPECT_EQ(duration.raw(), raw);
EXPECT_EQ(duration.value(), 7);
EXPECT_EQ(duration.to_seconds(), std::chrono::hours(7));
}
TEST(Duration, ToSeconds_Sixty_Hour_Blocks)
{
const uint16_t raw = 0x6007;
Duration duration(raw);
EXPECT_EQ(duration.raw(), raw);
EXPECT_EQ(duration.value(), 7);
EXPECT_EQ(duration.to_seconds(), std::chrono::hours(7 * 60));
}
TEST(Duration, ToSeconds_Years)
{
const uint16_t raw = 0x8002;
Duration duration(raw);
EXPECT_EQ(duration.raw(), raw);
EXPECT_EQ(duration.value(), 2);
EXPECT_EQ(duration.to_seconds(), std::chrono::seconds(2 * 31556925));
}
TEST(Duration, ToSecondsMax)
{
Duration duration(0xffff, Duration::Units::Years);
EXPECT_EQ(duration.value(), 0x1fff);
EXPECT_EQ(duration.unit(), Duration::Units::Years);
EXPECT_EQ(duration.to_seconds(), std::chrono::seconds(static_cast<int64_t>(31556925) * 0x1fff));
}
TEST(Duration, ToSecondsInvalidUnit)
{
Duration duration(0xffff);
EXPECT_EQ(duration.to_seconds(), std::chrono::seconds::min());
}
TEST(ValidityRestriction, Serialization)
{
std::list<ValidityRestriction> list;
list.push_back(EndValidity { 0x548736 });
list.push_back(StartAndEndValidity { 0x54, 0x5712});
list.push_back(StartAndDurationValidity { 0x5712, Duration(13, Duration::Units::Hours)});
list.push_back(GeographicRegion { CircularRegion {} });
check(list, serialize_roundtrip(list));
}
TEST(ValidityRestriction, WebValidator_Size)
{
std::list<ValidityRestriction> list;
StartAndEndValidity start;
start.start_validity = 12345;
start.end_validity = 4786283;
list.push_back(start);
IdentifiedRegion id;
id.region_dictionary = RegionDictionary::UN_Stats;
id.region_identifier = 150;
id.local_region.set(0);
list.push_back(GeographicRegion { id });
EXPECT_EQ(15, get_size(list));
// TODO: compare raw bytes
}