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 // Map from OID to ParsedExtension. | |
| 24 using ExtensionsMap = std::map<der::Input, ParsedExtension>; | |
| 25 | |
| 26 // Describes all parsed properties of a certificate that are relevant for | |
| 27 // certificate verification. | |
| 28 struct FullyParsedCert { | |
| 29 ParsedCertificate cert; | |
| 30 ParsedTbsCertificate tbs; | |
| 31 | |
| 32 scoped_ptr<SignatureAlgorithm> signature_algorithm; | |
| 33 | |
| 34 // Standard extensions that were parsed. | |
| 35 bool has_basic_constraints = false; | |
| 36 ParsedBasicConstraints basic_constraints; | |
| 37 | |
| 38 bool has_key_usage = false; | |
| 39 der::BitString key_usage; | |
| 40 | |
| 41 // The remaining extensions (excludes the standard ones above). | |
| 42 ExtensionsMap unconsumed_extensions; | |
| 43 }; | |
| 44 | |
| 45 // Removes the extension with OID |oid| from |unconsumed_extensions| and fills | |
| 46 // |extension| with the matching extension value. If there was no extension | |
| 47 // matching |oid| then returns |false|. | |
| 48 WARN_UNUSED_RESULT bool ConsumeExtension(const der::Input& oid, | |
| 49 ExtensionsMap* unconsumed_extensions, | |
| 50 ParsedExtension* extension) { | |
| 51 auto it = unconsumed_extensions->find(oid); | |
| 52 if (it == unconsumed_extensions->end()) | |
| 53 return false; | |
| 54 | |
| 55 *extension = it->second; | |
| 56 unconsumed_extensions->erase(it); | |
| 57 return true; | |
| 58 } | |
| 59 | |
| 60 // Returns true if the certificate does not contain any unconsumed _critical_ | |
| 61 // extensions. | |
| 62 WARN_UNUSED_RESULT bool VerifyNoUnconsumedCriticalExtensions( | |
| 63 const FullyParsedCert& cert) { | |
| 64 for (const auto& entry : cert.unconsumed_extensions) { | |
| 65 if (entry.second.critical) | |
| 66 return false; | |
| 67 } | |
| 68 return true; | |
| 69 } | |
| 70 | |
| 71 // Parses an X.509 Certificate fully (including the TBSCertificate and | |
| 72 // standard extensions), saving all the properties to |out_|. | |
| 73 WARN_UNUSED_RESULT bool FullyParseCertificate(const der::Input& cert_tlv, | |
| 74 FullyParsedCert* out) { | |
| 75 // Reset everything. | |
| 76 *out = FullyParsedCert(); | |
| 77 | |
| 78 // Parse the outer Certificate. | |
| 79 if (!ParseCertificate(cert_tlv, &out->cert)) | |
| 80 return false; | |
| 81 | |
| 82 // Parse the signature algorithm contained in the Certificate (there is | |
| 83 // another one in the TBSCertificate, which is checked later by | |
| 84 // VerifySignatureAlgorithmsMatch) | |
| 85 out->signature_algorithm = | |
| 86 SignatureAlgorithm::CreateFromDer(out->cert.signature_algorithm_tlv); | |
| 87 if (!out->signature_algorithm) | |
| 88 return false; | |
| 89 | |
| 90 // Parse the TBSCertificate. | |
| 91 if (!ParseTbsCertificate(out->cert.tbs_certificate_tlv, &out->tbs)) | |
| 92 return false; | |
| 93 | |
| 94 // Parse the standard X.509 extensions and remove them from | |
| 95 // |unconsumed_extensions|. | |
| 96 if (out->tbs.has_extensions) { | |
| 97 // ParseExtensions() ensures there are no duplicates, and maps the (unique) | |
| 98 // OID to the extension value. | |
| 99 if (!ParseExtensions(out->tbs.extensions_tlv, &out->unconsumed_extensions)) | |
| 100 return false; | |
| 101 | |
| 102 ParsedExtension extension; | |
| 103 | |
| 104 // Basic constraints. | |
| 105 if (ConsumeExtension(BasicConstraintsOid(), &out->unconsumed_extensions, | |
| 106 &extension)) { | |
| 107 out->has_basic_constraints = true; | |
| 108 if (!ParseBasicConstraints(extension.value, &out->basic_constraints)) | |
| 109 return false; | |
| 110 } | |
| 111 | |
| 112 // KeyUsage. | |
| 113 if (ConsumeExtension(KeyUsageOid(), &out->unconsumed_extensions, | |
| 114 &extension)) { | |
| 115 out->has_key_usage = true; | |
| 116 if (!ParseKeyUsage(extension.value, &out->key_usage)) | |
| 117 return false; | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 return true; | |
| 122 } | |
| 123 | |
| 124 // Returns true if |name1| matches |name2|. | |
| 125 WARN_UNUSED_RESULT bool NameMatches(const der::Input& name1, | |
| 126 const der::Input& name2) { | |
| 127 // TODO(eroman): Should account for normalization (i.e. call | |
| 128 // VerifyNameMatches() instead). | |
| 129 return name1.Equals(name2); | |
| 130 } | |
| 131 | |
| 132 // Returns true if |cert| was self-issued. The definition of self-issuance | |
| 133 // comes from RFC 5280 section 6.1: | |
| 134 // | |
| 135 // A certificate is self-issued if the same DN appears in the subject | |
| 136 // and issuer fields (the two DNs are the same if they match according | |
| 137 // to the rules specified in Section 7.1). In general, the issuer and | |
| 138 // subject of the certificates that make up a path are different for | |
| 139 // each certificate. However, a CA may issue a certificate to itself to | |
| 140 // support key rollover or changes in certificate policies. These | |
| 141 // self-issued certificates are not counted when evaluating path length | |
| 142 // or name constraints. | |
| 143 WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) { | |
| 144 return NameMatches(cert.tbs.subject_tlv, cert.tbs.issuer_tlv); | |
| 145 } | |
| 146 | |
| 147 // Finds a trust anchor that matches |name| in |trust_store| or returns | |
| 148 // nullptr. The returned pointer references data in |trust_store|. | |
| 149 // | |
| 150 // TODO(eroman): This implementation is linear in the size of the trust store, | |
| 151 // and also presumes that all names are unique. In practice it is possible to | |
| 152 // have multiple SPKIs with the same name. Also this mechanism of | |
| 153 // searching is fairly primitive, and does not take advantage of other | |
| 154 // properties like the authority key id. | |
| 155 WARN_UNUSED_RESULT const TrustAnchor* FindTrustAnchorByName( | |
| 156 const TrustStore& trust_store, | |
| 157 const der::Input& name) { | |
| 158 for (const auto& anchor : trust_store.anchors) { | |
| 159 if (NameMatches(name, InputFromString(&anchor.name))) | |
| 160 return &anchor; | |
| 161 } | |
| 162 return nullptr; | |
| 163 } | |
| 164 | |
| 165 // Returns true if |cert| is valid at time |time|. | |
| 166 // | |
| 167 // The certificate's validity requirements are described by RFC 5280 section | |
| 168 // 4.1.2.5: | |
| 169 // | |
| 170 // The validity period for a certificate is the period of time from | |
| 171 // notBefore through notAfter, inclusive. | |
| 172 WARN_UNUSED_RESULT bool VerifyTimeValidity(const FullyParsedCert& cert, | |
| 173 const der::GeneralizedTime time) { | |
| 174 return !(time < cert.tbs.validity_not_before) && | |
| 175 !(cert.tbs.validity_not_after < time); | |
| 176 } | |
| 177 | |
| 178 // Returns true if |signature_algorithm_tlv| is a valid algorithm encoding for | |
| 179 // RSA with SHA1. | |
| 180 WARN_UNUSED_RESULT bool IsRsaWithSha1SignatureAlgorithm( | |
| 181 const der::Input& signature_algorithm_tlv) { | |
| 182 scoped_ptr<SignatureAlgorithm> algorithm = | |
| 183 SignatureAlgorithm::CreateFromDer(signature_algorithm_tlv); | |
| 184 | |
| 185 return algorithm && | |
| 186 algorithm->algorithm() == SignatureAlgorithmId::RsaPkcs1 && | |
| 187 algorithm->digest() == DigestAlgorithm::Sha1; | |
| 188 } | |
| 189 | |
| 190 // Returns true if |cert| has internally consistent signature algorithms. | |
| 191 // | |
| 192 // X.509 certificates contain two different signature algorithms: | |
| 193 // (1) The signatureAlgorithm field of Certificate | |
| 194 // (2) The signature field of TBSCertificate | |
| 195 // | |
| 196 // According to RFC 5280 section 4.1.1.2 and 4.1.2.3 these two fields must be | |
| 197 // equal: | |
| 198 // | |
| 199 // This field MUST contain the same algorithm identifier as the | |
| 200 // signature field in the sequence tbsCertificate (Section 4.1.2.3). | |
| 201 // | |
| 202 // The spec is not explicit about what "the same algorithm identifier" means. | |
| 203 // Our interpretation is that the two DER-encoded fields must be byte-for-byte | |
| 204 // identical. | |
| 205 // | |
| 206 // In practice however there are certificates which use different encodings for | |
| 207 // specifying RSA with SHA1 (different OIDs). This is special-cased for | |
| 208 // compatibility sake. | |
|
davidben
2015/12/10 23:23:35
[Incidentally, I have a guess as to what happened.
eroman
2015/12/17 19:43:52
Good to know, thanks
| |
| 209 WARN_UNUSED_RESULT bool VerifySignatureAlgorithmsMatch( | |
| 210 const FullyParsedCert& cert) { | |
| 211 const der::Input& alg1_tlv = cert.cert.signature_algorithm_tlv; | |
| 212 const der::Input& alg2_tlv = cert.tbs.signature_algorithm_tlv; | |
| 213 | |
| 214 // Ensure that the two DER-encoded signature algorithms are byte-for-byte | |
| 215 // equal, but make a compatibility concession for RSA with SHA1. | |
| 216 return alg1_tlv.Equals(alg2_tlv) || | |
| 217 (IsRsaWithSha1SignatureAlgorithm(alg1_tlv) && | |
| 218 IsRsaWithSha1SignatureAlgorithm(alg2_tlv)); | |
| 219 } | |
| 220 | |
| 221 // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate | |
| 222 // Processing" procedure. | |
| 223 WARN_UNUSED_RESULT bool BasicCertificateProcessing( | |
| 224 const FullyParsedCert& cert, | |
| 225 const SignaturePolicy* signature_policy, | |
| 226 const der::GeneralizedTime& time, | |
| 227 const der::Input& working_public_key, | |
| 228 const der::Input& working_issuer_name) { | |
| 229 // Check that the signature algorithms in Certificate vs TBSCertificate | |
| 230 // match. This isn't part of RFC section 6.1.3, but is mandated by sections | |
|
davidben
2015/12/10 23:23:35
Nit: RFC section -> section or RFC 5280 section?
eroman
2015/12/17 19:43:53
Done.
| |
| 231 // 4.1.1.2 and 4.1.2.3. | |
| 232 if (!VerifySignatureAlgorithmsMatch(cert)) | |
| 233 return false; | |
| 234 | |
| 235 // Verify the digital signature using the previous certificate's (or trust | |
| 236 // anchor's) key (RFC 5280 section 6.1.3 step a.1). | |
| 237 if (!VerifySignedData( | |
| 238 *cert.signature_algorithm, cert.cert.tbs_certificate_tlv, | |
| 239 cert.cert.signature_value, working_public_key, signature_policy)) { | |
| 240 return false; | |
| 241 } | |
| 242 | |
| 243 // Check the time range for the certificate's validity, ensuring it is valid | |
| 244 // at |time|. | |
| 245 // (RFC 5280 section 6.1.3 step a.2) | |
| 246 if (!VerifyTimeValidity(cert, time)) | |
| 247 return false; | |
| 248 | |
| 249 // TODO(eroman): Check revocation (RFC 5280 section 6.1.3 step a.3) | |
| 250 | |
| 251 // Verify the certificate's issuer name matches the issuing certificate's (or | |
| 252 // trust anchor's) subject name. (RFC 5280 section 6.1.3 step a.4) | |
| 253 if (!NameMatches(cert.tbs.issuer_tlv, working_issuer_name)) | |
| 254 return false; | |
| 255 | |
| 256 return true; | |
| 257 } | |
| 258 | |
| 259 // This function corresponds to RFC 5280 section 6.1.4's "Preparation for | |
| 260 // Certificate i+1" procedure. |cert| is expected to be an intermediary. | |
| 261 WARN_UNUSED_RESULT bool PrepareForNextCertificate( | |
| 262 const FullyParsedCert& cert, | |
| 263 size_t* max_path_length_ptr, | |
| 264 der::Input* working_public_key, | |
| 265 der::Input* working_issuer_name) { | |
| 266 // From RFC 5280 section 6.1.4 step c: | |
| 267 // | |
| 268 // Assign the certificate subject name to working_issuer_name. | |
| 269 *working_issuer_name = cert.tbs.subject_tlv; | |
| 270 | |
| 271 // From RFC 5280 section 6.1.4 step d: | |
|
davidben
2015/12/10 23:23:35
Strictly speaking, this is steps d-f combined, wit
eroman
2015/12/17 19:43:53
Done. (added comment)
| |
| 272 // | |
| 273 // Assign the certificate subjectPublicKey to working_public_key. | |
| 274 *working_public_key = cert.tbs.spki_tlv; | |
| 275 | |
| 276 // From RFC 5280 section 6.1.4 step k: | |
| 277 // | |
| 278 // If certificate i is a version 3 certificate, verify that the | |
| 279 // basicConstraints extension is present and that cA is set to | |
| 280 // TRUE. (If certificate i is a version 1 or version 2 | |
| 281 // certificate, then the application MUST either verify that | |
| 282 // certificate i is a CA certificate through out-of-band means | |
| 283 // or reject the certificate. Conforming implementations may | |
| 284 // choose to reject all version 1 and version 2 intermediate | |
| 285 // certificates.) | |
| 286 // | |
| 287 // This code implicitly rejects non version 3 intermediaries, since they | |
| 288 // can't contain a BasicConstraints extension. | |
| 289 if (!cert.has_basic_constraints || !cert.basic_constraints.is_ca) | |
| 290 return false; | |
| 291 | |
| 292 // From RFC 5280 section 6.1.4 step l: | |
| 293 // | |
| 294 // If the certificate was not self-issued, verify that | |
| 295 // max_path_length is greater than zero and decrement | |
| 296 // max_path_length by 1. | |
| 297 if (!IsSelfIssued(cert)) { | |
| 298 if (*max_path_length_ptr == 0) | |
| 299 return false; | |
| 300 --(*max_path_length_ptr); | |
| 301 } | |
| 302 | |
| 303 // From RFC 5280 section 6.1.4 step m: | |
| 304 // | |
| 305 // If pathLenConstraint is present in the certificate and is | |
| 306 // less than max_path_length, set max_path_length to the value | |
| 307 // of pathLenConstraint. | |
| 308 if (cert.basic_constraints.has_path_len && | |
| 309 cert.basic_constraints.path_len < *max_path_length_ptr) { | |
| 310 *max_path_length_ptr = cert.basic_constraints.path_len; | |
| 311 } | |
| 312 | |
| 313 // From RFC 5280 section 6.1.4 step n: | |
| 314 // | |
| 315 // If a key usage extension is present, verify that the | |
| 316 // keyCertSign bit is set. | |
| 317 if (cert.has_key_usage && | |
| 318 !cert.key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) { | |
| 319 return false; | |
| 320 } | |
| 321 | |
| 322 // From RFC 5280 section 6.1.4 step o: | |
| 323 // | |
| 324 // Recognize and process any other critical extension present in | |
| 325 // the certificate. Process any other recognized non-critical | |
| 326 // extension present in the certificate that is relevant to path | |
| 327 // processing. | |
| 328 if (!VerifyNoUnconsumedCriticalExtensions(cert)) | |
| 329 return false; | |
| 330 | |
|
davidben
2015/12/10 23:23:35
Nit: Add TODO about policies and name constraints
mattm
2015/12/17 02:37:35
I think it would make sense. It's kind of obvious
eroman
2015/12/17 19:43:53
Done. I have added numerous comments so each step
| |
| 331 return true; | |
| 332 } | |
| 333 | |
| 334 // Checks that if the target certificate has properties that only a CA should | |
| 335 // have (keyCertSign, CA=true, pathLenConstraint), then its other properties | |
| 336 // are consistent with being a CA. | |
| 337 // | |
| 338 // This follows from some requirements in RFC 5280 section 4.2.1.9. In | |
| 339 // particular: | |
| 340 // | |
| 341 // CAs MUST NOT include the pathLenConstraint field unless the cA | |
| 342 // boolean is asserted and the key usage extension asserts the | |
| 343 // keyCertSign bit. | |
| 344 // | |
| 345 // And: | |
| 346 // | |
| 347 // If the cA boolean is not asserted, then the keyCertSign bit in the key | |
| 348 // usage extension MUST NOT be asserted. | |
| 349 // | |
| 350 // TODO(eroman): Strictly speaking the first requirement is on CAs and not the | |
| 351 // certificate client, so could be skipped. | |
| 352 // | |
| 353 // TODO(eroman): I don't believe Firefox enforces the keyCertSign restriction | |
| 354 // for compatibility reasons. Investigate if we need to similarly relax this | |
| 355 // constraint. | |
| 356 WARN_UNUSED_RESULT bool VerifyTargetCertHasConsistentCaBits( | |
| 357 const FullyParsedCert& cert) { | |
| 358 // Check if the certificate contains any property specific to CAs. | |
| 359 bool has_ca_property = | |
| 360 (cert.has_basic_constraints && | |
| 361 (cert.basic_constraints.is_ca || cert.basic_constraints.has_path_len)) || | |
| 362 (cert.has_key_usage && | |
| 363 cert.key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | |
| 364 | |
| 365 // If it "looks" like a CA because it has a CA-only property, then check that | |
| 366 // it sets ALL the properties expected of a CA. | |
| 367 if (has_ca_property) { | |
| 368 return cert.has_basic_constraints && cert.basic_constraints.is_ca && | |
| 369 (!cert.has_key_usage || | |
| 370 cert.key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)); | |
| 371 } | |
| 372 | |
| 373 return true; | |
| 374 } | |
| 375 | |
| 376 // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure". | |
| 377 // It does processing for the final certificate (the target cert). | |
| 378 WARN_UNUSED_RESULT bool WrapUp(const FullyParsedCert& cert) { | |
| 379 // From RFC 5280 section 6.1.5 step f: | |
| 380 // | |
| 381 // Recognize and process any other critical extension present in | |
| 382 // the certificate n. Process any other recognized non-critical | |
| 383 // extension present in certificate n that is relevant to path | |
| 384 // processing. | |
| 385 // | |
| 386 // Note that this is duplicated with PrepareForNextCertificate() so as to | |
| 387 // direclty match the procedures in RFC 5280's section 6.1. | |
|
davidben
2015/12/10 23:23:35
directly
eroman
2015/12/17 19:43:52
Done.
| |
| 388 if (!VerifyNoUnconsumedCriticalExtensions(cert)) | |
| 389 return false; | |
| 390 | |
| 391 // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", | |
| 392 // however is implied by RFC 5280 section 4.2.1.9. | |
| 393 if (!VerifyTargetCertHasConsistentCaBits(cert)) | |
| 394 return false; | |
| 395 | |
| 396 return true; | |
| 397 } | |
| 398 | |
| 399 } // namespace | |
| 400 | |
| 401 TrustAnchor::~TrustAnchor() {} | |
| 402 | |
| 403 TrustStore::TrustStore() {} | |
| 404 TrustStore::~TrustStore() {} | |
| 405 | |
| 406 // This implementation is structured to mimic the description of certificate | |
| 407 // path verification given by RFC 5280 section 6.1. | |
| 408 bool VerifyCertificateChain(const std::vector<der::Input>& certs_der, | |
| 409 const TrustStore& trust_store, | |
| 410 const SignaturePolicy* signature_policy, | |
| 411 const der::GeneralizedTime& time) { | |
| 412 // An empty chain is necessarily invalid. | |
| 413 if (certs_der.empty()) | |
| 414 return false; | |
| 415 | |
| 416 // |working_public_key| corresponds with the same named variable in RFC 5280 | |
| 417 // section 6.1.2: | |
| 418 // | |
| 419 // working_public_key: the public key used to verify the | |
| 420 // signature of a certificate. The working_public_key is | |
| 421 // initialized from the trusted public key provided in the trust | |
| 422 // anchor information. | |
| 423 der::Input working_public_key; | |
|
davidben
2015/12/10 23:23:35
It's actually a combination of working_public_key,
eroman
2015/12/17 19:43:53
Good idea, done (also added a comment block trying
| |
| 424 | |
| 425 // |working_public_key| corresponds with the same named variable in RFC 5280 | |
|
davidben
2015/12/10 23:23:35
working_issuer_name
eroman
2015/12/17 19:43:53
Done.
| |
| 426 // section 6.1.2: | |
| 427 // | |
| 428 // working_issuer_name: the issuer distinguished name expected | |
| 429 // in the next certificate in the chain. The | |
| 430 // working_issuer_name is initialized to the trusted issuer name | |
| 431 // provided in the trust anchor information. | |
| 432 der::Input working_issuer_name; | |
| 433 | |
| 434 // |max_path_length| corresponds with the same named variable in RFC 5280 | |
| 435 // section 6.1.2: | |
| 436 // | |
| 437 // max_path_length: this integer is initialized to n, is | |
| 438 // decremented for each non-self-issued certificate in the path, | |
| 439 // and may be reduced to the value in the path length constraint | |
| 440 // field within the basic constraints extension of a CA | |
| 441 // certificate. | |
| 442 size_t max_path_length = certs_der.size(); | |
| 443 | |
| 444 // Iterate over all the certificates in the reverse direction: starting from | |
| 445 // the trust anchor and progressing towards the target certificate. | |
| 446 for (size_t i = 1; i <= certs_der.size(); ++i) { | |
| 447 // Note that |i| is a 1-based index as per RFC 5280, where the target | |
| 448 // certificate is i=N and the certificate signed by trust anchor is i=N. | |
|
davidben
2015/12/10 23:23:35
(I probably wouldn't have bothered, but whatever.
eroman
2015/12/17 19:43:52
Changed to 0-based indexing. Agreed, perhaps this
| |
| 449 const size_t index_into_certs_der = certs_der.size() - i; | |
| 450 const bool is_target_cert = index_into_certs_der == 0; | |
| 451 | |
| 452 // Parse the current certificate into |cert|. | |
| 453 FullyParsedCert cert; | |
| 454 const der::Input& cert_der = certs_der[index_into_certs_der]; | |
| 455 if (!FullyParseCertificate(cert_der, &cert)) | |
| 456 return false; | |
| 457 | |
| 458 // When processing the first certificate, initialize |working_public_key| | |
| 459 // and |working_issuer_name| to the trust anchor per RFC 5280 section 6.1.2. | |
| 460 // This is done inside the loop in order to have access to the parsed | |
| 461 // certificate. | |
| 462 if (i == 1) { | |
| 463 const TrustAnchor* trust_anchor = | |
| 464 FindTrustAnchorByName(trust_store, cert.tbs.issuer_tlv); | |
| 465 if (!trust_anchor) | |
| 466 return false; | |
| 467 working_public_key = InputFromString(&trust_anchor->spki); | |
| 468 working_issuer_name = InputFromString(&trust_anchor->name); | |
| 469 } | |
| 470 | |
| 471 // Per RFC 5280 section 6.1: | |
| 472 // * Do basic processing for each certificate | |
| 473 // * If it is the last certificate in the path (target certificate) | |
| 474 // - Then run "Wrap up" | |
| 475 // - Otherwise run "Prepare for Next cert" | |
| 476 if (!BasicCertificateProcessing(cert, signature_policy, time, | |
| 477 working_public_key, working_issuer_name)) { | |
| 478 return false; | |
| 479 } | |
| 480 if (!is_target_cert) { | |
| 481 if (!PrepareForNextCertificate(cert, &max_path_length, | |
| 482 &working_public_key, | |
| 483 &working_issuer_name)) { | |
| 484 return false; | |
| 485 } | |
| 486 } else { | |
| 487 if (!WrapUp(cert)) | |
| 488 return false; | |
| 489 } | |
| 490 } | |
| 491 | |
| 492 // TODO(eroman): Are duplicates possible? RFC 5280 forbids them per section | |
| 493 // 6.1: | |
| 494 // | |
| 495 // A certificate MUST NOT appear more than once in a prospective | |
| 496 // certification path. | |
|
davidben
2015/12/10 23:23:35
It's certainly possible in so far as I could const
eroman
2015/12/17 19:43:52
Perhaps not worth handling this at the verificatio
davidben
2015/12/17 20:02:26
None that I can think of.
| |
| 497 | |
| 498 return true; | |
| 499 } | |
| 500 | |
| 501 } // namespace net | |
| OLD | NEW |