Vanetza
 
Loading...
Searching...
No Matches
certificate.cpp
1#include <vanetza/common/byte_buffer_sink.hpp>
2#include <vanetza/common/serialization_buffer.hpp>
3#include <vanetza/security/exception.hpp>
4#include <vanetza/security/sha.hpp>
5#include <vanetza/security/v2/certificate.hpp>
6#include <vanetza/security/v2/length_coding.hpp>
7#include <vanetza/security/v2/signer_info.hpp>
8#include <vanetza/security/v2/validity_restriction.hpp>
9#include <boost/iostreams/stream.hpp>
10#include <boost/variant/apply_visitor.hpp>
11#include <boost/variant/get.hpp>
12#include <boost/variant/static_visitor.hpp>
13#include <algorithm>
14#include <array>
15#include <cstdint>
16
17namespace vanetza
18{
19namespace security
20{
21namespace v2
22{
23
24size_t get_size(const Certificate& cert)
25{
26 size_t size = sizeof(cert.version());
27 size += get_size(cert.signer_info);
28 size += get_size(cert.subject_info);
29 size += get_size(cert.subject_attributes);
30 size += length_coding_size(get_size(cert.subject_attributes));
31 size += get_size(cert.validity_restriction);
32 size += length_coding_size(get_size(cert.validity_restriction));
33 size += get_size(cert.signature);
34 return size;
35}
36
37
38void serialize(OutputArchive& ar, const Certificate& cert)
39{
40 serialize(ar, host_cast(cert.version()));
41 serialize(ar, cert.signer_info);
42 serialize(ar, cert.subject_info);
43 serialize(ar, cert.subject_attributes);
44 serialize(ar, cert.validity_restriction);
45 serialize(ar, cert.signature);
46}
47
48size_t deserialize(InputArchive& ar, Certificate& cert)
49{
50 uint8_t version = 0;
51 deserialize(ar, version);
52 size_t size = sizeof(cert.version());
53 if (2 == version) {
54 size += deserialize(ar, cert.signer_info);
55 size += deserialize(ar, cert.subject_info);
56 size += deserialize(ar, cert.subject_attributes);
57 size += length_coding_size(get_size(cert.subject_attributes));
58 size += deserialize(ar, cert.validity_restriction);
59 size += length_coding_size(get_size(cert.validity_restriction));
60 size += deserialize(ar, cert.signature);
61 } else {
62 throw deserialization_error("Unsupported Certificate version");
63 }
64
65 return size;
66}
67
68ByteBuffer convert_for_signing(const Certificate& cert)
69{
70 ByteBuffer buf;
71 byte_buffer_sink sink(buf);
72
73 boost::iostreams::stream_buffer<byte_buffer_sink> stream(sink);
74 OutputArchive ar(stream);
75
76 const uint8_t version = cert.version();
77 ar << version;
78 serialize(ar, cert.signer_info);
79 serialize(ar, cert.subject_info);
80 serialize(ar, cert.subject_attributes);
81 serialize(ar, cert.validity_restriction);
82
83 stream.close();
84 return buf;
85}
86
87void sort(Certificate& cert)
88{
89 cert.subject_attributes.sort([](const SubjectAttribute& a, const SubjectAttribute& b) {
90 const SubjectAttributeType type_a = get_type(a);
91 const SubjectAttributeType type_b = get_type(b);
92
93 // all fields must be encoded in ascending order
94 using enum_int = std::underlying_type<SubjectAttributeType>::type;
95 return static_cast<enum_int>(type_a) < static_cast<enum_int>(type_b);
96 });
97
98 cert.validity_restriction.sort([](const ValidityRestriction& a, const ValidityRestriction& b) {
99 const ValidityRestrictionType type_a = get_type(a);
100 const ValidityRestrictionType type_b = get_type(b);
101
102 // all fields must be encoded in ascending order
103 using enum_int = std::underlying_type<ValidityRestrictionType>::type;
104 return static_cast<enum_int>(type_a) < static_cast<enum_int>(type_b);
105 });
106}
107
108boost::optional<Uncompressed> get_uncompressed_public_key(const Certificate& cert, Backend& backend)
109{
110 boost::optional<Uncompressed> public_key_coordinates;
111 for (auto& attribute : cert.subject_attributes) {
112 if (get_type(attribute) == SubjectAttributeType::Verification_Key) {
113 const VerificationKey& verification_key = boost::get<VerificationKey>(attribute);
114 const EccPoint& ecc_point = boost::get<ecdsa_nistp256_with_sha256>(verification_key.key).public_key;
115 public_key_coordinates = backend.decompress_point(ecc_point);
116 break;
117 }
118 }
119
120 return public_key_coordinates;
121}
122
123boost::optional<ecdsa256::PublicKey> get_public_key(const Certificate& cert, Backend& backend)
124{
125 auto unc = get_uncompressed_public_key(cert, backend);
126 boost::optional<ecdsa256::PublicKey> result;
127 ecdsa256::PublicKey pub;
128 if (unc && unc->x.size() == pub.x.size() && unc->y.size() == pub.y.size()) {
129 std::copy_n(unc->x.begin(), pub.x.size(), pub.x.data());
130 std::copy_n(unc->y.begin(), pub.y.size(), pub.y.data());
131 result = std::move(pub);
132 }
133 return result;
134}
135
136HashedId8 calculate_hash(const Certificate& cert)
137{
138 Certificate canonical_cert = cert;
139
140 // canonical encoding according to TS 103 097 V1.2.1, section 4.2.12
141 boost::optional<EcdsaSignature> signature = extract_ecdsa_signature(cert.signature);
142 if (signature) {
143 struct canonical_visitor : public boost::static_visitor<EccPoint>
144 {
145 EccPoint operator()(const X_Coordinate_Only& x_only) const
146 {
147 return x_only;
148 }
149
150 EccPoint operator()(const Compressed_Lsb_Y_0& y0) const
151 {
152 return X_Coordinate_Only { y0.x };
153 }
154
155 EccPoint operator()(const Compressed_Lsb_Y_1& y1) const
156 {
157 return X_Coordinate_Only { y1.x };
158 }
159
160 EccPoint operator()(const Uncompressed& unc) const
161 {
162 return X_Coordinate_Only { unc.x };
163 }
164 };
165
166 EcdsaSignature canonical_sig;
167 canonical_sig.s = signature->s;
168 canonical_sig.R = boost::apply_visitor(canonical_visitor(), signature->R);
169 assert(get_type(canonical_sig.R) == EccPointType::X_Coordinate_Only);
170 canonical_cert.signature = canonical_sig;
171 }
172
173 ByteBuffer bytes;
174 serialize_into_buffer(canonical_cert, bytes);
175
176 HashedId8 id;
177 Sha256Digest digest = calculate_sha256_digest(bytes.data(), bytes.size());
178 assert(digest.size() >= id.size());
179 std::copy(digest.end() - id.size(), digest.end(), id.begin());
180 return id;
181}
182
183const SubjectAttribute* Certificate::get_attribute(SubjectAttributeType sat) const
184{
185 const SubjectAttribute* match = nullptr;
186 for (auto& attribute : subject_attributes) {
187 if (get_type(attribute) == sat) {
188 match = &attribute;
189 break;
190 }
191 }
192 return match;
193}
194
195const ValidityRestriction* Certificate::get_restriction(ValidityRestrictionType vrt) const
196{
197 const ValidityRestriction* match = nullptr;
198 for (auto& restriction : validity_restriction) {
199 if (get_type(restriction) == vrt) {
200 match = &restriction;
201 break;
202 }
203 }
204 return match;
205}
206
207void Certificate::remove_attribute(SubjectAttributeType type)
208{
209 for (auto it = subject_attributes.begin(); it != subject_attributes.end(); /* noop */) {
210 if (get_type(*it) == type) {
211 it = subject_attributes.erase(it);
212 } else {
213 ++it;
214 }
215 }
216}
217
218void Certificate::remove_restriction(ValidityRestrictionType type)
219{
220 for (auto it = validity_restriction.begin(); it != validity_restriction.end(); /* noop */) {
221 if (get_type(*it) == type) {
222 it = validity_restriction.erase(it);
223 } else {
224 ++it;
225 }
226 }
227}
228
230{
231 for (auto& item : subject_attributes) {
232 if (get_type(item) == SubjectAttributeType::ITS_AID_List) {
233 auto& aid_list = boost::get<std::list<IntX>>(item);
234 aid_list.push_back(IntX(aid));
235 return;
236 }
237 }
238
239 subject_attributes.push_back(std::list<IntX>({ IntX(aid) }));
240}
241
242void Certificate::add_permission(ItsAid aid, const ByteBuffer& ssp)
243{
244 ItsAidSsp permission({ IntX(aid), ssp });
245
246 for (auto& item : subject_attributes) {
247 if (get_type(item) == SubjectAttributeType::ITS_AID_SSP_List) {
248 auto& aid_ssp_list = boost::get<std::list<ItsAidSsp> >(item);
249 aid_ssp_list.push_back(permission);
250 return;
251 }
252 }
253
254 subject_attributes.push_back(std::list<ItsAidSsp>({ permission }));
255}
256
257/*
258std::unique_ptr<security::Certificate> Certificate::clone() const
259{
260 return std::unique_ptr<Certificate> { new Certificate(*this) };
261}
262
263bool Certificate::is_root_ca() const
264{
265 return subject_info.subject_type == SubjectType::Root_CA;
266}
267*/
268
269} // ns v2
270} // ns security
271} // ns vanetza
IntX specified in TS 103 097 v1.2.1, section 4.2.1.
Definition: int_x.hpp:21
const validity_restriction_type< T > * get_restriction() const
Definition: certificate.hpp:93
void remove_attribute(SubjectAttributeType type)
const subject_attribute_type< T > * get_attribute() const
Definition: certificate.hpp:80
void remove_restriction(ValidityRestrictionType type)
ItsAidSsp specified in TS 103 097 v1.2.1, section 6.9.