Vanetza
 
Loading...
Searching...
No Matches
default_certificate_validator.cpp
1#include <vanetza/common/its_aid.hpp>
2#include <vanetza/common/position_fix.hpp>
3#include <vanetza/security/hashed_id.hpp>
4#include <vanetza/security/v2/certificate.hpp>
5#include <vanetza/security/v2/certificate_cache.hpp>
6#include <vanetza/security/v2/default_certificate_validator.hpp>
7#include <vanetza/security/v2/signature.hpp>
8#include <vanetza/security/v2/trust_store.hpp>
9#include <vanetza/security/v2/validity_restriction.hpp>
10#include <algorithm>
11#include <chrono>
12
13namespace vanetza
14{
15namespace security
16{
17namespace v2
18{
19namespace
20{
21
22boost::optional<StartAndEndValidity> extract_validity_time(const Certificate& certificate)
23{
24 boost::optional<StartAndEndValidity> restriction;
25
26 for (auto& validity_restriction : certificate.validity_restriction) {
27 ValidityRestrictionType type = get_type(validity_restriction);
28
29 if (type == ValidityRestrictionType::Time_Start_And_End) {
30 // reject more than one restriction
31 if (restriction) {
32 return boost::none;
33 }
34
35 restriction = boost::get<StartAndEndValidity>(validity_restriction);
36
37 // check if certificate validity restriction timestamps are logically correct
38 if (restriction->start_validity >= restriction->end_validity) {
39 return boost::none;
40 }
41 } else if (type == ValidityRestrictionType::Time_End) {
42 // must not be used, no certificate profile allows it
43 return boost::none;
44 } else if (type == ValidityRestrictionType::Time_Start_And_Duration) {
45 // must not be used, no certificate profile allows it
46 return boost::none;
47 }
48 }
49
50 return restriction;
51}
52
53bool check_time_consistency(const Certificate& certificate, const Certificate& signer)
54{
55 boost::optional<StartAndEndValidity> certificate_time = extract_validity_time(certificate);
56 boost::optional<StartAndEndValidity> signer_time = extract_validity_time(signer);
57
58 if (!certificate_time || !signer_time) {
59 return false;
60 }
61
62 if (signer_time->start_validity > certificate_time->start_validity) {
63 return false;
64 }
65
66 if (signer_time->end_validity < certificate_time->end_validity) {
67 return false;
68 }
69
70 return true;
71}
72
73std::list<ItsAid> extract_application_identifiers(const Certificate& certificate)
74{
75 std::list<ItsAid> aids;
76
77 auto certificate_type = certificate.subject_info.subject_type;
78 if (certificate_type == SubjectType::Authorization_Ticket) {
79 auto list = certificate.get_attribute<SubjectAttributeType::ITS_AID_SSP_List>();
80 if (list) {
81 for (auto& item : *list) {
82 aids.push_back(item.its_aid.get());
83 }
84 }
85 } else {
86 auto list = certificate.get_attribute<SubjectAttributeType::ITS_AID_List>();
87 if (list) {
88 for (auto& item : *list) {
89 aids.push_back(item.get());
90 }
91 }
92 }
93
94 return aids;
95}
96
97bool check_permission_consistency(const Certificate& certificate, const Certificate& signer)
98{
99 auto certificate_aids = extract_application_identifiers(certificate);
100 auto signer_aids = extract_application_identifiers(signer);
101 auto compare = [](ItsAid a, ItsAid b) { return a < b; };
102
103 certificate_aids.sort(compare);
104 signer_aids.sort(compare);
105
106 return std::includes(signer_aids.begin(), signer_aids.end(), certificate_aids.begin(), certificate_aids.end());
107}
108
109bool check_subject_assurance_consistency(const Certificate& certificate, const Certificate& signer)
110{
111 auto certificate_assurance = certificate.get_attribute<SubjectAttributeType::Assurance_Level>();
112 auto signer_assurance = signer.get_attribute<SubjectAttributeType::Assurance_Level>();
113
114 if (!certificate_assurance || !signer_assurance) {
115 return false;
116 }
117
118 // See TS 103 096-2 v1.3.1, section 5.2.7.11 + 5.3.5.17 and following
119 if (certificate_assurance->assurance() > signer_assurance->assurance()) {
120 return false;
121 } else if (certificate_assurance->assurance() == signer_assurance->assurance()) {
122 if (certificate_assurance->confidence() > signer_assurance->confidence()) {
123 return false;
124 }
125 }
126
127 return true;
128}
129
130bool check_region_consistency(const Certificate& certificate, const Certificate& signer)
131{
132 auto certificate_region = certificate.get_restriction<ValidityRestrictionType::Region>();
133 auto signer_region = signer.get_restriction<ValidityRestrictionType::Region>();
134
135 if (!signer_region) {
136 return true;
137 }
138
139 if (!certificate_region) {
140 return false;
141 }
142
143 return is_within(*certificate_region, *signer_region);
144}
145
146bool check_consistency(const Certificate& certificate, const Certificate& signer)
147{
148 if (!check_time_consistency(certificate, signer)) {
149 return false;
150 }
151
152 if (!check_permission_consistency(certificate, signer)) {
153 return false;
154 }
155
156 if (!check_subject_assurance_consistency(certificate, signer)) {
157 return false;
158 }
159
160 if (!check_region_consistency(certificate, signer)) {
161 return false;
162 }
163
164 return true;
165}
166
167} // namespace
168
169DefaultCertificateValidator::DefaultCertificateValidator(Backend& backend, CertificateCache& cert_cache, const TrustStore& trust_store) :
170 m_crypto_backend(backend),
171 m_cert_cache(cert_cache),
172 m_trust_store(trust_store)
173{
174}
175
176CertificateValidity DefaultCertificateValidator::check_certificate(const Certificate& certificate)
177{
178 if (!extract_validity_time(certificate)) {
179 return CertificateInvalidReason::Broken_Time_Period;
180 }
181
182 if (!certificate.get_attribute<SubjectAttributeType::Assurance_Level>()) {
183 return CertificateInvalidReason::Missing_Subject_Assurance;
184 }
185
186 SubjectType subject_type = certificate.subject_info.subject_type;
187
188 // check if subject_name is empty if certificate is authorization ticket
189 if (subject_type == SubjectType::Authorization_Ticket && 0 != certificate.subject_info.subject_name.size()) {
190 return CertificateInvalidReason::Invalid_Name;
191 }
192
193 if (get_type(certificate.signer_info) != SignerInfoType::Certificate_Digest_With_SHA256) {
194 return CertificateInvalidReason::Invalid_Signer;
195 }
196
197 HashedId8 signer_hash = boost::get<HashedId8>(certificate.signer_info);
198
199 // try to extract ECDSA signature
200 boost::optional<EcdsaSignature> sig = extract_ecdsa_signature(certificate.signature);
201 if (!sig) {
202 return CertificateInvalidReason::Missing_Signature;
203 }
204
205 // create buffer of certificate
206 ByteBuffer binary_cert = convert_for_signing(certificate);
207
208 // authorization tickets may only be signed by authorization authorities
209 if (subject_type == SubjectType::Authorization_Ticket) {
210 for (auto& possible_signer : m_cert_cache.lookup(signer_hash, SubjectType::Authorization_Authority)) {
211 auto verification_key = get_public_key(possible_signer, m_crypto_backend);
212 if (!verification_key) {
213 continue;
214 }
215
216 if (m_crypto_backend.verify_data(verification_key.get(), binary_cert, sig.get())) {
217 if (!check_consistency(certificate, possible_signer)) {
218 return CertificateInvalidReason::Inconsistent_With_Signer;
219 }
220
221 return CertificateValidity::valid();
222 }
223 }
224 }
225
226 // authorization authorities may only be signed by root CAs
227 // Note: There's no clear specification about this, but there's a test for it in 5.2.7.12.4 of TS 103 096-2 V1.3.1
228 if (subject_type == SubjectType::Authorization_Authority) {
229 for (auto& possible_signer : m_trust_store.lookup(signer_hash)) {
230 auto verification_key = get_public_key(possible_signer, m_crypto_backend);
231 if (!verification_key) {
232 continue;
233 }
234
235 if (m_crypto_backend.verify_data(verification_key.get(), binary_cert, sig.get())) {
236 if (!check_consistency(certificate, possible_signer)) {
237 return CertificateInvalidReason::Inconsistent_With_Signer;
238 }
239
240 return CertificateValidity::valid();
241 }
242 }
243 }
244
245 return CertificateInvalidReason::Unknown_Signer;
246}
247
248} // namespace v2
249} // namespace security
250} // namespace vanetza
described in TS 103 097 v1.2.1 (2015-06), section 6.1
Definition: certificate.hpp:28
const SubjectAttribute * get_attribute(SubjectAttributeType type) const