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/security/backend.hpp>
5#include <vanetza/security/v3/secured_message.hpp>
6#include <iterator>
7#include <boost/optional/optional.hpp>
8
9// asn1c quirk
10struct Certificate : public CertificateBase {};
11
12namespace vanetza
13{
14namespace security
15{
16namespace v3
17{
18
19namespace
20{
21
22const SignedData_t* get_signed_data(const EtsiTs103097Data_t* data)
23{
24 if (data && data->content && data->content->present == Ieee1609Dot2Content_PR_signedData) {
25 return data->content->choice.signedData;
26 } else {
27 return nullptr;
28 }
29}
30
31const HeaderInfo_t* get_header_info(const EtsiTs103097Data_t* data)
32{
33 const SignedData_t* signed_data = get_signed_data(data);
34 if (signed_data) {
35 return &signed_data->tbsData->headerInfo;
36 } else {
37 return nullptr;
38 }
39}
40
41HashedId8 make_hashed_id8(const HashedId8_t& asn)
42{
43 HashedId8 result;
44 std::copy_n(asn.buf, std::min(asn.size, result.size()), result.data());
45 return result;
46}
47
48ByteBuffer copy_octets(const OCTET_STRING_t& octets)
49{
50 ByteBuffer buffer(octets.size);
51 std::memcpy(buffer.data(), octets.buf, octets.size);
52 return buffer;
53}
54
55ByteBuffer get_x_coordinate(const EccP256CurvePoint_t& point)
56{
57 switch (point.present) {
58 case EccP256CurvePoint_PR_compressed_y_0:
59 return copy_octets(point.choice.compressed_y_0);
60 break;
61 case EccP256CurvePoint_PR_compressed_y_1:
62 return copy_octets(point.choice.compressed_y_1);
63 break;
64 case EccP256CurvePoint_PR_x_only:
65 return copy_octets(point.choice.x_only);
66 break;
67 case EccP256CurvePoint_PR_uncompressedP256:
68 return copy_octets(point.choice.uncompressedP256.x);
69 break;
70 default:
71 return ByteBuffer {};
72 break;
73 }
74}
75
76ByteBuffer get_x_coordinate(const EccP384CurvePoint_t& point)
77{
78 switch (point.present) {
79 case EccP384CurvePoint_PR_compressed_y_0:
80 return copy_octets(point.choice.compressed_y_0);
81 break;
82 case EccP384CurvePoint_PR_compressed_y_1:
83 return copy_octets(point.choice.compressed_y_1);
84 break;
85 case EccP384CurvePoint_PR_x_only:
86 return copy_octets(point.choice.x_only);
87 break;
88 case EccP384CurvePoint_PR_uncompressedP384:
89 return copy_octets(point.choice.uncompressedP384.x);
90 break;
91 default:
92 return ByteBuffer {};
93 break;
94 }
95}
96
97} // namespace
98
99SecuredMessage::SecuredMessage() :
100 asn1::asn1c_oer_wrapper<EtsiTs103097Data_t>(asn_DEF_EtsiTs103097Data)
101{
102}
103
104uint8_t SecuredMessage::protocol_version() const
105{
106 return m_struct->protocolVersion;
107}
108
109ItsAid SecuredMessage::its_aid() const
110{
111 ItsAid aid = 0;
112 if (m_struct->content->present == Ieee1609Dot2Content_PR_signedData) {
113 const SignedData* signed_data = m_struct->content->choice.signedData;
114 if (signed_data && signed_data->tbsData) {
115 aid = signed_data->tbsData->headerInfo.psid;
116 }
117 }
118 return aid;
119}
120
121PacketVariant SecuredMessage::payload() const
122{
123 ByteBuffer buffer;
124 switch (m_struct->content->present) {
125 case Ieee1609Dot2Content_PR_unsecuredData:
126 buffer = get_payload(&m_struct->content->choice.unsecuredData);
127 break;
128 case Ieee1609Dot2Content_PR_signedData:
129 buffer = get_payload(m_struct->content->choice.signedData);
130 break;
131 }
132
133 return CohesivePacket { std::move(buffer), OsiLayer::Network };
134}
135
136bool SecuredMessage::is_signed() const
137{
138 return m_struct->content->present == Ieee1609Dot2Content_PR_signedData;
139}
140
141boost::optional<SecuredMessage::Time64> SecuredMessage::generation_time() const
142{
143 boost::optional<Time64> gen_time;
144 auto header_info = get_header_info(m_struct);
145 if (header_info) {
146 std::uintmax_t tmp;
147 if (asn_INTEGER2umax(header_info->generationTime, &tmp) == 0) {
148 gen_time = tmp;
149 }
150 }
151 return gen_time;
152}
153
154boost::optional<Signature> SecuredMessage::signature() const
155{
156 const SignedData_t* signed_data = get_signed_data(m_struct);
157 if (signed_data) {
158 const Signature_t& asn = signed_data->signature;
159 Signature sig;
160 switch (asn.present)
161 {
162 case Signature_PR_ecdsaNistP256Signature:
163 sig.type = KeyType::NistP256;
164 sig.r = get_x_coordinate(asn.choice.ecdsaNistP256Signature.rSig);
165 sig.s = copy_octets(asn.choice.ecdsaNistP256Signature.sSig);
166 break;
167 case Signature_PR_ecdsaBrainpoolP256r1Signature:
168 sig.type = KeyType::BrainpoolP256r1;
169 sig.r = get_x_coordinate(asn.choice.ecdsaBrainpoolP256r1Signature.rSig);
170 sig.s = copy_octets(asn.choice.ecdsaBrainpoolP256r1Signature.sSig);
171 break;
172 case Signature_PR_ecdsaBrainpoolP384r1Signature:
173 sig.type = KeyType::BrainpoolP384r1;
174 sig.r = get_x_coordinate(asn.choice.ecdsaBrainpoolP384r1Signature.rSig);
175 sig.s = copy_octets(asn.choice.ecdsaBrainpoolP384r1Signature.sSig);
176 break;
177 default:
178 return boost::none;
179 }
180 return sig;
181 }
182
183 return boost::none;
184}
185
186SecuredMessage::SignerIdentifier SecuredMessage::signer_identifier() const
187{
188 const SignedData_t* signed_data = get_signed_data(m_struct);
189 if (signed_data) {
190 if (signed_data->signer.present == SignerIdentifier_PR_digest) {
191 return &signed_data->signer.choice.digest;
192 } else if (signed_data->signer.present == SignerIdentifier_PR_certificate) {
193 const SequenceOfCertificate_t& certificates = signed_data->signer.choice.certificate;
194 // TS 103 097 v1.3.1 contraints this to exactly one certificate in clause 5.2
195 if (certificates.list.count == 1) {
196 const Certificate_t* cert = certificates.list.array[0];
197 return cert;
198 }
199 }
200 }
201
202 return static_cast<HashedId8_t*>(nullptr);
203}
204
205ByteBuffer SecuredMessage::signing_payload() const
206{
207 const SignedData_t* signed_data = get_signed_data(m_struct);
208 if (signed_data) {
209 return asn1::encode_oer(asn_DEF_ToBeSignedData, signed_data->tbsData);
210 } else {
211 return ByteBuffer {};
212 }
213}
214
215size_t get_size(const SecuredMessage& message)
216{
217 return message.size();
218}
219
220void serialize(OutputArchive& ar, const SecuredMessage& msg)
221{
222 ByteBuffer buffer = msg.encode();
223 ar.save_binary(buffer.data(), buffer.size());
224}
225
226size_t deserialize(InputArchive& ar, SecuredMessage& msg)
227{
228 std::size_t len = ar.remaining_bytes();
229 // TODO optimize decoding step without buffer allocation
230 ByteBuffer buffer;
231 buffer.resize(len);
232 ar.load_binary(buffer.data(), len);
233 return msg.decode(buffer) ? len : 0;
234}
235
236ByteBuffer get_payload(const Opaque_t* unsecured)
237{
238 ByteBuffer buffer;
239 buffer.reserve(unsecured->size);
240 std::copy_n(unsecured->buf, unsecured->size, std::back_inserter(buffer));
241 return buffer;
242}
243
244ByteBuffer get_payload(const SignedData* signed_data)
245{
246 ByteBuffer buffer;
247 if (signed_data->tbsData && signed_data->tbsData->payload) {
248 const SignedDataPayload_t* signed_payload = signed_data->tbsData->payload;
249 if (signed_payload->data && signed_payload->data->content) {
250 const Ieee1609Dot2Content_t* content = signed_payload->data->content;
251 if (content->present == Ieee1609Dot2Content_PR_unsecuredData) {
252 buffer = get_payload(&content->choice.unsecuredData);
253 }
254 }
255 }
256 return buffer;
257}
258
259boost::optional<HashedId8> get_certificate_id(const SecuredMessage::SignerIdentifier& identifier)
260{
261 using result_type = boost::optional<HashedId8>;
262 struct cert_id_visitor : public boost::static_visitor<result_type> {
263 result_type operator()(const HashedId8_t* digest) const
264 {
265 return digest ? make_hashed_id8(*digest) : result_type { };
266 }
267
268 result_type operator()(const Certificate_t* cert) const
269 {
270 return cert ? calculate_hash(*cert) : result_type { };
271 }
272 };
273 return boost::apply_visitor(cert_id_visitor(), identifier);
274}
275
276} // namespace v3
277} // namespace security
278} // namespace vanetza