Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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 "net/cert/internal/verify_certificate_chain.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "net/cert/internal/parse_certificate.h" | |
| 9 #include "net/cert/internal/signature_algorithm.h" | |
| 10 #include "net/cert/internal/signature_policy.h" | |
| 11 #include "net/cert/internal/verify_signed_data.h" | |
| 12 #include "net/der/input.h" | |
| 13 | |
| 14 namespace net { | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 // TODO(eroman): Move into net/der (duplicated from test_helpers.cc). | |
| 19 static der::Input InputFromString(const std::string* s) { | |
| 20 return der::Input(reinterpret_cast<const uint8_t*>(s->data()), s->size()); | |
| 21 } | |
| 22 | |
| 23 // Describes all parsed properties of a certificate. | |
| 24 struct FullyParsedCert { | |
| 25 CertificateVersion version; | |
| 26 scoped_ptr<SignatureAlgorithm> signature_algorithm; | |
| 27 scoped_ptr<SignatureAlgorithm> tbs_signature_algorithm; | |
| 28 der::BitString signature_value; | |
| 29 der::Input tbs_tlv; | |
| 30 | |
| 31 der::Input issuer_tlv; | |
| 32 der::GeneralizedTime validity_not_before; | |
| 33 der::GeneralizedTime validity_not_after; | |
| 34 | |
| 35 // TODO(eroman): Everywhere this is consumed should also consider | |
| 36 // subjectAltName. | |
| 37 der::Input subject_tlv; | |
| 38 der::Input spki_tlv; | |
| 39 | |
| 40 // Extensions | |
| 41 bool has_basic_constraints = false; | |
| 42 ParsedBasicConstraints basic_constraints; | |
| 43 bool has_key_usage = false; | |
| 44 der::BitString key_usage; | |
| 45 }; | |
| 46 | |
| 47 // Removes the extension with OID |oid| from |extensions| and fills |extension| | |
| 48 // with the matching extension value. If there was no extension matching |oid| | |
| 49 // then returns |false|. | |
| 50 WARN_UNUSED_RESULT bool ConsumeExtension( | |
| 51 const der::Input& oid, | |
| 52 std::map<der::Input, ParsedExtension>* extensions, | |
| 53 ParsedExtension* extension) { | |
| 54 auto it = extensions->find(oid); | |
| 55 if (it == extensions->end()) | |
| 56 return false; | |
| 57 | |
| 58 *extension = it->second; | |
| 59 | |
| 60 // TODO(eroman): Could be faster to just reset the entry instead of | |
| 61 // deleting it, although a bit less clear. | |
| 62 extensions->erase(it); | |
| 63 return true; | |
| 64 } | |
| 65 | |
| 66 // Parses a Certificate and saves all properties to |out|. | |
| 67 WARN_UNUSED_RESULT bool FullyParseCertificate(const der::Input& cert_tlv, | |
| 68 FullyParsedCert* out) { | |
| 69 // Parse the Certificate. | |
| 70 ParsedCertificate cert; | |
| 71 if (!ParseCertificate(cert_tlv, &cert)) | |
| 72 return false; | |
| 73 | |
| 74 // Extract values of interest from the parsed Certificate. | |
| 75 out->tbs_tlv = cert.tbs_certificate_tlv; | |
| 76 out->signature_value = cert.signature_value; | |
| 77 | |
| 78 // Parse the signature algorithm in the Certificate. | |
| 79 out->signature_algorithm = | |
| 80 SignatureAlgorithm::CreateFromDer(cert.signature_algorithm_tlv); | |
| 81 if (!out->signature_algorithm) | |
| 82 return false; | |
| 83 | |
| 84 // Parse the TBSCertificate. | |
| 85 ParsedTbsCertificate tbs; | |
| 86 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs)) | |
| 87 return false; | |
| 88 | |
| 89 // Parse the signature algorithm in the TBSCertificate. | |
| 90 out->tbs_signature_algorithm = | |
| 91 SignatureAlgorithm::CreateFromDer(tbs.signature_algorithm_tlv); | |
| 92 if (!out->tbs_signature_algorithm) | |
| 93 return false; | |
| 94 | |
| 95 // Copy fields of interest from the TBSCertificate (just copying pointers to | |
| 96 // the data, not the actual DER). | |
| 97 out->issuer_tlv = tbs.issuer_tlv; | |
| 98 out->version = tbs.version; | |
| 99 out->spki_tlv = tbs.spki_tlv; | |
| 100 out->subject_tlv = tbs.subject_tlv; | |
| 101 out->validity_not_after = tbs.validity_not_after; | |
| 102 out->validity_not_before = tbs.validity_not_before; | |
| 103 | |
| 104 // Parse the X.509 extensions. | |
| 105 out->has_basic_constraints = false; | |
| 106 out->has_key_usage = false; | |
| 107 | |
| 108 if (tbs.has_extensions) { | |
| 109 // ParseExtensions() ensures there are no duplicates, and maps the (unique) | |
| 110 // OID to the extension value. The verification code must ensure that every | |
| 111 // critical extension is understood. | |
| 112 std::map<der::Input, ParsedExtension> extensions; | |
| 113 if (!ParseExtensions(tbs.extensions_tlv, &extensions)) | |
| 114 return false; | |
| 115 | |
| 116 ParsedExtension extension; | |
| 117 | |
| 118 // Process each of the recognized extensions. In doing so, the processed | |
| 119 // extension is cleared from the |extensions| map. | |
| 120 if (ConsumeExtension(BasicConstraintsOid(), &extensions, &extension)) { | |
| 121 out->has_basic_constraints = true; | |
| 122 if (!ParseBasicConstraints(extension.value, &out->basic_constraints)) | |
| 123 return false; | |
| 124 } | |
| 125 | |
| 126 if (ConsumeExtension(KeyUsageOid(), &extensions, &extension)) { | |
| 127 out->has_key_usage = true; | |
| 128 if (!ParseKeyUsage(extension.value, &out->key_usage)) | |
| 129 return false; | |
| 130 } | |
| 131 | |
| 132 // Check that there aren't any unconsumed (unprocessed) critical | |
| 133 // extensions in |extensions|. It is OK however for there to be | |
| 134 // unconsumed non-critical extensions. | |
| 135 for (const auto& entry : extensions) { | |
| 136 if (entry.second.critical) | |
| 137 return false; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 return true; | |
| 142 } | |
| 143 | |
| 144 // Returns true if |name1| matches |name2|. | |
| 145 WARN_UNUSED_RESULT bool NameMatches(const der::Input& name1, | |
| 146 const der::Input& name2) { | |
| 147 // TODO(eroman): Should account for normalization (that work is part of a | |
| 148 // different change). | |
|
davidben
2015/11/19 22:24:02
Link to a bug or something? "that work is part of
eroman
2015/12/03 04:45:12
I re-worded the TODO, and will address as follow-u
| |
| 149 return name1.Equals(name2); | |
| 150 } | |
| 151 | |
| 152 // Returns true if |cert| was self-issued. Note that self-issued is not the | |
| 153 // same thing as self-signed, see RFC 5280 for the explanation. | |
| 154 WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) { | |
| 155 return NameMatches(cert.subject_tlv, cert.issuer_tlv); | |
| 156 } | |
| 157 | |
| 158 // Finds a mapping in the trust store that matches |name|, or returns nullptr. | |
| 159 // | |
| 160 // TODO(eroman): This implementation is linear in the size of the trust store, | |
| 161 // and also presumes that all names are unique. In practice it is possible to | |
| 162 // have have multiple SPKIs with the same name. Also this mechanism of | |
| 163 // searching is fairly primitive, and does not take advantage of other | |
| 164 // properties like the authority key id. | |
| 165 WARN_UNUSED_RESULT const TrustedRoot* FindTrustedRootByName( | |
| 166 const TrustStore& trust_store, | |
| 167 const der::Input& name) { | |
| 168 for (const auto& root : trust_store.roots) { | |
| 169 if (NameMatches(name, InputFromString(&root.name))) | |
| 170 return &root; | |
| 171 } | |
| 172 return nullptr; | |
| 173 } | |
| 174 | |
| 175 // Returns true if |cert| is valid at time |time|. | |
| 176 // | |
| 177 // The certificate's validity requirements are described by RFC 5280 section | |
| 178 // 4.1.2.5: | |
| 179 // | |
| 180 // The validity period for a certificate is the period of time from | |
| 181 // notBefore through notAfter, inclusive. | |
| 182 WARN_UNUSED_RESULT bool VerifyValidity(const FullyParsedCert& cert, | |
| 183 const der::GeneralizedTime time) { | |
| 184 return (!(time < cert.validity_not_before) && | |
| 185 !(cert.validity_not_after < time)); | |
| 186 } | |
| 187 | |
| 188 // Returns true if |cert| has internally consistent signature algorithms. | |
| 189 // | |
| 190 // X.509 certificates contain two signature algorithms: | |
| 191 // (1) The signatureAlgorithm field of Certificate | |
| 192 // (2) The signature of TBSCertificate | |
| 193 // | |
| 194 // According to RFC 5280 section 4.1.1.2 these two fields must be in agreement: | |
| 195 // | |
| 196 // This field MUST contain the same algorithm identifier as the | |
| 197 // signature field in the sequence tbsCertificate (Section 4.1.2.3). | |
| 198 // | |
| 199 // The mechanism through which equality is determined is unspecified. | |
|
davidben
2015/11/19 22:24:02
It's an ASN.1 structure, so I think the natural in
eroman
2015/12/03 04:45:12
Done.
That sounds like a very sensible approach.
| |
| 200 // The interpretation taken here is that they identify the same algorithm, | |
| 201 // but the DER-encoded AlgorithmIdentifier needn't be byte-for-byte equal. | |
| 202 // There are a small number of certificates that require this (having for | |
| 203 // instance specified a different OID for RSA with SHA-1). | |
| 204 WARN_UNUSED_RESULT bool VerifySignatureAlgorithsMatch( | |
| 205 const FullyParsedCert& cert) { | |
| 206 return cert.signature_algorithm->Equals(*cert.tbs_signature_algorithm); | |
| 207 } | |
| 208 | |
| 209 // Returns true if |cert| has a correct key usage for the issuance of other | |
| 210 // certificates. | |
| 211 WARN_UNUSED_RESULT bool VerifyKeyUsageForIssuer(const FullyParsedCert& cert) { | |
| 212 // If the Key Usage extension is not present, then the key can be used for | |
| 213 // any operation. | |
| 214 if (!cert.has_key_usage) | |
| 215 return true; | |
| 216 | |
| 217 // RFC 5280 section 4.2.1.9: | |
| 218 // | |
| 219 // If the keyUsage extension is present, then the subject public key | |
| 220 // MUST NOT be used to verify signatures on certificates or CRLs unless | |
| 221 // the corresponding keyCertSign or cRLSign bit is set. | |
| 222 if (!cert.key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) | |
| 223 return false; | |
| 224 | |
| 225 // RFC 5280 section 4.2.1.9: | |
| 226 // | |
| 227 // If the keyCertSign bit is asserted, then the cA bit in the basic | |
| 228 // constraints extension (Section 4.2.1.9) MUST also be asserted. | |
| 229 // | |
| 230 // NOTE: this normative requirement is not enforced by this function, but | |
| 231 // rather by VerifyBasicConstraintsForIssuer(). | |
| 232 return true; | |
| 233 } | |
| 234 | |
| 235 // Returns true if |cert| has a correct BasicConstraints extension for the | |
| 236 // issuance of other certificates. | |
|
davidben
2015/11/19 22:24:02
Might be worth a comment that |current_cert_index|
eroman
2015/12/03 04:45:12
I went ahead and changed the ordering so it matche
| |
| 237 WARN_UNUSED_RESULT bool VerifyBasicConstraintsForIssuer( | |
| 238 const FullyParsedCert& cert, | |
| 239 size_t current_cert_index, | |
| 240 size_t num_prev_self_issued_certs) { | |
| 241 DCHECK_GT(current_cert_index, 0u); | |
|
davidben
2015/11/19 22:24:02
DCHECK_LT(num_prev_self_issued_certs, current_cert
eroman
2015/12/03 04:45:12
This line is no longer applicable.
| |
| 242 | |
| 243 // Only V3 certificates have the concept of extensions. | |
| 244 if (cert.version == CertificateVersion::V1 || | |
| 245 cert.version == CertificateVersion::V2) { | |
| 246 // RFC 5280: | |
| 247 // | |
| 248 // (If certificate i is a version 1 or version 2 certificate, then the | |
| 249 // application MUST either verify that certificate i is a CA | |
| 250 // certificate through out-of-band means or reject the certificate. | |
| 251 // Conforming implementations may choose to reject all version 1 and | |
| 252 // version 2 intermediate certificates.) | |
| 253 return false; | |
| 254 } | |
| 255 | |
| 256 // RFC 5280 section 4.2.1.9: | |
| 257 // | |
| 258 // If the basic constraints extension is not present in a version 3 | |
| 259 // certificate, or the extension is present but the cA boolean | |
| 260 // is not asserted, then the certified public key MUST NOT be used to | |
| 261 // verify certificate signatures. | |
| 262 if (!cert.has_basic_constraints || !cert.basic_constraints.is_ca) | |
| 263 return false; | |
| 264 | |
| 265 // RFC 5280 section 4.2.1.9: | |
| 266 // | |
| 267 // Where pathLenConstraint does not appear, no limit is imposed. | |
| 268 if (cert.basic_constraints.has_path_len) { | |
| 269 // RFC 5280 section 4.2.1.9: | |
| 270 // | |
| 271 // ... In this case, it gives the maximum number of non-self-issued | |
| 272 // intermediate certificates that may follow this certificate in a valid | |
| 273 // certification path. (Note: The last certificate in the certification | |
| 274 // path is not an intermediate certificate, and is not included in this | |
| 275 // limit. Usually, the last certificate is an end entity certificate, | |
| 276 // but it can be a CA certificate.) | |
| 277 size_t current_path_len = | |
| 278 current_cert_index - 1 - num_prev_self_issued_certs; | |
| 279 if (current_path_len > cert.basic_constraints.path_len) | |
| 280 return false; | |
| 281 } | |
| 282 | |
| 283 return true; | |
| 284 } | |
| 285 | |
| 286 // Returns true if the subject of |issuing_cert| matches the issuer of | |
| 287 // |subordinate_cert|. | |
| 288 WARN_UNUSED_RESULT bool VerifyIssuerMatchesSubject( | |
| 289 const FullyParsedCert& issuing_cert, | |
| 290 const FullyParsedCert& subordinate_cert) { | |
| 291 // TODO(eroman): subjectAltName and issuerAltName ? | |
|
davidben
2015/11/19 22:24:02
This TODO should also be removed, right?
| |
| 292 return NameMatches(issuing_cert.subject_tlv, subordinate_cert.issuer_tlv); | |
| 293 } | |
| 294 | |
| 295 // Returns true if |cert| was signed by a trusted root in |trust_store|. | |
| 296 WARN_UNUSED_RESULT bool IsSignedByTrustAnchor( | |
| 297 const FullyParsedCert& cert, | |
| 298 const TrustStore& trust_store, | |
| 299 const SignaturePolicy* signature_policy) { | |
| 300 const TrustedRoot* trusted_root = | |
| 301 FindTrustedRootByName(trust_store, cert.issuer_tlv); | |
| 302 | |
| 303 if (!trusted_root) | |
| 304 return false; | |
| 305 | |
| 306 if (!VerifySignedData( | |
| 307 *cert.signature_algorithm, cert.tbs_tlv, cert.signature_value, | |
| 308 InputFromString(&trusted_root->spki), signature_policy)) { | |
| 309 return false; | |
| 310 } | |
| 311 | |
| 312 return true; | |
| 313 } | |
| 314 | |
| 315 // Returns true if |cert| has BasicConstraints and KeyUsage consistent with | |
| 316 // being an end-entity certificate. | |
| 317 WARN_UNUSED_RESULT bool VerifyTargetCertificateIsEndEntity( | |
| 318 const FullyParsedCert& cert) { | |
| 319 if (cert.has_basic_constraints) { | |
| 320 if (cert.basic_constraints.is_ca) | |
| 321 return false; // Not an end-entity certificate. | |
| 322 | |
| 323 // RFC 5280 section 4.2.1.9: | |
| 324 // | |
| 325 // CAs MUST NOT include the pathLenConstraint field unless the cA | |
| 326 // boolean is asserted and the key usage extension asserts the | |
| 327 // keyCertSign bit. | |
| 328 if (cert.basic_constraints.has_path_len) | |
| 329 return false; | |
| 330 } | |
| 331 | |
| 332 // RFC 5280 section 4.2.1.9: | |
| 333 // | |
| 334 // If the cA boolean is not asserted, then the keyCertSign bit in the key | |
| 335 // usage extension MUST NOT be asserted. | |
| 336 // | |
| 337 // TODO(eroman): Should "asserted" in the above apply only when the basic | |
| 338 // constraints extension is actually present? (In other words, if Basic | |
| 339 // Constraints was omitted, should keyCertSign be allowed even though it | |
| 340 // doesn't make sense?) | |
|
davidben
2015/11/19 22:24:02
My interpretation is {cA boolean is asserted} mean
eroman
2015/12/03 04:45:12
Removed TODO and am enforcing this along that inte
| |
| 341 if (cert.has_key_usage && | |
| 342 cert.key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) { | |
| 343 return false; | |
| 344 } | |
| 345 | |
| 346 return true; | |
| 347 } | |
| 348 | |
| 349 } // namespace | |
| 350 | |
| 351 TrustedRoot::~TrustedRoot() {} | |
| 352 | |
| 353 TrustStore::TrustStore() {} | |
| 354 TrustStore::~TrustStore() {} | |
| 355 | |
| 356 bool VerifyCertificateChain(const std::vector<der::Input>& certs_der, | |
| 357 const TrustStore& trust_store, | |
| 358 const SignaturePolicy* signature_policy, | |
| 359 const der::GeneralizedTime& time) { | |
| 360 // An empty chain is invalid. Fail early since the rest of the code | |
| 361 // assumes a non-empty chain. | |
| 362 if (certs_der.empty()) | |
| 363 return false; | |
| 364 | |
| 365 // Fully parse all of the certificates. This is done up-front to simply | |
| 366 // access to properties. | |
| 367 std::vector<FullyParsedCert> certs(certs_der.size()); | |
| 368 for (size_t i = 0; i < certs_der.size(); ++i) { | |
| 369 if (!FullyParseCertificate(certs_der[i], &certs[i])) | |
| 370 return false; | |
| 371 } | |
| 372 | |
| 373 // TODO(eroman): Relax this and allow the caller to decide. | |
| 374 if (!VerifyTargetCertificateIsEndEntity(certs.front())) | |
| 375 return false; | |
| 376 | |
| 377 // The last intermediary must be issued by a trusted root. | |
| 378 if (!IsSignedByTrustAnchor(certs.back(), trust_store, signature_policy)) | |
| 379 return false; | |
| 380 | |
| 381 // Walk the chain in the forward direction (from end entity towards trust | |
| 382 // anchor) and check all properties of the certificate, including issuance. | |
| 383 size_t num_prev_self_issued_certs = 0; | |
| 384 for (size_t i = 0; i < certs_der.size(); ++i) { | |
|
davidben
2015/11/19 22:24:02
It seems RFC 5280 6.1 actually specifies a differe
eroman
2015/12/03 04:45:12
I have switched it to the other direction.
(Doesn
| |
| 385 // |cert| is the current certificate -- either the target or an | |
| 386 // intermediary, but never a root. | |
| 387 const auto& cert = certs[i]; | |
| 388 | |
| 389 if (!VerifyValidity(cert, time)) | |
|
davidben
2015/11/19 22:24:02
At no point do we verify that the the certificate
eroman
2015/12/03 04:45:12
I think we are already good here, but worth adding
| |
| 390 return false; | |
| 391 | |
| 392 if (!VerifySignatureAlgorithsMatch(cert)) | |
| 393 return false; | |
| 394 | |
| 395 // With the exception of the target (i=0), every other certificate (i) must | |
| 396 // be a CA. This section verifies that it is in fact a CA, and that it | |
| 397 // issued certificate (i-1). | |
| 398 if (i > 0) { | |
| 399 // The previous certificate in the chain, that purports to be issued by | |
| 400 // |cert|. | |
| 401 const auto& subordinate_cert = certs[i - 1]; | |
| 402 | |
| 403 if (!VerifyKeyUsageForIssuer(cert)) | |
| 404 return false; | |
| 405 | |
| 406 if (!VerifyBasicConstraintsForIssuer(cert, i, num_prev_self_issued_certs)) | |
| 407 return false; | |
| 408 | |
| 409 if (!VerifyIssuerMatchesSubject(cert, subordinate_cert)) | |
| 410 return false; | |
| 411 | |
| 412 // Verify the digital signature. | |
| 413 if (!VerifySignedData(*subordinate_cert.signature_algorithm, | |
| 414 subordinate_cert.tbs_tlv, | |
| 415 subordinate_cert.signature_value, cert.spki_tlv, | |
| 416 signature_policy)) { | |
| 417 return false; | |
| 418 } | |
| 419 } | |
| 420 | |
| 421 // Keep track of how many certificates were self-issued, since some rules | |
| 422 // are different for self-issued certificates (notably pathlen for | |
| 423 // BasicConstraints). | |
| 424 if (IsSelfIssued(cert)) | |
| 425 num_prev_self_issued_certs++; | |
| 426 } | |
| 427 | |
| 428 // TODO(eroman): | |
| 429 // * Name constraints | |
| 430 // * Policy constraints | |
| 431 // * Extended Key Usage | |
| 432 | |
| 433 return true; | |
| 434 } | |
| 435 | |
| 436 } // namespace net | |
| OLD | NEW |