1#include <vanetza/common/its_aid.hpp>
2#include <vanetza/common/position_provider.hpp>
3#include <vanetza/common/runtime.hpp>
4#include <vanetza/security/backend.hpp>
5#include <vanetza/security/public_key.hpp>
6#include <vanetza/security/straight_verify_service.hpp>
7#include <vanetza/security/v2/basic_elements.hpp>
8#include <vanetza/security/v2/certificate_cache.hpp>
9#include <vanetza/security/v2/certificate_provider.hpp>
10#include <vanetza/security/v2/certificate_validator.hpp>
11#include <vanetza/security/v2/sign_header_policy.hpp>
12#include <vanetza/security/v2/verification.hpp>
13#include <vanetza/security/v3/asn1_conversions.hpp>
14#include <vanetza/security/v3/asn1_types.hpp>
15#include <vanetza/security/v3/certificate_cache.hpp>
16#include <vanetza/security/v3/certificate_provider.hpp>
17#include <vanetza/security/v3/certificate_validator.hpp>
18#include <vanetza/security/v3/hash.hpp>
19#include <vanetza/security/v3/sign_header_policy.hpp>
20#include <boost/optional.hpp>
23struct Vanetza_Security_Certificate :
public Vanetza_Security_CertificateBase {};
35 for (
auto& subject_attribute : certificate.subject_attributes) {
36 if (get_type(subject_attribute) != v2::SubjectAttributeType::ITS_AID_SSP_List) {
40 auto& permissions = boost::get<std::list<v2::ItsAidSsp> >(subject_attribute);
41 for (
auto& permission : permissions) {
42 if (permission.its_aid == confirm.its_aid) {
43 confirm.permissions = permission.service_specific_permissions;
57 m_runtime(runtime), m_backend(backend)
62 m_runtime(runtime), m_backend(backend), m_position_provider(&position)
68 m_context_v2.m_cert_cache = cache;
73 m_context_v2.m_cert_provider = provider;
78 m_context_v2.m_cert_validator = validator;
83 m_context_v2.m_sign_policy = policy;
90 use_certificate_cache(&provider
->cache());
96 m_context_v3.m_cert_cache = cache;
101 m_context_v3.m_cert_validator = validator;
106 m_context_v3.m_sign_policy = policy;
111 struct visitor :
public boost::static_visitor<VerifyConfirm>
119 return m_service->verify(msg);
124 return m_service->verify(msg);
130 return boost::apply_visitor(visitor, request.secured_message);
139 if (PayloadType::Signed != secured_message.payload.type) {
140 confirm.report = VerificationReport::Unsigned_Message;
144 if (2 != secured_message.protocol_version()) {
145 confirm.report = VerificationReport::Incompatible_Protocol;
149 if (!m_context_v2.complete() || !m_position_provider) {
150 confirm.report = VerificationReport::Configuration_Problem;
159 const std::list<HashedId3>* requested_certs = secured_message.header_field<HeaderFieldType::Request_Unrecognized_Certificate>();
160 if (requested_certs) {
161 for (
auto& requested_cert : *requested_certs) {
162 if (truncate(calculate_hash(cert_provider.own_certificate())) == requested_cert) {
163 sign_policy.request_certificate();
166 for (
auto& cert : cert_provider.own_chain()) {
167 if (truncate(calculate_hash(cert)) == requested_cert) {
168 sign_policy.request_certificate_chain();
174 const IntX* its_aid = secured_message.header_field<HeaderFieldType::Its_Aid>();
177 confirm.report = VerificationReport::Incompatible_Protocol;
180 confirm.its_aid = its_aid->get();
182 const SignerInfo* signer_info = secured_message.header_field<HeaderFieldType::Signer_Info>();
183 std::list<v2::Certificate> possible_certificates;
184 bool possible_certificates_from_cache =
false;
187 HashedId8 signer_hash;
188 signer_hash.fill(0x00);
191 switch (get_type(*signer_info)) {
192 case SignerInfoType::Certificate:
193 possible_certificates.push_back(boost::get<v2::
Certificate>(*signer_info));
194 signer_hash = calculate_hash(boost::get<v2::
Certificate>(*signer_info));
196 if (confirm.its_aid == aid::CA && cert_cache.lookup(signer_hash, SubjectType::Authorization_Ticket).size() == 0) {
203 case SignerInfoType::Certificate_Digest_With_SHA256:
204 signer_hash = boost::get<HashedId8>(*signer_info);
205 possible_certificates.splice(possible_certificates.end(), cert_cache.lookup(signer_hash, SubjectType::Authorization_Ticket));
206 possible_certificates_from_cache =
true;
208 case SignerInfoType::Certificate_Chain:
210 std::list<v2::Certificate> chain = boost::get<std::list<v2::Certificate>>(*signer_info);
211 if (chain.size() == 0) {
212 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
214 }
else if (chain.size() > 3) {
217 confirm.report = VerificationReport::Invalid_Certificate;
221 for (
auto& cert : chain) {
223 if (cert.subject_info.subject_type == SubjectType::Authorization_Authority) {
225 CertificateValidity validity = cert_validator.check_certificate(cert);
229 confirm.report = VerificationReport::Invalid_Certificate;
230 confirm.certificate_validity = validity;
237 if (!check_certificate_time(cert, m_runtime.now()) || !check_certificate_region(cert, m_position_provider->position_fix())) {
238 confirm.report = VerificationReport::Invalid_Certificate;
242 cert_cache.insert(cert);
246 signer_hash = calculate_hash(chain.back());
247 possible_certificates.push_back(chain.back());
251 confirm.report = VerificationReport::Unsupported_Signer_Identifier_Type;
257 if (possible_certificates.size() == 0) {
258 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
259 confirm.certificate_id = signer_hash;
264 if (!check_generation_time(secured_message, m_runtime
.now())) {
265 confirm.report = VerificationReport::Invalid_Timestamp;
272 const TrailerField* signature_field = secured_message
.trailer_field(TrailerFieldType::Signature
);
276 confirm.report = VerificationReport::Unsigned_Message;
280 if (PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256 != get_type(*signature)) {
281 confirm.report = VerificationReport::False_Signature;
286 auto ecdsa = extract_ecdsa_signature(*signature);
287 const auto field_len = field_size(PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256);
288 if (!ecdsa || ecdsa->s.size() != field_len) {
289 confirm.report = VerificationReport::False_Signature;
294 ByteBuffer payload = convert_for_signing(secured_message, secured_message.trailer_fields);
297 for (
const auto& cert : possible_certificates) {
298 SubjectType subject_type = cert.subject_info.subject_type;
299 if (subject_type != SubjectType::Authorization_Ticket) {
300 confirm.report = VerificationReport::Invalid_Certificate;
301 confirm.certificate_validity = CertificateInvalidReason::Invalid_Signer;
305 boost::optional<ecdsa256::PublicKey> public_key = get_public_key(cert, m_backend);
309 confirm.report = VerificationReport::Invalid_Certificate;
310 confirm.certificate_validity = CertificateInvalidReason::Missing_Public_Key;
314 if (m_backend.verify_data(public_key.get(), payload, *ecdsa)) {
323 if (signer_info && get_type(*signer_info) == SignerInfoType::Certificate_Digest_With_SHA256) {
325 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
328 confirm.report = VerificationReport::False_Signature;
331 confirm.certificate_id = signer_hash;
337 if (!check_generation_location(secured_message, *signer)) {
338 confirm.report = VerificationReport::Invalid_Certificate;
339 confirm.certificate_validity = CertificateInvalidReason::Off_Region;
344 if (!possible_certificates_from_cache) {
348 confirm.certificate_validity = cert_validity;
351 if (!cert_validity) {
352 confirm.report = VerificationReport::Invalid_Certificate;
354 if (cert_validity
.reason() == CertificateInvalidReason::Unknown_Signer) {
355 if (get_type(signer->signer_info) == SignerInfoType::Certificate_Digest_With_SHA256) {
356 auto signer_hash = boost::get<HashedId8>(signer->signer_info);
357 confirm.certificate_id = signer_hash;
365 if (!check_certificate_time(*signer, m_runtime
.now())) {
366 confirm.report = VerificationReport::Invalid_Certificate;
367 confirm.certificate_validity = CertificateInvalidReason::Off_Time_Period;
371 if (!check_certificate_region(*signer, m_position_provider
->position_fix())) {
372 confirm.report = VerificationReport::Invalid_Certificate;
373 confirm.certificate_validity = CertificateInvalidReason::Off_Region;
379 if (!assign_permissions(*signer, confirm)) {
381 confirm.report = VerificationReport::Invalid_Certificate;
382 confirm.certificate_validity = CertificateInvalidReason::Insufficient_ITS_AID;
389 confirm.report = VerificationReport::Success;
396
397
398
400 confirm.report = VerificationReport::Incompatible_Protocol;
402 if (!msg.is_signed()) {
403 confirm.report = VerificationReport::Unsigned_Message;
407 if (msg.protocol_version() != 3) {
408 confirm.report = VerificationReport::Incompatible_Protocol;
412 auto gen_time = msg.generation_time();
415 confirm.report = VerificationReport::Invalid_Timestamp;
420 auto signature = msg.signature();
422 confirm.report = VerificationReport::Unsigned_Message;
426 struct certificate_lookup_visitor :
public boost::static_visitor<
const v3::asn1::Certificate*> {
432 const v3::asn1::Certificate* operator()(
const v3::asn1::HashedId8* digest)
435 if (m_cache && digest) {
436 const v3::
Certificate* found = m_cache->lookup(v3::convert(*digest));
437 return found ? found->content() :
nullptr;
443 const v3::asn1::Certificate* operator()(
const v3::asn1::Certificate* cert)
449 } certificate_lookup_visitor(m_context_v3.m_cert_cache);
450 auto signer_identifier = msg.signer_identifier();
453 auto maybe_digest = v3::get_certificate_id(signer_identifier);
454 if (m_context_v3.m_cert_cache && maybe_digest) {
455 bool was_unknown_station = m_context_v3.m_cert_cache
->announce(*maybe_digest
);
456 if (was_unknown_station && msg.its_aid() == aid::CA && m_context_v3.m_sign_policy) {
463 if (msg.its_aid() == aid::CA && m_context_v3.m_sign_policy) {
464 Vanetza_Security_SequenceOfHashedId3* requests = msg->content->choice.signedData->tbsData->headerInfo.inlineP2pcdRequest;
466 for (
int i = 0; i < requests->list.count; ++i)
468 const Vanetza_Security_HashedId3_t* req_digest = requests->list.array[i];
469 const HashedId3 hid3 = create_hashed_id3(*req_digest);
474 Vanetza_Security_Certificate* included_cert = msg->content->choice.signedData->tbsData->headerInfo.requestedCertificate;
476 auto maybe_digest = v3::calculate_digest(*included_cert);
483 const v3::asn1::Certificate* certificate = boost::apply_visitor(certificate_lookup_visitor, signer_identifier);
485 if (msg.its_aid() == aid::CA && m_context_v3.m_sign_policy && maybe_digest) {
489 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
494 assert(certificate !=
nullptr);
497 if (m_context_v3.m_cert_validator) {
500 confirm.report = VerificationReport::Invalid_Certificate;
505 boost::optional<HashedId8> aa_digest;
506 switch (certificate->issuer.present)
508 case Vanetza_Security_IssuerIdentifier_PR_sha256AndDigest:
509 aa_digest = v3::convert(certificate->issuer.choice.sha256AndDigest);
511 case Vanetza_Security_IssuerIdentifier_PR_sha384AndDigest:
512 aa_digest = v3::convert(certificate->issuer.choice.sha384AndDigest);
518 if (aa_digest && m_context_v3.m_cert_cache) {
520 if (m_context_v3.m_sign_policy) {
528 auto public_key = v3::get_public_key(*certificate);
530 confirm.report = VerificationReport::Invalid_Certificate;
531 confirm.certificate_validity = CertificateInvalidReason::Missing_Public_Key;
535 ByteBuffer msg_hash = v3::calculate_message_hash(m_backend, msg.hash_id(),
537 if (!m_backend.verify_digest(*public_key, msg_hash, *signature)) {
538 confirm.report = VerificationReport::False_Signature;
542 confirm.its_aid = msg.its_aid();
543 confirm.permissions = v3::get_app_permissions(*certificate, confirm.its_aid);
544 confirm.certificate_id = maybe_digest;
545 confirm.report = VerificationReport::Success;
547 if (m_context_v3.m_cert_cache && confirm.certificate_id) {
549 bool already_cached = cache.lookup(*confirm.certificate_id) !=
nullptr;
550 if (!already_cached && confirm.its_aid == aid::CA && m_context_v3.m_sign_policy) {
556 if (v3::contains_certificate(signer_identifier)) {
virtual const PositionFix & position_fix()=0
virtual Clock::time_point now() const =0
static CertificateValidity valid()
Create CertificateValidity signalling a valid certificate This method is equivalent to default constr...
CertificateInvalidReason reason() const
Get reason for certificate invalidity This call is only safe if reason is available,...
void insert(const Certificate &certificate)
virtual CertificateValidity check_certificate(const Certificate &certificate)=0
IntX specified in TS 103 097 v1.2.1, section 4.2.1.
bool is_known(const HashedId8 &digest) const
bool announce(const HashedId8 &digest)
void store(Certificate cert)
virtual CertificateCache & cache()=0
virtual Verdict valid_for_signing(const CertificateView &certificate, ItsAid app)=0
described in TS 103 097 v1.2.1 (2015-06), section 6.1
SecuredMessage as specified in TS 103 097 v1.2.1, section 5.1.
const TrailerField * trailer_field(TrailerFieldType type) const