Vanetza
Loading...
Searching...
No Matches
secured_message.cpp
1#include <vanetza/asn1/asn1c_wrapper.hpp>
2#include <vanetza/asn1/security_profile.hpp>
3#include VANETZA_ASN1_SECURITY_HEADER(Certificate.h)
4#include VANETZA_ASN1_SECURITY_HEADER(EtsiTs103097Data.h)
5#include <vanetza/common/byte_buffer.hpp>
6#include <vanetza/common/byte_buffer_sink.hpp>
7#include <vanetza/net/packet.hpp>
8#include <vanetza/security/backend.hpp>
9#include <vanetza/security/v3/asn1_conversions.hpp>
10#include <vanetza/security/v3/secured_message.hpp>
11
12#include <boost/iostreams/stream.hpp>
13#include <boost/optional/optional.hpp>
14#include <boost/variant/static_visitor.hpp>
15
16// asn1c quirk
17struct Vanetza_Security_Certificate : public Vanetza_Security_CertificateBase {};
18
19namespace vanetza
20{
21namespace security
22{
23namespace v3
24{
25
26namespace
27{
28
29const asn1::SignedData* get_signed_data(const asn1::EtsiTs103097Data* data)
30{
31 if (data && data->content && data->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
32 return data->content->choice.signedData;
33 } else {
34 return nullptr;
35 }
36}
37
38const asn1::HeaderInfo* get_header_info(const asn1::EtsiTs103097Data* data)
39{
40 const asn1::SignedData* signed_data = get_signed_data(data);
41 if (signed_data) {
42 return &signed_data->tbsData->headerInfo;
43 } else {
44 return nullptr;
45 }
46}
47
48HashedId8 make_hashed_id8(const asn1::HashedId8& asn)
49{
50 HashedId8 result;
51 std::copy_n(asn.buf, std::min(asn.size, result.size()), result.data());
52 return result;
53}
54
55ByteBuffer copy_octets(const OCTET_STRING_t& octets)
56{
57 ByteBuffer buffer(octets.size);
58 std::memcpy(buffer.data(), octets.buf, octets.size);
59 return buffer;
60}
61
62ByteBuffer get_x_coordinate(const asn1::EccP256CurvePoint& point)
63{
64 switch (point.present) {
65 case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_0:
66 return copy_octets(point.choice.compressed_y_0);
67 break;
68 case Vanetza_Security_EccP256CurvePoint_PR_compressed_y_1:
69 return copy_octets(point.choice.compressed_y_1);
70 break;
71 case Vanetza_Security_EccP256CurvePoint_PR_x_only:
72 return copy_octets(point.choice.x_only);
73 break;
74 case Vanetza_Security_EccP256CurvePoint_PR_uncompressedP256:
75 return copy_octets(point.choice.uncompressedP256.x);
76 break;
77 default:
78 return ByteBuffer {};
79 break;
80 }
81}
82
83ByteBuffer get_x_coordinate(const asn1::EccP384CurvePoint& point)
84{
85 switch (point.present) {
86 case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_0:
87 return copy_octets(point.choice.compressed_y_0);
88 break;
89 case Vanetza_Security_EccP384CurvePoint_PR_compressed_y_1:
90 return copy_octets(point.choice.compressed_y_1);
91 break;
92 case Vanetza_Security_EccP384CurvePoint_PR_x_only:
93 return copy_octets(point.choice.x_only);
94 break;
95 case Vanetza_Security_EccP384CurvePoint_PR_uncompressedP384:
96 return copy_octets(point.choice.uncompressedP384.x);
97 break;
98 default:
99 return ByteBuffer {};
100 break;
101 }
102}
103
104} // namespace
105
106SecuredMessage SecuredMessage::with_signed_data()
107{
108 SecuredMessage secured_message;
109 secured_message->protocolVersion = 3;
110 secured_message->content = asn1::allocate<asn1::Ieee1609Dot2Content>();
111 secured_message->content->present = Vanetza_Security_Ieee1609Dot2Content_PR_signedData;
112 secured_message->content->choice.signedData = asn1::allocate<asn1::SignedData>();
113 secured_message->content->choice.signedData->tbsData = asn1::allocate<asn1::ToBeSignedData>();
114 secured_message->content->choice.signedData->tbsData->payload = asn1::allocate<asn1::SignedDataPayload>();
115 secured_message->content->choice.signedData->tbsData->payload->data = asn1::allocate<asn1::Ieee1609Dot2Data>();
116 secured_message->content->choice.signedData->tbsData->payload->data->protocolVersion = 3;
117 secured_message->content->choice.signedData->tbsData->payload->data->content = asn1::allocate<asn1::Ieee1609Dot2Content>();
118 secured_message->content->choice.signedData->tbsData->payload->data->content->present = Vanetza_Security_Ieee1609Dot2Content_PR_unsecuredData;
119 return secured_message;
120}
121
122SecuredMessage SecuredMessage::with_signed_data_hash()
123{
124 SecuredMessage secured_message;
125 secured_message->protocolVersion = 3;
126 secured_message->content = asn1::allocate<asn1::Ieee1609Dot2Content>();
127 secured_message->content->present = Vanetza_Security_Ieee1609Dot2Content_PR_signedData;
128 secured_message->content->choice.signedData = asn1::allocate<asn1::SignedData>();
129 secured_message->content->choice.signedData->tbsData = asn1::allocate<asn1::ToBeSignedData>();
130 secured_message->content->choice.signedData->tbsData->payload = asn1::allocate<asn1::SignedDataPayload>();
131 secured_message->content->choice.signedData->tbsData->payload->extDataHash = asn1::allocate<asn1::HashedData>();
132 secured_message->content->choice.signedData->tbsData->payload->extDataHash->present = Vanetza_Security_HashedData_PR_sha256HashedData;
133 return secured_message;
134}
135
136SecuredMessage SecuredMessage::with_encrypted_data()
137{
138 SecuredMessage secured_message;
139 secured_message->protocolVersion = 3;
140 secured_message->content = asn1::allocate<asn1::Ieee1609Dot2Content>();
141 secured_message->content->present = Vanetza_Security_Ieee1609Dot2Content_PR_encryptedData;
142 return secured_message;
143}
144
145SecuredMessage::SecuredMessage() :
146 asn1::asn1c_oer_wrapper<asn1::EtsiTs103097Data>(asn_DEF_Vanetza_Security_EtsiTs103097Data)
147{
148}
149
150uint8_t SecuredMessage::protocol_version() const
151{
152 return m_struct->protocolVersion;
153}
154
155boost::optional<HashedId8> SecuredMessage::certificate_id() const
156{
157 return get_certificate_id(signer_identifier());
158}
159
160ItsAid SecuredMessage::its_aid() const
161{
162 ItsAid aid = 0;
163 const asn1::SignedData* signed_data = get_signed_data(m_struct);
164 if (signed_data && signed_data->tbsData) {
165 aid = signed_data->tbsData->headerInfo.psid;
166 }
167 return aid;
168}
169
170void SecuredMessage::set_its_aid(ItsAid its_aid)
171{
172 if (m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
173 asn1::SignedData* signed_data = m_struct->content->choice.signedData;
174 if (signed_data && signed_data->tbsData) {
175 signed_data->tbsData->headerInfo.psid = its_aid;
176 }
177 }
178}
179
180void SecuredMessage::set_generation_time(Time64 time)
181{
182 if (m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
183 if (m_struct->content->choice.signedData->tbsData->headerInfo.generationTime == nullptr) {
184 m_struct->content->choice.signedData->tbsData->headerInfo.generationTime = asn1::allocate<asn1::Time64>();
185 }
186 asn_uint642INTEGER(m_struct->content->choice.signedData->tbsData->headerInfo.generationTime, time);
187 }
188}
189
190void SecuredMessage::set_generation_location(const asn1::ThreeDLocation& location)
191{
192 if (m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
193 if (m_struct->content->choice.signedData->tbsData->headerInfo.generationLocation == nullptr) {
194 m_struct->content->choice.signedData->tbsData->headerInfo.generationLocation = asn1::allocate<asn1::ThreeDLocation>();
195 }
196 m_struct->content->choice.signedData->tbsData->headerInfo.generationLocation->latitude = location.latitude;
197 m_struct->content->choice.signedData->tbsData->headerInfo.generationLocation->longitude = location.longitude;
198 m_struct->content->choice.signedData->tbsData->headerInfo.generationLocation->elevation = location.elevation;
199 }
200}
201
202std::list<HashedId3> SecuredMessage::get_inline_p2pcd_request() const
203{
204 std::list<HashedId3> requests;
205 if (m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
206 const asn1::SequenceOfHashedId3* inline_p2pcd_request = m_struct->content->choice.signedData->tbsData->headerInfo.inlineP2pcdRequest;
207 if (inline_p2pcd_request) {
208 for (int i = 0; i < inline_p2pcd_request->list.count; i++) {
209 HashedId3 new_elem = truncate(convert(*inline_p2pcd_request->list.array[i]));
210 requests.push_back(new_elem);
211 }
212 }
213 }
214 return requests;
215}
216
217void SecuredMessage::set_inline_p2pcd_request(std::list<HashedId3> requests)
218{
219 if (m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
220 assert(m_struct->content->choice.signedData);
221 assert(m_struct->content->choice.signedData->tbsData);
222
223 if (m_struct->content->choice.signedData->tbsData->headerInfo.inlineP2pcdRequest) {
224 asn1::reset(m_struct->content->choice.signedData->tbsData->headerInfo.inlineP2pcdRequest);
225 }
226
227 for (HashedId3 request : requests) {
228 this->add_inline_p2pcd_request(request);
229 }
230 }
231}
232
233void SecuredMessage::add_inline_p2pcd_request(HashedId3 unknown_certificate_digest)
234{
235 if (m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
236 if (m_struct->content->choice.signedData->tbsData->headerInfo.inlineP2pcdRequest == nullptr) {
237 m_struct->content->choice.signedData->tbsData->headerInfo.inlineP2pcdRequest = asn1::allocate<asn1::SequenceOfHashedId3>();
238 }
239 Vanetza_Security_HashedId3_t* asn_digest = OCTET_STRING_new_fromBuf(&asn_DEF_Vanetza_Security_HashedId3,
240 reinterpret_cast<char*>(unknown_certificate_digest.data()), unknown_certificate_digest.size());
241 ASN_SEQUENCE_ADD(m_struct->content->choice.signedData->tbsData->headerInfo.inlineP2pcdRequest, asn_digest);
242 }
243}
244
245void SecuredMessage::set_dummy_signature()
246{
247 if (m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
248 asn1::SignedData* signed_data = m_struct->content->choice.signedData;
249 if (signed_data) {
250 // Reset the signature structure
251 asn1::reset(signed_data->signature);
252
253 // Set the signature type to ECDSA NIST P256
254 signed_data->signature.present = Vanetza_Security_Signature_PR_ecdsaNistP256Signature;
255
256 // Initialize rSig part of the signature
257 signed_data->signature.choice.ecdsaNistP256Signature.rSig.present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
258 std::vector<uint8_t> dummy_r(32, 0); // Correct length for P256 signature part
259 dummy_r[0] = 0; // Ensure the leading byte is set to zero if needed
260 assign(&signed_data->signature.choice.ecdsaNistP256Signature.rSig.choice.x_only, dummy_r);
261
262 // Initialize sSig part of the signature
263 std::vector<uint8_t> dummy_s(32, 0); // Correct length for P256 signature part
264 assign(&signed_data->signature.choice.ecdsaNistP256Signature.sSig, dummy_s);
265 }
266 }
267}
268
269void SecuredMessage::set_signature(const Signature& signature)
270{
271 if (m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData) {
272 asn1::SignedData* signed_data = m_struct->content->choice.signedData;
273 if (signed_data) {
274 // Reset the signature structure
275 asn1::reset(signed_data->signature);
276
277 // Set the signature type to ECDSA NIST P256
278 switch (signature.type)
279 {
280 case vanetza::security::KeyType::NistP256:
281 signed_data->signature.present = Vanetza_Security_Signature_PR_ecdsaNistP256Signature;
282 // Initialize rSig and sSig part of the signature
283
284 // Check the type (x_only, y-1, y-0 or uncompressed ??????)
285 signed_data->signature.choice.ecdsaNistP256Signature.rSig.present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
286 assign(&signed_data->signature.choice.ecdsaNistP256Signature.rSig.choice.x_only, signature.r);
287 assign(&signed_data->signature.choice.ecdsaNistP256Signature.sSig, signature.s);
288 break;
289 case vanetza::security::KeyType::BrainpoolP256r1 :
290 signed_data->signature.present = Vanetza_Security_Signature_PR_ecdsaBrainpoolP256r1Signature;
291 // Check the type (x_only, y-1, y-0 or uncompressed ??????)
292 signed_data->signature.choice.ecdsaBrainpoolP256r1Signature.rSig.present = Vanetza_Security_EccP256CurvePoint_PR_x_only;
293 assign(&signed_data->signature.choice.ecdsaBrainpoolP256r1Signature.rSig.choice.x_only, signature.r);
294 assign(&signed_data->signature.choice.ecdsaBrainpoolP256r1Signature.sSig, signature.s);
295 break;
296 case vanetza::security::KeyType::BrainpoolP384r1 :
297 signed_data->signature.present = Vanetza_Security_Signature_PR_ecdsaBrainpoolP384r1Signature;
298 // Check the type (x_only, y-1, y-0 or uncompressed ??????)
299 signed_data->signature.choice.ecdsaBrainpoolP384r1Signature.rSig.present = Vanetza_Security_EccP384CurvePoint_PR_x_only;
300 assign(&signed_data->signature.choice.ecdsaBrainpoolP384r1Signature.rSig.choice.x_only, signature.r);
301 assign(&signed_data->signature.choice.ecdsaBrainpoolP384r1Signature.sSig, signature.s);
302 break;
303 default:
304 this->set_dummy_signature();
305 break;
306 }
307 }
308 }
309}
310
311void SecuredMessage::set_signature(const SomeEcdsaSignature& signature)
312{
313 struct signature_visitor : public boost::static_visitor<asn1::Signature>
314 {
315 asn1::Signature operator()(const EcdsaSignature& signature) const
316 {
317 asn1::Signature final_signature = {};
318 final_signature.present = Vanetza_Security_Signature_PR_ecdsaNistP256Signature;
319 assign(&final_signature.choice.ecdsaNistP256Signature.sSig, signature.s);
320 final_signature.choice.ecdsaNistP256Signature.rSig = to_asn1(signature.R);
321 return final_signature;
322 }
323
324 asn1::Signature operator()(const EcdsaSignatureFuture& signature) const
325 {
326 return this->operator()(signature.get());
327 }
328 };
329
330 asn1::reset(m_struct->content->choice.signedData->signature);
331 m_struct->content->choice.signedData->signature = boost::apply_visitor(signature_visitor(), signature);
332}
333
334PacketVariant SecuredMessage::payload() const
335{
336 ByteBuffer buffer;
337 switch (m_struct->content->present) {
338 case Vanetza_Security_Ieee1609Dot2Content_PR_unsecuredData:
339 buffer = get_payload(&m_struct->content->choice.unsecuredData);
340 break;
341 case Vanetza_Security_Ieee1609Dot2Content_PR_signedData:
342 buffer = get_payload(m_struct->content->choice.signedData);
343 break;
344 default:
345 // empty buffer as fallback
346 break;
347 }
348
349 return CohesivePacket { std::move(buffer), OsiLayer::Network };
350}
351
352void SecuredMessage::set_payload(const ByteBuffer& payload)
353{
354 switch (m_struct->content->present) {
355 case Vanetza_Security_Ieee1609Dot2Content_PR_unsecuredData:
356 vanetza::security::v3::set_payload(&m_struct->content->choice.unsecuredData, payload);
357 break;
358 case Vanetza_Security_Ieee1609Dot2Content_PR_signedData:
359 vanetza::security::v3::set_payload(&m_struct->content->choice.signedData->tbsData->payload->data->content->choice.unsecuredData, payload);
360 break;
361 default:
362 // cannot copy payload into secured message
363 break;
364 }
365}
366
367void SecuredMessage::set_external_payload_hash(const Sha256Digest& hash)
368{
369 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData);
370 asn1::HashedData* hashed_data = m_struct->content->choice.signedData->tbsData->payload->extDataHash;
371 asn1::reset(hashed_data);
372 hashed_data->present = Vanetza_Security_HashedData_PR_sha256HashedData;
373 OCTET_STRING_fromBuf(&hashed_data->choice.sha256HashedData, reinterpret_cast<const char*>(hash.data()), hash.size());
374}
375
376HashAlgorithm SecuredMessage::hash_id() const
377{
378 HashAlgorithm algo = HashAlgorithm::Unspecified;
379
380 const asn1::SignedData* signed_data = get_signed_data(m_struct);
381 if (signed_data) {
382 switch (signed_data->hashId) {
383 case Vanetza_Security_HashAlgorithm_sha256:
384 algo = HashAlgorithm::SHA256;
385 break;
386 case Vanetza_Security_HashAlgorithm_sha384:
387 algo = HashAlgorithm::SHA384;
388 break;
389 default:
390 break;
391 }
392 }
393
394 return algo;
395}
396
397void SecuredMessage::set_hash_id(HashAlgorithm hash)
398{
399 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData);
400 switch (hash) {
401 case HashAlgorithm::SHA256:
402 m_struct->content->choice.signedData->hashId = Vanetza_Security_HashAlgorithm_sha256;
403 break;
404 case HashAlgorithm::SHA384:
405 m_struct->content->choice.signedData->hashId = Vanetza_Security_HashAlgorithm_sha384;
406 break;
407 default:
408 m_struct->content->choice.signedData->hashId = -1;
409 }
410}
411
412void SecuredMessage::set_signer_identifier_self()
413{
414 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData);
415 asn1::SignerIdentifier* signer = &m_struct->content->choice.signedData->signer;
416 asn1::reset(signer);
417 signer->present = Vanetza_Security_SignerIdentifier_PR_self;
418}
419
420void SecuredMessage::set_signer_identifier(const HashedId8& digest)
421{
422 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData);
423 asn1::SignerIdentifier* signer = &m_struct->content->choice.signedData->signer;
424 asn1::reset(signer);
425 signer->present = Vanetza_Security_SignerIdentifier_PR_digest;
426 OCTET_STRING_fromBuf(&signer->choice.digest, reinterpret_cast<const char*>(digest.data()), digest.size());
427}
428
429void SecuredMessage::set_signer_identifier(const Certificate& cert)
430{
431 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData);
432 asn1::SignerIdentifier* signer = &m_struct->content->choice.signedData->signer;
433 asn1::reset(signer);
434 signer->present = Vanetza_Security_SignerIdentifier_PR_certificate;
435 ASN_SEQUENCE_ADD(&signer->choice.certificate, asn1::copy(asn_DEF_Vanetza_Security_EtsiTs103097Certificate, cert.content()));
436}
437
438void SecuredMessage::get_aes_ccm_ciphertext(ByteBuffer &ccm_ciphertext, std::array<uint8_t, 12> &nonce) const
439{
440 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_encryptedData);
441
442 const asn1::SymmetricCiphertext &symmetric_ciphertext = m_struct->content->choice.encryptedData.ciphertext;
443 assert(symmetric_ciphertext.present == Vanetza_Security_SymmetricCiphertext_PR_aes128ccm);
444
445 const asn1::AesCcmCiphertext &aes_ccm_ciphertext = symmetric_ciphertext.choice.aes128ccm;
446 ccm_ciphertext = copy_octets(aes_ccm_ciphertext.ccmCiphertext);
447 std::memcpy(nonce.data(), aes_ccm_ciphertext.nonce.buf, nonce.size());
448}
449
450void SecuredMessage::set_aes_ccm_ciphertext(const ByteBuffer &ccm_ciphertext, const std::array<uint8_t, 12> &nonce)
451{
452 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_encryptedData);
453
454 asn1::SymmetricCiphertext &symmetric_ciphertext = m_struct->content->choice.encryptedData.ciphertext;
455 CHOICE_variant_set_presence(&asn_DEF_Vanetza_Security_SymmetricCiphertext, &symmetric_ciphertext, Vanetza_Security_SymmetricCiphertext_PR_aes128ccm);
456
457 asn1::AesCcmCiphertext &aes_ccm_ciphertext = symmetric_ciphertext.choice.aes128ccm;
458 OCTET_STRING_fromBuf(&aes_ccm_ciphertext.ccmCiphertext, reinterpret_cast<const char *>(ccm_ciphertext.data()), ccm_ciphertext.size());
459 OCTET_STRING_fromBuf(&aes_ccm_ciphertext.nonce, reinterpret_cast<const char *>(nonce.data()), nonce.size());
460}
461
462void SecuredMessage::set_cert_recip_info(const HashedId8& recipient_id,
463 const std::array<uint8_t, 16>& ecies_ciphertext,
464 const std::array<uint8_t, 16>& ecies_tag,
465 const PublicKey& ecies_pub_key)
466{
467 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_encryptedData);
468
469 // own the RecipientInfo until it is handed to the message (exception safety)
470 auto cert_recip_info = asn1::make_unique<asn1::RecipientInfo>();
471 CHOICE_variant_set_presence(&asn_DEF_Vanetza_Security_RecipientInfo, cert_recip_info.get(), Vanetza_Security_RecipientInfo_PR_certRecipInfo);
472
473 asn1::PKRecipientInfo &pk_recip_info = cert_recip_info->choice.certRecipInfo;
474 // Set recipient certificate digest
475 OCTET_STRING_fromBuf(&pk_recip_info.recipientId, reinterpret_cast<const char *>(recipient_id.data()), recipient_id.size());
476
477 asn1::EncryptedDataEncryptionKey &enc_data_enc_key = pk_recip_info.encKey;
478 asn1::EciesP256EncryptedKey *ecies_enc_key = nullptr;
479 if (ecies_pub_key.type == KeyType::NistP256) {
480 enc_data_enc_key.present = Vanetza_Security_EncryptedDataEncryptionKey_PR_eciesNistP256;
481 ecies_enc_key = &enc_data_enc_key.choice.eciesNistP256;
482 } else if (ecies_pub_key.type == KeyType::BrainpoolP256r1) {
483 enc_data_enc_key.present = Vanetza_Security_EncryptedDataEncryptionKey_PR_eciesBrainpoolP256r1;
484 ecies_enc_key = &enc_data_enc_key.choice.eciesBrainpoolP256r1;
485 } else {
486 throw std::invalid_argument("Unsupported EC curve");
487 }
488
489 // Set ECIES ciphertext and tag
490 OCTET_STRING_fromBuf(&ecies_enc_key->c, reinterpret_cast<const char *>(ecies_ciphertext.data()), ecies_ciphertext.size());
491 OCTET_STRING_fromBuf(&ecies_enc_key->t, reinterpret_cast<const char *>(ecies_tag.data()), ecies_tag.size());
492
493 // Set ECIES ephemeral public key
494 ecies_enc_key->v = to_asn1(make_ecc_point(ecies_pub_key));
495
496 ASN_SEQUENCE_ADD(&m_struct->content->choice.encryptedData.recipients.list, cert_recip_info.release());
497}
498
499bool SecuredMessage::check_psk_match(const std::array<uint8_t, 16>& psk) const
500{
501 assert(m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_encryptedData);
502
503 // Wrap the given PSK into a PSKRecipientInfo_t to calculate the HashedId8
504 asn1::asn1c_oer_wrapper<asn1::SymmetricEncryptionKey> psk_key(asn_DEF_Vanetza_Security_SymmetricEncryptionKey);
505 asn1::SymmetricEncryptionKey *psk_key_ptr = &(*psk_key);
506 CHOICE_variant_set_presence(
507 &asn_DEF_Vanetza_Security_SymmetricEncryptionKey,
508 psk_key_ptr,
509 Vanetza_Security_SymmetricEncryptionKey_PR_aes128Ccm);
510 OCTET_STRING_fromBuf(&psk_key_ptr->choice.aes128Ccm, reinterpret_cast<const char *>(psk.data()), psk.size());
511
512 ByteBuffer bytes = psk_key.encode();
513 Sha256Digest psk_digest = calculate_sha256_digest(bytes.data(), bytes.size());
514 HashedId8 psk_id = create_hashed_id8(psk_digest);
515
516 // Check every RecipientInfo for a PSKRecipientInfo with matching PSK
517 const auto &recipient_list = m_struct->content->choice.encryptedData.recipients.list;
518
519 for (int i = 0; i < recipient_list.count; i++) {
520 const asn1::RecipientInfo &recipient_info = *recipient_list.array[i];
521 if (recipient_info.present != Vanetza_Security_RecipientInfo_PR_pskRecipInfo) {
522 continue;
523 }
524
525 HashedId8 message_psk_id;
526 std::memcpy(message_psk_id.data(), recipient_info.choice.pskRecipInfo.buf, message_psk_id.size());
527 if (psk_id == message_psk_id) {
528 return true;
529 }
530 }
531
532 return false;
533}
534
535bool SecuredMessage::is_signed() const
536{
537 return m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_signedData;
538}
539
540bool SecuredMessage::is_encrypted() const
541{
542 return m_struct->content->present == Vanetza_Security_Ieee1609Dot2Content_PR_encryptedData;
543}
544
545boost::optional<SecuredMessage::Time64> SecuredMessage::generation_time() const
546{
547 boost::optional<Time64> gen_time;
548 auto header_info = get_header_info(m_struct);
549 if (header_info) {
550 std::uintmax_t tmp;
551 if (asn_INTEGER2umax(header_info->generationTime, &tmp) == 0) {
552 gen_time = tmp;
553 }
554 }
555 return gen_time;
556}
557
558boost::optional<Signature> SecuredMessage::signature() const
559{
560 const asn1::SignedData* signed_data = get_signed_data(m_struct);
561 if (signed_data) {
562 const asn1::Signature& asn = signed_data->signature;
563 Signature sig;
564 switch (asn.present)
565 {
566 case Vanetza_Security_Signature_PR_ecdsaNistP256Signature:
567 sig.type = KeyType::NistP256;
568 sig.r = get_x_coordinate(asn.choice.ecdsaNistP256Signature.rSig);
569 sig.s = copy_octets(asn.choice.ecdsaNistP256Signature.sSig);
570 break;
571 case Vanetza_Security_Signature_PR_ecdsaBrainpoolP256r1Signature:
572 sig.type = KeyType::BrainpoolP256r1;
573 sig.r = get_x_coordinate(asn.choice.ecdsaBrainpoolP256r1Signature.rSig);
574 sig.s = copy_octets(asn.choice.ecdsaBrainpoolP256r1Signature.sSig);
575 break;
576 case Vanetza_Security_Signature_PR_ecdsaBrainpoolP384r1Signature:
577 sig.type = KeyType::BrainpoolP384r1;
578 sig.r = get_x_coordinate(asn.choice.ecdsaBrainpoolP384r1Signature.rSig);
579 sig.s = copy_octets(asn.choice.ecdsaBrainpoolP384r1Signature.sSig);
580 break;
581 default:
582 return boost::none;
583 }
584 return sig;
585 }
586
587 return boost::none;
588}
589
590SecuredMessage::SignerIdentifier SecuredMessage::signer_identifier() const
591{
592 const asn1::SignedData* signed_data = get_signed_data(m_struct);
593 if (signed_data) {
594 if (signed_data->signer.present == Vanetza_Security_SignerIdentifier_PR_digest) {
595 const asn1::HashedId8* digest = &signed_data->signer.choice.digest;
596 return digest;
597 } else if (signed_data->signer.present == Vanetza_Security_SignerIdentifier_PR_certificate) {
598 const asn1::SequenceOfCertificate& certificates = signed_data->signer.choice.certificate;
599 // TS 103 097 v1.3.1 contraints this to exactly one certificate in clause 5.2
600 if (certificates.list.count == 1) {
601 const asn1::Certificate* cert = certificates.list.array[0];
602 return cert;
603 }
604 }
605 }
606
607 return static_cast<asn1::HashedId8*>(nullptr);
608}
609
610ByteBuffer SecuredMessage::signing_payload() const
611{
612 const asn1::SignedData* signed_data = get_signed_data(m_struct);
613 if (signed_data) {
614 return asn1::encode_oer(asn_DEF_Vanetza_Security_ToBeSignedData, signed_data->tbsData);
615 } else {
616 return ByteBuffer {};
617 }
618}
619
620void SecuredMessage::set_requested_certificate(const Certificate& cert)
621{
622 const asn1::SignedData* signed_data = get_signed_data(m_struct);
623 if (signed_data && signed_data->tbsData) {
624 if (signed_data->tbsData->headerInfo.requestedCertificate) {
625 ASN_STRUCT_FREE(asn_DEF_Vanetza_Security_Certificate, signed_data->tbsData->headerInfo.requestedCertificate);
626 }
627 signed_data->tbsData->headerInfo.requestedCertificate =
628 static_cast<Vanetza_Security_Certificate*>(asn1::copy(asn_DEF_Vanetza_Security_Certificate, cert.content()));
629 }
630}
631
632size_t get_size(const SecuredMessage& message)
633{
634 return message.size();
635}
636
637void serialize(OutputArchive& ar, const SecuredMessage& msg)
638{
639 ByteBuffer buffer = msg.encode();
640 ar.save_binary(buffer.data(), buffer.size());
641}
642
643size_t deserialize(InputArchive& ar, SecuredMessage& msg)
644{
645 std::size_t len = ar.remaining_bytes();
646 // TODO optimize decoding step without buffer allocation
647 ByteBuffer buffer;
648 buffer.resize(len);
649 ar.load_binary(buffer.data(), len);
650 return msg.decode(buffer) ? len : 0;
651}
652
653ByteBuffer get_payload(const asn1::Opaque* unsecured)
654{
655 ByteBuffer buffer;
656 buffer.reserve(unsecured->size);
657 std::copy_n(unsecured->buf, unsecured->size, std::back_inserter(buffer));
658 return buffer;
659}
660
661ByteBuffer convert_to_payload(vanetza::DownPacket packet)
662{
663 ByteBuffer buf;
664 byte_buffer_sink sink(buf);
665
666 boost::iostreams::stream_buffer<byte_buffer_sink> stream(sink);
667 OutputArchive ar(stream);
668
669 serialize(ar, packet);
670
671 stream.close();
672 return buf;
673}
674
675void set_payload(asn1::Opaque* unsecured, const ByteBuffer& buffer)
676{
677 OCTET_STRING_fromBuf(unsecured, reinterpret_cast<const char*>(buffer.data()), buffer.size());
678}
679
680ByteBuffer get_payload(const asn1::SignedData* signed_data)
681{
682 ByteBuffer buffer;
683 if (signed_data->tbsData && signed_data->tbsData->payload) {
684 const asn1::SignedDataPayload* signed_payload = signed_data->tbsData->payload;
685 if (signed_payload->data && signed_payload->data->content) {
686 const asn1::Ieee1609Dot2Content* content = signed_payload->data->content;
687 if (content->present == Vanetza_Security_Ieee1609Dot2Content_PR_unsecuredData) {
688 buffer = get_payload(&content->choice.unsecuredData);
689 }
690 }
691 }
692 return buffer;
693}
694
695boost::optional<HashedId8> get_certificate_id(const SecuredMessage::SignerIdentifier& identifier)
696{
697 using result_type = boost::optional<HashedId8>;
698 struct cert_id_visitor : public boost::static_visitor<result_type> {
699 result_type operator()(const asn1::HashedId8* digest) const
700 {
701 return digest ? make_hashed_id8(*digest) : result_type { };
702 }
703
704 result_type operator()(const asn1::Certificate* cert) const
705 {
706 return cert ? calculate_digest(*cert) : result_type { };
707 }
708 };
709 return boost::apply_visitor(cert_id_visitor(), identifier);
710}
711
712bool contains_certificate(const SecuredMessage::SignerIdentifier& identifier)
713{
714 struct visitor : public boost::static_visitor<bool> {
715 bool operator()(const asn1::HashedId8*) const
716 {
717 return false;
718 }
719
720 bool operator()(const asn1::Certificate*) const
721 {
722 return true;
723 }
724 };
725 return boost::apply_visitor(visitor(), identifier);
726}
727
728const asn1::Certificate* get_certificate(const SecuredMessage::SignerIdentifier& identifier)
729{
730 struct visitor : public boost::static_visitor<const asn1::Certificate*> {
731 const asn1::Certificate* operator()(const asn1::HashedId8*) const
732 {
733 return nullptr;
734 }
735
736 const asn1::Certificate* operator()(const asn1::Certificate* cert) const
737 {
738 return cert;
739 }
740 };
741 return boost::apply_visitor(visitor(), identifier);
742}
743
744} // namespace v3
745} // namespace security
746} // namespace vanetza
EcdsaSignature specified in TS 103 097 v1.2.1, section 4.2.9.
Definition signature.hpp:17