1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "cast/common/certificate/cast_crl.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <openssl/digest.h>
8*3f982cf4SFabien Sanglard #include <time.h>
9*3f982cf4SFabien Sanglard
10*3f982cf4SFabien Sanglard #include <memory>
11*3f982cf4SFabien Sanglard
12*3f982cf4SFabien Sanglard #include "absl/strings/string_view.h"
13*3f982cf4SFabien Sanglard #include "cast/common/certificate/cast_cert_validator_internal.h"
14*3f982cf4SFabien Sanglard #include "platform/base/macros.h"
15*3f982cf4SFabien Sanglard #include "util/crypto/certificate_utils.h"
16*3f982cf4SFabien Sanglard #include "util/crypto/sha2.h"
17*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
18*3f982cf4SFabien Sanglard
19*3f982cf4SFabien Sanglard namespace openscreen {
20*3f982cf4SFabien Sanglard namespace cast {
21*3f982cf4SFabien Sanglard namespace {
22*3f982cf4SFabien Sanglard
23*3f982cf4SFabien Sanglard enum CrlVersion {
24*3f982cf4SFabien Sanglard // version 0: Spki Hash Algorithm = SHA-256
25*3f982cf4SFabien Sanglard // Signature Algorithm = RSA-PKCS1 V1.5 with SHA-256
26*3f982cf4SFabien Sanglard kCrlVersion0 = 0,
27*3f982cf4SFabien Sanglard };
28*3f982cf4SFabien Sanglard
29*3f982cf4SFabien Sanglard // -------------------------------------------------------------------------
30*3f982cf4SFabien Sanglard // Cast CRL trust anchors.
31*3f982cf4SFabien Sanglard // -------------------------------------------------------------------------
32*3f982cf4SFabien Sanglard
33*3f982cf4SFabien Sanglard // There is one trusted root for Cast CRL certificate chains:
34*3f982cf4SFabien Sanglard //
35*3f982cf4SFabien Sanglard // (1) CN=Cast CRL Root CA (kCastCRLRootCaDer)
36*3f982cf4SFabien Sanglard //
37*3f982cf4SFabien Sanglard // These constants are defined by the file included next:
38*3f982cf4SFabien Sanglard
39*3f982cf4SFabien Sanglard #include "cast/common/certificate/cast_crl_root_ca_cert_der-inc.h"
40*3f982cf4SFabien Sanglard
41*3f982cf4SFabien Sanglard // Singleton for the trust store using the default Cast CRL root.
42*3f982cf4SFabien Sanglard class CastCRLTrustStore {
43*3f982cf4SFabien Sanglard public:
GetInstance()44*3f982cf4SFabien Sanglard static CastCRLTrustStore* GetInstance() {
45*3f982cf4SFabien Sanglard static CastCRLTrustStore* store = new CastCRLTrustStore();
46*3f982cf4SFabien Sanglard return store;
47*3f982cf4SFabien Sanglard }
48*3f982cf4SFabien Sanglard
trust_store()49*3f982cf4SFabien Sanglard TrustStore* trust_store() { return &trust_store_; }
50*3f982cf4SFabien Sanglard
51*3f982cf4SFabien Sanglard ~CastCRLTrustStore() = default;
52*3f982cf4SFabien Sanglard
53*3f982cf4SFabien Sanglard private:
CastCRLTrustStore()54*3f982cf4SFabien Sanglard CastCRLTrustStore() {
55*3f982cf4SFabien Sanglard trust_store_.certs.emplace_back(MakeTrustAnchor(kCastCRLRootCaDer));
56*3f982cf4SFabien Sanglard }
57*3f982cf4SFabien Sanglard
58*3f982cf4SFabien Sanglard TrustStore trust_store_;
59*3f982cf4SFabien Sanglard OSP_DISALLOW_COPY_AND_ASSIGN(CastCRLTrustStore);
60*3f982cf4SFabien Sanglard };
61*3f982cf4SFabien Sanglard
ConstDataSpanFromString(const std::string & s)62*3f982cf4SFabien Sanglard ConstDataSpan ConstDataSpanFromString(const std::string& s) {
63*3f982cf4SFabien Sanglard return ConstDataSpan{reinterpret_cast<const uint8_t*>(s.data()),
64*3f982cf4SFabien Sanglard static_cast<uint32_t>(s.size())};
65*3f982cf4SFabien Sanglard }
66*3f982cf4SFabien Sanglard
67*3f982cf4SFabien Sanglard // Verifies the CRL is signed by a trusted CRL authority at the time the CRL
68*3f982cf4SFabien Sanglard // was issued. Verifies the signature of |tbs_crl| is valid based on the
69*3f982cf4SFabien Sanglard // certificate and signature in |crl|. The validity of |tbs_crl| is verified
70*3f982cf4SFabien Sanglard // at |time|. The validity period of the CRL is adjusted to be the earliest
71*3f982cf4SFabien Sanglard // of the issuer certificate chain's expiration and the CRL's expiration and
72*3f982cf4SFabien Sanglard // the result is stored in |overall_not_after|.
VerifyCRL(const Crl & crl,const TbsCrl & tbs_crl,const DateTime & time,TrustStore * trust_store,DateTime * overall_not_after)73*3f982cf4SFabien Sanglard bool VerifyCRL(const Crl& crl,
74*3f982cf4SFabien Sanglard const TbsCrl& tbs_crl,
75*3f982cf4SFabien Sanglard const DateTime& time,
76*3f982cf4SFabien Sanglard TrustStore* trust_store,
77*3f982cf4SFabien Sanglard DateTime* overall_not_after) {
78*3f982cf4SFabien Sanglard CertificatePathResult result_path = {};
79*3f982cf4SFabien Sanglard Error error =
80*3f982cf4SFabien Sanglard FindCertificatePath({crl.signer_cert()}, time, &result_path, trust_store);
81*3f982cf4SFabien Sanglard if (!error.ok()) {
82*3f982cf4SFabien Sanglard return false;
83*3f982cf4SFabien Sanglard }
84*3f982cf4SFabien Sanglard
85*3f982cf4SFabien Sanglard bssl::UniquePtr<EVP_PKEY> public_key{
86*3f982cf4SFabien Sanglard X509_get_pubkey(result_path.target_cert.get())};
87*3f982cf4SFabien Sanglard if (!VerifySignedData(EVP_sha256(), public_key.get(),
88*3f982cf4SFabien Sanglard ConstDataSpanFromString(crl.tbs_crl()),
89*3f982cf4SFabien Sanglard ConstDataSpanFromString(crl.signature()))) {
90*3f982cf4SFabien Sanglard return false;
91*3f982cf4SFabien Sanglard }
92*3f982cf4SFabien Sanglard
93*3f982cf4SFabien Sanglard // Verify the CRL is still valid.
94*3f982cf4SFabien Sanglard DateTime not_before;
95*3f982cf4SFabien Sanglard if (!DateTimeFromSeconds(tbs_crl.not_before_seconds(), ¬_before)) {
96*3f982cf4SFabien Sanglard return false;
97*3f982cf4SFabien Sanglard }
98*3f982cf4SFabien Sanglard DateTime not_after;
99*3f982cf4SFabien Sanglard if (!DateTimeFromSeconds(tbs_crl.not_after_seconds(), ¬_after)) {
100*3f982cf4SFabien Sanglard return false;
101*3f982cf4SFabien Sanglard }
102*3f982cf4SFabien Sanglard if ((time < not_before) || (not_after < time)) {
103*3f982cf4SFabien Sanglard return false;
104*3f982cf4SFabien Sanglard }
105*3f982cf4SFabien Sanglard
106*3f982cf4SFabien Sanglard // Set CRL expiry to the earliest of the cert chain expiry and CRL expiry
107*3f982cf4SFabien Sanglard // (excluding trust anchor). No intermediates are provided above, so this
108*3f982cf4SFabien Sanglard // just amounts to |signer_cert| vs. |not_after_seconds|.
109*3f982cf4SFabien Sanglard *overall_not_after = not_after;
110*3f982cf4SFabien Sanglard bssl::UniquePtr<ASN1_GENERALIZEDTIME> not_after_asn1{
111*3f982cf4SFabien Sanglard ASN1_TIME_to_generalizedtime(
112*3f982cf4SFabien Sanglard X509_get0_notAfter(result_path.target_cert.get()), nullptr)};
113*3f982cf4SFabien Sanglard if (!not_after_asn1) {
114*3f982cf4SFabien Sanglard return false;
115*3f982cf4SFabien Sanglard }
116*3f982cf4SFabien Sanglard DateTime cert_not_after;
117*3f982cf4SFabien Sanglard bool time_valid =
118*3f982cf4SFabien Sanglard ParseAsn1GeneralizedTime(not_after_asn1.get(), &cert_not_after);
119*3f982cf4SFabien Sanglard if (!time_valid) {
120*3f982cf4SFabien Sanglard return false;
121*3f982cf4SFabien Sanglard }
122*3f982cf4SFabien Sanglard if (cert_not_after < *overall_not_after) {
123*3f982cf4SFabien Sanglard *overall_not_after = cert_not_after;
124*3f982cf4SFabien Sanglard }
125*3f982cf4SFabien Sanglard
126*3f982cf4SFabien Sanglard // Perform sanity check on serial numbers.
127*3f982cf4SFabien Sanglard for (const auto& range : tbs_crl.revoked_serial_number_ranges()) {
128*3f982cf4SFabien Sanglard uint64_t first_serial_number = range.first_serial_number();
129*3f982cf4SFabien Sanglard uint64_t last_serial_number = range.last_serial_number();
130*3f982cf4SFabien Sanglard if (last_serial_number < first_serial_number) {
131*3f982cf4SFabien Sanglard return false;
132*3f982cf4SFabien Sanglard }
133*3f982cf4SFabien Sanglard }
134*3f982cf4SFabien Sanglard
135*3f982cf4SFabien Sanglard return true;
136*3f982cf4SFabien Sanglard }
137*3f982cf4SFabien Sanglard
138*3f982cf4SFabien Sanglard } // namespace
139*3f982cf4SFabien Sanglard
CastCRL(const TbsCrl & tbs_crl,const DateTime & overall_not_after)140*3f982cf4SFabien Sanglard CastCRL::CastCRL(const TbsCrl& tbs_crl, const DateTime& overall_not_after) {
141*3f982cf4SFabien Sanglard // Parse the validity information.
142*3f982cf4SFabien Sanglard // Assume DateTimeFromSeconds will succeed. Successful call to VerifyCRL means
143*3f982cf4SFabien Sanglard // that these calls were successful.
144*3f982cf4SFabien Sanglard DateTimeFromSeconds(tbs_crl.not_before_seconds(), ¬_before_);
145*3f982cf4SFabien Sanglard DateTimeFromSeconds(tbs_crl.not_after_seconds(), ¬_after_);
146*3f982cf4SFabien Sanglard if (overall_not_after < not_after_) {
147*3f982cf4SFabien Sanglard not_after_ = overall_not_after;
148*3f982cf4SFabien Sanglard }
149*3f982cf4SFabien Sanglard
150*3f982cf4SFabien Sanglard // Parse the revoked hashes.
151*3f982cf4SFabien Sanglard for (const auto& hash : tbs_crl.revoked_public_key_hashes()) {
152*3f982cf4SFabien Sanglard revoked_hashes_.insert(hash);
153*3f982cf4SFabien Sanglard }
154*3f982cf4SFabien Sanglard
155*3f982cf4SFabien Sanglard // Parse the revoked serial ranges.
156*3f982cf4SFabien Sanglard for (const auto& range : tbs_crl.revoked_serial_number_ranges()) {
157*3f982cf4SFabien Sanglard std::string issuer_hash = range.issuer_public_key_hash();
158*3f982cf4SFabien Sanglard
159*3f982cf4SFabien Sanglard uint64_t first_serial_number = range.first_serial_number();
160*3f982cf4SFabien Sanglard uint64_t last_serial_number = range.last_serial_number();
161*3f982cf4SFabien Sanglard auto& serial_number_range = revoked_serial_numbers_[issuer_hash];
162*3f982cf4SFabien Sanglard serial_number_range.push_back({first_serial_number, last_serial_number});
163*3f982cf4SFabien Sanglard }
164*3f982cf4SFabien Sanglard }
165*3f982cf4SFabien Sanglard
~CastCRL()166*3f982cf4SFabien Sanglard CastCRL::~CastCRL() {}
167*3f982cf4SFabien Sanglard
168*3f982cf4SFabien Sanglard // Verifies the revocation status of the certificate chain, at the specified
169*3f982cf4SFabien Sanglard // time.
CheckRevocation(const std::vector<X509 * > & trusted_chain,const DateTime & time) const170*3f982cf4SFabien Sanglard bool CastCRL::CheckRevocation(const std::vector<X509*>& trusted_chain,
171*3f982cf4SFabien Sanglard const DateTime& time) const {
172*3f982cf4SFabien Sanglard if (trusted_chain.empty())
173*3f982cf4SFabien Sanglard return false;
174*3f982cf4SFabien Sanglard
175*3f982cf4SFabien Sanglard if ((time < not_before_) || (not_after_ < time)) {
176*3f982cf4SFabien Sanglard return false;
177*3f982cf4SFabien Sanglard }
178*3f982cf4SFabien Sanglard
179*3f982cf4SFabien Sanglard // Check revocation. This loop iterates over both certificates AND then the
180*3f982cf4SFabien Sanglard // trust anchor after exhausting the certs.
181*3f982cf4SFabien Sanglard for (size_t i = 0; i < trusted_chain.size(); ++i) {
182*3f982cf4SFabien Sanglard std::string spki_tlv = GetSpkiTlv(trusted_chain[i]);
183*3f982cf4SFabien Sanglard if (spki_tlv.empty()) {
184*3f982cf4SFabien Sanglard return false;
185*3f982cf4SFabien Sanglard }
186*3f982cf4SFabien Sanglard
187*3f982cf4SFabien Sanglard ErrorOr<std::string> spki_hash = SHA256HashString(spki_tlv);
188*3f982cf4SFabien Sanglard if (spki_hash.is_error() ||
189*3f982cf4SFabien Sanglard (revoked_hashes_.find(spki_hash.value()) != revoked_hashes_.end())) {
190*3f982cf4SFabien Sanglard return false;
191*3f982cf4SFabien Sanglard }
192*3f982cf4SFabien Sanglard
193*3f982cf4SFabien Sanglard // Check if the subordinate certificate was revoked by serial number.
194*3f982cf4SFabien Sanglard if (i < (trusted_chain.size() - 1)) {
195*3f982cf4SFabien Sanglard const auto issuer_iter = revoked_serial_numbers_.find(spki_hash.value());
196*3f982cf4SFabien Sanglard if (issuer_iter != revoked_serial_numbers_.end()) {
197*3f982cf4SFabien Sanglard const auto& subordinate = trusted_chain[i + 1];
198*3f982cf4SFabien Sanglard uint64_t serial_number;
199*3f982cf4SFabien Sanglard
200*3f982cf4SFabien Sanglard // Only Google generated device certificates will be revoked by range.
201*3f982cf4SFabien Sanglard // These will always be less than 64 bits in length.
202*3f982cf4SFabien Sanglard ErrorOr<uint64_t> maybe_serial =
203*3f982cf4SFabien Sanglard ParseDerUint64(X509_get0_serialNumber(subordinate));
204*3f982cf4SFabien Sanglard if (!maybe_serial) {
205*3f982cf4SFabien Sanglard continue;
206*3f982cf4SFabien Sanglard }
207*3f982cf4SFabien Sanglard serial_number = maybe_serial.value();
208*3f982cf4SFabien Sanglard for (const auto& revoked_serial : issuer_iter->second) {
209*3f982cf4SFabien Sanglard if (revoked_serial.first_serial <= serial_number &&
210*3f982cf4SFabien Sanglard revoked_serial.last_serial >= serial_number) {
211*3f982cf4SFabien Sanglard return false;
212*3f982cf4SFabien Sanglard }
213*3f982cf4SFabien Sanglard }
214*3f982cf4SFabien Sanglard }
215*3f982cf4SFabien Sanglard }
216*3f982cf4SFabien Sanglard }
217*3f982cf4SFabien Sanglard return true;
218*3f982cf4SFabien Sanglard }
219*3f982cf4SFabien Sanglard
ParseAndVerifyCRL(const std::string & crl_proto,const DateTime & time,TrustStore * trust_store)220*3f982cf4SFabien Sanglard std::unique_ptr<CastCRL> ParseAndVerifyCRL(const std::string& crl_proto,
221*3f982cf4SFabien Sanglard const DateTime& time,
222*3f982cf4SFabien Sanglard TrustStore* trust_store) {
223*3f982cf4SFabien Sanglard if (!trust_store)
224*3f982cf4SFabien Sanglard trust_store = CastCRLTrustStore::GetInstance()->trust_store();
225*3f982cf4SFabien Sanglard
226*3f982cf4SFabien Sanglard CrlBundle crl_bundle;
227*3f982cf4SFabien Sanglard if (!crl_bundle.ParseFromString(crl_proto)) {
228*3f982cf4SFabien Sanglard return nullptr;
229*3f982cf4SFabien Sanglard }
230*3f982cf4SFabien Sanglard for (const auto& crl : crl_bundle.crls()) {
231*3f982cf4SFabien Sanglard TbsCrl tbs_crl;
232*3f982cf4SFabien Sanglard if (!tbs_crl.ParseFromString(crl.tbs_crl())) {
233*3f982cf4SFabien Sanglard OSP_LOG_WARN << "Binary TBS CRL could not be parsed.";
234*3f982cf4SFabien Sanglard continue;
235*3f982cf4SFabien Sanglard }
236*3f982cf4SFabien Sanglard if (tbs_crl.version() != kCrlVersion0) {
237*3f982cf4SFabien Sanglard OSP_LOG_WARN << "Binary TBS CRL has unknown version: "
238*3f982cf4SFabien Sanglard << tbs_crl.version();
239*3f982cf4SFabien Sanglard continue;
240*3f982cf4SFabien Sanglard }
241*3f982cf4SFabien Sanglard DateTime overall_not_after;
242*3f982cf4SFabien Sanglard if (!VerifyCRL(crl, tbs_crl, time, trust_store, &overall_not_after)) {
243*3f982cf4SFabien Sanglard return nullptr;
244*3f982cf4SFabien Sanglard }
245*3f982cf4SFabien Sanglard // TODO(btolsch): Why is this 'return first successful CRL'?
246*3f982cf4SFabien Sanglard return std::make_unique<CastCRL>(tbs_crl, overall_not_after);
247*3f982cf4SFabien Sanglard }
248*3f982cf4SFabien Sanglard return nullptr;
249*3f982cf4SFabien Sanglard }
250*3f982cf4SFabien Sanglard
251*3f982cf4SFabien Sanglard } // namespace cast
252*3f982cf4SFabien Sanglard } // namespace openscreen
253