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