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;
57StraightVerifyService::StraightVerifyService(
const Runtime& runtime,
Backend& backend, PositionProvider& position) :
58 m_runtime(runtime), m_backend(backend),m_position_provider(position)
62void StraightVerifyService::use_certificate_cache(v2::CertificateCache* cache)
64 m_context_v2.m_cert_cache = cache;
67void StraightVerifyService::use_certificate_provider(v2::CertificateProvider* provider)
69 m_context_v2.m_cert_provider = provider;
72void StraightVerifyService::use_certificate_validator(v2::CertificateValidator* validator)
74 m_context_v2.m_cert_validator = validator;
77void StraightVerifyService::use_sign_header_policy(v2::SignHeaderPolicy* policy)
79 m_context_v2.m_sign_policy = policy;
82void StraightVerifyService::use_certificate_provider(v3::CertificateProvider* provider)
84 m_context_v3.m_cert_provider = provider;
87void StraightVerifyService::use_certificate_validator(v3::CertificateValidator* validator)
89 m_context_v3.m_cert_validator = validator;
92void StraightVerifyService::use_sign_header_policy(v3::SignHeaderPolicy* policy)
94 m_context_v3.m_sign_policy = policy;
97VerifyConfirm StraightVerifyService::verify(
const VerifyRequest& request)
99 struct visitor :
public boost::static_visitor<VerifyConfirm>
101 visitor(StraightVerifyService* service) : m_service(service)
105 VerifyConfirm operator()(
const v2::SecuredMessage& msg)
107 return m_service->verify(msg);
110 VerifyConfirm operator()(
const v3::SecuredMessage& msg)
112 return m_service->verify(msg);
115 StraightVerifyService* m_service =
nullptr;
118 return boost::apply_visitor(visitor, request.secured_message);
121VerifyConfirm StraightVerifyService::verify(
const v2::SecuredMessage& secured_message)
124 VerifyConfirm confirm;
127 if (PayloadType::Signed != secured_message.payload.type) {
128 confirm.report = VerificationReport::Unsigned_Message;
132 if (2 != secured_message.protocol_version()) {
133 confirm.report = VerificationReport::Incompatible_Protocol;
137 if (!m_context_v2.complete()) {
138 confirm.report = VerificationReport::Configuration_Problem;
142 v2::CertificateProvider& cert_provider = *m_context_v2.m_cert_provider;
143 v2::CertificateCache& cert_cache = *m_context_v2.m_cert_cache;
144 v2::CertificateValidator& cert_validator = *m_context_v2.m_cert_validator;
145 v2::SignHeaderPolicy& sign_policy = *m_context_v2.m_sign_policy;
147 const std::list<HashedId3>* requested_certs = secured_message.header_field<HeaderFieldType::Request_Unrecognized_Certificate>();
148 if (requested_certs) {
149 for (
auto& requested_cert : *requested_certs) {
150 if (truncate(calculate_hash(cert_provider.own_certificate())) == requested_cert) {
151 sign_policy.request_certificate();
154 for (
auto& cert : cert_provider.own_chain()) {
155 if (truncate(calculate_hash(cert)) == requested_cert) {
156 sign_policy.request_certificate_chain();
162 const IntX* its_aid = secured_message.header_field<HeaderFieldType::Its_Aid>();
165 confirm.report = VerificationReport::Incompatible_Protocol;
168 confirm.its_aid = its_aid->get();
170 const SignerInfo* signer_info = secured_message.header_field<HeaderFieldType::Signer_Info>();
171 std::list<v2::Certificate> possible_certificates;
172 bool possible_certificates_from_cache =
false;
175 HashedId8 signer_hash;
176 signer_hash.fill(0x00);
179 switch (get_type(*signer_info)) {
180 case SignerInfoType::Certificate:
181 possible_certificates.push_back(boost::get<v2::Certificate>(*signer_info));
182 signer_hash = calculate_hash(boost::get<v2::Certificate>(*signer_info));
184 if (confirm.its_aid == aid::CA && cert_cache.lookup(signer_hash, SubjectType::Authorization_Ticket).size() == 0) {
187 sign_policy.request_certificate();
191 case SignerInfoType::Certificate_Digest_With_SHA256:
192 signer_hash = boost::get<HashedId8>(*signer_info);
193 possible_certificates.splice(possible_certificates.end(), cert_cache.lookup(signer_hash, SubjectType::Authorization_Ticket));
194 possible_certificates_from_cache =
true;
196 case SignerInfoType::Certificate_Chain:
198 std::list<v2::Certificate> chain = boost::get<std::list<v2::Certificate>>(*signer_info);
199 if (chain.size() == 0) {
200 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
202 }
else if (chain.size() > 3) {
205 confirm.report = VerificationReport::Invalid_Certificate;
209 for (
auto& cert : chain) {
211 if (cert.subject_info.subject_type == SubjectType::Authorization_Authority) {
213 CertificateValidity validity = cert_validator.check_certificate(cert);
217 confirm.report = VerificationReport::Invalid_Certificate;
218 confirm.certificate_validity = validity;
225 if (!check_certificate_time(cert, m_runtime.now()) || !check_certificate_region(cert, m_position_provider.position_fix())) {
226 confirm.report = VerificationReport::Invalid_Certificate;
230 cert_cache.insert(cert);
234 signer_hash = calculate_hash(chain.back());
235 possible_certificates.push_back(chain.back());
239 confirm.report = VerificationReport::Unsupported_Signer_Identifier_Type;
245 if (possible_certificates.size() == 0) {
246 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
247 confirm.certificate_id = signer_hash;
248 sign_policy.request_unrecognized_certificate(signer_hash);
252 if (!check_generation_time(secured_message, m_runtime.now())) {
253 confirm.report = VerificationReport::Invalid_Timestamp;
260 const TrailerField* signature_field = secured_message.trailer_field(TrailerFieldType::Signature);
261 const v2::Signature* signature = boost::get<v2::Signature>(signature_field);
264 confirm.report = VerificationReport::Unsigned_Message;
268 if (PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256 != get_type(*signature)) {
269 confirm.report = VerificationReport::False_Signature;
274 auto ecdsa = extract_ecdsa_signature(*signature);
275 const auto field_len = field_size(PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256);
276 if (!ecdsa || ecdsa->s.size() != field_len) {
277 confirm.report = VerificationReport::False_Signature;
282 ByteBuffer payload = convert_for_signing(secured_message, secured_message.trailer_fields);
283 boost::optional<v2::Certificate> signer;
285 for (
const auto& cert : possible_certificates) {
286 SubjectType subject_type = cert.subject_info.subject_type;
287 if (subject_type != SubjectType::Authorization_Ticket) {
288 confirm.report = VerificationReport::Invalid_Certificate;
289 confirm.certificate_validity = CertificateInvalidReason::Invalid_Signer;
293 boost::optional<ecdsa256::PublicKey> public_key = get_public_key(cert, m_backend);
297 confirm.report = VerificationReport::Invalid_Certificate;
298 confirm.certificate_validity = CertificateInvalidReason::Missing_Public_Key;
302 if (m_backend.verify_data(public_key.get(), payload, *ecdsa)) {
311 if (signer_info && get_type(*signer_info) == SignerInfoType::Certificate_Digest_With_SHA256) {
313 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
316 confirm.report = VerificationReport::False_Signature;
319 confirm.certificate_id = signer_hash;
320 sign_policy.request_unrecognized_certificate(signer_hash);
325 if (!check_generation_location(secured_message, *signer)) {
326 confirm.report = VerificationReport::Invalid_Certificate;
327 confirm.certificate_validity = CertificateInvalidReason::Off_Region;
331 CertificateValidity cert_validity = CertificateValidity::valid();
332 if (!possible_certificates_from_cache) {
333 cert_validity = cert_validator.check_certificate(*signer);
336 confirm.certificate_validity = cert_validity;
339 if (!cert_validity) {
340 confirm.report = VerificationReport::Invalid_Certificate;
342 if (cert_validity.reason() == CertificateInvalidReason::Unknown_Signer) {
343 if (get_type(signer->signer_info) == SignerInfoType::Certificate_Digest_With_SHA256) {
344 auto signer_hash = boost::get<HashedId8>(signer->signer_info);
345 confirm.certificate_id = signer_hash;
346 sign_policy.request_unrecognized_certificate(signer_hash);
353 if (!check_certificate_time(*signer, m_runtime.now())) {
354 confirm.report = VerificationReport::Invalid_Certificate;
355 confirm.certificate_validity = CertificateInvalidReason::Off_Time_Period;
359 if (!check_certificate_region(*signer, m_position_provider.position_fix())) {
360 confirm.report = VerificationReport::Invalid_Certificate;
361 confirm.certificate_validity = CertificateInvalidReason::Off_Region;
367 if (!assign_permissions(*signer, confirm)) {
369 confirm.report = VerificationReport::Invalid_Certificate;
370 confirm.certificate_validity = CertificateInvalidReason::Insufficient_ITS_AID;
375 cert_cache.insert(*signer);
377 confirm.report = VerificationReport::Success;
381VerifyConfirm StraightVerifyService::verify(
const v3::SecuredMessage& msg)
387 VerifyConfirm confirm;
388 confirm.report = VerificationReport::Incompatible_Protocol;
390 if (!msg.is_signed()) {
391 confirm.report = VerificationReport::Unsigned_Message;
395 if (msg.protocol_version() != 3) {
396 confirm.report = VerificationReport::Incompatible_Protocol;
400 auto gen_time = msg.generation_time();
403 confirm.report = VerificationReport::Invalid_Timestamp;
408 auto signature = msg.signature();
410 confirm.report = VerificationReport::Unsigned_Message;
414 struct certificate_lookup_visitor :
public boost::static_visitor<const v3::asn1::Certificate*> {
415 certificate_lookup_visitor(v3::CertificateProvider* provider) :
416 m_cache(provider != nullptr ? &provider->cache() : nullptr)
420 const v3::asn1::Certificate* operator()(
const v3::asn1::HashedId8* digest)
423 if (m_cache && digest) {
424 const v3::Certificate* found = m_cache->lookup(v3::convert(*digest));
425 return found ? found->content() :
nullptr;
431 const v3::asn1::Certificate* operator()(
const v3::asn1::Certificate* cert)
436 v3::CertificateCache* m_cache;
437 } certificate_lookup_visitor(m_context_v3.m_cert_provider);
438 auto signer_identifier = msg.signer_identifier();
441 auto maybe_digest = v3::get_certificate_id(signer_identifier);
442 if (m_context_v3.m_cert_provider && maybe_digest) {
443 bool was_unknown_station = m_context_v3.m_cert_provider->cache().announce(*maybe_digest);
444 if (was_unknown_station && msg.its_aid() == aid::CA && m_context_v3.m_sign_policy) {
446 m_context_v3.m_sign_policy->request_certificate();
451 if (msg.its_aid() == aid::CA && m_context_v3.m_sign_policy && m_context_v3.m_cert_provider) {
452 Vanetza_Security_SequenceOfHashedId3* requests = msg->content->choice.signedData->tbsData->headerInfo.inlineP2pcdRequest;
454 for (
int i = 0; i < requests->list.count; ++i)
456 const Vanetza_Security_HashedId3_t* req_digest = requests->list.array[i];
457 const HashedId3 hid3 = create_hashed_id3(*req_digest);
458 m_context_v3.m_sign_policy->enqueue_p2p_request(hid3);
462 Vanetza_Security_Certificate* included_cert = msg->content->choice.signedData->tbsData->headerInfo.requestedCertificate;
464 auto maybe_digest = v3::calculate_digest(*included_cert);
466 m_context_v3.m_sign_policy->discard_p2p_request(truncate(*maybe_digest));
471 const v3::asn1::Certificate* certificate = boost::apply_visitor(certificate_lookup_visitor, signer_identifier);
473 if (msg.its_aid() == aid::CA && m_context_v3.m_sign_policy && maybe_digest) {
475 m_context_v3.m_sign_policy->request_unrecognized_certificate(*maybe_digest);
477 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
482 assert(certificate !=
nullptr);
485 if (m_context_v3.m_cert_validator) {
486 auto verdict = m_context_v3.m_cert_validator->valid_for_signing(v3::CertificateView { certificate }, msg.its_aid());
487 if (verdict != v3::CertificateValidator::Verdict::Valid) {
488 confirm.report = VerificationReport::Invalid_Certificate;
493 boost::optional<HashedId8> aa_digest;
494 switch (certificate->issuer.present)
496 case Vanetza_Security_IssuerIdentifier_PR_sha256AndDigest:
497 aa_digest = v3::convert(certificate->issuer.choice.sha256AndDigest);
499 case Vanetza_Security_IssuerIdentifier_PR_sha384AndDigest:
500 aa_digest = v3::convert(certificate->issuer.choice.sha384AndDigest);
506 if (aa_digest && m_context_v3.m_cert_provider) {
507 if (!m_context_v3.m_cert_provider->cache().is_known(*aa_digest)) {
508 if (m_context_v3.m_sign_policy) {
510 m_context_v3.m_sign_policy->request_unrecognized_certificate(*aa_digest);
516 auto public_key = v3::get_public_key(*certificate);
518 confirm.report = VerificationReport::Invalid_Certificate;
519 confirm.certificate_validity = CertificateInvalidReason::Missing_Public_Key;
523 ByteBuffer msg_hash = v3::calculate_message_hash(m_backend, msg.hash_id(),
524 msg.signing_payload(), v3::CertificateView { certificate });
525 if (!m_backend.verify_digest(*public_key, msg_hash, *signature)) {
526 confirm.report = VerificationReport::False_Signature;
530 confirm.its_aid = msg.its_aid();
531 confirm.permissions = v3::get_app_permissions(*certificate, confirm.its_aid);
532 confirm.certificate_id = maybe_digest;
533 confirm.report = VerificationReport::Success;
535 if (m_context_v3.m_cert_provider && confirm.certificate_id) {
536 v3::CertificateCache& cache = m_context_v3.m_cert_provider->cache();
537 bool already_cached = cache.lookup(*confirm.certificate_id) !=
nullptr;
538 if (!already_cached && confirm.its_aid == aid::CA && m_context_v3.m_sign_policy) {
540 m_context_v3.m_sign_policy->request_certificate();
544 if (v3::contains_certificate(signer_identifier)) {
545 cache.store(v3::Certificate { *certificate });
described in TS 103 097 v1.2.1 (2015-06), section 6.1