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/certificate_cache.hpp>
15#include <boost/optional.hpp>
25bool assign_permissions(
const v2::Certificate& certificate, VerifyConfirm& confirm)
27 for (
auto& subject_attribute : certificate.subject_attributes) {
28 if (get_type(subject_attribute) != v2::SubjectAttributeType::ITS_AID_SSP_List) {
32 auto& permissions = boost::get<std::list<v2::ItsAidSsp> >(subject_attribute);
33 for (
auto& permission : permissions) {
34 if (permission.its_aid == confirm.its_aid) {
35 confirm.permissions = permission.service_specific_permissions;
49StraightVerifyService::StraightVerifyService(
const Runtime& runtime, Backend& backend, PositionProvider& position) :
50 m_runtime(runtime), m_backend(backend),m_position_provider(position)
54void StraightVerifyService::use_certificate_cache(v2::CertificateCache* cache)
56 m_context_v2.m_cert_cache = cache;
59void StraightVerifyService::use_certificate_provider(v2::CertificateProvider* provider)
61 m_context_v2.m_cert_provider = provider;
64void StraightVerifyService::use_certitifcate_validator(v2::CertificateValidator* validator)
66 m_context_v2.m_cert_validator = validator;
69void StraightVerifyService::use_sign_header_policy(v2::SignHeaderPolicy* policy)
71 m_context_v2.m_sign_policy = policy;
74void StraightVerifyService::use_certificate_cache(v3::CertificateCache* cache)
76 m_context_v3.m_cert_cache = cache;
79VerifyConfirm StraightVerifyService::verify(VerifyRequest&& request)
81 struct visitor :
public boost::static_visitor<VerifyConfirm>
83 visitor(StraightVerifyService* service) : m_service(service)
87 VerifyConfirm operator()(
const v2::SecuredMessage& msg)
89 return m_service->verify(msg);
92 VerifyConfirm operator()(
const v3::SecuredMessage& msg)
94 return m_service->verify(msg);
97 StraightVerifyService* m_service =
nullptr;
100 const SecuredMessage& secured_message = request.secured_message;
101 return boost::apply_visitor(visitor, secured_message);
104VerifyConfirm StraightVerifyService::verify(
const v2::SecuredMessage& secured_message)
107 VerifyConfirm confirm;
110 if (PayloadType::Signed != secured_message.payload.type) {
111 confirm.report = VerificationReport::Unsigned_Message;
115 if (2 != secured_message.protocol_version()) {
116 confirm.report = VerificationReport::Incompatible_Protocol;
120 if (!m_context_v2.complete()) {
121 confirm.report = VerificationReport::Configuration_Problem;
125 v2::CertificateProvider& cert_provider = *m_context_v2.m_cert_provider;
126 v2::CertificateCache& cert_cache = *m_context_v2.m_cert_cache;
127 v2::CertificateValidator& cert_validator = *m_context_v2.m_cert_validator;
128 v2::SignHeaderPolicy& sign_policy = *m_context_v2.m_sign_policy;
130 const std::list<HashedId3>* requested_certs = secured_message.header_field<HeaderFieldType::Request_Unrecognized_Certificate>();
131 if (requested_certs) {
132 for (
auto& requested_cert : *requested_certs) {
133 if (truncate(calculate_hash(cert_provider.own_certificate())) == requested_cert) {
134 sign_policy.request_certificate();
137 for (
auto& cert : cert_provider.own_chain()) {
138 if (truncate(calculate_hash(cert)) == requested_cert) {
139 sign_policy.request_certificate_chain();
145 const IntX* its_aid = secured_message.header_field<HeaderFieldType::Its_Aid>();
148 confirm.report = VerificationReport::Incompatible_Protocol;
151 confirm.its_aid = its_aid->get();
153 const SignerInfo* signer_info = secured_message.header_field<HeaderFieldType::Signer_Info>();
154 std::list<v2::Certificate> possible_certificates;
155 bool possible_certificates_from_cache =
false;
158 HashedId8 signer_hash;
159 signer_hash.fill(0x00);
162 switch (get_type(*signer_info)) {
163 case SignerInfoType::Certificate:
164 possible_certificates.push_back(boost::get<v2::Certificate>(*signer_info));
165 signer_hash = calculate_hash(boost::get<v2::Certificate>(*signer_info));
167 if (confirm.its_aid == aid::CA && cert_cache.lookup(signer_hash, SubjectType::Authorization_Ticket).size() == 0) {
170 sign_policy.request_certificate();
174 case SignerInfoType::Certificate_Digest_With_SHA256:
175 signer_hash = boost::get<HashedId8>(*signer_info);
176 possible_certificates.splice(possible_certificates.end(), cert_cache.lookup(signer_hash, SubjectType::Authorization_Ticket));
177 possible_certificates_from_cache =
true;
179 case SignerInfoType::Certificate_Chain:
181 std::list<v2::Certificate> chain = boost::get<std::list<v2::Certificate>>(*signer_info);
182 if (chain.size() == 0) {
183 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
185 }
else if (chain.size() > 3) {
188 confirm.report = VerificationReport::Invalid_Certificate;
192 for (
auto& cert : chain) {
194 if (cert.subject_info.subject_type == SubjectType::Authorization_Authority) {
196 CertificateValidity validity = cert_validator.check_certificate(cert);
200 confirm.report = VerificationReport::Invalid_Certificate;
201 confirm.certificate_validity = validity;
208 if (!check_certificate_time(cert, m_runtime.now()) || !check_certificate_region(cert, m_position_provider.position_fix())) {
209 confirm.report = VerificationReport::Invalid_Certificate;
213 cert_cache.insert(cert);
217 signer_hash = calculate_hash(chain.back());
218 possible_certificates.push_back(chain.back());
222 confirm.report = VerificationReport::Unsupported_Signer_Identifier_Type;
228 if (possible_certificates.size() == 0) {
229 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
230 confirm.certificate_id = signer_hash;
231 sign_policy.request_unrecognized_certificate(signer_hash);
235 if (!check_generation_time(secured_message, m_runtime.now())) {
236 confirm.report = VerificationReport::Invalid_Timestamp;
243 const TrailerField* signature_field = secured_message.trailer_field(TrailerFieldType::Signature);
244 const v2::Signature* signature = boost::get<v2::Signature>(signature_field);
247 confirm.report = VerificationReport::Unsigned_Message;
251 if (PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256 != get_type(*signature)) {
252 confirm.report = VerificationReport::False_Signature;
257 auto ecdsa = extract_ecdsa_signature(*signature);
258 const auto field_len = field_size(PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256);
259 if (!ecdsa || ecdsa->s.size() != field_len) {
260 confirm.report = VerificationReport::False_Signature;
265 ByteBuffer payload = convert_for_signing(secured_message, secured_message.trailer_fields);
266 boost::optional<v2::Certificate> signer;
268 for (
const auto& cert : possible_certificates) {
269 SubjectType subject_type = cert.subject_info.subject_type;
270 if (subject_type != SubjectType::Authorization_Ticket) {
271 confirm.report = VerificationReport::Invalid_Certificate;
272 confirm.certificate_validity = CertificateInvalidReason::Invalid_Signer;
276 boost::optional<ecdsa256::PublicKey> public_key = get_public_key(cert, m_backend);
280 confirm.report = VerificationReport::Invalid_Certificate;
281 confirm.certificate_validity = CertificateInvalidReason::Missing_Public_Key;
285 if (m_backend.verify_data(public_key.get(), payload, *ecdsa)) {
294 if (signer_info && get_type(*signer_info) == SignerInfoType::Certificate_Digest_With_SHA256) {
296 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
299 confirm.report = VerificationReport::False_Signature;
302 confirm.certificate_id = signer_hash;
303 sign_policy.request_unrecognized_certificate(signer_hash);
308 if (!check_generation_location(secured_message, *signer)) {
309 confirm.report = VerificationReport::Invalid_Certificate;
310 confirm.certificate_validity = CertificateInvalidReason::Off_Region;
314 CertificateValidity cert_validity = CertificateValidity::valid();
315 if (!possible_certificates_from_cache) {
316 cert_validity = cert_validator.check_certificate(*signer);
319 confirm.certificate_validity = cert_validity;
322 if (!cert_validity) {
323 confirm.report = VerificationReport::Invalid_Certificate;
325 if (cert_validity.reason() == CertificateInvalidReason::Unknown_Signer) {
326 if (get_type(signer->signer_info) == SignerInfoType::Certificate_Digest_With_SHA256) {
327 auto signer_hash = boost::get<HashedId8>(signer->signer_info);
328 confirm.certificate_id = signer_hash;
329 sign_policy.request_unrecognized_certificate(signer_hash);
336 if (!check_certificate_time(*signer, m_runtime.now())) {
337 confirm.report = VerificationReport::Invalid_Certificate;
338 confirm.certificate_validity = CertificateInvalidReason::Off_Time_Period;
342 if (!check_certificate_region(*signer, m_position_provider.position_fix())) {
343 confirm.report = VerificationReport::Invalid_Certificate;
344 confirm.certificate_validity = CertificateInvalidReason::Off_Region;
350 if (!assign_permissions(*signer, confirm)) {
352 confirm.report = VerificationReport::Invalid_Certificate;
353 confirm.certificate_validity = CertificateInvalidReason::Insufficient_ITS_AID;
358 cert_cache.insert(*signer);
360 confirm.report = VerificationReport::Success;
364VerifyConfirm StraightVerifyService::verify(
const v3::SecuredMessage& msg)
370 VerifyConfirm confirm;
371 confirm.report = VerificationReport::Incompatible_Protocol;
373 if (!msg.is_signed()) {
374 confirm.report = VerificationReport::Unsigned_Message;
378 if (msg.protocol_version() != 3) {
379 confirm.report = VerificationReport::Incompatible_Protocol;
383 auto gen_time = msg.generation_time();
386 confirm.report = VerificationReport::Invalid_Timestamp;
391 auto signature = msg.signature();
393 confirm.report = VerificationReport::Unsigned_Message;
397 struct certificate_lookup_visitor :
public boost::static_visitor<const Certificate_t*> {
398 certificate_lookup_visitor(v3::CertificateCache* cache) : m_cache(cache)
405 if (m_cache && digest) {
406 const v3::Certificate* found = m_cache->lookup(v3::convert(*digest));
407 return found ? found->content() :
nullptr;
418 v3::CertificateCache* m_cache;
419 } certificate_lookup_visitor(m_context_v3.m_cert_cache);
420 auto signer_identifier = msg.signer_identifier();
421 const Certificate_t* certificate = boost::apply_visitor(certificate_lookup_visitor, signer_identifier);
423 confirm.report = VerificationReport::Signer_Certificate_Not_Found;
428 auto public_key = v3::get_public_key(*certificate);
430 confirm.report = VerificationReport::Invalid_Certificate;
431 confirm.certificate_validity = CertificateInvalidReason::Missing_Public_Key;
435 ByteBuffer data_hash = m_backend.calculate_hash(public_key->type, msg.signing_payload());
436 ByteBuffer cert_hash = m_backend.calculate_hash(public_key->type, asn1::encode_oer(asn_DEF_CertificateBase, certificate));
437 ByteBuffer concat_hash = data_hash;
438 concat_hash.insert(concat_hash.end(), cert_hash.begin(), cert_hash.end());
439 ByteBuffer msg_hash = m_backend.calculate_hash(public_key->type, concat_hash);
441 if (!m_backend.verify_digest(*public_key, msg_hash, *signature)) {
442 confirm.report = VerificationReport::False_Signature;
446 confirm.its_aid = msg.its_aid();
447 confirm.permissions = v3::get_app_permissions(*certificate, confirm.its_aid);
448 confirm.certificate_id = v3::get_certificate_id(signer_identifier);
449 confirm.report = VerificationReport::Success;