Vanetza
Loading...
Searching...
No Matches
certificate.cpp
1#include <vanetza/asn1/security/Certificate.h>
2#include <vanetza/security/sha.hpp>
3#include <vanetza/security/v3/asn1_conversions.hpp>
4#include <vanetza/security/v3/certificate.hpp>
5#include <vanetza/security/v3/distance.hpp>
6#include <boost/optional/optional.hpp>
7#include <cassert>
8#include <cstring>
9
10namespace vanetza
11{
12namespace security
13{
14namespace v3
15{
16
17namespace
18{
19bool copy_curve_point(PublicKey& to, const asn1::EccP256CurvePoint& from);
20bool copy_curve_point(PublicKey& to, const asn1::EccP384CurvePoint& from);
21ByteBuffer fetch_octets(const OCTET_STRING_t& octets);
22ByteBuffer get_x_coordinate(const asn1::EccP256CurvePoint& point);
23ByteBuffer get_x_coordinate(const asn1::EccP384CurvePoint& point);
24
25bool is_compressed(const Vanetza_Security_EccP256CurvePoint& point);
26bool is_compressed(const Vanetza_Security_EccP384CurvePoint& point);
27bool is_signature_x_only(const Vanetza_Security_Signature_t& sig);
28bool compress(Vanetza_Security_EccP256CurvePoint&);
29bool compress(Vanetza_Security_EccP384CurvePoint&);
30bool make_x_only(Vanetza_Security_EccP256CurvePoint&);
31bool make_x_only(Vanetza_Security_EccP384CurvePoint&);
32bool make_signature_x_only(Vanetza_Security_Signature_t& sig);
33
34} // namespace
35
36CertificateView::CertificateView(const asn1::EtsiTs103097Certificate* cert) :
37 m_cert(cert)
38{
39}
40
41Certificate::Certificate() :
42 Wrapper(asn_DEF_Vanetza_Security_EtsiTs103097Certificate),
43 CertificateView { content() }
44{
45 assert(CertificateView::m_cert == Wrapper::m_struct);
46}
47
48Certificate::Certificate(const asn1::EtsiTs103097Certificate& cert) :
49 Wrapper(asn_DEF_Vanetza_Security_EtsiTs103097Certificate, &cert),
50 CertificateView { content() }
51{
52 assert(CertificateView::m_cert == Wrapper::m_struct);
53}
54
55Certificate::Certificate(const Certificate& other) :
56 Wrapper(other), CertificateView(content())
57{
58 assert(CertificateView::m_cert == Wrapper::m_struct);
59}
60
61Certificate& Certificate::operator=(const Certificate& other)
62{
63 Wrapper::operator=(other);
64 CertificateView::m_cert = content();
65 assert(CertificateView::m_cert == Wrapper::m_struct);
66 return *this;
67}
68
69Certificate::Certificate(Certificate&& other) :
70 Wrapper(std::move(other)), CertificateView(content())
71{
72 assert(CertificateView::m_cert == Wrapper::m_struct);
73}
74
75Certificate& Certificate::operator=(Certificate&& other)
76{
77 Wrapper::operator=(std::move(other));
78 CertificateView::m_cert = content();
79 assert(CertificateView::m_cert == Wrapper::m_struct);
80 return *this;
81}
82
83boost::optional<HashedId8> CertificateView::calculate_digest() const
84{
85 return m_cert ? v3::calculate_digest(*m_cert) : boost::none;
86}
87
89{
90 return m_cert ? v3::get_verification_key_type(*m_cert) : KeyType::Unspecified;
91}
92
94{
95 return m_cert ? lc ? lc->valid_at_location(*m_cert, location) : false : false;
96}
97
98bool CertificateView::valid_at_timepoint(const Clock::time_point& timepoint) const
99{
100 return m_cert ? v3::valid_at_timepoint(*m_cert, timepoint) : false;
101}
102
103bool valid_at_timepoint(const asn1::EtsiTs103097Certificate& cert, const Clock::time_point& timepoint)
104{
105 const asn1::ValidityPeriod& validity = cert.toBeSigned.validityPeriod;
106 Clock::time_point start { std::chrono::seconds(validity.start) };
107 Clock::time_point end = start;
108
109 switch (validity.duration.present)
110 {
111 case Vanetza_Security_Duration_PR_microseconds:
112 end += std::chrono::microseconds(validity.duration.choice.microseconds);
113 break;
114 case Vanetza_Security_Duration_PR_milliseconds:
115 end += std::chrono::milliseconds(validity.duration.choice.milliseconds);
116 break;
117 case Vanetza_Security_Duration_PR_seconds:
118 end += std::chrono::seconds(validity.duration.choice.seconds);
119 break;
120 case Vanetza_Security_Duration_PR_minutes:
121 end += std::chrono::minutes(validity.duration.choice.minutes);
122 break;
123 case Vanetza_Security_Duration_PR_hours:
124 end += std::chrono::hours(validity.duration.choice.hours);
125 break;
126 case Vanetza_Security_Duration_PR_sixtyHours:
127 end += std::chrono::hours(60) * validity.duration.choice.sixtyHours;
128 break;
129 case Vanetza_Security_Duration_PR_years:
130 // one year is considered 31556952 seconds according to IEEE 1609.2
131 end += std::chrono::seconds(31556952) * validity.duration.choice.years;
132 break;
133 default:
134 // leave end at start and thus forming an invalid range
135 break;
136 }
137
138 return timepoint >= start && timepoint < end;
139}
140
142{
143 return m_cert ? v3::valid_for_application(*m_cert, aid) : false;
144}
145
146bool valid_for_application(const asn1::EtsiTs103097Certificate& cert, ItsAid aid)
147{
148 const asn1::SequenceOfPsidSsp* permissions = cert.toBeSigned.appPermissions;
149 if (permissions) {
150 for (int i = 0; i < permissions->list.count; ++i) {
151 if (permissions->list.array[i]->psid == aid) {
152 return true;
153 }
154 }
155 }
156
157 // only explicitly allowed applications are valid
158 return false;
159}
160
161boost::optional<HashedId8> CertificateView::issuer_digest() const
162{
163 boost::optional<HashedId8> digest;
164 if (m_cert != nullptr) {
165 switch (m_cert->issuer.present)
166 {
167 case Vanetza_Security_IssuerIdentifier_PR_sha256AndDigest:
168 digest = create_hashed_id8(m_cert->issuer.choice.sha256AndDigest);
169 break;
170 case Vanetza_Security_IssuerIdentifier_PR_sha384AndDigest:
171 digest = create_hashed_id8(m_cert->issuer.choice.sha384AndDigest);
172 break;
173 default:
174 break;
175 }
176 }
177 return digest;
178}
179
181{
182 return m_cert->issuer.present == Vanetza_Security_IssuerIdentifier_PR_self;
183}
184
186{
187 return m_cert ? m_cert->toBeSigned.region != nullptr : false;
188}
189
191{
192 return m_cert && m_cert->toBeSigned.certIssuePermissions != nullptr;
193}
194
196{
197 return m_cert && m_cert->toBeSigned.certIssuePermissions == nullptr && m_cert->toBeSigned.appPermissions != nullptr;
198}
199
201{
202 return m_cert ? v3::is_canonical(*m_cert) : false;
203}
204
206{
207 StartAndEndValidity start_and_end;
208 start_and_end.start_validity = Time32(m_cert->toBeSigned.validityPeriod.start);
209 Time32 duration = 0;
210 switch (m_cert->toBeSigned.validityPeriod.duration.present)
211 {
212 case Vanetza_Security_Duration_PR_NOTHING:
213 break;
214 case Vanetza_Security_Duration_PR_microseconds:
215 duration += (int)m_cert->toBeSigned.validityPeriod.duration.choice.microseconds/1000000;
216 break;
217 case Vanetza_Security_Duration_PR_milliseconds:
218 duration += (int)m_cert->toBeSigned.validityPeriod.duration.choice.milliseconds/1000;
219 break;
220 case Vanetza_Security_Duration_PR_seconds:
221 duration += (int)m_cert->toBeSigned.validityPeriod.duration.choice.seconds;
222 break;
223 case Vanetza_Security_Duration_PR_minutes:
224 duration += (int)m_cert->toBeSigned.validityPeriod.duration.choice.minutes*60;
225 break;
226 case Vanetza_Security_Duration_PR_hours:
227 duration += (int)m_cert->toBeSigned.validityPeriod.duration.choice.hours*60*60;
228 break;
229 case Vanetza_Security_Duration_PR_sixtyHours:
230 duration += (int)m_cert->toBeSigned.validityPeriod.duration.choice.sixtyHours*60*60*60;
231 break;
232 case Vanetza_Security_Duration_PR_years:
233 duration += (int)m_cert->toBeSigned.validityPeriod.duration.choice.years*60*60*24*365;
234 break;
235 default:
236 break;
237 }
238 start_and_end.end_validity = start_and_end.start_validity + duration;
239 return start_and_end;
240}
241
242bool is_canonical(const asn1::EtsiTs103097Certificate& cert)
243{
244 bool compressed_point = true;
245 const Vanetza_Security_VerificationKeyIndicator& indicator = cert.toBeSigned.verifyKeyIndicator;
246 if (indicator.present == Vanetza_Security_VerificationKeyIndicator_PR_verificationKey) {
247 const Vanetza_Security_PublicVerificationKey& pubkey = indicator.choice.verificationKey;
248 switch (pubkey.present) {
249 case Vanetza_Security_PublicVerificationKey_PR_ecdsaNistP256:
250 compressed_point = is_compressed(pubkey.choice.ecdsaNistP256);
251 break;
252 case Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP256r1:
253 compressed_point = is_compressed(pubkey.choice.ecdsaBrainpoolP256r1);
254 break;
255 case Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP384r1:
256 compressed_point = is_compressed(pubkey.choice.ecdsaBrainpoolP384r1);
257 break;
258 default:
259 break;
260 }
261 } else if (indicator.present == Vanetza_Security_VerificationKeyIndicator_PR_reconstructionValue) {
262 compressed_point = is_compressed(indicator.choice.reconstructionValue);
263 }
264
265 if (!compressed_point) {
266 return false;
267 } else if (cert.signature && !is_signature_x_only(*cert.signature)) {
268 return false;
269 } else {
270 return true;
271 }
272}
273
274ByteBuffer CertificateView::encode() const
275{
276 return m_cert ? asn1::encode_oer(asn_DEF_Vanetza_Security_EtsiTs103097Certificate, m_cert) : ByteBuffer {};
277}
278
279ByteBuffer Certificate::encode() const
280{
281 return Wrapper::encode();
282}
283
284boost::optional<Certificate> CertificateView::canonicalize() const
285{
286 return m_cert ? v3::canonicalize(*m_cert) : boost::none;
287}
288
289boost::optional<Certificate> canonicalize(const asn1::EtsiTs103097Certificate& cert)
290{
291 Certificate canonical { cert };
292 bool success = true;
293
294 if (canonical->toBeSigned.verifyKeyIndicator.present == Vanetza_Security_VerificationKeyIndicator_PR_verificationKey) {
295 Vanetza_Security_PublicVerificationKey& pubkey = canonical->toBeSigned.verifyKeyIndicator.choice.verificationKey;
296 switch (pubkey.present) {
297 case Vanetza_Security_PublicVerificationKey_PR_ecdsaNistP256:
298 success &= compress(pubkey.choice.ecdsaNistP256);
299 break;
300 case Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP256r1:
301 success &= compress(pubkey.choice.ecdsaBrainpoolP256r1);
302 break;
303 case Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP384r1:
304 success &= compress(pubkey.choice.ecdsaBrainpoolP384r1);
305 break;
306 default:
307 break;
308 }
309 } else if (canonical->toBeSigned.verifyKeyIndicator.present == Vanetza_Security_VerificationKeyIndicator_PR_reconstructionValue) {
310 success &= compress(canonical->toBeSigned.verifyKeyIndicator.choice.reconstructionValue);
311 }
312
313 if (canonical->toBeSigned.encryptionKey) {
314 Vanetza_Security_BasePublicEncryptionKey& pubkey = canonical->toBeSigned.encryptionKey->publicKey;
315 switch (pubkey.present) {
316 case Vanetza_Security_BasePublicEncryptionKey_PR_eciesNistP256:
317 success &= compress(pubkey.choice.eciesNistP256);
318 break;
319 case Vanetza_Security_BasePublicEncryptionKey_PR_eciesBrainpoolP256r1:
320 success &= compress(pubkey.choice.eciesBrainpoolP256r1);
321 break;
322 default:
323 break;
324 }
325 }
326
327 if (canonical->signature) {
328 success &= make_signature_x_only(*canonical->signature);
329 }
330
331 if (success) {
332 assert(is_canonical(*canonical));
333 return canonical;
334 } else {
335 return boost::none;
336 }
337}
338
339boost::optional<HashedId8> calculate_digest_internal(const asn1::EtsiTs103097Certificate& cert, KeyType key_type)
340{
341 boost::optional<HashedId8> digest;
342
343 try {
344 ByteBuffer buffer = asn1::encode_oer(asn_DEF_Vanetza_Security_EtsiTs103097Certificate, &cert);
345
346 switch (key_type)
347 {
348 case KeyType::NistP256:
349 case KeyType::BrainpoolP256r1:
350 digest = create_hashed_id8(calculate_sha256_digest(buffer.data(), buffer.size()));
351 break;
352 case KeyType::BrainpoolP384r1:
353 digest = create_hashed_id8(calculate_sha384_digest(buffer.data(), buffer.size()));
354 break;
355 default:
356 break;
357 }
358 } catch (const std::exception&) {
359 // cannot calculate digest of non-encodable certificate
360 }
361
362 return digest;
363}
364
365boost::optional<HashedId8> calculate_digest(const asn1::EtsiTs103097Certificate& cert)
366{
367 boost::optional<HashedId8> digest;
368 auto key_type = get_verification_key_type(cert);
369 if (key_type != KeyType::Unspecified) {
370 if (is_canonical(cert)) {
371 digest = calculate_digest_internal(cert, key_type);
372 } else {
373 auto maybe_canonical_cert = canonicalize(cert);
374 if (maybe_canonical_cert) {
375 digest = calculate_digest_internal(*maybe_canonical_cert.value(), key_type);
376 }
377 }
378 }
379 return digest;
380}
381
382KeyType get_verification_key_type(const asn1::EtsiTs103097Certificate& cert)
383{
384 KeyType key_type = KeyType::Unspecified;
385
386 if (cert.toBeSigned.verifyKeyIndicator.present == Vanetza_Security_VerificationKeyIndicator_PR_verificationKey)
387 {
388 switch (cert.toBeSigned.verifyKeyIndicator.choice.verificationKey.present)
389 {
390 case Vanetza_Security_PublicVerificationKey_PR_ecdsaNistP256:
391 key_type = KeyType::NistP256;
392 break;
393 case Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP256r1:
394 key_type = KeyType::BrainpoolP256r1;
395 break;
396 case Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP384r1:
397 key_type = KeyType::BrainpoolP384r1;
398 break;
399 default:
400 break;
401 }
402 }
403
404 return key_type;
405}
406
407boost::optional<PublicKey> get_public_key(const asn1::EtsiTs103097Certificate& cert)
408{
409 asn1::VerificationKeyIndicator indicator = cert.toBeSigned.verifyKeyIndicator;
410 if (indicator.present != Vanetza_Security_VerificationKeyIndicator_PR_verificationKey) {
411 return boost::none;
412 }
413
414 const asn1::PublicVerificationKey& input = cert.toBeSigned.verifyKeyIndicator.choice.verificationKey;
415 PublicKey output;
416 switch (input.present) {
417 case Vanetza_Security_PublicVerificationKey_PR_ecdsaNistP256:
418 output.type = KeyType::NistP256;
419 if (copy_curve_point(output, input.choice.ecdsaNistP256)) {
420 return output;
421 } else {
422 return boost::none;
423 }
424 break;
425 case Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP256r1:
426 output.type = KeyType::BrainpoolP256r1;
427 if (copy_curve_point(output, input.choice.ecdsaBrainpoolP256r1)) {
428 return output;
429 } else {
430 return boost::none;
431 }
432 break;
433 case Vanetza_Security_PublicVerificationKey_PR_ecdsaBrainpoolP384r1:
434 output.type = KeyType::BrainpoolP384r1;
435 if (copy_curve_point(output, input.choice.ecdsaBrainpoolP384r1)) {
436 return output;
437 } else {
438 return boost::none;
439 }
440 break;
441 default:
442 return boost::none;
443 break;
444 }
445}
446
447boost::optional<PublicKey> get_public_encryption_key(const asn1::EtsiTs103097Certificate& cert)
448{
449 const asn1::PublicEncryptionKey* enc_key = cert.toBeSigned.encryptionKey;
450 if (!enc_key || enc_key->supportedSymmAlg != Vanetza_Security_SymmAlgorithm_aes128Ccm) {
451 return boost::none;
452 }
453
454 PublicKey output;
455 switch (enc_key->publicKey.present) {
456 case Vanetza_Security_BasePublicEncryptionKey_PR_eciesNistP256:
457 output.type = KeyType::NistP256;
458 if (copy_curve_point(output, enc_key->publicKey.choice.eciesNistP256)) {
459 return output;
460 } else {
461 return boost::none;
462 }
463 break;
464 case Vanetza_Security_BasePublicEncryptionKey_PR_eciesBrainpoolP256r1:
465 output.type = KeyType::BrainpoolP256r1;
466 if (copy_curve_point(output, enc_key->publicKey.choice.eciesBrainpoolP256r1)) {
467 return output;
468 } else {
469 return boost::none;
470 }
471 break;
472 default:
473 return boost::none;
474 break;
475 }
476}
477
478boost::optional<Signature> get_signature(const asn1::EtsiTs103097Certificate& cert)
479{
480 if (!cert.signature) {
481 return boost::none;
482 }
483
484 const asn1::Signature* asn = cert.signature;
485 Signature sig;
486 switch (asn->present) {
487 case Vanetza_Security_Signature_PR_ecdsaNistP256Signature:
488 sig.type = KeyType::NistP256;
489 sig.r = get_x_coordinate(asn->choice.ecdsaNistP256Signature.rSig);
490 sig.s = fetch_octets(asn->choice.ecdsaNistP256Signature.sSig);
491 break;
492 case Vanetza_Security_Signature_PR_ecdsaBrainpoolP256r1Signature:
493 sig.type = KeyType::BrainpoolP256r1;
494 sig.r = get_x_coordinate(asn->choice.ecdsaBrainpoolP256r1Signature.rSig);
495 sig.s = fetch_octets(asn->choice.ecdsaBrainpoolP256r1Signature.sSig);
496 break;
497 case Vanetza_Security_Signature_PR_ecdsaBrainpoolP384r1Signature:
498 sig.type = KeyType::BrainpoolP384r1;
499 sig.r = get_x_coordinate(asn->choice.ecdsaBrainpoolP384r1Signature.rSig);
500 sig.s = fetch_octets(asn->choice.ecdsaBrainpoolP384r1Signature.sSig);
501 break;
502 default:
503 return boost::none;
504 }
505
506 return sig;
507}
508
509std::list<ItsAid> get_aids(const asn1::EtsiTs103097Certificate& cert)
510{
511 std::list<ItsAid> aids;
512 const asn1::SequenceOfPsidSsp* seq = cert.toBeSigned.appPermissions;
513 if (seq) {
514 for (int i = 0; i < seq->list.count; ++i) {
515 aids.push_back(seq->list.array[i]->psid);
516 }
517 }
518 return aids;
519}
520
521ByteBuffer get_app_permissions(const asn1::EtsiTs103097Certificate& cert, ItsAid aid)
522{
523 ByteBuffer perms;
524 const asn1::SequenceOfPsidSsp* seq = cert.toBeSigned.appPermissions;
525 if (seq) {
526 for (int i = 0; i < seq->list.count; ++i) {
527 if (seq->list.array[i]->psid == aid && seq->list.array[i]->ssp != nullptr) {
528 const asn1::ServiceSpecificPermissions& ssp = *seq->list.array[i]->ssp;
529 if (ssp.present == Vanetza_Security_ServiceSpecificPermissions_PR_bitmapSsp) {
530 const asn1::BitmapSsp& bitmap = ssp.choice.bitmapSsp;
531 perms.assign(bitmap.buf, bitmap.buf + bitmap.size);
532 break;
533 }
534 }
535 }
536 }
537 return perms;
538}
539
540void add_psid_group_permission(asn1::PsidGroupPermissions* group_permission, ItsAid aid, const ByteBuffer& ssp, const ByteBuffer& bitmask)
541{
542 auto psid_range_scr = asn1::allocate<asn1::PsidSspRange>();
543 psid_range_scr->psid = aid;
544 psid_range_scr->sspRange = asn1::allocate<asn1::SspRange>();
545 psid_range_scr->sspRange->present = Vanetza_Security_SspRange_PR_bitmapSspRange;
546 OCTET_STRING_fromBuf(
547 &psid_range_scr->sspRange->choice.bitmapSspRange.sspValue,
548 reinterpret_cast<const char*>(ssp.data()),
549 ssp.size()
550 );
551 OCTET_STRING_fromBuf(
552 &psid_range_scr->sspRange->choice.bitmapSspRange.sspBitmask,
553 reinterpret_cast<const char*>(bitmask.data()),
554 bitmask.size()
555 );
556 ASN_SEQUENCE_ADD(&group_permission->subjectPermissions.choice.Explicit, psid_range_scr);
557}
558
559void add_app_permissions(Certificate& cert, ItsAid aid)
560{
561 asn1::SequenceOfPsidSsp* seq = cert->toBeSigned.appPermissions;
562 if (!seq) {
563 seq = asn1::allocate<asn1::SequenceOfPsidSsp>();
564 cert->toBeSigned.appPermissions = seq;
565 }
566 // Allocate the memory
567 auto psid_ptr = asn1::allocate<asn1::PsidSsp>();
568 psid_ptr->psid = aid;
569 ASN_SEQUENCE_ADD(seq, psid_ptr);
570}
571
572void Certificate::add_permission(ItsAid aid, const ByteBuffer& ssp)
573{
574 asn1::SequenceOfPsidSsp* seq = m_struct->toBeSigned.appPermissions;
575 if (!seq) {
576 seq = asn1::allocate<asn1::SequenceOfPsidSsp>();
577 m_struct->toBeSigned.appPermissions = seq;
578 }
579 // Allocate the memory
580 auto psid_ptr = asn1::allocate<asn1::PsidSsp>();
581 psid_ptr->psid = aid;
582 psid_ptr->ssp = asn1::allocate<asn1::ServiceSpecificPermissions>();
583 psid_ptr->ssp->present = Vanetza_Security_ServiceSpecificPermissions_PR_opaque;
584 OCTET_STRING_fromBuf(
585 &(psid_ptr->ssp->choice.opaque),
586 reinterpret_cast<const char *>(ssp.data()),
587 ssp.size()
588 );
589 ASN_SEQUENCE_ADD(seq, psid_ptr);
590
591}
592
593void Certificate::add_cert_permission(asn1::PsidGroupPermissions* group_permission)
594{
595 asn1::SequenceOfPsidGroupPermissions* seq = m_struct->toBeSigned.certIssuePermissions;
596 if (!seq) {
597 seq = asn1::allocate<asn1::SequenceOfPsidGroupPermissions>();
598 m_struct->toBeSigned.certIssuePermissions = seq;
599 }
600 ASN_SEQUENCE_ADD(seq, group_permission);
601}
602
603void Certificate::set_signature(const SomeEcdsaSignature& signature)
604{
605 struct ecc_point_visitor : public boost::static_visitor<asn1::EccP256CurvePoint>
606 {
607 asn1::EccP256CurvePoint operator()(const X_Coordinate_Only& x_only) const
608 {
609 auto to_return = asn1::allocate<asn1::EccP256CurvePoint>();
610 to_return->present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
611 OCTET_STRING_fromBuf(
612 &(to_return->choice.x_only),
613 reinterpret_cast<const char*>(x_only.x.data()),
614 x_only.x.size()
615 );
616 return *to_return;
617 }
618
619 asn1::EccP256CurvePoint operator()(const Compressed_Lsb_Y_0& y0) const
620 {
621 auto to_return = asn1::allocate<asn1::EccP256CurvePoint>();
622 to_return->present = Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0;
623 OCTET_STRING_fromBuf(
624 &(to_return->choice.compressed_y_0),
625 reinterpret_cast<const char*>(y0.x.data()),
626 y0.x.size()
627 );
628 return *to_return;
629 }
630
631 asn1::EccP256CurvePoint operator()(const Compressed_Lsb_Y_1& y1) const
632 {
633 auto to_return = asn1::allocate<asn1::EccP256CurvePoint>();
634 to_return->present = Vanetza_Security_EccP256CurvePoint_PR_compressed_y_1;
635 OCTET_STRING_fromBuf(
636 &(to_return->choice.compressed_y_1),
637 reinterpret_cast<const char*>(y1.x.data()),
638 y1.x.size()
639 );
640 return *to_return;
641 }
642
643 asn1::EccP256CurvePoint operator()(const Uncompressed& unc) const
644 {
645 auto to_return = asn1::allocate<asn1::EccP256CurvePoint>();
646 to_return->present = Vanetza_Security_EccP256CurvePoint_PR_uncompressedP256;
647 OCTET_STRING_fromBuf(
648 &(to_return->choice.uncompressedP256.x),
649 reinterpret_cast<const char*>(unc.x.data()),
650 unc.x.size()
651 );
652 OCTET_STRING_fromBuf(
653 &(to_return->choice.uncompressedP256.y),
654 reinterpret_cast<const char*>(unc.y.data()),
655 unc.y.size()
656 );
657 return *to_return;
658 }
659 };
660
661 struct signature_visitor : public boost::static_visitor<asn1::Signature*>
662 {
663 asn1::Signature* operator()(const EcdsaSignature& signature) const
664 {
665 auto final_signature = asn1::allocate<asn1::Signature>();
666 final_signature->present = Vanetza_Security_Signature_PR_ecdsaNistP256Signature;
667 OCTET_STRING_fromBuf(
668 &(final_signature->choice.ecdsaNistP256Signature.sSig),
669 reinterpret_cast<const char*>(signature.s.data()),
670 signature.s.size()
671 );
672 final_signature->choice.ecdsaNistP256Signature.rSig = boost::apply_visitor(
673 ecc_point_visitor(),
674 signature.R
675 );
676 return final_signature;
677 }
678
679 asn1::Signature* operator()(const EcdsaSignatureFuture& signature) const
680 {
681 return this->operator()(signature.get());
682 }
683 };
684
685 m_struct->signature = boost::apply_visitor(signature_visitor(), signature);
686}
687
688Certificate fake_certificate()
689{
690 Certificate certi;
691 certi->issuer.present = Vanetza_Security_IssuerIdentifier_PR_self;
692 certi->toBeSigned.id.present = Vanetza_Security_CertificateId_PR_none;
693 std::vector<uint8_t> craciId(3, 0); // Correct length for P256 signature part
694 OCTET_STRING_fromBuf(
695 &certi->toBeSigned.cracaId,
696 reinterpret_cast<const char*>(craciId.data()),
697 craciId.size()
698 );
699 certi->version = 3;
700 certi->toBeSigned.crlSeries = 0;
701 certi->toBeSigned.validityPeriod.start = 0;
702 certi->toBeSigned.validityPeriod.duration.present = Vanetza_Security_Duration_PR_minutes;
703 certi->toBeSigned.validityPeriod.duration.choice.minutes = 10080;
704 certi->toBeSigned.verifyKeyIndicator.present = Vanetza_Security_VerificationKeyIndicator_PR_verificationKey;
705 certi->toBeSigned.verifyKeyIndicator.choice.verificationKey.present = Vanetza_Security_PublicVerificationKey_PR_ecdsaNistP256;
706 certi->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecdsaNistP256.present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
707 std::vector<uint8_t> dummy_r(32, 0); // Correct length for P256 signature part
708 dummy_r[0] = 0; // Ensure the leading byte is set to zero if needed
709 OCTET_STRING_fromBuf(
710 &certi->toBeSigned.verifyKeyIndicator.choice.verificationKey.choice.ecdsaNistP256.choice.x_only,
711 reinterpret_cast<const char*>(dummy_r.data()),
712 dummy_r.size()
713 );
714 certi.add_permission(aid::CA, ByteBuffer({ 1, 0, 0 }));
715 return certi;
716}
717
718void serialize(OutputArchive& ar, const Certificate& certificate)
719{
720 ByteBuffer buffer = certificate.encode();
721 ar.save_binary(buffer.data(), buffer.size());
722}
723
724namespace
725{
726
727bool copy_curve_point(PublicKey& to, const asn1::EccP256CurvePoint& from)
728{
729 bool copied = true;
730 switch (from.present) {
731 case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0:
732 to.compression = KeyCompression::Y0;
733 to.x = fetch_octets(from.choice.compressed_y_0);
734 break;
735 case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_1:
736 to.compression = KeyCompression::Y1;
737 to.x = fetch_octets(from.choice.compressed_y_1);
738 break;
739 case Vanetza_Security_EccP256CurvePoint_PR_uncompressedP256:
740 to.compression = KeyCompression::NoCompression;
741 to.x = fetch_octets(from.choice.uncompressedP256.x);
742 to.y = fetch_octets(from.choice.uncompressedP256.y);
743 break;
744 default:
745 copied = false;
746 break;
747 }
748
749 return copied;
750}
751
752bool copy_curve_point(PublicKey& to, const asn1::EccP384CurvePoint& from)
753{
754 bool copied = true;
755 switch (from.present) {
756 case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_0:
757 to.compression = KeyCompression::Y0;
758 to.x = fetch_octets(from.choice.compressed_y_0);
759 break;
760 case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_1:
761 to.compression = KeyCompression::Y1;
762 to.x = fetch_octets(from.choice.compressed_y_1);
763 break;
764 case Vanetza_Security_EccP384CurvePoint_PR_uncompressedP384:
765 to.compression = KeyCompression::NoCompression;
766 to.x = fetch_octets(from.choice.uncompressedP384.x);
767 to.y = fetch_octets(from.choice.uncompressedP384.y);
768 break;
769 default:
770 copied = false;
771 break;
772 }
773
774 return copied;
775}
776
777ByteBuffer fetch_octets(const OCTET_STRING_t& octets)
778{
779 ByteBuffer buffer(octets.size);
780 std::memcpy(buffer.data(), octets.buf, octets.size);
781 return buffer;
782}
783
784ByteBuffer get_x_coordinate(const asn1::EccP256CurvePoint& point)
785{
786 switch (point.present) {
787 case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0:
788 return fetch_octets(point.choice.compressed_y_0);
789 case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_1:
790 return fetch_octets(point.choice.compressed_y_1);
791 case Vanetza_Security_EccP256CurvePoint_PR_x_only:
792 return fetch_octets(point.choice.x_only);
793 case Vanetza_Security_EccP256CurvePoint_PR_uncompressedP256:
794 return fetch_octets(point.choice.uncompressedP256.x);
795 default:
796 return ByteBuffer {};
797 }
798}
799
800ByteBuffer get_x_coordinate(const asn1::EccP384CurvePoint& point)
801{
802 switch (point.present) {
803 case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_0:
804 return fetch_octets(point.choice.compressed_y_0);
805 case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_1:
806 return fetch_octets(point.choice.compressed_y_1);
807 case Vanetza_Security_EccP384CurvePoint_PR_x_only:
808 return fetch_octets(point.choice.x_only);
809 case Vanetza_Security_EccP384CurvePoint_PR_uncompressedP384:
810 return fetch_octets(point.choice.uncompressedP384.x);
811 default:
812 return ByteBuffer {};
813 }
814}
815
816bool is_compressed(const Vanetza_Security_EccP256CurvePoint& point)
817{
818 switch (point.present) {
819 case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0:
820 case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_1:
821 return true;
822 default:
823 return false;
824 }
825}
826
827bool is_compressed(const Vanetza_Security_EccP384CurvePoint& point)
828{
829 switch (point.present) {
830 case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_0:
831 case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_1:
832 return true;
833 default:
834 return false;
835 }
836}
837
838bool is_signature_x_only(const Vanetza_Security_Signature_t& sig)
839{
840 switch (sig.present) {
841 case Vanetza_Security_Signature_PR_ecdsaNistP256Signature:
842 return sig.choice.ecdsaNistP256Signature.rSig.present == Vanetza_Security_EccP256CurvePoint_PR_x_only;
843 case Vanetza_Security_Signature_PR_ecdsaBrainpoolP256r1Signature:
844 return sig.choice.ecdsaBrainpoolP256r1Signature.rSig.present == Vanetza_Security_EccP256CurvePoint_PR_x_only;
845 case Vanetza_Security_Signature_PR_ecdsaBrainpoolP384r1Signature:
846 return sig.choice.ecdsaBrainpoolP384r1Signature.rSig.present == Vanetza_Security_EccP384CurvePoint_PR_x_only;
847 default:
848 return true; // not an ECDSA signature at all
849 }
850}
851
852bool compress(Vanetza_Security_EccP256CurvePoint& point)
853{
854 if (point.present == Vanetza_Security_EccP256CurvePoint_PR_uncompressedP256) {
855 auto& unc = point.choice.uncompressedP256;
856 if (unc.y.size > 0 && unc.y.buf[unc.y.size - 1] & 0x01) {
857 assert(&point.choice.uncompressedP256.x == &point.choice.compressed_y_1);
858 point.present = Vanetza_Security_EccP256CurvePoint_PR_compressed_y_1;
859 } else {
860 assert(&point.choice.uncompressedP256.x == &point.choice.compressed_y_0);
861 point.present = Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0;
862 }
863 return true;
864 } else if (point.present == Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0 || point.present == Vanetza_Security_EccP256CurvePoint_PR_compressed_y_1) {
865 return true;
866 } else {
867 return false;
868 }
869}
870
871bool compress(Vanetza_Security_EccP384CurvePoint& point)
872{
873 if (point.present == Vanetza_Security_EccP384CurvePoint_PR_uncompressedP384) {
874 auto& unc = point.choice.uncompressedP384;
875 if (unc.y.size > 0 && unc.y.buf[unc.y.size - 1] & 0x01) {
876 assert(&point.choice.uncompressedP384.x == &point.choice.compressed_y_1);
877 point.present = Vanetza_Security_EccP384CurvePoint_PR_compressed_y_1;
878 } else {
879 assert(&point.choice.uncompressedP384.x == &point.choice.compressed_y_0);
880 point.present = Vanetza_Security_EccP384CurvePoint_PR_compressed_y_0;
881 }
882 return true;
883 } else if (point.present == Vanetza_Security_EccP384CurvePoint_PR_compressed_y_0 || point.present == Vanetza_Security_EccP384CurvePoint_PR_compressed_y_1) {
884 return true;
885 } else {
886 return false;
887 }
888}
889
890bool make_x_only(Vanetza_Security_EccP256CurvePoint& point)
891{
892 if (point.present == Vanetza_Security_EccP256CurvePoint_PR_uncompressedP256) {
893 assert(&point.choice.uncompressedP256.x == &point.choice.x_only);
894 point.present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
895 return true;
896 } else if (point.present == Vanetza_Security_EccP256CurvePoint_PR_x_only) {
897 return true;
898 } else {
899 return false;
900 }
901}
902
903bool make_x_only(Vanetza_Security_EccP384CurvePoint& point)
904{
905 if (point.present == Vanetza_Security_EccP384CurvePoint_PR_uncompressedP384) {
906 assert(&point.choice.uncompressedP384.x == &point.choice.x_only);
907 point.present = Vanetza_Security_EccP384CurvePoint_PR_x_only;
908 return true;
909 } else if (point.present == Vanetza_Security_EccP384CurvePoint_PR_x_only) {
910 return true;
911 } else {
912 return false;
913 }
914}
915
916bool make_signature_x_only(Vanetza_Security_Signature& sig)
917{
918 switch (sig.present) {
919 case Vanetza_Security_Signature_PR_ecdsaNistP256Signature:
920 return make_x_only(sig.choice.ecdsaNistP256Signature.rSig);
921 break;
922 case Vanetza_Security_Signature_PR_ecdsaBrainpoolP256r1Signature:
923 return make_x_only(sig.choice.ecdsaBrainpoolP256r1Signature.rSig);
924 break;
925 case Vanetza_Security_Signature_PR_ecdsaBrainpoolP384r1Signature:
926 return make_x_only(sig.choice.ecdsaBrainpoolP384r1Signature.rSig);
927 break;
928 default:
929 return false;
930 break;
931 }
932}
933
934} // namespace
935
936} // namespace v3
937} // namespace security
938} // namespace vanetza
boost::optional< Certificate > canonicalize() const
bool valid_at_timepoint(const Clock::time_point &time_point) const
StartAndEndValidity get_start_and_end_validity() const
bool valid_for_application(ItsAid aid) const
boost::optional< HashedId8 > calculate_digest() const
bool valid_at_location(const PositionFix &location, const LocationChecker *lc) const
boost::optional< HashedId8 > issuer_digest() const
STL namespace.