riebl/vanetza

secured CAM/DENM: Unknown Signer at receiver

Closed this issue · 12 comments

Hello,
I am using vanetza with security on a client/server architecture, meaning one OBU 1 sends CAM/DENM the OBU 2 only listens. In the current version, none of them have access to valid position from gpsd (gpsd provides 0,0 as lat/long).
From the various FAQ, I understood that for CAM to be sent I need a ticket, so I send a CAM with the following command:
OBU 1 & OBU2:
v2xmanager --interface=wlp2s0 --gpsd-host=localhost --gpsd-port 2947 --cam-interval 6000 --certificate-key ticket.key --certificate ticket.cert --certificate-chain root.cert aa.cert ticket.cert
At the receiver, the packet is dropped with reasons: "INVALID_CERTIFICATE" and validity reason: "UNKNOWN_SIGNER".

I traced the issue to default_certificate_validator.cpp, lines: ligne 210, where i do not find a valid Authorization Authority certificate in the certificate cache, which lead me to thinking I do not fully understand what needs to be send and configured in terms of certificates.

if (subject_type == SubjectType::Authorization_Ticket) {
for (auto& possible_signer : m_cert_cache.lookup(signer_hash, SubjectType::Authorization_Authority)) {
/////// Never Enters Here /////////////
auto verification_key = get_public_key(possible_signer, m_crypto_backend);
if (!verification_key) {
continue;
}
if (m_crypto_backend.verify_data(verification_key.get(), binary_cert, sig.get())) {
if (!check_consistency(certificate, possible_signer)) {
return CertificateInvalidReason::Inconsistent_With_Signer;
}
return CertificateValidity::valid();
}
}
}

As I use a ticket (both OBUs, maybe I should only use a ticket at the RX OBU?), it is not a authorization authority. I added the root.cert, aa.cert and even ticket.aa as chain certificates on both sides, but I do not fully understand how a certificate would be injected in the certificate cache (at the OBU 2 side).

am I not configuring vanetza correctly on the command line? btw, I imagine that the *.key and *cert should not be the same on both side (OBU 1 and OBU 2), but I tried with exact and fully different files..both have the same issue. Also, maybe I need to have real position (with fakegps)?

thanks in advance for your help on shedding some light on this..

You need to tell the receiver which certificates to trust, which can be done with --trusted-certificate and including the root.cert on the receiver. The root.cert doesn't have to be in the chain on the sender side, as the receiver needs that to be configured anyway.

If you have a more complex scenario, you can even have multiple roots and provide multiple trusted certificates by repeating the --trusted-certificate switch.

I'm not sure how I implemented it anymore, but IIRC you can even trust tickets and intermediates directly, but I'd recommend putting only the root certificate in the trust store.

("help", "Print out available options.")
("interface,i", po::value<std::string>()->default_value("lo"), "Network interface to use.")
("mac-address", po::value<std::string>(), "Override the network interface's MAC address.")
("certificate", po::value<std::string>(), "Certificate to use for secured messages.")
("certificate-key", po::value<std::string>(), "Certificate key to use for secured messages.")
("certificate-chain", po::value<std::vector<std::string> >()->multitoken(), "Certificate chain to use, use as often as needed.")
("trusted-certificate", po::value<std::vector<std::string> >()->multitoken(), "Trusted certificate, use as often as needed. Root certificates in the chain are automatically trusted.")
("gpsd-host", po::value<std::string>()->default_value(gpsd::shared_memory), "gpsd's server hostname")
("gpsd-port", po::value<std::string>()->default_value(gpsd::default_port), "gpsd's listening port")
("require-gnss-fix", "Suppress transmissions while GNSS position fix is missing")
("gn-version", po::value<unsigned>()->default_value(1), "GeoNetworking protocol version to use.")
("cam-interval", po::value<unsigned>()->default_value(1000), "CAM sending interval in milliseconds.")

Thanks #kelunik,
Actually, I thought that the trusted certificate would also be automatically inserted by --certificate-chain for root-CA. But I tried according to your suggestion. Unfortunately, it failed. My test:
sender: --certificate-key ticket.key --certificate ticket.cert --certificate-chain root.cert aa.cert ticket.cert
reciever: --certificate-key ticket.key --certificate ticket.cert --certificate-chain root.cert aa.cert ticket.cert
note: all keys and certificate are the same (I generated them once and gave the same both to the sender and receiver).

Maybe the certificate are invalid. So I plotted them according to 'show certificate':
root.cert:
Subject: Root Authority (Hello World Root-CA)
Digest: 6A999C9F99433F58 (SHA-256)
Signer: Self-Signed

Assurance: 0 with a confidence of 0

ITS Application IDs:

  • 36 (CA-Basic service)
  • 37 (DEN-Basic service)

Validity starts 2019-Aug-08 12:23:54 and ends 2020-Aug-07 13:23:54

This certificate doesn't have any regional restriction.

aa.cert
Subject: Authorization Authority (Hello World Auth-CA)
Digest: 3DF6322B263C8E5D (SHA-256)
Signer: 6A999C9F99433F58 (SHA-256)

Assurance: 0 with a confidence of 0

ITS Application IDs:

  • 36 (CA-Basic service)
  • 37 (DEN-Basic service)

Validity starts 2019-Aug-08 12:23:54 and ends 2020-Feb-04 13:23:54

This certificate doesn't have any regional restriction.
ticket.cert:
Subject: Authorization Ticket
Digest: 7C5BAD4512FD0A1B (SHA-256)
Signer: 3DF6322B263C8E5D (SHA-256)

Assurance: 0 with a confidence of 0

CA - ITS Service Specific Permissions:

Warning: Certificate doesn't contain any application IDs.

Validity starts 2019-Aug-08 12:23:54 and ends 2019-Aug-15 13:23:54

This certificate doesn't have any regional restriction.

Also, I tried to pass all of them in hex-binary to the tool https://werkzeug.dcaiti.tu-berlin.de/etsi/ts103097/
all three have the same output:

[OK] successfully parsed hex-string: 216 bytes
[FAIL] DecodingException: while decoding Element at buffer position 0: unsupported version: 0

here is the bin-hex: root.cert (xxd -p root.cert | tr -d '\n')
0200041348656c6c6f20576f726c6420526f6f742d43414900000429f2346f82805605805298ddf90a4127f3a403c85ab7fbf2f957ed3ee9531f4db4ce99b39481868da80a288f50d1f86e80102cef49b67e6bf6cb379b44cd388202002002242509011d58b15a1f39f2ea000051f59b050f8abffd5a57ecb25d31ea15926b25dc44ae6b806b1b1ab51f065c8ad9d1c2eecc36e074f116884efa9e99101985d370070de42928aa030bc423701a

maybe my binary hex conversion is wrong, but from the 'show-certificate', would you see anything wrong?

Thanks,

BR,

Jérôme

Dear #kelunik,
Following up from before, I did a geonet hex decoding at the tool: https://werkzeug.dcaiti.tu-berlin.de/etsi/ts103097/ and got the following error message (consistent with my previous issues):

[OK] successfully parsed hex-string: 342 bytes
[OK] successfully decoded : GeoNetPacket
[FAIL] validation result: SIGNER_CERTIFICATE_NOT_FOUND

Maybe I am not generating the ticket.cert correctly, but I generated them according to the following script:

#generating private keys
certify generate-key root.key
certify generate-key aa.key
certify generate-key ticket.key

#extracting public keys
certify extract-public-key --private-key root.key root.pub

#generating certificats
certify generate-root --subject-key root.key root.cert
certify generate-aa --sign-key root.key --sign-cert root.cert --subject-key aa.key aa.cert
certify generate-ticket --sign-key aa.key --sign-cert aa.cert --subject-key ticket.key ticket.cert
echo "...key generation DONE!"

My geonet hex file is:
12 00 1a 0a 02 80 b8 80 02 02 01 3d f6 32 2b 26 3c 8e 5d 01 00 52 00 00 04 67 6c cf 13 9e 62 bd a3 5e 28 dc c7 62 32 fa 46 f9 6a ea 73 1b 5b c1 91 d3 33 65 86 9f c3 47 92 f1 09 50 1a 45 01 42 e9 8c 62 67 aa 6a 8d 31 ae 35 e0 55 fb 72 c3 f8 c5 c1 87 48 b8 8b 42 a6 0d 02 00 21 0b 24 03 01 00 00 25 04 01 00 00 00 09 01 1d 58 b1 5a 1d 61 f9 ea 00 00 16 b6 64 15 a6 19 b8 b0 df 3f b6 1f 9e 5f 9d d3 d8 aa e5 de a4 ff 83 0d 26 20 f8 42 4c f3 8e e2 09 85 13 d4 75 24 fc f3 1c 8b c1 ad f5 88 76 2b eb 0e 2e 8b 08 50 0c f1 cb 16 d9 4f e0 a0 43 30 00 00 01 c0 19 86 32 14 c4 05 24 01 51 20 50 00 80 00 2d 0a 00 80 00 a4 34 d9 e2 d5 83 b6 a9 85 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 d1 00 00 02 02 00 00 00 01 85 a7 00 56 b4 9d 20 0d 69 3a 40 1f ff ff fc 23 b7 74 20 00 00 01 20 00 00 3f e1 ed 04 03 ff e3 ff f4 00 43 01 00 00 1b f5 b1 8d 4c b7 7c cf f1 6b dd 64 8e 93 6c 65 36 a1 be 1b aa 88 fb 1f fc 9e 47 64 4b 94 1d 33 c9 f2 61 59 23 5d f6 62 73 b5 2e d4 bd 2c 88 40 a4 18 59 00 62 ab 58 12 ec 70 ed 0a 51 6a 16 a2

thanks in advance for any hints,
regards,
Jérôme

Hey!

Please try the following

sender: --certificate-key ticket.key --certificate ticket.cert --certificate-chain aa.cert
receiver: --certificate-key ticket.key --certificate ticket.cert --certificate-chain aa.cert --trusted-certificate root.cert

Thanks @kelunik

thanks for your suggestion. I just tried it, but same issue. I need to look into the security part of vanetza to understand a bit better how (or if I influenced it with my own code, although I did not touch vanetza core code) it does not send the signer certificate along with the certificate...could it be during the generation of the keys/certificate?

Outcome:
[OK] successfully parsed hex-string: 342 bytes
[OK] successfully decoded : GeoNetPacket
[FAIL] validation result: SIGNER_CERTIFICATE_NOT_FOUND

Geonet bin/hex:
12 00 1a 0a 02 80 b8 80 02 02 01 3d f6 32 2b 26 3c 8e 5d 01 00 52 00 00 04 67 6c cf 13 9e 62 bd a3 5e 28 dc c7 62 32 fa 46 f9 6a ea 73 1b 5b c1 91 d3 33 65 86 9f c3 47 92 f1 09 50 1a 45 01 42 e9 8c 62 67 aa 6a 8d 31 ae 35 e0 55 fb 72 c3 f8 c5 c1 87 48 b8 8b 42 a6 0d 02 00 21 0b 24 03 01 00 00 25 04 01 00 00 00 09 01 1d 58 b1 5a 1d 61 f9 ea 00 00 16 b6 64 15 a6 19 b8 b0 df 3f b6 1f 9e 5f 9d d3 d8 aa e5 de a4 ff 83 0d 26 20 f8 42 4c f3 8e e2 09 85 13 d4 75 24 fc f3 1c 8b c1 ad f5 88 76 2b eb 0e 2e 8b 08 50 0c f1 cb 16 d9 4f e0 a0 43 30 00 00 01 c0 2c ab 69 d5 63 05 24 01 51 20 50 00 80 00 2d 0a 00 80 00 a4 34 d9 e2 d5 83 bb 90 3b 8c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 d1 00 00 02 02 00 00 00 01 3b dc 00 56 b4 9d 20 0d 69 3a 40 1f ff ff fc 23 b7 74 20 00 00 01 20 00 00 3f e1 ed 04 03 ff e3 ff f4 00 43 01 00 00 43 17 a5 2b 5e 59 b5 47 ab 46 be 20 be 05 12 e1 27 35 f5 24 23 1d f2 26 32 ea 99 eb ab 58 a2 6f 7e b7 3a 5e b3 b4 7f a9 3a 19 64 95 27 7f 41 86 2e d8 92 42 c3 d0 22 2e 0e 8e c0 df 19 dd f7 da

@jhaerri How often did you try? I think the chained certificate is only sent periodically or if explicitly requested or encountering a new station.

Could you try setting up both to send multiple CAMs?

@kelunik Thanks..indeed at the beginning, I was only sending one CAM/DENM. I modified my code to send a CAM every 100ms..and indeed, the client sends one 'fat' CAM of 356 bytes per 9 'slim' CAM of 192 bytes, which seems fully coherent with the standard. I will check, but I assume that the fat cam includes the chained certificate...
But at the receiver, I still get the same packet being dropped due to "possible_signer : m_cert_cache.lookup(signer_hash, SubjectType::Authorization_Authority)" being empty for the 'fat' CAM, while the slim CAM does not go through this part of code, but also drops due to invalid signer.

I tested both geonet on the FOKUS tool and both gave the same 'missing signer certificate'. Here is the 'fat' CAM data...

maybe I do something wrong at the sender or somehow the certificate chains are not correctly decoded/validated..I will look into it, but would you see if anything would be wrong from the sec-CAM information below?

Thanks a lot,

    [OK] successfully parsed hex-string: 342 bytes
    [OK] successfully decoded : GeoNetPacket
    [FAIL] validation result: SIGNER_CERTIFICATE_NOT_FOUND

GeoNetPacket {
    BasicHeader: BasicHeader {
        Version: 1
        NextHeader: SECURED_PACKET
        Reserved: 0
        LifeTime (in ms): 0
        Remaining Hop Limit: 10
    }
    SecuredPacket: struct SecuredMessage {
        uint8 protocol_version: 2
        HeaderField<184> header_fields {
            struct HeaderField {
                HeaderFieldType type: signer_info (128)
                struct SignerInfo signer {
                    SignerInfoType type: certificate (2)
                    struct Certificate certificate {
                        uint8 version: 2
                        struct SignerInfo signer_info {
                            SignerInfoType type: certificate_digest_with_sha256 (1)
                            HashedId8 digest: 3DF6322B263C8E5D
                        }
                        struct SubjectInfo subject_info {
                            SubjectType subject_type: authorization_ticket (1)
                            opaque<0> subject_name: 
                        }
                        SubjectAttribute<82> 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: 676CCF139E62BDA35E28DCC76232FA46F96AEA731B5BC191D33365869FC34792
                                        opaque[32] y: F109501A450142E98C6267AA6A8D31AE35E055FB72C3F8C5C18748B88B42A60D
                                    }
                                }
                            }
                            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<11> its_aid_ssp_list {
                                    struct ItsAidSsp {
                                        IntX its_aid: 36
                                        opaque<3> service_specific_permissions: 010000
                                    }
                                    struct ItsAidSsp {
                                        IntX its_aid: 37
                                        opaque<4> service_specific_permissions: 01000000
                                    }
                                }
                            }
                        }
                        ValidityRestriction<9> validity_restrictions {
                            struct ValidityRestriction {
                                ValidityRestrictionType type: time_start_and_end (1)
                                Time32 start_validity: 2019-08-08 12:23:50 UTC
                                Time32 end_validity: 2019-08-15 13:23:50 UTC
                            }
                        }
                        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: 16B66415A619B8B0DF3FB61F9E5F9DD3D8AAE5DEA4FF830D2620F8424CF38EE2
                                }
                                opaque[32] s: 098513D47524FCF31C8BC1ADF588762BEB0E2E8B08500CF1CB16D94FE0A04330
                            }
                        }
                    }
                }
            }
            struct HeaderField {
                HeaderFieldType type: generation_time (0)
                Time64 generation_time: 2019-08-21 09:08:43.286 UTC
            }
            struct HeaderField {
                HeaderFieldType type: its_aid (5)
                IntX its_aid: 36
            }
        }
        struct Payload payload_field {
            PayloadType type: signed (1)
            opaque<81> data: 20500080002D0A008000A434D9E2D583E4B4D10F0000000000000000000000000000000007D10000020200000001D2360056B49D200D693A401FFFFFFC23B774200000012000003FE1ED0403FFE3FFF400
        }
        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: 15813AD5D91D1CD85102AEF034C849B1267834168BAE1D2479804E40558D616E
                        }
                        opaque[32] s: ADAF7AEEDF682EC4212F71D28096480996866E7AD1FE770C2F6FD96D37D68AE0
                    }
                }
            }
        }
    }
    CommonHeader: CommonHeader {
        NextHeader: BTP_B
        Reserved1: 0
        HeaderType and Subtype: TSB_SINGLE_HOP
        Traffic Class: 0
        itsGnIsMobile (Flag 0): false
        Flags 1-7: 128
        Payload Length: 45
        Maximum Hop Limit: 10
        Reserved2: 0
    }
    ExtendedHeader: SHBPacketHeader {
        SOPV: LongPositionVector {
            GN Address: GeoNetworkingAddress {
                Manually Configured: 1
                ITS-S Station Type: Unknown
                ITS-S Country Code: 0
                LL_ADDR: A434D9E2D583
            }
            Timestamp: 3837055247 (2019-08-21 09:08:42.991 UTC)
            Latitude: 0
            Longitude: 0
            Position Accuracy Indicator: 0
            Speed: 0
            Heading: 0
        }
        Reserved: 0
    }
    BTP: BTP_B {
        Destination port: CAM (2001)
        Destination port info: 0
    }
    Payload: 020200000001D2360056B49D200D693A401FFFFFFC23B774200000012000003FE1ED0403FFE3FFF400
}

@kelunik I think I found the issue. The previous CAM did not have the full chain...and I think I found out why. As my architecture is unidirectional (I receive CAMs but do not send CAMs), then I cannot 'explicitelty' requested the full security chain (as I understood, it needs to be requested via a CAM).
Once I reconfigured VANETZA to 'always' send the chain, then it worked. I could decode the CAM at the receiver.
However, astonishingly, via the FOKUS site, I still get the same error...but as long as it works on VANETZA, I am fine with it...

Would you have any idea why?

Anyways, thanks a lot for your help,

BR,

Jérôme

    [OK] successfully parsed hex-string: 525 bytes
    [OK] successfully decoded : GeoNetPacket
    [FAIL] validation result: SIGNER_CERTIFICATE_NOT_FOUND

GeoNetPacket {
    BasicHeader: BasicHeader {
        Version: 1
        NextHeader: SECURED_PACKET
        Reserved: 0
        LifeTime (in ms): 0
        Remaining Hop Limit: 10
    }
    SecuredPacket: struct SecuredMessage {
        uint8 protocol_version: 2
        HeaderField<367> header_fields {
            struct HeaderField {
                HeaderFieldType type: signer_info (128)
                struct SignerInfo signer {
                    SignerInfoType type: certificate_chain (3)
                    Certificate<352> certificates {
                        struct Certificate {
                            uint8 version: 2
                            struct SignerInfo signer_info {
                                SignerInfoType type: certificate_digest_with_sha256 (1)
                                HashedId8 digest: EC3F3F5B075879BE
                            }
                            struct SubjectInfo subject_info {
                                SubjectType subject_type: authorization_authority (2)
                                opaque<19> subject_name: Hello World Auth-CA
                            }
                            SubjectAttribute<73> 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: 6BE40CB604F59D21CC55D8CACD222AD44C6262FED1124C9AAFE1102CEB588F5F
                                            opaque[32] y: C5E72D5A9ABD7C32B73A14F6239F00980D9B5CF70396FF2DD3DF1479DEA30FA1
                                        }
                                    }
                                }
                                struct SubjectAttribute {
                                    SubjectAttributeType type: assurance_level (2)
                                    SubjectAssurance assurance_level: assurance level = 0, confidence = 0 (bitmask = 0)
                                }
                                struct SubjectAttribute {
                                    SubjectAttributeType type: its_aid_list (32)
                                    IntX<2> its_aid_list {
                                        IntX: 36
                                        IntX: 37
                                    }
                                }
                            }
                            ValidityRestriction<9> validity_restrictions {
                                struct ValidityRestriction {
                                    ValidityRestrictionType type: time_start_and_end (1)
                                    Time32 start_validity: 2019-08-21 11:38:13 UTC
                                    Time32 end_validity: 2020-02-17 12:38:13 UTC
                                }
                            }
                            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: 5D85A2168B383CAF5456A487E4B68297230CD5CB1C6D7526A993AFF33CFB8FD9
                                    }
                                    opaque[32] s: 2C2FFC284B198605EB7D0F76D2223FDAD1BE4688FC75EBA8AE29D635EA733E98
                                }
                            }
                        }
                        struct Certificate {
                            uint8 version: 2
                            struct SignerInfo signer_info {
                                SignerInfoType type: certificate_digest_with_sha256 (1)
                                HashedId8 digest: 276BCA0F9D478413
                            }
                            struct SubjectInfo subject_info {
                                SubjectType subject_type: authorization_ticket (1)
                                opaque<0> subject_name: 
                            }
                            SubjectAttribute<82> 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: 8FBAD23F82DDF3C4708FC98E598184C980E2D1448500B9C1214C0B25027C22E6
                                            opaque[32] y: 50E8CE635D560B6E577C6AE3DB3497FB7FAABFFC5B11ACC665EB5FBC2136160D
                                        }
                                    }
                                }
                                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<11> its_aid_ssp_list {
                                        struct ItsAidSsp {
                                            IntX its_aid: 36
                                            opaque<3> service_specific_permissions: 010000
                                        }
                                        struct ItsAidSsp {
                                            IntX its_aid: 37
                                            opaque<4> service_specific_permissions: 01000000
                                        }
                                    }
                                }
                            }
                            ValidityRestriction<9> validity_restrictions {
                                struct ValidityRestriction {
                                    ValidityRestrictionType type: time_start_and_end (1)
                                    Time32 start_validity: 2019-08-21 11:38:13 UTC
                                    Time32 end_validity: 2019-08-28 12:38:13 UTC
                                }
                            }
                            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: B3498105FFEFC71155F536A0B5322191291B1DB82BDA4E17FBCC9A710E58E026
                                    }
                                    opaque[32] s: 4E95B710D0BBB6B3CC470F9F623BE710A4DF2E5A945F3909883CEF17B611DC14
                                }
                            }
                        }
                    }
                }
            }
            struct HeaderField {
                HeaderFieldType type: generation_time (0)
                Time64 generation_time: 2019-08-21 15:26:34.152 UTC
            }
            struct HeaderField {
                HeaderFieldType type: its_aid (5)
                IntX its_aid: 36
            }
        }
        struct Payload payload_field {
            PayloadType type: signed (1)
            opaque<81> data: 20500080002D0A008000A434D9E2D583E60EBE6D0000000000000000000000000000000007D10000020200000001C0480056B49D200D693A401FFFFFFC23B774200000012000003FE1ED0403FFE3FFF400
        }
        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: DC957FF786883629246D2A616A52EE49CCA6AA6C7BBF71C03DAAD5EA6245372C
                        }
                        opaque[32] s: 2F5E6A25E58A8F11C00A8FD1AC98B6D3C31947C7A230139B5D80254DC1737C46
                    }
                }
            }
        }
    }
    CommonHeader: CommonHeader {
        NextHeader: BTP_B
        Reserved1: 0
        HeaderType and Subtype: TSB_SINGLE_HOP
        Traffic Class: 0
        itsGnIsMobile (Flag 0): false
        Flags 1-7: 128
        Payload Length: 45
        Maximum Hop Limit: 10
        Reserved2: 0
    }
    ExtendedHeader: SHBPacketHeader {
        SOPV: LongPositionVector {
            GN Address: GeoNetworkingAddress {
                Manually Configured: 1
                ITS-S Station Type: Unknown
                ITS-S Country Code: 0
                LL_ADDR: A434D9E2D583
            }
            Timestamp: 3859725933 (2019-08-21 15:26:33.677 UTC)
            Latitude: 0
            Longitude: 0
            Position Accuracy Indicator: 0
            Speed: 0
            Heading: 0
        }
        Reserved: 0
    }
    BTP: BTP_B {
        Destination port: CAM (2001)
        Destination port info: 0
    }
    Payload: 020200000001C0480056B49D200D693A401FFFFFFC23B774200000012000003FE1ED0403FFE3FFF400
}

The validation tool doesn't know about the signing certificates, so that error is entirely expected. It behaves as if you don't pass --trusted-certificate at the receiver.

It's strange that is accepts CAMs if all are fat, but not if they're only periodically fat. You said that it even rejected the fat cams there, is that correct?

@kelunik problem solved I think. On the infrastructure side, I did not insert the aa.cert inside the certificate cache structure in VANETZA. In normal operation, a car will request the aa.cert via a CAM, but it is an optional behavior if the aa.cert is not only in the cache (from the KPI), I guess. I will explicitly add the provided aa.cert to the cache (like the trust store). I guess it should do it..will let you know.

As for your question, I got three types of CAM: CAM with only digest, CAM with certificate and CAM with certificate and aa.cert (the full chain). Once I got at least one CAM with aa.cert, all others were accepted...but before, all (CAM with digest and CAM with ticket certificate) were rejected. I think this is coherent with the standard...

@jhaerri Indeed, totally forgot that there are hashes, thought big and small would just be certificate / certificate + chain. If your other station is basically stealth and only listing, you'll need to insert the certificate manually, yes.

@kelunik confirmed. I added the aa.cert directly to the cert_cache at the RX and now even without forcing the client (CAM/DENM) to send the full chain, I can decode all packets.

Thanks a lot for you time and help...