void CertificateCache::insert(const Certificate& certificate) { const HashedId8 id = calculate_hash(certificate); // this may drop expired entries and extend some's lifetime std::list<Certificate> certs = lookup(id, certificate.subject_info.subject_type); // TODO: implement equality comparison for Certificate if (certs.size()) { const auto binary_insert = convert_for_signing(certificate); for (auto& cert : certs) { const auto binary_found = convert_for_signing(cert); if (binary_insert == binary_found) { return; } } } Clock::duration lifetime = Clock::duration::zero(); if (certificate.subject_info.subject_type == SubjectType::Authorization_Ticket) { // section 7.1 in ETSI TS 103 097 v1.2.1 // there must be a CAM with the authorization ticket every one second // we choose two seconds here to account for one missed message lifetime = std::chrono::seconds(2); } else if (certificate.subject_info.subject_type == SubjectType::Authorization_Authority) { // section 7.1 in ETSI TS 103 097 v1.2.1 // chains are only sent upon request, there will probably only be a few authoritation authorities in use // one hour is an arbitrarily choosen cache period for now lifetime = std::chrono::seconds(3600); } if (lifetime > Clock::duration::zero()) { CachedCertificate entry; entry.certificate = certificate; map_type::iterator stored = m_certificates.emplace(id, entry); heap_type::handle_type& handle = stored->second.handle; handle = m_expiries.push(Expiry { m_runtime.now() + lifetime, stored }); } }
CertificateValidity NaiveCertificateManager::check_certificate(const Certificate& certificate) { // check validity restriction for (auto& restriction : certificate.validity_restriction) { ValidityRestriction validity_restriction = restriction; ValidityRestrictionType type = get_type(validity_restriction); if (type == ValidityRestrictionType::Time_Start_And_End) { // change start and end time of certificate validity StartAndEndValidity start_and_end = boost::get<StartAndEndValidity>(validity_restriction); // check if certificate validity restriction timestamps are logically correct if (start_and_end.start_validity >= start_and_end.end_validity) { return CertificateInvalidReason::BROKEN_TIME_PERIOD; } // check if certificate is premature or outdated auto now = convert_time32(m_time_now); if (now < start_and_end.start_validity || now > start_and_end.end_validity) { return CertificateInvalidReason::OFF_TIME_PERIOD; } } } // check if subject_name is empty if (0 != certificate.subject_info.subject_name.size()) { return CertificateInvalidReason::INVALID_NAME; } // check signer info if(get_type(certificate.signer_info) == SignerInfoType::Certificate_Digest_With_SHA256) { HashedId8 signer_hash = boost::get<HashedId8>(certificate.signer_info); if(signer_hash != m_root_certificate_hash) { return CertificateInvalidReason::INVALID_ROOT_HASH; } } // try to extract ECDSA signature boost::optional<EcdsaSignature> sig = extract_ecdsa_signature(certificate.signature); if (!sig) { return CertificateInvalidReason::MISSING_SIGNATURE; } // create buffer of certificate ByteBuffer cert = convert_for_signing(certificate); if (!m_crypto_backend.verify_data(m_root_key_pair.public_key, cert, sig.get())) { return CertificateInvalidReason::INVALID_SIGNATURE; } return CertificateValidity::valid(); }
Certificate NaiveCertificateManager::generate_certificate(const ecdsa256::KeyPair& key_pair) { // create certificate Certificate certificate; // section 6.1 in TS 103 097 v1.2.1 certificate.signer_info = m_root_certificate_hash; // section 6.3 in TS 103 097 v1.2.1 certificate.subject_info.subject_type = SubjectType::Authorization_Ticket; // section 7.4.2 in TS 103 097 v1.2.1, subject_name implicit empty // set assurance level certificate.subject_attributes.push_back(SubjectAssurance(0x00)); // section 7.4.1 in TS 103 097 v1.2.1 // set subject attributes // set the verification_key Uncompressed coordinates; coordinates.x.assign(key_pair.public_key.x.begin(), key_pair.public_key.x.end()); coordinates.y.assign(key_pair.public_key.y.begin(), key_pair.public_key.y.end()); EccPoint ecc_point = coordinates; ecdsa_nistp256_with_sha256 ecdsa; ecdsa.public_key = ecc_point; VerificationKey verification_key; verification_key.key = ecdsa; certificate.subject_attributes.push_back(verification_key); // section 6.7 in TS 103 097 v1.2.1 // set validity restriction StartAndEndValidity start_and_end; start_and_end.start_validity = convert_time32(m_time_now - std::chrono::hours(1)); start_and_end.end_validity = convert_time32(m_time_now + std::chrono::hours(23)); certificate.validity_restriction.push_back(start_and_end); // set signature ByteBuffer data_buffer = convert_for_signing(certificate); certificate.signature = m_crypto_backend.sign_data(m_root_key_pair.private_key, data_buffer); return certificate; }