#include "security.hpp" #include "certificate_validation_v3.hpp" #include #include #include #include #include #include "vanetza/security/v2/certificate_provider.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace vanetza; namespace po = boost::program_options; class SecurityContextV2 : public security::SecurityEntity { public: SecurityContextV2(const Runtime& runtime, PositionProvider& positioning, const std::string& backend_name) : runtime(runtime), positioning(positioning), backend(security::create_backend(backend_name)), sign_header_policy(runtime, positioning), cert_cache(runtime), cert_validator(*backend, cert_cache, trust_store) { } security::EncapConfirm encapsulate_packet(security::EncapRequest&& request) override { if (!entity) { throw std::runtime_error("security entity is not ready"); } return entity->encapsulate_packet(std::move(request)); } security::DecapConfirm decapsulate_packet(security::DecapRequest&& request) override { if (!entity) { throw std::runtime_error("security entity is not ready"); } return entity->decapsulate_packet(std::move(request)); } void build_entity() { if (!cert_provider) { throw std::runtime_error("certificate provider is missing"); } std::unique_ptr sign_service { new security::v2::StraightSignService(*cert_provider, *backend, sign_header_policy) }; std::unique_ptr verify_service { new security::StraightVerifyService(runtime, *backend, positioning) }; verify_service->use_certificate_provider(cert_provider.get()); verify_service->use_certificate_cache(&cert_cache); verify_service->use_certificate_validator(&cert_validator); verify_service->use_sign_header_policy(&sign_header_policy); entity.reset(new security::DelegatingSecurityEntity { std::move(sign_service), std::move(verify_service) }); } const Runtime& runtime; PositionProvider& positioning; std::unique_ptr backend; std::unique_ptr entity; std::unique_ptr cert_provider; security::v2::DefaultSignHeaderPolicy sign_header_policy; security::v2::TrustStore trust_store; security::v2::CertificateCache cert_cache; security::v2::DefaultCertificateValidator cert_validator; }; class SecurityContextV3 : public security::SecurityEntity { public: SecurityContextV3(const po::variables_map& options, const Runtime& runtime, PositionProvider& positioning, const std::string& backend_name, bool permissive_identified_region = false) : runtime(runtime), positioning(positioning), backend(security::create_backend(backend_name)), country_database(geodesy::CountryDatabase::embedded()) { location_checker.set_permissive_identified_region(permissive_identified_region); location_checker.use_country_database(&country_database); certificate_validation = create_certificate_validation_v3( options, runtime, positioning, location_checker, *backend); } security::EncapConfirm encapsulate_packet(security::EncapRequest&& request) override { if (!entity) { throw std::runtime_error("security entity is not ready"); } return entity->encapsulate_packet(std::move(request)); } security::DecapConfirm decapsulate_packet(security::DecapRequest&& request) override { if (!entity) { throw std::runtime_error("security entity is not ready"); } return entity->decapsulate_packet(std::move(request)); } void build_entity() { if (!cert_provider) { throw std::runtime_error("certificate provider is missing"); } auto& cert_validator = certificate_validation->validator(); sign_header_policy.reset(new security::v3::DefaultSignHeaderPolicy(runtime, positioning, *cert_provider)); std::unique_ptr sign_service { new security::v3::StraightSignService(*cert_provider, *backend, *sign_header_policy, cert_validator) }; std::unique_ptr verify_service { new security::StraightVerifyService(runtime, *backend, positioning) }; verify_service->use_certificate_provider(cert_provider.get()); verify_service->use_certificate_validator(&cert_validator); verify_service->use_sign_header_policy(sign_header_policy.get()); entity.reset(new security::DelegatingSecurityEntity { std::move(sign_service), std::move(verify_service) }); } const Runtime& runtime; PositionProvider& positioning; std::unique_ptr backend; geodesy::CountryDatabase country_database; security::v3::DefaultLocationChecker location_checker; std::unique_ptr cert_provider; std::unique_ptr sign_header_policy; std::unique_ptr certificate_validation; std::unique_ptr entity; }; std::unique_ptr create_dummy_v2_security_entity(const Runtime& runtime) { std::unique_ptr sign_service { new security::v2::DummySignService { runtime, nullptr } }; std::unique_ptr verify_service { new security::DummyVerifyService { security::VerificationReport::Success, security::CertificateValidity::valid() } }; return std::make_unique(std::move(sign_service), std::move(verify_service)); } std::unique_ptr create_dummy_v3_security_entity(const Runtime& runtime) { std::unique_ptr sign_service { new security::v3::DummySignService { runtime } }; std::unique_ptr verify_service { new security::DummyVerifyService { security::VerificationReport::Success, security::CertificateValidity::valid() } }; return std::make_unique(std::move(sign_service), std::move(verify_service)); } std::unique_ptr load_v2_certificates(const std::string& cert_path, const std::string& cert_key_path, const std::vector cert_chain_path, security::v2::CertificateCache& cert_cache) { auto authorization_ticket = security::v2::load_certificate_from_file(cert_path); auto authorization_ticket_key = security::v2::load_private_key_from_file(cert_key_path); std::list chain; for (auto& chain_path : cert_chain_path) { auto chain_certificate = security::v2::load_certificate_from_file(chain_path); chain.push_back(chain_certificate); cert_cache.insert(chain_certificate); } return std::make_unique(authorization_ticket, authorization_ticket_key.private_key, chain); } std::unique_ptr load_v3_certificates(const std::string& cert_path, const std::string& cert_key_path, const std::vector cert_chain_path, CertificateValidationV3& validation) { auto authorization_ticket = security::v3::load_certificate_from_file(cert_path); auto authorization_ticket_key = validation.load_authorization_ticket_key(cert_key_path); auto provider = std::make_unique(authorization_ticket, authorization_ticket_key); for (auto& chain_path : cert_chain_path) { auto chain_certificate = security::v3::load_certificate_from_file(chain_path); provider->cache().store(chain_certificate); validation.add_chain_certificate(chain_certificate); } return provider; } std::unique_ptr create_security_entity(const po::variables_map& vm, const Runtime& runtime, PositionProvider& positioning) { std::unique_ptr security; const std::string name = vm["security"].as(); const std::string backend_name = vm["crypto-backend"].as(); if (name.empty() || name == "none") { // no operation } else if (name == "dummy" || name == "dummy-v3") { security = create_dummy_v3_security_entity(runtime); } else if (name == "dummy-v2") { security = create_dummy_v2_security_entity(runtime); } else if (name == "certs" || name == "certs-v3" || name == "certs-v2") { const unsigned version = name == "certs-v2" ? 2 : 3; if (vm.count("certificate") ^ vm.count("certificate-key")) { throw std::runtime_error("Either --certificate and --certificate-key must be present or none."); } if (vm.count("certificate") && vm.count("certificate-key")) { const std::string& cert_path = vm["certificate"].as(); const std::string& cert_key_path = vm["certificate-key"].as(); std::vector chain_paths; if (vm.count("certificate-chain")) { chain_paths = vm["certificate-chain"].as>(); } if (version == 3) { bool permissive_ir = vm.count("security.permissive-identified-region") && vm["security.permissive-identified-region"].as(); auto context = std::make_unique(vm, runtime, positioning, backend_name, permissive_ir); context->cert_provider = load_v3_certificates( cert_path, cert_key_path, chain_paths, *context->certificate_validation); context->build_entity(); security = std::move(context); } else { auto context = std::make_unique(runtime, positioning, backend_name); context->cert_provider = load_v2_certificates(cert_path, cert_key_path, chain_paths, context->cert_cache); if (vm.count("trusted-certificate")) { for (auto& cert_path : vm["trusted-certificate"].as >()) { auto trusted_certificate = security::v2::load_certificate_from_file(cert_path); context->trust_store.insert(trusted_certificate); } } context->build_entity(); security = std::move(context); } } else { if (version == 3) { bool permissive_ir = vm.count("security.permissive-identified-region") && vm["security.permissive-identified-region"].as(); auto context = std::make_unique(vm, runtime, positioning, backend_name, permissive_ir); auto provider = std::make_unique(runtime); context->certificate_validation->add_chain_certificate(provider->aa_certificate()); context->certificate_validation->add_chain_certificate(provider->root_certificate()); context->cert_provider = std::move(provider); context->build_entity(); security = std::move(context); } else { auto context = std::make_unique(runtime, positioning, backend_name); context->cert_provider = std::make_unique(runtime); context->build_entity(); security = std::move(context); } } if (!security) { throw std::runtime_error("internal failure setting up security entity"); } } else { throw std::runtime_error("Unknown security entity requested"); } return security; } void add_security_options(po::options_description& options) { options.add_options() ("security", po::value()->default_value("dummy"), "Security entity [none,dummy,certs] (with optional -v2 or -v3 suffix)") ("crypto-backend", po::value()->default_value("default"), "Crypto backend [default,OpenSSL,CryptoPP,Null]") ("certificate", po::value(), "Certificate to use for secured messages.") ("certificate-key", po::value(), "Certificate key to use for secured messages.") ("certificate-chain", po::value >()->multitoken(), "Certificate chain to use, use as often as needed.") ("trusted-certificate", po::value >()->multitoken(), "Trusted certificate, use as often as needed.") ("security.permissive-identified-region", po::bool_switch()->default_value(false), "Accept IdentifiedRegion certificate constraints without verification (opt-in fallback; see issue #262). Default: reject (OutsideRegion).") ; add_certificate_validation_v3_options(options); }