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:
@@ -0,0 +1,21 @@
|
||||
include(UseGTest)
|
||||
add_library(security_test STATIC
|
||||
serialization.cpp
|
||||
)
|
||||
target_include_directories(security_test PUBLIC $<TARGET_PROPERTY:security,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
target_link_libraries(security_test PUBLIC ${GTest_LIBRARY})
|
||||
configure_gtest_directory(LINK_LIBRARIES Boost::boost security security_test
|
||||
COMPILE_DEFINITIONS ASSET_DIR="${SECURITY_TEST_ASSET_DIR}")
|
||||
|
||||
add_gtest(Backend backend.cpp)
|
||||
add_gtest(CamServiceSpecificPermissions cam_ssp.cpp)
|
||||
add_gtest(CertificateV3 certificate_v3.cpp)
|
||||
add_gtest(DecapService decap_service.cpp)
|
||||
add_gtest(DummyVerifyService dummy_verify_service.cpp)
|
||||
add_gtest(EccPointDecompression ecc_point_decompression.cpp)
|
||||
add_gtest(Geometry geometry.cpp)
|
||||
add_gtest(Hmac hmac.cpp)
|
||||
add_gtest(PeerRequestTracker peer_request_tracker.cpp)
|
||||
add_gtest(Persistence persistence.cpp)
|
||||
add_gtest(PublicKey public_key.cpp)
|
||||
add_gtest(SecuredMessageV3 secured_message_v3.cpp)
|
||||
Vendored
+394
@@ -0,0 +1,394 @@
|
||||
# FOKUS WebValidator for TS 103 097
|
||||
|
||||
Vanetza unit tests for SecuredMessage serialization use some third-party test data available online: [FOKUS WebValidator](https://werkzeug.dcaiti.tu-berlin.de/etsi/ts103097/)
|
||||
Unfortunately, the provided SecuredMessages are for protocol version 1 whereas Vanetza currently follows version 2. The original messages from FOKUS WebValidator are pasted into this document for reference because changes were necessary to adapt these for the recent protocol version.
|
||||
|
||||
## SecuredMessage/v1 (1)
|
||||
|
||||
``
|
||||
010181038002010901A8ED6DF65B0E6D6A0100809400000418929DB6A9E452223062C52028E956BF9874E0A40D21D5F9F56564F39C5DD187C922F2E5F0630373879A43393373B9F6205BF01FBD9C1F113165C291C376F535010004EABA91A915D81807E910FD292D99DF8B401EED88CF7F031412D5ED9905F9996469798C412FC8F7237A3AB3469795E2DEF5E1B783EA4F6B6A2359D21772B2EA9D0200210AC040800101C0408101010F01099EB20109B1270003040100960000004B2E6D0D0EE9BC4AD9CD087B601E9AF06031995443D652763455FBB794B33982889260740EF64CFA8C6808A58F98E06CE42A1E9C22A0785D7242647F7895ABFC0000009373931CD7580500021E011C983E690E5F6D755BD4871578A9427E7BC383903DC7DA3B560384013643010000FE8566BEA87B39E6411F80226E792D6E01E77B598F2BB1FCE7F2DD441185C07CEF0573FBFB9876B99FE811486F6F5D499E6114FC0724A67F8D71D2A897A7EB34
|
||||
``
|
||||
|
||||
struct SecuredMessage {
|
||||
uint8 protocol_version: 1
|
||||
uint8 security_profile: 1
|
||||
HeaderField<259> header_fields {
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: signer_info (128)
|
||||
struct SignerInfo signer {
|
||||
SignerInfoType type: certificate (2)
|
||||
struct Certificate certificate {
|
||||
uint8 version: 1
|
||||
SignerInfo<9> signer_info_v1 {
|
||||
struct SignerInfo {
|
||||
SignerInfoType type: certificate_digest_with_sha256 (1)
|
||||
HashedId8 digest: A8ED6DF65B0E6D6A
|
||||
}
|
||||
}
|
||||
struct SubjectInfo subject_info {
|
||||
SubjectType subject_type: authorization_ticket (1)
|
||||
opaque<0> subject_name:
|
||||
}
|
||||
SubjectAttribute<148> subject_attributes {
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: verification_key (0)
|
||||
struct PublicKey key {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EccPoint public_key {
|
||||
EccPointType type: uncompressed (4)
|
||||
opaque[32] x: 18929DB6A9E452223062C52028E956BF9874E0A40D21D5F9F56564F39C5DD187
|
||||
opaque[32] y: C922F2E5F0630373879A43393373B9F6205BF01FBD9C1F113165C291C376F535
|
||||
}
|
||||
}
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: encryption_key (1)
|
||||
struct PublicKey key {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EccPoint public_key {
|
||||
EccPointType type: uncompressed (4)
|
||||
opaque[32] x: EABA91A915D81807E910FD292D99DF8B401EED88CF7F031412D5ED9905F99964
|
||||
opaque[32] y: 69798C412FC8F7237A3AB3469795E2DEF5E1B783EA4F6B6A2359D21772B2EA9D
|
||||
}
|
||||
}
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: assurance_level (2)
|
||||
SubjectAssurance assurance_level: assurance level = 0, confidence = 0 (bitmask = 0)
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: its_aid_ssp_list (33)
|
||||
ItsAidSsp<10> its_aid_ssp_list {
|
||||
struct ItsAidSsp {
|
||||
IntX its_aid: 16512
|
||||
opaque<1> service_specific_permissions: 01
|
||||
}
|
||||
struct ItsAidSsp {
|
||||
IntX its_aid: 16513
|
||||
opaque<1> service_specific_permissions: 01
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ValidityRestriction<15> validity_restrictions {
|
||||
struct ValidityRestriction {
|
||||
ValidityRestrictionType type: time_start_and_end (1)
|
||||
Time32 start_validity: 2015-02-12 00:00:00 UTC
|
||||
Time32 end_validity: 2015-02-25 23:59:59 UTC
|
||||
}
|
||||
struct ValidityRestriction {
|
||||
ValidityRestrictionType type: region (3)
|
||||
struct GeographicRegion region {
|
||||
RegionType region_type: id (4)
|
||||
struct IdentifiedRegion id_region {
|
||||
RegionDictionary region_dictionary: un_stats (1)
|
||||
uint16 region_identifier: 150
|
||||
IntX local_region: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct Signature {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EcdsaSignature ecdsa_signature {
|
||||
struct EccPoint R {
|
||||
EccPointType type: x_coordinate_only (0)
|
||||
opaque[32] x: 4B2E6D0D0EE9BC4AD9CD087B601E9AF06031995443D652763455FBB794B33982
|
||||
}
|
||||
opaque[32] s: 889260740EF64CFA8C6808A58F98E06CE42A1E9C22A0785D7242647F7895ABFC
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: generation_time (0)
|
||||
Time64 generation_time: 2015-02-20 10:36:37.663 UTC
|
||||
}
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: message_type (5)
|
||||
uint16 message_type: 2
|
||||
}
|
||||
}
|
||||
Payload<30> payload_fields {
|
||||
struct Payload {
|
||||
PayloadType type: signed (1)
|
||||
opaque<28> data: 983E690E5F6D755BD4871578A9427E7BC383903DC7DA3B5603840136
|
||||
}
|
||||
}
|
||||
TrailerField<67> trailer_fields {
|
||||
struct TrailerField {
|
||||
TrailerFieldType type: signature (1)
|
||||
struct Signature signature {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EcdsaSignature ecdsa_signature {
|
||||
struct EccPoint R {
|
||||
EccPointType type: x_coordinate_only (0)
|
||||
opaque[32] x: FE8566BEA87B39E6411F80226E792D6E01E77B598F2BB1FCE7F2DD441185C07C
|
||||
}
|
||||
opaque[32] s: EF0573FBFB9876B99FE811486F6F5D499E6114FC0724A67F8D71D2A897A7EB34
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## SecuredMessage/v1 (2)
|
||||
|
||||
``
|
||||
010181038002010901A8ED6DF65B0E6D6A01008094000004C4EC137145DD4F450145DE530CCA36E73AB3D87FC8275847CDAD8248C1CD20879BD6A8CB54EA9E05D3B41376CE2F24789AEF82836CA818D568ADF4A140E96E48010004D6C268EE68B5B8B387B2312B7E1D21CE0C366D251A32431508B96EB6A3479CCF96A8738F30ED451F00DA8DDE84367C7EB16727D14FF14F5DD8F9791FE0A12A640200210AC040800101C0408101010F01099EB20109B1270003040100960000001EB035FE8E51DCDD8558DE0BE9B87895B36B420583A5C6B2B8B2EAB7F3D3C99163638FA025A0033D4BD80BBA02B8E3DE1B55766459D494677AF24917E51B80AC0000009373CC5F22C8050002220120F29384759027349075829034707ABABABABABAABAB98437985739845783974954301000081E7CDB6D2C741C1700822305C39E8E809622AF9FCA1C0786F762D08E80580C42F1FCC1D5499577210834C390BB4613E102DECB14F575A2820743DC9A66BBD7A
|
||||
``
|
||||
|
||||
struct SecuredMessage {
|
||||
uint8 protocol_version: 1
|
||||
uint8 security_profile: 1
|
||||
HeaderField<259> header_fields {
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: signer_info (128)
|
||||
struct SignerInfo signer {
|
||||
SignerInfoType type: certificate (2)
|
||||
struct Certificate certificate {
|
||||
uint8 version: 1
|
||||
SignerInfo<9> signer_info_v1 {
|
||||
struct SignerInfo {
|
||||
SignerInfoType type: certificate_digest_with_sha256 (1)
|
||||
HashedId8 digest: A8ED6DF65B0E6D6A
|
||||
}
|
||||
}
|
||||
struct SubjectInfo subject_info {
|
||||
SubjectType subject_type: authorization_ticket (1)
|
||||
opaque<0> subject_name:
|
||||
}
|
||||
SubjectAttribute<148> subject_attributes {
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: verification_key (0)
|
||||
struct PublicKey key {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EccPoint public_key {
|
||||
EccPointType type: uncompressed (4)
|
||||
opaque[32] x: C4EC137145DD4F450145DE530CCA36E73AB3D87FC8275847CDAD8248C1CD2087
|
||||
opaque[32] y: 9BD6A8CB54EA9E05D3B41376CE2F24789AEF82836CA818D568ADF4A140E96E48
|
||||
}
|
||||
}
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: encryption_key (1)
|
||||
struct PublicKey key {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EccPoint public_key {
|
||||
EccPointType type: uncompressed (4)
|
||||
opaque[32] x: D6C268EE68B5B8B387B2312B7E1D21CE0C366D251A32431508B96EB6A3479CCF
|
||||
opaque[32] y: 96A8738F30ED451F00DA8DDE84367C7EB16727D14FF14F5DD8F9791FE0A12A64
|
||||
}
|
||||
}
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: assurance_level (2)
|
||||
SubjectAssurance assurance_level: assurance level = 0, confidence = 0 (bitmask = 0)
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: its_aid_ssp_list (33)
|
||||
ItsAidSsp<10> its_aid_ssp_list {
|
||||
struct ItsAidSsp {
|
||||
IntX its_aid: 16512
|
||||
opaque<1> service_specific_permissions: 01
|
||||
}
|
||||
struct ItsAidSsp {
|
||||
IntX its_aid: 16513
|
||||
opaque<1> service_specific_permissions: 01
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ValidityRestriction<15> validity_restrictions {
|
||||
struct ValidityRestriction {
|
||||
ValidityRestrictionType type: time_start_and_end (1)
|
||||
Time32 start_validity: 2015-02-12 00:00:00 UTC
|
||||
Time32 end_validity: 2015-02-25 23:59:59 UTC
|
||||
}
|
||||
struct ValidityRestriction {
|
||||
ValidityRestrictionType type: region (3)
|
||||
struct GeographicRegion region {
|
||||
RegionType region_type: id (4)
|
||||
struct IdentifiedRegion id_region {
|
||||
RegionDictionary region_dictionary: un_stats (1)
|
||||
uint16 region_identifier: 150
|
||||
IntX local_region: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct Signature {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EcdsaSignature ecdsa_signature {
|
||||
struct EccPoint R {
|
||||
EccPointType type: x_coordinate_only (0)
|
||||
opaque[32] x: 1EB035FE8E51DCDD8558DE0BE9B87895B36B420583A5C6B2B8B2EAB7F3D3C991
|
||||
}
|
||||
opaque[32] s: 63638FA025A0033D4BD80BBA02B8E3DE1B55766459D494677AF24917E51B80AC
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: generation_time (0)
|
||||
Time64 generation_time: 2015-02-20 10:52:38.309 UTC
|
||||
}
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: message_type (5)
|
||||
uint16 message_type: 2
|
||||
}
|
||||
}
|
||||
Payload<34> payload_fields {
|
||||
struct Payload {
|
||||
PayloadType type: signed (1)
|
||||
opaque<32> data: F29384759027349075829034707ABABABABABAABAB9843798573984578397495
|
||||
}
|
||||
}
|
||||
TrailerField<67> trailer_fields {
|
||||
struct TrailerField {
|
||||
TrailerFieldType type: signature (1)
|
||||
struct Signature signature {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EcdsaSignature ecdsa_signature {
|
||||
struct EccPoint R {
|
||||
EccPointType type: x_coordinate_only (0)
|
||||
opaque[32] x: 81E7CDB6D2C741C1700822305C39E8E809622AF9FCA1C0786F762D08E80580C4
|
||||
}
|
||||
opaque[32] s: 2F1FCC1D5499577210834C390BB4613E102DECB14F575A2820743DC9A66BBD7A
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## SecuredMessage/v1 (3)
|
||||
|
||||
``
|
||||
010181038002010901A8ED6DF65B0E6D6A010080940000040209B0434163CCBAFDD34A45333E418FB96C05BBE0E7E1D755D40D0B4BBE8DA508EC2F2723B7ADF0F27C39F3AECFF0783C196F9961F8821E6294375D9294CD6A01000452113CE698DB081491675DF8FFE81C23EA5D0071B2D2BF0E0DA4ADA0CDA58259CA5D999200B6565E194EDAB8BD3DCA863F2DDF39C13E7A0375ECE2566C5EB8C60200210AC040800101C0408101010F01099EB20109B1270003040100960000008DA1F3F9F35E04C3DE77D7438988A8D57EBE44DAA021A4269E297C177C9CFE458E128EC290785D6631961625020943B6D87DAA54919A98F7865709929A7C6E480000009373CF482D400500020A01080123456789ABCDEF43010000371423BBA0902D8AF2FB2226D73A7781D4D6B6772650A8BEE5A1AF198CEDABA2C9BF57540C629E6A1E629B8812AEBDDDBCAF472F6586F16C14B3DEFBE9B6ADB2
|
||||
``
|
||||
|
||||
struct SecuredMessage {
|
||||
uint8 protocol_version: 1
|
||||
uint8 security_profile: 1
|
||||
HeaderField<259> header_fields {
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: signer_info (128)
|
||||
struct SignerInfo signer {
|
||||
SignerInfoType type: certificate (2)
|
||||
struct Certificate certificate {
|
||||
uint8 version: 1
|
||||
SignerInfo<9> signer_info_v1 {
|
||||
struct SignerInfo {
|
||||
SignerInfoType type: certificate_digest_with_sha256 (1)
|
||||
HashedId8 digest: A8ED6DF65B0E6D6A
|
||||
}
|
||||
}
|
||||
struct SubjectInfo subject_info {
|
||||
SubjectType subject_type: authorization_ticket (1)
|
||||
opaque<0> subject_name:
|
||||
}
|
||||
SubjectAttribute<148> subject_attributes {
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: verification_key (0)
|
||||
struct PublicKey key {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EccPoint public_key {
|
||||
EccPointType type: uncompressed (4)
|
||||
opaque[32] x: 0209B0434163CCBAFDD34A45333E418FB96C05BBE0E7E1D755D40D0B4BBE8DA5
|
||||
opaque[32] y: 08EC2F2723B7ADF0F27C39F3AECFF0783C196F9961F8821E6294375D9294CD6A
|
||||
}
|
||||
}
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: encryption_key (1)
|
||||
struct PublicKey key {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EccPoint public_key {
|
||||
EccPointType type: uncompressed (4)
|
||||
opaque[32] x: 52113CE698DB081491675DF8FFE81C23EA5D0071B2D2BF0E0DA4ADA0CDA58259
|
||||
opaque[32] y: CA5D999200B6565E194EDAB8BD3DCA863F2DDF39C13E7A0375ECE2566C5EB8C6
|
||||
}
|
||||
}
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: assurance_level (2)
|
||||
SubjectAssurance assurance_level: assurance level = 0, confidence = 0 (bitmask = 0)
|
||||
}
|
||||
struct SubjectAttribute {
|
||||
SubjectAttributeType type: its_aid_ssp_list (33)
|
||||
ItsAidSsp<10> its_aid_ssp_list {
|
||||
struct ItsAidSsp {
|
||||
IntX its_aid: 16512
|
||||
opaque<1> service_specific_permissions: 01
|
||||
}
|
||||
struct ItsAidSsp {
|
||||
IntX its_aid: 16513
|
||||
opaque<1> service_specific_permissions: 01
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ValidityRestriction<15> validity_restrictions {
|
||||
struct ValidityRestriction {
|
||||
ValidityRestrictionType type: time_start_and_end (1)
|
||||
Time32 start_validity: 2015-02-12 00:00:00 UTC
|
||||
Time32 end_validity: 2015-02-25 23:59:59 UTC
|
||||
}
|
||||
struct ValidityRestriction {
|
||||
ValidityRestrictionType type: region (3)
|
||||
struct GeographicRegion region {
|
||||
RegionType region_type: id (4)
|
||||
struct IdentifiedRegion id_region {
|
||||
RegionDictionary region_dictionary: un_stats (1)
|
||||
uint16 region_identifier: 150
|
||||
IntX local_region: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct Signature {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EcdsaSignature ecdsa_signature {
|
||||
struct EccPoint R {
|
||||
EccPointType type: x_coordinate_only (0)
|
||||
opaque[32] x: 8DA1F3F9F35E04C3DE77D7438988A8D57EBE44DAA021A4269E297C177C9CFE45
|
||||
}
|
||||
opaque[32] s: 8E128EC290785D6631961625020943B6D87DAA54919A98F7865709929A7C6E48
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: generation_time (0)
|
||||
Time64 generation_time: 2015-02-20 10:53:27.136 UTC
|
||||
}
|
||||
struct HeaderField {
|
||||
HeaderFieldType type: message_type (5)
|
||||
uint16 message_type: 2
|
||||
}
|
||||
}
|
||||
Payload<10> payload_fields {
|
||||
struct Payload {
|
||||
PayloadType type: signed (1)
|
||||
opaque<8> data: 0123456789ABCDEF
|
||||
}
|
||||
}
|
||||
TrailerField<67> trailer_fields {
|
||||
struct TrailerField {
|
||||
TrailerFieldType type: signature (1)
|
||||
struct Signature signature {
|
||||
PublicKeyAlgorithm algorithm: ecdsa_nistp256_with_sha256 (0)
|
||||
struct EcdsaSignature ecdsa_signature {
|
||||
struct EccPoint R {
|
||||
EccPointType type: x_coordinate_only (0)
|
||||
opaque[32] x: 371423BBA0902D8AF2FB2226D73A7781D4D6B6772650A8BEE5A1AF198CEDABA2
|
||||
}
|
||||
opaque[32] s: C9BF57540C629E6A1E629B8812AEBDDDBCAF472F6586F16C14B3DEFBE9B6ADB2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
+5
@@ -0,0 +1,5 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgU7d+uEguPBrTNnDA
|
||||
xsRrwDaQ1ABZ08u1gbM2r4qYk/ShRANCAAQchQ3HRWMpPLDz5V7aexDstOl0b4Nv
|
||||
hHaWwx7oaE43dijxZ/tkznt5pgIGKqwRf1lrrHfHHNb0yqcIeszNq5Gr
|
||||
-----END PRIVATE KEY-----
|
||||
@@ -0,0 +1,212 @@
|
||||
#include <vanetza/security/backend.hpp>
|
||||
#ifdef VANETZA_WITH_OPENSSL
|
||||
#include <vanetza/security/backend_openssl.hpp>
|
||||
#endif
|
||||
#ifdef VANETZA_WITH_CRYPTOPP
|
||||
#include <vanetza/security/backend_cryptopp.hpp>
|
||||
#endif
|
||||
#include <gtest/gtest.h>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
#include "serialization.hpp"
|
||||
|
||||
using namespace vanetza;
|
||||
using namespace vanetza::security;
|
||||
|
||||
class BackendTest : public ::testing::TestWithParam<std::string>
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
backend = create_backend(GetParam());
|
||||
ASSERT_NE(backend.get(), nullptr);
|
||||
}
|
||||
|
||||
ByteBuffer buffer_from_string(const std::string& s)
|
||||
{
|
||||
ByteBuffer b;
|
||||
std::copy(s.begin(), s.end(), std::back_inserter(b));
|
||||
return b;
|
||||
}
|
||||
|
||||
std::unique_ptr<Backend> backend;
|
||||
};
|
||||
|
||||
TEST_P(BackendTest, sha256sum)
|
||||
{
|
||||
const ByteBuffer input = buffer_from_string("All your ITS stations are belong to us");
|
||||
const ByteBuffer expected = buffer_from_hexstring("dcb61edffc5f536aeb80c7e61fc943239a28b16edad52f4a0bc6e83f2df0fdc8");
|
||||
EXPECT_EQ(backend->calculate_hash(HashAlgorithm::SHA256, input), expected);
|
||||
}
|
||||
|
||||
TEST_P(BackendTest, sha384sum)
|
||||
{
|
||||
const ByteBuffer input = buffer_from_string("All your ITS stations are belong to us");
|
||||
const ByteBuffer expected = buffer_from_hexstring("4dfdccefa8612f3285aa4e909c644eb841e0347132465a733cbc99b46437d9ea0886c96a25fd9d51389585431b069651");
|
||||
EXPECT_EQ(backend->calculate_hash(HashAlgorithm::SHA384, input), expected);
|
||||
}
|
||||
|
||||
TEST_P(BackendTest, sign_and_verify_nistp256)
|
||||
{
|
||||
const ByteBuffer digest = buffer_from_hexstring("33e57499804cebc409407d6bf4ade70b49b58d0d4bae9ca57d507b260a676685");
|
||||
PrivateKey private_key;
|
||||
private_key.type = KeyType::NistP256;
|
||||
private_key.key = buffer_from_hexstring("f4ce0e4b48829aae85abd2124a2574dba44388eea94ebd373f9203ad39719a30");
|
||||
PublicKey public_key;
|
||||
public_key.type = KeyType::NistP256;
|
||||
public_key.compression = KeyCompression::NoCompression;
|
||||
public_key.x = buffer_from_hexstring("8e65e0ab7d4cd66860be693e29bf747fe796ebfe3942416b1f9c7ecf7fdb5797");
|
||||
public_key.y = buffer_from_hexstring("49ce27c4acfc53c34867420a35b999e7deb3aeabec388f0d08d7fe0edf54ba62");
|
||||
Signature sig = backend->sign_digest(private_key, digest);
|
||||
EXPECT_TRUE(backend->verify_digest(public_key, digest, sig));
|
||||
}
|
||||
|
||||
TEST_P(BackendTest, sign_and_verify_brainpoolp256r1)
|
||||
{
|
||||
const ByteBuffer digest = buffer_from_hexstring("33e57499804cebc409407d6bf4ade70b49b58d0d4bae9ca57d507b260a676685");
|
||||
PrivateKey private_key;
|
||||
private_key.type = KeyType::BrainpoolP256r1;
|
||||
private_key.key = buffer_from_hexstring("38f72493269d99c77b6e6488de05aea60bc707a35b464b0286665463ecc2883d");
|
||||
PublicKey public_key;
|
||||
public_key.type = KeyType::BrainpoolP256r1;
|
||||
public_key.compression = KeyCompression::NoCompression;
|
||||
public_key.x = buffer_from_hexstring("2cdb98f1053bb69fb4879101946d0a49aba965c8c4ffad5ef64356b0cff0bcf8");
|
||||
public_key.y = buffer_from_hexstring("17828cc0e33f68cbf9cb1d5419597464aef62efea8503676403177a9074cf86e");
|
||||
Signature sig = backend->sign_digest(private_key, digest);
|
||||
EXPECT_TRUE(backend->verify_digest(public_key, digest, sig));
|
||||
}
|
||||
|
||||
TEST_P(BackendTest, sign_and_verify_brainpoolp384r1)
|
||||
{
|
||||
const ByteBuffer digest = buffer_from_hexstring("33e57499804cebc409407d6bf4ade70b49b58d0d4bae9ca57d507b260a676685");
|
||||
PrivateKey private_key;
|
||||
private_key.type = KeyType::BrainpoolP384r1;
|
||||
private_key.key = buffer_from_hexstring("29267526c4511103f094f4d9ef1e8a57e2e6429642188939b756fe6738db49744363ea4081601e5acebe091d258bcedd");
|
||||
PublicKey public_key;
|
||||
public_key.type = KeyType::BrainpoolP384r1;
|
||||
public_key.compression = KeyCompression::NoCompression;
|
||||
public_key.x = buffer_from_hexstring("271dd92e47814e1f6b39c29488a80a720ae18153597380f41b2079cca4d92373b058850af280e920b10993bf925bdc4a");
|
||||
public_key.y = buffer_from_hexstring("388b971cb0ad878842de6825e5f1a6e359c1c4cddd65593781af6179fa743c21a056577de9cca2631e107edc28dc2ef7");
|
||||
Signature sig = backend->sign_digest(private_key, digest);
|
||||
EXPECT_TRUE(backend->verify_digest(public_key, digest, sig));
|
||||
}
|
||||
|
||||
TEST_P(BackendTest, verify_nistp256)
|
||||
{
|
||||
Signature sig;
|
||||
sig.type = KeyType::NistP256;
|
||||
sig.r = buffer_from_hexstring("de99edf601b3682d90e6458ab0e5588fcdef54d679852e38fc85e7e16ad02074");
|
||||
sig.s = buffer_from_hexstring("552962f3572898a05dd99b179124d6e1d1a672a3f407083b59a1fe2dc62e8161");
|
||||
|
||||
PublicKey public_key;
|
||||
public_key.type = KeyType::NistP256;
|
||||
public_key.compression = KeyCompression::NoCompression;
|
||||
public_key.x = buffer_from_hexstring("8e65e0ab7d4cd66860be693e29bf747fe796ebfe3942416b1f9c7ecf7fdb5797");
|
||||
public_key.y = buffer_from_hexstring("49ce27c4acfc53c34867420a35b999e7deb3aeabec388f0d08d7fe0edf54ba62");
|
||||
|
||||
ByteBuffer digest = buffer_from_hexstring("33e57499804cebc409407d6bf4ade70b49b58d0d4bae9ca57d507b260a676685");
|
||||
EXPECT_TRUE(backend->verify_digest(public_key, digest, sig));
|
||||
|
||||
ByteBuffer false_digest = digest;
|
||||
false_digest[0] ^= 0x01;
|
||||
EXPECT_FALSE(backend->verify_digest(public_key, false_digest, sig));
|
||||
}
|
||||
|
||||
TEST_P(BackendTest, verify_brainpoolp256r1)
|
||||
{
|
||||
Signature sig;
|
||||
sig.type = KeyType::BrainpoolP256r1;
|
||||
sig.r = buffer_from_hexstring("28c9b30e37b05388c2f04be921dbc79480d972f1c782ff8c5ade76c40e136d5a");
|
||||
sig.s = buffer_from_hexstring("77cf1e91d0204d2a58847b543df055605ff968cd6120c4ac9c751be08d782518");
|
||||
|
||||
PublicKey public_key;
|
||||
public_key.type = KeyType::BrainpoolP256r1;
|
||||
public_key.compression = KeyCompression::NoCompression;
|
||||
public_key.x = buffer_from_hexstring("2cdb98f1053bb69fb4879101946d0a49aba965c8c4ffad5ef64356b0cff0bcf8");
|
||||
public_key.y = buffer_from_hexstring("17828cc0e33f68cbf9cb1d5419597464aef62efea8503676403177a9074cf86e");
|
||||
|
||||
ByteBuffer digest = buffer_from_hexstring("33e57499804cebc409407d6bf4ade70b49b58d0d4bae9ca57d507b260a676685");
|
||||
EXPECT_TRUE(backend->verify_digest(public_key, digest, sig));
|
||||
|
||||
ByteBuffer false_digest = digest;
|
||||
false_digest[0] ^= 0x01;
|
||||
EXPECT_FALSE(backend->verify_digest(public_key, false_digest, sig));
|
||||
}
|
||||
|
||||
TEST_P(BackendTest, verify_brainpoolp384r1)
|
||||
{
|
||||
Signature sig;
|
||||
sig.type = KeyType::BrainpoolP384r1;
|
||||
sig.r = buffer_from_hexstring("2b51c205ac9598ff245cbed8df5c8f3e1d9d3c7d6901a08d45e790784457900a84c903167f5d6b124ee193881ff93950");
|
||||
sig.s = buffer_from_hexstring("81c06d7f5fdf4e825b3cd8545956e6b1b587be4dcc66ce3007ca8b6966f90bc94efc8d88c70b5bd3bd44739ec34da54f");
|
||||
|
||||
PublicKey public_key;
|
||||
public_key.type = KeyType::BrainpoolP384r1;
|
||||
public_key.compression = KeyCompression::NoCompression;
|
||||
public_key.x = buffer_from_hexstring("271dd92e47814e1f6b39c29488a80a720ae18153597380f41b2079cca4d92373b058850af280e920b10993bf925bdc4a");
|
||||
public_key.y = buffer_from_hexstring("388b971cb0ad878842de6825e5f1a6e359c1c4cddd65593781af6179fa743c21a056577de9cca2631e107edc28dc2ef7");
|
||||
|
||||
ByteBuffer digest = buffer_from_hexstring("33e57499804cebc409407d6bf4ade70b49b58d0d4bae9ca57d507b260a676685");
|
||||
EXPECT_TRUE(backend->verify_digest(public_key, digest, sig));
|
||||
|
||||
ByteBuffer false_digest = digest;
|
||||
false_digest[0] ^= 0x01;
|
||||
EXPECT_FALSE(backend->verify_digest(public_key, false_digest, sig));
|
||||
}
|
||||
|
||||
#if defined VANETZA_WITH_OPENSSL || defined VANETZA_WITH_CRYPTOPP
|
||||
namespace
|
||||
{
|
||||
|
||||
// Check that every built backend derives the known public key from the private key.
|
||||
void check_derive_public_key(KeyType type, const char* priv_hex, const char* x_hex, const char* y_hex)
|
||||
{
|
||||
PrivateKey priv;
|
||||
priv.type = type;
|
||||
priv.key = buffer_from_hexstring(priv_hex);
|
||||
const ByteBuffer x = buffer_from_hexstring(x_hex);
|
||||
const ByteBuffer y = buffer_from_hexstring(y_hex);
|
||||
|
||||
#ifdef VANETZA_WITH_OPENSSL
|
||||
EXPECT_EQ(openssl::derive_public_key(priv).x, x);
|
||||
EXPECT_EQ(openssl::derive_public_key(priv).y, y);
|
||||
#endif
|
||||
#ifdef VANETZA_WITH_CRYPTOPP
|
||||
EXPECT_EQ(cryptopp::derive_public_key(priv).x, x);
|
||||
EXPECT_EQ(cryptopp::derive_public_key(priv).y, y);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Backend, derive_public_key_nistp256)
|
||||
{
|
||||
check_derive_public_key(KeyType::NistP256,
|
||||
"f4ce0e4b48829aae85abd2124a2574dba44388eea94ebd373f9203ad39719a30",
|
||||
"8e65e0ab7d4cd66860be693e29bf747fe796ebfe3942416b1f9c7ecf7fdb5797",
|
||||
"49ce27c4acfc53c34867420a35b999e7deb3aeabec388f0d08d7fe0edf54ba62");
|
||||
}
|
||||
|
||||
TEST(Backend, derive_public_key_brainpoolp384r1)
|
||||
{
|
||||
check_derive_public_key(KeyType::BrainpoolP384r1,
|
||||
"29267526c4511103f094f4d9ef1e8a57e2e6429642188939b756fe6738db49744363ea4081601e5acebe091d258bcedd",
|
||||
"271dd92e47814e1f6b39c29488a80a720ae18153597380f41b2079cca4d92373b058850af280e920b10993bf925bdc4a",
|
||||
"388b971cb0ad878842de6825e5f1a6e359c1c4cddd65593781af6179fa743c21a056577de9cca2631e107edc28dc2ef7");
|
||||
}
|
||||
#endif /* VANETZA_WITH_OPENSSL || VANETZA_WITH_CRYPTOPP */
|
||||
|
||||
std::list<std::string> available_backends()
|
||||
{
|
||||
std::list<std::string> backends;
|
||||
#ifdef VANETZA_WITH_OPENSSL
|
||||
backends.emplace_back("OpenSSL");
|
||||
#endif
|
||||
#ifdef VANETZA_WITH_CRYPTOPP
|
||||
backends.emplace_back("CryptoPP");
|
||||
#endif
|
||||
return backends;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(BackendImplementations, BackendTest, ::testing::ValuesIn(available_backends()));
|
||||
@@ -0,0 +1,133 @@
|
||||
#include <vanetza/security/cam_ssp.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
|
||||
using vanetza::ByteBuffer;
|
||||
using namespace vanetza::security;
|
||||
|
||||
static const std::set<CamPermission> all {{
|
||||
CamPermission::CEN_DSRC_Tolling_Zone,
|
||||
CamPermission::Public_Transport,
|
||||
CamPermission::Special_Transport,
|
||||
CamPermission::Dangerous_Goods,
|
||||
CamPermission::Roadwork,
|
||||
CamPermission::Rescue,
|
||||
CamPermission::Emergency,
|
||||
CamPermission::Safety_Car,
|
||||
CamPermission::Closed_Lanes,
|
||||
CamPermission::Request_For_Right_Of_Way,
|
||||
CamPermission::Request_For_Free_Crossing_At_Traffic_Light,
|
||||
CamPermission::No_Passing,
|
||||
CamPermission::No_Passing_For_Trucks,
|
||||
CamPermission::Speed_Limit,
|
||||
}};
|
||||
|
||||
TEST(CamSsp, empty)
|
||||
{
|
||||
CamPermissions empty;
|
||||
EXPECT_TRUE(std::none_of(all.begin(), all.end(), [empty](CamPermission cp) { return empty.has(cp); }));
|
||||
EXPECT_TRUE(empty.none());
|
||||
}
|
||||
|
||||
TEST(CamSsp, single)
|
||||
{
|
||||
CamPermissions single(CamPermission::Safety_Car);
|
||||
EXPECT_FALSE(single.none());
|
||||
EXPECT_TRUE(single.has(CamPermission::Safety_Car));
|
||||
|
||||
std::set<CamPermission> rest = all;
|
||||
rest.erase(CamPermission::Safety_Car);
|
||||
EXPECT_TRUE(std::none_of(rest.begin(), rest.end(), [single](CamPermission cp) { return single.has(cp); }));
|
||||
}
|
||||
|
||||
TEST(CamSsp, multiple)
|
||||
{
|
||||
CamPermissions multiple({CamPermission::Roadwork, CamPermission::Public_Transport, CamPermission::Speed_Limit});
|
||||
EXPECT_TRUE(multiple.has(CamPermission::Roadwork));
|
||||
EXPECT_TRUE(multiple.has(CamPermission::Public_Transport));
|
||||
EXPECT_TRUE(multiple.has(CamPermission::Speed_Limit));
|
||||
EXPECT_TRUE(multiple.has({CamPermission::Roadwork, CamPermission::Public_Transport, CamPermission::Speed_Limit}));
|
||||
}
|
||||
|
||||
TEST(CamSsp, manipulation)
|
||||
{
|
||||
CamPermissions ssp({CamPermission::No_Passing, CamPermission::Rescue});
|
||||
EXPECT_TRUE(ssp.has({CamPermission::Rescue, CamPermission::No_Passing}));
|
||||
ssp.remove(CamPermission::Rescue);
|
||||
EXPECT_FALSE(ssp.has({CamPermission::Rescue, CamPermission::No_Passing}));
|
||||
EXPECT_TRUE(ssp.has(CamPermission::No_Passing));
|
||||
|
||||
ssp.remove(CamPermission::Speed_Limit);
|
||||
EXPECT_FALSE(ssp.has(CamPermission::Speed_Limit));
|
||||
EXPECT_TRUE(ssp.has(CamPermission::No_Passing));
|
||||
|
||||
ssp.add(CamPermission::Closed_Lanes);
|
||||
EXPECT_TRUE(ssp.has({CamPermission::Closed_Lanes, CamPermission::No_Passing}));
|
||||
ssp.remove(CamPermission::No_Passing).remove(CamPermission::Closed_Lanes);
|
||||
EXPECT_TRUE(ssp.none());
|
||||
}
|
||||
|
||||
TEST(CamSsp, serialization)
|
||||
{
|
||||
CamPermissions ssp;
|
||||
const auto empty_ssp_buffer = ssp.encode();
|
||||
EXPECT_EQ(ByteBuffer({0x01, 0x00, 0x00}), empty_ssp_buffer);
|
||||
|
||||
ssp.add(CamPermission::CEN_DSRC_Tolling_Zone);
|
||||
const auto dsrc_ssp_buffer = ssp.encode();
|
||||
EXPECT_EQ(ByteBuffer({0x01, 0x80, 0x00}), dsrc_ssp_buffer);
|
||||
|
||||
ssp.add(CamPermission::Speed_Limit);
|
||||
const auto extremes_ssp_buffer = ssp.encode();
|
||||
EXPECT_EQ(ByteBuffer({0x01, 0x80, 0x04}), extremes_ssp_buffer);
|
||||
|
||||
CamPermissions decoded = CamPermissions::decode(extremes_ssp_buffer);
|
||||
EXPECT_EQ(extremes_ssp_buffer, decoded.encode());
|
||||
EXPECT_TRUE(decoded.has({CamPermission::Speed_Limit, CamPermission::CEN_DSRC_Tolling_Zone}));
|
||||
decoded.remove(CamPermission::Speed_Limit).remove(CamPermission::CEN_DSRC_Tolling_Zone);
|
||||
EXPECT_TRUE(decoded.none());
|
||||
|
||||
CamPermissions decoded_empty = CamPermissions::decode(ByteBuffer {});
|
||||
EXPECT_TRUE(decoded_empty.none());
|
||||
|
||||
CamPermissions decoded_testing = CamPermissions::decode(ByteBuffer {0x00});
|
||||
EXPECT_TRUE(decoded_testing.none());
|
||||
|
||||
CamPermissions decoded_version = CamPermissions::decode(ByteBuffer {0xff, 0x80, 0x30});
|
||||
EXPECT_TRUE(decoded_version.none());
|
||||
|
||||
CamPermissions decoded_short = CamPermissions::decode(ByteBuffer {0x01, 0x40});
|
||||
EXPECT_TRUE(decoded_short.none());
|
||||
|
||||
CamPermissions decoded_long = CamPermissions::decode(ByteBuffer {0x01, 0x80, 0x04, 0x00});
|
||||
EXPECT_TRUE(decoded_long.none());
|
||||
|
||||
CamPermissions decoded_reserved = CamPermissions::decode(ByteBuffer {0x01, 0x02, 0x07});
|
||||
EXPECT_FALSE(decoded_reserved.none());
|
||||
EXPECT_TRUE(decoded_reserved.has(CamPermission::Speed_Limit));
|
||||
decoded_reserved.remove(CamPermission::Speed_Limit).remove(CamPermission::Emergency);
|
||||
EXPECT_TRUE(std::none_of(all.begin(), all.end(),
|
||||
[decoded_reserved](CamPermission cp) { return decoded_reserved.has(cp); }));
|
||||
EXPECT_FALSE(decoded_reserved.none());
|
||||
}
|
||||
|
||||
TEST(CamSsp, permissions)
|
||||
{
|
||||
CamPermissions ssp { CamPermission::No_Passing, CamPermission::Speed_Limit };
|
||||
std::set<CamPermission> expected { CamPermission::No_Passing, CamPermission::Speed_Limit };
|
||||
EXPECT_EQ(expected, ssp.permissions());
|
||||
|
||||
// works also for reserved bits
|
||||
const CamPermission reserved = static_cast<CamPermission>(0x0100);
|
||||
ssp.add(reserved);
|
||||
expected.insert(reserved);
|
||||
ASSERT_EQ(3, expected.size());
|
||||
EXPECT_EQ(expected, ssp.permissions());
|
||||
}
|
||||
|
||||
TEST(CamSsp, stringify)
|
||||
{
|
||||
EXPECT_EQ("Safety Car", stringify(CamPermission::Safety_Car));
|
||||
EXPECT_EQ("Reserved (0x0200)", stringify(static_cast<CamPermission>(0x0200)));
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/security/v3/certificate.hpp>
|
||||
#include <vanetza/security/v3/certificate_cache.hpp>
|
||||
#include <vanetza/security/sha.hpp>
|
||||
|
||||
using namespace vanetza;
|
||||
using namespace vanetza::security;
|
||||
|
||||
// implicit certificate (IEEE 1609.2 clause 6.4.5) with a dummy reconstruction value
|
||||
inline v3::Certificate fake_implicit_certificate()
|
||||
{
|
||||
v3::Certificate cert;
|
||||
cert->version = 3;
|
||||
cert->type = Vanetza_Security_CertificateType_implicit;
|
||||
cert->issuer.present = Vanetza_Security_IssuerIdentifier_PR_sha256AndDigest;
|
||||
std::array<char, 8> issuer_digest = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
OCTET_STRING_fromBuf(&cert->issuer.choice.sha256AndDigest, issuer_digest.data(), issuer_digest.size());
|
||||
cert->toBeSigned.id.present = Vanetza_Security_CertificateId_PR_none;
|
||||
std::array<char, 3> craca_id = { 0, 0, 0 };
|
||||
OCTET_STRING_fromBuf(&cert->toBeSigned.cracaId, craca_id.data(), craca_id.size());
|
||||
cert->toBeSigned.crlSeries = 0;
|
||||
cert->toBeSigned.validityPeriod.start = 0;
|
||||
cert->toBeSigned.validityPeriod.duration.present = Vanetza_Security_Duration_PR_minutes;
|
||||
cert->toBeSigned.validityPeriod.duration.choice.minutes = 10080;
|
||||
cert->toBeSigned.verifyKeyIndicator.present = Vanetza_Security_VerificationKeyIndicator_PR_reconstructionValue;
|
||||
cert->toBeSigned.verifyKeyIndicator.choice.reconstructionValue.present = Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0;
|
||||
std::array<char, 32> dummy_point {};
|
||||
OCTET_STRING_fromBuf(
|
||||
&cert->toBeSigned.verifyKeyIndicator.choice.reconstructionValue.choice.compressed_y_0,
|
||||
dummy_point.data(), dummy_point.size()
|
||||
);
|
||||
cert.add_app_permission(aid::CA, ByteBuffer({ 1, 0, 0 }));
|
||||
return cert;
|
||||
}
|
||||
|
||||
TEST(CertificateV3, cache)
|
||||
{
|
||||
v3::CertificateCache cache;
|
||||
cache.store(v3::fake_certificate());
|
||||
}
|
||||
|
||||
TEST(CertificateV3, implicit_certificate_digest)
|
||||
{
|
||||
v3::Certificate cert = fake_implicit_certificate();
|
||||
ASSERT_TRUE(v3::is_canonical(*cert));
|
||||
|
||||
// curve of a reconstructed key is unknown without the issuer certificate
|
||||
EXPECT_EQ(KeyType::Unspecified, cert.get_verification_key_type());
|
||||
// ECQV public key reconstruction is not supported
|
||||
EXPECT_FALSE(v3::get_public_key(*cert));
|
||||
|
||||
// IEEE 1609.2 clause 5.3.2: SHA-256 over the canonical encoding
|
||||
const ByteBuffer encoded = cert.encode();
|
||||
const HashedId8 expected = create_hashed_id8(calculate_sha256_digest(encoded.data(), encoded.size()));
|
||||
auto digest = cert.calculate_digest();
|
||||
ASSERT_TRUE(digest);
|
||||
EXPECT_EQ(expected, *digest);
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/common/its_aid.hpp>
|
||||
#include <vanetza/security/decap_service.hpp>
|
||||
#include <vanetza/security/v3/secured_message.hpp>
|
||||
|
||||
#include "printer.hpp"
|
||||
|
||||
using namespace vanetza;
|
||||
using namespace vanetza::security;
|
||||
|
||||
TEST(DecapService, confirm_from_verify_confirm)
|
||||
{
|
||||
v3::SecuredMessage v3_msg = v3::SecuredMessage::with_signed_data();
|
||||
v3_msg.set_payload(ByteBuffer { 0xca, 0xfe });
|
||||
SecuredMessage msg { std::move(v3_msg) };
|
||||
|
||||
const HashedId8 signer { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
|
||||
VerifyConfirm verify;
|
||||
verify.report = VerificationReport::Success;
|
||||
verify.its_aid = aid::CA;
|
||||
verify.permissions = ByteBuffer { 0x01, 0x02 };
|
||||
verify.certificate_validity = CertificateValidity::valid();
|
||||
verify.certificate_id = signer;
|
||||
|
||||
DecapConfirm decap = DecapConfirm::from(std::move(verify), SecuredMessageView { msg });
|
||||
EXPECT_EQ(VerificationReport::Success, decap.report);
|
||||
EXPECT_EQ(aid::CA, decap.its_aid);
|
||||
EXPECT_EQ(ByteBuffer({ 0x01, 0x02 }), decap.permissions);
|
||||
EXPECT_TRUE(decap.certificate_validity);
|
||||
ASSERT_TRUE(decap.certificate_id);
|
||||
EXPECT_EQ(signer, *decap.certificate_id);
|
||||
EXPECT_EQ(2, boost::apply_visitor([](const auto& packet) { return packet.size(); }, decap.plaintext_payload));
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <vanetza/common/its_aid.hpp>
|
||||
#include <vanetza/security/verify_service.hpp>
|
||||
#include <vanetza/security/v3/certificate.hpp>
|
||||
#include <vanetza/security/v3/certificate_cache.hpp>
|
||||
#include <vanetza/security/v3/secured_message.hpp>
|
||||
#include <memory>
|
||||
|
||||
using namespace vanetza;
|
||||
using namespace vanetza::security;
|
||||
|
||||
TEST(DummyVerifyServiceTest, lookup)
|
||||
{
|
||||
std::unique_ptr<VerifyService> dummy { new DummyVerifyService {
|
||||
VerificationReport::Invalid_Timestamp, CertificateValidity::valid() }};
|
||||
|
||||
SecuredMessage message;
|
||||
VerifyRequest req(SecuredMessageView { message });
|
||||
|
||||
auto confirm = dummy->verify(std::move(req));
|
||||
|
||||
EXPECT_EQ(VerificationReport::Invalid_Timestamp, confirm.report);
|
||||
EXPECT_TRUE(confirm.certificate_validity);
|
||||
EXPECT_EQ(0, confirm.its_aid);
|
||||
EXPECT_EQ(vanetza::ByteBuffer({}), confirm.permissions);
|
||||
EXPECT_FALSE(confirm.certificate_id);
|
||||
}
|
||||
|
||||
TEST(DummyVerifyServiceTest, signer_with_full_certificate)
|
||||
{
|
||||
DummyVerifyService dummy { VerificationReport::Success, CertificateValidity::valid() };
|
||||
|
||||
v3::Certificate cert = v3::fake_certificate();
|
||||
auto digest = cert.calculate_digest();
|
||||
ASSERT_TRUE(digest);
|
||||
|
||||
v3::SecuredMessage msg = v3::SecuredMessage::with_signed_data();
|
||||
msg.set_its_aid(aid::CA);
|
||||
msg.set_signer_identifier(cert);
|
||||
|
||||
auto confirm = dummy.verify(VerifyRequest { SecuredMessageView { std::move(msg) } });
|
||||
|
||||
EXPECT_EQ(aid::CA, confirm.its_aid);
|
||||
ASSERT_TRUE(confirm.certificate_id);
|
||||
EXPECT_EQ(*digest, *confirm.certificate_id);
|
||||
EXPECT_EQ(ByteBuffer({ 1, 0, 0 }), confirm.permissions);
|
||||
}
|
||||
|
||||
TEST(DummyVerifyServiceTest, signer_with_digest_no_cache)
|
||||
{
|
||||
DummyVerifyService dummy { VerificationReport::Success, CertificateValidity::valid() };
|
||||
|
||||
HashedId8 digest = {{ 1, 2, 3, 4, 5, 6, 7, 8 }};
|
||||
v3::SecuredMessage msg = v3::SecuredMessage::with_signed_data();
|
||||
msg.set_its_aid(aid::CA);
|
||||
msg.set_signer_identifier(digest);
|
||||
|
||||
auto confirm = dummy.verify(VerifyRequest { SecuredMessageView { std::move(msg) } });
|
||||
|
||||
ASSERT_TRUE(confirm.certificate_id);
|
||||
EXPECT_EQ(digest, *confirm.certificate_id);
|
||||
EXPECT_TRUE(confirm.permissions.empty());
|
||||
}
|
||||
|
||||
TEST(DummyVerifyServiceTest, signer_with_digest_cache_hit)
|
||||
{
|
||||
DummyVerifyService dummy { VerificationReport::Success, CertificateValidity::valid() };
|
||||
|
||||
v3::Certificate cert = v3::fake_certificate();
|
||||
auto digest = cert.calculate_digest();
|
||||
ASSERT_TRUE(digest);
|
||||
|
||||
v3::CertificateCache cache;
|
||||
cache.store(std::move(cert));
|
||||
dummy.use_certificate_cache(&cache);
|
||||
|
||||
v3::SecuredMessage msg = v3::SecuredMessage::with_signed_data();
|
||||
msg.set_its_aid(aid::CA);
|
||||
msg.set_signer_identifier(*digest);
|
||||
|
||||
auto confirm = dummy.verify(VerifyRequest { SecuredMessageView { std::move(msg) } });
|
||||
|
||||
ASSERT_TRUE(confirm.certificate_id);
|
||||
EXPECT_EQ(*digest, *confirm.certificate_id);
|
||||
EXPECT_EQ(ByteBuffer({ 1, 0, 0 }), confirm.permissions);
|
||||
}
|
||||
|
||||
TEST(DummyVerifyServiceTest, signer_with_digest_cache_miss)
|
||||
{
|
||||
DummyVerifyService dummy { VerificationReport::Success, CertificateValidity::valid() };
|
||||
|
||||
v3::Certificate cert = v3::fake_certificate();
|
||||
auto digest = cert.calculate_digest();
|
||||
ASSERT_TRUE(digest);
|
||||
|
||||
v3::CertificateCache cache;
|
||||
// certificate is not added
|
||||
dummy.use_certificate_cache(&cache);
|
||||
|
||||
v3::SecuredMessage msg = v3::SecuredMessage::with_signed_data();
|
||||
msg.set_its_aid(aid::CA);
|
||||
msg.set_signer_identifier(*digest);
|
||||
|
||||
auto confirm = dummy.verify(VerifyRequest { SecuredMessageView { std::move(msg) } });
|
||||
|
||||
ASSERT_TRUE(confirm.certificate_id);
|
||||
EXPECT_EQ(*digest, *confirm.certificate_id);
|
||||
EXPECT_TRUE(confirm.permissions.empty());
|
||||
}
|
||||
|
||||
TEST(DummyVerifyServiceTest, full_certificate_populates_cache)
|
||||
{
|
||||
DummyVerifyService dummy { VerificationReport::Success, CertificateValidity::valid() };
|
||||
|
||||
v3::CertificateCache cache;
|
||||
dummy.use_certificate_cache(&cache);
|
||||
|
||||
v3::Certificate cert = v3::fake_certificate();
|
||||
auto digest = cert.calculate_digest();
|
||||
ASSERT_TRUE(digest);
|
||||
|
||||
v3::SecuredMessage msg = v3::SecuredMessage::with_signed_data();
|
||||
msg.set_its_aid(aid::CA);
|
||||
msg.set_signer_identifier(cert);
|
||||
|
||||
EXPECT_EQ(nullptr, cache.lookup(*digest));
|
||||
auto confirm = dummy.verify(VerifyRequest { SecuredMessageView { std::move(msg) } });
|
||||
|
||||
EXPECT_EQ(ByteBuffer({ 1, 0, 0 }), confirm.permissions);
|
||||
EXPECT_EQ(1u, cache.size());
|
||||
EXPECT_NE(nullptr, cache.lookup(*digest));
|
||||
}
|
||||
|
||||
TEST(DummyVerifyServiceTest, permissions_empty_for_unrelated_aid)
|
||||
{
|
||||
DummyVerifyService dummy { VerificationReport::Success, CertificateValidity::valid() };
|
||||
|
||||
v3::Certificate cert = v3::fake_certificate();
|
||||
auto digest = cert.calculate_digest();
|
||||
ASSERT_TRUE(digest);
|
||||
|
||||
v3::SecuredMessage msg = v3::SecuredMessage::with_signed_data();
|
||||
msg.set_its_aid(aid::DEN);
|
||||
msg.set_signer_identifier(cert);
|
||||
|
||||
auto confirm = dummy.verify(VerifyRequest { SecuredMessageView { std::move(msg) } });
|
||||
|
||||
EXPECT_EQ(aid::DEN, confirm.its_aid);
|
||||
ASSERT_TRUE(confirm.certificate_id);
|
||||
EXPECT_EQ(*digest, *confirm.certificate_id);
|
||||
EXPECT_TRUE(confirm.permissions.empty());
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/security/backend.hpp>
|
||||
#include <vanetza/security/ecc_point.hpp>
|
||||
#include <memory>
|
||||
|
||||
using namespace vanetza::security;
|
||||
using namespace vanetza;
|
||||
|
||||
class EccPointDecompressionTest: public ::testing::TestWithParam<const char*>
|
||||
{
|
||||
protected:
|
||||
std::unique_ptr<Backend> backend;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
backend = create_backend(GetParam());
|
||||
ASSERT_TRUE(backend);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TEST_P(EccPointDecompressionTest, LSB_Y_0)
|
||||
{
|
||||
const ByteBuffer x = {
|
||||
0x21, 0x31, 0xB5, 0x19, 0x4C, 0xE6, 0xEE, 0x9F,
|
||||
0x47, 0xB6, 0xB4, 0x5F, 0xF8, 0x46, 0xC1, 0x79,
|
||||
0x65, 0x1A, 0x4A, 0x15, 0x63, 0x5A, 0x09, 0x87,
|
||||
0xCC, 0xC3, 0x8F, 0x3E, 0x34, 0x4D, 0xCD, 0x77 };
|
||||
const ByteBuffer y_expected = {
|
||||
0xD0, 0x12, 0x39, 0xBF, 0x92, 0x7F, 0x16, 0xA3,
|
||||
0xAD, 0xDB, 0x58, 0x2F, 0x94, 0x9B, 0xA7, 0x25,
|
||||
0x8F, 0xAC, 0x53, 0xFE, 0xD2, 0xE7, 0x26, 0xDB,
|
||||
0x9C, 0x62, 0xC3, 0x2C, 0xAC, 0x8D, 0xBA, 0x5A };
|
||||
const EccPoint point = Compressed_Lsb_Y_0 { x };
|
||||
|
||||
auto decompressed = backend->decompress_point(point);
|
||||
ASSERT_TRUE(decompressed);
|
||||
EXPECT_EQ(x, decompressed->x);
|
||||
EXPECT_EQ(y_expected, decompressed->y);
|
||||
}
|
||||
|
||||
TEST_P(EccPointDecompressionTest, LSB_Y_1)
|
||||
{
|
||||
const ByteBuffer x = {
|
||||
0x7F, 0x92, 0xF5, 0xBA, 0x25, 0xE0, 0x2C, 0x7F,
|
||||
0x7C, 0xF9, 0x82, 0x2D, 0x74, 0x6F, 0x28, 0x05,
|
||||
0x65, 0xD6, 0xA1, 0x4A, 0x64, 0x38, 0x40, 0x61,
|
||||
0x2E, 0x08, 0x63, 0x4D, 0x6E, 0x85, 0x7F, 0x13 };
|
||||
const ByteBuffer y_expected = {
|
||||
0x32, 0xD9, 0x85, 0xB6, 0x1D, 0x0E, 0x70, 0x51,
|
||||
0x51, 0x03, 0x88, 0xF9, 0x08, 0x2E, 0x24, 0x05,
|
||||
0x0B, 0x1A, 0xFE, 0xB6, 0x56, 0x49, 0x2D, 0x17,
|
||||
0x29, 0xB2, 0x8F, 0x9B, 0x58, 0xCE, 0xCB, 0xAF };
|
||||
const EccPoint point = Compressed_Lsb_Y_1 { x };
|
||||
|
||||
auto decompressed = backend->decompress_point(point);
|
||||
ASSERT_TRUE(decompressed);
|
||||
EXPECT_EQ(x, decompressed->x);
|
||||
EXPECT_EQ(y_expected, decompressed->y);
|
||||
}
|
||||
|
||||
#if defined VANETZA_WITH_OPENSSL && defined VANETZA_WITH_CRYPTOPP
|
||||
static auto backends = ::testing::Values("OpenSSL", "CryptoPP");
|
||||
#elif defined VANETZA_WITH_OPENSSL
|
||||
static auto backends = ::testing::Values("OpenSSL");
|
||||
#elif defined VANETZA_WITH_CRYPTOPP
|
||||
static auto backends = ::testing::Values("CryptoPP");
|
||||
#endif
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(EccPointDecompression, EccPointDecompressionTest, backends);
|
||||
@@ -0,0 +1,104 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/asn1/security_profile.hpp>
|
||||
#include VANETZA_ASN1_SECURITY_HEADER(CircularRegion.h)
|
||||
#include VANETZA_ASN1_SECURITY_HEADER(PolygonalRegion.h)
|
||||
#include VANETZA_ASN1_SECURITY_HEADER(RectangularRegion.h)
|
||||
#include <vanetza/common/position_fix.hpp>
|
||||
#include <vanetza/security/v3/geometry.hpp>
|
||||
#include <vanetza/units/angle.hpp>
|
||||
#include <array>
|
||||
|
||||
using namespace vanetza::security::v3;
|
||||
namespace units = vanetza::units;
|
||||
|
||||
TEST(Geometry, location_is_valid)
|
||||
{
|
||||
asn1::TwoDLocation location;
|
||||
location.latitude = Vanetza_Security_NinetyDegreeInt_unknown;
|
||||
location.longitude = Vanetza_Security_OneEightyDegreeInt_unknown;
|
||||
EXPECT_FALSE(is_valid(location));
|
||||
|
||||
location.latitude = 0;
|
||||
EXPECT_FALSE(is_valid(location));
|
||||
|
||||
location.longitude = 0;
|
||||
EXPECT_TRUE(is_valid(location));
|
||||
}
|
||||
|
||||
TEST(Geometry, is_inside_circular)
|
||||
{
|
||||
vanetza::PositionFix fix;
|
||||
fix.latitude = 48.0 * units::degree;
|
||||
fix.longitude = 11.0 * units::degree;
|
||||
|
||||
asn1::CircularRegion region;
|
||||
region.center.latitude = 480010000; /*< 1 degree equals 111km */
|
||||
region.center.longitude = 110000000;
|
||||
|
||||
region.radius = 100; /*< 100 is not enough */
|
||||
EXPECT_FALSE(is_inside(fix, region));
|
||||
|
||||
region.radius = 120; /*< 120 exceeds 111m */
|
||||
EXPECT_TRUE(is_inside(fix, region));
|
||||
}
|
||||
|
||||
TEST(Geometry, is_inside_rectangular)
|
||||
{
|
||||
asn1::RectangularRegion region;
|
||||
region.northWest.latitude = 485000000;
|
||||
region.northWest.longitude = 110000000;
|
||||
region.southEast.latitude = 480000000;
|
||||
region.southEast.longitude = 115000000;
|
||||
|
||||
auto build_posfix = [](double lat, double lon) {
|
||||
vanetza::PositionFix fix;
|
||||
fix.latitude = lat * units::degree;
|
||||
fix.longitude = lon * units::degree;
|
||||
return fix;
|
||||
};
|
||||
|
||||
EXPECT_TRUE(is_inside(build_posfix(48.001, 11.001), region));
|
||||
EXPECT_FALSE(is_inside(build_posfix(47.999, 11.001), region));
|
||||
EXPECT_FALSE(is_inside(build_posfix(48.501, 11.001), region));
|
||||
EXPECT_FALSE(is_inside(build_posfix(48.001, 10.999), region));
|
||||
EXPECT_FALSE(is_inside(build_posfix(48.001, 11.501), region));
|
||||
|
||||
std::swap(region.northWest, region.southEast);
|
||||
EXPECT_FALSE(is_inside(build_posfix(48.001, 11.001), region));
|
||||
}
|
||||
|
||||
TEST(Geometry, is_inside_polygon)
|
||||
{
|
||||
asn1::PolygonalRegion region;
|
||||
std::array<asn1::TwoDLocation, 4> locations = {{
|
||||
{ 100000000, 0 },
|
||||
{ 100000000, 100000000 },
|
||||
{ 0, 100000000 },
|
||||
{ 0, 0}
|
||||
}};
|
||||
std::array<asn1::TwoDLocation*, 4> location_ptrs = {
|
||||
&locations[0], &locations[1], &locations[2], &locations[3]
|
||||
};
|
||||
region.list.array = location_ptrs.data();
|
||||
region.list.count = location_ptrs.size();
|
||||
region.list.size = location_ptrs.size();
|
||||
|
||||
asn1::TwoDLocation point_b = { -10000000, -10000000 };
|
||||
EXPECT_FALSE(is_inside(&point_b, ®ion));
|
||||
|
||||
asn1::TwoDLocation point_a = { 50000000, 50000000 };
|
||||
EXPECT_TRUE(is_inside(&point_a, ®ion));
|
||||
|
||||
// also reversed order of region points
|
||||
location_ptrs = { &locations[3], &locations[2], &locations[1], &locations[0] };
|
||||
EXPECT_TRUE(is_inside(&point_a, ®ion));
|
||||
|
||||
vanetza::PositionFix fix;
|
||||
fix.latitude = -1 * units::degree;
|
||||
fix.longitude = -1 * units::degree;
|
||||
EXPECT_FALSE(is_inside(fix, region));
|
||||
|
||||
fix.latitude = 5 * units::degree;
|
||||
fix.longitude = 5 * units::degree;
|
||||
EXPECT_TRUE(is_inside(fix, region));
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#include <vanetza/common/byte_buffer.hpp>
|
||||
#include <vanetza/security/hmac.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace vanetza::security;
|
||||
using vanetza::ByteBuffer;
|
||||
|
||||
class HmacTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
ByteBuffer data = {0x01, 0x02, 0x03, 0x04, 0x05};
|
||||
HmacKey key = {{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
|
||||
}};
|
||||
};
|
||||
|
||||
#if defined VANETZA_WITH_OPENSSL || defined VANETZA_WITH_CRYPTOPP
|
||||
TEST_F(HmacTest, create_hmac_tag)
|
||||
{
|
||||
KeyTag tag = create_hmac_tag(data, key);
|
||||
KeyTag zero = {};
|
||||
EXPECT_NE(tag, zero);
|
||||
}
|
||||
|
||||
TEST_F(HmacTest, deterministic)
|
||||
{
|
||||
KeyTag tag1 = create_hmac_tag(data, key);
|
||||
KeyTag tag2 = create_hmac_tag(data, key);
|
||||
EXPECT_EQ(tag1, tag2);
|
||||
}
|
||||
|
||||
TEST_F(HmacTest, different_data_different_tag)
|
||||
{
|
||||
ByteBuffer other_data = {0x05, 0x04, 0x03, 0x02, 0x01};
|
||||
KeyTag tag1 = create_hmac_tag(data, key);
|
||||
KeyTag tag2 = create_hmac_tag(other_data, key);
|
||||
EXPECT_NE(tag1, tag2);
|
||||
}
|
||||
|
||||
TEST_F(HmacTest, different_key_different_tag)
|
||||
{
|
||||
HmacKey other_key = {};
|
||||
KeyTag tag1 = create_hmac_tag(data, key);
|
||||
KeyTag tag2 = create_hmac_tag(data, other_key);
|
||||
EXPECT_NE(tag1, tag2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined VANETZA_WITH_OPENSSL
|
||||
TEST_F(HmacTest, openssl)
|
||||
{
|
||||
KeyTag tag = create_hmac_tag_openssl(data, key);
|
||||
KeyTag zero = {};
|
||||
EXPECT_NE(tag, zero);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined VANETZA_WITH_CRYPTOPP
|
||||
TEST_F(HmacTest, cryptopp)
|
||||
{
|
||||
KeyTag tag = create_hmac_tag_cryptopp(data, key);
|
||||
KeyTag zero = {};
|
||||
EXPECT_NE(tag, zero);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined VANETZA_WITH_OPENSSL && defined VANETZA_WITH_CRYPTOPP
|
||||
TEST_F(HmacTest, openssl_and_cryptopp_match)
|
||||
{
|
||||
KeyTag tag_openssl = create_hmac_tag_openssl(data, key);
|
||||
KeyTag tag_cryptopp = create_hmac_tag_cryptopp(data, key);
|
||||
EXPECT_EQ(tag_openssl, tag_cryptopp);
|
||||
}
|
||||
#endif
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/security/peer_request_tracker.hpp>
|
||||
|
||||
#include "printer.hpp"
|
||||
|
||||
using namespace vanetza::security;
|
||||
|
||||
HashedId3 create_id(uint32_t id)
|
||||
{
|
||||
HashedId3 hid;
|
||||
hid[0] = id & 0xFF;
|
||||
hid[1] = (id >> 8) & 0xFF;
|
||||
hid[2] = (id >> 16) & 0xFF;
|
||||
return hid;
|
||||
}
|
||||
|
||||
TEST(PeerRequestTracker, is_pending)
|
||||
{
|
||||
PeerRequestTracker tracker;
|
||||
EXPECT_FALSE(tracker.is_pending(create_id(42)));
|
||||
tracker.add_request(create_id(42));
|
||||
EXPECT_TRUE(tracker.is_pending(create_id(42)));
|
||||
tracker.discard_request(create_id(42));
|
||||
EXPECT_FALSE(tracker.is_pending(create_id(42)));
|
||||
}
|
||||
|
||||
TEST(PeerRequestTracker, bounded_capacity)
|
||||
{
|
||||
PeerRequestTracker tracker(2);
|
||||
tracker.add_request(create_id(1));
|
||||
tracker.add_request(create_id(2));
|
||||
EXPECT_TRUE(tracker.is_pending(create_id(1)));
|
||||
EXPECT_TRUE(tracker.is_pending(create_id(2)));
|
||||
|
||||
tracker.add_request(create_id(3));
|
||||
EXPECT_TRUE(tracker.is_pending(create_id(3)));
|
||||
EXPECT_TRUE(tracker.is_pending(create_id(2)));
|
||||
// dropped oldest pending request
|
||||
EXPECT_FALSE(tracker.is_pending(create_id(1)));
|
||||
}
|
||||
|
||||
TEST(PeerRequestTracker, keep_order)
|
||||
{
|
||||
PeerRequestTracker tracker(4);
|
||||
tracker.add_request(create_id(1));
|
||||
tracker.add_request(create_id(2));
|
||||
tracker.add_request(create_id(3));
|
||||
tracker.add_request(create_id(4));
|
||||
tracker.add_request(create_id(3));
|
||||
tracker.add_request(create_id(2));
|
||||
|
||||
std::list<HashedId3> expected = { create_id(1), create_id(2), create_id(3), create_id(4) };
|
||||
EXPECT_EQ(expected, tracker.all());
|
||||
|
||||
// nothing left in tracker
|
||||
EXPECT_FALSE(tracker.next_one());
|
||||
}
|
||||
|
||||
TEST(PeerRequestTracker, next_one)
|
||||
{
|
||||
PeerRequestTracker tracker(3);
|
||||
tracker.add_request(create_id(0xc0));
|
||||
tracker.add_request(create_id(0xff));
|
||||
tracker.add_request(create_id(0xee));
|
||||
tracker.add_request(create_id(0x42));
|
||||
|
||||
EXPECT_EQ(tracker.next_one(), create_id(0xff));
|
||||
EXPECT_EQ(tracker.next_one(), create_id(0xee));
|
||||
EXPECT_EQ(tracker.next_one(), create_id(0x42));
|
||||
EXPECT_FALSE(tracker.next_one());
|
||||
}
|
||||
|
||||
TEST(PeerRequestTracker, next_n)
|
||||
{
|
||||
PeerRequestTracker tracker(6);
|
||||
tracker.add_request(create_id(0x01));
|
||||
tracker.add_request(create_id(0x02));
|
||||
tracker.add_request(create_id(0x03));
|
||||
tracker.add_request(create_id(0x04));
|
||||
tracker.add_request(create_id(0x05));
|
||||
|
||||
std::list<HashedId3> expected = { create_id(0x01), create_id(0x02), create_id(0x03) };
|
||||
EXPECT_EQ(expected, tracker.next_n(3));
|
||||
|
||||
expected = { create_id(0x04), create_id(0x05) };
|
||||
EXPECT_EQ(expected, tracker.next_n(8));
|
||||
|
||||
expected = { };
|
||||
EXPECT_EQ(expected, tracker.next_n(2));
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#include <vanetza/security/persistence.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace vanetza::security;
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
void check_private_key(const PrivateKey& key)
|
||||
{
|
||||
EXPECT_EQ(key.type, KeyType::NistP256);
|
||||
ASSERT_EQ(key.key.size(), expected_private_key.size());
|
||||
EXPECT_TRUE(std::equal(key.key.begin(), key.key.end(), expected_private_key.begin()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined VANETZA_WITH_OPENSSL || defined VANETZA_WITH_CRYPTOPP
|
||||
|
||||
TEST(Persistence, load_pem)
|
||||
{
|
||||
check_private_key(load_private_key_from_pem_file(ASSET("test_key.pem")));
|
||||
}
|
||||
|
||||
TEST(Persistence, load_der)
|
||||
{
|
||||
check_private_key(load_private_key_from_der_file(ASSET("test_key.der")));
|
||||
}
|
||||
|
||||
TEST(Persistence, pem_and_der_load_same_key)
|
||||
{
|
||||
auto pem = load_private_key_from_pem_file(ASSET("test_key.pem"));
|
||||
auto der = load_private_key_from_der_file(ASSET("test_key.der"));
|
||||
EXPECT_EQ(pem.type, der.type);
|
||||
EXPECT_EQ(pem.key, der.key);
|
||||
}
|
||||
|
||||
TEST(Persistence, load_pem_nonexistent_file)
|
||||
{
|
||||
EXPECT_THROW(load_private_key_from_pem_file("nonexistent.pem"), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(Persistence, load_der_nonexistent_file)
|
||||
{
|
||||
EXPECT_THROW(load_private_key_from_der_file("nonexistent.der"), std::runtime_error);
|
||||
}
|
||||
|
||||
#endif /* VANETZA_WITH_OPENSSL || VANETZA_WITH_CRYPTOPP */
|
||||
|
||||
#ifdef VANETZA_WITH_OPENSSL
|
||||
TEST(Persistence, openssl_load_pem)
|
||||
{
|
||||
check_private_key(load_private_key_from_pem_file_openssl(ASSET("test_key.pem")));
|
||||
}
|
||||
|
||||
TEST(Persistence, openssl_load_der)
|
||||
{
|
||||
check_private_key(load_private_key_from_der_file_openssl(ASSET("test_key.der")));
|
||||
}
|
||||
#endif /* VANETZA_WITH_OPENSSL */
|
||||
|
||||
#ifdef VANETZA_WITH_CRYPTOPP
|
||||
TEST(Persistence, cryptopp_load_pem)
|
||||
{
|
||||
check_private_key(load_private_key_from_pem_file_cryptopp(ASSET("test_key.pem")));
|
||||
}
|
||||
|
||||
TEST(Persistence, cryptopp_load_der)
|
||||
{
|
||||
check_private_key(load_private_key_from_der_file_cryptopp(ASSET("test_key.der")));
|
||||
}
|
||||
#endif /* VANETZA_WITH_CRYPTOPP */
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
#include <vanetza/security/decap_service.hpp>
|
||||
#include <vanetza/security/hashed_id.hpp>
|
||||
#include <ostream>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace security
|
||||
{
|
||||
|
||||
void PrintTo(const DecapReport& report, std::ostream* out)
|
||||
{
|
||||
struct Printer : boost::static_visitor<>
|
||||
{
|
||||
Printer(std::ostream* out) : out(out) {}
|
||||
|
||||
void operator()(const VerificationReport& report) const
|
||||
{
|
||||
*out << "DecapReport(VerificationReport(" << static_cast<int>(report) << "))";
|
||||
}
|
||||
|
||||
void operator()(const boost::blank&) const
|
||||
{
|
||||
*out << "DecapReport(None)";
|
||||
}
|
||||
|
||||
std::ostream* out;
|
||||
};
|
||||
boost::apply_visitor(Printer(out), report);
|
||||
}
|
||||
|
||||
} // namespace security
|
||||
} // namespace vanetza
|
||||
|
||||
namespace std {
|
||||
|
||||
/* HashedId3 and HashedId8 are mere type aliases of std::array<> */
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const vanetza::security::HashedId3& id)
|
||||
{
|
||||
os << vanetza::security::to_string(id);
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const vanetza::security::HashedId8& id)
|
||||
{
|
||||
os << vanetza::security::to_string(id);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/security/public_key.hpp>
|
||||
|
||||
using namespace vanetza;
|
||||
using namespace vanetza::security;
|
||||
using namespace std;
|
||||
|
||||
TEST(PublicKey, canonical_hexstring_y0)
|
||||
{
|
||||
PublicKey key;
|
||||
key.type = KeyType::NistP256;
|
||||
key.compression = KeyCompression::Y0;
|
||||
key.x = ByteBuffer(32, 0x00);
|
||||
EXPECT_EQ("02" + std::string(64, '0'), canonical_hexstring(key));
|
||||
}
|
||||
|
||||
TEST(PublicKey, canonical_hexstring_y1)
|
||||
{
|
||||
PublicKey key;
|
||||
key.type = KeyType::BrainpoolP384r1;
|
||||
key.compression = KeyCompression::Y1;
|
||||
key.x = ByteBuffer(48, 0x00);
|
||||
EXPECT_EQ("03" + std::string(96, '0'), canonical_hexstring(key));
|
||||
}
|
||||
|
||||
TEST(PublicKey, canonical_hexstring_encoding)
|
||||
{
|
||||
PublicKey key;
|
||||
key.type = KeyType::NistP256;
|
||||
key.compression = KeyCompression::Y0;
|
||||
key.x = {
|
||||
0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd,
|
||||
0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
|
||||
0x10, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba,
|
||||
0xbe, 0x00, 0xff, 0x11, 0xee, 0x22, 0xdd, 0x33
|
||||
};
|
||||
auto expected = "02"
|
||||
"000123456789ABCD"
|
||||
"EFFEDCBA98765432"
|
||||
"10DEADBEEFCAFEBA"
|
||||
"BE00FF11EE22DD33";
|
||||
EXPECT_EQ(expected, canonical_hexstring(key));
|
||||
}
|
||||
|
||||
TEST(PublicKey, canonical_hexstring_uncompressed_parity)
|
||||
{
|
||||
PublicKey key;
|
||||
key.type = KeyType::NistP256;
|
||||
key.compression = KeyCompression::NoCompression;
|
||||
key.x = ByteBuffer(32, 0xab);
|
||||
key.y = ByteBuffer(32, 0x04);
|
||||
EXPECT_EQ("02", canonical_hexstring(key).substr(0, 2));
|
||||
|
||||
key.y = ByteBuffer(32, 0x05);
|
||||
EXPECT_EQ("03", canonical_hexstring(key).substr(0, 2));
|
||||
}
|
||||
|
||||
TEST(PublicKey, canonical_hexstring_rejects_malformed)
|
||||
{
|
||||
PublicKey key;
|
||||
key.compression = KeyCompression::Y0;
|
||||
|
||||
key.type = KeyType::Unspecified;
|
||||
key.x = ByteBuffer(32, 0xab);
|
||||
EXPECT_TRUE(canonical_hexstring(key).empty());
|
||||
|
||||
key.type = KeyType::NistP256;
|
||||
key.x.clear();
|
||||
EXPECT_TRUE(canonical_hexstring(key).empty());
|
||||
|
||||
key.x = ByteBuffer(31, 0xab);
|
||||
EXPECT_TRUE(canonical_hexstring(key).empty());
|
||||
|
||||
key.x = ByteBuffer(32, 0xab);
|
||||
key.compression = KeyCompression::NoCompression;
|
||||
EXPECT_TRUE(canonical_hexstring(key).empty());
|
||||
|
||||
key.y = ByteBuffer(31, 0x04);
|
||||
EXPECT_TRUE(canonical_hexstring(key).empty());
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/common/manual_runtime.hpp>
|
||||
#include <vanetza/common/stored_position_provider.hpp>
|
||||
#include <vanetza/security/backend.hpp>
|
||||
#include <vanetza/security/straight_verify_service.hpp>
|
||||
#include <vanetza/security/v3/naive_certificate_provider.hpp>
|
||||
#include <vanetza/security/v3/secured_message.hpp>
|
||||
#include <vanetza/security/v3/sign_service.hpp>
|
||||
|
||||
#include "printer.hpp"
|
||||
|
||||
using namespace vanetza;
|
||||
using namespace vanetza::security;
|
||||
|
||||
TEST(SecuredMessageV3, deserialize)
|
||||
{
|
||||
const ByteBuffer encoded_secured_msg = {
|
||||
0x03, 0x81, 0x00, 0x40, 0x03, 0x80, 0x56, 0x20, 0x50, 0x02, 0x80, 0x00,
|
||||
0x32, 0x01, 0x00, 0x14, 0x00, 0xd2, 0xfb, 0x6a, 0x0c, 0x62, 0xd2, 0xbf,
|
||||
0x6c, 0x54, 0x53, 0x1f, 0x44, 0xef, 0xf5, 0x06, 0x66, 0x36, 0x09, 0x84,
|
||||
0x6a, 0x06, 0xc8, 0x00, 0x00, 0xa0, 0x00, 0x07, 0xd1, 0x00, 0x00, 0x02,
|
||||
0x02, 0x6a, 0x0c, 0x62, 0xd2, 0x57, 0x41, 0x00, 0x5a, 0x9d, 0x3a, 0xbf,
|
||||
0x6e, 0x36, 0x01, 0x20, 0x22, 0x34, 0x23, 0x00, 0xfc, 0x35, 0x96, 0xd4,
|
||||
0x58, 0x69, 0x40, 0xe2, 0x4e, 0x03, 0x02, 0x96, 0x8a, 0x9b, 0x34, 0x3d,
|
||||
0x82, 0x09, 0x9e, 0x10, 0x41, 0xc0, 0x14, 0xb9, 0x80, 0x40, 0x01, 0x24,
|
||||
0x00, 0x01, 0xc8, 0x0b, 0xbf, 0x35, 0x4b, 0x4f, 0x80, 0x0b, 0xa2, 0xd2,
|
||||
0xfb, 0x6a, 0x0c, 0x62, 0xd2, 0x80, 0x82, 0xea, 0x71, 0xef, 0xf9, 0xc6,
|
||||
0xbb, 0x15, 0x7b, 0x8e, 0x16, 0x66, 0x44, 0x12, 0x0d, 0x7f, 0x98, 0xf2,
|
||||
0x52, 0x5e, 0x73, 0x8f, 0x6f, 0x41, 0xd7, 0xfd, 0xfa, 0xc7, 0xd0, 0xd8,
|
||||
0x8a, 0xa3, 0x9b, 0x10, 0x96, 0xfa, 0xb3, 0xfb, 0x2a, 0x0a, 0x92, 0x2a,
|
||||
0x3b, 0x5f, 0xeb, 0x91, 0xf9, 0xf5, 0x22, 0xd0, 0x06, 0x1f, 0x3b, 0x9c,
|
||||
0xa7, 0xa4, 0x6f, 0x7c, 0x7b, 0xd3, 0xef, 0x9d, 0x3a, 0x84, 0xbc
|
||||
};
|
||||
|
||||
v3::SecuredMessage msg;
|
||||
EXPECT_TRUE(msg.decode(encoded_secured_msg));
|
||||
EXPECT_EQ(3, msg.protocol_version());
|
||||
}
|
||||
|
||||
TEST(SecuredMessageV3, verify)
|
||||
{
|
||||
// a CAM signed by a VW Golf 8 including a full signer certificate
|
||||
const ByteBuffer encoded_secured_msg = {
|
||||
0x03, 0x81, 0x00, 0x40, 0x03, 0x80, 0x56, 0x20, 0x50, 0x02, 0x80, 0x00,
|
||||
0x32, 0x01, 0x00, 0x14, 0x00, 0xfe, 0x38, 0x4c, 0xe0, 0xb8, 0x90, 0xbf,
|
||||
0x6b, 0x2f, 0x5b, 0x1f, 0x45, 0x28, 0x58, 0x06, 0x64, 0x0a, 0x6d, 0x80,
|
||||
0xe8, 0x03, 0xbe, 0x00, 0x00, 0xa0, 0x00, 0x07, 0xd1, 0x00, 0x00, 0x02,
|
||||
0x02, 0x4c, 0xe0, 0xb8, 0x90, 0x30, 0xbc, 0x00, 0x5a, 0x9d, 0x42, 0x2a,
|
||||
0x0e, 0x35, 0xbb, 0xa0, 0x22, 0x44, 0x23, 0x86, 0xda, 0x35, 0x96, 0xd4,
|
||||
0x58, 0x3b, 0xe1, 0x20, 0xa1, 0x03, 0x02, 0x96, 0x8a, 0xcf, 0x33, 0xe7,
|
||||
0x81, 0xff, 0x82, 0x10, 0x3f, 0xe0, 0x14, 0x19, 0x80, 0x40, 0x01, 0x24,
|
||||
0x00, 0x01, 0xc8, 0x0b, 0xba, 0xb6, 0xc8, 0x15, 0x81, 0x01, 0x01, 0x80,
|
||||
0x03, 0x00, 0x80, 0x56, 0xdf, 0xd6, 0xd6, 0x27, 0xa3, 0x62, 0xdc, 0x10,
|
||||
0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xdf, 0xf7, 0xb5, 0x84, 0x00,
|
||||
0xa8, 0x01, 0x02, 0x80, 0x01, 0x24, 0x81, 0x04, 0x03, 0x01, 0x00, 0x00,
|
||||
0x80, 0x01, 0x25, 0x81, 0x05, 0x04, 0x01, 0x90, 0x1a, 0x25, 0x80, 0x80,
|
||||
0x82, 0x04, 0x27, 0xbb, 0x27, 0xc9, 0x98, 0xc1, 0xec, 0xa2, 0xb1, 0x0e,
|
||||
0x71, 0x07, 0x98, 0x02, 0x44, 0x51, 0x8b, 0x3c, 0x50, 0xa3, 0xa3, 0x27,
|
||||
0xb5, 0xb1, 0x90, 0xd0, 0x90, 0xf1, 0x45, 0x1f, 0x3d, 0x80, 0x80, 0x83,
|
||||
0xc2, 0xf3, 0xca, 0xeb, 0xc7, 0xfa, 0x35, 0x94, 0x5c, 0x03, 0x0a, 0x5a,
|
||||
0xe0, 0x1a, 0x41, 0x7a, 0xdf, 0x6d, 0xff, 0xd5, 0x41, 0xcc, 0xd2, 0xd9,
|
||||
0x2b, 0xfe, 0xb6, 0x3d, 0xc1, 0x56, 0x89, 0xcb, 0xd6, 0xb8, 0xe3, 0x2b,
|
||||
0xd5, 0xe8, 0x66, 0xd9, 0xfa, 0xa2, 0xfe, 0x55, 0x95, 0xe2, 0xdb, 0xb9,
|
||||
0xbe, 0x3e, 0x96, 0x5a, 0x70, 0x94, 0x25, 0x8b, 0x4a, 0x24, 0x9d, 0xfb,
|
||||
0x75, 0x8a, 0x07, 0x80, 0x82, 0x73, 0x7a, 0x94, 0x51, 0x6c, 0x56, 0xf8,
|
||||
0x85, 0x26, 0x2f, 0xd4, 0xd2, 0xac, 0x77, 0x5e, 0xba, 0xa1, 0x46, 0x84,
|
||||
0xeb, 0xf6, 0x59, 0x39, 0x66, 0xef, 0x7d, 0x30, 0x84, 0x07, 0x8e, 0xdd,
|
||||
0xd0, 0xf4, 0xfe, 0x94, 0x06, 0x04, 0x2b, 0x1d, 0x1a, 0x92, 0xb7, 0x0a,
|
||||
0x0c, 0xce, 0x8d, 0x7d, 0xe7, 0xe9, 0xb6, 0xfe, 0x13, 0xfb, 0x26, 0x9a,
|
||||
0x5a, 0x67, 0x57, 0x31, 0x61, 0x58, 0x9e, 0x2a, 0x79
|
||||
};
|
||||
|
||||
v3::SecuredMessage msg;
|
||||
EXPECT_TRUE(msg.decode(encoded_secured_msg));
|
||||
EXPECT_EQ(3, msg.protocol_version());
|
||||
|
||||
StoredPositionProvider position_provider;
|
||||
ManualRuntime runtime { Clock::at("2019-11-21 11:30") };
|
||||
auto backend = create_backend("default");
|
||||
|
||||
StraightVerifyService verify_service { runtime, *backend, position_provider };
|
||||
VerifyConfirm confirm = verify_service.verify(msg);
|
||||
EXPECT_EQ(confirm.report, VerificationReport::Success);
|
||||
EXPECT_EQ(confirm.its_aid, aid::CA);
|
||||
ByteBuffer ca_ssp {0x01, 0x00, 0x00};
|
||||
EXPECT_EQ(confirm.permissions, ca_ssp);
|
||||
HashedId8 digest { 0x12, 0x7c, 0xff, 0x38, 0x4c, 0xe0, 0xb8, 0x90};
|
||||
EXPECT_EQ(confirm.certificate_id, digest);
|
||||
// AT issuer digest = 56dfd6d627a362dc
|
||||
}
|
||||
|
||||
TEST(SecuredMessageV3, sign_and_verify)
|
||||
{
|
||||
StoredPositionProvider position_provider;
|
||||
ManualRuntime runtime { Clock::at("2024-08-12 11:30") };
|
||||
auto backend = create_backend("default");
|
||||
|
||||
v3::NaiveCertificateProvider cert_provider { runtime };
|
||||
v3::DefaultSignHeaderPolicy sign_header_policy { runtime, position_provider, cert_provider };
|
||||
v3::NullCertificateValidator cert_validator;
|
||||
v3::StraightSignService sign_service { cert_provider, *backend, sign_header_policy, cert_validator };
|
||||
|
||||
SignRequest request;
|
||||
ChunkPacket packet;
|
||||
packet[OsiLayer::Application] = ByteBuffer {0x01, 0x02, 0x03};
|
||||
request.plain_message = std::move(packet);
|
||||
request.its_aid = aid::DEN;
|
||||
SignConfirm sign_confirm = sign_service.sign(std::move(request));
|
||||
ASSERT_TRUE(sign_confirm.secured_message);
|
||||
|
||||
StraightVerifyService verify_service { runtime, *backend, position_provider };
|
||||
VerifyRequest verify_request { SecuredMessageView { *sign_confirm.secured_message } };
|
||||
VerifyConfirm verify_confirm = verify_service.verify(verify_request);
|
||||
EXPECT_EQ(verify_confirm.report, VerificationReport::Success);
|
||||
EXPECT_TRUE(verify_confirm.certificate_validity.valid());
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
#include <vanetza/security/tests/serialization.hpp>
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace security
|
||||
{
|
||||
|
||||
ByteBuffer buffer_from_hexstring(const char* string)
|
||||
{
|
||||
ByteBuffer buf;
|
||||
boost::algorithm::unhex(string, back_inserter(buf));
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // namespace security
|
||||
} // namespace vanetza
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
#ifndef SERIALIZATION_HPP_ZWGI3RCG
|
||||
#define SERIALIZATION_HPP_ZWGI3RCG
|
||||
|
||||
#include <vanetza/common/byte_buffer.hpp>
|
||||
#include <vanetza/common/byte_buffer_source.hpp>
|
||||
#include <vanetza/security/v2/serialization.hpp>
|
||||
#include <boost/iostreams/stream_buffer.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
namespace security
|
||||
{
|
||||
|
||||
/**
|
||||
* \brief create a ByteBuffer from griven hex string
|
||||
* \param string hex string
|
||||
* \return equivalent byte buffer
|
||||
*/
|
||||
ByteBuffer buffer_from_hexstring(const char*);
|
||||
|
||||
/**
|
||||
* \brief Deserialize any class from given hex string
|
||||
* \tparam T the target type of deserialization
|
||||
* \tparam ARGS additional arguments passed to deserialize function
|
||||
* \param string hex string
|
||||
* \param result deserialize into this object
|
||||
* \param args additional arguments for deserialization
|
||||
*/
|
||||
template<typename T, typename... ARGS>
|
||||
size_t deserialize_from_hexstring(const char* string, T& result, ARGS&&... args)
|
||||
{
|
||||
auto buffer = buffer_from_hexstring(string);
|
||||
byte_buffer_source source(buffer);
|
||||
boost::iostreams::stream_buffer<byte_buffer_source> stream(source);
|
||||
InputArchive ar(stream);
|
||||
return deserialize(ar, result, std::forward<ARGS>(args)...);
|
||||
}
|
||||
|
||||
namespace v2
|
||||
{
|
||||
|
||||
/**
|
||||
* \brief Serialize and deserialize an object
|
||||
*
|
||||
* Source object is serialized and deserialized
|
||||
* object form this binary representation is returned.
|
||||
*
|
||||
* \tparam T the type of the result
|
||||
* \tparam ARGS additional arguments passed to underlying functions
|
||||
* \param source serialize from this object
|
||||
* \param args additional arguments
|
||||
* \return deserialized object (should be equal to source)
|
||||
*/
|
||||
template<typename T, typename... ARGS>
|
||||
T serialize_roundtrip(const T& source, ARGS&&... args)
|
||||
{
|
||||
std::stringstream stream;
|
||||
OutputArchive oa(stream);
|
||||
serialize(oa, source, std::forward<ARGS>(args)...);
|
||||
|
||||
T result;
|
||||
InputArchive ia(stream);
|
||||
deserialize(ia, result, std::forward<ARGS>(args)...);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace v2
|
||||
} // namespace security
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* SERIALIZATION_HPP_ZWGI3RCG */
|
||||
Reference in New Issue
Block a user