1#include <vanetza/security/pqc/hybrid_certificate.hpp>
2#include <vanetza/asn1/asn1c_wrapper.hpp>
3#include <vanetza/asn1/security_profile.hpp>
4#include VANETZA_ASN1_SECURITY_HEADER(PublicVerificationKey.h)
5#include VANETZA_ASN1_SECURITY_HEADER(Signature.h)
6#include VANETZA_ASN1_SECURITY_HEADER(ToBeSignedCertificate.h)
7#include <vanetza/security/backend.hpp>
8#include <vanetza/security/private_key.hpp>
9#include <vanetza/security/v3/asn1_conversions.hpp>
10#include <vanetza/security/v3/certificate.hpp>
11#include <vanetza/security/v3/hash.hpp>
24using v3::CertificateView;
36 }
catch (
const std::exception&) {
44 auto certificate = copy_certificate(view);
46 throw std::invalid_argument(
"certificate cannot be encoded and decoded");
48 return std::move(*certificate);
51ByteBuffer copy_octets(
const OCTET_STRING_t& value)
53 if (!value.buf || value.size == 0) {
56 return ByteBuffer(value.buf, value.buf + value.size);
61 const auto* key = certificate->toBeSigned.altVerificationKey;
62 if (!key || key->present != Vanetza_Security_PublicVerificationKey_PR_fnDsa512) {
66 PublicKey result { copy_octets(key->choice.fnDsa512) };
67 return result.bytes.size() == fndsa512_public_key_size ?
68 boost::optional<
PublicKey> { std::move(result) } : boost::none;
73 const auto* signature = certificate->toBeSigned.altSignatureValue;
74 if (!signature || signature->present != Vanetza_Security_Signature_PR_fnDsa512Signature) {
78 Signature result { copy_octets(signature->choice.fnDsa512Signature) };
79 return result.bytes.size() == fndsa512_signature_size ?
80 boost::optional<
Signature> { std::move(result) } : boost::none;
83void assign_octets(OCTET_STRING_t& destination,
const ByteBuffer& source)
85 if (source.size() >
static_cast<std::size_t>(std::numeric_limits<
int>::max()) ||
86 OCTET_STRING_fromBuf(&destination,
87 reinterpret_cast<
const char*>(source.data()),
88 static_cast<
int>(source.size())) != 0) {
89 throw std::runtime_error(
"cannot allocate ASN.1 octet string");
93void set_primary_signature(
96 if (signature.r.size() != key_length(signature.type) ||
97 signature.s.size() != key_length(signature.type)) {
98 throw std::invalid_argument(
"ECC certificate signature has an invalid size");
101 if (certificate->signature) {
102 vanetza::asn1::free(asn_DEF_Vanetza_Security_Signature, certificate->signature);
104 certificate->signature = vanetza::asn1::allocate<v3::asn1::Signature>();
106 v3::asn1::EccP256CurvePoint* r256 =
nullptr;
107 v3::asn1::EccP384CurvePoint* r384 =
nullptr;
108 OCTET_STRING_t* s =
nullptr;
109 switch (signature.type) {
110 case KeyType::NistP256:
111 certificate->signature->present = Vanetza_Security_Signature_PR_ecdsaNistP256Signature;
112 r256 = &certificate->signature->choice.ecdsaNistP256Signature.rSig;
113 s = &certificate->signature->choice.ecdsaNistP256Signature.sSig;
115 case KeyType::BrainpoolP256r1:
116 certificate->signature->present = Vanetza_Security_Signature_PR_ecdsaBrainpoolP256r1Signature;
117 r256 = &certificate->signature->choice.ecdsaBrainpoolP256r1Signature.rSig;
118 s = &certificate->signature->choice.ecdsaBrainpoolP256r1Signature.sSig;
120 case KeyType::BrainpoolP384r1:
121 certificate->signature->present = Vanetza_Security_Signature_PR_ecdsaBrainpoolP384r1Signature;
122 r384 = &certificate->signature->choice.ecdsaBrainpoolP384r1Signature.rSig;
123 s = &certificate->signature->choice.ecdsaBrainpoolP384r1Signature.sSig;
126 throw std::invalid_argument(
"unsupported ECC certificate signature type");
130 r256->present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
131 assign_octets(r256->choice.x_only, signature.r);
133 r384->present = Vanetza_Security_EccP384CurvePoint_PR_x_only;
134 assign_octets(r384->choice.x_only, signature.r);
136 assign_octets(*s, signature.s);
146 throw std::invalid_argument(
"issuer certificate is required for a non-self-signed certificate");
151ByteBuffer canonical_tbs(
const CertificateView& subject, SignatureLayer layer)
153 Certificate certificate = copy_certificate_or_throw(subject);
154 if (layer == SignatureLayer::Alternative) {
155 clear_alternative_signature(certificate);
160 throw std::invalid_argument(
"certificate cannot be canonicalized");
163 return vanetza::asn1::encode_oer(
164 asn_DEF_Vanetza_Security_ToBeSignedCertificate, &canonical->content()->toBeSigned);
173 throw std::invalid_argument(
"issuer certificate is required for a non-self-signed certificate");
178 if (!expected_digest || !actual_digest || *expected_digest != *actual_digest) {
179 throw std::invalid_argument(
"issuer certificate does not match the subject issuer identifier");
184 throw std::invalid_argument(
"issuer certificate cannot be canonicalized");
186 return canonical->encode();
193 auto certificate = copy_certificate(view);
194 return certificate ? extract_alternative_public_key(*certificate) : boost::none;
199 auto certificate = copy_certificate(view);
200 return certificate ? extract_alternative_signature(*certificate) : boost::none;
205 auto certificate = copy_certificate(view);
207 return MaterialState::Inconsistent;
210 const bool key_present = certificate->content()->toBeSigned.altVerificationKey;
211 const bool signature_present = certificate->content()->toBeSigned.altSignatureValue;
212 const bool has_key =
static_cast<
bool>(extract_alternative_public_key(*certificate));
213 const bool has_signature =
static_cast<
bool>(extract_alternative_signature(*certificate));
214 if (!key_present && !signature_present) {
215 return MaterialState::None;
217 if (key_present != has_key || signature_present != has_signature) {
218 return MaterialState::Inconsistent;
221 return !has_key && has_signature ? MaterialState::EndEntity : MaterialState::Inconsistent;
224 return has_key && has_signature ? MaterialState::Authority : MaterialState::Inconsistent;
226 return MaterialState::Inconsistent;
231 if (key.bytes.size() != fndsa512_public_key_size) {
232 throw std::invalid_argument(
"FN-DSA-512 public key has an invalid size");
234 clear_alternative_public_key(certificate);
235 certificate->toBeSigned.altVerificationKey =
236 vanetza::asn1::allocate<v3::asn1::PublicVerificationKey>();
237 certificate->toBeSigned.altVerificationKey->present =
238 Vanetza_Security_PublicVerificationKey_PR_fnDsa512;
239 assign_octets(certificate->toBeSigned.altVerificationKey->choice.fnDsa512, key.bytes);
244 if (signature.bytes.size() != fndsa512_signature_size) {
245 throw std::invalid_argument(
"FN-DSA-512 signature has an invalid size");
247 clear_alternative_signature(certificate);
248 certificate->toBeSigned.altSignatureValue =
249 vanetza::asn1::allocate<v3::asn1::Signature>();
250 certificate->toBeSigned.altSignatureValue->present =
251 Vanetza_Security_Signature_PR_fnDsa512Signature;
253 certificate->toBeSigned.altSignatureValue->choice.fnDsa512Signature,
257void clear_alternative_public_key(
Certificate& certificate)
259 if (certificate->toBeSigned.altVerificationKey) {
261 asn_DEF_Vanetza_Security_PublicVerificationKey,
262 certificate->toBeSigned.altVerificationKey);
263 certificate->toBeSigned.altVerificationKey =
nullptr;
267void clear_alternative_signature(
Certificate& certificate)
269 if (certificate->toBeSigned.altSignatureValue) {
271 asn_DEF_Vanetza_Security_Signature,
272 certificate->toBeSigned.altSignatureValue);
273 certificate->toBeSigned.altSignatureValue =
nullptr;
277ByteBuffer calculate_certificate_hash(
278 ::vanetza::security::
Backend& backend, HashAlgorithm algorithm,
282 if (algorithm == HashAlgorithm::Unspecified) {
283 throw std::invalid_argument(
"certificate hash algorithm is unspecified");
286 const ByteBuffer data_input = canonical_tbs(subject, layer);
287 const ByteBuffer signer_input = canonical_issuer(subject, issuer);
291 ByteBuffer concatenated;
292 concatenated.reserve(data_hash.size() + signer_hash.size());
293 concatenated.insert(concatenated.end(), data_hash.begin(), data_hash.end());
294 concatenated.insert(concatenated.end(), signer_hash.begin(), signer_hash.end());
298void sign_primary_certificate(
300 ::vanetza::security::
Backend& backend,
301 const ::vanetza::security::
PrivateKey& issuer_key)
304 const auto public_key = v3::get_public_key(*copy_certificate_or_throw(signer).content());
305 if (!public_key || public_key->type != issuer_key.type) {
306 throw std::invalid_argument(
"ECC private key does not match the issuer certificate key type");
309 const HashAlgorithm algorithm = v3::specified_hash_algorithm(issuer_key.type);
310 const ByteBuffer digest = calculate_certificate_hash(
311 backend, algorithm, subject, issuer, SignatureLayer::Primary);
314 throw std::invalid_argument(
315 "ECC private key does not match the issuer certificate public key");
317 set_primary_signature(subject, signature);
320bool verify_primary_certificate(
322 ::vanetza::security::
Backend& backend)
326 Certificate signer_copy = copy_certificate_or_throw(signer);
327 Certificate subject_copy = copy_certificate_or_throw(subject);
328 const auto public_key = v3::get_public_key(*signer_copy.content());
329 const auto signature = v3::get_signature(*subject_copy.content());
330 if (!public_key || !signature || public_key->type != signature->type) {
334 const HashAlgorithm algorithm = v3::specified_hash_algorithm(public_key->type);
335 const ByteBuffer digest = calculate_certificate_hash(
336 backend, algorithm, subject, issuer, SignatureLayer::Primary);
338 }
catch (
const std::exception&) {
343void sign_alternative_certificate(
349 const auto public_key = get_alternative_public_key(signer);
351 throw std::invalid_argument(
"issuer certificate has no FN-DSA-512 alternative key");
354 const ByteBuffer digest = calculate_certificate_hash(
355 hash_backend, HashAlgorithm::SHA256, subject, issuer, SignatureLayer::Alternative);
356 const auto signature = backend.sign(issuer_key, digest);
357 if (!backend.verify(*public_key, digest, signature)) {
358 throw std::invalid_argument(
359 "FN-DSA-512 private key does not match the issuer certificate public key");
361 set_alternative_signature(subject, signature);
364bool verify_alternative_certificate(
370 const auto public_key = get_alternative_public_key(signer);
371 const auto signature = get_alternative_signature(subject);
372 if (!public_key || !signature) {
376 const ByteBuffer digest = calculate_certificate_hash(
377 hash_backend, HashAlgorithm::SHA256, subject, issuer, SignatureLayer::Alternative);
378 return backend.verify(*public_key, digest, *signature);
379 }
catch (
const std::exception&) {
virtual Signature sign_digest(const PrivateKey &, const ByteBuffer &digest)=0
calculate signature for given digest and private key
virtual bool verify_digest(const PublicKey &public_key, const ByteBuffer &digest, const Signature &sig)=0
try to verify digest using public key and signature
virtual ByteBuffer calculate_hash(HashAlgorithm algo, const ByteBuffer &data)=0
calculate hash value of data
ByteBuffer encode() const
boost::optional< Certificate > canonicalize() const
bool is_at_certificate() const
bool is_ca_certificate() const
bool issuer_is_self() const
boost::optional< HashedId8 > calculate_digest() const
boost::optional< HashedId8 > issuer_digest() const