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