diff options
Diffstat (limited to 'chromium/net/cert')
106 files changed, 2236 insertions, 4429 deletions
diff --git a/chromium/net/cert/cert_net_fetcher.h b/chromium/net/cert/cert_net_fetcher.h index f8344702bea..2a45fe3b6f7 100644 --- a/chromium/net/cert/cert_net_fetcher.h +++ b/chromium/net/cert/cert_net_fetcher.h @@ -19,59 +19,42 @@ class GURL; namespace net { -class URLRequestContext; - -// CertNetFetcher is an asynchronous interface for fetching AIA URLs and CRL -// URLs. -// -// ------------------------- -// Cancellation of requests -// ------------------------- -// -// * Network requests started by the CertNetFetcher can be cancelled by -// deleting the Request object. Cancellation means the request's callback -// will no longer be invoked. -// -// * If the CertNetFetcher is deleted then any outstanding -// requests are automatically cancelled. -// -// * Cancelling a request within the execution of a callback is allowed. -// -// * Deleting the CertNetFetcher from within the execution of a callback is -// allowed. -// -// ------------------------- -// Threading -// ------------------------- +// CertNetFetcher is a synchronous interface for fetching AIA URLs and CRL +// URLs. It is shared between a caller thread (which starts and waits for +// fetches), and a network thread (which does the actual fetches). It can be +// shutdown from the network thread to cancel outstanding requests. // -// The CertNetFetcher is expected to be operated from a single thread, which has -// an IO message loop. The URLRequestContext will be accessed from this same -// thread, and callbacks will be posted to this message loop. -// -// For more details see the design document: -// https://docs.google.com/a/chromium.org/document/d/1CdS9YOnPdAyVZBJqHY7ZJ6tUlU71OCvX8kHnaVhf144/edit -class NET_EXPORT CertNetFetcher { +// A Request object is returned when starting a fetch. The consumer can +// use this as a handle for aborting the request (by freeing it), or reading +// the result of the request (WaitForResult) +class NET_EXPORT CertNetFetcher + : public base::RefCountedThreadSafe<CertNetFetcher> { public: class Request { public: virtual ~Request() {} - }; - // Callback invoked on request completion. If the Error is OK, then the - // vector contains the response bytes. - using FetchCallback = - base::Callback<void(Error, const std::vector<uint8_t>&)>; + // WaitForResult() can be called at most once. + // + // It will block and wait for the (network) request to complete, and + // then write the result into the provided out-parameters. + virtual void WaitForResult(Error* error, std::vector<uint8_t>* bytes) = 0; + }; // This value can be used in place of timeout or max size limits. enum { DEFAULT = -1 }; CertNetFetcher() {} - // Deletion implicitly cancels any outstanding requests. - virtual ~CertNetFetcher() {} + // Shuts down the CertNetFetcher and cancels outstanding network requests. It + // is not guaranteed that any outstanding or subsequent + // Request::WaitForResult() calls will be completed. Shutdown() must be called + // from the network thread. It can be called more than once, but must be + // called before the CertNetFetcher is destroyed. + virtual void Shutdown() = 0; - // The Fetch*() methods start an asynchronous request which can be cancelled - // by deleting the returned Request. Here is the meaning of the common + // The Fetch*() methods start a request which can be cancelled by + // deleting the returned Request. Here is the meaning of the common // parameters: // // * url -- The http:// URL to fetch. @@ -81,30 +64,30 @@ class NET_EXPORT CertNetFetcher { // * max_response_bytes -- The maximum size of the response body. If this // size is exceeded then the request will fail. To use a default timeout // pass DEFAULT. - // * callback -- The callback that will be invoked on completion of the job. virtual WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCaIssuers( const GURL& url, int timeout_milliseconds, - int max_response_bytes, - const FetchCallback& callback) = 0; + int max_response_bytes) = 0; virtual WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCrl( const GURL& url, int timeout_milliseconds, - int max_response_bytes, - const FetchCallback& callback) = 0; + int max_response_bytes) = 0; virtual WARN_UNUSED_RESULT std::unique_ptr<Request> FetchOcsp( const GURL& url, int timeout_milliseconds, - int max_response_bytes, - const FetchCallback& callback) = 0; + int max_response_bytes) = 0; + + protected: + virtual ~CertNetFetcher() {} private: + friend class base::RefCountedThreadSafe<CertNetFetcher>; DISALLOW_COPY_AND_ASSIGN(CertNetFetcher); }; } // namespace net -#endif // NET_CERT_NET_CERT_NET_FETCHER_H_ +#endif // NET_CERT_CERT_NET_FETCHER_H_ diff --git a/chromium/net/cert/cert_verify_proc.cc b/chromium/net/cert/cert_verify_proc.cc index 413abb4b2fb..d9462561012 100644 --- a/chromium/net/cert/cert_verify_proc.cc +++ b/chromium/net/cert/cert_verify_proc.cc @@ -369,6 +369,69 @@ bool AreSHA1IntermediatesAllowed() { #endif }; +// Sets the "has_*" boolean members in |verify_result| that correspond with +// the the presence of |hash| somewhere in the certificate chain (excluding the +// trust anchor). +void MapHashAlgorithmToBool(X509Certificate::SignatureHashAlgorithm hash, + CertVerifyResult* verify_result) { + switch (hash) { + case X509Certificate::kSignatureHashAlgorithmMd2: + verify_result->has_md2 = true; + break; + case X509Certificate::kSignatureHashAlgorithmMd4: + verify_result->has_md4 = true; + break; + case X509Certificate::kSignatureHashAlgorithmMd5: + verify_result->has_md5 = true; + break; + case X509Certificate::kSignatureHashAlgorithmSha1: + verify_result->has_sha1 = true; + break; + case X509Certificate::kSignatureHashAlgorithmOther: + break; + } +} + +// Sets to true the |verify_result->has_*| boolean members for the hash +// algorithms present in the certificate chain. +// +// This considers the hash algorithms in all certificates except trusted +// certificates. +// +// In the case of a successful verification the trust anchor is the final +// certificate in the chain (either the final intermediate, or the leaf +// certificate). +// +// Whereas if verification was uncessful, the chain may be partial, and the +// final certificate may not be a trust anchor. This heuristic is used +// in both successful and failed verifications, despite this ambiguity (failure +// to tag one of the signature algorithms should only affect the final error). +void ComputeSignatureHashAlgorithms(CertVerifyResult* verify_result) { + const X509Certificate::OSCertHandles& intermediates = + verify_result->verified_cert->GetIntermediateCertificates(); + + // If there are no intermediates, then the leaf is trusted or verification + // failed. + if (intermediates.empty()) + return; + + DCHECK(!verify_result->has_sha1); + + // Fill in hash algorithms for the leaf certificate. + MapHashAlgorithmToBool(X509Certificate::GetSignatureHashAlgorithm( + verify_result->verified_cert->os_cert_handle()), + verify_result); + verify_result->has_sha1_leaf = verify_result->has_sha1; + + // Fill in hash algorithms for the intermediate cerificates, excluding the + // final one (which is the trust anchor). + for (size_t i = 0; i + 1 < intermediates.size(); ++i) { + MapHashAlgorithmToBool( + X509Certificate::GetSignatureHashAlgorithm(intermediates[i]), + verify_result); + } +} + } // namespace // static @@ -420,6 +483,8 @@ int CertVerifyProc::Verify(X509Certificate* cert, int rv = VerifyInternal(cert, hostname, ocsp_response, flags, crl_set, additional_trust_anchors, verify_result); + ComputeSignatureHashAlgorithms(verify_result); + UMA_HISTOGRAM_BOOLEAN("Net.CertCommonNameFallback", verify_result->common_name_fallback_used); if (!verify_result->is_issued_by_known_root) { @@ -448,7 +513,7 @@ int CertVerifyProc::Verify(X509Certificate* cert, } if (IsNonWhitelistedCertificate(*verify_result->verified_cert, - verify_result->public_key_hashes)) { + verify_result->public_key_hashes, hostname)) { verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; rv = MapCertStatusToNetError(verify_result->cert_status); } @@ -476,30 +541,28 @@ int CertVerifyProc::Verify(X509Certificate* cert, verify_result->cert_status |= CERT_STATUS_SHA1_SIGNATURE_PRESENT; // Flag certificates using weak signature algorithms. - // The CA/Browser Forum Baseline Requirements (beginning with v1.2.1) - // prohibits SHA-1 certificates from being issued beginning on - // 1 January 2016. Ideally, all of SHA-1 in new certificates would be - // disabled on this date, but enterprises need more time to transition. - // As the risk is greatest for publicly trusted certificates, prevent - // those certificates from being trusted from that date forward. - // - // TODO(mattm): apply the SHA-1 deprecation check to all certs unless - // CertVerifier::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS flag is present. + + // Legacy SHA-1 behaviour: + // - Reject all publicly trusted SHA-1 leaf certs issued after + // 2016-01-01. + bool legacy_sha1_issue = verify_result->has_sha1_leaf && + verify_result->is_issued_by_known_root && + IsPastSHA1DeprecationDate(*cert); + + // Current SHA-1 behaviour: + // - Reject all SHA-1 + // - ... unless it's not publicly trusted and SHA-1 is allowed + // - ... or SHA-1 is in the intermediate and SHA-1 intermediates are + // allowed for that platform. See https://crbug.com/588789 + bool current_sha1_issue = + (verify_result->is_issued_by_known_root || + !(flags & CertVerifier::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS)) && + (verify_result->has_sha1_leaf || + (verify_result->has_sha1 && !AreSHA1IntermediatesAllowed())); + if (verify_result->has_md5 || - // Current SHA-1 behaviour: - // - Reject all publicly trusted SHA-1 - // - ... unless it's in the intermediate and SHA-1 intermediates are - // allowed for that platform. See https://crbug.com/588789 - (!sha1_legacy_mode_enabled && - (verify_result->is_issued_by_known_root && - (verify_result->has_sha1_leaf || - (verify_result->has_sha1 && !AreSHA1IntermediatesAllowed())))) || - // Legacy SHA-1 behaviour: - // - Reject all publicly trusted SHA-1 leaf certs issued after - // 2016-01-01. - (sha1_legacy_mode_enabled && (verify_result->has_sha1_leaf && - verify_result->is_issued_by_known_root && - IsPastSHA1DeprecationDate(*cert)))) { + (sha1_legacy_mode_enabled && legacy_sha1_issue) || + (!sha1_legacy_mode_enabled && current_sha1_issue)) { verify_result->cert_status |= CERT_STATUS_WEAK_SIGNATURE_ALGORITHM; // Avoid replacing a more serious error, such as an OS/library failure, // by ensuring that if verification failed, it failed with a certificate diff --git a/chromium/net/cert/cert_verify_proc.h b/chromium/net/cert/cert_verify_proc.h index 352610f22e5..33f87ee3f62 100644 --- a/chromium/net/cert/cert_verify_proc.h +++ b/chromium/net/cert/cert_verify_proc.h @@ -88,9 +88,25 @@ class NET_EXPORT CertVerifyProc VerifyRejectsSHA1AfterDeprecationLegacyMode); // Performs the actual verification using the desired underlying - // cryptographic library. On entry, |verify_result->verified_cert| - // is set to |cert|, the unverified chain. If no chain is built, the - // value must be left untouched. + // + // On entry, |verify_result| will be default-initialized as a successful + // validation, with |verify_result->verified_cert| set to |cert|. + // + // Implementations are expected to fill in all applicable fields, excluding: + // + // * ocsp_result + // * has_md2 + // * has_md4 + // * has_md5 + // * has_sha1 + // * has_sha1_leaf + // + // which will be filled in by |Verify()|. If an error code is returned, + // |verify_result->cert_status| should be non-zero, indicating an + // error occurred. + // + // On success, net::OK should be returned, with |verify_result| updated to + // reflect the successfully verified chain. virtual int VerifyInternal(X509Certificate* cert, const std::string& hostname, const std::string& ocsp_response, diff --git a/chromium/net/cert/cert_verify_proc_android.cc b/chromium/net/cert/cert_verify_proc_android.cc index 2cb12f75c23..f90f5721c3d 100644 --- a/chromium/net/cert/cert_verify_proc_android.cc +++ b/chromium/net/cert/cert_verify_proc_android.cc @@ -79,32 +79,6 @@ bool VerifyFromAndroidTrustManager(const std::vector<std::string>& cert_bytes, chain.push_back(verify_result->verified_cert->os_cert_handle()); chain.insert(chain.end(), intermediates.begin(), intermediates.end()); - // If the chain successfully verified, ignore the trust anchor (the last - // certificate). Otherwise, assume the chain is partial. This is not entirely - // correct, as a full chain may have been constructed and then failed to - // validate. However, if that is the case, the more serious error will - // override any SHA-1 considerations. - size_t correction_for_root = - (status == android::CERT_VERIFY_STATUS_ANDROID_OK) ? 1 : 0; - for (size_t i = 0; i < chain.size() - correction_for_root; ++i) { - int sig_alg = OBJ_obj2nid(chain[i]->sig_alg->algorithm); - if (sig_alg == NID_md2WithRSAEncryption) { - verify_result->has_md2 = true; - } else if (sig_alg == NID_md4WithRSAEncryption) { - verify_result->has_md4 = true; - } else if (sig_alg == NID_md5WithRSAEncryption || - sig_alg == NID_md5WithRSA) { - verify_result->has_md5 = true; - } else if (sig_alg == NID_sha1WithRSAEncryption || - sig_alg == NID_dsaWithSHA || sig_alg == NID_dsaWithSHA1 || - sig_alg == NID_dsaWithSHA1_2 || sig_alg == NID_sha1WithRSA || - sig_alg == NID_ecdsa_with_SHA1) { - verify_result->has_sha1 = true; - if (i == 0) - verify_result->has_sha1_leaf = true; - } - } - // Extract the public key hashes. for (size_t i = 0; i < verified_chain.size(); i++) { base::StringPiece spki_bytes; diff --git a/chromium/net/cert/cert_verify_proc_blacklist.inc b/chromium/net/cert/cert_verify_proc_blacklist.inc index b2bb55464a3..3ca92f144eb 100644 --- a/chromium/net/cert/cert_verify_proc_blacklist.inc +++ b/chromium/net/cert/cert_verify_proc_blacklist.inc @@ -5,7 +5,7 @@ // The certificate(s) that were misissued, and which represent these SPKIs, // are stored within net/data/ssl/blacklist. Further details about the // rationale is documented in net/data/ssl/blacklist/README.md -static const size_t kNumBlacklistedSPKIs = 34u; +static const size_t kNumBlacklistedSPKIs = 36u; static const uint8_t kBlacklistedSPKIs[kNumBlacklistedSPKIs][crypto::kSHA256Length] = { // ead610e6e90b439f2ecb51628b0932620f6ef340bd843fca38d3181b8f4ba197.pem @@ -24,6 +24,10 @@ static const uint8_t {0x1a, 0xf5, 0x6c, 0x98, 0xff, 0x04, 0x3e, 0xf9, 0x2b, 0xeb, 0xff, 0x54, 0xce, 0xbb, 0x4d, 0xd6, 0x7a, 0x25, 0xba, 0x95, 0x6c, 0x81, 0x7f, 0x3e, 0x6d, 0xd3, 0xc1, 0xe5, 0x2e, 0xb5, 0x84, 0xc1}, + // e28393773da845a679f2080cc7fb44a3b7a1c3792cb7eb7729fdcb6a8d99aea7.pem + {0x1f, 0x42, 0x24, 0xce, 0xc8, 0x4f, 0xc9, 0x9c, 0xed, 0x88, 0x1f, + 0xf6, 0xfc, 0xfd, 0x3e, 0x21, 0xf8, 0xc5, 0x19, 0xc5, 0x47, 0xaa, + 0x6a, 0x5d, 0xd3, 0xde, 0x24, 0x73, 0x02, 0xce, 0x50, 0xd1}, // 2c998e761160c3b06d82faa9fdc7545d9bda9eb60310f992aa510a6280b74245.pem {0x2c, 0x99, 0x8e, 0x76, 0x11, 0x60, 0xc3, 0xb0, 0x6d, 0x82, 0xfa, 0xa9, 0xfd, 0xc7, 0x54, 0x5d, 0x9b, 0xda, 0x9e, 0xb6, 0x03, 0x10, @@ -78,6 +82,10 @@ static const uint8_t {0x9b, 0x8a, 0x93, 0xde, 0xcc, 0xcf, 0xba, 0xfc, 0xf4, 0xd0, 0x4d, 0x34, 0x42, 0x12, 0x8f, 0xb3, 0x52, 0x18, 0xcf, 0xe4, 0x37, 0xa3, 0xd8, 0xd0, 0x32, 0x8c, 0x99, 0xf8, 0x90, 0x89, 0xe4, 0x50}, + // 1c01c6f4dbb2fefc22558b2bca32563f49844acfc32b7be4b0ff599f9e8c7af7.pem + {0x9d, 0xd5, 0x5f, 0xc5, 0x73, 0xf5, 0x46, 0xcb, 0x6a, 0x38, 0x31, + 0xd1, 0x11, 0x2d, 0x87, 0x10, 0xa6, 0xf4, 0xf8, 0x2d, 0xc8, 0x7f, + 0x5f, 0xae, 0x9d, 0x3a, 0x1a, 0x02, 0x8d, 0xd3, 0x6e, 0x4b}, // 0d136e439f0ab6e97f3a02a540da9f0641aa554e1d66ea51ae2920d51b2f7217.pem // 4fee0163686ecbd65db968e7494f55d84b25486d438e9de558d629d28cd4d176.pem // 8a1bd21661c60015065212cc98b1abb50dfd14c872a208e66bae890f25c448af.pem diff --git a/chromium/net/cert/cert_verify_proc_ios.cc b/chromium/net/cert/cert_verify_proc_ios.cc index 2ab30ed07e4..19dc20fa722 100644 --- a/chromium/net/cert/cert_verify_proc_ios.cc +++ b/chromium/net/cert/cert_verify_proc_ios.cc @@ -104,12 +104,6 @@ int BuildAndEvaluateSecTrustRef(CFArrayRef cert_array, void GetCertChainInfo(CFArrayRef cert_chain, CertVerifyResult* verify_result) { DCHECK_LT(0, CFArrayGetCount(cert_chain)); - verify_result->has_md2 = false; - verify_result->has_md4 = false; - verify_result->has_md5 = false; - verify_result->has_sha1 = false; - verify_result->has_sha1_leaf = false; - SecCertificateRef verified_cert = nullptr; std::vector<SecCertificateRef> verified_chain; for (CFIndex i = 0, count = CFArrayGetCount(cert_chain); i < count; ++i) { @@ -124,8 +118,6 @@ void GetCertChainInfo(CFArrayRef cert_chain, CertVerifyResult* verify_result) { std::string der_bytes; if (!X509Certificate::GetDEREncoded(chain_cert, &der_bytes)) return; - const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_bytes.data()); - bssl::UniquePtr<X509> x509_cert(d2i_X509(NULL, &bytes, der_bytes.size())); base::StringPiece spki_bytes; if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) @@ -144,23 +136,6 @@ void GetCertChainInfo(CFArrayRef cert_chain, CertVerifyResult* verify_result) { i == count - 1) { continue; } - - int sig_alg = OBJ_obj2nid(x509_cert->sig_alg->algorithm); - if (sig_alg == NID_md2WithRSAEncryption) { - verify_result->has_md2 = true; - } else if (sig_alg == NID_md4WithRSAEncryption) { - verify_result->has_md4 = true; - } else if (sig_alg == NID_md5WithRSAEncryption || - sig_alg == NID_md5WithRSA) { - verify_result->has_md5 = true; - } else if (sig_alg == NID_sha1WithRSAEncryption || - sig_alg == NID_dsaWithSHA || sig_alg == NID_dsaWithSHA1 || - sig_alg == NID_dsaWithSHA1_2 || sig_alg == NID_sha1WithRSA || - sig_alg == NID_ecdsa_with_SHA1) { - verify_result->has_sha1 = true; - if (i == 0) - verify_result->has_sha1_leaf = true; - } } if (!verified_cert) { NOTREACHED(); diff --git a/chromium/net/cert/cert_verify_proc_mac.cc b/chromium/net/cert/cert_verify_proc_mac.cc index 08f1b887f59..46d1cc864b8 100644 --- a/chromium/net/cert/cert_verify_proc_mac.cc +++ b/chromium/net/cert/cert_verify_proc_mac.cc @@ -177,23 +177,12 @@ OSStatus CreateTrustPolicies(int flags, ScopedCFTypeRef<CFArrayRef>* policies) { return noErr; } -// Stores the constructed certificate chain |cert_chain| and information about -// the signature algorithms used into |*verify_result|. If the leaf cert in -// |cert_chain| contains a weak (MD2, MD4, MD5, SHA-1) signature, stores that -// in |*leaf_is_weak|. |cert_chain| must not be empty. -void GetCertChainInfo(CFArrayRef cert_chain, - CSSM_TP_APPLE_EVIDENCE_INFO* chain_info, - CertVerifyResult* verify_result, - bool* leaf_is_weak) { +// Stores the constructed certificate chain |cert_chain| into +// |*verify_result|. |cert_chain| must not be empty. +void CopyCertChainToVerifyResult(CFArrayRef cert_chain, + CertVerifyResult* verify_result) { DCHECK_LT(0, CFArrayGetCount(cert_chain)); - *leaf_is_weak = false; - verify_result->has_md2 = false; - verify_result->has_md4 = false; - verify_result->has_md5 = false; - verify_result->has_sha1 = false; - verify_result->has_sha1_leaf = false; - SecCertificateRef verified_cert = NULL; std::vector<SecCertificateRef> verified_chain; for (CFIndex i = 0, count = CFArrayGetCount(cert_chain); i < count; ++i) { @@ -204,6 +193,29 @@ void GetCertChainInfo(CFArrayRef cert_chain, } else { verified_chain.push_back(chain_cert); } + } + if (!verified_cert) { + NOTREACHED(); + return; + } + + verify_result->verified_cert = + X509Certificate::CreateFromHandle(verified_cert, verified_chain); +} + +// Returns true if the intermediates (excluding trusted certificates) use a +// weak hashing algorithm, but the target does not use a weak hash. +bool IsWeakChainBasedOnHashingAlgorithms( + CFArrayRef cert_chain, + CSSM_TP_APPLE_EVIDENCE_INFO* chain_info) { + DCHECK_LT(0, CFArrayGetCount(cert_chain)); + + bool intermediates_contain_weak_hash = false; + bool leaf_uses_weak_hash = false; + + for (CFIndex i = 0, count = CFArrayGetCount(cert_chain); i < count; ++i) { + SecCertificateRef chain_cert = reinterpret_cast<SecCertificateRef>( + const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); if ((chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_IN_ANCHORS) || (chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_ROOT)) { @@ -215,57 +227,26 @@ void GetCertChainInfo(CFArrayRef cert_chain, continue; } - x509_util::CSSMCachedCertificate cached_cert; - OSStatus status = cached_cert.Init(chain_cert); - if (status) - continue; - x509_util::CSSMFieldValue signature_field; - status = cached_cert.GetField(&CSSMOID_X509V1SignatureAlgorithm, - &signature_field); - if (status || !signature_field.field()) - continue; - // Match the behaviour of OS X system tools and defensively check that - // sizes are appropriate. This would indicate a critical failure of the - // OS X certificate library, but based on history, it is best to play it - // safe. - const CSSM_X509_ALGORITHM_IDENTIFIER* sig_algorithm = - signature_field.GetAs<CSSM_X509_ALGORITHM_IDENTIFIER>(); - if (!sig_algorithm) - continue; - - const CSSM_OID* alg_oid = &sig_algorithm->algorithm; - if (CSSMOIDEqual(alg_oid, &CSSMOID_MD2WithRSA)) { - verify_result->has_md2 = true; - if (i == 0) - *leaf_is_weak = true; - } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD4WithRSA)) { - verify_result->has_md4 = true; - if (i == 0) - *leaf_is_weak = true; - } else if (CSSMOIDEqual(alg_oid, &CSSMOID_MD5WithRSA)) { - verify_result->has_md5 = true; - if (i == 0) - *leaf_is_weak = true; - } else if (CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithRSA) || - CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithRSA_OIW) || - CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA) || - CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_CMS) || - CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_JDK) || - CSSMOIDEqual(alg_oid, &CSSMOID_ECDSA_WithSHA1)) { - verify_result->has_sha1 = true; - if (i == 0) { - verify_result->has_sha1_leaf = true; - *leaf_is_weak = true; - } + X509Certificate::SignatureHashAlgorithm hash_algorithm = + X509Certificate::GetSignatureHashAlgorithm(chain_cert); + + switch (hash_algorithm) { + case X509Certificate::kSignatureHashAlgorithmMd2: + case X509Certificate::kSignatureHashAlgorithmMd4: + case X509Certificate::kSignatureHashAlgorithmMd5: + case X509Certificate::kSignatureHashAlgorithmSha1: + if (i == 0) { + leaf_uses_weak_hash = true; + } else { + intermediates_contain_weak_hash = true; + } + break; + case X509Certificate::kSignatureHashAlgorithmOther: + break; } } - if (!verified_cert) { - NOTREACHED(); - return; - } - verify_result->verified_cert = - X509Certificate::CreateFromHandle(verified_cert, verified_chain); + return !leaf_uses_weak_hash && intermediates_contain_weak_hash; } using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; @@ -842,14 +823,8 @@ int VerifyWithGivenFlags(X509Certificate* cert, DCHECK(untrusted); DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result); } else { - CertVerifyResult temp_verify_result; - bool leaf_is_weak = false; - GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result, - &leaf_is_weak); weak_chain = - !leaf_is_weak && - (temp_verify_result.has_md2 || temp_verify_result.has_md4 || - temp_verify_result.has_md5 || temp_verify_result.has_sha1); + IsWeakChainBasedOnHashingAlgorithms(temp_chain, temp_chain_info); } // Set the result to the current chain if: // - This is the first verification attempt. This ensures that if @@ -894,9 +869,7 @@ int VerifyWithGivenFlags(X509Certificate* cert, verify_result->cert_status |= CERT_STATUS_REVOKED; if (CFArrayGetCount(completed_chain) > 0) { - bool leaf_is_weak_unused = false; - GetCertChainInfo(completed_chain, chain_info, verify_result, - &leaf_is_weak_unused); + CopyCertChainToVerifyResult(completed_chain, verify_result); } // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits diff --git a/chromium/net/cert/cert_verify_proc_nss.cc b/chromium/net/cert/cert_verify_proc_nss.cc index 1ac27cb48ef..59cfa03235a 100644 --- a/chromium/net/cert/cert_verify_proc_nss.cc +++ b/chromium/net/cert/cert_verify_proc_nss.cc @@ -191,30 +191,6 @@ void GetCertChainInfo(CERTCertList* cert_list, } verified_chain.push_back(node->cert); } - - SECAlgorithmID& signature = node->cert->signature; - SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm); - switch (oid_tag) { - case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: - verify_result->has_md5 = true; - break; - case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: - verify_result->has_md2 = true; - break; - case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: - verify_result->has_md4 = true; - break; - case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: - case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: - case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: - case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: - verify_result->has_sha1 = true; - if (i == 0) - verify_result->has_sha1_leaf = true; - break; - default: - break; - } } if (root_cert) diff --git a/chromium/net/cert/cert_verify_proc_openssl.cc b/chromium/net/cert/cert_verify_proc_openssl.cc index 988bdec1e2e..d822bc00d6c 100644 --- a/chromium/net/cert/cert_verify_proc_openssl.cc +++ b/chromium/net/cert/cert_verify_proc_openssl.cc @@ -104,27 +104,6 @@ void GetCertChainInfo(X509_STORE_CTX* store_ctx, } else { verified_chain.push_back(cert); } - - // Only check the algorithm status for certificates that are not in the - // trust store. - if (i < static_cast<size_t>(store_ctx->last_untrusted)) { - int sig_alg = OBJ_obj2nid(cert->sig_alg->algorithm); - if (sig_alg == NID_md2WithRSAEncryption) { - verify_result->has_md2 = true; - } else if (sig_alg == NID_md4WithRSAEncryption) { - verify_result->has_md4 = true; - } else if (sig_alg == NID_md5WithRSAEncryption || - sig_alg == NID_md5WithRSA) { - verify_result->has_md5 = true; - } else if (sig_alg == NID_sha1WithRSAEncryption || - sig_alg == NID_dsaWithSHA || sig_alg == NID_dsaWithSHA1 || - sig_alg == NID_dsaWithSHA1_2 || sig_alg == NID_sha1WithRSA || - sig_alg == NID_ecdsa_with_SHA1) { - verify_result->has_sha1 = true; - if (i == 0) - verify_result->has_sha1_leaf = true; - } - } } // Set verify_result->verified_cert and diff --git a/chromium/net/cert/cert_verify_proc_unittest.cc b/chromium/net/cert/cert_verify_proc_unittest.cc index 862f7c8690c..2e3a0f5d458 100644 --- a/chromium/net/cert/cert_verify_proc_unittest.cc +++ b/chromium/net/cert/cert_verify_proc_unittest.cc @@ -38,6 +38,7 @@ #endif #if defined(OS_MACOSX) && !defined(OS_IOS) +#include "base/mac/mac_util.h" #include "net/cert/test_keychain_search_list_mac.h" #endif @@ -122,6 +123,16 @@ bool SupportsDetectingKnownRoots() { return true; } +bool WeakKeysAreInvalid() { +#if defined(OS_MACOSX) && !defined(OS_IOS) + // Starting with Mac OS 10.12, certs with weak keys are treated as + // (recoverable) invalid certificate errors. + return base::mac::IsAtLeastOS10_12(); +#else + return false; +#endif +} + // Template helper to load a series of certificate files into a CertificateList. // Like CertTestUtil's CreateCertificateListFromFile, except it can load a // series of individual certificates (to make the tests clearer). @@ -407,7 +418,7 @@ TEST_F(CertVerifyProcTest, RejectWeakKeys) { EXPECT_NE(OK, error); EXPECT_EQ(CERT_STATUS_WEAK_KEY, verify_result.cert_status & CERT_STATUS_WEAK_KEY); - EXPECT_NE(CERT_STATUS_INVALID, + EXPECT_EQ(WeakKeysAreInvalid() ? CERT_STATUS_INVALID : 0, verify_result.cert_status & CERT_STATUS_INVALID); } else { EXPECT_THAT(error, IsOk()); @@ -882,8 +893,6 @@ TEST_F(CertVerifyProcTest, IntranetHostsRejected) { // that were issued after 1 January 2016, while still allowing those from // before that date, with SHA-1 in the intermediate, or from an enterprise // CA. -// -// TODO(rsleevi): This code should be removed in M57. TEST_F(CertVerifyProcTest, VerifyRejectsSHA1AfterDeprecationLegacyMode) { base::test::ScopedFeatureList scoped_feature_list; scoped_feature_list.InitAndEnableFeature(CertVerifyProc::kSHA1LegacyMode); @@ -928,7 +937,7 @@ TEST_F(CertVerifyProcTest, VerifyRejectsSHA1AfterDeprecationLegacyMode) { EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_WEAK_SIGNATURE_ALGORITHM); // Enterprise issued SHA-1 leaf certificates issued on/after 1 January 2016 - // remain accepted until SHA-1 is disabled. + // remain accepted. verify_result.Reset(); dummy_result.Reset(); dummy_result.is_issued_by_known_root = false; @@ -1208,39 +1217,32 @@ TEST_F(CertVerifyProcTest, CRLSet) { TEST_F(CertVerifyProcTest, CRLSetLeafSerial) { CertificateList ca_cert_list = - CreateCertificateListFromFile(GetTestCertsDirectory(), - "quic_root.crt", + CreateCertificateListFromFile(GetTestCertsDirectory(), "root_ca_cert.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, ca_cert_list.size()); ScopedTestRoot test_root(ca_cert_list[0].get()); - CertificateList intermediate_cert_list = - CreateCertificateListFromFile(GetTestCertsDirectory(), - "quic_intermediate.crt", - X509Certificate::FORMAT_AUTO); + CertificateList intermediate_cert_list = CreateCertificateListFromFile( + GetTestCertsDirectory(), "intermediate_ca_cert.pem", + X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, intermediate_cert_list.size()); X509Certificate::OSCertHandles intermediates; intermediates.push_back(intermediate_cert_list[0]->os_cert_handle()); CertificateList cert_list = CreateCertificateListFromFile( - GetTestCertsDirectory(), "quic_test.example.com.crt", + GetTestCertsDirectory(), "ok_cert_by_intermediate.pem", X509Certificate::FORMAT_AUTO); ASSERT_EQ(1U, cert_list.size()); - scoped_refptr<X509Certificate> leaf = - X509Certificate::CreateFromHandle(cert_list[0]->os_cert_handle(), - intermediates); + scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromHandle( + cert_list[0]->os_cert_handle(), intermediates); + ASSERT_TRUE(leaf); int flags = 0; CertVerifyResult verify_result; - int error = Verify(leaf.get(), - "test.example.com", - flags, - NULL, - empty_cert_list_, + int error = Verify(leaf.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); EXPECT_THAT(error, IsOk()); - EXPECT_EQ(CERT_STATUS_SHA1_SIGNATURE_PRESENT, verify_result.cert_status); // Test revocation by serial number of a certificate not under the root. scoped_refptr<CRLSet> crl_set; @@ -1250,12 +1252,8 @@ TEST_F(CertVerifyProcTest, CRLSetLeafSerial) { &crl_set_bytes)); ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set)); - error = Verify(leaf.get(), - "test.example.com", - flags, - crl_set.get(), - empty_cert_list_, - &verify_result); + error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(), + empty_cert_list_, &verify_result); EXPECT_THAT(error, IsError(ERR_CERT_REVOKED)); } @@ -1392,6 +1390,11 @@ TEST_F(CertVerifyProcTest, CRLSetDuringPathBuilding) { // The verifier should rollback until it just tries A(B) alone, at which point // it will pull B(F) & F(E) from the keychain and succeed. TEST_F(CertVerifyProcTest, MacCRLIntermediate) { + if (base::mac::IsAtLeastOS10_12()) { + // TODO(crbug.com/671889): Investigate SecTrustSetKeychains issue on Sierra. + LOG(INFO) << "Skipping test, SecTrustSetKeychains does not work on 10.12"; + return; + } const char* const kPath2Files[] = { "multi-root-A-by-B.pem", "multi-root-B-by-C.pem", "multi-root-C-by-E.pem", "multi-root-E-by-E.pem"}; @@ -1631,7 +1634,7 @@ TEST_F(CertVerifyProcTest, RejectsPublicSHA1IntermediatesUnlessAllowed) { } } -TEST_F(CertVerifyProcTest, AcceptsPrivateSHA1) { +TEST_F(CertVerifyProcTest, RejectsPrivateSHA1UnlessFlag) { scoped_refptr<X509Certificate> cert( ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem")); ASSERT_TRUE(cert); @@ -1642,10 +1645,19 @@ TEST_F(CertVerifyProcTest, AcceptsPrivateSHA1) { result.is_issued_by_known_root = false; verify_proc_ = new MockCertVerifyProc(result); + // SHA-1 should be rejected by default for private roots... int flags = 0; CertVerifyResult verify_result; int error = Verify(cert.get(), "127.0.0.1", flags, nullptr /* crl_set */, empty_cert_list_, &verify_result); + EXPECT_THAT(error, IsError(ERR_CERT_WEAK_SIGNATURE_ALGORITHM)); + EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_SHA1_SIGNATURE_PRESENT); + + // ... unless VERIFY_ENABLE_SHA1_LOCAL_ANCHORS was supplied. + flags = CertVerifier::VERIFY_ENABLE_SHA1_LOCAL_ANCHORS; + verify_result.Reset(); + error = Verify(cert.get(), "127.0.0.1", flags, nullptr /* crl_set */, + empty_cert_list_, &verify_result); EXPECT_THAT(error, IsOk()); EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_SHA1_SIGNATURE_PRESENT); } @@ -1665,14 +1677,20 @@ struct WeakDigestTestData { int expected_algorithms; }; +const char* StringOrDefault(const char* str, const char* default_value) { + if (!str) + return default_value; + return str; +} + // GTest 'magic' pretty-printer, so that if/when a test fails, it knows how // to output the parameter that was passed. Without this, it will simply // attempt to print out the first twenty bytes of the object, which depending // on platform and alignment, may result in an invalid read. void PrintTo(const WeakDigestTestData& data, std::ostream* os) { - *os << "root: " - << (data.root_cert_filename ? data.root_cert_filename : "none") - << "; intermediate: " << data.intermediate_cert_filename + *os << "root: " << StringOrDefault(data.root_cert_filename, "none") + << "; intermediate: " + << StringOrDefault(data.intermediate_cert_filename, "none") << "; end-entity: " << data.ee_cert_filename; } @@ -1684,31 +1702,35 @@ class CertVerifyProcWeakDigestTest virtual ~CertVerifyProcWeakDigestTest() {} }; -// Test that the underlying cryptographic library properly surfaces the -// algorithms used in the chain. Some libraries, like NSS, don't return -// the failing chain on error, and thus not all tests can be run. +// Test that the CertVerifyProc::Verify() properly surfaces the (weak) hashing +// algorithms used in the chain. TEST_P(CertVerifyProcWeakDigestTest, VerifyDetectsAlgorithm) { WeakDigestTestData data = GetParam(); base::FilePath certs_dir = GetTestCertsDirectory(); - ScopedTestRoot test_root; + scoped_refptr<X509Certificate> intermediate_cert; + scoped_refptr<X509Certificate> root_cert; + + // Build |intermediates| as the full chain (including trust anchor). + X509Certificate::OSCertHandles intermediates; + + if (data.intermediate_cert_filename) { + intermediate_cert = + ImportCertFromFile(certs_dir, data.intermediate_cert_filename); + ASSERT_TRUE(intermediate_cert); + intermediates.push_back(intermediate_cert->os_cert_handle()); + } + if (data.root_cert_filename) { - scoped_refptr<X509Certificate> root_cert = - ImportCertFromFile(certs_dir, data.root_cert_filename); - ASSERT_TRUE(root_cert); - test_root.Reset(root_cert.get()); + root_cert = ImportCertFromFile(certs_dir, data.root_cert_filename); + ASSERT_TRUE(root_cert); + intermediates.push_back(root_cert->os_cert_handle()); } - scoped_refptr<X509Certificate> intermediate_cert = - ImportCertFromFile(certs_dir, data.intermediate_cert_filename); - ASSERT_TRUE(intermediate_cert); scoped_refptr<X509Certificate> ee_cert = ImportCertFromFile(certs_dir, data.ee_cert_filename); ASSERT_TRUE(ee_cert); - X509Certificate::OSCertHandles intermediates; - intermediates.push_back(intermediate_cert->os_cert_handle()); - scoped_refptr<X509Certificate> ee_chain = X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(), intermediates); @@ -1716,8 +1738,16 @@ TEST_P(CertVerifyProcWeakDigestTest, VerifyDetectsAlgorithm) { int flags = 0; CertVerifyResult verify_result; - Verify(ee_chain.get(), "127.0.0.1", flags, NULL, empty_cert_list_, - &verify_result); + + // Use a mock CertVerifyProc that returns success with a verified_cert of + // |ee_chain|. + // + // This is sufficient for the purposes of this test, as the checking for weak + // hashing algorithms is done by CertVerifyProc::Verify(). + scoped_refptr<CertVerifyProc> proc = + new MockCertVerifyProc(CertVerifyResult()); + proc->Verify(ee_chain.get(), "127.0.0.1", std::string(), flags, nullptr, + empty_cert_list_, &verify_result); EXPECT_EQ(!!(data.expected_algorithms & EXPECT_MD2), verify_result.has_md2); EXPECT_EQ(!!(data.expected_algorithms & EXPECT_MD4), verify_result.has_md4); EXPECT_EQ(!!(data.expected_algorithms & EXPECT_MD5), verify_result.has_md5); @@ -1726,34 +1756,16 @@ TEST_P(CertVerifyProcWeakDigestTest, VerifyDetectsAlgorithm) { verify_result.has_sha1_leaf); } -// Unlike TEST/TEST_F, which are macros that expand to further macros, -// INSTANTIATE_TEST_CASE_P is a macro that expands directly to code that -// stringizes the arguments. As a result, macros passed as parameters (such as -// prefix or test_case_name) will not be expanded by the preprocessor. To work -// around this, indirect the macro for INSTANTIATE_TEST_CASE_P, so that the -// pre-processor will expand macros such as MAYBE_test_name before -// instantiating the test. -#define WRAPPED_INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) - // The signature algorithm of the root CA should not matter. const WeakDigestTestData kVerifyRootCATestData[] = { {"weak_digest_md5_root.pem", "weak_digest_sha1_intermediate.pem", "weak_digest_sha1_ee.pem", EXPECT_SHA1 | EXPECT_SHA1_LEAF}, -#if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) - // MD4 is not supported by OS X / NSS {"weak_digest_md4_root.pem", "weak_digest_sha1_intermediate.pem", "weak_digest_sha1_ee.pem", EXPECT_SHA1 | EXPECT_SHA1_LEAF}, -#endif {"weak_digest_md2_root.pem", "weak_digest_sha1_intermediate.pem", "weak_digest_sha1_ee.pem", EXPECT_SHA1 | EXPECT_SHA1_LEAF}, }; -#if defined(OS_ANDROID) -#define MAYBE_VerifyRoot DISABLED_VerifyRoot -#else -#define MAYBE_VerifyRoot VerifyRoot -#endif -INSTANTIATE_TEST_CASE_P(MAYBE_VerifyRoot, +INSTANTIATE_TEST_CASE_P(VerifyRoot, CertVerifyProcWeakDigestTest, testing::ValuesIn(kVerifyRootCATestData)); @@ -1761,97 +1773,66 @@ INSTANTIATE_TEST_CASE_P(MAYBE_VerifyRoot, const WeakDigestTestData kVerifyIntermediateCATestData[] = { {"weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem", "weak_digest_sha1_ee.pem", EXPECT_MD5 | EXPECT_SHA1 | EXPECT_SHA1_LEAF}, -#if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) - // MD4 is not supported by OS X / NSS {"weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem", "weak_digest_sha1_ee.pem", EXPECT_MD4 | EXPECT_SHA1 | EXPECT_SHA1_LEAF}, -#endif {"weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem", "weak_digest_sha1_ee.pem", EXPECT_MD2 | EXPECT_SHA1 | EXPECT_SHA1_LEAF}, }; -// Disabled on NSS - MD4 is not supported, and MD2 and MD5 are disabled. -#if defined(USE_NSS_CERTS) || defined(OS_IOS) || defined(OS_ANDROID) -#define MAYBE_VerifyIntermediate DISABLED_VerifyIntermediate -#else -#define MAYBE_VerifyIntermediate VerifyIntermediate -#endif -WRAPPED_INSTANTIATE_TEST_CASE_P( - MAYBE_VerifyIntermediate, - CertVerifyProcWeakDigestTest, - testing::ValuesIn(kVerifyIntermediateCATestData)); + +INSTANTIATE_TEST_CASE_P(VerifyIntermediate, + CertVerifyProcWeakDigestTest, + testing::ValuesIn(kVerifyIntermediateCATestData)); // The signature algorithm of end-entity should be properly detected. const WeakDigestTestData kVerifyEndEntityTestData[] = { { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem", "weak_digest_md5_ee.pem", EXPECT_MD5 | EXPECT_SHA1 }, -#if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) - // MD4 is not supported by OS X / NSS { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem", "weak_digest_md4_ee.pem", EXPECT_MD4 | EXPECT_SHA1 }, -#endif { "weak_digest_sha1_root.pem", "weak_digest_sha1_intermediate.pem", "weak_digest_md2_ee.pem", EXPECT_MD2 | EXPECT_SHA1 }, }; -// Disabled on NSS - NSS caches chains/signatures in such a way that cannot -// be cleared until NSS is cleanly shutdown, which is not presently supported -// in Chromium. -#if defined(USE_NSS_CERTS) || defined(OS_IOS) || defined(OS_ANDROID) -#define MAYBE_VerifyEndEntity DISABLED_VerifyEndEntity -#else -#define MAYBE_VerifyEndEntity VerifyEndEntity -#endif -WRAPPED_INSTANTIATE_TEST_CASE_P(MAYBE_VerifyEndEntity, - CertVerifyProcWeakDigestTest, - testing::ValuesIn(kVerifyEndEntityTestData)); -// Incomplete chains should still report the status of the intermediate. +INSTANTIATE_TEST_CASE_P(VerifyEndEntity, + CertVerifyProcWeakDigestTest, + testing::ValuesIn(kVerifyEndEntityTestData)); + +// Incomplete chains do not report the status of the intermediate. +// Note: really each of these tests should also expect the digest algorithm of +// the intermediate (included as a comment). However CertVerifyProc::Verify() is +// unable to distinguish that this is an intermediate and not a trust anchor, so +// this intermediate is treated like a trust anchor. const WeakDigestTestData kVerifyIncompleteIntermediateTestData[] = { {NULL, "weak_digest_md5_intermediate.pem", "weak_digest_sha1_ee.pem", - EXPECT_MD5 | EXPECT_SHA1 | EXPECT_SHA1_LEAF}, -#if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) - // MD4 is not supported by OS X / NSS + /*EXPECT_MD5 |*/ EXPECT_SHA1 | EXPECT_SHA1_LEAF}, {NULL, "weak_digest_md4_intermediate.pem", "weak_digest_sha1_ee.pem", - EXPECT_MD4 | EXPECT_SHA1 | EXPECT_SHA1_LEAF}, -#endif + /*EXPECT_MD4 |*/ EXPECT_SHA1 | EXPECT_SHA1_LEAF}, {NULL, "weak_digest_md2_intermediate.pem", "weak_digest_sha1_ee.pem", - EXPECT_MD2 | EXPECT_SHA1 | EXPECT_SHA1_LEAF}, + /*EXPECT_MD2 |*/ EXPECT_SHA1 | EXPECT_SHA1_LEAF}, }; -// Disabled on NSS - libpkix does not return constructed chains on error, -// preventing us from detecting/inspecting the verified chain. -#if defined(USE_NSS_CERTS) || defined(OS_IOS) || defined(OS_ANDROID) -#define MAYBE_VerifyIncompleteIntermediate \ - DISABLED_VerifyIncompleteIntermediate -#else -#define MAYBE_VerifyIncompleteIntermediate VerifyIncompleteIntermediate -#endif -WRAPPED_INSTANTIATE_TEST_CASE_P( + +INSTANTIATE_TEST_CASE_P( MAYBE_VerifyIncompleteIntermediate, CertVerifyProcWeakDigestTest, testing::ValuesIn(kVerifyIncompleteIntermediateTestData)); -// Incomplete chains should still report the status of the end-entity. +// Incomplete chains should report the status of the end-entity. +// Note: really each of these tests should also expect EXPECT_SHA1 (included as +// a comment). However CertVerifyProc::Verify() is unable to distinguish that +// this is an intermediate and not a trust anchor, so this intermediate is +// treated like a trust anchor. const WeakDigestTestData kVerifyIncompleteEETestData[] = { - { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md5_ee.pem", - EXPECT_MD5 | EXPECT_SHA1 }, -#if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) - // MD4 is not supported by OS X / NSS - { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md4_ee.pem", - EXPECT_MD4 | EXPECT_SHA1 }, -#endif - { NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md2_ee.pem", - EXPECT_MD2 | EXPECT_SHA1 }, + {NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md5_ee.pem", + /*EXPECT_SHA1 |*/ EXPECT_MD5}, + {NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md4_ee.pem", + /*EXPECT_SHA1 |*/ EXPECT_MD4}, + {NULL, "weak_digest_sha1_intermediate.pem", "weak_digest_md2_ee.pem", + /*EXPECT_SHA1 |*/ EXPECT_MD2}, }; -// Disabled on NSS - libpkix does not return constructed chains on error, -// preventing us from detecting/inspecting the verified chain. -#if defined(USE_NSS_CERTS) || defined(OS_IOS) || defined(OS_ANDROID) -#define MAYBE_VerifyIncompleteEndEntity DISABLED_VerifyIncompleteEndEntity -#else -#define MAYBE_VerifyIncompleteEndEntity VerifyIncompleteEndEntity -#endif -WRAPPED_INSTANTIATE_TEST_CASE_P( - MAYBE_VerifyIncompleteEndEntity, - CertVerifyProcWeakDigestTest, - testing::ValuesIn(kVerifyIncompleteEETestData)); + +INSTANTIATE_TEST_CASE_P(VerifyIncompleteEndEntity, + CertVerifyProcWeakDigestTest, + testing::ValuesIn(kVerifyIncompleteEETestData)); // Differing algorithms between the intermediate and the EE should still be // reported. @@ -1860,23 +1841,26 @@ const WeakDigestTestData kVerifyMixedTestData[] = { "weak_digest_md2_ee.pem", EXPECT_MD2 | EXPECT_MD5 }, { "weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem", "weak_digest_md5_ee.pem", EXPECT_MD2 | EXPECT_MD5 }, -#if defined(USE_OPENSSL_CERTS) || defined(OS_WIN) - // MD4 is not supported by OS X / NSS { "weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem", "weak_digest_md2_ee.pem", EXPECT_MD2 | EXPECT_MD4 }, -#endif }; -// NSS does not support MD4 and does not enable MD2 by default, making all -// permutations invalid. -#if defined(USE_NSS_CERTS) || defined(OS_IOS) || defined(OS_ANDROID) -#define MAYBE_VerifyMixed DISABLED_VerifyMixed -#else -#define MAYBE_VerifyMixed VerifyMixed -#endif -WRAPPED_INSTANTIATE_TEST_CASE_P( - MAYBE_VerifyMixed, - CertVerifyProcWeakDigestTest, - testing::ValuesIn(kVerifyMixedTestData)); + +INSTANTIATE_TEST_CASE_P(VerifyMixed, + CertVerifyProcWeakDigestTest, + testing::ValuesIn(kVerifyMixedTestData)); + +// The EE is a trusted certificate. Even though it uses weak hashes, these +// should not be reported. +const WeakDigestTestData kVerifyTrustedEETestData[] = { + {NULL, NULL, "weak_digest_md5_ee.pem", 0}, + {NULL, NULL, "weak_digest_md4_ee.pem", 0}, + {NULL, NULL, "weak_digest_md2_ee.pem", 0}, + {NULL, NULL, "weak_digest_sha1_ee.pem", 0}, +}; + +INSTANTIATE_TEST_CASE_P(VerifyTrustedEE, + CertVerifyProcWeakDigestTest, + testing::ValuesIn(kVerifyTrustedEETestData)); // For the list of valid hostnames, see // net/cert/data/ssl/certificates/subjectAltName_sanity_check.pem @@ -1938,15 +1922,17 @@ TEST_P(CertVerifyProcNameTest, VerifyCertName) { } } -WRAPPED_INSTANTIATE_TEST_CASE_P( - VerifyName, - CertVerifyProcNameTest, - testing::ValuesIn(kVerifyNameData)); +INSTANTIATE_TEST_CASE_P(VerifyName, + CertVerifyProcNameTest, + testing::ValuesIn(kVerifyNameData)); #if defined(OS_MACOSX) && !defined(OS_IOS) // Test that CertVerifyProcMac reacts appropriately when Apple's certificate // verifier rejects a certificate with a fatal error. This is a regression // test for https://crbug.com/472291. +// (Since 10.12, this causes a recoverable error instead of a fatal one.) +// TODO(mattm): Try to find a different way to cause a fatal error that works +// on 10.12. TEST_F(CertVerifyProcTest, LargeKey) { // Load root_ca_cert.pem into the test root store. ScopedTestRoot test_root( @@ -1963,7 +1949,7 @@ TEST_F(CertVerifyProcTest, LargeKey) { int error = Verify(cert.get(), "127.0.0.1", flags, NULL, empty_cert_list_, &verify_result); EXPECT_THAT(error, IsError(ERR_CERT_INVALID)); - EXPECT_EQ(CERT_STATUS_INVALID, verify_result.cert_status); + EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID); } #endif // defined(OS_MACOSX) && !defined(OS_IOS) diff --git a/chromium/net/cert/cert_verify_proc_whitelist.cc b/chromium/net/cert/cert_verify_proc_whitelist.cc index 5c53a77a36c..2ba4166d4d8 100644 --- a/chromium/net/cert/cert_verify_proc_whitelist.cc +++ b/chromium/net/cert/cert_verify_proc_whitelist.cc @@ -6,6 +6,7 @@ #include <cstdlib> +#include "net/base/lookup_string_in_fixed_set.h" #include "net/cert/x509_certificate.h" namespace net { @@ -46,1604 +47,7 @@ const uint8_t kWosignKeys[][crypto::kSHA256Length] = { 0x21, 0x9f, 0xe0, 0xe9, 0xe3, 0xa3, 0x82, 0xa1, 0xb3, 0xcb, 0x66, 0xc9, 0x39, 0x55, 0xde, 0x75 }, }; - -// SHA-256 hashes of the leaf certificates whitelisted as issued by CNNIC's -// DV root. -const uint8_t kCNNICDVWhitelist[][crypto::kSHA256Length] = { - { 0x00, 0xc5, 0x9f, 0x5e, 0xf3, 0xb4, 0x6d, 0xbc, - 0xa0, 0xa8, 0xbb, 0xa5, 0x0a, 0x72, 0xd4, 0xe1, - 0x83, 0x9a, 0x94, 0xfb, 0x1a, 0x58, 0x5a, 0xd7, - 0x2a, 0x7a, 0xac, 0x3c, 0x72, 0x56, 0x1f, 0xc0 }, - { 0x02, 0x01, 0x4e, 0x80, 0xf5, 0xc4, 0xf3, 0x8b, - 0xa9, 0xd9, 0x04, 0x79, 0x1a, 0x63, 0xf6, 0x4d, - 0x05, 0xf9, 0xe2, 0x03, 0xa1, 0xf1, 0x2b, 0x06, - 0xd6, 0x55, 0x94, 0x01, 0x41, 0x0e, 0x73, 0x36 }, - { 0x02, 0x35, 0x38, 0xe2, 0x48, 0x15, 0x28, 0x75, - 0x29, 0x2f, 0x2c, 0x83, 0x9a, 0xb3, 0x2b, 0xc7, - 0x35, 0x1e, 0x2b, 0x29, 0x99, 0x1d, 0x66, 0xae, - 0xa6, 0x16, 0xcb, 0x0b, 0x26, 0xa5, 0xe3, 0x75 }, - { 0x02, 0xec, 0x35, 0xf5, 0x83, 0x4c, 0xd2, 0xc3, - 0x43, 0x33, 0x39, 0x9a, 0xea, 0x6b, 0xda, 0x84, - 0x68, 0xab, 0x8d, 0x74, 0xef, 0x6c, 0xa5, 0x2d, - 0x33, 0x7a, 0x30, 0x69, 0x4c, 0x3f, 0x95, 0xa4 }, - { 0x03, 0xe0, 0x6e, 0x0b, 0x7a, 0x2c, 0xba, 0xe4, - 0xb6, 0x8b, 0xce, 0x5f, 0x83, 0xe7, 0xa9, 0x31, - 0x6e, 0xd7, 0x82, 0x3e, 0x8d, 0x94, 0x85, 0x38, - 0xf1, 0x94, 0x3f, 0xa4, 0x27, 0xd7, 0x91, 0x0e }, - { 0x04, 0x0f, 0x53, 0x7a, 0x51, 0x95, 0x95, 0xcc, - 0xff, 0xde, 0x35, 0xe0, 0xd1, 0x28, 0xb7, 0x99, - 0x92, 0x2b, 0xa9, 0x37, 0xa2, 0xe8, 0x65, 0x84, - 0x36, 0x62, 0xf1, 0xf4, 0x50, 0x02, 0xb8, 0x2d }, - { 0x07, 0x19, 0x4f, 0x47, 0xf4, 0xce, 0xd0, 0x96, - 0xd1, 0x06, 0x8d, 0x34, 0x49, 0x3b, 0x67, 0x37, - 0x14, 0x45, 0x16, 0x93, 0xa6, 0xa2, 0x71, 0x2f, - 0x70, 0x8f, 0x59, 0x36, 0x12, 0x11, 0xc6, 0x21 }, - { 0x07, 0x8f, 0xee, 0x58, 0x8a, 0x2c, 0x55, 0xc8, - 0xe2, 0xc1, 0x78, 0x71, 0xaa, 0xb6, 0xe4, 0x00, - 0xb3, 0xfd, 0xbc, 0xdc, 0xf3, 0x91, 0x46, 0xa0, - 0x89, 0x37, 0xf9, 0xac, 0x06, 0xa1, 0xb8, 0xbd }, - { 0x08, 0x21, 0x0a, 0xc3, 0xa2, 0x95, 0x56, 0xf6, - 0x8d, 0x33, 0xb4, 0x40, 0x87, 0x9c, 0x54, 0x63, - 0x64, 0x04, 0xe9, 0x7c, 0x4d, 0x9f, 0x97, 0x82, - 0x23, 0xd2, 0x42, 0xab, 0xe5, 0x38, 0x5e, 0x4e }, - { 0x08, 0xc2, 0xd3, 0x17, 0xa8, 0x4a, 0x3c, 0xbe, - 0x38, 0xde, 0x64, 0xa2, 0x4d, 0xd4, 0x27, 0x91, - 0x09, 0xe2, 0xbc, 0x02, 0x2b, 0x93, 0xb1, 0x05, - 0xa8, 0x94, 0xa5, 0x1a, 0xdc, 0x3e, 0xe5, 0xcc }, - { 0x09, 0x9f, 0x3e, 0x71, 0xb5, 0x00, 0xd1, 0x5b, - 0x03, 0x7b, 0x93, 0xaa, 0x5f, 0xb4, 0x16, 0x19, - 0x0a, 0xd1, 0xdf, 0x86, 0x73, 0xab, 0x31, 0xa8, - 0xf6, 0xd9, 0x7f, 0x59, 0x5e, 0x8e, 0x16, 0xe9 }, - { 0x09, 0xeb, 0xdd, 0x1b, 0x7f, 0xfa, 0x4e, 0xd7, - 0x4b, 0xeb, 0xae, 0x96, 0xba, 0x10, 0x65, 0xdc, - 0x7d, 0xa1, 0xc5, 0xd3, 0x18, 0x3c, 0xc5, 0x94, - 0x19, 0xe9, 0x78, 0x36, 0xaf, 0x7f, 0x6d, 0x70 }, - { 0x0a, 0x01, 0x88, 0x81, 0x2c, 0x9d, 0xe8, 0x8a, - 0x2f, 0x0a, 0x5c, 0x4c, 0x57, 0xe6, 0xf9, 0xa8, - 0x15, 0x69, 0xe9, 0xc7, 0x09, 0xc0, 0x95, 0x40, - 0x80, 0xe5, 0xe4, 0xe6, 0x62, 0x85, 0x6d, 0xf8 }, - { 0x0a, 0x42, 0x19, 0x7e, 0x48, 0x70, 0xb2, 0x34, - 0x20, 0xf5, 0x51, 0x9f, 0xb8, 0x39, 0xb6, 0xcc, - 0x83, 0x03, 0x52, 0x9a, 0xa9, 0x06, 0x9a, 0xd1, - 0xa0, 0x90, 0x86, 0xcf, 0x6c, 0xba, 0x07, 0xc2 }, - { 0x0b, 0x03, 0xe1, 0x27, 0xc2, 0xe3, 0x3e, 0xad, - 0xbc, 0xb0, 0x99, 0x80, 0x46, 0xcc, 0x9b, 0xa7, - 0x33, 0x46, 0x3e, 0x0c, 0xa6, 0x43, 0x52, 0x27, - 0x81, 0xb0, 0x3d, 0x81, 0x53, 0x97, 0xeb, 0x4f }, - { 0x0b, 0x1e, 0x1e, 0x73, 0x43, 0xa0, 0xe9, 0x1c, - 0x2a, 0x27, 0xdd, 0x2a, 0x4d, 0x7e, 0x6b, 0xf1, - 0xe8, 0x04, 0x4b, 0x58, 0xce, 0x1a, 0xe8, 0x1e, - 0x27, 0xd8, 0x14, 0xfd, 0x2d, 0xc0, 0x18, 0x93 }, - { 0x0b, 0x48, 0xd5, 0x5c, 0xac, 0x84, 0xfd, 0xee, - 0x15, 0xd8, 0x1a, 0xff, 0x99, 0x07, 0xbb, 0x9a, - 0x57, 0x11, 0xa9, 0x5c, 0xe2, 0x3a, 0x8d, 0x4d, - 0x5e, 0x88, 0x62, 0xbf, 0x15, 0xa7, 0x6a, 0x75 }, - { 0x0b, 0xfe, 0xa1, 0x38, 0x31, 0x67, 0x3e, 0xc9, - 0x69, 0xd0, 0x5f, 0xd8, 0x67, 0xb6, 0x69, 0xf2, - 0x71, 0x24, 0xaf, 0xeb, 0x7c, 0x60, 0x8c, 0xfe, - 0x54, 0xcf, 0x46, 0x33, 0x06, 0xcc, 0x99, 0x2e }, - { 0x0c, 0xb9, 0x31, 0x93, 0xf1, 0x65, 0x26, 0xe1, - 0xd1, 0x65, 0x52, 0x11, 0x7b, 0xa2, 0x1a, 0xac, - 0xb9, 0xf1, 0xd7, 0xa8, 0x93, 0x56, 0xa3, 0x5d, - 0xe4, 0xf6, 0x65, 0xe9, 0x39, 0x90, 0x79, 0x38 }, - { 0x0d, 0x16, 0x1b, 0xb9, 0xca, 0x0d, 0x20, 0xe4, - 0x67, 0x35, 0x89, 0x67, 0x22, 0x78, 0xb0, 0xa3, - 0xc5, 0xe2, 0x69, 0x30, 0xa4, 0xdc, 0x3a, 0x82, - 0x16, 0x85, 0x43, 0x24, 0x27, 0xc7, 0x31, 0x5a }, - { 0x0d, 0x71, 0xc8, 0xca, 0x16, 0x56, 0x59, 0xef, - 0xaf, 0x69, 0x65, 0x29, 0x28, 0x9a, 0xae, 0x25, - 0xd9, 0xc4, 0x2a, 0x1b, 0xbb, 0x03, 0x5a, 0x2b, - 0x8c, 0x61, 0x14, 0x7e, 0x1b, 0x8b, 0x90, 0x52 }, - { 0x0e, 0xfd, 0x68, 0x73, 0xd6, 0x0e, 0x77, 0x96, - 0x2d, 0xf6, 0x00, 0x16, 0xdc, 0x3b, 0xaf, 0x9c, - 0xa7, 0x1e, 0x7d, 0x86, 0x19, 0xe7, 0xeb, 0xaa, - 0x3a, 0xf2, 0xdc, 0xb5, 0xba, 0x24, 0xde, 0xc2 }, - { 0x0e, 0xff, 0x3c, 0xff, 0xda, 0x4a, 0x3e, 0x87, - 0x23, 0x4a, 0x86, 0xc7, 0x0d, 0x49, 0x8c, 0x62, - 0x60, 0x7f, 0x37, 0x44, 0xea, 0x71, 0xf1, 0x83, - 0x1d, 0xcf, 0xca, 0xf3, 0xaf, 0x15, 0x56, 0x9c }, - { 0x10, 0x83, 0x6d, 0xa0, 0xcd, 0x6a, 0xc0, 0x95, - 0xdd, 0x7a, 0xc3, 0x4d, 0x99, 0x01, 0x90, 0x9a, - 0x8e, 0xf8, 0x4d, 0x6e, 0xe0, 0x5b, 0x83, 0x43, - 0x03, 0xd4, 0x7f, 0xc0, 0xa5, 0xf9, 0x14, 0xfa }, - { 0x11, 0xa4, 0x02, 0x7b, 0x45, 0xfc, 0x9a, 0x6f, - 0x40, 0x21, 0x25, 0xc3, 0xca, 0x22, 0x68, 0xe0, - 0x15, 0xa3, 0x1b, 0xa4, 0xfd, 0xb0, 0x05, 0x9d, - 0x66, 0x6b, 0x73, 0xc8, 0x51, 0xd5, 0x35, 0x92 }, - { 0x12, 0x6b, 0x1b, 0xa6, 0x38, 0xc7, 0xe6, 0x99, - 0xbc, 0xbc, 0x54, 0xf5, 0x79, 0xac, 0xd3, 0x9f, - 0xe6, 0x1d, 0x08, 0x22, 0x5f, 0xe5, 0xb1, 0xf9, - 0x01, 0x88, 0xb2, 0x3f, 0xd8, 0x43, 0x3e, 0x8e }, - { 0x13, 0x5d, 0x3e, 0xda, 0x6e, 0x55, 0x9b, 0xf5, - 0xee, 0x23, 0x0a, 0xa5, 0xba, 0x59, 0xbb, 0x6a, - 0x2a, 0x0f, 0x07, 0x82, 0x2f, 0xed, 0x38, 0x44, - 0x7e, 0x6a, 0xbc, 0x5c, 0x23, 0xaa, 0xd0, 0x27 }, - { 0x13, 0x6a, 0x40, 0x09, 0x81, 0xb1, 0xa3, 0xe0, - 0x5f, 0xdc, 0xac, 0x20, 0xa2, 0x36, 0xf8, 0x6e, - 0x94, 0xe5, 0xee, 0x58, 0x59, 0xd8, 0xfd, 0x45, - 0xe9, 0xe9, 0xc5, 0xa6, 0xc5, 0xc0, 0xa4, 0x13 }, - { 0x14, 0x21, 0x28, 0xa6, 0x65, 0x1c, 0xdc, 0x18, - 0x70, 0xc2, 0x67, 0x5e, 0xc0, 0xb0, 0xef, 0x32, - 0xb5, 0xd4, 0xc1, 0x55, 0x35, 0x8e, 0x7e, 0xd9, - 0x5a, 0x98, 0xe8, 0x3b, 0x1a, 0xd8, 0xbe, 0x4d }, - { 0x14, 0x47, 0x25, 0xa6, 0x79, 0x1c, 0x60, 0x0c, - 0x4c, 0x2c, 0xf3, 0x94, 0x3f, 0x3e, 0xcf, 0x40, - 0xd6, 0x31, 0xd7, 0x60, 0xe4, 0x51, 0xef, 0x28, - 0x29, 0xaf, 0xfb, 0xee, 0x74, 0x80, 0xad, 0x17 }, - { 0x15, 0x27, 0x2a, 0xbc, 0x1f, 0x0c, 0x4d, 0x1d, - 0x1a, 0x92, 0x08, 0x73, 0x55, 0xa1, 0xe0, 0x42, - 0x6c, 0x2b, 0xb5, 0xb4, 0x37, 0x30, 0x00, 0xb8, - 0x2c, 0x2c, 0xca, 0xb7, 0xfa, 0xd6, 0xfa, 0x20 }, - { 0x15, 0x48, 0x1f, 0xde, 0x4e, 0x3f, 0x72, 0x49, - 0x66, 0x87, 0xdf, 0x57, 0x5f, 0xb5, 0xb1, 0x27, - 0xbd, 0x6d, 0xeb, 0x66, 0x1d, 0xd9, 0x07, 0x71, - 0x8b, 0xa0, 0x65, 0xc7, 0xda, 0x66, 0x76, 0xd1 }, - { 0x15, 0x5a, 0x88, 0x39, 0x60, 0x8b, 0x77, 0x25, - 0x34, 0x6a, 0x72, 0x40, 0xe4, 0xe2, 0x50, 0x3a, - 0xcc, 0x7b, 0x8b, 0xef, 0x0b, 0x1b, 0xe6, 0x15, - 0xb9, 0x02, 0x4a, 0x88, 0xe6, 0x52, 0x11, 0xf9 }, - { 0x15, 0x5d, 0x88, 0x6e, 0x99, 0x1d, 0x40, 0x0a, - 0xbf, 0x2f, 0x83, 0xc2, 0x80, 0xd1, 0x24, 0x6d, - 0xce, 0x02, 0xa6, 0x28, 0x31, 0x26, 0xc6, 0x17, - 0xe4, 0x17, 0xd2, 0xb7, 0xea, 0xc1, 0x19, 0x24 }, - { 0x17, 0x3d, 0xe2, 0x60, 0xe2, 0x2d, 0x76, 0x9d, - 0x2d, 0x54, 0x99, 0xc8, 0x22, 0x0d, 0x86, 0xed, - 0xe3, 0x48, 0xda, 0x1e, 0x57, 0xc1, 0xe7, 0xc8, - 0x15, 0x07, 0xfb, 0x3e, 0x6b, 0xd7, 0x3b, 0x7f }, - { 0x18, 0x1e, 0xbb, 0x29, 0x8d, 0x20, 0x68, 0x5c, - 0x48, 0xf7, 0x53, 0x89, 0x80, 0xc5, 0x63, 0xc8, - 0xf7, 0x48, 0x95, 0x4c, 0xf2, 0x64, 0x41, 0x9a, - 0x72, 0xfc, 0xc6, 0x34, 0x0a, 0x10, 0x23, 0x80 }, - { 0x19, 0xff, 0xe6, 0xc6, 0x7a, 0x35, 0x86, 0xfc, - 0x48, 0x6c, 0xe2, 0x07, 0xfa, 0x2a, 0xf6, 0x62, - 0xf5, 0x50, 0xfc, 0x51, 0x2f, 0xdd, 0x78, 0x17, - 0xe3, 0x86, 0xc9, 0x4a, 0x7b, 0xde, 0x37, 0xa9 }, - { 0x1a, 0x9e, 0xc6, 0x8c, 0xed, 0xb6, 0xbd, 0x94, - 0x0c, 0x95, 0x34, 0xe6, 0x84, 0xbb, 0x04, 0x9f, - 0xf1, 0xe2, 0x3b, 0x66, 0xa1, 0x33, 0x01, 0x2f, - 0xc3, 0x99, 0xeb, 0x4f, 0xb5, 0xd3, 0xaa, 0x35 }, - { 0x1b, 0x7b, 0xf8, 0xd9, 0xe8, 0x29, 0x3c, 0x53, - 0xdd, 0x59, 0xec, 0x97, 0xfe, 0x16, 0xf0, 0xea, - 0xb4, 0x68, 0x5b, 0x95, 0xce, 0x14, 0xd2, 0x62, - 0x3e, 0x70, 0x94, 0x2c, 0xff, 0x25, 0xe7, 0x30 }, - { 0x1b, 0xd7, 0xb3, 0x62, 0xbc, 0x14, 0x66, 0xfa, - 0xc0, 0x5e, 0xc5, 0x9e, 0x12, 0xe8, 0x1b, 0xe7, - 0x35, 0x38, 0xc4, 0x97, 0x28, 0xf5, 0xad, 0xba, - 0x2d, 0x81, 0xfc, 0xdb, 0xc4, 0x65, 0x7c, 0x1b }, - { 0x1b, 0xec, 0xfe, 0x78, 0xce, 0x5e, 0x77, 0xa9, - 0x77, 0xbb, 0x5f, 0xe3, 0x49, 0x91, 0x06, 0xc6, - 0x4c, 0xf2, 0xb0, 0x76, 0x16, 0x59, 0x49, 0x04, - 0x11, 0x17, 0xcd, 0x8a, 0xbc, 0xd9, 0x05, 0xd4 }, - { 0x1b, 0xf4, 0x8a, 0x83, 0x3c, 0xe4, 0x05, 0x64, - 0x8c, 0xc0, 0xbd, 0xd3, 0xb5, 0xb8, 0xc1, 0x8e, - 0xb5, 0x13, 0x15, 0x34, 0x29, 0x3a, 0xb2, 0x63, - 0x44, 0xb5, 0x00, 0x76, 0x48, 0x11, 0x41, 0xed }, - { 0x1c, 0x04, 0x82, 0x0f, 0x7b, 0x4a, 0x2f, 0x1e, - 0x38, 0x5d, 0xe1, 0xde, 0x16, 0xb2, 0x22, 0x6e, - 0x88, 0x3d, 0x9c, 0x34, 0x66, 0x3e, 0x1b, 0x64, - 0xe8, 0x5b, 0x98, 0x0e, 0xaf, 0xf0, 0xb9, 0xd3 }, - { 0x1d, 0x9e, 0xc0, 0x06, 0xa5, 0x26, 0xfa, 0xb5, - 0xce, 0x2e, 0x71, 0xfd, 0xfc, 0x07, 0xc0, 0x11, - 0xf7, 0x65, 0x7b, 0xf8, 0x5f, 0x5d, 0x03, 0x52, - 0xb8, 0xcb, 0x21, 0x8d, 0x4f, 0xcb, 0xc4, 0x43 }, - { 0x1e, 0x78, 0xf8, 0x08, 0x84, 0xe3, 0x2a, 0x2e, - 0xa5, 0xad, 0x1e, 0xe8, 0x35, 0x88, 0xac, 0xdb, - 0x18, 0x4a, 0x4a, 0x6e, 0x87, 0x56, 0x5b, 0xf5, - 0x03, 0xb5, 0x69, 0x7a, 0xbf, 0xae, 0x64, 0xa4 }, - { 0x1f, 0x11, 0x85, 0xa5, 0x21, 0xe2, 0x8e, 0x95, - 0x17, 0x1c, 0xf3, 0x86, 0x07, 0x8a, 0x76, 0x4a, - 0x9a, 0x3e, 0x71, 0xc2, 0x59, 0xbc, 0xdc, 0x5f, - 0x8e, 0x66, 0xe1, 0xb5, 0x20, 0x55, 0xa2, 0x6d }, - { 0x1f, 0x23, 0xd7, 0xa6, 0x38, 0x17, 0x1f, 0x6d, - 0x09, 0x99, 0x64, 0xe0, 0xfa, 0x01, 0x72, 0x1c, - 0x06, 0xcc, 0xeb, 0x8e, 0xa2, 0x98, 0xbf, 0xd0, - 0x04, 0x8e, 0x13, 0x8d, 0x98, 0xfc, 0x36, 0x24 }, - { 0x1f, 0xc7, 0xf8, 0x10, 0x4e, 0x27, 0xff, 0x2a, - 0x45, 0x56, 0xf9, 0x1e, 0x05, 0x42, 0x17, 0xc5, - 0x8f, 0x69, 0x3f, 0x70, 0x36, 0x25, 0x9e, 0x39, - 0x80, 0xb5, 0x59, 0x5b, 0x04, 0x3d, 0x11, 0x92 }, - { 0x20, 0x0b, 0x49, 0xbd, 0xd6, 0x35, 0x02, 0x57, - 0xcc, 0xd4, 0xe6, 0xad, 0xe1, 0xcb, 0x75, 0x13, - 0x8d, 0xd6, 0xd9, 0x06, 0xfe, 0xf3, 0x49, 0xc0, - 0xc9, 0x86, 0xa5, 0x1b, 0x29, 0xb9, 0xe5, 0x2d }, - { 0x21, 0x78, 0xe8, 0x28, 0x3a, 0x73, 0x39, 0x6e, - 0x08, 0xc0, 0xa1, 0x1a, 0x88, 0x72, 0xfa, 0x4a, - 0x9f, 0xcc, 0x05, 0x67, 0x0c, 0xee, 0xff, 0xb8, - 0x95, 0x83, 0x8e, 0xb6, 0x59, 0xde, 0x38, 0xdb }, - { 0x22, 0x01, 0x71, 0xf7, 0x0e, 0x1f, 0xc3, 0xc4, - 0xf7, 0x8d, 0xa6, 0xc8, 0xb1, 0xd7, 0x2c, 0x3b, - 0xa8, 0x31, 0x9a, 0x46, 0xf8, 0x19, 0x2d, 0x1e, - 0x19, 0xb9, 0xe2, 0x9a, 0xba, 0x18, 0xee, 0x87 }, - { 0x23, 0x19, 0xcb, 0x3d, 0x58, 0xc6, 0xd5, 0x53, - 0x62, 0x5d, 0xe5, 0xf4, 0x25, 0x2b, 0xf0, 0x29, - 0xab, 0x83, 0x05, 0xeb, 0xf2, 0x2f, 0xa2, 0x3e, - 0x99, 0x73, 0x04, 0x66, 0xde, 0x24, 0xd6, 0xc3 }, - { 0x23, 0x8a, 0x80, 0xcc, 0x9b, 0x58, 0x9a, 0xdc, - 0x89, 0xb7, 0xa8, 0xf3, 0x4d, 0xdf, 0x12, 0x48, - 0x73, 0x4b, 0x9f, 0x7f, 0x78, 0x20, 0xb6, 0x04, - 0x07, 0x66, 0xc5, 0x41, 0x3a, 0xd2, 0xbd, 0xef }, - { 0x23, 0x9c, 0x79, 0x5f, 0x0c, 0x55, 0xa5, 0x53, - 0x16, 0x2a, 0x9c, 0xa0, 0x6e, 0x88, 0x01, 0xe1, - 0x19, 0xbd, 0xff, 0x54, 0x35, 0x4a, 0x3f, 0x68, - 0x43, 0xcf, 0x2a, 0x2f, 0xa6, 0x01, 0x75, 0x8e }, - { 0x24, 0x62, 0x52, 0x48, 0x32, 0xc1, 0x54, 0xd8, - 0x4d, 0xf5, 0x8e, 0xd7, 0x75, 0x22, 0x3b, 0xbe, - 0x25, 0x7d, 0xea, 0xf7, 0x0e, 0xf9, 0xd2, 0x08, - 0x61, 0x4e, 0xc0, 0xf5, 0x97, 0x7f, 0x6d, 0x58 }, - { 0x24, 0x6d, 0x0c, 0x31, 0x48, 0x72, 0x75, 0x59, - 0xf9, 0x9a, 0xd0, 0xc1, 0x50, 0x37, 0x70, 0x06, - 0xb7, 0xa1, 0x7a, 0x60, 0x3a, 0x47, 0x3b, 0x6a, - 0xac, 0xd2, 0x4e, 0x16, 0xc6, 0xc5, 0x1b, 0x42 }, - { 0x25, 0x1b, 0xb7, 0xc5, 0x42, 0x33, 0xda, 0x44, - 0xbf, 0x53, 0xb5, 0x8a, 0xf2, 0x9a, 0xe1, 0x74, - 0xb9, 0x78, 0xba, 0xdb, 0x89, 0xa9, 0x50, 0xab, - 0x3e, 0x5f, 0x9b, 0x4d, 0x0d, 0xcd, 0xbc, 0x62 }, - { 0x26, 0x03, 0xcb, 0xdf, 0x69, 0x75, 0xe3, 0x68, - 0x83, 0x7f, 0x95, 0x1a, 0x00, 0x49, 0xfd, 0xc3, - 0xc4, 0xb2, 0x39, 0xf0, 0x82, 0xf6, 0xbf, 0x89, - 0x5d, 0xb8, 0xf3, 0x27, 0x05, 0xe6, 0x9c, 0xf3 }, - { 0x27, 0x50, 0x11, 0x93, 0xe4, 0x61, 0xca, 0xce, - 0x55, 0x32, 0xfa, 0xd5, 0xd5, 0xb2, 0x7e, 0x01, - 0x16, 0x57, 0x92, 0xe0, 0x4f, 0x24, 0x21, 0x93, - 0x2f, 0x39, 0x28, 0xaf, 0x9f, 0xcd, 0xa4, 0xf3 }, - { 0x27, 0xa8, 0x41, 0xae, 0xcf, 0xe0, 0xa1, 0x39, - 0x37, 0x51, 0xc2, 0x55, 0xf9, 0x06, 0xdb, 0x9e, - 0x88, 0x6b, 0xba, 0x4d, 0x7c, 0x44, 0xec, 0x63, - 0xce, 0x7d, 0xc6, 0xde, 0xc1, 0x8b, 0xb9, 0x20 }, - { 0x28, 0x07, 0x10, 0x60, 0x44, 0x03, 0x45, 0xd0, - 0x0e, 0x80, 0xb9, 0xd7, 0xcb, 0xe1, 0x87, 0xc1, - 0xd8, 0xb0, 0xf2, 0xef, 0x5d, 0x0a, 0xac, 0x9c, - 0xce, 0xef, 0x9a, 0x8c, 0x5a, 0x06, 0xf3, 0x02 }, - { 0x28, 0xd9, 0x51, 0x84, 0xb5, 0xea, 0x14, 0x0f, - 0x47, 0x4f, 0x3a, 0xf6, 0xce, 0x70, 0x52, 0xe8, - 0x59, 0x3c, 0xf3, 0xa5, 0x01, 0x0f, 0x52, 0x24, - 0x1a, 0x1e, 0x36, 0x64, 0x60, 0xe5, 0x91, 0x9e }, - { 0x29, 0x01, 0x93, 0xe3, 0x7a, 0x38, 0x87, 0xfd, - 0x36, 0x15, 0xdf, 0x12, 0x2e, 0x95, 0x21, 0x17, - 0x42, 0x15, 0xee, 0x68, 0xf7, 0x44, 0xb2, 0xfa, - 0x35, 0xd2, 0x9c, 0x5d, 0xf1, 0x08, 0xf5, 0x5b }, - { 0x2a, 0x0f, 0x70, 0x67, 0x6e, 0x18, 0x4d, 0x49, - 0x39, 0xa4, 0x04, 0xde, 0x35, 0xac, 0x84, 0xab, - 0x81, 0xaf, 0xec, 0x36, 0x17, 0xe7, 0xe1, 0xbf, - 0x34, 0x67, 0xd4, 0x19, 0x25, 0x5d, 0xd8, 0x17 }, - { 0x2a, 0xa6, 0x47, 0x8c, 0xc7, 0x5d, 0x67, 0xa8, - 0xca, 0x55, 0xb2, 0xe1, 0x63, 0xfd, 0xbb, 0xbc, - 0x9d, 0x74, 0xb4, 0xe5, 0xf3, 0x7b, 0x7d, 0xbd, - 0x13, 0xc9, 0x4e, 0x85, 0x8d, 0x40, 0xda, 0xd0 }, - { 0x2c, 0x82, 0x47, 0x4f, 0x0e, 0xf6, 0xcb, 0x65, - 0x0a, 0x13, 0xef, 0x20, 0x99, 0x6e, 0x65, 0x7b, - 0x67, 0x24, 0xf0, 0xa0, 0xd5, 0xee, 0x24, 0x6d, - 0x26, 0xbb, 0xfa, 0x0a, 0xbb, 0x2c, 0x22, 0xe1 }, - { 0x2c, 0x9b, 0xe1, 0x2d, 0xa4, 0x99, 0xea, 0xbb, - 0x2f, 0xfd, 0xf9, 0x91, 0x6f, 0x2b, 0x27, 0x18, - 0x81, 0x19, 0x5b, 0x74, 0x19, 0xbd, 0x1e, 0xef, - 0x8d, 0x50, 0x77, 0x2a, 0xb9, 0x46, 0x4a, 0xa8 }, - { 0x2c, 0xbd, 0xd5, 0x6c, 0xe4, 0xb4, 0x06, 0x09, - 0xe9, 0xaa, 0x52, 0x1e, 0xaa, 0x76, 0xac, 0x7e, - 0x55, 0x73, 0x7b, 0xf4, 0x3e, 0x2b, 0x0c, 0x30, - 0xdd, 0xcf, 0x59, 0x87, 0x2e, 0xab, 0xe7, 0x7b }, - { 0x2d, 0xde, 0xe4, 0x5f, 0x72, 0x78, 0x38, 0xde, - 0xad, 0xe6, 0x7e, 0x9c, 0xa7, 0x05, 0xeb, 0xb4, - 0xc2, 0xe9, 0x40, 0xae, 0x1b, 0x9d, 0x62, 0x35, - 0x72, 0x18, 0x04, 0x58, 0x31, 0xe9, 0x8f, 0xde }, - { 0x2e, 0x5d, 0xd2, 0x55, 0x09, 0x6d, 0x64, 0x83, - 0x10, 0x5c, 0xb6, 0x03, 0x6c, 0x59, 0x17, 0x57, - 0xfd, 0x98, 0x49, 0x70, 0x66, 0x05, 0x3f, 0x83, - 0x39, 0xe4, 0xd8, 0xd0, 0xc3, 0x75, 0x49, 0x03 }, - { 0x2e, 0xd2, 0x05, 0x8f, 0x39, 0xea, 0xba, 0x5c, - 0xb3, 0xd7, 0xdf, 0x24, 0xca, 0x74, 0xa7, 0x7d, - 0xdc, 0x12, 0x06, 0x01, 0x52, 0x7b, 0x0f, 0x51, - 0x06, 0x91, 0x05, 0xca, 0x88, 0x37, 0x6e, 0x20 }, - { 0x30, 0x7b, 0x09, 0x34, 0xef, 0x97, 0x85, 0xe7, - 0x08, 0xed, 0x48, 0x1a, 0x99, 0x7a, 0x8a, 0x88, - 0xb7, 0xbf, 0x22, 0xdd, 0x26, 0xaa, 0x17, 0x17, - 0x31, 0xb8, 0xf7, 0xe0, 0xd5, 0x97, 0xb7, 0x08 }, - { 0x30, 0xe0, 0x69, 0x80, 0x9c, 0x79, 0x90, 0xf0, - 0xb5, 0xf2, 0x66, 0xe8, 0x94, 0x59, 0x96, 0x42, - 0xe8, 0x53, 0x50, 0xab, 0x82, 0x81, 0x05, 0x34, - 0xc7, 0xf3, 0xfd, 0x67, 0x0c, 0x1b, 0xeb, 0x18 }, - { 0x31, 0x53, 0x47, 0x52, 0xb6, 0xf5, 0x48, 0x20, - 0x91, 0x5c, 0x39, 0x5b, 0xee, 0x97, 0x5b, 0xc5, - 0x4e, 0x3f, 0x07, 0xc0, 0x8c, 0xd3, 0x4c, 0x5a, - 0x51, 0x15, 0xde, 0xf0, 0x17, 0xdb, 0x2b, 0x54 }, - { 0x31, 0xb8, 0x3e, 0x01, 0x90, 0x98, 0x95, 0xbc, - 0x74, 0x2d, 0x6b, 0xe8, 0x40, 0x0a, 0xde, 0x51, - 0xb2, 0x09, 0x83, 0xf6, 0x83, 0xa2, 0xaa, 0xee, - 0xb2, 0x5f, 0x58, 0xdf, 0x98, 0x1b, 0xde, 0x0d }, - { 0x32, 0xef, 0x13, 0x33, 0x86, 0xbf, 0x0c, 0x63, - 0xcf, 0x29, 0xd6, 0x2b, 0x0d, 0x76, 0x88, 0x9e, - 0x9d, 0x9d, 0x53, 0x2e, 0xe4, 0x90, 0x38, 0x94, - 0x4d, 0xbc, 0x21, 0x49, 0xd8, 0xca, 0xa5, 0xd1 }, - { 0x33, 0xd1, 0x6c, 0xd9, 0xe8, 0x2e, 0xdf, 0xfd, - 0x0b, 0x3a, 0xfb, 0x46, 0xa6, 0x84, 0xc5, 0xa0, - 0xd1, 0x2f, 0x2b, 0x40, 0x58, 0x6d, 0x53, 0x2f, - 0x6a, 0xab, 0x54, 0xce, 0xbc, 0x42, 0x33, 0xd3 }, - { 0x34, 0x06, 0x4f, 0xf9, 0x3b, 0x27, 0x4c, 0xf5, - 0xa7, 0x24, 0xec, 0x19, 0x64, 0x50, 0x4a, 0x71, - 0x0a, 0xb9, 0x7b, 0xa1, 0x10, 0x3c, 0xd9, 0xb9, - 0x8c, 0x81, 0xd0, 0xab, 0xcf, 0x3b, 0x19, 0xbd }, - { 0x34, 0x65, 0xc2, 0xf9, 0xa0, 0xcf, 0x36, 0xe5, - 0xee, 0xf0, 0x27, 0x1c, 0x52, 0x91, 0x2d, 0x58, - 0x6f, 0xb2, 0x0b, 0x94, 0x43, 0xe7, 0xd5, 0x82, - 0xa3, 0xe2, 0x23, 0x93, 0xfa, 0xc8, 0x1b, 0xb4 }, - { 0x34, 0x87, 0x46, 0xbf, 0xd4, 0x98, 0xc3, 0xf5, - 0xc8, 0x68, 0x5e, 0xea, 0xac, 0x57, 0x87, 0x2d, - 0x3b, 0x47, 0xe6, 0x02, 0xf4, 0x97, 0xe9, 0xf0, - 0x28, 0x54, 0x12, 0x32, 0x59, 0xfb, 0xe1, 0x69 }, - { 0x36, 0x45, 0xef, 0x7f, 0x5d, 0x15, 0xa5, 0x46, - 0x7e, 0x85, 0x30, 0x7d, 0xda, 0x15, 0xcb, 0xbb, - 0x55, 0xb7, 0x30, 0xae, 0xf8, 0xef, 0x9c, 0x71, - 0x5d, 0x7d, 0x9f, 0xb4, 0x7f, 0xdf, 0x33, 0xad }, - { 0x36, 0xb4, 0xfe, 0x74, 0x3b, 0x6d, 0xf4, 0x4a, - 0x71, 0x3e, 0x91, 0x4c, 0xab, 0xfb, 0xf2, 0xbe, - 0x60, 0x24, 0x9b, 0x46, 0x43, 0x4d, 0x04, 0x43, - 0x59, 0x12, 0x5a, 0x10, 0x6a, 0x37, 0xeb, 0x1c }, - { 0x36, 0xf5, 0xa9, 0x7d, 0x79, 0x3f, 0x84, 0x97, - 0x44, 0xd6, 0xab, 0x39, 0xb7, 0xa8, 0x18, 0xf8, - 0x17, 0x6e, 0x65, 0x20, 0xdc, 0x86, 0x3d, 0xce, - 0x43, 0xb3, 0x98, 0xc3, 0x0b, 0x5e, 0xdb, 0x09 }, - { 0x38, 0x23, 0x4e, 0x55, 0x9d, 0x30, 0x27, 0xd1, - 0x61, 0xda, 0x8c, 0x98, 0x88, 0x04, 0x9a, 0x4d, - 0x20, 0xac, 0xf2, 0x00, 0x90, 0xad, 0x1a, 0x22, - 0x2b, 0x73, 0x9a, 0xc8, 0x6e, 0xb7, 0x6f, 0x06 }, - { 0x39, 0x02, 0x27, 0xce, 0x88, 0x1c, 0x71, 0x8b, - 0x59, 0xa6, 0xbc, 0x31, 0x90, 0xd5, 0x17, 0xe7, - 0x1e, 0x1e, 0x58, 0x66, 0x93, 0xc8, 0xbf, 0x8a, - 0x30, 0x27, 0x26, 0x20, 0x13, 0xfe, 0x16, 0x63 }, - { 0x39, 0x21, 0x5c, 0xaa, 0x37, 0x1a, 0xbe, 0x57, - 0x6a, 0xb9, 0x3b, 0x18, 0xc2, 0xf3, 0x75, 0x5e, - 0xe2, 0x6f, 0x8c, 0x3a, 0xdb, 0x75, 0x9b, 0x6f, - 0x34, 0x78, 0x9f, 0xb8, 0xec, 0xf0, 0x54, 0x28 }, - { 0x39, 0x7d, 0x00, 0x6e, 0xf8, 0xaf, 0xb2, 0x0f, - 0x43, 0x61, 0xa6, 0xc9, 0x72, 0xf0, 0xc5, 0x7c, - 0xc0, 0x87, 0x74, 0x01, 0x06, 0x12, 0x78, 0x3f, - 0xba, 0xbc, 0xb8, 0xd6, 0xf6, 0x03, 0x9e, 0x2c }, - { 0x3a, 0xcf, 0x85, 0x3c, 0x4e, 0x45, 0x02, 0xbd, - 0x82, 0xd5, 0x85, 0xd5, 0xe0, 0x82, 0xc4, 0xb3, - 0xad, 0x03, 0xcd, 0xb6, 0xb5, 0x05, 0xca, 0x80, - 0x47, 0x19, 0x88, 0xec, 0x4c, 0x58, 0x99, 0x9e }, - { 0x3a, 0xea, 0x2c, 0xef, 0xae, 0x63, 0x44, 0xff, - 0xae, 0x67, 0x49, 0x4c, 0x68, 0x4e, 0x1e, 0xbf, - 0x87, 0x95, 0x40, 0xb5, 0x3d, 0x40, 0xf5, 0x16, - 0x9f, 0x78, 0x89, 0x7f, 0x1b, 0x38, 0xab, 0x66 }, - { 0x3b, 0x47, 0x85, 0x0b, 0xf8, 0x4c, 0x4c, 0xf2, - 0xca, 0x6c, 0x31, 0xb3, 0x78, 0x39, 0xc9, 0x50, - 0x76, 0x63, 0x70, 0xd7, 0xf4, 0xb6, 0x4a, 0xd0, - 0x18, 0x55, 0xca, 0xcf, 0xe3, 0x51, 0x2f, 0xc3 }, - { 0x3b, 0xaa, 0x31, 0x31, 0x70, 0x68, 0xac, 0xe0, - 0x89, 0xae, 0xb4, 0xa8, 0x8d, 0x7e, 0xde, 0xbe, - 0x94, 0xab, 0x4a, 0xce, 0x46, 0xbb, 0xd2, 0x68, - 0x3e, 0x3f, 0xdf, 0xf5, 0x59, 0x30, 0x0f, 0x93 }, - { 0x3c, 0x38, 0x36, 0x2e, 0x16, 0x8b, 0xb4, 0xa7, - 0x59, 0xc4, 0x80, 0x55, 0x1c, 0xb1, 0x65, 0x6f, - 0x6a, 0x96, 0x8b, 0x9b, 0x43, 0xcb, 0xe0, 0xd7, - 0x39, 0x75, 0x4a, 0xb7, 0x8a, 0x28, 0x87, 0x0e }, - { 0x3c, 0x84, 0xa8, 0xb3, 0x4d, 0x0f, 0x95, 0xca, - 0xc6, 0xfa, 0xaa, 0xb6, 0x22, 0xc2, 0x74, 0x46, - 0xb4, 0xc4, 0x72, 0xdf, 0x34, 0x53, 0xd7, 0x54, - 0x64, 0xc0, 0x96, 0x23, 0x86, 0x56, 0xb9, 0xd4 }, - { 0x3d, 0x14, 0x47, 0x2d, 0xce, 0x4a, 0xfd, 0xc2, - 0x27, 0x6c, 0x81, 0x47, 0x97, 0xc7, 0xbc, 0x7a, - 0x6c, 0x14, 0xf7, 0x95, 0x3e, 0x7e, 0x9f, 0xea, - 0x69, 0x51, 0x04, 0x0f, 0x2d, 0xaf, 0xbe, 0x9a }, - { 0x3e, 0x8e, 0x9b, 0xad, 0x8e, 0xd9, 0xb5, 0x72, - 0x38, 0x2e, 0x59, 0x8d, 0x2d, 0x73, 0x67, 0xe1, - 0xfd, 0x6a, 0xf6, 0x95, 0x25, 0x00, 0x9d, 0x67, - 0xb4, 0xe8, 0xaf, 0x80, 0xd9, 0x15, 0x85, 0x49 }, - { 0x3f, 0x27, 0xbd, 0xca, 0x9b, 0x0e, 0x42, 0xf3, - 0xf6, 0xd0, 0x91, 0x2c, 0x92, 0xe2, 0xda, 0x65, - 0xcb, 0x35, 0x8f, 0x0b, 0x8f, 0x80, 0x5b, 0xec, - 0x5d, 0xe9, 0x32, 0x51, 0xd9, 0xc4, 0xb1, 0x99 }, - { 0x3f, 0x2e, 0xa6, 0x4e, 0xfb, 0xd6, 0xbf, 0xc4, - 0x0a, 0xf0, 0xad, 0x46, 0xa4, 0xa2, 0x57, 0x84, - 0x19, 0xd8, 0x68, 0x6e, 0x38, 0x98, 0x8b, 0x91, - 0x47, 0x01, 0x8c, 0x36, 0x29, 0x31, 0xe4, 0xf9 }, - { 0x3f, 0x4f, 0x28, 0x8b, 0xaf, 0x5b, 0xde, 0x86, - 0x72, 0xd6, 0xad, 0xd1, 0x50, 0xe3, 0x23, 0x79, - 0x49, 0x9a, 0x16, 0xc5, 0x81, 0xfb, 0x77, 0x37, - 0xec, 0x49, 0x80, 0xe4, 0xf9, 0xc3, 0x3d, 0x4d }, - { 0x3f, 0x92, 0x54, 0x89, 0x64, 0xcc, 0xde, 0xfb, - 0x29, 0x96, 0x5a, 0x27, 0xc1, 0x6c, 0x2f, 0xed, - 0x28, 0xd9, 0xb9, 0x14, 0x0e, 0x4f, 0xb5, 0x5b, - 0x37, 0x22, 0x4c, 0x67, 0xb2, 0xa0, 0x55, 0x1f }, - { 0x40, 0x58, 0xec, 0x4a, 0x7a, 0x7b, 0xa0, 0xb8, - 0x65, 0xa7, 0x39, 0xa0, 0x0c, 0x85, 0xf3, 0x44, - 0x58, 0x79, 0xd6, 0x5e, 0x1d, 0x42, 0x2e, 0xed, - 0x07, 0x65, 0x5a, 0x8e, 0x3e, 0xc3, 0x18, 0xcf }, - { 0x41, 0x29, 0x6b, 0x9f, 0xaa, 0xd6, 0x41, 0x33, - 0xfc, 0xcb, 0xa6, 0xba, 0x74, 0x54, 0x11, 0xec, - 0xc9, 0x11, 0xfd, 0x8e, 0xd5, 0x41, 0x90, 0x0f, - 0x9e, 0x20, 0x36, 0x08, 0xee, 0xa3, 0x59, 0x2d }, - { 0x41, 0x88, 0x71, 0x80, 0x7e, 0xdc, 0xed, 0xa8, - 0x57, 0xd7, 0xe8, 0x48, 0x31, 0x71, 0x81, 0xe1, - 0xe8, 0x33, 0xf5, 0x4c, 0x89, 0xa6, 0x11, 0xa2, - 0x30, 0xad, 0x99, 0x06, 0x5d, 0x45, 0x86, 0x95 }, - { 0x41, 0xa6, 0x8d, 0xfd, 0x90, 0xda, 0x6d, 0x12, - 0x09, 0x84, 0x85, 0xbf, 0x6f, 0x87, 0x24, 0x5f, - 0x4e, 0xc0, 0x54, 0x71, 0xda, 0x59, 0xd0, 0x81, - 0x06, 0x01, 0x53, 0xa2, 0x22, 0x25, 0x23, 0x7f }, - { 0x42, 0x08, 0x71, 0xd8, 0xac, 0x49, 0x3c, 0xf9, - 0x46, 0x8b, 0xb3, 0x76, 0x97, 0x6d, 0x65, 0x5e, - 0xf0, 0xaf, 0xaa, 0xc2, 0x3d, 0x77, 0x00, 0x92, - 0x20, 0xc3, 0xaf, 0x8b, 0xdd, 0x37, 0x5a, 0x24 }, - { 0x42, 0x5d, 0x4e, 0xbf, 0x1b, 0xde, 0x0b, 0xf8, - 0xd1, 0xdb, 0xd3, 0x3d, 0x8d, 0x16, 0x34, 0xc4, - 0xfa, 0xfe, 0xb6, 0xf8, 0x05, 0xf1, 0xcc, 0xb5, - 0x34, 0xac, 0xb7, 0x2a, 0xed, 0xa2, 0xcd, 0x0a }, - { 0x44, 0x12, 0x63, 0x80, 0xa0, 0x73, 0xfe, 0xa1, - 0xa2, 0x00, 0x4f, 0x71, 0x1d, 0xf2, 0xca, 0x47, - 0xc2, 0xc4, 0xb4, 0xff, 0x64, 0x4e, 0x76, 0xaf, - 0xbe, 0x27, 0x97, 0xc9, 0x63, 0x7c, 0x6a, 0xf9 }, - { 0x44, 0x25, 0xdd, 0xfb, 0xba, 0xfb, 0xe1, 0xaa, - 0xce, 0x25, 0x85, 0x70, 0x48, 0x96, 0x9d, 0xc8, - 0x9d, 0xf5, 0x97, 0x7b, 0xb2, 0xe3, 0x34, 0x7c, - 0x9c, 0xeb, 0x0e, 0x5a, 0x7b, 0x68, 0xc5, 0x31 }, - { 0x45, 0x63, 0xcf, 0x13, 0xc2, 0x49, 0x2c, 0xaa, - 0x92, 0xf5, 0x5b, 0x17, 0x26, 0x3a, 0xdd, 0x72, - 0x04, 0xa8, 0x0f, 0xe6, 0x24, 0x0c, 0x4d, 0x63, - 0xe8, 0x39, 0x59, 0x58, 0xf6, 0x94, 0xcd, 0x33 }, - { 0x45, 0xcb, 0x86, 0xca, 0x97, 0x52, 0x29, 0xb7, - 0xd5, 0xda, 0xfc, 0x05, 0xeb, 0x0c, 0x53, 0x65, - 0x82, 0x3a, 0x91, 0xa9, 0x8b, 0x7d, 0xbe, 0x81, - 0xab, 0x5f, 0x17, 0x8b, 0x2d, 0xa4, 0xad, 0x9e }, - { 0x46, 0x9b, 0xd8, 0x04, 0xe9, 0x98, 0xae, 0x27, - 0x9a, 0xc3, 0xfe, 0x1b, 0x52, 0x88, 0x46, 0xe7, - 0xae, 0xc7, 0x6c, 0x56, 0xb8, 0x0b, 0x40, 0xf3, - 0x24, 0x20, 0x8f, 0x5a, 0x9f, 0x64, 0x5c, 0xb5 }, - { 0x46, 0xcd, 0x08, 0x08, 0x8d, 0x36, 0x06, 0x2c, - 0x56, 0x71, 0x09, 0x2c, 0x02, 0x76, 0x7a, 0x25, - 0x0d, 0xe7, 0x0b, 0xf3, 0xe1, 0x53, 0x63, 0x69, - 0x66, 0xe6, 0x6e, 0xc5, 0x7e, 0x8e, 0xe9, 0xf5 }, - { 0x47, 0x84, 0xf6, 0xcd, 0x59, 0x3d, 0x7b, 0x31, - 0x2e, 0xb1, 0xf6, 0x19, 0xe1, 0x11, 0xdf, 0x3b, - 0x48, 0x6d, 0x1b, 0xf8, 0x37, 0x15, 0xad, 0x8d, - 0xab, 0xa5, 0x72, 0xaf, 0xb2, 0x61, 0xd5, 0xbe }, - { 0x47, 0x8c, 0xdd, 0x82, 0x3f, 0x81, 0x7d, 0x21, - 0x8b, 0xf5, 0xdd, 0xa4, 0xc3, 0xe9, 0x9e, 0x7f, - 0xa3, 0x10, 0x9b, 0x67, 0xbd, 0x0c, 0x9b, 0x1f, - 0x40, 0x75, 0x96, 0x65, 0xb9, 0xec, 0x3f, 0xf2 }, - { 0x48, 0xc5, 0xd4, 0xff, 0x5d, 0x08, 0x4a, 0xc1, - 0x95, 0xb1, 0xa6, 0xa2, 0x19, 0xf8, 0x1b, 0xbd, - 0xf9, 0xd2, 0xe5, 0xc0, 0x70, 0xec, 0x97, 0xdf, - 0x3c, 0xb0, 0xb7, 0x3e, 0xf4, 0x70, 0xdc, 0xe9 }, - { 0x49, 0xdc, 0xf8, 0xfa, 0x68, 0xe9, 0x2b, 0x5c, - 0x21, 0xfe, 0xf9, 0x3d, 0x26, 0x0c, 0x24, 0x8c, - 0xe3, 0xbe, 0x98, 0x62, 0x68, 0x68, 0xe7, 0x5a, - 0x3f, 0x63, 0x34, 0xbb, 0x7d, 0xc1, 0x81, 0xec }, - { 0x4b, 0x1f, 0xc8, 0x2d, 0x24, 0x72, 0x92, 0x7a, - 0xc1, 0x7c, 0x58, 0x43, 0x07, 0xcb, 0x96, 0xd6, - 0xfd, 0xdb, 0x8d, 0x50, 0xa5, 0x29, 0x53, 0x07, - 0xd3, 0x0c, 0x75, 0x88, 0x59, 0x6a, 0xd4, 0x0b }, - { 0x4b, 0x51, 0xfc, 0x11, 0x4b, 0xac, 0x8e, 0x2d, - 0x2a, 0xf2, 0xae, 0x56, 0x84, 0x42, 0x9c, 0xca, - 0xab, 0x21, 0x39, 0xc9, 0xb3, 0x51, 0xbf, 0x7e, - 0x1b, 0x03, 0x0a, 0xe8, 0x62, 0x4a, 0xc1, 0x72 }, - { 0x4c, 0xd0, 0xd6, 0x7e, 0xcc, 0x3b, 0x01, 0xc8, - 0xc2, 0x63, 0x4e, 0x7a, 0x73, 0x76, 0x12, 0xf6, - 0x3a, 0x17, 0xff, 0x51, 0x0a, 0x77, 0xa8, 0x04, - 0xbb, 0x33, 0x1b, 0x2b, 0xe5, 0x8d, 0xfe, 0x0c }, - { 0x4d, 0xcf, 0xeb, 0xdc, 0x15, 0x4b, 0x0c, 0x85, - 0x46, 0x7f, 0x6f, 0x52, 0xad, 0x80, 0x4e, 0x19, - 0x1d, 0x5b, 0xc8, 0x13, 0x51, 0x72, 0x0e, 0xc0, - 0xd1, 0x9b, 0xd2, 0x5b, 0xf8, 0xf0, 0xa5, 0x53 }, - { 0x4f, 0x19, 0xdd, 0x12, 0x92, 0x4c, 0xe0, 0xc1, - 0x4f, 0x82, 0xc0, 0x56, 0xc7, 0xd4, 0x2b, 0xac, - 0x43, 0xd0, 0x13, 0x3a, 0xaf, 0x89, 0xc1, 0xef, - 0xdc, 0xfa, 0x3c, 0x3e, 0x47, 0x09, 0x7d, 0x59 }, - { 0x4f, 0xfb, 0x59, 0x19, 0xbc, 0x38, 0x5c, 0x8c, - 0x58, 0xe4, 0x62, 0xbf, 0x13, 0x22, 0x10, 0xd8, - 0xb7, 0x86, 0x12, 0xd0, 0xc2, 0x2a, 0x6b, 0x6a, - 0x68, 0x2e, 0x0b, 0x9e, 0x9c, 0x9f, 0x9a, 0x44 }, - { 0x50, 0xf4, 0x78, 0x1e, 0xb1, 0xc1, 0x46, 0x70, - 0xd9, 0xa5, 0x52, 0xc3, 0x49, 0x5f, 0xb9, 0xf6, - 0xae, 0x86, 0x8a, 0xb1, 0xc9, 0xd9, 0x83, 0xe0, - 0x82, 0x68, 0x65, 0xa1, 0x02, 0xec, 0xa6, 0xd3 }, - { 0x51, 0x6a, 0x2f, 0x33, 0x60, 0xc7, 0x6f, 0xc4, - 0x6a, 0xb2, 0x88, 0x7f, 0x88, 0xe8, 0xd0, 0x8e, - 0xfb, 0xd8, 0x44, 0x5a, 0xa7, 0xbb, 0xd2, 0x29, - 0xdf, 0xc7, 0x1a, 0x90, 0x4f, 0x55, 0xae, 0xb4 }, - { 0x52, 0x1f, 0x6c, 0x6a, 0x84, 0x36, 0x65, 0x79, - 0xca, 0x2d, 0xea, 0xeb, 0x23, 0x15, 0xbf, 0x8e, - 0x53, 0x1c, 0x9f, 0xa4, 0x7b, 0x89, 0x9d, 0xa2, - 0x72, 0x16, 0xa9, 0x98, 0x82, 0x86, 0xaf, 0xe5 }, - { 0x52, 0xff, 0x8b, 0x6e, 0x98, 0xb0, 0x96, 0x19, - 0x90, 0x03, 0xde, 0x97, 0xbc, 0xcf, 0xd2, 0xa7, - 0xf1, 0xac, 0x57, 0xa8, 0x31, 0x35, 0xb9, 0x55, - 0xff, 0x68, 0x63, 0x36, 0xa6, 0x91, 0xd5, 0xca }, - { 0x53, 0x79, 0x64, 0x58, 0xda, 0x97, 0xce, 0x36, - 0x78, 0xf2, 0xd1, 0xd9, 0xb2, 0xa5, 0xb2, 0xfb, - 0x30, 0x75, 0xea, 0xfa, 0xf6, 0xff, 0x04, 0x78, - 0xb5, 0x72, 0xdd, 0xfd, 0x70, 0x99, 0xae, 0xe2 }, - { 0x53, 0x82, 0xd6, 0xba, 0xb5, 0x78, 0x51, 0xd9, - 0xb5, 0x8c, 0x17, 0x54, 0x46, 0xbf, 0x2d, 0x1b, - 0xb7, 0x86, 0xa5, 0x30, 0xfb, 0xf0, 0xae, 0xcd, - 0x12, 0xea, 0xb8, 0xa9, 0xa5, 0xb4, 0x96, 0x60 }, - { 0x53, 0x9c, 0xa9, 0xe1, 0xf0, 0x6a, 0xf2, 0x10, - 0x7f, 0x96, 0xbf, 0x4b, 0x7d, 0xd4, 0xce, 0xcd, - 0x9e, 0xd1, 0x1a, 0x38, 0xd6, 0x70, 0x91, 0x69, - 0x9c, 0x56, 0x26, 0xe2, 0x7a, 0x1f, 0x54, 0xa5 }, - { 0x55, 0x21, 0xf9, 0x63, 0x57, 0x81, 0x58, 0xb8, - 0xd0, 0xe7, 0xc4, 0x91, 0xcd, 0xb8, 0x5c, 0x3d, - 0xe9, 0xd5, 0x2e, 0xa5, 0x1f, 0xfc, 0xb0, 0x93, - 0xd3, 0x12, 0x28, 0x11, 0x13, 0x14, 0x97, 0xeb }, - { 0x55, 0xd0, 0xeb, 0xe3, 0x2c, 0xba, 0x09, 0xf6, - 0x58, 0x4d, 0x9e, 0x7b, 0x57, 0x92, 0xa4, 0x03, - 0xc2, 0x1d, 0x39, 0xd6, 0xe1, 0xf5, 0xe8, 0xed, - 0x37, 0xb9, 0x3f, 0xa6, 0x1d, 0x88, 0x35, 0x16 }, - { 0x58, 0x1a, 0xde, 0x64, 0x84, 0x95, 0xb4, 0xb1, - 0x62, 0x9c, 0x3c, 0x7c, 0x78, 0xef, 0xbe, 0xf2, - 0x75, 0x06, 0x56, 0x65, 0xb2, 0x41, 0x1c, 0x0e, - 0x5f, 0xcf, 0xbc, 0x7e, 0xb4, 0xbe, 0x34, 0x0b }, - { 0x59, 0xc9, 0xe8, 0xdf, 0x03, 0x0b, 0x1c, 0xd5, - 0x89, 0xa8, 0xb3, 0x4f, 0xe7, 0x42, 0x51, 0xea, - 0xd5, 0xa5, 0xfb, 0xe9, 0xe6, 0x13, 0x67, 0xca, - 0x76, 0xaf, 0xd9, 0xdd, 0xd9, 0xc6, 0xf1, 0x6f }, - { 0x59, 0xe9, 0xfa, 0x2f, 0xf0, 0x76, 0x89, 0x33, - 0x28, 0x33, 0xc6, 0x40, 0xf5, 0x05, 0xfa, 0x24, - 0x09, 0xeb, 0x88, 0x93, 0x32, 0x57, 0xc1, 0x93, - 0xb0, 0x07, 0xd3, 0xa2, 0x89, 0x6a, 0x98, 0x50 }, - { 0x59, 0xee, 0x9b, 0x36, 0x80, 0xae, 0x20, 0x56, - 0x83, 0x9c, 0x0b, 0xf6, 0x9e, 0xe6, 0x63, 0x26, - 0x57, 0x16, 0xa8, 0xe2, 0x4c, 0xc6, 0x49, 0x95, - 0xfb, 0xa6, 0xcb, 0x6f, 0x0c, 0x12, 0x39, 0xdc }, - { 0x5a, 0x84, 0xaf, 0xe6, 0x74, 0x05, 0xab, 0xe8, - 0x4a, 0x0c, 0xd4, 0x2c, 0x2b, 0xa2, 0xe4, 0xc8, - 0x8f, 0x35, 0xe0, 0xa5, 0x95, 0xe5, 0x69, 0xa3, - 0xe1, 0x86, 0x69, 0x44, 0x40, 0x5b, 0xe7, 0x36 }, - { 0x5a, 0x8e, 0x86, 0x21, 0x2c, 0x06, 0x33, 0x94, - 0x94, 0xf8, 0x5b, 0x5f, 0x85, 0x11, 0xdf, 0x00, - 0x00, 0x23, 0x94, 0x07, 0x8f, 0xfc, 0x77, 0x4d, - 0x43, 0x6f, 0x0d, 0x63, 0x86, 0xd7, 0xa6, 0xf7 }, - { 0x5a, 0xc0, 0x98, 0x2d, 0xa0, 0xc8, 0x3d, 0x0b, - 0xa9, 0x38, 0x1a, 0x5c, 0xd8, 0x7b, 0x80, 0xd1, - 0x10, 0xf2, 0x6e, 0xe8, 0x39, 0x27, 0x1b, 0xc2, - 0x70, 0x60, 0x8f, 0xd1, 0x43, 0x7f, 0x55, 0xb0 }, - { 0x5c, 0x7f, 0xf0, 0x55, 0xc2, 0xfd, 0x03, 0x3f, - 0x34, 0xc4, 0xc4, 0xf7, 0xc4, 0xfb, 0x7d, 0xda, - 0xaa, 0xfb, 0x43, 0x56, 0xc5, 0x60, 0xc9, 0x9e, - 0xdf, 0xf0, 0x74, 0xda, 0x04, 0xaf, 0x65, 0x7c }, - { 0x5c, 0xd2, 0x44, 0x6a, 0x8e, 0x4a, 0x0f, 0xa7, - 0xe3, 0xcd, 0xf8, 0x00, 0x5d, 0xed, 0xce, 0xba, - 0xe9, 0xe6, 0x81, 0x9a, 0x8a, 0x69, 0x87, 0x31, - 0x55, 0x5b, 0x7d, 0xc9, 0xd0, 0xa2, 0x3f, 0xc0 }, - { 0x5c, 0xeb, 0xeb, 0xd8, 0x34, 0x01, 0xb7, 0x0b, - 0xac, 0xb5, 0x4f, 0x66, 0xa9, 0xb7, 0x78, 0x55, - 0x69, 0x6e, 0xce, 0x16, 0x7f, 0xe6, 0xc6, 0x0a, - 0x05, 0x16, 0x8b, 0xe4, 0x39, 0x19, 0xc8, 0x0f }, - { 0x5f, 0x8b, 0x88, 0x8e, 0xe9, 0x6c, 0x0c, 0x0f, - 0x5a, 0x91, 0x72, 0x90, 0xac, 0xa6, 0x5a, 0xfd, - 0x6e, 0xbd, 0xae, 0x05, 0xa0, 0x2a, 0xaf, 0x04, - 0x29, 0xe9, 0x72, 0xec, 0x01, 0x90, 0xec, 0xfc }, - { 0x62, 0x2e, 0xc3, 0xbe, 0x7c, 0xf5, 0xe4, 0xe6, - 0x3f, 0x74, 0x18, 0x69, 0x28, 0x74, 0x40, 0x05, - 0xcb, 0xb7, 0x8d, 0xf3, 0x06, 0xb8, 0x67, 0xc3, - 0xfc, 0xad, 0x5e, 0x2b, 0xa7, 0x53, 0x96, 0x83 }, - { 0x62, 0x6f, 0x7e, 0xb4, 0xfd, 0x9b, 0x71, 0xff, - 0xaa, 0x0c, 0x8e, 0xc9, 0x65, 0x54, 0x64, 0xe6, - 0x5e, 0x7f, 0x96, 0xcf, 0xa3, 0x82, 0x73, 0x97, - 0x41, 0x35, 0x66, 0xaa, 0x2c, 0xc1, 0xe5, 0x72 }, - { 0x63, 0x64, 0x15, 0x61, 0x77, 0xdc, 0xdf, 0x60, - 0x4d, 0xf9, 0x1e, 0x31, 0x32, 0x2e, 0x57, 0x74, - 0x69, 0x1e, 0x0c, 0x41, 0xfa, 0x0d, 0x2f, 0x25, - 0x7a, 0xd7, 0xf9, 0xf0, 0x25, 0x98, 0x14, 0x45 }, - { 0x65, 0x66, 0x00, 0xa4, 0x5e, 0x45, 0x6a, 0xba, - 0x5b, 0x00, 0x8d, 0x87, 0x91, 0x54, 0xb7, 0x69, - 0x0d, 0x7f, 0x27, 0x31, 0x02, 0x09, 0x7d, 0x8f, - 0xd8, 0xc3, 0xde, 0xab, 0x30, 0xd8, 0x4a, 0xb2 }, - { 0x65, 0xed, 0x61, 0xa8, 0x8c, 0x55, 0xef, 0xb0, - 0x38, 0x07, 0x1a, 0xee, 0xde, 0xf8, 0xe1, 0x83, - 0xe2, 0x37, 0x38, 0x46, 0x97, 0x26, 0xeb, 0x99, - 0x68, 0x0c, 0xd2, 0x44, 0x72, 0x73, 0x6b, 0xec }, - { 0x66, 0x50, 0xb2, 0xea, 0x64, 0x4c, 0x3f, 0x4e, - 0x8c, 0x9e, 0x3c, 0x46, 0xac, 0xea, 0xc4, 0x52, - 0x33, 0xd8, 0x66, 0xe3, 0x98, 0xff, 0x90, 0xeb, - 0x59, 0xb2, 0xc6, 0x25, 0x20, 0x82, 0xac, 0x04 }, - { 0x66, 0xbe, 0x7e, 0xa1, 0x13, 0x8b, 0xcb, 0xa4, - 0xde, 0x0b, 0x41, 0x28, 0x5d, 0x9a, 0x13, 0x3f, - 0xa7, 0xf5, 0x70, 0xa3, 0xc8, 0x13, 0x55, 0x79, - 0xb8, 0x60, 0x19, 0x9d, 0x0a, 0x51, 0x45, 0x7c }, - { 0x69, 0x01, 0x4b, 0xbc, 0x84, 0x29, 0xd8, 0x5f, - 0x41, 0xc2, 0x22, 0xd9, 0x7f, 0x7e, 0xd5, 0x35, - 0xcf, 0x81, 0x23, 0x9a, 0xf2, 0x7a, 0xcc, 0x88, - 0x70, 0xdc, 0xd4, 0x08, 0x34, 0x8b, 0x48, 0xba }, - { 0x69, 0x21, 0x1f, 0x36, 0x3a, 0x2d, 0xbe, 0x01, - 0x5b, 0x31, 0xcb, 0xd9, 0xfc, 0x5e, 0x94, 0xc2, - 0xf6, 0xf4, 0x3c, 0x58, 0xdb, 0xde, 0xe9, 0xe3, - 0xe4, 0x6b, 0x19, 0xd7, 0x59, 0xbb, 0xb8, 0x81 }, - { 0x69, 0x75, 0x67, 0xbb, 0xac, 0x94, 0xee, 0xc3, - 0xe6, 0xfa, 0x4a, 0x4e, 0x46, 0xfa, 0x51, 0x74, - 0x05, 0xf3, 0x77, 0xc0, 0xde, 0xe3, 0xd4, 0x29, - 0x91, 0x4e, 0x6b, 0x7e, 0xa0, 0x8c, 0xb1, 0xa6 }, - { 0x6a, 0xac, 0xc5, 0x09, 0x2f, 0x12, 0xbc, 0x94, - 0xa0, 0xad, 0x0e, 0x9e, 0xf6, 0x36, 0x43, 0x7d, - 0x36, 0x0d, 0xc7, 0xc9, 0xf1, 0x40, 0x44, 0x17, - 0xa3, 0x36, 0x91, 0x94, 0x4e, 0x76, 0x31, 0x36 }, - { 0x6b, 0x4a, 0x8c, 0xb6, 0x07, 0xf5, 0x1c, 0x83, - 0x0d, 0xe7, 0x20, 0xf4, 0xbb, 0xde, 0xdf, 0x49, - 0x10, 0x15, 0x13, 0xdf, 0xd1, 0xdb, 0x0b, 0x0a, - 0x97, 0xcc, 0x3f, 0xdd, 0x9a, 0x39, 0xc6, 0xe7 }, - { 0x6c, 0x8f, 0xd1, 0xe6, 0xe1, 0x1b, 0xaf, 0xa6, - 0x17, 0x78, 0x13, 0xa0, 0x44, 0x40, 0xb1, 0xb9, - 0x6a, 0x1c, 0xdb, 0x7c, 0x2d, 0x70, 0x3f, 0x55, - 0xde, 0x85, 0x7c, 0x80, 0xa8, 0x9e, 0x73, 0x25 }, - { 0x6c, 0xc6, 0xdc, 0xda, 0x58, 0xc6, 0x1f, 0xb2, - 0x86, 0x70, 0xd1, 0xc2, 0x01, 0x76, 0x57, 0xb0, - 0xc5, 0xd6, 0x1a, 0x26, 0xc9, 0xcb, 0xd1, 0xea, - 0x75, 0x5c, 0x68, 0x20, 0xb5, 0xf6, 0xd6, 0x7d }, - { 0x6d, 0x32, 0xf4, 0x93, 0x40, 0x56, 0xee, 0x17, - 0x14, 0xca, 0x72, 0x70, 0x3f, 0x64, 0x46, 0x9b, - 0x98, 0x58, 0xfc, 0x39, 0x96, 0x4b, 0x4c, 0x03, - 0x93, 0xb3, 0x7d, 0xde, 0xab, 0x8b, 0x19, 0x75 }, - { 0x6e, 0x1a, 0x88, 0x63, 0xf2, 0x93, 0x4b, 0x39, - 0x01, 0x23, 0x7e, 0x84, 0xd0, 0x76, 0x27, 0x04, - 0x23, 0x06, 0x78, 0x7f, 0x2d, 0xe0, 0x66, 0x30, - 0xbd, 0x37, 0xd8, 0x03, 0x94, 0x35, 0xbf, 0xca }, - { 0x6e, 0x99, 0x8d, 0xdd, 0xf2, 0x93, 0x9b, 0xfe, - 0x8c, 0xc5, 0x2a, 0x48, 0x0a, 0xc0, 0x6d, 0x69, - 0x71, 0xc5, 0xa3, 0xda, 0x97, 0xcf, 0x3e, 0xf0, - 0x1a, 0xf2, 0x9d, 0x74, 0x72, 0x62, 0x31, 0xe2 }, - { 0x6f, 0x3b, 0xb3, 0x4b, 0x5d, 0x32, 0x91, 0xdf, - 0xb3, 0xe4, 0x12, 0x71, 0xa1, 0xd7, 0x30, 0xcd, - 0xbc, 0xff, 0xc1, 0x0b, 0x68, 0x05, 0x9d, 0xcc, - 0xd3, 0x1c, 0x47, 0x4b, 0xb7, 0x44, 0x16, 0xe5 }, - { 0x6f, 0xbd, 0xcd, 0xf1, 0xb4, 0x37, 0x9f, 0xc4, - 0x73, 0xab, 0x5e, 0xea, 0x4e, 0xc2, 0xf4, 0x84, - 0xce, 0x91, 0xd1, 0x0e, 0x31, 0x34, 0x5f, 0x15, - 0xa7, 0x6a, 0x84, 0x85, 0xb8, 0xff, 0xfb, 0x7e }, - { 0x70, 0xb8, 0xec, 0xd5, 0x62, 0xec, 0x3d, 0x9f, - 0x48, 0x64, 0x75, 0x2a, 0x3a, 0x8c, 0x54, 0x39, - 0x93, 0xb4, 0x38, 0x72, 0x8f, 0xe2, 0x71, 0x81, - 0xf4, 0xc0, 0x8d, 0xe6, 0xa0, 0xd8, 0xb7, 0x9a }, - { 0x72, 0x1b, 0x1f, 0x92, 0x9d, 0xa7, 0xea, 0xf8, - 0x96, 0x24, 0x64, 0x7b, 0xa3, 0xcc, 0x4e, 0x1e, - 0xd1, 0x57, 0x54, 0xab, 0x83, 0x6e, 0x33, 0x58, - 0xb0, 0x35, 0xa1, 0xf2, 0x27, 0x4a, 0x43, 0xbe }, - { 0x72, 0x81, 0xda, 0x0d, 0x8c, 0xe9, 0xd5, 0x3e, - 0xa3, 0xd1, 0xf5, 0x93, 0x5c, 0x58, 0x21, 0xea, - 0x8d, 0x9a, 0xf1, 0xce, 0x0b, 0xca, 0xf8, 0x82, - 0x5d, 0x78, 0x3f, 0x37, 0xea, 0xc3, 0x4f, 0x40 }, - { 0x72, 0xe7, 0x49, 0x87, 0x21, 0x0c, 0x7e, 0xf6, - 0x67, 0x46, 0xe4, 0x9a, 0x96, 0xdf, 0x55, 0xcc, - 0x6f, 0xad, 0xf7, 0xa6, 0x31, 0xc7, 0xae, 0x3f, - 0x3e, 0x9e, 0x18, 0x72, 0x3d, 0xe5, 0x2a, 0x6e }, - { 0x73, 0x3b, 0x42, 0x24, 0x25, 0x8d, 0xee, 0x07, - 0x0e, 0xdf, 0xa3, 0x41, 0x1f, 0xbc, 0x9b, 0xad, - 0x31, 0x65, 0xbe, 0x66, 0x0f, 0x34, 0x0a, 0xa2, - 0x30, 0x8a, 0x5a, 0x33, 0x23, 0xfa, 0xbf, 0xa7 }, - { 0x74, 0x8e, 0xbb, 0x72, 0xd1, 0x02, 0x04, 0xf4, - 0x04, 0x10, 0xbe, 0x70, 0x80, 0xbf, 0xe7, 0xee, - 0x63, 0x1f, 0xc0, 0x4d, 0x1f, 0xdb, 0x50, 0x72, - 0x04, 0x4b, 0xfa, 0x55, 0x7a, 0xdf, 0x6e, 0x5a }, - { 0x74, 0xe2, 0xcc, 0xcf, 0x62, 0xd5, 0xb9, 0xf9, - 0x00, 0xb4, 0x14, 0x73, 0xca, 0x44, 0xe6, 0x87, - 0x96, 0x38, 0x74, 0x3d, 0x8f, 0xee, 0x66, 0xee, - 0x71, 0x8c, 0x18, 0xd8, 0xf1, 0x12, 0x15, 0xd1 }, - { 0x76, 0x98, 0x67, 0x60, 0xac, 0xfe, 0x55, 0x59, - 0xa2, 0xa2, 0xab, 0x2a, 0x4e, 0x85, 0x49, 0x83, - 0xc5, 0xfd, 0xe6, 0x73, 0xce, 0x8e, 0xb1, 0x71, - 0x23, 0x49, 0x48, 0x64, 0x86, 0x7a, 0x98, 0xb1 }, - { 0x78, 0x0c, 0x33, 0xfe, 0x95, 0x4c, 0xc4, 0xdb, - 0x39, 0x04, 0xd7, 0x6a, 0x68, 0x58, 0xbc, 0xd1, - 0x01, 0x7f, 0x52, 0xda, 0x59, 0x9d, 0x36, 0xda, - 0xe6, 0x66, 0xc0, 0x4e, 0x41, 0xaf, 0x8d, 0xcd }, - { 0x78, 0xc9, 0x30, 0x40, 0x5a, 0x72, 0x0d, 0x9f, - 0x00, 0x66, 0xdd, 0x88, 0xa2, 0xa8, 0xda, 0xfb, - 0xbe, 0x6c, 0xd6, 0x5d, 0x54, 0xb7, 0x76, 0x06, - 0x42, 0x1b, 0x45, 0x43, 0x8c, 0x65, 0x8a, 0xd4 }, - { 0x79, 0x8f, 0x83, 0xb1, 0xc4, 0xc6, 0x5c, 0x4d, - 0x5d, 0xea, 0x13, 0x03, 0x53, 0x53, 0xd8, 0xed, - 0xe5, 0xd7, 0x1d, 0x99, 0x47, 0xf4, 0x34, 0xfd, - 0xea, 0x0d, 0xbc, 0x1e, 0xc8, 0x2f, 0x45, 0x35 }, - { 0x7b, 0xfe, 0x47, 0xae, 0xba, 0x8b, 0x0a, 0x3a, - 0x94, 0x5a, 0x88, 0xd8, 0xef, 0x18, 0x91, 0xc9, - 0x89, 0x97, 0x8a, 0xbf, 0x12, 0x2e, 0xc5, 0xe0, - 0x51, 0x4b, 0xe3, 0x6c, 0x3a, 0x7f, 0x22, 0x9b }, - { 0x7d, 0x20, 0xc7, 0xa9, 0x27, 0x26, 0x2b, 0xe7, - 0x38, 0xd2, 0x58, 0xd0, 0xfd, 0x97, 0x6e, 0x9a, - 0xf3, 0x6e, 0xf7, 0x99, 0x5f, 0x05, 0xe2, 0x87, - 0x6a, 0x29, 0xae, 0xbc, 0x3a, 0x24, 0xaa, 0xce }, - { 0x7e, 0x2e, 0xdb, 0x9d, 0x38, 0xf9, 0x29, 0x3c, - 0xdd, 0xd6, 0x03, 0xb1, 0x75, 0xc9, 0xb2, 0x05, - 0xac, 0x0b, 0x55, 0x3a, 0x4b, 0xf5, 0xfb, 0x08, - 0xc2, 0x46, 0xec, 0xf9, 0xc8, 0x49, 0xdb, 0x28 }, - { 0x7f, 0x95, 0x9b, 0x06, 0x34, 0xda, 0x94, 0xfa, - 0xca, 0xda, 0xb0, 0x21, 0xcf, 0x94, 0x20, 0x78, - 0x16, 0x00, 0x36, 0x13, 0xef, 0x09, 0xeb, 0x54, - 0xf6, 0x48, 0x60, 0x50, 0x08, 0x19, 0x02, 0x75 }, - { 0x7f, 0x9a, 0x69, 0xcf, 0xa2, 0xf5, 0x0c, 0x13, - 0xe1, 0xb7, 0x11, 0xdd, 0x6b, 0x14, 0x69, 0x2b, - 0xdb, 0x77, 0xd9, 0xff, 0xd8, 0xc1, 0x10, 0xae, - 0x5d, 0x05, 0xa4, 0xcb, 0x73, 0x12, 0x37, 0x48 }, - { 0x7f, 0xcc, 0xa8, 0xb5, 0xf5, 0xe3, 0x3b, 0xca, - 0x6d, 0xe0, 0x9c, 0x14, 0xaf, 0xbb, 0xe0, 0xc3, - 0x41, 0x21, 0xac, 0xbb, 0x22, 0x22, 0x9f, 0x44, - 0xee, 0x5c, 0x3f, 0x4d, 0xde, 0x73, 0x50, 0x55 }, - { 0x80, 0x20, 0x56, 0xe1, 0xdb, 0x9d, 0x9b, 0x73, - 0x21, 0xd1, 0xff, 0xbb, 0xe1, 0x2f, 0x5c, 0xbe, - 0xde, 0xc3, 0x6d, 0x0b, 0x5e, 0xc2, 0xa4, 0xe1, - 0x8d, 0x99, 0x54, 0x36, 0x4c, 0xec, 0x81, 0x29 }, - { 0x80, 0x97, 0x63, 0x4c, 0xe3, 0x3d, 0x41, 0x53, - 0x3d, 0x41, 0x5d, 0xaf, 0xdb, 0x8b, 0xa1, 0x91, - 0xc0, 0x30, 0x52, 0xac, 0x8b, 0xaa, 0x25, 0x54, - 0x34, 0x77, 0x3a, 0x16, 0x4b, 0x91, 0x1d, 0x6e }, - { 0x80, 0xd0, 0x17, 0x09, 0x34, 0xd2, 0x2a, 0xea, - 0x73, 0x3f, 0x11, 0x5e, 0x52, 0x42, 0xc6, 0xb8, - 0x6d, 0x7f, 0xcf, 0xb4, 0x90, 0x4e, 0x65, 0xb7, - 0xb7, 0xb9, 0x07, 0xf2, 0xca, 0x94, 0xed, 0x71 }, - { 0x81, 0x1d, 0xf2, 0xf4, 0x73, 0x6f, 0x85, 0x62, - 0xe2, 0x02, 0xfd, 0x00, 0x75, 0x32, 0xf1, 0xde, - 0x40, 0x17, 0x86, 0x1e, 0xfa, 0xbe, 0x67, 0x34, - 0x20, 0xc2, 0x7f, 0x2e, 0x2a, 0x33, 0xfa, 0xc1 }, - { 0x81, 0x1e, 0x37, 0x86, 0x37, 0xb1, 0xd2, 0xcb, - 0xb1, 0x89, 0xaf, 0xd6, 0x74, 0x95, 0xfe, 0x8a, - 0xb9, 0xd8, 0x3a, 0x74, 0x2e, 0x35, 0x8c, 0xbb, - 0xdb, 0xd1, 0x54, 0x98, 0xbf, 0x9c, 0x7b, 0x56 }, - { 0x81, 0xa0, 0xf1, 0xd0, 0x29, 0x46, 0x8e, 0xe8, - 0x66, 0x36, 0x4a, 0x19, 0x8a, 0x26, 0x08, 0x58, - 0x30, 0xc2, 0xa4, 0x16, 0xe4, 0x9e, 0x22, 0x4c, - 0xe8, 0x09, 0x66, 0xfc, 0xc4, 0x99, 0xd6, 0x36 }, - { 0x82, 0x56, 0x8b, 0x3b, 0xb3, 0xc6, 0x55, 0xd7, - 0xf2, 0x2d, 0x8c, 0x97, 0xa5, 0x66, 0x9c, 0xc8, - 0x34, 0xa2, 0xdd, 0x7c, 0xda, 0xe7, 0x5a, 0x26, - 0x45, 0x59, 0x55, 0x16, 0x46, 0x55, 0x8e, 0x14 }, - { 0x82, 0x7c, 0x8c, 0x80, 0x11, 0x1f, 0xf2, 0x21, - 0xc3, 0xeb, 0x1e, 0xf5, 0xc0, 0xd5, 0xd4, 0x34, - 0x48, 0x31, 0x86, 0xe2, 0x09, 0x00, 0x75, 0x63, - 0x15, 0x8e, 0x9e, 0x76, 0xd2, 0x79, 0x0f, 0x1c }, - { 0x82, 0x92, 0x67, 0xc5, 0xad, 0x70, 0xe5, 0x45, - 0x18, 0x02, 0x3a, 0xb7, 0x85, 0xfa, 0x3c, 0xde, - 0xd6, 0x6f, 0x42, 0x5d, 0xe1, 0xf3, 0x2f, 0xcd, - 0x72, 0x1b, 0x49, 0x46, 0x3a, 0x5a, 0x5f, 0x5b }, - { 0x83, 0x34, 0xea, 0xb8, 0x1c, 0x60, 0x4e, 0x99, - 0xd5, 0x40, 0x51, 0x3e, 0xf2, 0xe3, 0x7a, 0xba, - 0x71, 0x4f, 0x07, 0xb2, 0xba, 0x01, 0x0a, 0xd7, - 0x1d, 0xc4, 0xe1, 0x1a, 0x92, 0x18, 0xc1, 0x8c }, - { 0x83, 0x54, 0x7a, 0xca, 0x3c, 0xed, 0x73, 0xdf, - 0x99, 0x14, 0xf3, 0x15, 0x60, 0x74, 0x63, 0x79, - 0x29, 0x4c, 0x76, 0x0e, 0xf9, 0xa8, 0xb7, 0x6e, - 0x00, 0x06, 0x46, 0xc7, 0x39, 0x07, 0x21, 0x65 }, - { 0x83, 0x89, 0xc8, 0x79, 0xb6, 0x3b, 0x82, 0x9d, - 0x2d, 0x39, 0xa8, 0xcf, 0xb7, 0x87, 0xe7, 0x72, - 0x77, 0xd5, 0xcf, 0xa3, 0xe3, 0x6f, 0xda, 0xcb, - 0xab, 0x4d, 0x18, 0xb2, 0xb0, 0x4e, 0x32, 0x94 }, - { 0x84, 0x23, 0xb3, 0xf1, 0xcc, 0x85, 0x2b, 0x49, - 0xcf, 0x81, 0xb7, 0xd5, 0xff, 0x51, 0xa7, 0xa5, - 0x6a, 0x84, 0x78, 0x3a, 0x2d, 0xf7, 0x43, 0x61, - 0xff, 0x2e, 0xee, 0x0f, 0x92, 0x12, 0xc1, 0x59 }, - { 0x84, 0x7b, 0x5f, 0x1e, 0xeb, 0x2a, 0x44, 0x13, - 0xc8, 0xfa, 0x37, 0x98, 0x21, 0x97, 0x37, 0xe1, - 0x92, 0xba, 0x72, 0x72, 0xa1, 0x08, 0xb7, 0x17, - 0x28, 0xa8, 0xd1, 0x65, 0x17, 0xf6, 0x1e, 0x9d }, - { 0x85, 0x31, 0xb2, 0xbf, 0xc5, 0x45, 0x79, 0xe8, - 0xf1, 0x8f, 0x27, 0xb2, 0xe6, 0xec, 0xc0, 0xf8, - 0x90, 0x64, 0xee, 0x86, 0x87, 0x0e, 0xcc, 0x8b, - 0xbe, 0x0c, 0xe6, 0x86, 0xec, 0xda, 0x2c, 0x17 }, - { 0x85, 0x76, 0x0f, 0x59, 0x51, 0x90, 0xe9, 0xb4, - 0x67, 0x8b, 0xbf, 0x44, 0xef, 0xb5, 0xcf, 0x8f, - 0x6b, 0x19, 0x37, 0xa9, 0xb8, 0x6b, 0x31, 0xb7, - 0x51, 0xbe, 0xcf, 0x72, 0x18, 0x03, 0xb0, 0x1c }, - { 0x85, 0xf0, 0x79, 0x36, 0xb4, 0x29, 0x1f, 0x36, - 0xd9, 0xb7, 0x5f, 0x42, 0xe8, 0xb7, 0xee, 0x8a, - 0x64, 0xe6, 0x32, 0xa1, 0x18, 0x11, 0x65, 0xfe, - 0x72, 0xb4, 0x88, 0x23, 0xc3, 0xd9, 0x9d, 0x9d }, - { 0x86, 0x12, 0x9f, 0xe7, 0x61, 0x99, 0x4d, 0x7b, - 0x64, 0xe4, 0x02, 0x85, 0x8f, 0x88, 0xc5, 0x2b, - 0x3e, 0xb9, 0xc0, 0x71, 0xff, 0xbe, 0x80, 0x02, - 0x80, 0xac, 0x8c, 0x0c, 0x6f, 0x79, 0xe7, 0xa6 }, - { 0x86, 0x19, 0x6b, 0x0f, 0xd3, 0x0f, 0x8f, 0x57, - 0x56, 0x98, 0xb5, 0xee, 0xf2, 0x69, 0xd0, 0x69, - 0x2f, 0x88, 0xad, 0xea, 0xc4, 0x83, 0x6a, 0x62, - 0x67, 0xab, 0xc8, 0x36, 0x23, 0x34, 0x00, 0x86 }, - { 0x86, 0xcf, 0xec, 0xbe, 0x82, 0xba, 0xdb, 0x93, - 0x14, 0x75, 0xf1, 0x9e, 0xcd, 0x6e, 0xa6, 0x7d, - 0x59, 0xc2, 0xc7, 0x00, 0x78, 0xb6, 0xcc, 0x56, - 0xbf, 0xdc, 0x27, 0x55, 0x47, 0x67, 0xf2, 0x3f }, - { 0x86, 0xd1, 0x8b, 0xcd, 0xde, 0x16, 0x45, 0x42, - 0x48, 0x6e, 0x56, 0x44, 0x2c, 0xe1, 0xb8, 0x8b, - 0x1a, 0x10, 0x73, 0x7c, 0xbd, 0x5e, 0xa4, 0xaa, - 0xb8, 0xd5, 0xb8, 0xaf, 0x51, 0xf5, 0x29, 0x09 }, - { 0x87, 0x5f, 0x57, 0x42, 0x4c, 0x90, 0x2b, 0x24, - 0xe8, 0x1c, 0x27, 0xd1, 0xca, 0xf2, 0x74, 0xb1, - 0x7d, 0x72, 0x0d, 0xf8, 0x07, 0x8b, 0x6f, 0x2a, - 0x5c, 0x3b, 0xb8, 0xd8, 0xdf, 0xf0, 0x55, 0x00 }, - { 0x88, 0x8d, 0x6d, 0x77, 0xd8, 0x1c, 0x62, 0x91, - 0xcb, 0x84, 0xd9, 0xd6, 0x56, 0x27, 0x82, 0xfd, - 0x2e, 0xb3, 0x42, 0x5d, 0x49, 0x1e, 0x68, 0x74, - 0x20, 0x28, 0x4b, 0x76, 0xa1, 0xde, 0xbf, 0xab }, - { 0x89, 0xaf, 0x0e, 0x54, 0xc7, 0x62, 0x77, 0x86, - 0x93, 0x52, 0x9d, 0x0a, 0x95, 0x0b, 0x78, 0x33, - 0xf5, 0xea, 0xba, 0xf3, 0x42, 0x79, 0x72, 0x60, - 0x7f, 0xb2, 0xc7, 0x0c, 0x96, 0xa3, 0x21, 0x61 }, - { 0x89, 0xda, 0xc7, 0x89, 0x6b, 0x46, 0xf2, 0xfc, - 0x8b, 0xea, 0x62, 0x11, 0xff, 0x98, 0xb6, 0x1f, - 0xaa, 0x15, 0x7b, 0xa8, 0xc4, 0xad, 0x6f, 0xd1, - 0x75, 0x92, 0x75, 0xce, 0x39, 0x41, 0xc3, 0x28 }, - { 0x8a, 0x09, 0x85, 0xbf, 0x86, 0xe8, 0xc9, 0xb9, - 0x17, 0xec, 0x84, 0xda, 0x2a, 0x56, 0x73, 0x1e, - 0x75, 0x2a, 0xa0, 0xdc, 0x52, 0x87, 0xc2, 0xbf, - 0x39, 0x51, 0x0b, 0xb3, 0xf0, 0xf2, 0x0a, 0xd1 }, - { 0x8a, 0xaf, 0x36, 0x3c, 0xc9, 0xd8, 0x44, 0x15, - 0xa7, 0xeb, 0x0d, 0x72, 0xda, 0x08, 0xb3, 0x58, - 0x80, 0x68, 0x55, 0x9c, 0xb0, 0xa9, 0xae, 0x92, - 0xb8, 0xf4, 0x60, 0x2e, 0xda, 0x23, 0x82, 0xaa }, - { 0x8a, 0xb2, 0x77, 0x62, 0xf4, 0xa2, 0xe3, 0x11, - 0x22, 0x04, 0x96, 0x98, 0x39, 0x99, 0xc8, 0xc4, - 0x60, 0x96, 0x3d, 0xfc, 0x1b, 0x88, 0x51, 0x11, - 0x1d, 0xa4, 0x1d, 0x3f, 0x3b, 0x0a, 0x6e, 0x94 }, - { 0x8a, 0xd1, 0xd5, 0x48, 0x95, 0x27, 0xb5, 0x28, - 0xe5, 0xb5, 0xd6, 0xa5, 0x95, 0x78, 0x87, 0x08, - 0x88, 0x8a, 0x3f, 0xb1, 0x9f, 0x2c, 0x7c, 0x8b, - 0x38, 0x07, 0x0e, 0x1f, 0x38, 0x98, 0x96, 0x8b }, - { 0x8a, 0xdb, 0x49, 0xd4, 0x15, 0x53, 0x56, 0x70, - 0x5b, 0x64, 0x42, 0x6a, 0x99, 0x0f, 0x58, 0xb3, - 0xa0, 0x71, 0xef, 0x78, 0x2e, 0x6c, 0x09, 0x53, - 0x07, 0xd7, 0x74, 0x74, 0xd5, 0xb5, 0x7a, 0x62 }, - { 0x8b, 0x3a, 0x10, 0x35, 0xc3, 0xfd, 0xf3, 0x45, - 0xfb, 0x70, 0x80, 0x44, 0x83, 0xa5, 0x04, 0x49, - 0xa3, 0xd7, 0x60, 0xc6, 0xba, 0x48, 0xf5, 0xb8, - 0x2d, 0x6b, 0xb2, 0x62, 0xed, 0x9d, 0xe3, 0x73 }, - { 0x8b, 0x3a, 0x75, 0xcb, 0xc3, 0x62, 0xd2, 0x35, - 0x57, 0x0e, 0x5d, 0xe7, 0x04, 0x29, 0x38, 0x70, - 0x8a, 0x1b, 0x0f, 0xce, 0xb4, 0x59, 0x86, 0x2a, - 0x38, 0x67, 0xb7, 0x34, 0xcd, 0xcb, 0x97, 0x94 }, - { 0x8c, 0x3e, 0x7c, 0x1d, 0xcc, 0x7d, 0xd8, 0xe7, - 0xd8, 0xbf, 0x7b, 0x5b, 0x3a, 0xe5, 0xe0, 0x27, - 0x2e, 0x81, 0x1a, 0xb9, 0xf3, 0xc3, 0xc5, 0x38, - 0xe5, 0x74, 0x71, 0x77, 0xe6, 0x2d, 0x62, 0x92 }, - { 0x8c, 0x7c, 0x65, 0x7b, 0xda, 0x13, 0xca, 0x62, - 0xf2, 0x9a, 0x65, 0xc6, 0xd5, 0x19, 0x3a, 0x93, - 0xcf, 0x6c, 0x58, 0x77, 0x18, 0xad, 0xca, 0x67, - 0x15, 0x8e, 0x97, 0xd3, 0x6a, 0x62, 0x3e, 0xca }, - { 0x8c, 0xa6, 0x79, 0x62, 0xc4, 0xa8, 0x09, 0x13, - 0x33, 0xf2, 0x4e, 0xfd, 0x60, 0xee, 0x70, 0xcf, - 0xed, 0xdb, 0xd6, 0x41, 0x59, 0x04, 0x70, 0x9e, - 0x78, 0x5c, 0x33, 0x1b, 0x1e, 0xf5, 0x8f, 0x8e }, - { 0x8e, 0x18, 0xfd, 0xbd, 0xb0, 0x08, 0x16, 0x00, - 0x35, 0xfa, 0xf5, 0x01, 0x5b, 0xe7, 0xda, 0xf4, - 0x63, 0xb5, 0xc4, 0x14, 0xea, 0xbc, 0x8b, 0x89, - 0xf3, 0xdb, 0xa2, 0x05, 0xab, 0x09, 0xa6, 0x43 }, - { 0x8f, 0x10, 0x10, 0x47, 0x93, 0xe8, 0x55, 0x42, - 0xbc, 0x06, 0x04, 0xd6, 0xcf, 0x21, 0x5f, 0x78, - 0x80, 0xbd, 0x6a, 0x4d, 0xd0, 0xfd, 0xf1, 0xe7, - 0xa5, 0xb9, 0xca, 0x12, 0x46, 0xf5, 0xc4, 0x09 }, - { 0x8f, 0x71, 0x27, 0x76, 0x2e, 0xe7, 0x51, 0x69, - 0xbd, 0xc3, 0x5b, 0x04, 0xa7, 0x28, 0xe9, 0xd3, - 0x1b, 0x7e, 0x4d, 0x37, 0x89, 0xaa, 0x2c, 0x46, - 0xd8, 0xa3, 0x1b, 0x3d, 0xfa, 0x81, 0xa9, 0x7e }, - { 0x8f, 0x94, 0x15, 0x92, 0x6f, 0x40, 0x49, 0xea, - 0x41, 0x8a, 0x30, 0x7c, 0x76, 0x36, 0xe4, 0x9b, - 0x14, 0x4f, 0xa5, 0x3e, 0x52, 0xe1, 0x04, 0x15, - 0x5f, 0x58, 0x03, 0x5e, 0x45, 0x41, 0xcd, 0x6e }, - { 0x90, 0xe2, 0x51, 0x86, 0x7f, 0x6b, 0x0c, 0x14, - 0xbd, 0x9b, 0x51, 0x0c, 0xfd, 0xa8, 0x48, 0x49, - 0x72, 0xfd, 0xf0, 0xe0, 0x6d, 0xc1, 0x1f, 0x5d, - 0x1d, 0x59, 0x0b, 0xe3, 0xfc, 0x38, 0xdf, 0xf0 }, - { 0x91, 0x90, 0xf8, 0x25, 0x51, 0x0c, 0x65, 0x98, - 0xe1, 0x9d, 0x17, 0xdb, 0xbe, 0x6e, 0x7c, 0x82, - 0x31, 0x86, 0x9c, 0xa7, 0xf6, 0xe3, 0x07, 0xa2, - 0xc2, 0xcc, 0x54, 0x77, 0x8d, 0x4a, 0x89, 0xb3 }, - { 0x92, 0x3f, 0x0f, 0x8c, 0x40, 0x5a, 0x02, 0xe6, - 0x82, 0xc4, 0xb4, 0x66, 0x5a, 0x7e, 0xe7, 0x16, - 0xaa, 0x57, 0xe0, 0xa5, 0x86, 0xc2, 0x4a, 0x16, - 0x5a, 0xad, 0x7e, 0x5b, 0xda, 0x22, 0x78, 0x24 }, - { 0x92, 0x71, 0x44, 0x12, 0x1c, 0x23, 0x63, 0x57, - 0x07, 0xe9, 0x40, 0x7f, 0x7f, 0xff, 0x6a, 0x64, - 0x63, 0x5d, 0x7c, 0xe9, 0x06, 0x66, 0xd4, 0x29, - 0x94, 0x09, 0x7a, 0xf4, 0x0c, 0x31, 0x36, 0xfb }, - { 0x94, 0xdc, 0x80, 0x07, 0x49, 0x1d, 0xa8, 0xbf, - 0xb7, 0x39, 0x14, 0xad, 0xce, 0xf7, 0x1a, 0x12, - 0x41, 0x58, 0xba, 0xd1, 0x7b, 0xa8, 0x8f, 0xa9, - 0x46, 0x57, 0x9b, 0xbc, 0x2d, 0x64, 0x97, 0x8d }, - { 0x95, 0x68, 0x33, 0xae, 0xe6, 0x61, 0x19, 0x26, - 0xe9, 0x52, 0x72, 0xa1, 0xf5, 0x88, 0xf9, 0x2a, - 0xf5, 0x2c, 0xae, 0x70, 0x7a, 0xcd, 0xcc, 0x82, - 0x63, 0x99, 0x7b, 0xfa, 0x8c, 0x71, 0x9c, 0xa8 }, - { 0x95, 0x89, 0xda, 0xc9, 0xec, 0xe7, 0x6d, 0xf5, - 0x72, 0x01, 0x96, 0xdc, 0x58, 0x6d, 0x17, 0x9d, - 0x73, 0x5d, 0xf7, 0x17, 0x92, 0x6c, 0x06, 0x1e, - 0xa7, 0x0c, 0x40, 0x85, 0x64, 0x8f, 0xf3, 0x12 }, - { 0x96, 0xa4, 0x59, 0x90, 0xfc, 0xd0, 0x1c, 0x9c, - 0x2a, 0xf0, 0x64, 0x5f, 0x87, 0xb9, 0x69, 0x8b, - 0x05, 0xaf, 0xe6, 0x94, 0x32, 0xeb, 0x57, 0x01, - 0x08, 0x20, 0x13, 0xba, 0xc5, 0xb0, 0x55, 0x60 }, - { 0x96, 0xeb, 0x44, 0xaa, 0x6a, 0x20, 0x49, 0xe6, - 0xba, 0xff, 0xe6, 0xb5, 0x21, 0xc4, 0xad, 0x8c, - 0x58, 0x77, 0x26, 0xca, 0xa0, 0x12, 0xe8, 0xfb, - 0x8e, 0x8e, 0x21, 0x89, 0x77, 0xbf, 0x1d, 0xf6 }, - { 0x97, 0x4f, 0x51, 0xa6, 0x04, 0x68, 0x48, 0xfa, - 0xa7, 0xb3, 0x3f, 0xd2, 0x39, 0x13, 0x86, 0x42, - 0x8b, 0xd5, 0x24, 0xea, 0xeb, 0xa8, 0x01, 0x4e, - 0x6d, 0x1f, 0xe2, 0x54, 0x38, 0x3f, 0x41, 0x79 }, - { 0x97, 0x8d, 0x6f, 0x1e, 0x9a, 0xa3, 0xa3, 0xce, - 0xb1, 0xad, 0xa6, 0x09, 0xe2, 0x00, 0x95, 0xfb, - 0xc3, 0x3a, 0x6b, 0xbc, 0x6a, 0x21, 0xd8, 0x0a, - 0x4e, 0xcb, 0x27, 0x3c, 0x60, 0xac, 0x2a, 0xc7 }, - { 0x99, 0xa5, 0x5f, 0x76, 0xcb, 0xea, 0x0f, 0x3e, - 0x60, 0x71, 0xd3, 0x82, 0x18, 0x1a, 0xf6, 0xcb, - 0x25, 0xbd, 0xc5, 0x87, 0x5e, 0x29, 0xf0, 0xf4, - 0xd7, 0x19, 0xa9, 0xd3, 0x5b, 0x5b, 0xd6, 0xbf }, - { 0x9a, 0x4b, 0x49, 0x93, 0xb4, 0xed, 0x8c, 0x27, - 0xe7, 0x7f, 0x3c, 0x8a, 0xaf, 0xdb, 0xdc, 0x11, - 0x1a, 0x36, 0xb7, 0x3c, 0xca, 0xdb, 0x87, 0x04, - 0x98, 0x25, 0x00, 0xd1, 0xb0, 0xf1, 0x09, 0xf2 }, - { 0x9a, 0xae, 0x9d, 0x45, 0xaa, 0x04, 0x03, 0x06, - 0x4b, 0xc5, 0xa7, 0x4d, 0xd0, 0x32, 0x5d, 0xa4, - 0x1e, 0x12, 0xcf, 0x58, 0x6c, 0x46, 0x2e, 0xe0, - 0x6c, 0x2b, 0xb4, 0x56, 0xf8, 0x44, 0x1c, 0x4f }, - { 0x9b, 0x8f, 0x9f, 0xc4, 0xaf, 0xa7, 0x04, 0x0d, - 0x4e, 0x59, 0x4d, 0x66, 0x7c, 0x44, 0x44, 0xb5, - 0x25, 0x88, 0x20, 0xc0, 0x8f, 0x89, 0x91, 0x0e, - 0xd3, 0x42, 0x1c, 0xb4, 0xa9, 0x7b, 0xb7, 0x9e }, - { 0x9c, 0x70, 0x8d, 0x5b, 0xab, 0x37, 0xf5, 0xb6, - 0xbc, 0x8a, 0x77, 0x53, 0x12, 0x57, 0x2a, 0xb2, - 0x79, 0x21, 0x6d, 0x55, 0x6d, 0xa7, 0x4a, 0xc2, - 0xa7, 0xc0, 0x41, 0xe8, 0xce, 0xb0, 0xbe, 0x0a }, - { 0x9d, 0x6b, 0xdf, 0xcf, 0x0c, 0xbf, 0xfe, 0xea, - 0x3b, 0x1a, 0xc7, 0xe9, 0x63, 0xcb, 0xb5, 0xf2, - 0x7f, 0xbd, 0xa8, 0x9d, 0x27, 0x77, 0xf6, 0x0e, - 0x56, 0x5b, 0x27, 0x78, 0x54, 0xef, 0xb0, 0x19 }, - { 0x9d, 0xac, 0x33, 0x14, 0xb2, 0x5b, 0xb7, 0x9a, - 0x39, 0xcd, 0x01, 0xec, 0x4b, 0x33, 0xa1, 0x2f, - 0x47, 0x51, 0x2f, 0x54, 0x09, 0xff, 0x09, 0x5d, - 0x40, 0xaa, 0xd6, 0x20, 0x84, 0xef, 0x15, 0xbe }, - { 0x9f, 0x24, 0x5c, 0x0a, 0x0e, 0xc6, 0x3a, 0xaa, - 0xcb, 0xf9, 0x69, 0xc6, 0xfc, 0x24, 0xa1, 0x07, - 0x15, 0x83, 0xb7, 0x79, 0xa5, 0x8a, 0xb6, 0x23, - 0xdd, 0x15, 0x31, 0xa2, 0xca, 0x9f, 0x87, 0x51 }, - { 0x9f, 0xaf, 0x1c, 0x11, 0xa3, 0xc7, 0xe2, 0x41, - 0xf8, 0x63, 0x71, 0x97, 0xe8, 0x99, 0x68, 0xdb, - 0x86, 0x6a, 0xd0, 0x1a, 0x5d, 0x4e, 0xd5, 0x34, - 0x59, 0x48, 0x65, 0xb9, 0x70, 0x75, 0xf2, 0x60 }, - { 0xa0, 0x05, 0x20, 0xb9, 0x68, 0xbf, 0xcb, 0x63, - 0x40, 0x87, 0x9f, 0xa8, 0x43, 0x82, 0x0c, 0xec, - 0x95, 0x45, 0x86, 0x0f, 0xe2, 0x9e, 0x2f, 0x8f, - 0xee, 0x00, 0xb0, 0x0f, 0xf8, 0x43, 0x42, 0x74 }, - { 0xa0, 0xc2, 0xd2, 0x07, 0xa4, 0x7e, 0x18, 0xd0, - 0x37, 0x14, 0xd5, 0xb3, 0x44, 0x5d, 0x88, 0xbe, - 0x81, 0xff, 0x5e, 0x1d, 0x16, 0x07, 0x3d, 0xc1, - 0x16, 0x6b, 0xb5, 0x44, 0x8f, 0xf6, 0x52, 0xdf }, - { 0xa1, 0x50, 0x03, 0x2f, 0x4e, 0xf5, 0xd4, 0xfe, - 0xb0, 0xae, 0x4a, 0xe1, 0xcd, 0x54, 0x35, 0xba, - 0x04, 0xa9, 0xb6, 0xa0, 0xf9, 0x0e, 0x2f, 0x3c, - 0x4b, 0x8a, 0x7b, 0x69, 0xe7, 0xc8, 0x7e, 0x43 }, - { 0xa1, 0x97, 0x7d, 0x0c, 0x92, 0x7c, 0x21, 0xeb, - 0x47, 0x6f, 0x67, 0xbe, 0xfe, 0xd6, 0xcf, 0x2c, - 0x61, 0xb7, 0x45, 0xf0, 0xce, 0x8d, 0x26, 0x58, - 0x3d, 0x03, 0xb2, 0x70, 0x02, 0xd5, 0xcd, 0xaf }, - { 0xa2, 0x6c, 0x37, 0x5e, 0xb3, 0x19, 0x6e, 0x28, - 0x3b, 0xec, 0x60, 0x3d, 0xb6, 0xbb, 0xda, 0xe2, - 0x49, 0x55, 0xe4, 0xba, 0x91, 0x0c, 0xd4, 0x2d, - 0x9e, 0xac, 0x55, 0xca, 0xc6, 0x10, 0x3a, 0xb9 }, - { 0xa3, 0xa4, 0xfc, 0x03, 0xe1, 0x75, 0xf2, 0x68, - 0x02, 0x57, 0x46, 0x34, 0xde, 0x70, 0x7d, 0x2f, - 0x92, 0xf4, 0xd0, 0xcb, 0x90, 0xcd, 0xb6, 0x1d, - 0xd1, 0x95, 0x8b, 0xcf, 0x0c, 0x55, 0x20, 0x86 }, - { 0xa6, 0x62, 0xfc, 0x81, 0xc9, 0x09, 0x34, 0xb9, - 0xb4, 0xd6, 0x30, 0xb5, 0xd8, 0x2e, 0x86, 0xf2, - 0x36, 0x3e, 0xc1, 0x5c, 0xcf, 0xcd, 0xaf, 0xa7, - 0xa2, 0x0c, 0x9b, 0x4e, 0x3a, 0x90, 0x0d, 0xd1 }, - { 0xa6, 0xa4, 0xa3, 0xf6, 0x1f, 0xa5, 0x8c, 0xe9, - 0x70, 0xb4, 0x58, 0xb7, 0xc3, 0x7c, 0x05, 0x2e, - 0xad, 0x1e, 0xb2, 0x0b, 0x85, 0x67, 0xe3, 0x51, - 0xad, 0x8e, 0x6f, 0xba, 0x49, 0xc2, 0x69, 0x2c }, - { 0xa6, 0xde, 0x6c, 0x3b, 0x8c, 0x14, 0x05, 0xcb, - 0xe1, 0x2d, 0xb4, 0x09, 0x97, 0x61, 0x71, 0xac, - 0xb5, 0x1f, 0xb3, 0xdc, 0xfb, 0xb7, 0x6e, 0xe3, - 0x84, 0x95, 0x39, 0xcd, 0x8a, 0xb0, 0x66, 0xdf }, - { 0xa8, 0x53, 0xad, 0xc1, 0xc2, 0x18, 0x59, 0xaf, - 0x7c, 0x46, 0x2b, 0x4a, 0xa0, 0xa5, 0x74, 0xca, - 0x9f, 0xee, 0xfb, 0x18, 0x5a, 0x1f, 0xdb, 0xb6, - 0xc1, 0x0e, 0x17, 0xd6, 0x01, 0xb7, 0x09, 0x8f }, - { 0xa8, 0xdf, 0xf0, 0x6a, 0x17, 0x35, 0xb4, 0x6d, - 0x17, 0xda, 0xeb, 0xc3, 0x43, 0x43, 0x18, 0x31, - 0x3b, 0x2d, 0x9e, 0x7c, 0x3e, 0xf4, 0x8f, 0x28, - 0x53, 0x75, 0x35, 0x13, 0xe1, 0xb2, 0x53, 0xa8 }, - { 0xa8, 0xe3, 0x8c, 0x6e, 0xc0, 0x93, 0xf5, 0xaf, - 0x53, 0x88, 0xf1, 0xe7, 0x66, 0xd7, 0x5f, 0xfb, - 0x57, 0xdd, 0xbe, 0x3e, 0x9d, 0xc2, 0xe0, 0xbe, - 0x57, 0xbb, 0x88, 0x36, 0x46, 0xc5, 0xc0, 0x32 }, - { 0xa9, 0x0b, 0x8d, 0xe1, 0x7f, 0x6b, 0x68, 0x37, - 0x56, 0x21, 0x2d, 0xb3, 0xab, 0x34, 0x89, 0x6e, - 0x91, 0x70, 0x93, 0x11, 0x3e, 0x47, 0xca, 0x35, - 0x96, 0x2e, 0xac, 0xca, 0x9c, 0xb3, 0x86, 0xf0 }, - { 0xaa, 0x4b, 0xb3, 0x6f, 0x51, 0xd3, 0xc5, 0x33, - 0xb5, 0x27, 0x23, 0xcf, 0x66, 0xa5, 0xa9, 0x9f, - 0xc1, 0x2f, 0x11, 0xd4, 0xcc, 0x12, 0x87, 0x56, - 0xa5, 0xa3, 0xe8, 0x9c, 0x57, 0xbb, 0x97, 0x51 }, - { 0xaa, 0xeb, 0xfe, 0x2d, 0x21, 0xb7, 0xe5, 0x35, - 0x1b, 0xb9, 0x99, 0x69, 0x44, 0x44, 0x19, 0xef, - 0x21, 0xc9, 0x68, 0x8c, 0xe0, 0x53, 0x24, 0x88, - 0x84, 0xca, 0xb0, 0xb8, 0x95, 0x10, 0x30, 0xff }, - { 0xab, 0x41, 0x28, 0x10, 0x9c, 0xab, 0x8a, 0x58, - 0x7c, 0x8f, 0xf4, 0xc7, 0xf6, 0x87, 0x34, 0x49, - 0x98, 0x18, 0xd1, 0x3f, 0x52, 0x26, 0x76, 0xd0, - 0x66, 0xb3, 0x52, 0x17, 0x6f, 0xd2, 0x35, 0x96 }, - { 0xab, 0x80, 0xd9, 0xba, 0x0a, 0xef, 0xad, 0x7b, - 0xec, 0xce, 0x7f, 0x5e, 0x61, 0x59, 0x9a, 0xf5, - 0x26, 0x69, 0xbf, 0x59, 0x50, 0x7f, 0x8e, 0xf1, - 0x99, 0x13, 0xc4, 0x2e, 0xe1, 0x29, 0xda, 0xf0 }, - { 0xab, 0xeb, 0x6a, 0xa0, 0xd1, 0xb0, 0xe0, 0x49, - 0xd6, 0x9d, 0xf8, 0x3a, 0xdd, 0x19, 0xf7, 0x26, - 0x8a, 0x38, 0xde, 0x6c, 0x00, 0x72, 0x60, 0x68, - 0xc2, 0xee, 0xe4, 0x55, 0x44, 0xf6, 0xd6, 0x7a }, - { 0xac, 0x1b, 0x4c, 0x64, 0x6c, 0xae, 0xfb, 0x10, - 0x8a, 0x54, 0xca, 0xb5, 0x4a, 0x96, 0xe9, 0x66, - 0x6e, 0x72, 0xa8, 0x20, 0x22, 0x44, 0xef, 0x3d, - 0x7c, 0xa9, 0x34, 0xdf, 0xcc, 0x24, 0xfc, 0xa7 }, - { 0xad, 0x69, 0x54, 0x5f, 0x9f, 0x85, 0x25, 0x5f, - 0xe4, 0x16, 0x51, 0x3d, 0x94, 0xdb, 0x31, 0x50, - 0x5f, 0x38, 0x4b, 0x52, 0x3c, 0x2c, 0xa2, 0x6e, - 0xdc, 0x0a, 0x54, 0x9a, 0x8f, 0x16, 0x26, 0xf9 }, - { 0xae, 0x03, 0x19, 0xfe, 0xa6, 0xa6, 0x5e, 0x84, - 0xe8, 0x54, 0xb5, 0x15, 0x50, 0xea, 0x44, 0x4f, - 0xa3, 0xb8, 0xbb, 0x50, 0xae, 0x93, 0x74, 0x01, - 0x3c, 0xfe, 0xf3, 0x88, 0x73, 0x5d, 0x0b, 0xd3 }, - { 0xaf, 0x1f, 0x37, 0x1f, 0x34, 0x84, 0x57, 0x51, - 0x65, 0x2d, 0xc7, 0x48, 0x23, 0xf3, 0x01, 0x5c, - 0x5a, 0x11, 0xca, 0x65, 0x3f, 0x28, 0x70, 0x1e, - 0xdd, 0x4a, 0x7e, 0x0d, 0x23, 0x17, 0x1b, 0xbb }, - { 0xaf, 0x6b, 0x80, 0x51, 0x47, 0x14, 0x0a, 0x0e, - 0x41, 0x81, 0xd8, 0x6a, 0x7e, 0x8f, 0x07, 0x69, - 0xb6, 0x1d, 0x46, 0xd7, 0xb6, 0xfa, 0xc6, 0xe6, - 0xf9, 0x59, 0x6d, 0xe9, 0x4a, 0xa8, 0xe2, 0xe8 }, - { 0xb0, 0x5c, 0x14, 0x33, 0x61, 0x75, 0x9b, 0xe1, - 0x52, 0xfd, 0x76, 0xa5, 0xff, 0xa4, 0x87, 0x2d, - 0xd4, 0x2e, 0xa0, 0x60, 0xae, 0x40, 0xa3, 0x83, - 0x13, 0xb7, 0xb5, 0x4a, 0xec, 0x06, 0x73, 0xc2 }, - { 0xb0, 0xe0, 0xe1, 0x6c, 0x5f, 0x69, 0x1f, 0x66, - 0xa9, 0x57, 0x3b, 0xd3, 0xcf, 0x43, 0xf9, 0xdf, - 0xd2, 0xad, 0x3e, 0x56, 0x15, 0x54, 0x63, 0x7f, - 0x1e, 0x7b, 0x71, 0x91, 0x4d, 0x62, 0x73, 0x38 }, - { 0xb2, 0xdc, 0x86, 0x25, 0x6c, 0xcf, 0xf4, 0xbb, - 0x14, 0xfd, 0x70, 0x27, 0x9f, 0xcc, 0x3c, 0xe9, - 0x25, 0xc5, 0x1f, 0xb7, 0x17, 0xe5, 0x87, 0x6f, - 0x29, 0x1b, 0xa1, 0x70, 0x73, 0x43, 0x85, 0x68 }, - { 0xb3, 0x0d, 0x88, 0x44, 0x30, 0x43, 0xf5, 0xf3, - 0x72, 0x32, 0xbb, 0x9b, 0xac, 0xb9, 0x94, 0xc5, - 0xba, 0xe9, 0x3a, 0x46, 0xfc, 0x87, 0xf1, 0x51, - 0x29, 0xc9, 0x74, 0x69, 0xa5, 0x81, 0x4e, 0xca }, - { 0xb3, 0x1a, 0xf0, 0xc2, 0xe5, 0x1e, 0xa2, 0x1c, - 0x91, 0x04, 0xf9, 0x4f, 0xaa, 0x66, 0xe0, 0xcc, - 0xc0, 0x41, 0x34, 0xd5, 0x80, 0x9a, 0x2a, 0x26, - 0x70, 0xa3, 0xb7, 0xbc, 0x7d, 0xd9, 0x64, 0xf8 }, - { 0xb3, 0xf4, 0xb1, 0x6f, 0x8e, 0xce, 0xbb, 0x41, - 0x47, 0x4f, 0x92, 0x4f, 0xee, 0xf9, 0xb0, 0xbd, - 0x97, 0x9b, 0x36, 0x36, 0xc3, 0x4f, 0xf2, 0x72, - 0x3f, 0x67, 0x3c, 0x8e, 0xee, 0x2a, 0xf1, 0x52 }, - { 0xb5, 0xe5, 0xdc, 0xde, 0xcb, 0x8d, 0xeb, 0x27, - 0x13, 0x4f, 0x02, 0xa5, 0x18, 0x79, 0x43, 0x16, - 0xf0, 0x8f, 0xaf, 0x9c, 0x2b, 0x1f, 0xda, 0xd6, - 0xd4, 0x86, 0x61, 0xf5, 0x7e, 0xa6, 0x45, 0xd9 }, - { 0xb7, 0x06, 0xde, 0x1b, 0xd1, 0xee, 0x2f, 0x4c, - 0xec, 0x6c, 0xe0, 0x92, 0x02, 0x2b, 0x49, 0x32, - 0x81, 0xe2, 0x9a, 0x21, 0x73, 0x50, 0x8c, 0x9b, - 0xd0, 0xfb, 0xc2, 0xc3, 0xd9, 0x68, 0xe3, 0xe7 }, - { 0xb7, 0xa2, 0xae, 0x06, 0x06, 0xaa, 0x2c, 0xfb, - 0x27, 0x01, 0xb3, 0xb2, 0x77, 0xf4, 0xd7, 0x12, - 0x54, 0x70, 0x48, 0x7e, 0xfd, 0x94, 0x05, 0x85, - 0x7f, 0xfc, 0xe4, 0xbf, 0x29, 0x10, 0x5e, 0x68 }, - { 0xb8, 0x74, 0x36, 0x95, 0x1c, 0xec, 0x37, 0x7e, - 0xef, 0x73, 0xde, 0x4b, 0x74, 0xf2, 0x83, 0xc4, - 0x2b, 0x2c, 0xcb, 0x1c, 0xa3, 0x7c, 0x5b, 0x30, - 0xaa, 0xd6, 0x55, 0xa7, 0x40, 0x1a, 0x3d, 0x2f }, - { 0xb9, 0x8d, 0x83, 0x38, 0x55, 0xc3, 0x67, 0x88, - 0x62, 0xb6, 0x2f, 0x36, 0x50, 0xdb, 0x00, 0xa3, - 0x45, 0xf4, 0x6a, 0x0e, 0x8e, 0x01, 0x1a, 0x20, - 0x01, 0x3f, 0xd8, 0xed, 0xce, 0x25, 0x27, 0x0d }, - { 0xba, 0x51, 0xaf, 0xf5, 0xd5, 0xd3, 0x10, 0x5f, - 0x34, 0xa2, 0xb3, 0x3a, 0x83, 0xe3, 0xad, 0xfd, - 0x12, 0xd7, 0x9c, 0xa6, 0x05, 0x90, 0x9d, 0x96, - 0x03, 0x3e, 0x32, 0xa5, 0xcf, 0x2f, 0x71, 0xf6 }, - { 0xbb, 0x5c, 0xb3, 0x78, 0xb7, 0xb9, 0x48, 0x7f, - 0xa6, 0x1b, 0xc0, 0x91, 0x3d, 0xa1, 0xdf, 0x26, - 0xa1, 0xcf, 0xef, 0xf7, 0x45, 0x2d, 0x9b, 0xa3, - 0x6c, 0xac, 0x47, 0xa8, 0x5c, 0x7f, 0xf3, 0x48 }, - { 0xbc, 0x14, 0x2e, 0xba, 0xc2, 0x78, 0xa8, 0xfe, - 0x8c, 0xa8, 0xbc, 0x2c, 0x62, 0xfb, 0xcc, 0x40, - 0x17, 0xff, 0x24, 0x96, 0x98, 0xbe, 0xed, 0xfb, - 0x1e, 0xf3, 0x6f, 0x37, 0x5f, 0xb3, 0x9f, 0x72 }, - { 0xbd, 0x2e, 0x2f, 0x37, 0xc9, 0x66, 0xc3, 0x86, - 0xd9, 0x70, 0x44, 0xfd, 0xe3, 0xe3, 0xf9, 0x00, - 0xfb, 0x1a, 0x0b, 0x04, 0x03, 0xb5, 0x81, 0x72, - 0x5f, 0x34, 0xe3, 0xc1, 0x90, 0x05, 0x60, 0x56 }, - { 0xbe, 0xb9, 0x09, 0x0c, 0x92, 0xd1, 0x6b, 0xd0, - 0x5a, 0xf3, 0x91, 0x5a, 0x39, 0xcc, 0x2a, 0xfa, - 0x9f, 0x6a, 0x8a, 0x6f, 0xbe, 0xd4, 0xfe, 0x54, - 0xd9, 0xde, 0x32, 0x49, 0x23, 0xb3, 0x93, 0x5a }, - { 0xbf, 0x38, 0xe6, 0xae, 0x32, 0x0f, 0x69, 0x16, - 0x16, 0x0d, 0xa6, 0x06, 0x86, 0x83, 0xbf, 0x49, - 0xf2, 0xb2, 0x2b, 0x25, 0x24, 0x84, 0x63, 0x68, - 0xf5, 0x04, 0x51, 0x81, 0x52, 0x40, 0x25, 0x9a }, - { 0xbf, 0x60, 0xae, 0xb3, 0x91, 0xc0, 0xfb, 0xd0, - 0x49, 0x53, 0x52, 0x6d, 0xa9, 0xfd, 0x59, 0x96, - 0x9a, 0x82, 0xf1, 0xee, 0x81, 0xa7, 0x97, 0x98, - 0xa4, 0x17, 0x1e, 0x14, 0x59, 0x39, 0x19, 0x67 }, - { 0xbf, 0xf4, 0x3a, 0x97, 0x20, 0x48, 0x2d, 0x13, - 0x4c, 0xd5, 0xee, 0x8a, 0x88, 0x99, 0xe1, 0xa7, - 0x36, 0xbf, 0x54, 0xa2, 0xb7, 0x86, 0x26, 0x9c, - 0x0d, 0xcb, 0x8b, 0xa1, 0x92, 0xa8, 0x1f, 0xa4 }, - { 0xc0, 0x09, 0xa1, 0xbe, 0x5b, 0xe8, 0xaf, 0xb5, - 0x25, 0x8e, 0x12, 0x85, 0x5c, 0x64, 0xd0, 0x4d, - 0x13, 0xe8, 0xcc, 0xc4, 0x7b, 0x02, 0xbf, 0x3b, - 0x51, 0xc6, 0xe1, 0x18, 0x05, 0xae, 0xec, 0xeb }, - { 0xc0, 0x9f, 0xfa, 0x0e, 0xdd, 0x16, 0xba, 0x55, - 0xf2, 0x3c, 0xea, 0xf7, 0x2b, 0x11, 0x34, 0xe9, - 0x28, 0xdb, 0xa1, 0xc2, 0x34, 0x5a, 0x5a, 0xb5, - 0x63, 0x1e, 0x25, 0x41, 0x24, 0x05, 0x4a, 0xdb }, - { 0xc0, 0xab, 0xd1, 0xc3, 0x56, 0x2f, 0xbc, 0x7f, - 0xf7, 0xbd, 0x38, 0x95, 0x54, 0x60, 0xc3, 0xfc, - 0x43, 0x55, 0x0d, 0x97, 0x7f, 0x25, 0xe3, 0x43, - 0xd4, 0x9c, 0xd4, 0xaf, 0xad, 0xf2, 0x09, 0x3c }, - { 0xc0, 0xfe, 0xb7, 0x2a, 0x5f, 0x33, 0x16, 0x5c, - 0x0d, 0xc7, 0xc4, 0x24, 0x7e, 0x23, 0xf3, 0x8c, - 0xc6, 0x1f, 0x25, 0x24, 0x42, 0xb2, 0xf6, 0x13, - 0x40, 0x92, 0xde, 0x3b, 0xad, 0x7e, 0x45, 0x0d }, - { 0xc1, 0x77, 0x12, 0x97, 0xa4, 0xe8, 0xdc, 0x53, - 0x75, 0x19, 0x5e, 0x1b, 0x63, 0x04, 0x2b, 0x59, - 0x19, 0x09, 0xf1, 0xd7, 0xeb, 0x5d, 0x25, 0xf2, - 0x97, 0xae, 0x7a, 0x61, 0xc1, 0x53, 0x8f, 0x9e }, - { 0xc1, 0x86, 0xbe, 0x26, 0xe4, 0x47, 0x89, 0x7c, - 0x48, 0x3c, 0x43, 0xfd, 0xc0, 0x86, 0xe2, 0x60, - 0x74, 0x17, 0xeb, 0x3e, 0xa7, 0x88, 0xec, 0x03, - 0x10, 0xa7, 0x9d, 0xa9, 0x24, 0x1d, 0x16, 0xde }, - { 0xc1, 0xde, 0x5f, 0xa3, 0x92, 0x13, 0x68, 0x58, - 0x11, 0xa5, 0xba, 0x93, 0x12, 0x1d, 0xe7, 0xa3, - 0x95, 0x98, 0x4e, 0x84, 0x44, 0x4e, 0x58, 0xf1, - 0x63, 0xb7, 0xa6, 0x20, 0xae, 0x3b, 0xbf, 0xa8 }, - { 0xc2, 0xad, 0xdf, 0x99, 0xcf, 0xc4, 0x2c, 0xe0, - 0xe5, 0xa0, 0x93, 0xbc, 0xbf, 0x87, 0x40, 0x7c, - 0x61, 0x1f, 0x9d, 0x0a, 0xbf, 0x2a, 0x35, 0xd6, - 0xe8, 0x03, 0xa3, 0x8e, 0xcb, 0x92, 0xc7, 0xb3 }, - { 0xc2, 0xe7, 0x92, 0x11, 0x6a, 0x05, 0x00, 0x00, - 0xbd, 0x47, 0x59, 0x1d, 0x93, 0x04, 0x71, 0xe6, - 0x17, 0x4c, 0x93, 0x85, 0xf5, 0xdc, 0x32, 0xb7, - 0x62, 0x31, 0x65, 0x5f, 0xc8, 0x5e, 0x22, 0xe2 }, - { 0xc3, 0x79, 0x03, 0xc5, 0x3a, 0xe6, 0x02, 0xec, - 0x96, 0x9e, 0xc3, 0x3f, 0x63, 0xfe, 0x9a, 0xb2, - 0x0c, 0x39, 0x5f, 0x83, 0x0d, 0x30, 0xe4, 0xee, - 0x9d, 0x8d, 0xd9, 0x05, 0x92, 0x1e, 0xc1, 0xa0 }, - { 0xc3, 0xcf, 0x54, 0x16, 0xa5, 0x31, 0xaf, 0x4b, - 0xfa, 0xe8, 0x9c, 0x45, 0x14, 0x3f, 0x20, 0xcc, - 0x1b, 0x3e, 0x18, 0x1d, 0x29, 0xc2, 0xd0, 0xe8, - 0xff, 0x7d, 0x3f, 0x2a, 0x66, 0xb1, 0x82, 0xfe }, - { 0xc4, 0x98, 0xa1, 0xb6, 0x9f, 0x54, 0x40, 0x86, - 0x17, 0x47, 0x47, 0x71, 0x5a, 0x27, 0x4d, 0x3f, - 0xb5, 0x90, 0x19, 0xbe, 0x09, 0x21, 0x31, 0xbc, - 0xfa, 0xa8, 0x3a, 0x39, 0x5f, 0x7e, 0x57, 0x3c }, - { 0xc4, 0xe2, 0x8d, 0xd8, 0x3f, 0xe3, 0x0c, 0x96, - 0x33, 0x8c, 0xef, 0x77, 0x73, 0xc6, 0xdf, 0xca, - 0x6c, 0xe4, 0xfa, 0x96, 0x41, 0xbe, 0xab, 0x38, - 0x05, 0xa8, 0xef, 0xb6, 0xcd, 0xc3, 0xcf, 0x0a }, - { 0xc5, 0x00, 0xb8, 0x3f, 0x3e, 0x06, 0x6c, 0xd1, - 0xdd, 0x0e, 0xbc, 0xd7, 0x3d, 0xd4, 0x01, 0x61, - 0xb9, 0x25, 0x9a, 0xa7, 0x7a, 0xb8, 0xa6, 0x47, - 0xe8, 0x57, 0x1f, 0xf3, 0x37, 0xcf, 0x94, 0x6d }, - { 0xc5, 0x29, 0x5b, 0xa6, 0xe2, 0x7e, 0x72, 0x10, - 0x22, 0xfe, 0xb2, 0x1e, 0x78, 0xeb, 0x7b, 0x03, - 0x57, 0xc9, 0xcd, 0x56, 0x5b, 0xd0, 0xe5, 0x96, - 0x72, 0xf6, 0x66, 0x34, 0x2b, 0x79, 0x94, 0x9d }, - { 0xc6, 0x12, 0x75, 0x6b, 0xa5, 0x42, 0x34, 0x4a, - 0xdc, 0x1b, 0x80, 0xe9, 0x38, 0x84, 0x5a, 0x1e, - 0xd6, 0xe9, 0x38, 0xfe, 0xf4, 0x0d, 0x04, 0xec, - 0x86, 0x55, 0x8f, 0x4b, 0x21, 0x05, 0x2f, 0xd2 }, - { 0xc6, 0x17, 0xe0, 0x85, 0x5b, 0xf1, 0x4f, 0xbf, - 0x21, 0xaf, 0x00, 0x82, 0x25, 0xca, 0xbe, 0x40, - 0x4f, 0x73, 0x8c, 0x27, 0x8a, 0x4a, 0x42, 0x87, - 0xf1, 0xee, 0x38, 0x01, 0x27, 0xc5, 0x61, 0xfa }, - { 0xc6, 0xa4, 0x24, 0xbf, 0x7c, 0xfe, 0x31, 0x72, - 0x74, 0x7a, 0x47, 0x14, 0xa0, 0xef, 0xb9, 0x17, - 0x93, 0x8c, 0x5e, 0xbd, 0x59, 0x12, 0x9d, 0xed, - 0x7a, 0x81, 0x18, 0xc7, 0xf6, 0x59, 0xd1, 0x33 }, - { 0xc6, 0xad, 0x1d, 0x7a, 0x14, 0x1a, 0x91, 0x75, - 0x2d, 0x31, 0xfb, 0xc1, 0x06, 0x16, 0xbf, 0x1c, - 0xa2, 0xfb, 0x5b, 0x02, 0xe8, 0x46, 0xb5, 0x9e, - 0x63, 0x34, 0x6b, 0x31, 0x92, 0xa7, 0x52, 0x92 }, - { 0xc7, 0x01, 0x83, 0x64, 0x38, 0xf3, 0x7b, 0xea, - 0x8a, 0x88, 0x16, 0x10, 0x63, 0x70, 0x86, 0xf8, - 0x8d, 0x9a, 0x11, 0x5e, 0x00, 0x92, 0x46, 0xd2, - 0x7f, 0x48, 0x9f, 0xa7, 0x18, 0x51, 0x88, 0xa8 }, - { 0xc7, 0xff, 0x8e, 0xfd, 0xec, 0xdf, 0x00, 0xd1, - 0xfc, 0x8d, 0x55, 0x2d, 0x2a, 0x70, 0x70, 0xe5, - 0xe3, 0x3d, 0x42, 0xe5, 0x90, 0xf5, 0x86, 0xc6, - 0xae, 0xde, 0x03, 0x2b, 0x2d, 0x86, 0x7b, 0xd5 }, - { 0xc7, 0xff, 0xb4, 0x9f, 0xbc, 0x94, 0x72, 0x24, - 0x5c, 0x8e, 0x95, 0xde, 0x62, 0x9a, 0xf5, 0xc1, - 0xbf, 0xea, 0xc5, 0x50, 0x04, 0xc1, 0x54, 0x82, - 0x3a, 0x58, 0xba, 0xe8, 0x05, 0x6e, 0x3c, 0x64 }, - { 0xc8, 0x37, 0xd6, 0xf2, 0xab, 0x14, 0x79, 0x91, - 0x42, 0xed, 0x3c, 0x79, 0xbe, 0xd9, 0x44, 0x1e, - 0x92, 0x50, 0xbd, 0x05, 0x20, 0x25, 0xad, 0x8a, - 0xf4, 0x40, 0x41, 0xac, 0x19, 0xef, 0xbb, 0x4c }, - { 0xc9, 0x72, 0xf4, 0xf9, 0x6e, 0x71, 0x33, 0xe1, - 0x6e, 0x55, 0x57, 0xa0, 0x57, 0xb1, 0xd4, 0x2b, - 0xa9, 0x2d, 0x98, 0x5c, 0xae, 0xe7, 0x3c, 0xaf, - 0xda, 0xeb, 0x55, 0xec, 0xa2, 0xe4, 0xab, 0xb0 }, - { 0xc9, 0x78, 0x37, 0x2c, 0x9e, 0x11, 0x60, 0x71, - 0xb6, 0x1b, 0x90, 0x92, 0xa9, 0xaa, 0x96, 0x81, - 0x62, 0x36, 0x55, 0xa6, 0x6f, 0x4f, 0xcb, 0xc4, - 0xd3, 0xa6, 0x7e, 0xfd, 0x56, 0x72, 0x48, 0x30 }, - { 0xca, 0x55, 0x6f, 0x82, 0xc9, 0x68, 0x4c, 0x9a, - 0xf3, 0x55, 0x7d, 0x3e, 0x2d, 0x88, 0xaf, 0x92, - 0xed, 0x25, 0x9c, 0x20, 0xff, 0xd1, 0xdd, 0xe9, - 0xf7, 0x9d, 0x6b, 0x92, 0xc6, 0x1e, 0xe1, 0xb9 }, - { 0xca, 0xbe, 0x25, 0x56, 0xf1, 0xbb, 0x56, 0x57, - 0x0c, 0xef, 0x3a, 0x87, 0x03, 0x32, 0x71, 0xa1, - 0xf2, 0x1d, 0x09, 0xb7, 0xfd, 0x04, 0x12, 0x83, - 0x18, 0xe5, 0xe7, 0xbc, 0xe3, 0xa2, 0x01, 0xe2 }, - { 0xca, 0xdc, 0xd5, 0xae, 0x1b, 0x75, 0x6a, 0xb7, - 0x41, 0xb3, 0x56, 0x9c, 0x42, 0xa5, 0x41, 0x1f, - 0x09, 0x3e, 0x4e, 0x1f, 0x01, 0x2e, 0xc5, 0x79, - 0x91, 0xcb, 0xd6, 0xdb, 0xe0, 0x8f, 0xaa, 0xc1 }, - { 0xcb, 0x7a, 0x43, 0x8d, 0x16, 0xe4, 0xa5, 0xf3, - 0xc5, 0x6f, 0xdf, 0x19, 0x1e, 0x1d, 0xaf, 0x9f, - 0x32, 0x5c, 0x65, 0x0b, 0xd6, 0x2f, 0x07, 0xc4, - 0x67, 0x71, 0x72, 0x07, 0x35, 0x1a, 0xe3, 0x29 }, - { 0xcc, 0x30, 0xd8, 0x19, 0xde, 0x54, 0x05, 0xf6, - 0x49, 0xc8, 0xb7, 0xa8, 0x14, 0x8f, 0x26, 0xd7, - 0x71, 0x08, 0x3e, 0xc5, 0x18, 0xf9, 0xb6, 0x6f, - 0xf5, 0x47, 0xf2, 0x82, 0x2d, 0x11, 0x93, 0x6d }, - { 0xcc, 0x65, 0xcd, 0xc5, 0x33, 0x62, 0xd4, 0x21, - 0x62, 0x7e, 0xae, 0xf5, 0xd0, 0xc8, 0xe4, 0xc4, - 0xe2, 0x40, 0xad, 0xe0, 0xc9, 0xd4, 0x20, 0xbe, - 0x67, 0x1e, 0x70, 0xf0, 0xfb, 0xac, 0x8d, 0x0a }, - { 0xcd, 0xb1, 0x62, 0x53, 0xd2, 0x2e, 0xd5, 0xd4, - 0x26, 0xcf, 0xa1, 0xb0, 0x5c, 0xec, 0xd8, 0x6e, - 0xf1, 0xb7, 0xde, 0xaa, 0x07, 0xc5, 0x70, 0x5e, - 0xbb, 0xaf, 0x7d, 0x9a, 0x80, 0x7d, 0x56, 0x16 }, - { 0xcd, 0xc0, 0x39, 0xf3, 0xa2, 0xd1, 0xbb, 0xa5, - 0xe8, 0x09, 0x4e, 0x55, 0x23, 0xcf, 0x60, 0x47, - 0x09, 0x7d, 0x4b, 0x3c, 0xd4, 0xec, 0x4e, 0xd6, - 0xaa, 0x8e, 0xb7, 0xb4, 0xd8, 0xb5, 0x77, 0x7d }, - { 0xcd, 0xc4, 0xea, 0x92, 0x02, 0xe3, 0x3e, 0xdd, - 0x0f, 0x2d, 0x3a, 0xe8, 0x6a, 0xca, 0xc7, 0xfb, - 0x25, 0x35, 0x4b, 0x02, 0x23, 0x5b, 0x09, 0x33, - 0xaa, 0x81, 0xa3, 0x13, 0xb5, 0xfd, 0xfe, 0xec }, - { 0xce, 0x4c, 0x2f, 0x8f, 0x16, 0x46, 0x8a, 0x58, - 0x88, 0xe9, 0x0f, 0x73, 0x4e, 0x4d, 0x22, 0x02, - 0xdf, 0xad, 0xbf, 0xa6, 0x6f, 0x5b, 0x35, 0x75, - 0x2b, 0xaa, 0x76, 0x21, 0xa7, 0x60, 0xb0, 0x88 }, - { 0xce, 0x81, 0x44, 0x58, 0x54, 0x03, 0x1f, 0x3d, - 0x0f, 0x5c, 0x88, 0x75, 0x46, 0x4d, 0xcd, 0x5b, - 0xa6, 0xc8, 0x90, 0xf4, 0x49, 0xb3, 0x20, 0x7b, - 0xca, 0x2b, 0xc9, 0x61, 0x82, 0x2d, 0x27, 0xc4 }, - { 0xcf, 0xa0, 0xc0, 0x0c, 0xb2, 0xfb, 0x4b, 0x85, - 0x7a, 0xad, 0x22, 0xb1, 0x3a, 0x90, 0xe3, 0x46, - 0xa0, 0x3e, 0x6b, 0x79, 0xab, 0xd5, 0xd2, 0x75, - 0xb5, 0x43, 0x24, 0x68, 0x17, 0x92, 0xd6, 0xd1 }, - { 0xd0, 0xf5, 0x93, 0xc1, 0xa8, 0x1b, 0x1e, 0xf8, - 0x51, 0x69, 0x81, 0xee, 0x56, 0xf1, 0xd5, 0x98, - 0xa2, 0xa6, 0x03, 0x48, 0x8c, 0x67, 0x8c, 0x1b, - 0x7b, 0xbe, 0xa6, 0x44, 0x6b, 0x00, 0x83, 0xad }, - { 0xd2, 0x90, 0x3c, 0xa2, 0x55, 0x17, 0x27, 0xed, - 0x01, 0x71, 0xcc, 0x4a, 0x43, 0xb3, 0xca, 0xe0, - 0x09, 0xb7, 0x47, 0xb9, 0xf4, 0xf8, 0x48, 0x72, - 0x92, 0x27, 0xbf, 0x59, 0x02, 0xf2, 0x3e, 0x47 }, - { 0xd2, 0xe8, 0xa1, 0x23, 0x7a, 0x93, 0xf5, 0x78, - 0xd1, 0xba, 0x8f, 0x09, 0xe4, 0xff, 0x10, 0x7b, - 0x62, 0x35, 0x78, 0x85, 0x42, 0xaa, 0x61, 0x83, - 0xd1, 0x76, 0xdb, 0xf1, 0xc8, 0x8d, 0xcf, 0xb6 }, - { 0xd5, 0x04, 0x88, 0x96, 0x86, 0x07, 0x29, 0xa8, - 0xfa, 0x5d, 0x23, 0x57, 0x81, 0x2b, 0xa5, 0x6c, - 0xbe, 0x84, 0xc9, 0xab, 0x7d, 0x14, 0xdf, 0x47, - 0x64, 0xe0, 0xb6, 0x62, 0x0f, 0xa3, 0x20, 0x10 }, - { 0xd5, 0x41, 0xa7, 0x7e, 0x13, 0x6e, 0x9e, 0x70, - 0x3b, 0xb9, 0x9f, 0x80, 0x68, 0xcf, 0xee, 0x86, - 0xa4, 0xb9, 0xf0, 0x89, 0xe0, 0x2d, 0x0c, 0x6c, - 0xb6, 0xd4, 0xa3, 0x94, 0x6c, 0x6b, 0x16, 0x7a }, - { 0xd5, 0x83, 0x94, 0x96, 0xcd, 0xc8, 0x5b, 0xe3, - 0xd1, 0xf1, 0xac, 0x65, 0x2e, 0xfa, 0x92, 0xbe, - 0xa3, 0xb0, 0x61, 0xc1, 0x3d, 0xad, 0x5a, 0x82, - 0x11, 0x22, 0xcf, 0xe9, 0xc7, 0x1a, 0x5a, 0x32 }, - { 0xd5, 0xa4, 0xee, 0x46, 0x95, 0xb5, 0x65, 0xa6, - 0x7e, 0x50, 0x48, 0x66, 0xfe, 0x5b, 0xa3, 0xc0, - 0xed, 0xca, 0xee, 0xd5, 0x2a, 0xd0, 0xaf, 0x07, - 0xe6, 0x79, 0x17, 0x73, 0x85, 0x12, 0xc8, 0xf5 }, - { 0xd6, 0x25, 0xc0, 0x59, 0x2b, 0x25, 0xdc, 0x03, - 0xaa, 0x7e, 0x87, 0x8e, 0x6a, 0x85, 0x09, 0x1b, - 0xaa, 0x07, 0x8d, 0x26, 0x8b, 0xbd, 0xb4, 0x9f, - 0x09, 0x67, 0x94, 0x08, 0x61, 0x2d, 0x1e, 0xfe }, - { 0xd6, 0xd1, 0xb3, 0x5c, 0xbc, 0x12, 0xfb, 0x1c, - 0x70, 0xa0, 0xb4, 0x3b, 0xa5, 0x9a, 0xb3, 0xd3, - 0x22, 0x5f, 0x37, 0x32, 0x64, 0xdd, 0x87, 0xfb, - 0xca, 0x00, 0x61, 0xec, 0x1c, 0x4d, 0xa1, 0x1a }, - { 0xd7, 0x32, 0x49, 0x74, 0xb5, 0x60, 0x09, 0x62, - 0x17, 0x61, 0xf7, 0xc0, 0xff, 0x68, 0x9d, 0xde, - 0x47, 0x74, 0x99, 0x85, 0xe1, 0xee, 0x8b, 0x5c, - 0x89, 0x61, 0xdd, 0x8f, 0x6a, 0x78, 0xbb, 0xf5 }, - { 0xd9, 0x2e, 0x3e, 0xe3, 0x82, 0xc8, 0xdc, 0xaf, - 0xa0, 0x39, 0x3d, 0x9f, 0x9a, 0x00, 0xbf, 0x4c, - 0xd9, 0xd5, 0x64, 0x26, 0x2b, 0x18, 0x0f, 0x68, - 0x16, 0x0b, 0x20, 0x34, 0xc5, 0x44, 0xd1, 0x0a }, - { 0xd9, 0x65, 0xf7, 0x41, 0x62, 0x04, 0xda, 0x83, - 0x1a, 0xf6, 0x6b, 0xfa, 0x8f, 0x90, 0xd1, 0x41, - 0xe9, 0x93, 0xf0, 0x00, 0x21, 0x33, 0xf2, 0x8d, - 0xe9, 0x7f, 0x56, 0x4a, 0x1d, 0x60, 0x4e, 0xcc }, - { 0xda, 0xdf, 0x97, 0x13, 0x34, 0x14, 0xad, 0x51, - 0x3f, 0xc7, 0x50, 0x14, 0xe9, 0x56, 0x65, 0xda, - 0xd7, 0x76, 0xb1, 0x50, 0x4b, 0x15, 0x67, 0x43, - 0x4f, 0xd8, 0x2a, 0x79, 0xa2, 0x20, 0xe9, 0xa1 }, - { 0xda, 0xff, 0xd4, 0x05, 0x6f, 0xc3, 0x68, 0xfa, - 0x64, 0x8d, 0x0e, 0xd8, 0x9b, 0x5d, 0xe0, 0xee, - 0x93, 0x1f, 0x1b, 0x33, 0x84, 0x78, 0xab, 0xf5, - 0x69, 0x29, 0xa9, 0x4d, 0x3b, 0xd6, 0x1d, 0x46 }, - { 0xde, 0xcd, 0xb9, 0xfc, 0x1d, 0xde, 0xc9, 0x7e, - 0x09, 0xc3, 0x02, 0x6a, 0xce, 0xb7, 0x6b, 0xda, - 0xe9, 0xde, 0xb6, 0x62, 0x75, 0x1d, 0xda, 0x34, - 0x9d, 0x2f, 0xa6, 0xbd, 0x75, 0xca, 0x59, 0x14 }, - { 0xde, 0xd1, 0x9a, 0xd5, 0xde, 0x99, 0x65, 0xd9, - 0x22, 0x5c, 0x1b, 0xba, 0x5f, 0xb4, 0xd8, 0x90, - 0xc8, 0xe5, 0xc0, 0x35, 0xe4, 0x85, 0x27, 0x52, - 0xb6, 0x69, 0xb0, 0x40, 0x0f, 0x24, 0xf1, 0x74 }, - { 0xdf, 0x30, 0xbf, 0x8d, 0x1b, 0xf9, 0x37, 0x8e, - 0x43, 0x3e, 0xf9, 0xe1, 0xb3, 0xa2, 0x28, 0xa0, - 0x7e, 0x36, 0x58, 0xa5, 0xbc, 0x43, 0x88, 0x23, - 0x45, 0x4d, 0xb0, 0x6a, 0x67, 0x94, 0x4c, 0x6e }, - { 0xe0, 0x0b, 0xd7, 0x86, 0xd1, 0xf2, 0xf4, 0x46, - 0xc4, 0xba, 0x83, 0x99, 0xd4, 0xd8, 0xd5, 0xa0, - 0xd1, 0x98, 0x57, 0x8f, 0x42, 0x99, 0xfd, 0xfd, - 0xaf, 0xf7, 0x8c, 0x3f, 0x67, 0x71, 0xf3, 0x94 }, - { 0xe0, 0x8b, 0x2c, 0xc2, 0x7a, 0xe8, 0xe2, 0xef, - 0x1a, 0x33, 0x01, 0x7a, 0x9a, 0xc2, 0x5d, 0xda, - 0xfb, 0x5e, 0xa1, 0x12, 0xc9, 0x56, 0xb0, 0x02, - 0xfe, 0x6c, 0x79, 0x80, 0x14, 0xaa, 0x90, 0x65 }, - { 0xe1, 0xb2, 0xe8, 0x6b, 0x0d, 0xa8, 0x69, 0xe9, - 0x25, 0x26, 0x6c, 0x1b, 0x56, 0x88, 0x34, 0x5a, - 0x17, 0xb0, 0xf6, 0xe2, 0xa2, 0x14, 0x94, 0x54, - 0x7e, 0xac, 0x09, 0x7c, 0x8b, 0xf5, 0x3c, 0x5a }, - { 0xe1, 0xd6, 0x44, 0xa0, 0x96, 0xbd, 0x8a, 0x6c, - 0xac, 0xbb, 0xda, 0x3e, 0x7f, 0xc3, 0x38, 0xea, - 0xdd, 0xc1, 0x2f, 0x23, 0x6c, 0x72, 0x61, 0xe4, - 0x5f, 0x8a, 0xd2, 0xd8, 0x42, 0x42, 0x4f, 0x72 }, - { 0xe2, 0x24, 0x10, 0xb5, 0xa6, 0x7f, 0xed, 0xc2, - 0x64, 0x69, 0x4c, 0x44, 0x9d, 0x84, 0xfa, 0x1a, - 0x02, 0xbc, 0x8b, 0x21, 0x28, 0xc1, 0x25, 0x60, - 0x71, 0x58, 0xc9, 0x1b, 0x05, 0x38, 0x6c, 0x6a }, - { 0xe2, 0xa8, 0x47, 0xc3, 0xf0, 0x9b, 0xeb, 0x6f, - 0x05, 0x68, 0x6f, 0x17, 0x79, 0x1b, 0x05, 0xf1, - 0xfe, 0x25, 0xf7, 0x71, 0x86, 0x9c, 0x42, 0x63, - 0xa5, 0x5b, 0x94, 0x18, 0x77, 0xe4, 0x79, 0x04 }, - { 0xe2, 0xf3, 0x9a, 0x9d, 0x48, 0xa3, 0x22, 0x10, - 0x55, 0xb3, 0xc8, 0xa3, 0xeb, 0x14, 0x39, 0xd6, - 0xb8, 0x73, 0x01, 0x3e, 0xe4, 0xd0, 0x97, 0x12, - 0x20, 0x64, 0xf2, 0x7e, 0xc0, 0x3d, 0xd4, 0xda }, - { 0xe2, 0xf5, 0xde, 0x57, 0xcd, 0x67, 0x24, 0x9a, - 0x7e, 0x1f, 0x45, 0x5b, 0x85, 0xc0, 0x6f, 0x0d, - 0x80, 0x9e, 0x75, 0xa5, 0x5c, 0x6b, 0x05, 0x48, - 0x16, 0xe0, 0x19, 0x89, 0x9a, 0x3a, 0x02, 0xff }, - { 0xe4, 0xf1, 0xde, 0x31, 0xcd, 0xaa, 0x6d, 0x9e, - 0xb1, 0xaa, 0xfd, 0x10, 0x81, 0x27, 0xa2, 0xf0, - 0xa8, 0xfb, 0x6d, 0xa8, 0x5a, 0x04, 0x14, 0xad, - 0x24, 0x99, 0x47, 0xc4, 0x8d, 0x24, 0x92, 0xc5 }, - { 0xe6, 0x44, 0xd1, 0x1c, 0x37, 0x07, 0x0f, 0x89, - 0x69, 0x33, 0x08, 0x17, 0x8d, 0x6b, 0xe4, 0x95, - 0x94, 0x96, 0x92, 0xc1, 0xfb, 0xeb, 0x30, 0xed, - 0x32, 0x9b, 0x74, 0x02, 0x7f, 0xcf, 0xfd, 0x48 }, - { 0xe6, 0xb0, 0xf2, 0xe2, 0x5b, 0xd5, 0x16, 0xe4, - 0xbb, 0xa3, 0x7a, 0x2b, 0xf2, 0xe2, 0xc7, 0x2a, - 0x1e, 0x53, 0x9c, 0x60, 0x30, 0xf3, 0xcf, 0x9b, - 0xbe, 0x5e, 0x79, 0x72, 0x8d, 0x68, 0x64, 0x78 }, - { 0xe6, 0xe5, 0x4d, 0xe7, 0xb4, 0x97, 0x54, 0xd3, - 0x57, 0xb0, 0xa8, 0xd9, 0x4a, 0x4d, 0x4f, 0x80, - 0xac, 0xd1, 0x99, 0x4c, 0xcc, 0x1c, 0x99, 0x08, - 0xe9, 0xf0, 0xd9, 0x21, 0xe4, 0x28, 0xb8, 0x38 }, - { 0xe7, 0x0c, 0xbb, 0x7a, 0xf7, 0xaa, 0x20, 0xb9, - 0x89, 0x0b, 0xc1, 0xf9, 0xfa, 0x00, 0xd8, 0x09, - 0x0b, 0x5a, 0xc9, 0x82, 0x5e, 0xa9, 0xd2, 0xfd, - 0xf7, 0x7c, 0xa4, 0xda, 0xe9, 0x44, 0x51, 0xb2 }, - { 0xe8, 0x16, 0xf9, 0x92, 0x94, 0xa1, 0x3a, 0xc2, - 0xfa, 0x2b, 0xfb, 0x76, 0xc2, 0x2d, 0xfa, 0x71, - 0xbc, 0x3d, 0xa4, 0x8f, 0x67, 0x1e, 0xf7, 0x7c, - 0x00, 0xaa, 0x8e, 0x45, 0x9b, 0x7c, 0xc8, 0x2a }, - { 0xe9, 0xd4, 0x98, 0x51, 0xbf, 0x78, 0x37, 0x6d, - 0x54, 0x08, 0x2d, 0x1e, 0xb8, 0x2b, 0xd2, 0xdc, - 0x96, 0x82, 0x07, 0x09, 0xb7, 0x77, 0x2d, 0x3f, - 0xbc, 0xa3, 0x90, 0x08, 0x8b, 0x54, 0xc4, 0x53 }, - { 0xe9, 0xf5, 0x71, 0xc7, 0x71, 0x64, 0xab, 0xea, - 0xe1, 0x85, 0x28, 0x37, 0x5c, 0xfd, 0xc7, 0x21, - 0x9a, 0x6b, 0xde, 0x46, 0x1b, 0x19, 0x73, 0xbe, - 0x2b, 0xb8, 0xbd, 0xf0, 0xda, 0x78, 0xb2, 0xb4 }, - { 0xeb, 0x11, 0x63, 0xaa, 0xef, 0xe8, 0xfd, 0x88, - 0xe1, 0x32, 0x7b, 0x48, 0xa9, 0xc0, 0x06, 0x2e, - 0x06, 0xf0, 0xa6, 0xea, 0xa0, 0xa0, 0x18, 0x24, - 0x7f, 0x9f, 0xa4, 0xe3, 0x4e, 0x3a, 0x47, 0x4c }, - { 0xec, 0x4b, 0xbd, 0xeb, 0x15, 0x12, 0x1d, 0x96, - 0x76, 0x4d, 0x6c, 0x01, 0xb2, 0x7e, 0xd5, 0xae, - 0x86, 0x46, 0x5c, 0x46, 0xd5, 0xa4, 0x0e, 0x34, - 0xae, 0xfc, 0x09, 0x2d, 0x3e, 0x8b, 0xb1, 0x76 }, - { 0xec, 0x5f, 0xa4, 0x73, 0x12, 0x1e, 0x3f, 0x49, - 0xf0, 0x95, 0x3a, 0x2a, 0x91, 0x83, 0x39, 0xe3, - 0x6f, 0x3c, 0xb6, 0xb8, 0xd8, 0xb8, 0x9e, 0x91, - 0x74, 0x23, 0xda, 0xce, 0xac, 0xe6, 0xd5, 0x8a }, - { 0xec, 0xce, 0x4e, 0x52, 0x82, 0xfd, 0x2e, 0xe0, - 0x03, 0xa4, 0x03, 0x2c, 0x80, 0xd3, 0x32, 0x1a, - 0x69, 0x47, 0x25, 0x98, 0x94, 0x59, 0x09, 0xcb, - 0x25, 0x55, 0x7a, 0xa8, 0x47, 0x74, 0x2d, 0xdf }, - { 0xed, 0x5b, 0xb8, 0x6a, 0x95, 0xa5, 0xfe, 0x2b, - 0x17, 0x08, 0xf2, 0x56, 0x75, 0x4a, 0x89, 0xc4, - 0x29, 0x67, 0x9b, 0x30, 0x75, 0x8e, 0xe0, 0x12, - 0x2b, 0x9e, 0x50, 0x85, 0x8d, 0xe2, 0x10, 0x4b }, - { 0xed, 0xc1, 0xbf, 0x3e, 0xfb, 0xf7, 0xe1, 0xd9, - 0x5e, 0x19, 0xc5, 0x5e, 0xca, 0xe7, 0x7e, 0x83, - 0x69, 0x46, 0xab, 0x0a, 0x26, 0xa7, 0x8e, 0x32, - 0xa4, 0x72, 0xc9, 0xd3, 0x6c, 0x69, 0xce, 0xcd }, - { 0xed, 0xf4, 0xdf, 0x97, 0x2c, 0xad, 0x6c, 0x47, - 0x0b, 0xab, 0x5d, 0x66, 0x42, 0xf6, 0x60, 0xb8, - 0x42, 0xd6, 0xc9, 0x73, 0x07, 0x44, 0x93, 0xe4, - 0xef, 0x1b, 0xbf, 0x31, 0x1a, 0x92, 0x79, 0x95 }, - { 0xee, 0x34, 0xe1, 0xa1, 0x9b, 0xc8, 0x89, 0xf8, - 0x5f, 0x7f, 0x0f, 0x5b, 0xf8, 0x72, 0xb1, 0xac, - 0x56, 0x5e, 0xc6, 0xf1, 0x9d, 0xb5, 0x17, 0xba, - 0x4e, 0xd7, 0x55, 0xc4, 0x18, 0x5f, 0x69, 0xe8 }, - { 0xef, 0x36, 0xa2, 0x29, 0x89, 0x65, 0xe4, 0x98, - 0x84, 0x59, 0xb9, 0x21, 0x6a, 0xb3, 0x3c, 0x3c, - 0xa8, 0x42, 0xd2, 0x16, 0x83, 0xb6, 0x2a, 0x2b, - 0xf1, 0x53, 0x0d, 0x30, 0xb0, 0xae, 0x78, 0x25 }, - { 0xef, 0xaf, 0xca, 0x84, 0x90, 0x30, 0x7b, 0x0f, - 0x62, 0x2b, 0xf4, 0x3a, 0x0e, 0xb3, 0xc5, 0x1a, - 0xcb, 0xdd, 0xde, 0xdc, 0x23, 0x92, 0xf1, 0x61, - 0xac, 0xed, 0x16, 0x71, 0xa6, 0x53, 0x60, 0x7e }, - { 0xef, 0xd1, 0xe0, 0xe7, 0x3f, 0xa8, 0x71, 0x00, - 0xb7, 0x6a, 0x93, 0x23, 0x49, 0xc4, 0x5d, 0x09, - 0xb2, 0x8b, 0x2d, 0x8a, 0x00, 0x17, 0x19, 0xa5, - 0x8d, 0xfa, 0xcc, 0x74, 0x84, 0xc7, 0xcf, 0x42 }, - { 0xf0, 0x6b, 0x35, 0x95, 0x36, 0xd1, 0x34, 0x32, - 0x8b, 0x36, 0x00, 0x4d, 0xa9, 0xa9, 0x19, 0x0c, - 0x3a, 0x76, 0x69, 0xe8, 0x27, 0x8d, 0xb9, 0xf7, - 0x58, 0x57, 0xc4, 0x8d, 0x64, 0x4b, 0xe2, 0x03 }, - { 0xf0, 0xcf, 0xc7, 0x79, 0x13, 0x39, 0x7d, 0xe2, - 0x38, 0xed, 0xb5, 0x9f, 0x0f, 0x99, 0x23, 0xc6, - 0xd4, 0x11, 0x0a, 0x4b, 0x3a, 0xc8, 0xac, 0x76, - 0x55, 0x6a, 0x0c, 0x92, 0x44, 0xf0, 0x3f, 0xc1 }, - { 0xf2, 0xb1, 0x95, 0x84, 0x6e, 0xe2, 0xb9, 0xab, - 0x5f, 0x18, 0xe6, 0x80, 0x21, 0xf8, 0xdf, 0x7c, - 0x0b, 0x60, 0x58, 0xde, 0xde, 0x86, 0xc5, 0xd5, - 0x90, 0xf2, 0xe8, 0x64, 0x3a, 0xfe, 0x04, 0x52 }, - { 0xf2, 0xe5, 0x30, 0x0c, 0x39, 0xf2, 0x86, 0xc6, - 0x78, 0x99, 0x90, 0x9c, 0x7c, 0xe7, 0x35, 0x9b, - 0x09, 0x45, 0xd2, 0xaf, 0xd3, 0x4a, 0x6d, 0xd6, - 0x9e, 0x08, 0xcd, 0xa5, 0x44, 0xc8, 0x7b, 0x3a }, - { 0xf3, 0x0c, 0x0a, 0xed, 0x70, 0x6d, 0x22, 0x55, - 0x5f, 0x07, 0x09, 0x6a, 0xf4, 0xb8, 0xbe, 0xdc, - 0x16, 0x3c, 0x0f, 0x6e, 0xd5, 0x34, 0x6e, 0xfc, - 0x28, 0xe8, 0xcf, 0xaf, 0x84, 0x2f, 0xa5, 0xd9 }, - { 0xf6, 0x13, 0xd5, 0x90, 0x46, 0xd1, 0x66, 0x71, - 0xd3, 0xc5, 0x60, 0x17, 0x6f, 0x3d, 0x77, 0xfd, - 0xc5, 0x1e, 0x5f, 0x57, 0xb5, 0xe4, 0x8a, 0xe7, - 0xa4, 0xb9, 0x70, 0x0a, 0x11, 0xd4, 0x69, 0x3a }, - { 0xf6, 0x54, 0x6b, 0x2f, 0xfe, 0x2b, 0xae, 0xf7, - 0x35, 0xe8, 0x25, 0x67, 0xa6, 0xe2, 0x36, 0x75, - 0x03, 0x94, 0xc1, 0x19, 0x14, 0x09, 0x87, 0x0c, - 0x6f, 0xbe, 0x95, 0x2d, 0x08, 0xa3, 0x3a, 0xba }, - { 0xf8, 0x64, 0x44, 0x3e, 0x2f, 0x63, 0x9e, 0x7c, - 0xff, 0xd2, 0x42, 0x21, 0xf6, 0x1b, 0xbf, 0xf0, - 0x7c, 0xce, 0x5c, 0x61, 0xdd, 0xb1, 0x68, 0xb3, - 0xb4, 0x04, 0xd7, 0xc8, 0xcd, 0xca, 0x18, 0xb2 }, - { 0xf8, 0x94, 0xf9, 0x67, 0x36, 0x9c, 0xe7, 0xcf, - 0xa3, 0x1a, 0xc1, 0x9a, 0x66, 0x65, 0xb0, 0xc4, - 0x24, 0xba, 0x40, 0x8a, 0xd5, 0xd3, 0x65, 0xf1, - 0x68, 0xd8, 0xbe, 0xeb, 0x79, 0xf4, 0x89, 0xf3 }, - { 0xf8, 0xcf, 0x1e, 0x08, 0x6a, 0x6a, 0x06, 0x3f, - 0xad, 0x25, 0x74, 0x25, 0xaa, 0xe7, 0x20, 0x01, - 0x40, 0x05, 0xb4, 0x15, 0x91, 0x2d, 0xbb, 0x8c, - 0x0b, 0xc9, 0x99, 0xaf, 0x48, 0x48, 0xcf, 0xe5 }, - { 0xfb, 0x9a, 0xf7, 0x9d, 0xea, 0x18, 0xaf, 0x62, - 0x99, 0x85, 0x0e, 0x25, 0x15, 0x9b, 0x4f, 0xb2, - 0x24, 0xcb, 0xb0, 0xf1, 0x4e, 0xad, 0x7e, 0x85, - 0xf6, 0x0c, 0x2a, 0xb2, 0x09, 0xea, 0x45, 0x0d }, - { 0xfb, 0xc4, 0xc9, 0xba, 0xcf, 0xe3, 0xda, 0x64, - 0x13, 0x18, 0x26, 0x6b, 0x72, 0x58, 0x56, 0x00, - 0x35, 0xbc, 0x64, 0x60, 0x8e, 0x34, 0xb9, 0x90, - 0xca, 0x92, 0xa5, 0x52, 0xf3, 0x14, 0x21, 0x61 }, - { 0xfb, 0xed, 0xd3, 0x88, 0x89, 0xf0, 0xb4, 0x1f, - 0x73, 0x4d, 0xe2, 0xf4, 0xc9, 0xd6, 0xf2, 0x7c, - 0x8d, 0x4a, 0xa9, 0xab, 0x73, 0x64, 0x91, 0xe1, - 0x64, 0xe1, 0x21, 0xb7, 0xbc, 0xaf, 0x44, 0xe8 }, - { 0xfc, 0x01, 0xa5, 0x5a, 0x36, 0xcc, 0x8b, 0x7b, - 0x7c, 0xa2, 0xea, 0xb0, 0x84, 0x60, 0xc2, 0x8d, - 0x1d, 0x6c, 0xd8, 0x9c, 0x57, 0x59, 0x94, 0x05, - 0xd5, 0x37, 0x4b, 0x91, 0xaa, 0xeb, 0xc8, 0x79 }, - { 0xfc, 0x4d, 0x9a, 0x37, 0xe5, 0xf7, 0x32, 0x72, - 0xd0, 0xa9, 0xdf, 0xcc, 0xe9, 0x03, 0x12, 0xc7, - 0x52, 0xe1, 0xb5, 0x2e, 0xb6, 0x54, 0xc4, 0x2c, - 0x36, 0x94, 0x4b, 0x90, 0x2a, 0x30, 0x41, 0x07 }, - { 0xfc, 0x56, 0xdb, 0xa1, 0xe7, 0xaf, 0xbd, 0xaa, - 0x07, 0x33, 0xc6, 0x91, 0x1c, 0x5f, 0x1f, 0x18, - 0x28, 0xcb, 0x12, 0x98, 0x31, 0x40, 0x1a, 0x3c, - 0xfd, 0xea, 0xa7, 0x24, 0x62, 0x95, 0x35, 0x94 }, - { 0xfc, 0x83, 0xc2, 0x89, 0x89, 0x5a, 0x92, 0x08, - 0xc9, 0xb1, 0x7a, 0x16, 0xbc, 0xe5, 0xce, 0x80, - 0xe8, 0xf4, 0xa0, 0x77, 0x21, 0x25, 0x29, 0xce, - 0x0b, 0xc7, 0xf5, 0x42, 0xc6, 0xcb, 0xde, 0x1a }, - { 0xfc, 0xa6, 0x23, 0x5d, 0x2a, 0xa4, 0xb1, 0xb2, - 0x51, 0x50, 0x78, 0x57, 0xb4, 0xf0, 0x08, 0xdf, - 0xd5, 0x27, 0x04, 0x2c, 0xe0, 0x45, 0x01, 0xaa, - 0xe2, 0x9d, 0xd2, 0x05, 0xbb, 0xef, 0xce, 0x0d }, - { 0xfc, 0xe7, 0x34, 0xe1, 0x2b, 0x8e, 0xfb, 0x43, - 0x12, 0x71, 0xbf, 0xf6, 0x7a, 0x7a, 0x0a, 0x93, - 0xb2, 0x19, 0xdd, 0x5e, 0x5d, 0xcc, 0x12, 0x58, - 0x59, 0x4d, 0x96, 0xfc, 0xe1, 0x93, 0xb8, 0x60 }, - { 0xfd, 0x9c, 0xfe, 0x14, 0xda, 0xd8, 0x97, 0x8c, - 0x5b, 0xc8, 0x88, 0x93, 0x8f, 0x16, 0xf3, 0xb3, - 0x98, 0xf7, 0x63, 0xa3, 0xad, 0xaf, 0xaa, 0x4a, - 0xd9, 0x41, 0xb7, 0xe3, 0x87, 0xeb, 0x4f, 0x4a }, - { 0xfd, 0xed, 0x92, 0xcb, 0x40, 0x91, 0x66, 0x82, - 0x3a, 0x35, 0xe2, 0x17, 0xf3, 0x0b, 0x38, 0xc4, - 0x86, 0xf8, 0x3e, 0xf2, 0xd4, 0xf2, 0x7b, 0x05, - 0xf1, 0x8c, 0x74, 0x49, 0x81, 0x33, 0x9a, 0x1c }, - { 0xfe, 0x26, 0xb2, 0xa6, 0x45, 0xa3, 0x1a, 0x91, - 0x11, 0x00, 0x09, 0x9a, 0xa9, 0xa2, 0x93, 0x9f, - 0x49, 0xe9, 0xfb, 0xea, 0x64, 0x48, 0x7b, 0xdf, - 0x68, 0xa5, 0x23, 0x70, 0x32, 0x92, 0xd6, 0xa0 }, - { 0xfe, 0x42, 0x1b, 0x24, 0x4e, 0x0e, 0x81, 0x6d, - 0x9f, 0x26, 0xb3, 0x52, 0xc8, 0x31, 0xd9, 0x30, - 0xe1, 0xc1, 0xc5, 0xd2, 0xfa, 0x4e, 0x0a, 0x1c, - 0x77, 0x96, 0xa1, 0xf2, 0x02, 0x0e, 0xf1, 0x67 }, - { 0xfe, 0x4f, 0x35, 0x6c, 0x7f, 0x9b, 0xfc, 0x17, - 0xff, 0xcb, 0x68, 0xd0, 0x76, 0x4e, 0xcb, 0x2a, - 0x87, 0xca, 0xa0, 0xae, 0x4c, 0xb5, 0x66, 0x62, - 0x21, 0x04, 0xd3, 0x6f, 0xfb, 0x52, 0xcb, 0x29 }, - { 0xff, 0x82, 0x6e, 0x2d, 0x0c, 0xb7, 0x71, 0x68, - 0x68, 0x67, 0x5a, 0xe4, 0xb4, 0x31, 0xb6, 0x37, - 0x1e, 0x9f, 0x0c, 0xdf, 0xcc, 0xb4, 0x9d, 0x43, - 0xba, 0x30, 0x49, 0xbf, 0xdd, 0x2c, 0x41, 0xb1 }, - { 0xff, 0xdc, 0x6b, 0x85, 0xfe, 0x7b, 0x10, 0x83, - 0xb5, 0x41, 0x6f, 0x80, 0x6f, 0xc2, 0x44, 0xb9, - 0xe4, 0xdf, 0x42, 0x99, 0xfb, 0xe3, 0xf6, 0x81, - 0xaf, 0x3f, 0x5c, 0xf4, 0x22, 0x5a, 0x8e, 0xaf }, -}; - -// SHA-256 hashes of leaf certificates issued by CNNIC's EV root. -const uint8_t kCNNICEVWhitelist[][crypto::kSHA256Length] = { - { 0xb5, 0xef, 0x42, 0xc4, 0xbc, 0xed, 0xf1, 0x7b, - 0xec, 0xc7, 0x5b, 0xf4, 0x63, 0x66, 0x49, 0xce, - 0xbf, 0xf8, 0x71, 0x1b, 0xce, 0xff, 0xfa, 0x69, - 0x5c, 0xc2, 0x52, 0xfa, 0x57, 0x4d, 0x42, 0x18 }, - { 0xb6, 0x82, 0x3c, 0x9d, 0xbc, 0x8e, 0x8c, 0x05, - 0x4b, 0xcf, 0x60, 0xf2, 0x38, 0x21, 0xac, 0x6c, - 0x58, 0x19, 0x73, 0x51, 0xea, 0xcf, 0xa5, 0x57, - 0x4c, 0xf0, 0x41, 0xb4, 0xce, 0x6b, 0x84, 0x04 }, - { 0xdf, 0x69, 0xf9, 0x6a, 0x85, 0x67, 0x8f, 0x6c, - 0xaf, 0x3f, 0xde, 0x25, 0xec, 0xfb, 0x5d, 0xf4, - 0x74, 0x70, 0x87, 0xc2, 0xaf, 0x3b, 0x00, 0x65, - 0xfb, 0x15, 0x10, 0x55, 0xcb, 0xcb, 0xa8, 0xc1 }, - { 0xee, 0x0c, 0xf6, 0x2b, 0x9d, 0x8e, 0x42, 0xa2, - 0x23, 0xb9, 0xa9, 0x60, 0xb5, 0xe9, 0x67, 0x0c, - 0xcc, 0x34, 0x6d, 0x89, 0x93, 0x8f, 0xfa, 0x5d, - 0xf7, 0x98, 0x65, 0xe4, 0x13, 0xd6, 0x31, 0x54 }, -}; - -const PublicKeyWhitelist kBuiltinWhitelist[] = { - // C=CN, O=China Internet Network Information Center, - // CN=China Internet Network Information Center EV Certificates Root - // Expires: August 31 2030. - { { 0x9d, 0xd5, 0x5f, 0xc5, 0x73, 0xf5, 0x46, 0xcb, - 0x6a, 0x38, 0x31, 0xd1, 0x11, 0x2d, 0x87, 0x10, - 0xa6, 0xf4, 0xf8, 0x2d, 0xc8, 0x7f, 0x5f, 0xae, - 0x9d, 0x3a, 0x1a, 0x02, 0x8d, 0xd3, 0x6e, 0x4b }, - kCNNICEVWhitelist, arraysize(kCNNICEVWhitelist) - }, - // C=CN, O=CNNIC, CN=CNNIC ROOT - // Expires: April 16 2027. - { { 0x1f, 0x42, 0x24, 0xce, 0xc8, 0x4f, 0xc9, 0x9c, - 0xed, 0x88, 0x1f, 0xf6, 0xfc, 0xfd, 0x3e, 0x21, - 0xf8, 0xc5, 0x19, 0xc5, 0x47, 0xaa, 0x6a, 0x5d, - 0xd3, 0xde, 0x24, 0x73, 0x02, 0xce, 0x50, 0xd1 }, - kCNNICDVWhitelist, arraysize(kCNNICDVWhitelist) - }, -}; // clang-format on -const size_t kBuiltinWhitelistSize = arraysize(kBuiltinWhitelist); - -const PublicKeyWhitelist* g_whitelist = kBuiltinWhitelist; -size_t g_whitelist_size = kBuiltinWhitelistSize; - -// Comparator to compare a SHA256HashValue with a uint8_t array containing a -// raw SHA-256 hash. Return value follows memcmp semantics. -int CompareSHA256HashValueToRawHash(const void* key, const void* element) { - const SHA256HashValue* search_key = - reinterpret_cast<const SHA256HashValue*>(key); - return memcmp(search_key->data, element, sizeof(search_key->data)); -} // Comparator to compare a (SHA-256) HashValue with a uint8_t array containing // a raw SHA-256 hash. Return value follows memcmp semantics. @@ -1652,55 +56,74 @@ int CompareHashValueToRawHash(const void* key, const void* element) { return memcmp(search_key->data(), element, search_key->size()); } +namespace wosign { +#include "net/data/ssl/wosign/wosign_domains-inc.cc" } // namespace -bool IsNonWhitelistedCertificate(const X509Certificate& cert, - const HashValueVector& public_key_hashes) { - // 2016-10-21 00:00:00 UTC - const base::Time last_wosign_cert = - base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1477008000); +} // namespace +bool IsNonWhitelistedCertificate(const X509Certificate& cert, + const HashValueVector& public_key_hashes, + base::StringPiece hostname) { for (const auto& hash : public_key_hashes) { if (hash.tag != HASH_VALUE_SHA256) continue; // Check for WoSign/StartCom certificates. if (bsearch(&hash, kWosignKeys, arraysize(kWosignKeys), - crypto::kSHA256Length, CompareHashValueToRawHash) != nullptr && - (cert.valid_start().is_null() || cert.valid_start().is_max() || - cert.valid_start() > last_wosign_cert)) { - return true; - } - - // Check the public key whitelist. - for (size_t i = 0; i < g_whitelist_size; ++i) { - if (memcmp(hash.data(), g_whitelist[i].public_key, - crypto::kSHA256Length) != 0) { - continue; + crypto::kSHA256Length, CompareHashValueToRawHash) != nullptr) { + // 2016-10-21 00:00:00 UTC + const base::Time last_wosign_cert = + base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1477008000); + + // Don't allow new certificates. + if (cert.valid_start().is_null() || cert.valid_start().is_max() || + cert.valid_start() > last_wosign_cert) { + return true; } - const SHA256HashValue leaf_hash = - X509Certificate::CalculateFingerprint256(cert.os_cert_handle()); - void* result = bsearch( - &leaf_hash, g_whitelist[i].whitelist, g_whitelist[i].whitelist_size, - crypto::kSHA256Length, CompareSHA256HashValueToRawHash); - if (result == nullptr) - return true; // Hash was not found on the public key whitelist. - break; + + // Don't allow certificates from non-whitelisted hosts. + return !IsWhitelistedHost(wosign::kDafsa, arraysize(wosign::kDafsa), + hostname); } } return false; } -void SetCertificateWhitelistForTesting(const PublicKeyWhitelist* whitelist, - size_t whitelist_size) { - if (whitelist == nullptr || whitelist_size == 0) { - g_whitelist = kBuiltinWhitelist; - g_whitelist_size = kBuiltinWhitelistSize; - return; +bool IsWhitelistedHost(const unsigned char* graph, + size_t graph_length, + base::StringPiece host) { + if (host.empty()) + return false; + + size_t end = host.length(); + + // Skip trailing '.', if any. + if (host[end - 1] == '.') { + --end; + } + + // Reverse through each of the domain components, trying to see if the + // domain is on the whitelist. For example, the string + // "www.domain.example.com" would be processed by first searching + // for "com", then "example.com", then "domain.example.com". The + // loop will terminate when there are no more distinct label separators, + // and thus the final check for "www.domain.example.com". + size_t start = end; + while (start != 0 && + (start = host.rfind('.', start - 1)) != base::StringPiece::npos) { + const char* domain_str = host.data() + start + 1; + size_t domain_length = end - start - 1; + if (domain_length == 0) + return false; + if (LookupStringInFixedSet(graph, graph_length, domain_str, + domain_length) != kDafsaNotFound) { + return true; + } } - g_whitelist = whitelist; - g_whitelist_size = whitelist_size; + return LookupStringInFixedSet(graph, graph_length, host.data(), end) != + kDafsaNotFound; } } // namespace net diff --git a/chromium/net/cert/cert_verify_proc_whitelist.h b/chromium/net/cert/cert_verify_proc_whitelist.h index 47ce9831848..2c7dfd5bda1 100644 --- a/chromium/net/cert/cert_verify_proc_whitelist.h +++ b/chromium/net/cert/cert_verify_proc_whitelist.h @@ -8,6 +8,7 @@ #include <stddef.h> #include <stdint.h> +#include "base/strings/string_piece.h" #include "crypto/sha2.h" #include "net/base/hash_value.h" #include "net/base/net_export.h" @@ -16,32 +17,26 @@ namespace net { class X509Certificate; -// PublicKeyWhitelist contains a SHA-256 SPKI hash and a pointer to an array -// of SHA-256 certificate hashes that have been publicly disclosed and -// whitelisted. -struct PublicKeyWhitelist { - uint8_t public_key[crypto::kSHA256Length]; - const uint8_t (*whitelist)[crypto::kSHA256Length]; - size_t whitelist_size; -}; - // Returns true if |cert| has been issued by a CA that is constrained from // issuing new certificates and |cert| is not within the whitelist of // existing certificates. Returns false if |cert| was issued by an // unconstrained CA or if it was in the whitelist for that // CA. // |cert| should be the verified certificate chain, with |public_key_hashes| -// being the set of hashes of the SPKIs within the verified chain. +// being the set of hashes of the SPKIs within the verified chain, and +// |hostname| as the GURL-normalized hostname. bool NET_EXPORT_PRIVATE IsNonWhitelistedCertificate(const X509Certificate& cert, - const HashValueVector& public_key_hashes); + const HashValueVector& public_key_hashes, + base::StringPiece hostname); -// Sets the certificate whitelist for testing. Supply nullptr/0 to reset to -// the built-in whitelist. -void NET_EXPORT_PRIVATE -SetCertificateWhitelistForTesting(const PublicKeyWhitelist* whitelist, - size_t whitelist_size); +// Returns true if |host| is in (or a subdomain of) a whitelisted host +// in |graph|, which is a DAFSA constructed by +// //net/tools/dafsa/make_dafsa.py that is |graph_length| bytes long. +bool NET_EXPORT_PRIVATE IsWhitelistedHost(const unsigned char* graph, + size_t graph_length, + base::StringPiece host); } // namespace net -#endif // NET_CERT_CERT_VERIFY_PROC_WHITELIST +#endif // NET_CERT_CERT_VERIFY_PROC_WHITELIST_H_ diff --git a/chromium/net/cert/cert_verify_proc_whitelist_unittest.cc b/chromium/net/cert/cert_verify_proc_whitelist_unittest.cc index 791957315a6..1ad6a1c5316 100644 --- a/chromium/net/cert/cert_verify_proc_whitelist_unittest.cc +++ b/chromium/net/cert/cert_verify_proc_whitelist_unittest.cc @@ -14,177 +14,16 @@ namespace net { namespace { -HashValue GetTestHashValue(uint8_t label, HashValueTag tag) { - HashValue hash_value(tag); - memset(hash_value.data(), label, hash_value.size()); - return hash_value; -} - -HashValueVector GetFakeHashValues() { - HashValueVector public_key_hashes; - - // Fake "root" hash - public_key_hashes.push_back(GetTestHashValue(0x00, HASH_VALUE_SHA256)); - public_key_hashes.push_back(GetTestHashValue(0x01, HASH_VALUE_SHA1)); - // Fake "intermediate" hash - public_key_hashes.push_back(GetTestHashValue(0x02, HASH_VALUE_SHA256)); - public_key_hashes.push_back(GetTestHashValue(0x03, HASH_VALUE_SHA1)); - // Fake "leaf" hash - public_key_hashes.push_back(GetTestHashValue(0x04, HASH_VALUE_SHA256)); - public_key_hashes.push_back(GetTestHashValue(0x05, HASH_VALUE_SHA1)); - - return public_key_hashes; -} - -// The SHA-256 hash of the leaf cert "ok_cert.pem"; obtainable either -// via X509Certificate::CalculateFingerprint256 or -// openssl x509 -inform pem -in ok_cert.pem -outform der | openssl -// dgst -sha256 -c -const uint8_t kWhitelistCerts[][crypto::kSHA256Length] = { - /* clang-format off */ - { 0xf4, 0x42, 0xdd, 0x66, 0xfa, 0x10, 0x70, 0x65, - 0xd1, 0x7e, 0xd9, 0xbb, 0x7c, 0xa9, 0x3c, 0x79, - 0x63, 0xbe, 0x01, 0xa7, 0x54, 0x18, 0xab, 0x2f, - 0xc3, 0x9a, 0x14, 0x53, 0xc3, 0x83, 0xa0, 0x5a }, - /* clang-format on */ -}; - -TEST(CertVerifyProcWhitelistTest, AcceptsWhitelistedEEByRoot) { - scoped_refptr<X509Certificate> cert = - ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"); - ASSERT_TRUE(cert); - - // clang-format off - const PublicKeyWhitelist kWhitelist[] = { - { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - kWhitelistCerts, arraysize(kWhitelistCerts) - }, - }; - // clang-format on - - SetCertificateWhitelistForTesting(kWhitelist, arraysize(kWhitelist)); - - HashValueVector public_key_hashes = GetFakeHashValues(); - - // Should return false, indicating this cert is acceptable because of - // it being whitelisted. - EXPECT_FALSE(IsNonWhitelistedCertificate(*cert, public_key_hashes)); - - SetCertificateWhitelistForTesting(nullptr, 0); -} - -TEST(CertVerifyProcWhitelistTest, AcceptsWhitelistedEEByIntermediate) { - scoped_refptr<X509Certificate> cert = - ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"); - ASSERT_TRUE(cert); - - // clang-format off - const PublicKeyWhitelist kWhitelist[] = { - { { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, - kWhitelistCerts, arraysize(kWhitelistCerts) - }, - }; - // clang-format on - - SetCertificateWhitelistForTesting(kWhitelist, arraysize(kWhitelist)); - - HashValueVector public_key_hashes = GetFakeHashValues(); - - // Should return false, indicating this cert is acceptable because of - // it being whitelisted. - EXPECT_FALSE(IsNonWhitelistedCertificate(*cert, public_key_hashes)); - - SetCertificateWhitelistForTesting(nullptr, 0); -} - -TEST(CertVerifyProcWhitelistTest, RejectsNonWhitelistedEE) { - scoped_refptr<X509Certificate> cert = - ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); - ASSERT_TRUE(cert); - - // clang-format off - const PublicKeyWhitelist kWhitelist[] = { - { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - kWhitelistCerts, arraysize(kWhitelistCerts) - }, - }; - // clang-format on - - SetCertificateWhitelistForTesting(kWhitelist, arraysize(kWhitelist)); - - HashValueVector public_key_hashes = GetFakeHashValues(); - - // Should return true, indicating this certificate chains to a constrained - // root and is not whitelisted. - EXPECT_TRUE(IsNonWhitelistedCertificate(*cert, public_key_hashes)); - - SetCertificateWhitelistForTesting(nullptr, 0); -} - -TEST(CertVerifyProcWhitelistTest, RejectsNonWhitelistedEEByIntermediate) { - scoped_refptr<X509Certificate> cert = - ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem"); - ASSERT_TRUE(cert); - - // clang-format off - const PublicKeyWhitelist kWhitelist[] = { - { { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, - kWhitelistCerts, arraysize(kWhitelistCerts) - }, - }; - // clang-format on - - SetCertificateWhitelistForTesting(kWhitelist, arraysize(kWhitelist)); - - HashValueVector public_key_hashes = GetFakeHashValues(); - - // Should return true, indicating this certificate chains to a constrained - // root and is not whitelisted. - EXPECT_TRUE(IsNonWhitelistedCertificate(*cert, public_key_hashes)); - - SetCertificateWhitelistForTesting(nullptr, 0); -} - -TEST(CertVerifyProcWhitelistTest, AcceptsUnconstrainedLeaf) { - scoped_refptr<X509Certificate> cert = - ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"); - ASSERT_TRUE(cert); - - // clang-format off - const PublicKeyWhitelist kWhitelist[] = { - { { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, - kWhitelistCerts, arraysize(kWhitelistCerts) - }, - }; - // clang-format on - - SetCertificateWhitelistForTesting(kWhitelist, arraysize(kWhitelist)); - - HashValueVector public_key_hashes = GetFakeHashValues(); - - // Should return false, because the chain (as indicated by - // public_key_hashes) is not constrained. - EXPECT_FALSE(IsNonWhitelistedCertificate(*cert, public_key_hashes)); - - SetCertificateWhitelistForTesting(nullptr, 0); -} +namespace test1 { +#include "net/cert/cert_verify_proc_whitelist_unittest1-inc.cc" +} // namespace test TEST(CertVerifyProcWhitelistTest, HandlesWosignCerts) { + // The domain must be in the whitelist from + // //net/data/ssl/wosign/wosign_domains.gperf + const char kWhitelistedDomain[] = "005.tv"; + const char kNonWhitelistedDomain[] = "006.tv"; + scoped_refptr<X509Certificate> cert = ImportCertFromFile(GetTestCertsDirectory(), "wosign_before_oct_21.pem"); ASSERT_TRUE(cert); @@ -195,12 +34,68 @@ TEST(CertVerifyProcWhitelistTest, HandlesWosignCerts) { 0x95, 0xa5, 0x99, 0x68, 0xce, 0xf2, 0x34, 0x77, 0x37, 0x79, 0xdf, 0x51, 0x81, 0xcf, 0x10, 0xfa, 0x64, 0x75, 0x34, 0xbb, 0x65}}); - EXPECT_FALSE(IsNonWhitelistedCertificate(*cert, public_key_hashes)); + // Domains on the whitelist are allowed, as long as their certificates were + // pre-existing before Oct 21, 2016. + EXPECT_FALSE(IsNonWhitelistedCertificate(*cert, public_key_hashes, + kWhitelistedDomain)); + // Domains not on the whitelist are not allowed, regardless of the validity + // period of the certificate. + EXPECT_TRUE(IsNonWhitelistedCertificate(*cert, public_key_hashes, + kNonWhitelistedDomain)); cert = ImportCertFromFile(GetTestCertsDirectory(), "wosign_after_oct_21.pem"); ASSERT_TRUE(cert); - EXPECT_TRUE(IsNonWhitelistedCertificate(*cert, public_key_hashes)); + // No new certificates (after Oct 21, 2016) are all allowed, regardless + // of the domain. + EXPECT_TRUE(IsNonWhitelistedCertificate(*cert, public_key_hashes, + kWhitelistedDomain)); + EXPECT_TRUE(IsNonWhitelistedCertificate(*cert, public_key_hashes, + kNonWhitelistedDomain)); + + // Certificates that aren't issued by WoSign are allowed, regardless of + // domain. + public_key_hashes[0].data()[0] = 0x14; + EXPECT_FALSE(IsNonWhitelistedCertificate(*cert, public_key_hashes, + kWhitelistedDomain)); + EXPECT_FALSE(IsNonWhitelistedCertificate(*cert, public_key_hashes, + kNonWhitelistedDomain)); +} + +TEST(CertVerifyProcWhitelistTest, IsWhitelistedHost) { + const unsigned char* graph = test1::kDafsa; + size_t graph_size = arraysize(test1::kDafsa); + + // Test malformed inputs. + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "")); + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, ".")); + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "..")); + + // Make sure that TLDs aren't accepted just because a subdomain is. + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "com")); + + // Test various forms of domain names that GURL will accept for entries in + // the graph. + EXPECT_TRUE(IsWhitelistedHost(graph, graph_size, "example.com")); + EXPECT_TRUE(IsWhitelistedHost(graph, graph_size, "subdomain.example.com")); + EXPECT_TRUE(IsWhitelistedHost(graph, graph_size, ".subdomain.example.com")); + EXPECT_TRUE(IsWhitelistedHost(graph, graph_size, "example.com.")); + EXPECT_TRUE(IsWhitelistedHost(graph, graph_size, ".example.com.")); + EXPECT_TRUE(IsWhitelistedHost(graph, graph_size, "www.example.bar.jp")); + + // Test various prefix/suffices of entries in the graph, but that aren't + // themselves domain matches. + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "anotherexample.com")); + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "bar.jp")); + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "example.bar.jp.junk")); + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "foo.example.bar.jp.junk")); + + // Test various forms of domain names that GURL will accept for entries not + // in the graph. + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "domain.com")); + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "example..com")); + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "www.co.uk")); + EXPECT_FALSE(IsWhitelistedHost(graph, graph_size, "www..co.uk")); } } // namespace diff --git a/chromium/net/cert/cert_verify_proc_whitelist_unittest1.gperf b/chromium/net/cert/cert_verify_proc_whitelist_unittest1.gperf new file mode 100644 index 00000000000..cfe582aa6f7 --- /dev/null +++ b/chromium/net/cert/cert_verify_proc_whitelist_unittest1.gperf @@ -0,0 +1,9 @@ +%{ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +%} +%% +example.com, 0 +example.bar.jp, 0 +%% diff --git a/chromium/net/cert/cert_verify_proc_win.cc b/chromium/net/cert/cert_verify_proc_win.cc index a13117a7a8e..373b43cbe8e 100644 --- a/chromium/net/cert/cert_verify_proc_win.cc +++ b/chromium/net/cert/cert_verify_proc_win.cc @@ -363,27 +363,6 @@ void GetCertChainInfo(PCCERT_CHAIN_CONTEXT chain_context, } else { verified_chain.push_back(cert); } - - const char* algorithm = cert->pCertInfo->SignatureAlgorithm.pszObjId; - if (strcmp(algorithm, szOID_RSA_MD5RSA) == 0) { - // md5WithRSAEncryption: 1.2.840.113549.1.1.4 - verify_result->has_md5 = true; - } else if (strcmp(algorithm, szOID_RSA_MD2RSA) == 0) { - // md2WithRSAEncryption: 1.2.840.113549.1.1.2 - verify_result->has_md2 = true; - } else if (strcmp(algorithm, szOID_RSA_MD4RSA) == 0) { - // md4WithRSAEncryption: 1.2.840.113549.1.1.3 - verify_result->has_md4 = true; - } else if (strcmp(algorithm, szOID_RSA_SHA1RSA) == 0 || - strcmp(algorithm, szOID_X957_SHA1DSA) == 0 || - strcmp(algorithm, szOID_ECDSA_SHA1) == 0) { - // sha1WithRSAEncryption: 1.2.840.113549.1.1.5 - // id-dsa-with-sha1: 1.2.840.10040.4.3 - // ecdsa-with-SHA1: 1.2.840.10045.4.1 - verify_result->has_sha1 = true; - if (i == 0) - verify_result->has_sha1_leaf = true; - } } if (verified_cert) { diff --git a/chromium/net/cert/cert_verify_result.cc b/chromium/net/cert/cert_verify_result.cc index b1054e4ced3..4b605165d60 100644 --- a/chromium/net/cert/cert_verify_result.cc +++ b/chromium/net/cert/cert_verify_result.cc @@ -36,7 +36,8 @@ void CertVerifyResult::Reset() { } bool CertVerifyResult::operator==(const CertVerifyResult& other) const { - return verified_cert->Equals(other.verified_cert.get()) && + return (!!verified_cert == !!other.verified_cert) && + (!verified_cert || verified_cert->Equals(other.verified_cert.get())) && std::tie(cert_status, has_md2, has_md4, has_md5, has_sha1, has_sha1_leaf, public_key_hashes, is_issued_by_known_root, is_issued_by_additional_trust_anchor, diff --git a/chromium/net/cert/cert_verify_result.h b/chromium/net/cert/cert_verify_result.h index 29c0675af3f..176c4ca50ed 100644 --- a/chromium/net/cert/cert_verify_result.h +++ b/chromium/net/cert/cert_verify_result.h @@ -28,12 +28,22 @@ class NET_EXPORT CertVerifyResult { bool operator==(const CertVerifyResult& other) const; - // The certificate and chain that was constructed during verification. - // Note that the though the verified certificate will match the originally - // supplied certificate, the intermediate certificates stored within may - // be substantially different. In the event of a verification failure, this - // will contain the chain as supplied by the server. This may be NULL if - // running within the sandbox. + // The certificate chain that was constructed during verification. + // + // Note: Although |verified_cert| will match the originally supplied + // certificate to be validated, the results of GetIntermediateCertificates() + // may be substantially different, both in order and in content, then the + // originally supplied intermediates. + // + // In the event of validation failures, this may contain the originally + // supplied certificate chain or a partially constructed path, depending on + // the implementation. + // + // In the event of validation success, the trust anchor will be + // |verified_cert->GetIntermediateCertificates().back()| if + // there was a certificate chain to the trust anchor, and will + // be |verified_cert->os_cert_handle()| if the certificate was + // the trust anchor. scoped_refptr<X509Certificate> verified_cert; // Bitmask of CERT_STATUS_* from net/cert/cert_status_flags.h. Note that @@ -42,7 +52,8 @@ class NET_EXPORT CertVerifyResult { // chain. CertStatus cert_status; - // Properties of the certificate chain. + // Hash algorithms used by the certificate chain, excluding the trust + // anchor. bool has_md2; bool has_md4; bool has_md5; diff --git a/chromium/net/cert/crl_set_storage.cc b/chromium/net/cert/crl_set_storage.cc index a4e3fd122cd..007cf3c1f47 100644 --- a/chromium/net/cert/crl_set_storage.cc +++ b/chromium/net/cert/crl_set_storage.cc @@ -14,6 +14,7 @@ #include "base/trace_event/trace_event.h" #include "base/values.h" #include "crypto/sha2.h" +#include "net/base/trace_constants.h" #include "third_party/zlib/zlib.h" namespace net { @@ -132,7 +133,7 @@ static base::DictionaryValue* ReadHeader(base::StringPiece* data) { if (header.get() == NULL) return NULL; - if (!header->IsType(base::Value::TYPE_DICTIONARY)) + if (!header->IsType(base::Value::Type::DICTIONARY)) return NULL; return static_cast<base::DictionaryValue*>(header.release()); } @@ -294,7 +295,7 @@ static bool ReadDeltaCRL(base::StringPiece* data, // static bool CRLSetStorage::Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set) { - TRACE_EVENT0("net", "CRLSetStorage::Parse"); + TRACE_EVENT0(kNetTracingCategory, "CRLSetStorage::Parse"); // Other parts of Chrome assume that we're little endian, so we don't lose // anything by doing this. #if defined(__BYTE_ORDER) diff --git a/chromium/net/cert/ct_known_logs.cc b/chromium/net/cert/ct_known_logs.cc index a65988971ed..cca1fbefcef 100644 --- a/chromium/net/cert/ct_known_logs.cc +++ b/chromium/net/cert/ct_known_logs.cc @@ -92,4 +92,3 @@ bool IsLogDisqualified(base::StringPiece log_id, } // namespace ct } // namespace net - diff --git a/chromium/net/cert/ct_known_logs_static-inc.h b/chromium/net/cert/ct_known_logs_static-inc.h index 7ead66cc559..87961b92403 100644 --- a/chromium/net/cert/ct_known_logs_static-inc.h +++ b/chromium/net/cert/ct_known_logs_static-inc.h @@ -4,21 +4,21 @@ struct CTLogInfo { // The DER-encoded SubjectPublicKeyInfo for the log. - const char* const log_key; + const char* log_key; // The length, in bytes, of |log_key|. - const size_t log_key_length; + size_t log_key_length; // The user-friendly log name. // Note: This will not be translated. - const char* const log_name; + const char* log_name; // The HTTPS API endpoint for the log. // Note: Trailing slashes should be included. - const char* const log_url; + const char* log_url; // The DNS API endpoint for the log. // This is used as the parent domain for all queries about the log. // If empty, CT DNS queries are not supported for the log. This will prevent // retrieval of inclusion proofs over DNS for SCTs from the log. // https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md. - const char* const log_dns_domain; + const char* log_dns_domain; }; // The set of all presently-qualifying CT logs. diff --git a/chromium/net/cert/ct_log_response_parser.cc b/chromium/net/cert/ct_log_response_parser.cc index 5baf1b33534..b6067d14f38 100644 --- a/chromium/net/cert/ct_log_response_parser.cc +++ b/chromium/net/cert/ct_log_response_parser.cc @@ -4,10 +4,11 @@ #include "net/cert/ct_log_response_parser.h" +#include <memory> + #include "base/base64.h" #include "base/json/json_value_converter.h" #include "base/logging.h" -#include "base/memory/scoped_vector.h" #include "base/strings/string_piece.h" #include "base/time/time.h" #include "base/values.h" @@ -105,7 +106,7 @@ bool IsJsonSTHStructurallyValid(const JsonSignedTreeHead& sth) { // Structure for making JSON decoding easier. The string fields // are base64-encoded so will require further decoding. struct JsonConsistencyProof { - ScopedVector<std::string> proof_nodes; + std::vector<std::unique_ptr<std::string>> proof_nodes; static void RegisterJSONConverter( base::JSONValueConverter<JsonConsistencyProof>* converter); @@ -170,7 +171,7 @@ bool FillConsistencyProof(const base::Value& json_consistency_proof, } consistency_proof->reserve(parsed_proof.proof_nodes.size()); - for (std::string* proof_node : parsed_proof.proof_nodes) { + for (const auto& proof_node : parsed_proof.proof_nodes) { consistency_proof->push_back(*proof_node); } diff --git a/chromium/net/cert/ct_log_response_parser_unittest.cc b/chromium/net/cert/ct_log_response_parser_unittest.cc index 110a432aaa4..11006ec5ece 100644 --- a/chromium/net/cert/ct_log_response_parser_unittest.cc +++ b/chromium/net/cert/ct_log_response_parser_unittest.cc @@ -9,7 +9,6 @@ #include "base/base64.h" #include "base/json/json_reader.h" -#include "base/strings/stringprintf.h" #include "base/time/time.h" #include "base/values.h" #include "net/cert/ct_serialization.h" diff --git a/chromium/net/cert/ct_log_verifier_util.h b/chromium/net/cert/ct_log_verifier_util.h index 9894afe59ea..2e62d1a7a3d 100644 --- a/chromium/net/cert/ct_log_verifier_util.h +++ b/chromium/net/cert/ct_log_verifier_util.h @@ -27,4 +27,4 @@ NET_EXPORT std::string HashNodes(const std::string& lh, const std::string& rh); } // namespace net -#endif +#endif // NET_CERT_CT_LOG_VERIFIER_UTIL_H_ diff --git a/chromium/net/cert/ct_objects_extractor.cc b/chromium/net/cert/ct_objects_extractor.cc index 4f451fdd1f2..1a6e6e4772d 100644 --- a/chromium/net/cert/ct_objects_extractor.cc +++ b/chromium/net/cert/ct_objects_extractor.cc @@ -252,7 +252,7 @@ bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) { bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer, const std::string& cert_serial_number, - const std::string& ocsp_response, + base::StringPiece ocsp_response, std::string* sct_list) { // The input is an OCSPResponse. See RFC2560, section 4.2.1. The SCT list is // in the extensions field of the SingleResponse which matches the input diff --git a/chromium/net/cert/ct_objects_extractor.h b/chromium/net/cert/ct_objects_extractor.h index d8fc5f95e52..d5deb5b607e 100644 --- a/chromium/net/cert/ct_objects_extractor.h +++ b/chromium/net/cert/ct_objects_extractor.h @@ -7,6 +7,7 @@ #include <string> +#include "base/strings/string_piece.h" #include "net/base/net_export.h" #include "net/cert/x509_certificate.h" @@ -54,7 +55,7 @@ NET_EXPORT_PRIVATE bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, NET_EXPORT_PRIVATE bool ExtractSCTListFromOCSPResponse( X509Certificate::OSCertHandle issuer, const std::string& cert_serial_number, - const std::string& ocsp_response, + base::StringPiece ocsp_response, std::string* sct_list); } // namespace ct diff --git a/chromium/net/cert/ct_objects_extractor_unittest.cc b/chromium/net/cert/ct_objects_extractor_unittest.cc index 7efec352535..8f8896938cd 100644 --- a/chromium/net/cert/ct_objects_extractor_unittest.cc +++ b/chromium/net/cert/ct_objects_extractor_unittest.cc @@ -44,8 +44,7 @@ class CTObjectsExtractorTest : public ::testing::Test { std::vector<base::StringPiece> parsed_scts; base::StringPiece sct_list_sp(sct_list); // Make sure the SCT list can be decoded properly - EXPECT_TRUE(DecodeSCTList(&sct_list_sp, &parsed_scts)); - + EXPECT_TRUE(DecodeSCTList(sct_list_sp, &parsed_scts)); EXPECT_TRUE(DecodeSignedCertificateTimestamp(&parsed_scts[0], sct)); } diff --git a/chromium/net/cert/ct_policy_enforcer.h b/chromium/net/cert/ct_policy_enforcer.h index c732cee6ff4..7111970e29d 100644 --- a/chromium/net/cert/ct_policy_enforcer.h +++ b/chromium/net/cert/ct_policy_enforcer.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_CERT_CT_POLICY_ENFORCER_H -#define NET_CERT_CT_POLICY_ENFORCER_H +#ifndef NET_CERT_CT_POLICY_ENFORCER_H_ +#define NET_CERT_CT_POLICY_ENFORCER_H_ #include <stddef.h> #include <vector> @@ -105,4 +105,4 @@ class NET_EXPORT CTPolicyEnforcer { } // namespace net -#endif // NET_CERT_CT_POLICY_ENFORCER_H +#endif // NET_CERT_CT_POLICY_ENFORCER_H_ diff --git a/chromium/net/cert/ct_policy_enforcer_unittest.cc b/chromium/net/cert/ct_policy_enforcer_unittest.cc index 59544094c29..f30411c338b 100644 --- a/chromium/net/cert/ct_policy_enforcer_unittest.cc +++ b/chromium/net/cert/ct_policy_enforcer_unittest.cc @@ -85,11 +85,11 @@ class CTPolicyEnforcerTest : public ::testing::Test { sct->log_id = std::string(crypto::kSHA256Length, static_cast<char>(i)); if (timestamp_past_enforcement_date) { - sct->timestamp = - base::Time::FromUTCExploded({2015, 8, 0, 15, 0, 0, 0, 0}); + EXPECT_TRUE(base::Time::FromUTCExploded({2015, 8, 0, 15, 0, 0, 0, 0}, + &sct->timestamp)); } else { - sct->timestamp = - base::Time::FromUTCExploded({2015, 6, 0, 15, 0, 0, 0, 0}); + EXPECT_TRUE(base::Time::FromUTCExploded({2015, 6, 0, 15, 0, 0, 0, 0}, + &sct->timestamp)); } verified_scts->push_back(sct); @@ -111,10 +111,11 @@ class CTPolicyEnforcerTest : public ::testing::Test { sct->origin = desired_origin; sct->log_id = std::string(kCertlyLogID, crypto::kSHA256Length); if (timestamp_after_disqualification_date) { - sct->timestamp = - base::Time::FromUTCExploded({2016, 4, 0, 16, 0, 0, 0, 0}); + EXPECT_TRUE(base::Time::FromUTCExploded({2016, 4, 0, 16, 0, 0, 0, 0}, + &sct->timestamp)); } else { - sct->timestamp = base::Time::FromUTCExploded({2016, 4, 0, 1, 0, 0, 0, 0}); + EXPECT_TRUE(base::Time::FromUTCExploded({2016, 4, 0, 1, 0, 0, 0, 0}, + &sct->timestamp)); } verified_scts->push_back(sct); @@ -130,6 +131,14 @@ class CTPolicyEnforcerTest : public ::testing::Test { verified_scts); } + base::Time CreateTime(const base::Time::Exploded& exploded) { + base::Time result; + if (!base::Time::FromUTCExploded(exploded, &result)) { + ADD_FAILURE() << "Failed FromUTCExploded"; + } + return result; + } + protected: std::unique_ptr<CTPolicyEnforcer> policy_enforcer_; scoped_refptr<X509Certificate> chain_; @@ -137,8 +146,15 @@ class CTPolicyEnforcerTest : public ::testing::Test { std::string non_google_log_id_; }; +#if defined(OS_ANDROID) +#define MAYBE_DoesNotConformToCTEVPolicyNotEnoughDiverseSCTsAllGoogle \ + DISABLED_DoesNotConformToCTEVPolicyNotEnoughDiverseSCTsAllGoogle +#else +#define MAYBE_DoesNotConformToCTEVPolicyNotEnoughDiverseSCTsAllGoogle \ + DoesNotConformToCTEVPolicyNotEnoughDiverseSCTsAllGoogle +#endif TEST_F(CTPolicyEnforcerTest, - DoesNotConformToCTEVPolicyNotEnoughDiverseSCTsAllGoogle) { + MAYBE_DoesNotConformToCTEVPolicyNotEnoughDiverseSCTsAllGoogle) { ct::SCTList scts; std::vector<std::string> desired_log_ids(2, google_log_id_); @@ -443,38 +459,48 @@ TEST_F(CTPolicyEnforcerTest, ASSERT_TRUE(private_key); // Test multiple validity periods + base::Time time_2015_3_0_25_11_25_0_0 = + CreateTime({2015, 3, 0, 25, 11, 25, 0, 0}); + + base::Time time_2016_6_0_6_11_25_0_0 = + CreateTime({2016, 6, 0, 6, 11, 25, 0, 0}); + + base::Time time_2016_6_0_25_11_25_0_0 = + CreateTime({2016, 6, 0, 25, 11, 25, 0, 0}); + + base::Time time_2016_6_0_27_11_25_0_0 = + CreateTime({2016, 6, 0, 27, 11, 25, 0, 0}); + + base::Time time_2017_6_0_25_11_25_0_0 = + CreateTime({2017, 6, 0, 25, 11, 25, 0, 0}); + + base::Time time_2017_6_0_28_11_25_0_0 = + CreateTime({2017, 6, 0, 28, 11, 25, 0, 0}); + + base::Time time_2018_6_0_25_11_25_0_0 = + CreateTime({2018, 6, 0, 25, 11, 25, 0, 0}); + + base::Time time_2018_6_0_27_11_25_0_0 = + CreateTime({2018, 6, 0, 27, 11, 25, 0, 0}); + const struct TestData { base::Time validity_start; base::Time validity_end; size_t scts_required; } kTestData[] = {{// Cert valid for 14 months, needs 2 SCTs. - base::Time::FromUTCExploded({2015, 3, 0, 25, 11, 25, 0, 0}), - base::Time::FromUTCExploded({2016, 6, 0, 6, 11, 25, 0, 0}), - 2}, + time_2015_3_0_25_11_25_0_0, time_2016_6_0_6_11_25_0_0, 2}, {// Cert valid for exactly 15 months, needs 3 SCTs. - base::Time::FromUTCExploded({2015, 3, 0, 25, 11, 25, 0, 0}), - base::Time::FromUTCExploded({2016, 6, 0, 25, 11, 25, 0, 0}), - 3}, + time_2015_3_0_25_11_25_0_0, time_2016_6_0_25_11_25_0_0, 3}, {// Cert valid for over 15 months, needs 3 SCTs. - base::Time::FromUTCExploded({2015, 3, 0, 25, 11, 25, 0, 0}), - base::Time::FromUTCExploded({2016, 6, 0, 27, 11, 25, 0, 0}), - 3}, + time_2015_3_0_25_11_25_0_0, time_2016_6_0_27_11_25_0_0, 3}, {// Cert valid for exactly 27 months, needs 3 SCTs. - base::Time::FromUTCExploded({2015, 3, 0, 25, 11, 25, 0, 0}), - base::Time::FromUTCExploded({2017, 6, 0, 25, 11, 25, 0, 0}), - 3}, + time_2015_3_0_25_11_25_0_0, time_2017_6_0_25_11_25_0_0, 3}, {// Cert valid for over 27 months, needs 4 SCTs. - base::Time::FromUTCExploded({2015, 3, 0, 25, 11, 25, 0, 0}), - base::Time::FromUTCExploded({2017, 6, 0, 28, 11, 25, 0, 0}), - 4}, + time_2015_3_0_25_11_25_0_0, time_2017_6_0_28_11_25_0_0, 4}, {// Cert valid for exactly 39 months, needs 4 SCTs. - base::Time::FromUTCExploded({2015, 3, 0, 25, 11, 25, 0, 0}), - base::Time::FromUTCExploded({2018, 6, 0, 25, 11, 25, 0, 0}), - 4}, + time_2015_3_0_25_11_25_0_0, time_2018_6_0_25_11_25_0_0, 4}, {// Cert valid for over 39 months, needs 5 SCTs. - base::Time::FromUTCExploded({2015, 3, 0, 25, 11, 25, 0, 0}), - base::Time::FromUTCExploded({2018, 6, 0, 27, 11, 25, 0, 0}), - 5}}; + time_2015_3_0_25_11_25_0_0, time_2018_6_0_27_11_25_0_0, 5}}; for (size_t i = 0; i < arraysize(kTestData); ++i) { SCOPED_TRACE(i); diff --git a/chromium/net/cert/ct_policy_status.h b/chromium/net/cert/ct_policy_status.h index cc38585d6fa..c86e68100ed 100644 --- a/chromium/net/cert/ct_policy_status.h +++ b/chromium/net/cert/ct_policy_status.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_CERT_CT_POLICY_STATUS_H -#define NET_CERT_CT_POLICY_STATUS_H +#ifndef NET_CERT_CT_POLICY_STATUS_H_ +#define NET_CERT_CT_POLICY_STATUS_H_ namespace net { @@ -54,4 +54,4 @@ enum class EVPolicyCompliance { } // namespace net -#endif // NET_CERT_CT_POLICY_STATUS_H +#endif // NET_CERT_CT_POLICY_STATUS_H_ diff --git a/chromium/net/cert/ct_serialization.cc b/chromium/net/cert/ct_serialization.cc index 60d94263423..64a6ff5c5d0 100644 --- a/chromium/net/cert/ct_serialization.cc +++ b/chromium/net/cert/ct_serialization.cc @@ -383,15 +383,15 @@ void EncodeTreeHeadSignature(const SignedTreeHead& signed_tree_head, output); } -bool DecodeSCTList(base::StringPiece* input, +bool DecodeSCTList(base::StringPiece input, std::vector<base::StringPiece>* output) { std::vector<base::StringPiece> result; - if (!ReadList(kSCTListLengthBytes, kSerializedSCTLengthBytes, - input, &result)) { + if (!ReadList(kSCTListLengthBytes, kSerializedSCTLengthBytes, &input, + &result)) { return false; } - if (!input->empty() || result.empty()) + if (!input.empty() || result.empty()) return false; output->swap(result); return true; diff --git a/chromium/net/cert/ct_serialization.h b/chromium/net/cert/ct_serialization.h index 269892d3512..b5b3d77d69d 100644 --- a/chromium/net/cert/ct_serialization.h +++ b/chromium/net/cert/ct_serialization.h @@ -75,7 +75,7 @@ NET_EXPORT_PRIVATE void EncodeTreeHeadSignature( // Returns true if the list could be read and decoded successfully, false // otherwise (note that the validity of each individual SCT should be checked // separately). -NET_EXPORT_PRIVATE bool DecodeSCTList(base::StringPiece* input, +NET_EXPORT_PRIVATE bool DecodeSCTList(base::StringPiece input, std::vector<base::StringPiece>* output); // Decodes a single SCT from |input| to |output|. diff --git a/chromium/net/cert/ct_serialization_unittest.cc b/chromium/net/cert/ct_serialization_unittest.cc index 6056ea3bcf1..6ddb329b7c4 100644 --- a/chromium/net/cert/ct_serialization_unittest.cc +++ b/chromium/net/cert/ct_serialization_unittest.cc @@ -141,7 +141,7 @@ TEST_F(CtSerializationTest, DecodesSCTList) { base::StringPiece encoded("\x0\xa\x0\x3\x61\x62\x63\x0\x3\x64\x65\x66", 12); std::vector<base::StringPiece> decoded; - ASSERT_TRUE(ct::DecodeSCTList(&encoded, &decoded)); + ASSERT_TRUE(ct::DecodeSCTList(encoded, &decoded)); ASSERT_STREQ("abc", decoded[0].data()); ASSERT_STREQ("def", decoded[1].data()); } @@ -151,7 +151,7 @@ TEST_F(CtSerializationTest, FailsDecodingInvalidSCTList) { base::StringPiece encoded("\x0\xa\x0\x3\x61\x62\x63\x0\x5\x64\x65\x66", 12); std::vector<base::StringPiece> decoded; - ASSERT_FALSE(ct::DecodeSCTList(&encoded, &decoded)); + ASSERT_FALSE(ct::DecodeSCTList(encoded, &decoded)); } TEST_F(CtSerializationTest, DecodesSignedCertificateTimestamp) { @@ -259,4 +259,3 @@ TEST_F(CtSerializationTest, EncodesValidSignedTreeHead) { } } // namespace net - diff --git a/chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc b/chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc index 1930ba892ce..d92f028897f 100644 --- a/chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc +++ b/chromium/net/cert/ct_signed_certificate_timestamp_log_param.cc @@ -10,7 +10,6 @@ #include "base/base64.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" #include "base/values.h" #include "net/cert/ct_sct_to_string.h" #include "net/cert/signed_certificate_timestamp.h" @@ -22,10 +21,9 @@ namespace { // Base64 encode the given |value| string and put it in |dict| with the // description |key|. -void SetBinaryData( - const char* key, - const std::string& value, - base::DictionaryValue* dict) { +void SetBinaryData(const char* key, + base::StringPiece value, + base::DictionaryValue* dict) { std::string b64_value; base::Base64Encode(value, &b64_value); @@ -85,15 +83,15 @@ std::unique_ptr<base::Value> NetLogSignedCertificateTimestampCallback( } std::unique_ptr<base::Value> NetLogRawSignedCertificateTimestampCallback( - const std::string* embedded_scts, - const std::string* sct_list_from_ocsp, - const std::string* sct_list_from_tls_extension, + base::StringPiece embedded_scts, + base::StringPiece sct_list_from_ocsp, + base::StringPiece sct_list_from_tls_extension, NetLogCaptureMode capture_mode) { std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); - SetBinaryData("embedded_scts", *embedded_scts, dict.get()); - SetBinaryData("scts_from_ocsp_response", *sct_list_from_ocsp, dict.get()); - SetBinaryData("scts_from_tls_extension", *sct_list_from_tls_extension, + SetBinaryData("embedded_scts", embedded_scts, dict.get()); + SetBinaryData("scts_from_ocsp_response", sct_list_from_ocsp, dict.get()); + SetBinaryData("scts_from_tls_extension", sct_list_from_tls_extension, dict.get()); return std::move(dict); diff --git a/chromium/net/cert/ct_signed_certificate_timestamp_log_param.h b/chromium/net/cert/ct_signed_certificate_timestamp_log_param.h index 373a7525337..c2149cdb578 100644 --- a/chromium/net/cert/ct_signed_certificate_timestamp_log_param.h +++ b/chromium/net/cert/ct_signed_certificate_timestamp_log_param.h @@ -6,8 +6,8 @@ #define NET_CERT_CT_SIGNED_CERTIFICATE_TIMESTAMP_LOG_PARAM_H_ #include <memory> -#include <string> +#include "base/strings/string_piece.h" #include "net/cert/signed_certificate_timestamp_and_status.h" namespace base { @@ -31,9 +31,9 @@ std::unique_ptr<base::Value> NetLogSignedCertificateTimestampCallback( // See the documentation for SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED // in net/log/net_log_event_type_list.h std::unique_ptr<base::Value> NetLogRawSignedCertificateTimestampCallback( - const std::string* embedded_scts, - const std::string* sct_list_from_ocsp, - const std::string* sct_list_from_tls_extension, + base::StringPiece embedded_scts, + base::StringPiece sct_list_from_ocsp, + base::StringPiece sct_list_from_tls_extension, NetLogCaptureMode capture_mode); } // namespace net diff --git a/chromium/net/cert/ct_verifier.h b/chromium/net/cert/ct_verifier.h index b65a1334b48..b5b1c79045f 100644 --- a/chromium/net/cert/ct_verifier.h +++ b/chromium/net/cert/ct_verifier.h @@ -5,14 +5,12 @@ #ifndef NET_CERT_CT_VERIFIER_H_ #define NET_CERT_CT_VERIFIER_H_ -#include <string> - +#include "base/strings/string_piece.h" #include "net/base/net_export.h" #include "net/cert/signed_certificate_timestamp_and_status.h" namespace net { -class CTLogVerifier; class NetLogWithSource; class X509Certificate; @@ -45,13 +43,13 @@ class NET_EXPORT CTVerifier { // (embedding, TLS extension or OCSP stapling). If no stapled OCSP response // is available, |stapled_ocsp_response| should be an empty string. If no SCT // TLS extension was negotiated, |sct_list_from_tls_extension| should be an - // empty string. |result| will be filled with the SCTs present, divided into - // categories based on the verification result. - virtual int Verify(X509Certificate* cert, - const std::string& stapled_ocsp_response, - const std::string& sct_list_from_tls_extension, - SignedCertificateTimestampAndStatusList* output_scts, - const NetLogWithSource& net_log) = 0; + // empty string. |output_scts| will be cleared and filled with the SCTs + // present, if any, along with their verification results. + virtual void Verify(X509Certificate* cert, + base::StringPiece stapled_ocsp_response, + base::StringPiece sct_list_from_tls_extension, + SignedCertificateTimestampAndStatusList* output_scts, + const NetLogWithSource& net_log) = 0; // Registers |observer| to receive notifications of validated SCTs. Does not // take ownership of the observer as the observer may be performing diff --git a/chromium/net/cert/do_nothing_ct_verifier.cc b/chromium/net/cert/do_nothing_ct_verifier.cc new file mode 100644 index 00000000000..0429d86e765 --- /dev/null +++ b/chromium/net/cert/do_nothing_ct_verifier.cc @@ -0,0 +1,25 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/cert/do_nothing_ct_verifier.h" + +#include "net/base/net_errors.h" + +namespace net { + +DoNothingCTVerifier::DoNothingCTVerifier() = default; +DoNothingCTVerifier::~DoNothingCTVerifier() = default; + +void DoNothingCTVerifier::Verify( + X509Certificate* cert, + base::StringPiece stapled_ocsp_response, + base::StringPiece sct_list_from_tls_extension, + SignedCertificateTimestampAndStatusList* output_scts, + const NetLogWithSource& net_log) { + output_scts->clear(); +} + +void DoNothingCTVerifier::SetObserver(Observer* observer) {} + +} // namespace net diff --git a/chromium/net/cert/do_nothing_ct_verifier.h b/chromium/net/cert/do_nothing_ct_verifier.h new file mode 100644 index 00000000000..025ffd11be8 --- /dev/null +++ b/chromium/net/cert/do_nothing_ct_verifier.h @@ -0,0 +1,67 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_CERT_DO_NOTHING_CT_VERIFIER_H_ +#define NET_CERT_DO_NOTHING_CT_VERIFIER_H_ + +#include "base/macros.h" +#include "net/base/net_export.h" +#include "net/cert/ct_verifier.h" + +namespace net { + +// An implementation of CTVerifier that does not validate SCTs. +// +// SECURITY NOTE: +// As Certificate Transparency is an essential part in safeguarding TLS +// connections, disabling Certificate Transparency enforcement is a decision +// that should not be taken lightly, and it should be made an explicit +// decision rather than a potentially accidental decision (such as allowing +// for a nullptr instance). By checking Certificate Transparency information, +// typically via a net::MultiLogCTVerifier, and enforcing policies related +// to Certificate Transparency provided by a net::CTPolicyEnforcer, developers +// can help protect their users by ensuring that misissued TLS certificates +// are detected. +// +// However, not every consumer of TLS certificates is using the Web PKI. For +// example, they may be using connections authenticated out of band, or may +// be using private or local PKIs for which Certificate Transparency is not +// relevant. Alternatively, much like how a robust and secure TLS client +// requires a regularly updated root certificate store, a robust and secure +// Certificate Transparency client requires regular updates. However, since +// some clients may not support regular updates, it may be intentional to +// disable Certificate Transparency and choose a less-secure default +// behavior. +// +// Consumers of this class should generally try to get a security or design +// to discuss the type of net::X509Certificates they will be validating, +// and determine whether or not Certificate Transparency is right for the +// particular use case. +// +// Because of the complex nuances related to security tradeoffs, it is +// expected that classes which expect a CTVerifier will require one to be +// supplied, forcing the caller to make an intentional and explicit decision +// about the appropriate security policy, rather than leaving it ambiguous, +// such as via a nullptr. This class is intended to indicate an intentional +// consideration of CT, and a decision to not support it. +class NET_EXPORT DoNothingCTVerifier : public CTVerifier { + public: + DoNothingCTVerifier(); + ~DoNothingCTVerifier() override; + + void Verify(X509Certificate* cert, + base::StringPiece stapled_ocsp_response, + base::StringPiece sct_list_from_tls_extension, + SignedCertificateTimestampAndStatusList* output_scts, + const NetLogWithSource& net_log) override; + + void SetObserver(Observer* observer) override; + + private: + DISALLOW_COPY_AND_ASSIGN(DoNothingCTVerifier); +}; + +} // namespace net + +#endif // NET_CERT_DO_NOTHING_CT_VERIFIER_H_ diff --git a/chromium/net/cert/ev_root_ca_metadata.cc b/chromium/net/cert/ev_root_ca_metadata.cc index 1370f1726c4..a7e85ec8059 100644 --- a/chromium/net/cert/ev_root_ca_metadata.cc +++ b/chromium/net/cert/ev_root_ca_metadata.cc @@ -41,7 +41,7 @@ struct EVMetadata { SHA1HashValue fingerprint; // The EV policy OIDs of the root CA. - const char policy_oids[kMaxOIDsPerCA][kMaxOIDLength]; + char policy_oids[kMaxOIDsPerCA][kMaxOIDLength]; }; static const EVMetadata ev_root_ca_metadata[] = { @@ -114,6 +114,34 @@ static const EVMetadata ev_root_ca_metadata[] = { 0x55, 0x6c, 0x11, 0xa4, 0x37, 0xca, 0xeb, 0xff, 0xc3, 0xbb}}, {"1.3.6.1.4.1.34697.2.4", ""}, }, + // Amazon Root CA 1 + // https://good.sca1a.amazontrust.com/ + { + {{0x8d, 0xa7, 0xf9, 0x65, 0xec, 0x5e, 0xfc, 0x37, 0x91, 0x0f, + 0x1c, 0x6e, 0x59, 0xfd, 0xc1, 0xcc, 0x6a, 0x6e, 0xde, 0x16}}, + {"2.23.140.1.1", ""}, + }, + // Amazon Root CA 2 + // https://good.sca2a.amazontrust.com/ + { + {{0x5a, 0x8c, 0xef, 0x45, 0xd7, 0xa6, 0x98, 0x59, 0x76, 0x7a, + 0x8c, 0x8b, 0x44, 0x96, 0xb5, 0x78, 0xcf, 0x47, 0x4b, 0x1a}}, + {"2.23.140.1.1", ""}, + }, + // Amazon Root CA 3 + // https://good.sca3a.amazontrust.com/ + { + {{0x0d, 0x44, 0xdd, 0x8c, 0x3c, 0x8c, 0x1a, 0x1a, 0x58, 0x75, + 0x64, 0x81, 0xe9, 0x0f, 0x2e, 0x2a, 0xff, 0xb3, 0xd2, 0x6e}}, + {"2.23.140.1.1", ""}, + }, + // Amazon Root CA 4 + // https://good.sca4a.amazontrust.com/ + { + {{0xf6, 0x10, 0x84, 0x07, 0xd6, 0xf8, 0xbb, 0x67, 0x98, 0x0c, + 0xc2, 0xe2, 0x44, 0xc2, 0xeb, 0xae, 0x1c, 0xef, 0x63, 0xbe}}, + {"2.23.140.1.1", ""}, + }, // Autoridad de Certificacion Firmaprofesional CIF A62634068 // https://publifirma.firmaprofesional.com/ {{{0xae, 0xc5, 0xfb, 0x3f, 0xc8, 0xe1, 0xbf, 0xc4, 0xe5, 0x4f, @@ -168,6 +196,13 @@ static const EVMetadata ev_root_ca_metadata[] = { 0x06, 0x28, 0xa2, 0x59, 0x3a, 0x19, 0xa7, 0x0f, 0x06, 0x9e}}, {"1.2.616.1.113527.2.5.1.1", ""}, }, + // CFCA EV ROOT + // https://www.erenepu.com/ + { + {{0xe2, 0xb8, 0x29, 0x4b, 0x55, 0x84, 0xab, 0x6b, 0x58, 0xc2, + 0x90, 0x46, 0x6c, 0xac, 0x3f, 0xb8, 0x39, 0x8f, 0x84, 0x83}}, + {"2.16.156.112554.3", ""}, + }, // China Internet Network Information Center EV Certificates Root // https://evdemo.cnnic.cn/ { @@ -239,6 +274,13 @@ static const EVMetadata ev_root_ca_metadata[] = { 0xdc, 0x37, 0xd4, 0x4d, 0xf5, 0xd4, 0x67, 0x49, 0x52, 0xf9}}, {"2.16.840.1.114028.10.1.2", ""}, }, + // Entrust Root Certification Authority – G2 + // https://validg2.entrust.net + { + {{0x8c, 0xf4, 0x27, 0xfd, 0x79, 0x0c, 0x3a, 0xd1, 0x66, 0x06, + 0x8d, 0xe8, 0x1e, 0x57, 0xef, 0xbb, 0x93, 0x22, 0x72, 0xd4}}, + {"2.16.840.1.114028.10.1.2", ""}, + }, // Equifax Secure Certificate Authority (GeoTrust) // https://www.geotrust.com/ { @@ -343,6 +385,13 @@ static const EVMetadata ev_root_ca_metadata[] = { 0x3f, 0xf8, 0xbc, 0xf8, 0x15, 0xb0, 0x82, 0xf9, 0xae, 0xfd}}, {"1.3.6.1.4.1.14777.6.1.1", "1.3.6.1.4.1.14777.6.1.2"}, }, + // LuxTrust Global Root 2 + // https://ltsslca5.trustme.lu/ + { + {{0x1e, 0x0e, 0x56, 0x19, 0x0a, 0xd1, 0x8b, 0x25, 0x98, 0xb2, + 0x04, 0x44, 0xff, 0x66, 0x8a, 0x04, 0x17, 0x99, 0x5f, 0x3f}}, + {"1.3.171.1.1.10.5.2", ""}, + }, // Network Solutions Certificate Authority // https://www.networksolutions.com/website-packages/index.jsp { @@ -358,6 +407,13 @@ static const EVMetadata ev_root_ca_metadata[] = { 0xc0, 0x71, 0xf8, 0xf7, 0x33, 0xb1, 0x83, 0x85, 0x63, 0x32}}, {"1.3.6.1.4.1.782.1.2.1.8.1", ""}, }, + // OISTE WISeKey Global Root GB CA + // https://goodevssl.wisekey.com + { + {{0x0f, 0xf9, 0x40, 0x76, 0x18, 0xd3, 0xd7, 0x6a, 0x4b, 0x98, + 0xf0, 0xa8, 0x35, 0x9e, 0x0c, 0xfd, 0x27, 0xac, 0xcc, 0xed}}, + {"2.16.756.5.14.7.4.8", ""}, + }, // QuoVadis Root CA 2 // https://www.quovadis.bm/ { @@ -440,7 +496,7 @@ static const EVMetadata ev_root_ca_metadata[] = { { {{0x92, 0x5a, 0x8f, 0x8d, 0x2c, 0x6d, 0x04, 0xe0, 0x66, 0x5f, 0x59, 0x6a, 0xff, 0x22, 0xd8, 0x63, 0xe8, 0x25, 0x6f, 0x3f}}, - {"2.16.840.1.114414.1.7.24.3", ""}, + {"2.16.840.1.114414.1.7.24.3", "2.23.140.1.1"}, }, // SwissSign Gold CA - G2 // https://testevg2.swisssign.net/ diff --git a/chromium/net/cert/internal/cert_errors.h b/chromium/net/cert/internal/cert_errors.h index a9579ce0c31..cd713ed42ec 100644 --- a/chromium/net/cert/internal/cert_errors.h +++ b/chromium/net/cert/internal/cert_errors.h @@ -75,7 +75,6 @@ namespace net { class CertErrorParams; class CertErrorScoper; -class ParsedCertificate; // The type of a particular CertErrorNode. enum class CertErrorNodeType { diff --git a/chromium/net/cert/internal/cert_issuer_source.h b/chromium/net/cert/internal/cert_issuer_source.h index 1ffc3b3a9f9..c38b61d2546 100644 --- a/chromium/net/cert/internal/cert_issuer_source.h +++ b/chromium/net/cert/internal/cert_issuer_source.h @@ -8,9 +8,7 @@ #include <memory> #include <vector> -#include "base/callback.h" #include "net/base/net_export.h" -#include "net/cert/internal/completion_status.h" #include "net/cert/internal/parsed_certificate.h" namespace net { @@ -30,27 +28,19 @@ class NET_EXPORT CertIssuerSource { // Destruction of the Request cancels it. virtual ~Request() = default; - // Retrieves the next issuer. + // Retrieves issuers and appends them to |issuers|. // - // If one is available it will be stored in |out_cert| and SYNC will be - // returned. GetNext should be called again to retrieve any remaining - // issuers. + // GetNext should be called again to retrieve any remaining issuers. // - // If no issuers are currently available, |out_cert| will be cleared and the - // return value will indicate if the Request is exhausted. If the return - // value is ASYNC, the |issuers_callback| that was passed to - // AsyncGetIssuersOf will be called again (unless the Request is destroyed - // first). If the return value is SYNC, the Request is complete and the - // |issuers_callback| will not be called again. - virtual CompletionStatus GetNext( - scoped_refptr<ParsedCertificate>* out_cert) = 0; + // If no issuers are left then |issuers| will not be modified. This + // indicates that the issuers have been exhausted and GetNext() should + // not be called again. + virtual void GetNext(ParsedCertificateList* issuers) = 0; private: DISALLOW_COPY_AND_ASSIGN(Request); }; - using IssuerCallback = base::Callback<void(Request*)>; - virtual ~CertIssuerSource() = default; // Finds certificates whose Subject matches |cert|'s Issuer. @@ -61,18 +51,13 @@ class NET_EXPORT CertIssuerSource { ParsedCertificateList* issuers) = 0; // Finds certificates whose Subject matches |cert|'s Issuer. - // If an async callback will be made |*out_req| is filled with a Request - // object which may be destroyed to cancel the callback. If the implementation - // does not support asynchronous lookups or can determine synchronously that - // it would return no results, |*out_req| will be set to nullptr. + // If the implementation does not support asynchronous lookups or can + // determine synchronously that it would return no results, |*out_req| + // will be set to nullptr. // - // When matches are available or the request is complete, |issuers_callback| - // will be called with a pointer to the same Request. The Request::GetNext - // method may then be used to iterate through the retrieved issuers. Note that - // |issuers_callback| may be called multiple times. See the documentation for - // Request::GetNext for more details. + // Otherwise a request is started and saved to |out_req|. The results can be + // read through the Request interface. virtual void AsyncGetIssuersOf(const ParsedCertificate* cert, - const IssuerCallback& issuers_callback, std::unique_ptr<Request>* out_req) = 0; }; diff --git a/chromium/net/cert/internal/cert_issuer_source_aia.cc b/chromium/net/cert/internal/cert_issuer_source_aia.cc index a6fb1b703d1..6e1290ab26d 100644 --- a/chromium/net/cert/internal/cert_issuer_source_aia.cc +++ b/chromium/net/cert/internal/cert_issuer_source_aia.cc @@ -20,94 +20,82 @@ const int kMaxFetchesPerCert = 5; class AiaRequest : public CertIssuerSource::Request { public: - explicit AiaRequest(const CertIssuerSource::IssuerCallback& issuers_callback); + AiaRequest() {} ~AiaRequest() override; // CertIssuerSource::Request implementation. - CompletionStatus GetNext(scoped_refptr<ParsedCertificate>* out_cert) override; + void GetNext(ParsedCertificateList* issuers) override; void AddCertFetcherRequest( std::unique_ptr<CertNetFetcher::Request> cert_fetcher_request); - void OnFetchCompleted(Error error, const std::vector<uint8_t>& fetched_bytes); + bool AddCompletedFetchToResults(Error error, + std::vector<uint8_t> fetched_bytes, + ParsedCertificateList* results); private: - bool HasNext() const { return current_result_ < results_.size(); } - - CertIssuerSource::IssuerCallback issuers_callback_; std::vector<std::unique_ptr<CertNetFetcher::Request>> cert_fetcher_requests_; - size_t pending_requests_ = 0; - ParsedCertificateList results_; - size_t current_result_ = 0; + size_t current_request_ = 0; DISALLOW_COPY_AND_ASSIGN(AiaRequest); }; -AiaRequest::AiaRequest(const CertIssuerSource::IssuerCallback& issuers_callback) - : issuers_callback_(issuers_callback) {} - AiaRequest::~AiaRequest() = default; -CompletionStatus AiaRequest::GetNext( - scoped_refptr<ParsedCertificate>* out_cert) { - if (HasNext()) { - *out_cert = std::move(results_[current_result_++]); - return CompletionStatus::SYNC; +void AiaRequest::GetNext(ParsedCertificateList* out_certs) { + // TODO(eroman): Rather than blocking in FIFO order, select the one that + // completes first. + while (current_request_ < cert_fetcher_requests_.size()) { + Error error; + std::vector<uint8_t> bytes; + auto req = std::move(cert_fetcher_requests_[current_request_++]); + req->WaitForResult(&error, &bytes); + + if (AddCompletedFetchToResults(error, std::move(bytes), out_certs)) + return; } - *out_cert = nullptr; - if (pending_requests_) - return CompletionStatus::ASYNC; - return CompletionStatus::SYNC; } void AiaRequest::AddCertFetcherRequest( std::unique_ptr<CertNetFetcher::Request> cert_fetcher_request) { DCHECK(cert_fetcher_request); cert_fetcher_requests_.push_back(std::move(cert_fetcher_request)); - pending_requests_++; } -void AiaRequest::OnFetchCompleted(Error error, - const std::vector<uint8_t>& fetched_bytes) { - DCHECK_GT(pending_requests_, 0U); - pending_requests_--; - bool client_waiting_for_callback = !HasNext(); +bool AiaRequest::AddCompletedFetchToResults(Error error, + std::vector<uint8_t> fetched_bytes, + ParsedCertificateList* results) { if (error != OK) { // TODO(mattm): propagate error info. LOG(ERROR) << "AiaRequest::OnFetchCompleted got error " << error; - } else { - // RFC 5280 section 4.2.2.1: - // - // Conforming applications that support HTTP or FTP for accessing - // certificates MUST be able to accept individual DER encoded - // certificates and SHOULD be able to accept "certs-only" CMS messages. - // - // TODO(mattm): Is supporting CMS message format important? - // - // TODO(mattm): Avoid copying bytes. Change the CertNetFetcher and - // ParsedCertificate interface to allow passing through ownership of the - // bytes. - CertErrors errors; - if (!ParsedCertificate::CreateAndAddToVector(fetched_bytes.data(), - fetched_bytes.size(), {}, - &results_, &errors)) { - // TODO(crbug.com/634443): propagate error info. - LOG(ERROR) << "Error parsing cert retrieved from AIA:\n" - << errors.ToDebugString(); - } + return false; } - // If the client is waiting for results, need to run callback if: - // * Some are available now. - // * The last fetch finished, even with no results. (Client needs to know to - // stop waiting.) - if (client_waiting_for_callback && (HasNext() || pending_requests_ == 0)) - issuers_callback_.Run(this); + // RFC 5280 section 4.2.2.1: + // + // Conforming applications that support HTTP or FTP for accessing + // certificates MUST be able to accept individual DER encoded + // certificates and SHOULD be able to accept "certs-only" CMS messages. + // + // TODO(mattm): Is supporting CMS message format important? + // + // TODO(eroman): Avoid copying bytes in the certificate? + CertErrors errors; + if (!ParsedCertificate::CreateAndAddToVector( + fetched_bytes.data(), fetched_bytes.size(), {}, results, &errors)) { + // TODO(crbug.com/634443): propagate error info. + LOG(ERROR) << "Error parsing cert retrieved from AIA:\n" + << errors.ToDebugString(); + return false; + } + + return true; } } // namespace -CertIssuerSourceAia::CertIssuerSourceAia(CertNetFetcher* cert_fetcher) - : cert_fetcher_(cert_fetcher) {} +CertIssuerSourceAia::CertIssuerSourceAia( + scoped_refptr<CertNetFetcher> cert_fetcher) + : cert_fetcher_(std::move(cert_fetcher)) {} CertIssuerSourceAia::~CertIssuerSourceAia() = default; @@ -116,10 +104,8 @@ void CertIssuerSourceAia::SyncGetIssuersOf(const ParsedCertificate* cert, // CertIssuerSourceAia never returns synchronous results. } -void CertIssuerSourceAia::AsyncGetIssuersOf( - const ParsedCertificate* cert, - const IssuerCallback& issuers_callback, - std::unique_ptr<Request>* out_req) { +void CertIssuerSourceAia::AsyncGetIssuersOf(const ParsedCertificate* cert, + std::unique_ptr<Request>* out_req) { out_req->reset(); if (!cert->has_authority_info_access()) @@ -152,16 +138,14 @@ void CertIssuerSourceAia::AsyncGetIssuersOf( if (urls.empty()) return; - std::unique_ptr<AiaRequest> aia_request(new AiaRequest(issuers_callback)); + std::unique_ptr<AiaRequest> aia_request(new AiaRequest()); for (const auto& url : urls) { // TODO(mattm): add synchronous failure mode to FetchCaIssuers interface so // that this doesn't need to wait for async callback just to tell that an // URL has an unsupported scheme? aia_request->AddCertFetcherRequest(cert_fetcher_->FetchCaIssuers( - url, kTimeoutMilliseconds, kMaxResponseBytes, - base::Bind(&AiaRequest::OnFetchCompleted, - base::Unretained(aia_request.get())))); + url, kTimeoutMilliseconds, kMaxResponseBytes)); } *out_req = std::move(aia_request); diff --git a/chromium/net/cert/internal/cert_issuer_source_aia.h b/chromium/net/cert/internal/cert_issuer_source_aia.h index 73c8177bce0..3e62c95a085 100644 --- a/chromium/net/cert/internal/cert_issuer_source_aia.h +++ b/chromium/net/cert/internal/cert_issuer_source_aia.h @@ -16,21 +16,20 @@ class CertNetFetcher; class NET_EXPORT CertIssuerSourceAia : public CertIssuerSource { public: // Creates CertIssuerSource that will use |cert_fetcher| to retrieve issuers - // using AuthorityInfoAccess URIs. |cert_fetcher| must outlive the - // CertIssuerSourceAia. CertIssuerSourceAia must be created and used only on - // a single thread, which is the thread |cert_fetcher| will be operated from. - explicit CertIssuerSourceAia(CertNetFetcher* cert_fetcher); + // using AuthorityInfoAccess URIs. CertIssuerSourceAia must be created and + // used only on a single thread, which is the thread |cert_fetcher| will be + // operated from. + explicit CertIssuerSourceAia(scoped_refptr<CertNetFetcher> cert_fetcher); ~CertIssuerSourceAia() override; // CertIssuerSource implementation: void SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) override; void AsyncGetIssuersOf(const ParsedCertificate* cert, - const IssuerCallback& issuers_callback, std::unique_ptr<Request>* out_req) override; private: - CertNetFetcher* cert_fetcher_; + scoped_refptr<CertNetFetcher> cert_fetcher_; DISALLOW_COPY_AND_ASSIGN(CertIssuerSourceAia); }; diff --git a/chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc b/chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc index b0f1aa72d28..f81c33d76f3 100644 --- a/chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc +++ b/chromium/net/cert/internal/cert_issuer_source_aia_unittest.cc @@ -5,6 +5,7 @@ #include "net/cert/internal/cert_issuer_source_aia.h" #include "base/bind.h" +#include "base/memory/ptr_util.h" #include "net/cert/cert_net_fetcher.h" #include "net/cert/internal/cert_errors.h" #include "net/cert/internal/parsed_certificate.h" @@ -17,8 +18,11 @@ namespace net { namespace { +using ::testing::ByMove; using ::testing::Mock; +using ::testing::Return; using ::testing::StrictMock; +using ::testing::_; ::testing::AssertionResult ReadTestPem(const std::string& file_name, const std::string& block_name, @@ -56,112 +60,59 @@ std::vector<uint8_t> CertDataVector(const ParsedCertificate* cert) { return data; } -// Tracks a CertNetFetcher::Request that will be returned to the -// CertIssuerSourceAia. Allows the tests to tell if the Request is still alive -// or was deleted(cancelled) by the CertIssuerSourceAia. If the Request is still -// alive, the test can get the FetchCallback to simulate the Request completing. -class RequestManager { +// MockCertNetFetcher is an implementation of CertNetFetcher for testing. +class MockCertNetFetcher : public CertNetFetcher { public: - class Request : public CertNetFetcher::Request { - public: - Request(RequestManager* manager, - const CertNetFetcher::FetchCallback& callback) - : manager_(manager), callback_(callback) {} - ~Request() override { manager_->RequestWasDestroyed(); } - - CertNetFetcher::FetchCallback get_callback() const { return callback_; } - - private: - RequestManager* manager_; - CertNetFetcher::FetchCallback callback_; - }; - - ~RequestManager() { CHECK(!request_); } - - std::unique_ptr<Request> CreateRequest( - const CertNetFetcher::FetchCallback& callback) { - EXPECT_FALSE(request_); - std::unique_ptr<Request> request(new Request(this, callback)); - request_ = request.get(); - return request; - } - - bool is_request_alive() const { return request_; } - - CertNetFetcher::FetchCallback get_callback() const { - CHECK(is_request_alive()); - return request_->get_callback(); - } - - private: - void RequestWasDestroyed() { - EXPECT_TRUE(request_); - request_ = nullptr; - } - - Request* request_; + MockCertNetFetcher() {} + MOCK_METHOD0(Shutdown, void()); + MOCK_METHOD3(FetchCaIssuers, + std::unique_ptr<Request>(const GURL& url, + int timeout_milliseconds, + int max_response_bytes)); + MOCK_METHOD3(FetchCrl, + std::unique_ptr<Request>(const GURL& url, + int timeout_milliseconds, + int max_response_bytes)); + + MOCK_METHOD3(FetchOcsp, + std::unique_ptr<Request>(const GURL& url, + int timeout_milliseconds, + int max_response_bytes)); + + protected: + ~MockCertNetFetcher() override {} }; -// MockCertNetFetcherImpl is an implementation of CertNetFetcher for testing. -class MockCertNetFetcherImpl : public CertNetFetcher { +// MockCertNetFetcherRequest gives back the indicated error and bytes. +class MockCertNetFetcherRequest : public CertNetFetcher::Request { public: - MockCertNetFetcherImpl() = default; - ~MockCertNetFetcherImpl() override = default; - - RequestManager* GetRequestManagerForURL(const GURL& url) { - auto it = request_map_.find(url); - if (it == request_map_.end()) - return nullptr; - return it->second.get(); - } - - WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCaIssuers( - const GURL& url, - int timeout_milliseconds, - int max_response_bytes, - const FetchCallback& callback) override { - EXPECT_TRUE(request_map_.find(url) == request_map_.end()); - - std::unique_ptr<RequestManager> request_manager(new RequestManager()); - - std::unique_ptr<Request> request = request_manager->CreateRequest(callback); - - request_map_[url] = std::move(request_manager); - - return request; - } - - WARN_UNUSED_RESULT std::unique_ptr<Request> FetchCrl( - const GURL& url, - int timeout_milliseconds, - int max_response_bytes, - const FetchCallback& callback) override { - NOTREACHED(); - return nullptr; - } - - WARN_UNUSED_RESULT std::unique_ptr<Request> FetchOcsp( - const GURL& url, - int timeout_milliseconds, - int max_response_bytes, - const FetchCallback& callback) override { - NOTREACHED(); - return nullptr; + MockCertNetFetcherRequest(Error error, std::vector<uint8_t> bytes) + : error_(error), bytes_(std::move(bytes)) {} + + void WaitForResult(Error* error, std::vector<uint8_t>* bytes) override { + DCHECK(!did_consume_result_); + *error = error_; + *bytes = std::move(bytes_); + did_consume_result_ = true; } private: - std::map<GURL, std::unique_ptr<RequestManager>> request_map_; - - DISALLOW_COPY_AND_ASSIGN(MockCertNetFetcherImpl); + Error error_; + std::vector<uint8_t> bytes_; + bool did_consume_result_ = false; }; -class MockIssuerCallback { - public: - MOCK_METHOD1(Callback, void(CertIssuerSource::Request*)); -}; +// Creates a CertNetFetcher::Request that completes with an error. +std::unique_ptr<CertNetFetcher::Request> CreateMockRequest(Error error) { + return base::MakeUnique<MockCertNetFetcherRequest>(error, + std::vector<uint8_t>()); +} -void NotCalled(CertIssuerSource::Request* request) { - ADD_FAILURE() << "NotCalled was called"; +// Creates a CertNetFetcher::Request that completes with the specified error +// code and bytes. +std::unique_ptr<CertNetFetcher::Request> CreateMockRequest( + const std::vector<uint8_t>& bytes) { + return base::MakeUnique<MockCertNetFetcherRequest>(OK, bytes); } // CertIssuerSourceAia does not return results for SyncGetIssuersOf. @@ -169,8 +120,9 @@ TEST(CertIssuerSourceAiaTest, NoSyncResults) { scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert)); - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + // No methods on |mock_fetcher| should be called. + auto mock_fetcher = make_scoped_refptr(new StrictMock<MockCertNetFetcher>()); + CertIssuerSourceAia aia_source(mock_fetcher); ParsedCertificateList issuers; aia_source.SyncGetIssuersOf(cert.get(), &issuers); EXPECT_EQ(0U, issuers.size()); @@ -182,10 +134,11 @@ TEST(CertIssuerSourceAiaTest, NoAia) { scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_no_aia.pem", &cert)); - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + // No methods on |mock_fetcher| should be called. + auto mock_fetcher = make_scoped_refptr(new StrictMock<MockCertNetFetcher>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> request; - aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&NotCalled), &request); + aia_source.AsyncGetIssuersOf(cert.get(), &request); EXPECT_EQ(nullptr, request); } @@ -198,32 +151,19 @@ TEST(CertIssuerSourceAiaTest, FileAia) { scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_file_aia.pem", &cert)); - StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + auto mock_fetcher = make_scoped_refptr(new StrictMock<MockCertNetFetcher>()); + EXPECT_CALL(*mock_fetcher, FetchCaIssuers(GURL("file:///dev/null"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(ERR_DISALLOWED_URL_SCHEME)))); + + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); ASSERT_NE(nullptr, cert_source_request); - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("file:///dev/null")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); - - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - // CertNetFetcher rejects the URL scheme. - req_manager->get_callback().Run(ERR_DISALLOWED_URL_SCHEME, - std::vector<uint8_t>()); - Mock::VerifyAndClearExpectations(&mock_callback); - // No results. - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + EXPECT_TRUE(result_certs.empty()); } // If the AuthorityInfoAccess extension contains an invalid URL, @@ -232,10 +172,10 @@ TEST(CertIssuerSourceAiaTest, OneInvalidURL) { scoped_refptr<ParsedCertificate> cert; ASSERT_TRUE(ReadTestCert("target_invalid_url_aia.pem", &cert)); - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + auto mock_fetcher = make_scoped_refptr(new StrictMock<MockCertNetFetcher>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> request; - aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&NotCalled), &request); + aia_source.AsyncGetIssuersOf(cert.get(), &request); EXPECT_EQ(nullptr, request); } @@ -246,38 +186,26 @@ TEST(CertIssuerSourceAiaTest, OneAia) { scoped_refptr<ParsedCertificate> intermediate_cert; ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert)); - StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); - std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); - ASSERT_NE(nullptr, cert_source_request); - - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia/I.cer")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); + auto mock_fetcher = make_scoped_refptr(new StrictMock<MockCertNetFetcher>()); - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager->get_callback().Run(OK, CertDataVector(intermediate_cert.get())); - Mock::VerifyAndClearExpectations(&mock_callback); + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia/I.cer"), _, _)) + .WillOnce(Return( + ByMove(CreateMockRequest(CertDataVector(intermediate_cert.get()))))); - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert()); + CertIssuerSourceAia aia_source(mock_fetcher); + std::unique_ptr<CertIssuerSource::Request> cert_source_request; + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); + ASSERT_NE(nullptr, cert_source_request); - status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(1u, result_certs.size()); + ASSERT_EQ(result_certs.front()->der_cert(), intermediate_cert->der_cert()); - EXPECT_TRUE(req_manager->is_request_alive()); - cert_source_request.reset(); - EXPECT_FALSE(req_manager->is_request_alive()); + result_certs.clear(); + cert_source_request->GetNext(&result_certs); + EXPECT_TRUE(result_certs.empty()); } // AuthorityInfoAccess with two URIs, one a FILE, the other a HTTP. @@ -290,52 +218,32 @@ TEST(CertIssuerSourceAiaTest, OneFileOneHttpAia) { scoped_refptr<ParsedCertificate> intermediate_cert; ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert)); - StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); - std::unique_ptr<CertIssuerSource::Request> cert_source_request; - aia_source.AsyncGetIssuersOf(cert.get(), - base::Bind(&MockIssuerCallback::Callback, - base::Unretained(&mock_callback)), - &cert_source_request); - ASSERT_NE(nullptr, cert_source_request); - - RequestManager* req_manager = - mock_fetcher.GetRequestManagerForURL(GURL("file:///dev/null")); - ASSERT_TRUE(req_manager); - ASSERT_TRUE(req_manager->is_request_alive()); + auto mock_fetcher = make_scoped_refptr(new StrictMock<MockCertNetFetcher>()); - RequestManager* req_manager2 = - mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia2/I2.foo")); - ASSERT_TRUE(req_manager2); - ASSERT_TRUE(req_manager2->is_request_alive()); + EXPECT_CALL(*mock_fetcher, FetchCaIssuers(GURL("file:///dev/null"), _, _)) + .WillOnce(Return(ByMove(CreateMockRequest(ERR_DISALLOWED_URL_SCHEME)))); - // Request for file URL completes with disallowed scheme failure. Callback is - // NOT called. - req_manager->get_callback().Run(ERR_DISALLOWED_URL_SCHEME, - std::vector<uint8_t>()); - Mock::VerifyAndClearExpectations(&mock_callback); - - // Request for I2.foo completes. Callback should be called now. - EXPECT_CALL(mock_callback, Callback(cert_source_request.get())); - req_manager2->get_callback().Run(OK, CertDataVector(intermediate_cert.get())); - Mock::VerifyAndClearExpectations(&mock_callback); + EXPECT_CALL(*mock_fetcher, + FetchCaIssuers(GURL("http://url-for-aia2/I2.foo"), _, _)) + .WillOnce(Return( + ByMove(CreateMockRequest(CertDataVector(intermediate_cert.get()))))); - scoped_refptr<ParsedCertificate> result_cert; - CompletionStatus status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - ASSERT_TRUE(result_cert.get()); - ASSERT_EQ(result_cert->der_cert(), intermediate_cert->der_cert()); + CertIssuerSourceAia aia_source(mock_fetcher); + std::unique_ptr<CertIssuerSource::Request> cert_source_request; + aia_source.AsyncGetIssuersOf(cert.get(), &cert_source_request); + ASSERT_NE(nullptr, cert_source_request); - status = cert_source_request->GetNext(&result_cert); - EXPECT_EQ(CompletionStatus::SYNC, status); - EXPECT_FALSE(result_cert.get()); + ParsedCertificateList result_certs; + cert_source_request->GetNext(&result_certs); + ASSERT_EQ(1u, result_certs.size()); + ASSERT_EQ(result_certs.front()->der_cert(), intermediate_cert->der_cert()); - EXPECT_TRUE(req_manager2->is_request_alive()); - cert_source_request.reset(); - EXPECT_FALSE(req_manager2->is_request_alive()); + cert_source_request->GetNext(&result_certs); + EXPECT_EQ(1u, result_certs.size()); } +// TODO(eroman): Re-enable these tests! +#if 0 // AuthorityInfoAccess with two URIs, one is invalid, the other HTTP. TEST(CertIssuerSourceAiaTest, OneInvalidOneHttpAia) { scoped_refptr<ParsedCertificate> cert; @@ -344,8 +252,9 @@ TEST(CertIssuerSourceAiaTest, OneInvalidOneHttpAia) { ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -389,8 +298,9 @@ TEST(CertIssuerSourceAiaTest, TwoAiaCompletedInSeries) { ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -465,8 +375,9 @@ TEST(CertIssuerSourceAiaTest, TwoAiaCompletedBeforeGetNext) { ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -537,8 +448,9 @@ TEST(CertIssuerSourceAiaTest, AiaRequestCompletesDuringGetNextSequence) { ASSERT_TRUE(ReadTestCert("i3.pem", &intermediate_cert3)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -613,8 +525,9 @@ TEST(CertIssuerSourceAiaTest, OneAiaHttpError) { ASSERT_TRUE(ReadTestCert("target_one_aia.pem", &cert)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -647,8 +560,9 @@ TEST(CertIssuerSourceAiaTest, OneAiaParseError) { ASSERT_TRUE(ReadTestCert("target_one_aia.pem", &cert)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -682,8 +596,9 @@ TEST(CertIssuerSourceAiaTest, TwoAiaCompletedInSeriesFirstFails) { ASSERT_TRUE(ReadTestCert("i2.pem", &intermediate_cert2)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -736,8 +651,9 @@ TEST(CertIssuerSourceAiaTest, TwoAiaCompletedInSeriesSecondFails) { ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -794,8 +710,9 @@ TEST(CertIssuerSourceAiaTest, CertSourceRequestCancelled) { ASSERT_TRUE(ReadTestCert("target_two_aia.pem", &cert)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -830,8 +747,9 @@ TEST(CertIssuerSourceAiaTest, TwoAiaOneCompletedThenRequestCancelled) { ASSERT_TRUE(ReadTestCert("i.pem", &intermediate_cert)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -881,8 +799,9 @@ TEST(CertIssuerSourceAiaTest, MaxFetchesPerCert) { ASSERT_TRUE(ReadTestCert("target_six_aia.pem", &cert)); StrictMock<MockIssuerCallback> mock_callback; - StrictMock<MockCertNetFetcherImpl> mock_fetcher; - CertIssuerSourceAia aia_source(&mock_fetcher); + scoped_refptr<StrictMock<MockCertNetFetcherImpl>> mock_fetcher( + new StrictMock<MockCertNetFetcherImpl>()); + CertIssuerSourceAia aia_source(mock_fetcher); std::unique_ptr<CertIssuerSource::Request> cert_source_request; aia_source.AsyncGetIssuersOf(cert.get(), base::Bind(&MockIssuerCallback::Callback, @@ -920,6 +839,8 @@ TEST(CertIssuerSourceAiaTest, MaxFetchesPerCert) { mock_fetcher.GetRequestManagerForURL(GURL("http://url-for-aia6/I6.foo"))); } +#endif + } // namespace } // namespace net diff --git a/chromium/net/cert/internal/cert_issuer_source_nss.cc b/chromium/net/cert/internal/cert_issuer_source_nss.cc new file mode 100644 index 00000000000..418efe3ada6 --- /dev/null +++ b/chromium/net/cert/internal/cert_issuer_source_nss.cc @@ -0,0 +1,62 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/cert/internal/cert_issuer_source_nss.h" + +#include <cert.h> +#include <certdb.h> + +#include "crypto/nss_util.h" +#include "net/cert/internal/cert_errors.h" +#include "net/cert/internal/parsed_certificate.h" + +namespace net { + +CertIssuerSourceNSS::CertIssuerSourceNSS() = default; +CertIssuerSourceNSS::~CertIssuerSourceNSS() = default; + +void CertIssuerSourceNSS::SyncGetIssuersOf(const ParsedCertificate* cert, + ParsedCertificateList* issuers) { + crypto::EnsureNSSInit(); + + SECItem name; + // Use the original issuer value instead of the normalized version. NSS does a + // less extensive normalization in its Name comparisons, so our normalized + // version may not match the unnormalized version. + name.len = cert->tbs().issuer_tlv.Length(); + name.data = const_cast<uint8_t*>(cert->tbs().issuer_tlv.UnsafeData()); + // |validOnly| in CERT_CreateSubjectCertList controls whether to return only + // certs that are valid at |sorttime|. Including expired certs could lead to + // more useful error messages in the case where a valid path can't be found, + // so request all matches. + CERTCertList* found_certs = CERT_CreateSubjectCertList( + nullptr /* certList */, CERT_GetDefaultCertDB(), &name, + PR_Now() /* sorttime */, PR_FALSE /* validOnly */); + if (!found_certs) + return; + + for (CERTCertListNode* node = CERT_LIST_HEAD(found_certs); + !CERT_LIST_END(node, found_certs); node = CERT_LIST_NEXT(node)) { + CertErrors errors; + scoped_refptr<ParsedCertificate> issuer_cert = ParsedCertificate::Create( + node->cert->derCert.data, node->cert->derCert.len, {}, &errors); + if (!issuer_cert) { + // TODO(crbug.com/634443): return errors better. + LOG(ERROR) << "Error parsing issuer certificate:\n" + << errors.ToDebugString(); + continue; + } + + issuers->push_back(std::move(issuer_cert)); + } + CERT_DestroyCertList(found_certs); +} + +void CertIssuerSourceNSS::AsyncGetIssuersOf(const ParsedCertificate* cert, + std::unique_ptr<Request>* out_req) { + // CertIssuerSourceNSS never returns asynchronous results. + out_req->reset(); +} + +} // namespace net diff --git a/chromium/net/cert/internal/cert_issuer_source_nss.h b/chromium/net/cert/internal/cert_issuer_source_nss.h new file mode 100644 index 00000000000..1621b3b0457 --- /dev/null +++ b/chromium/net/cert/internal/cert_issuer_source_nss.h @@ -0,0 +1,40 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_CERT_INTERNAL_CERT_ISSUER_SOURCE_NSS_H_ +#define NET_CERT_INTERNAL_CERT_ISSUER_SOURCE_NSS_H_ + +#include "net/base/net_export.h" +#include "net/cert/internal/cert_issuer_source.h" + +namespace net { + +// Returns issuers from NSS. Always returns results synchronously. +// This will return any matches from NSS, possibly including trust anchors, +// blacklisted/distrusted certs, and temporary/cached certs. In the current +// implementation, trust is checked in a separate stage of path building, so +// including trusted certs here doesn't cause any issues. In particular, a trust +// anchor being returned here indicates the path ending in that trust anchor +// must already have been tested and failed to verify, and now the pathbuilder +// is trying to find a different path through that certificate. Including +// distrusted certs is desirable so that those paths can be built (and then fail +// to verify), leading to a better error message. +class NET_EXPORT CertIssuerSourceNSS : public CertIssuerSource { + public: + CertIssuerSourceNSS(); + ~CertIssuerSourceNSS() override; + + // CertIssuerSource implementation: + void SyncGetIssuersOf(const ParsedCertificate* cert, + ParsedCertificateList* issuers) override; + void AsyncGetIssuersOf(const ParsedCertificate* cert, + std::unique_ptr<Request>* out_req) override; + + private: + DISALLOW_COPY_AND_ASSIGN(CertIssuerSourceNSS); +}; + +} // namespace net + +#endif // NET_CERT_INTERNAL_CERT_ISSUER_SOURCE_NSS_H_ diff --git a/chromium/net/cert/internal/cert_issuer_source_nss_unittest.cc b/chromium/net/cert/internal/cert_issuer_source_nss_unittest.cc new file mode 100644 index 00000000000..1653998aa24 --- /dev/null +++ b/chromium/net/cert/internal/cert_issuer_source_nss_unittest.cc @@ -0,0 +1,62 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/cert/internal/cert_issuer_source_nss.h" + +#include <cert.h> +#include <certdb.h> + +#include "base/strings/string_number_conversions.h" +#include "crypto/scoped_test_nss_db.h" +#include "net/cert/internal/cert_issuer_source_sync_unittest.h" +#include "net/cert/scoped_nss_types.h" +#include "net/cert/x509_certificate.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +class CertIssuerSourceNSSTestDelegate { + public: + void AddCert(scoped_refptr<ParsedCertificate> cert) { + ASSERT_TRUE(test_nssdb_.is_open()); + std::string nickname = GetUniqueNickname(); + ScopedCERTCertificate nss_cert( + X509Certificate::CreateOSCertHandleFromBytesWithNickname( + cert->der_cert().AsStringPiece().data(), cert->der_cert().Length(), + nickname.c_str())); + ASSERT_TRUE(nss_cert); + SECStatus srv = + PK11_ImportCert(test_nssdb_.slot(), nss_cert.get(), CK_INVALID_HANDLE, + nickname.c_str(), PR_FALSE /* includeTrust (unused) */); + ASSERT_EQ(SECSuccess, srv); + } + + CertIssuerSource& source() { return cert_issuer_source_nss_; } + + protected: + std::string GetUniqueNickname() { + return "cert_issuer_source_nss_unittest" + + base::UintToString(nickname_counter_++); + } + + crypto::ScopedTestNSSDB test_nssdb_; + CertIssuerSourceNSS cert_issuer_source_nss_; + unsigned int nickname_counter_ = 0; +}; + +INSTANTIATE_TYPED_TEST_CASE_P(CertIssuerSourceNSSTest, + CertIssuerSourceSyncTest, + CertIssuerSourceNSSTestDelegate); + +// NSS doesn't normalize UTF8String values, so use the not-normalized version of +// those tests. +INSTANTIATE_TYPED_TEST_CASE_P(CertIssuerSourceNSSNotNormalizedTest, + CertIssuerSourceSyncNotNormalizedTest, + CertIssuerSourceNSSTestDelegate); + +} // namespace + +} // namespace net diff --git a/chromium/net/cert/internal/cert_issuer_source_static.cc b/chromium/net/cert/internal/cert_issuer_source_static.cc index d8a42a3f30e..e6ddb27b39f 100644 --- a/chromium/net/cert/internal/cert_issuer_source_static.cc +++ b/chromium/net/cert/internal/cert_issuer_source_static.cc @@ -24,7 +24,6 @@ void CertIssuerSourceStatic::SyncGetIssuersOf(const ParsedCertificate* cert, void CertIssuerSourceStatic::AsyncGetIssuersOf( const ParsedCertificate* cert, - const IssuerCallback& issuers_callback, std::unique_ptr<Request>* out_req) { // CertIssuerSourceStatic never returns asynchronous results. out_req->reset(); diff --git a/chromium/net/cert/internal/cert_issuer_source_static.h b/chromium/net/cert/internal/cert_issuer_source_static.h index 143e97d660b..4f9240b6e94 100644 --- a/chromium/net/cert/internal/cert_issuer_source_static.h +++ b/chromium/net/cert/internal/cert_issuer_source_static.h @@ -27,7 +27,6 @@ class NET_EXPORT CertIssuerSourceStatic : public CertIssuerSource { void SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) override; void AsyncGetIssuersOf(const ParsedCertificate* cert, - const IssuerCallback& issuers_callback, std::unique_ptr<Request>* out_req) override; private: diff --git a/chromium/net/cert/internal/cert_issuer_source_static_unittest.cc b/chromium/net/cert/internal/cert_issuer_source_static_unittest.cc index 949035c0eb1..627757f6c6d 100644 --- a/chromium/net/cert/internal/cert_issuer_source_static_unittest.cc +++ b/chromium/net/cert/internal/cert_issuer_source_static_unittest.cc @@ -4,142 +4,33 @@ #include "net/cert/internal/cert_issuer_source_static.h" -#include "base/bind.h" -#include "net/cert/internal/cert_errors.h" +#include "net/cert/internal/cert_issuer_source_sync_unittest.h" #include "net/cert/internal/parsed_certificate.h" -#include "net/cert/internal/test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { namespace { -void NotCalled(CertIssuerSource::Request* req) { - ADD_FAILURE() << "NotCalled was called"; -} - -::testing::AssertionResult ReadTestPem(const std::string& file_name, - const std::string& block_name, - std::string* result) { - const PemBlockMapping mappings[] = { - {block_name.c_str(), result}, - }; - - return ReadTestDataFromPemFile(file_name, mappings); -} - -::testing::AssertionResult ReadTestCert( - const std::string& file_name, - scoped_refptr<ParsedCertificate>* result) { - std::string der; - ::testing::AssertionResult r = - ReadTestPem("net/data/cert_issuer_source_static_unittest/" + file_name, - "CERTIFICATE", &der); - if (!r) - return r; - CertErrors errors; - *result = ParsedCertificate::Create(der, {}, &errors); - if (!*result) { - return ::testing::AssertionFailure() - << "ParsedCertificate::Create() failed:\n" - << errors.ToDebugString(); - } - return ::testing::AssertionSuccess(); -} - -class CertIssuerSourceStaticTest : public ::testing::Test { +class CertIssuerSourceStaticTestDelegate { public: - void SetUp() override { - ASSERT_TRUE(ReadTestCert("root.pem", &root_)); - ASSERT_TRUE(ReadTestCert("i1_1.pem", &i1_1_)); - ASSERT_TRUE(ReadTestCert("i1_2.pem", &i1_2_)); - ASSERT_TRUE(ReadTestCert("i2.pem", &i2_)); - ASSERT_TRUE(ReadTestCert("c1.pem", &c1_)); - ASSERT_TRUE(ReadTestCert("c2.pem", &c2_)); - ASSERT_TRUE(ReadTestCert("d.pem", &d_)); + void AddCert(scoped_refptr<ParsedCertificate> cert) { + source_.AddCert(std::move(cert)); } - void AddAllCerts(CertIssuerSourceStatic* source) { - source->AddCert(root_); - source->AddCert(i1_1_); - source->AddCert(i1_2_); - source->AddCert(i2_); - source->AddCert(c1_); - source->AddCert(c2_); - source->AddCert(d_); - } + CertIssuerSource& source() { return source_; } protected: - scoped_refptr<ParsedCertificate> root_; - scoped_refptr<ParsedCertificate> i1_1_; - scoped_refptr<ParsedCertificate> i1_2_; - scoped_refptr<ParsedCertificate> i2_; - scoped_refptr<ParsedCertificate> c1_; - scoped_refptr<ParsedCertificate> c2_; - scoped_refptr<ParsedCertificate> d_; + CertIssuerSourceStatic source_; }; -TEST_F(CertIssuerSourceStaticTest, NoMatch) { - CertIssuerSourceStatic source; - source.AddCert(root_); - - ParsedCertificateList issuers; - source.SyncGetIssuersOf(c1_.get(), &issuers); - ASSERT_EQ(0U, issuers.size()); -} - -TEST_F(CertIssuerSourceStaticTest, OneMatch) { - CertIssuerSourceStatic source; - AddAllCerts(&source); - - ParsedCertificateList issuers; - source.SyncGetIssuersOf(i1_1_.get(), &issuers); - ASSERT_EQ(1U, issuers.size()); - EXPECT_TRUE(issuers[0] == root_); - - issuers.clear(); - source.SyncGetIssuersOf(d_.get(), &issuers); - ASSERT_EQ(1U, issuers.size()); - EXPECT_TRUE(issuers[0] == i2_); -} - -TEST_F(CertIssuerSourceStaticTest, MultipleMatches) { - CertIssuerSourceStatic source; - AddAllCerts(&source); - - ParsedCertificateList issuers; - source.SyncGetIssuersOf(c1_.get(), &issuers); - - ASSERT_EQ(2U, issuers.size()); - EXPECT_TRUE(std::find(issuers.begin(), issuers.end(), i1_1_) != - issuers.end()); - EXPECT_TRUE(std::find(issuers.begin(), issuers.end(), i1_2_) != - issuers.end()); -} - -// Searching for the issuer of a self-issued cert returns the same cert if it -// happens to be in the CertIssuerSourceStatic. -// Conceptually this makes sense, though probably not very useful in practice. -// Doesn't hurt anything though. -TEST_F(CertIssuerSourceStaticTest, SelfIssued) { - CertIssuerSourceStatic source; - AddAllCerts(&source); - - ParsedCertificateList issuers; - source.SyncGetIssuersOf(root_.get(), &issuers); - - ASSERT_EQ(1U, issuers.size()); - EXPECT_TRUE(issuers[0] == root_); -} +INSTANTIATE_TYPED_TEST_CASE_P(CertIssuerSourceStaticTest, + CertIssuerSourceSyncTest, + CertIssuerSourceStaticTestDelegate); -// CertIssuerSourceStatic never returns results asynchronously. -TEST_F(CertIssuerSourceStaticTest, IsNotAsync) { - CertIssuerSourceStatic source; - source.AddCert(i1_1_); - std::unique_ptr<CertIssuerSource::Request> request; - source.AsyncGetIssuersOf(c1_.get(), base::Bind(&NotCalled), &request); - EXPECT_EQ(nullptr, request); -} +INSTANTIATE_TYPED_TEST_CASE_P(CertIssuerSourceStaticNormalizationTest, + CertIssuerSourceSyncNormalizationTest, + CertIssuerSourceStaticTestDelegate); } // namespace diff --git a/chromium/net/cert/internal/cert_issuer_source_sync_unittest.h b/chromium/net/cert/internal/cert_issuer_source_sync_unittest.h new file mode 100644 index 00000000000..6b36b2fe28f --- /dev/null +++ b/chromium/net/cert/internal/cert_issuer_source_sync_unittest.h @@ -0,0 +1,210 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_CERT_INTERNAL_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_ +#define NET_CERT_INTERNAL_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_ + +#include "net/cert/internal/cert_errors.h" +#include "net/cert/internal/cert_issuer_source.h" +#include "net/cert/internal/test_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +::testing::AssertionResult ReadTestPem(const std::string& file_name, + const std::string& block_name, + std::string* result) { + const PemBlockMapping mappings[] = { + {block_name.c_str(), result}, + }; + + return ReadTestDataFromPemFile(file_name, mappings); +} + +::testing::AssertionResult ReadTestCert( + const std::string& file_name, + scoped_refptr<ParsedCertificate>* result) { + std::string der; + ::testing::AssertionResult r = + ReadTestPem("net/data/cert_issuer_source_static_unittest/" + file_name, + "CERTIFICATE", &der); + if (!r) + return r; + CertErrors errors; + *result = ParsedCertificate::Create(der, {}, &errors); + if (!*result) { + return ::testing::AssertionFailure() + << "ParsedCertificate::Create() failed:\n" + << errors.ToDebugString(); + } + return ::testing::AssertionSuccess(); +} + +} // namespace + +template <typename TestDelegate> +class CertIssuerSourceSyncTest : public ::testing::Test { + public: + void SetUp() override { + ASSERT_TRUE(ReadTestCert("root.pem", &root_)); + ASSERT_TRUE(ReadTestCert("i1_1.pem", &i1_1_)); + ASSERT_TRUE(ReadTestCert("i1_2.pem", &i1_2_)); + ASSERT_TRUE(ReadTestCert("i2.pem", &i2_)); + ASSERT_TRUE(ReadTestCert("i3_1.pem", &i3_1_)); + ASSERT_TRUE(ReadTestCert("i3_2.pem", &i3_2_)); + ASSERT_TRUE(ReadTestCert("c1.pem", &c1_)); + ASSERT_TRUE(ReadTestCert("c2.pem", &c2_)); + ASSERT_TRUE(ReadTestCert("d.pem", &d_)); + ASSERT_TRUE(ReadTestCert("e1.pem", &e1_)); + ASSERT_TRUE(ReadTestCert("e2.pem", &e2_)); + } + + void AddCert(scoped_refptr<ParsedCertificate> cert) { + delegate_.AddCert(std::move(cert)); + } + + void AddAllCerts() { + AddCert(root_); + AddCert(i1_1_); + AddCert(i1_2_); + AddCert(i2_); + AddCert(i3_1_); + AddCert(i3_2_); + AddCert(c1_); + AddCert(c2_); + AddCert(d_); + AddCert(e1_); + AddCert(e2_); + } + + CertIssuerSource& source() { return delegate_.source(); } + + protected: + bool IssuersMatch(scoped_refptr<ParsedCertificate> cert, + ParsedCertificateList expected_matches) { + ParsedCertificateList matches; + source().SyncGetIssuersOf(cert.get(), &matches); + + std::vector<der::Input> der_result_matches; + for (const auto& it : matches) + der_result_matches.push_back(it->der_cert()); + std::sort(der_result_matches.begin(), der_result_matches.end()); + + std::vector<der::Input> der_expected_matches; + for (const auto& it : expected_matches) + der_expected_matches.push_back(it->der_cert()); + std::sort(der_expected_matches.begin(), der_expected_matches.end()); + + if (der_expected_matches == der_result_matches) + return true; + + // Print some extra information for debugging. + EXPECT_EQ(der_expected_matches, der_result_matches); + return false; + } + + TestDelegate delegate_; + scoped_refptr<ParsedCertificate> root_; + scoped_refptr<ParsedCertificate> i1_1_; + scoped_refptr<ParsedCertificate> i1_2_; + scoped_refptr<ParsedCertificate> i2_; + scoped_refptr<ParsedCertificate> i3_1_; + scoped_refptr<ParsedCertificate> i3_2_; + scoped_refptr<ParsedCertificate> c1_; + scoped_refptr<ParsedCertificate> c2_; + scoped_refptr<ParsedCertificate> d_; + scoped_refptr<ParsedCertificate> e1_; + scoped_refptr<ParsedCertificate> e2_; +}; + +TYPED_TEST_CASE_P(CertIssuerSourceSyncTest); + +TYPED_TEST_P(CertIssuerSourceSyncTest, NoMatch) { + this->AddCert(this->root_); + + EXPECT_TRUE(this->IssuersMatch(this->c1_, ParsedCertificateList())); +} + +TYPED_TEST_P(CertIssuerSourceSyncTest, OneMatch) { + this->AddAllCerts(); + + EXPECT_TRUE(this->IssuersMatch(this->i1_1_, {this->root_})); + EXPECT_TRUE(this->IssuersMatch(this->d_, {this->i2_})); +} + +TYPED_TEST_P(CertIssuerSourceSyncTest, MultipleMatches) { + this->AddAllCerts(); + + EXPECT_TRUE(this->IssuersMatch(this->e1_, {this->i3_1_, this->i3_2_})); + EXPECT_TRUE(this->IssuersMatch(this->e2_, {this->i3_1_, this->i3_2_})); +} + +// Searching for the issuer of a self-issued cert returns the same cert if it +// happens to be in the CertIssuerSourceStatic. +// Conceptually this makes sense, though probably not very useful in practice. +// Doesn't hurt anything though. +TYPED_TEST_P(CertIssuerSourceSyncTest, SelfIssued) { + this->AddAllCerts(); + + EXPECT_TRUE(this->IssuersMatch(this->root_, {this->root_})); +} + +// CertIssuerSourceStatic never returns results asynchronously. +TYPED_TEST_P(CertIssuerSourceSyncTest, IsNotAsync) { + this->AddCert(this->i1_1_); + std::unique_ptr<CertIssuerSource::Request> request; + this->source().AsyncGetIssuersOf(this->c1_.get(), &request); + EXPECT_EQ(nullptr, request); +} + +// These are all the tests that should have the same result with or without +// normalization. +REGISTER_TYPED_TEST_CASE_P(CertIssuerSourceSyncTest, + NoMatch, + OneMatch, + MultipleMatches, + SelfIssued, + IsNotAsync); + +template <typename TestDelegate> +class CertIssuerSourceSyncNormalizationTest + : public CertIssuerSourceSyncTest<TestDelegate> {}; +TYPED_TEST_CASE_P(CertIssuerSourceSyncNormalizationTest); + +TYPED_TEST_P(CertIssuerSourceSyncNormalizationTest, + MultipleMatchesAfterNormalization) { + this->AddAllCerts(); + + EXPECT_TRUE(this->IssuersMatch(this->c1_, {this->i1_1_, this->i1_2_})); + EXPECT_TRUE(this->IssuersMatch(this->c2_, {this->i1_1_, this->i1_2_})); +} + +// These tests require (utf8) normalization. +REGISTER_TYPED_TEST_CASE_P(CertIssuerSourceSyncNormalizationTest, + MultipleMatchesAfterNormalization); + +template <typename TestDelegate> +class CertIssuerSourceSyncNotNormalizedTest + : public CertIssuerSourceSyncTest<TestDelegate> {}; +TYPED_TEST_CASE_P(CertIssuerSourceSyncNotNormalizedTest); + +TYPED_TEST_P(CertIssuerSourceSyncNotNormalizedTest, + OneMatchWithoutNormalization) { + this->AddAllCerts(); + + // Without normalization c1 and c2 should at least be able to find their + // exact matching issuer. (c1 should match i1_1, and c2 should match i1_2.) + EXPECT_TRUE(this->IssuersMatch(this->c1_, {this->i1_1_})); + EXPECT_TRUE(this->IssuersMatch(this->c2_, {this->i1_2_})); +} + +// These tests are for implementations which do not do utf8 normalization. +REGISTER_TYPED_TEST_CASE_P(CertIssuerSourceSyncNotNormalizedTest, + OneMatchWithoutNormalization); + +} // namespace net + +#endif // NET_CERT_INTERNAL_CERT_ISSUER_SOURCE_SYNC_UNITTEST_H_ diff --git a/chromium/net/cert/internal/completion_status.h b/chromium/net/cert/internal/completion_status.h deleted file mode 100644 index 69126cd6010..00000000000 --- a/chromium/net/cert/internal/completion_status.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_CERT_INTERNAL_COMPLETION_STATUS_H_ -#define NET_CERT_INTERNAL_COMPLETION_STATUS_H_ - -namespace net { - -enum class CompletionStatus { - SYNC, - ASYNC, -}; - -} // namespace net - -#endif // NET_CERT_INTERNAL_COMPLETION_STATUS_H_ diff --git a/chromium/net/cert/internal/name_constraints.cc b/chromium/net/cert/internal/name_constraints.cc index 162569f964c..0ed685101e9 100644 --- a/chromium/net/cert/internal/name_constraints.cc +++ b/chromium/net/cert/internal/name_constraints.cc @@ -87,6 +87,11 @@ bool DNSNameMatches(base::StringPiece name, // Exact match. if (name.size() == dns_constraint.size()) return true; + // If dNSName constraint starts with a dot, only subdomains should match. + // (e.g., "foo.bar.com" matches constraint ".bar.com", but "bar.com" doesn't.) + // RFC 5280 is ambiguous, but this matches the behavior of other platforms. + if (!dns_constraint.empty() && dns_constraint[0] == '.') + dns_constraint.remove_prefix(1); // Subtree match. if (name.size() > dns_constraint.size() && name[name.size() - dns_constraint.size() - 1] == '.') { diff --git a/chromium/net/cert/internal/name_constraints_unittest.cc b/chromium/net/cert/internal/name_constraints_unittest.cc index f1dd470d093..150d851c491 100644 --- a/chromium/net/cert/internal/name_constraints_unittest.cc +++ b/chromium/net/cert/internal/name_constraints_unittest.cc @@ -186,7 +186,7 @@ TEST_P(ParseNameConstraints, EXPECT_FALSE(name_constraints->IsPermittedDNSName("*.foo.bar.com")); } -TEST_P(ParseNameConstraints, DNSNamesWithLeadingDot) { +TEST_P(ParseNameConstraints, DNSNamesPermittedWithLeadingDot) { std::string a; ASSERT_TRUE( LoadTestNameConstraint("dnsname-permitted_with_leading_dot.pem", &a)); @@ -194,13 +194,44 @@ TEST_P(ParseNameConstraints, DNSNamesWithLeadingDot) { NameConstraints::Create(der::Input(&a), is_critical())); ASSERT_TRUE(name_constraints); - // dNSName constraints should be specified as a host. A dNSName constraint - // with a leading "." doesn't make sense, though some certs include it - // (probably confusing it with the rules for uniformResourceIdentifier - // constraints). It should not match anything. + // A permitted dNSName constraint of ".bar.com" should only match subdomains + // of .bar.com, but not bar.com itself. EXPECT_FALSE(name_constraints->IsPermittedDNSName("com")); EXPECT_FALSE(name_constraints->IsPermittedDNSName("bar.com")); + EXPECT_FALSE(name_constraints->IsPermittedDNSName("foobar.com")); + EXPECT_TRUE(name_constraints->IsPermittedDNSName("foo.bar.com")); + EXPECT_TRUE(name_constraints->IsPermittedDNSName("*.bar.com")); +} + +TEST_P(ParseNameConstraints, DNSNamesExcludedWithLeadingDot) { + std::string a; + ASSERT_TRUE( + LoadTestNameConstraint("dnsname-excluded_with_leading_dot.pem", &a)); + std::unique_ptr<NameConstraints> name_constraints( + NameConstraints::Create(der::Input(&a), is_critical())); + ASSERT_TRUE(name_constraints); + + // An excluded dNSName constraint of ".bar.com" should only match subdomains + // of .bar.com, but not bar.com itself. + EXPECT_TRUE(name_constraints->IsPermittedDNSName("com")); + EXPECT_TRUE(name_constraints->IsPermittedDNSName("bar.com")); + EXPECT_TRUE(name_constraints->IsPermittedDNSName("foobar.com")); EXPECT_FALSE(name_constraints->IsPermittedDNSName("foo.bar.com")); + EXPECT_FALSE(name_constraints->IsPermittedDNSName("*.bar.com")); +} + +TEST_P(ParseNameConstraints, DNSNamesPermittedTwoDot) { + std::string a; + ASSERT_TRUE(LoadTestNameConstraint("dnsname-permitted_two_dot.pem", &a)); + std::unique_ptr<NameConstraints> name_constraints( + NameConstraints::Create(der::Input(&a), is_critical())); + ASSERT_TRUE(name_constraints); + + // A dNSName constraint of ".." isn't meaningful. Shouldn't match anything. + EXPECT_FALSE(name_constraints->IsPermittedDNSName("com")); + EXPECT_FALSE(name_constraints->IsPermittedDNSName("com.")); + EXPECT_FALSE(name_constraints->IsPermittedDNSName("foo.com")); + EXPECT_FALSE(name_constraints->IsPermittedDNSName("*.com")); } TEST_P(ParseNameConstraints, DNSNamesExcludeOnly) { diff --git a/chromium/net/cert/internal/nist_pkits_unittest.h b/chromium/net/cert/internal/nist_pkits_unittest.h index 47fd46274d6..6a454020ffb 100644 --- a/chromium/net/cert/internal/nist_pkits_unittest.h +++ b/chromium/net/cert/internal/nist_pkits_unittest.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_CERT_INTERNAL_NIST_PKITS_UNITTEST_H -#define NET_CERT_INTERNAL_NIST_PKITS_UNITTEST_H +#ifndef NET_CERT_INTERNAL_NIST_PKITS_UNITTEST_H_ +#define NET_CERT_INTERNAL_NIST_PKITS_UNITTEST_H_ #include "net/cert/internal/test_helpers.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,4 +33,4 @@ class PkitsTest : public ::testing::Test { // Inline the generated test code: #include "net/third_party/nist-pkits/pkits_testcases-inl.h" -#endif // NET_CERT_INTERNAL_NIST_PKITS_UNITTEST_H +#endif // NET_CERT_INTERNAL_NIST_PKITS_UNITTEST_H_ diff --git a/chromium/net/cert/internal/parse_certificate_unittest.cc b/chromium/net/cert/internal/parse_certificate_unittest.cc index 08c37944cea..a54d895acba 100644 --- a/chromium/net/cert/internal/parse_certificate_unittest.cc +++ b/chromium/net/cert/internal/parse_certificate_unittest.cc @@ -6,10 +6,6 @@ #include "base/strings/stringprintf.h" #include "net/cert/internal/cert_errors.h" -// TODO(eroman): These tests should be moved into -// parsed_certificate_unittest.cc; this include dependency should -// go. -#include "net/cert/internal/parsed_certificate.h" #include "net/cert/internal/test_helpers.h" #include "net/der/input.h" #include "testing/gtest/include/gtest/gtest.h" @@ -79,37 +75,6 @@ void RunCertificateTest(const std::string& file_name) { } } -// Reads and parses a certificate from the PEM file |file_name|. -// -// Returns nullptr if the certificate parsing failed, and verifies that any -// errors match the ERRORS block in the .pem file. -scoped_refptr<ParsedCertificate> ParseCertificateFromFile( - const std::string& file_name) { - std::string data; - std::string expected_errors; - - // Read the certificate data and error expectations from a single PEM file. - const PemBlockMapping mappings[] = { - {"CERTIFICATE", &data}, {"ERRORS", &expected_errors, true /*optional*/}, - }; - std::string test_file_path = GetFilePath(file_name); - EXPECT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings)); - - CertErrors errors; - scoped_refptr<ParsedCertificate> cert = - ParsedCertificate::Create(data, {}, &errors); - - EXPECT_EQ(expected_errors, errors.ToDebugString()) << "Test file: " - << test_file_path; - - // TODO(crbug.com/634443): Every parse failure being tested should emit error - // information. - // if (!cert) - // EXPECT_FALSE(errors.empty()); - - return cert; -} - // Tests parsing a Certificate. TEST(ParseCertificateTest, Version3) { RunCertificateTest("cert_version3.pem"); @@ -362,255 +327,6 @@ TEST(ParseTbsCertificateTest, ValidityRelaxed) { RunTbsCertificateTest("tbs_validity_relaxed.pem"); } -der::Input DavidBenOid() { - // This OID corresponds with - // 1.2.840.113554.4.1.72585.0 (https://davidben.net/oid) - static const uint8_t kOid[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, - 0x04, 0x01, 0x84, 0xb7, 0x09, 0x00}; - return der::Input(kOid); -} - -// Parses an Extension whose critical field is true (255). -TEST(ParseCertificateTest, ExtensionCritical) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("extension_critical.pem"); - ASSERT_TRUE(cert); - - const uint8_t kExpectedValue[] = {0x30, 0x00}; - - auto it = cert->unparsed_extensions().find(DavidBenOid()); - ASSERT_NE(cert->unparsed_extensions().end(), it); - const auto& extension = it->second; - - EXPECT_TRUE(extension.critical); - EXPECT_EQ(DavidBenOid(), extension.oid); - EXPECT_EQ(der::Input(kExpectedValue), extension.value); -} - -// Parses an Extension whose critical field is false (omitted). -TEST(ParseCertificateTest, ExtensionNotCritical) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("extension_not_critical.pem"); - ASSERT_TRUE(cert); - - const uint8_t kExpectedValue[] = {0x30, 0x00}; - - auto it = cert->unparsed_extensions().find(DavidBenOid()); - ASSERT_NE(cert->unparsed_extensions().end(), it); - const auto& extension = it->second; - - EXPECT_FALSE(extension.critical); - EXPECT_EQ(DavidBenOid(), extension.oid); - EXPECT_EQ(der::Input(kExpectedValue), extension.value); -} - -// Parses an Extension whose critical field is 0. This is in one sense FALSE, -// however because critical has DEFAULT of false this is in fact invalid -// DER-encoding. -TEST(ParseCertificateTest, ExtensionCritical0) { - ASSERT_FALSE(ParseCertificateFromFile("extension_critical_0.pem")); -} - -// Parses an Extension whose critical field is 3. Under DER-encoding BOOLEAN -// values must an octet of either all zero bits, or all 1 bits, so this is not -// valid. -TEST(ParseCertificateTest, ExtensionCritical3) { - ASSERT_FALSE(ParseCertificateFromFile("extension_critical_3.pem")); -} - -// Parses an Extensions that is an empty sequence. -TEST(ParseCertificateTest, ExtensionsEmptySequence) { - ASSERT_FALSE(ParseCertificateFromFile("extensions_empty_sequence.pem")); -} - -// Parses an Extensions that is not a sequence. -TEST(ParseCertificateTest, ExtensionsNotSequence) { - ASSERT_FALSE(ParseCertificateFromFile("extensions_not_sequence.pem")); -} - -// Parses an Extensions that has data after the sequence. -TEST(ParseCertificateTest, ExtensionsDataAfterSequence) { - ASSERT_FALSE(ParseCertificateFromFile("extensions_data_after_sequence.pem")); -} - -// Parses an Extensions that contains duplicated key usages. -TEST(ParseCertificateTest, ExtensionsDuplicateKeyUsage) { - ASSERT_FALSE(ParseCertificateFromFile("extensions_duplicate_key_usage.pem")); -} - -// Parses an Extensions that contains an extended key usages. -TEST(ParseCertificateTest, ExtendedKeyUsage) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("extended_key_usage.pem"); - ASSERT_TRUE(cert); - - const auto& extensions = cert->unparsed_extensions(); - ASSERT_EQ(3u, extensions.size()); - - auto iter = extensions.find(ExtKeyUsageOid()); - ASSERT_TRUE(iter != extensions.end()); - EXPECT_FALSE(iter->second.critical); - EXPECT_EQ(45u, iter->second.value.Length()); -} - -// Parses an Extensions that contains a key usage. -TEST(ParseCertificateTest, KeyUsage) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("key_usage.pem"); - ASSERT_TRUE(cert); - - ASSERT_TRUE(cert->has_key_usage()); - - EXPECT_EQ(5u, cert->key_usage().unused_bits()); - const uint8_t kExpectedBytes[] = {0xA0}; - EXPECT_EQ(der::Input(kExpectedBytes), cert->key_usage().bytes()); - - EXPECT_TRUE(cert->key_usage().AssertsBit(0)); - EXPECT_FALSE(cert->key_usage().AssertsBit(1)); - EXPECT_TRUE(cert->key_usage().AssertsBit(2)); -} - -// Parses an Extensions that contains a policies extension. -TEST(ParseCertificateTest, Policies) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("policies.pem"); - ASSERT_TRUE(cert); - - const auto& extensions = cert->unparsed_extensions(); - ASSERT_EQ(3u, extensions.size()); - - auto iter = extensions.find(CertificatePoliciesOid()); - ASSERT_TRUE(iter != extensions.end()); - EXPECT_FALSE(iter->second.critical); - EXPECT_EQ(95u, iter->second.value.Length()); -} - -// Parses an Extensions that contains a subjectaltname extension. -TEST(ParseCertificateTest, SubjectAltName) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("subject_alt_name.pem"); - ASSERT_TRUE(cert); - - ASSERT_TRUE(cert->has_subject_alt_names()); -} - -// Parses an Extensions that contains multiple extensions, sourced from a -// real-world certificate. -TEST(ParseCertificateTest, ExtensionsReal) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("extensions_real.pem"); - ASSERT_TRUE(cert); - - const auto& extensions = cert->unparsed_extensions(); - ASSERT_EQ(4u, extensions.size()); - - EXPECT_TRUE(cert->has_key_usage()); - EXPECT_TRUE(cert->has_basic_constraints()); - - auto iter = extensions.find(CertificatePoliciesOid()); - ASSERT_TRUE(iter != extensions.end()); - EXPECT_FALSE(iter->second.critical); - EXPECT_EQ(16u, iter->second.value.Length()); - - // TODO(eroman): Verify the other 4 extensions' values. -} - -// Parses a BasicConstraints with no CA or pathlen. -TEST(ParseCertificateTest, BasicConstraintsNotCa) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("basic_constraints_not_ca.pem"); - ASSERT_TRUE(cert); - - EXPECT_TRUE(cert->has_basic_constraints()); - EXPECT_FALSE(cert->basic_constraints().is_ca); - EXPECT_FALSE(cert->basic_constraints().has_path_len); -} - -// Parses a BasicConstraints with CA but no pathlen. -TEST(ParseCertificateTest, BasicConstraintsCaNoPath) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("basic_constraints_ca_no_path.pem"); - ASSERT_TRUE(cert); - - EXPECT_TRUE(cert->has_basic_constraints()); - EXPECT_TRUE(cert->basic_constraints().is_ca); - EXPECT_FALSE(cert->basic_constraints().has_path_len); -} - -// Parses a BasicConstraints with CA and pathlen of 9. -TEST(ParseCertificateTest, BasicConstraintsCaPath9) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("basic_constraints_ca_path_9.pem"); - ASSERT_TRUE(cert); - - EXPECT_TRUE(cert->has_basic_constraints()); - EXPECT_TRUE(cert->basic_constraints().is_ca); - EXPECT_TRUE(cert->basic_constraints().has_path_len); - EXPECT_EQ(9u, cert->basic_constraints().path_len); -} - -// Parses a BasicConstraints with CA and pathlen of 255 (largest allowed size). -TEST(ParseCertificateTest, BasicConstraintsPathlen255) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("basic_constraints_pathlen_255.pem"); - ASSERT_TRUE(cert); - - EXPECT_TRUE(cert->has_basic_constraints()); - EXPECT_TRUE(cert->basic_constraints().is_ca); - EXPECT_TRUE(cert->basic_constraints().has_path_len); - EXPECT_EQ(255, cert->basic_constraints().path_len); -} - -// Parses a BasicConstraints with CA and pathlen of 256 (too large). -TEST(ParseCertificateTest, BasicConstraintsPathlen256) { - ASSERT_FALSE(ParseCertificateFromFile("basic_constraints_pathlen_256.pem")); -} - -// Parses a BasicConstraints with CA and a negative pathlen. -TEST(ParseCertificateTest, BasicConstraintsNegativePath) { - ASSERT_FALSE(ParseCertificateFromFile("basic_constraints_negative_path.pem")); -} - -// Parses a BasicConstraints with CA and pathlen that is very large (and -// couldn't fit in a 64-bit integer). -TEST(ParseCertificateTest, BasicConstraintsPathTooLarge) { - ASSERT_FALSE( - ParseCertificateFromFile("basic_constraints_path_too_large.pem")); -} - -// Parses a BasicConstraints with CA explicitly set to false. This violates -// DER-encoding rules, however is commonly used, so it is accepted. -TEST(ParseCertificateTest, BasicConstraintsCaFalse) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("basic_constraints_ca_false.pem"); - ASSERT_TRUE(cert); - - EXPECT_TRUE(cert->has_basic_constraints()); - EXPECT_FALSE(cert->basic_constraints().is_ca); - EXPECT_FALSE(cert->basic_constraints().has_path_len); -} - -// Parses a BasicConstraints with CA set to true and an unexpected NULL at -// the end. -TEST(ParseCertificateTest, BasicConstraintsUnconsumedData) { - ASSERT_FALSE( - ParseCertificateFromFile("basic_constraints_unconsumed_data.pem")); -} - -// Parses a BasicConstraints with CA omitted (false), but with a pathlen of 1. -// This is valid DER for the ASN.1, however is not valid when interpreting the -// BasicConstraints at a higher level. -TEST(ParseCertificateTest, BasicConstraintsPathLenButNotCa) { - scoped_refptr<ParsedCertificate> cert = - ParseCertificateFromFile("basic_constraints_pathlen_not_ca.pem"); - ASSERT_TRUE(cert); - - EXPECT_TRUE(cert->has_basic_constraints()); - EXPECT_FALSE(cert->basic_constraints().is_ca); - EXPECT_TRUE(cert->basic_constraints().has_path_len); - EXPECT_EQ(1u, cert->basic_constraints().path_len); -} - // Parses a KeyUsage with a single 0 bit. TEST(ParseKeyUsageTest, OneBitAllZeros) { const uint8_t der[] = { diff --git a/chromium/net/cert/internal/parse_ocsp.cc b/chromium/net/cert/internal/parse_ocsp.cc index 2f734102270..0e13fc3d09a 100644 --- a/chromium/net/cert/internal/parse_ocsp.cc +++ b/chromium/net/cert/internal/parse_ocsp.cc @@ -5,6 +5,7 @@ #include <algorithm> #include "base/sha1.h" +#include "base/time/time.h" #include "crypto/sha2.h" #include "net/cert/internal/cert_errors.h" #include "net/cert/internal/parse_ocsp.h" diff --git a/chromium/net/cert/internal/parsed_certificate_unittest.cc b/chromium/net/cert/internal/parsed_certificate_unittest.cc new file mode 100644 index 00000000000..ab1d4a0f91c --- /dev/null +++ b/chromium/net/cert/internal/parsed_certificate_unittest.cc @@ -0,0 +1,303 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/cert/internal/parsed_certificate.h" + +#include "net/cert/internal/cert_errors.h" +#include "net/cert/internal/parse_certificate.h" +#include "net/cert/internal/test_helpers.h" +#include "net/der/input.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +std::string GetFilePath(const std::string& file_name) { + return std::string("net/data/parse_certificate_unittest/") + file_name; +} + +// Reads and parses a certificate from the PEM file |file_name|. +// +// Returns nullptr if the certificate parsing failed, and verifies that any +// errors match the ERRORS block in the .pem file. +scoped_refptr<ParsedCertificate> ParseCertificateFromFile( + const std::string& file_name) { + std::string data; + std::string expected_errors; + + // Read the certificate data and error expectations from a single PEM file. + const PemBlockMapping mappings[] = { + {"CERTIFICATE", &data}, {"ERRORS", &expected_errors, true /*optional*/}, + }; + std::string test_file_path = GetFilePath(file_name); + EXPECT_TRUE(ReadTestDataFromPemFile(test_file_path, mappings)); + + CertErrors errors; + scoped_refptr<ParsedCertificate> cert = + ParsedCertificate::Create(data, {}, &errors); + + EXPECT_EQ(expected_errors, errors.ToDebugString()) << "Test file: " + << test_file_path; + + // TODO(crbug.com/634443): Every parse failure being tested should emit error + // information. + // if (!cert) + // EXPECT_FALSE(errors.empty()); + + return cert; +} + +der::Input DavidBenOid() { + // This OID corresponds with + // 1.2.840.113554.4.1.72585.0 (https://davidben.net/oid) + static const uint8_t kOid[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, + 0x04, 0x01, 0x84, 0xb7, 0x09, 0x00}; + return der::Input(kOid); +} + +// Parses an Extension whose critical field is true (255). +TEST(ParsedCertificateTest, ExtensionCritical) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("extension_critical.pem"); + ASSERT_TRUE(cert); + + const uint8_t kExpectedValue[] = {0x30, 0x00}; + + auto it = cert->unparsed_extensions().find(DavidBenOid()); + ASSERT_NE(cert->unparsed_extensions().end(), it); + const auto& extension = it->second; + + EXPECT_TRUE(extension.critical); + EXPECT_EQ(DavidBenOid(), extension.oid); + EXPECT_EQ(der::Input(kExpectedValue), extension.value); +} + +// Parses an Extension whose critical field is false (omitted). +TEST(ParsedCertificateTest, ExtensionNotCritical) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("extension_not_critical.pem"); + ASSERT_TRUE(cert); + + const uint8_t kExpectedValue[] = {0x30, 0x00}; + + auto it = cert->unparsed_extensions().find(DavidBenOid()); + ASSERT_NE(cert->unparsed_extensions().end(), it); + const auto& extension = it->second; + + EXPECT_FALSE(extension.critical); + EXPECT_EQ(DavidBenOid(), extension.oid); + EXPECT_EQ(der::Input(kExpectedValue), extension.value); +} + +// Parses an Extension whose critical field is 0. This is in one sense FALSE, +// however because critical has DEFAULT of false this is in fact invalid +// DER-encoding. +TEST(ParsedCertificateTest, ExtensionCritical0) { + ASSERT_FALSE(ParseCertificateFromFile("extension_critical_0.pem")); +} + +// Parses an Extension whose critical field is 3. Under DER-encoding BOOLEAN +// values must an octet of either all zero bits, or all 1 bits, so this is not +// valid. +TEST(ParsedCertificateTest, ExtensionCritical3) { + ASSERT_FALSE(ParseCertificateFromFile("extension_critical_3.pem")); +} + +// Parses an Extensions that is an empty sequence. +TEST(ParsedCertificateTest, ExtensionsEmptySequence) { + ASSERT_FALSE(ParseCertificateFromFile("extensions_empty_sequence.pem")); +} + +// Parses an Extensions that is not a sequence. +TEST(ParsedCertificateTest, ExtensionsNotSequence) { + ASSERT_FALSE(ParseCertificateFromFile("extensions_not_sequence.pem")); +} + +// Parses an Extensions that has data after the sequence. +TEST(ParsedCertificateTest, ExtensionsDataAfterSequence) { + ASSERT_FALSE(ParseCertificateFromFile("extensions_data_after_sequence.pem")); +} + +// Parses an Extensions that contains duplicated key usages. +TEST(ParsedCertificateTest, ExtensionsDuplicateKeyUsage) { + ASSERT_FALSE(ParseCertificateFromFile("extensions_duplicate_key_usage.pem")); +} + +// Parses an Extensions that contains an extended key usages. +TEST(ParsedCertificateTest, ExtendedKeyUsage) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("extended_key_usage.pem"); + ASSERT_TRUE(cert); + + const auto& extensions = cert->unparsed_extensions(); + ASSERT_EQ(3u, extensions.size()); + + auto iter = extensions.find(ExtKeyUsageOid()); + ASSERT_TRUE(iter != extensions.end()); + EXPECT_FALSE(iter->second.critical); + EXPECT_EQ(45u, iter->second.value.Length()); +} + +// Parses an Extensions that contains a key usage. +TEST(ParsedCertificateTest, KeyUsage) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("key_usage.pem"); + ASSERT_TRUE(cert); + + ASSERT_TRUE(cert->has_key_usage()); + + EXPECT_EQ(5u, cert->key_usage().unused_bits()); + const uint8_t kExpectedBytes[] = {0xA0}; + EXPECT_EQ(der::Input(kExpectedBytes), cert->key_usage().bytes()); + + EXPECT_TRUE(cert->key_usage().AssertsBit(0)); + EXPECT_FALSE(cert->key_usage().AssertsBit(1)); + EXPECT_TRUE(cert->key_usage().AssertsBit(2)); +} + +// Parses an Extensions that contains a policies extension. +TEST(ParsedCertificateTest, Policies) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("policies.pem"); + ASSERT_TRUE(cert); + + const auto& extensions = cert->unparsed_extensions(); + ASSERT_EQ(3u, extensions.size()); + + auto iter = extensions.find(CertificatePoliciesOid()); + ASSERT_TRUE(iter != extensions.end()); + EXPECT_FALSE(iter->second.critical); + EXPECT_EQ(95u, iter->second.value.Length()); +} + +// Parses an Extensions that contains a subjectaltname extension. +TEST(ParsedCertificateTest, SubjectAltName) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("subject_alt_name.pem"); + ASSERT_TRUE(cert); + + ASSERT_TRUE(cert->has_subject_alt_names()); +} + +// Parses an Extensions that contains multiple extensions, sourced from a +// real-world certificate. +TEST(ParsedCertificateTest, ExtensionsReal) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("extensions_real.pem"); + ASSERT_TRUE(cert); + + const auto& extensions = cert->unparsed_extensions(); + ASSERT_EQ(4u, extensions.size()); + + EXPECT_TRUE(cert->has_key_usage()); + EXPECT_TRUE(cert->has_basic_constraints()); + + auto iter = extensions.find(CertificatePoliciesOid()); + ASSERT_TRUE(iter != extensions.end()); + EXPECT_FALSE(iter->second.critical); + EXPECT_EQ(16u, iter->second.value.Length()); + + // TODO(eroman): Verify the other 4 extensions' values. +} + +// Parses a BasicConstraints with no CA or pathlen. +TEST(ParsedCertificateTest, BasicConstraintsNotCa) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("basic_constraints_not_ca.pem"); + ASSERT_TRUE(cert); + + EXPECT_TRUE(cert->has_basic_constraints()); + EXPECT_FALSE(cert->basic_constraints().is_ca); + EXPECT_FALSE(cert->basic_constraints().has_path_len); +} + +// Parses a BasicConstraints with CA but no pathlen. +TEST(ParsedCertificateTest, BasicConstraintsCaNoPath) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("basic_constraints_ca_no_path.pem"); + ASSERT_TRUE(cert); + + EXPECT_TRUE(cert->has_basic_constraints()); + EXPECT_TRUE(cert->basic_constraints().is_ca); + EXPECT_FALSE(cert->basic_constraints().has_path_len); +} + +// Parses a BasicConstraints with CA and pathlen of 9. +TEST(ParsedCertificateTest, BasicConstraintsCaPath9) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("basic_constraints_ca_path_9.pem"); + ASSERT_TRUE(cert); + + EXPECT_TRUE(cert->has_basic_constraints()); + EXPECT_TRUE(cert->basic_constraints().is_ca); + EXPECT_TRUE(cert->basic_constraints().has_path_len); + EXPECT_EQ(9u, cert->basic_constraints().path_len); +} + +// Parses a BasicConstraints with CA and pathlen of 255 (largest allowed size). +TEST(ParsedCertificateTest, BasicConstraintsPathlen255) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("basic_constraints_pathlen_255.pem"); + ASSERT_TRUE(cert); + + EXPECT_TRUE(cert->has_basic_constraints()); + EXPECT_TRUE(cert->basic_constraints().is_ca); + EXPECT_TRUE(cert->basic_constraints().has_path_len); + EXPECT_EQ(255, cert->basic_constraints().path_len); +} + +// Parses a BasicConstraints with CA and pathlen of 256 (too large). +TEST(ParsedCertificateTest, BasicConstraintsPathlen256) { + ASSERT_FALSE(ParseCertificateFromFile("basic_constraints_pathlen_256.pem")); +} + +// Parses a BasicConstraints with CA and a negative pathlen. +TEST(ParsedCertificateTest, BasicConstraintsNegativePath) { + ASSERT_FALSE(ParseCertificateFromFile("basic_constraints_negative_path.pem")); +} + +// Parses a BasicConstraints with CA and pathlen that is very large (and +// couldn't fit in a 64-bit integer). +TEST(ParsedCertificateTest, BasicConstraintsPathTooLarge) { + ASSERT_FALSE( + ParseCertificateFromFile("basic_constraints_path_too_large.pem")); +} + +// Parses a BasicConstraints with CA explicitly set to false. This violates +// DER-encoding rules, however is commonly used, so it is accepted. +TEST(ParsedCertificateTest, BasicConstraintsCaFalse) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("basic_constraints_ca_false.pem"); + ASSERT_TRUE(cert); + + EXPECT_TRUE(cert->has_basic_constraints()); + EXPECT_FALSE(cert->basic_constraints().is_ca); + EXPECT_FALSE(cert->basic_constraints().has_path_len); +} + +// Parses a BasicConstraints with CA set to true and an unexpected NULL at +// the end. +TEST(ParsedCertificateTest, BasicConstraintsUnconsumedData) { + ASSERT_FALSE( + ParseCertificateFromFile("basic_constraints_unconsumed_data.pem")); +} + +// Parses a BasicConstraints with CA omitted (false), but with a pathlen of 1. +// This is valid DER for the ASN.1, however is not valid when interpreting the +// BasicConstraints at a higher level. +TEST(ParsedCertificateTest, BasicConstraintsPathLenButNotCa) { + scoped_refptr<ParsedCertificate> cert = + ParseCertificateFromFile("basic_constraints_pathlen_not_ca.pem"); + ASSERT_TRUE(cert); + + EXPECT_TRUE(cert->has_basic_constraints()); + EXPECT_FALSE(cert->basic_constraints().is_ca); + EXPECT_TRUE(cert->basic_constraints().has_path_len); + EXPECT_EQ(1u, cert->basic_constraints().path_len); +} + +} // namespace + +} // namespace net diff --git a/chromium/net/cert/internal/path_builder.cc b/chromium/net/cert/internal/path_builder.cc index 36cd9d45f8d..bb4283eeed6 100644 --- a/chromium/net/cert/internal/path_builder.cc +++ b/chromium/net/cert/internal/path_builder.cc @@ -7,7 +7,6 @@ #include <set> #include <unordered_set> -#include "base/callback_helpers.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "net/base/net_errors.h" @@ -71,24 +70,20 @@ class CertIssuersIter { CertIssuerSources* cert_issuer_sources, const TrustStore* trust_store); - // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC - // is returned and the cert is stored in |*cert|. If an issuer is not - // ready, ASYNC is returned and |callback| will be called once |*out_cert| has - // been set. If |callback| is null, always completes synchronously. - // - // In either case, if all issuers have been exhausted, |*out| is cleared. - CompletionStatus GetNextIssuer(CertificateOrTrustAnchor* out, - const base::Closure& callback); + // Gets the next candidate issuer, or clears |*out| when all issuers have been + // exhausted. + void GetNextIssuer(CertificateOrTrustAnchor* out); // Returns the |cert| for which issuers are being retrieved. const ParsedCertificate* cert() const { return cert_.get(); } scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } private: + void AddIssuers(ParsedCertificateList issuers); void DoAsyncIssuerQuery(); - void GotAsyncAnchors(TrustAnchors anchors); - void GotAsyncCerts(CertIssuerSource::Request* request); - void NotifyIfNecessary(); + + // Returns true if |issuers_| contains unconsumed certificates. + bool HasCurrentIssuer() const { return cur_issuer_ < issuers_.size(); } scoped_refptr<ParsedCertificate> cert_; CertIssuerSources* cert_issuer_sources_; @@ -119,19 +114,12 @@ class CertIssuersIter { // Tracks which requests have been made yet. bool did_initial_query_ = false; bool did_async_issuer_query_ = false; - // If asynchronous requests were made, how many of them are still outstanding? - size_t pending_async_results_; + // Index into pending_async_requests_ that is the next one to process. + size_t cur_async_request_ = 0; // Owns the Request objects for any asynchronous requests so that they will be // cancelled if CertIssuersIter is destroyed. std::vector<std::unique_ptr<CertIssuerSource::Request>> pending_async_requests_; - std::unique_ptr<TrustStore::Request> pending_anchor_request_; - - // When GetNextIssuer was called and returned asynchronously, |*out_| is - // where the result will be stored, and |callback_| will be run when the - // result is ready. - CertificateOrTrustAnchor* out_; - base::Closure callback_; DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); }; @@ -145,30 +133,15 @@ CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; } -CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, - const base::Closure& callback) { - // Should not be called again while already waiting for an async result. - DCHECK(callback_.is_null()); - +void CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out) { if (!did_initial_query_) { did_initial_query_ = true; - trust_store_->FindTrustAnchorsForCert( - cert_, - callback.is_null() ? TrustStore::TrustAnchorsCallback() - : base::Bind(&CertIssuersIter::GotAsyncAnchors, - base::Unretained(this)), - &anchors_, &pending_anchor_request_); + trust_store_->FindTrustAnchorsForCert(cert_, &anchors_); for (auto* cert_issuer_source : *cert_issuer_sources_) { ParsedCertificateList new_issuers; cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); - for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { - if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != - present_issuers_.end()) - continue; - present_issuers_.insert(issuer->der_cert().AsStringPiece()); - issuers_.push_back(std::move(issuer)); - } + AddIssuers(std::move(new_issuers)); } DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size() << " sync issuers"; @@ -186,18 +159,33 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, << anchors_.size(); // Still have anchors that haven't been returned yet, return one of them. *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]); - return CompletionStatus::SYNC; + return; } - if (pending_anchor_request_) { - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << ") Still waiting for async trust anchor results."; - out_ = out; - callback_ = callback; - return CompletionStatus::ASYNC; + // If there aren't any issuers left, block until async results are ready. + if (!HasCurrentIssuer()) { + if (!did_async_issuer_query_) { + // Now issue request(s) for async ones (AIA, etc). + DoAsyncIssuerQuery(); + } + + // TODO(eroman): Rather than blocking on the async requests in FIFO order, + // consume in the order they become ready. + while (!HasCurrentIssuer() && + cur_async_request_ < pending_async_requests_.size()) { + ParsedCertificateList new_issuers; + pending_async_requests_[cur_async_request_]->GetNext(&new_issuers); + if (new_issuers.empty()) { + // Request is exhausted, no more results pending from that + // CertIssuerSource. + pending_async_requests_[cur_async_request_++].reset(); + } else { + AddIssuers(std::move(new_issuers)); + } + } } - if (cur_issuer_ < issuers_.size()) { + if (HasCurrentIssuer()) { DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << "): returning issuer " << cur_issuer_ << " of " << issuers_.size(); @@ -205,148 +193,40 @@ CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, // A reference to the returned issuer is retained, since |present_issuers_| // points to data owned by it. *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); - return CompletionStatus::SYNC; - } - - if (did_async_issuer_query_) { - if (pending_async_results_ == 0) { - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << ") Reached the end of all available issuers."; - // Reached the end of all available issuers. - *out = CertificateOrTrustAnchor(); - return CompletionStatus::SYNC; - } - - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << ") Still waiting for async results from other " - "CertIssuerSources."; - // Still waiting for async results from other CertIssuerSources. - out_ = out; - callback_ = callback; - return CompletionStatus::ASYNC; + return; } - // Reached the end of synchronously gathered issuers. - if (callback.is_null()) { - // Synchronous-only mode, don't try to query async sources. - *out = CertificateOrTrustAnchor(); - return CompletionStatus::SYNC; - } - - // Now issue request(s) for async ones (AIA, etc). - DoAsyncIssuerQuery(); + DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) + << ") Reached the end of all available issuers."; + // Reached the end of all available issuers. + *out = CertificateOrTrustAnchor(); +} - if (pending_async_results_ == 0) { - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << ") No cert sources have async results."; - // No cert sources have async results. - *out = CertificateOrTrustAnchor(); - return CompletionStatus::SYNC; +void CertIssuersIter::AddIssuers(ParsedCertificateList new_issuers) { + for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { + if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != + present_issuers_.end()) + continue; + present_issuers_.insert(issuer->der_cert().AsStringPiece()); + issuers_.push_back(std::move(issuer)); } - - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ - << ")"; - out_ = out; - callback_ = callback; - return CompletionStatus::ASYNC; } void CertIssuersIter::DoAsyncIssuerQuery() { DCHECK(!did_async_issuer_query_); did_async_issuer_query_ = true; - pending_async_results_ = 0; + cur_async_request_ = 0; for (auto* cert_issuer_source : *cert_issuer_sources_) { std::unique_ptr<CertIssuerSource::Request> request; - cert_issuer_source->AsyncGetIssuersOf( - cert(), - base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), - &request); + cert_issuer_source->AsyncGetIssuersOf(cert(), &request); if (request) { DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) << ") pending..."; - pending_async_results_++; pending_async_requests_.push_back(std::move(request)); } } } -void CertIssuersIter::GotAsyncAnchors(TrustAnchors anchors) { - DVLOG(1) << "CertIssuersIter::GotAsyncAnchors(" << CertDebugString(cert()) - << "): " << anchors.size() << " anchors"; - for (scoped_refptr<TrustAnchor>& anchor : anchors) - anchors_.push_back(std::move(anchor)); - pending_anchor_request_.reset(); - - NotifyIfNecessary(); -} - -void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { - DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) - << ")"; - while (true) { - scoped_refptr<ParsedCertificate> cert; - CompletionStatus status = request->GetNext(&cert); - if (!cert) { - if (status == CompletionStatus::SYNC) { - // Request is exhausted, no more results pending from that - // CertIssuerSource. - DCHECK_GT(pending_async_results_, 0U); - pending_async_results_--; - } - break; - } - DCHECK_EQ(status, CompletionStatus::SYNC); - if (present_issuers_.find(cert->der_cert().AsStringPiece()) != - present_issuers_.end()) - continue; - present_issuers_.insert(cert->der_cert().AsStringPiece()); - issuers_.push_back(std::move(cert)); - } - - // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may - // be more than the ones just inserted, depending on |cur_| value). - - NotifyIfNecessary(); -} - -void CertIssuersIter::NotifyIfNecessary() { - // Notify that more results are available, if necessary. - if (!callback_.is_null()) { - if (cur_anchor_ < anchors_.size()) { - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << "): async returning anchor " << cur_anchor_ << " of " - << anchors_.size(); - *out_ = CertificateOrTrustAnchor(std::move(anchors_[cur_anchor_++])); - base::ResetAndReturn(&callback_).Run(); - return; - } - if (cur_issuer_ < issuers_.size()) { - DCHECK(!pending_anchor_request_); - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << "): async returning issuer " << cur_issuer_ << " of " - << issuers_.size(); - *out_ = CertificateOrTrustAnchor(std::move(issuers_[cur_issuer_++])); - base::ResetAndReturn(&callback_).Run(); - return; - } - - if (!did_async_issuer_query_) - DoAsyncIssuerQuery(); - - if (pending_async_results_ == 0) { - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << "): async returning empty result"; - *out_ = CertificateOrTrustAnchor(); - base::ResetAndReturn(&callback_).Run(); - return; - } - DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) - << "): empty result, but other async results " - "pending, waiting.."; - } -} - // CertIssuerIterPath tracks which certs are present in the path and prevents // paths from being built which repeat any certs (including different versions // of the same cert, based on Subject+SubjectAltName+SPKI). @@ -446,11 +326,9 @@ class CertPathIter { // CertPathIter. void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); - // Gets the next candidate path. If a path is ready synchronously, SYNC is - // returned and the path is stored in |*path|. If a path is not ready, - // ASYNC is returned and |callback| will be called once |*path| has been set. - // In either case, if all paths have been exhausted, |*path| is cleared. - CompletionStatus GetNextPath(CertPath* path, const base::Closure& callback); + // Gets the next candidate path, or clears |*path| when all paths have been + // exhausted. + void GetNextPath(CertPath* path); private: enum State { @@ -461,13 +339,9 @@ class CertPathIter { STATE_BACKTRACK, }; - CompletionStatus DoLoop(bool allow_async); - - CompletionStatus DoGetNextIssuer(bool allow_async); - CompletionStatus DoGetNextIssuerComplete(); - CompletionStatus DoBackTrack(); - - void HandleGotNextIssuer(void); + void DoGetNextIssuer(); + void DoGetNextIssuerComplete(); + void DoBackTrack(); // Stores the next candidate issuer, until it is used during the // STATE_GET_NEXT_ISSUER_COMPLETE step. @@ -483,8 +357,6 @@ class CertPathIter { // The output variable for storing the next candidate path, which the client // passes in to GetNextPath. Only used for a single path output. CertPath* out_path_; - // The callback to be called if an async lookup generated a candidate path. - base::Closure callback_; // Current state of the state machine. State next_state_; @@ -501,22 +373,10 @@ void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { cert_issuer_sources_.push_back(cert_issuer_source); } -CompletionStatus CertPathIter::GetNextPath(CertPath* path, - const base::Closure& callback) { +// TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). +void CertPathIter::GetNextPath(CertPath* path) { out_path_ = path; out_path_->Clear(); - CompletionStatus rv = DoLoop(!callback.is_null()); - if (rv == CompletionStatus::ASYNC) { - callback_ = callback; - } else { - // Clear the reference to the output parameter as a precaution. - out_path_ = nullptr; - } - return rv; -} - -CompletionStatus CertPathIter::DoLoop(bool allow_async) { - CompletionStatus result = CompletionStatus::SYNC; do { State state = next_state_; next_state_ = STATE_NONE; @@ -525,39 +385,32 @@ CompletionStatus CertPathIter::DoLoop(bool allow_async) { NOTREACHED(); break; case STATE_GET_NEXT_ISSUER: - result = DoGetNextIssuer(allow_async); + DoGetNextIssuer(); break; case STATE_GET_NEXT_ISSUER_COMPLETE: - result = DoGetNextIssuerComplete(); + DoGetNextIssuerComplete(); break; case STATE_RETURN_A_PATH: // If the returned path did not verify, keep looking for other paths // (the trust root is not part of cur_path_, so don't need to // backtrack). next_state_ = STATE_GET_NEXT_ISSUER; - result = CompletionStatus::SYNC; break; case STATE_BACKTRACK: - result = DoBackTrack(); + DoBackTrack(); break; } - } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && - next_state_ != STATE_RETURN_A_PATH); + } while (next_state_ != STATE_NONE && next_state_ != STATE_RETURN_A_PATH); - return result; + out_path_ = nullptr; } -CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { +void CertPathIter::DoGetNextIssuer() { next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; - CompletionStatus rv = cur_path_.back()->GetNextIssuer( - &next_issuer_, allow_async - ? base::Bind(&CertPathIter::HandleGotNextIssuer, - base::Unretained(this)) - : base::Closure()); - return rv; + cur_path_.back()->GetNextIssuer(&next_issuer_); } -CompletionStatus CertPathIter::DoGetNextIssuerComplete() { +void CertPathIter::DoGetNextIssuerComplete() { // If the issuer is a trust anchor signal readiness. if (next_issuer_.IsTrustAnchor()) { DVLOG(1) << "CertPathIter got anchor(" @@ -566,14 +419,14 @@ CompletionStatus CertPathIter::DoGetNextIssuerComplete() { cur_path_.CopyPath(&out_path_->certs); out_path_->trust_anchor = std::move(next_issuer_.anchor); next_issuer_ = CertificateOrTrustAnchor(); - return CompletionStatus::SYNC; + return; } if (next_issuer_.IsCertificate()) { // Skip this cert if it is already in the chain. if (cur_path_.IsPresent(next_issuer_.cert.get())) { next_state_ = STATE_GET_NEXT_ISSUER; - return CompletionStatus::SYNC; + return; } cur_path_.Append(base::MakeUnique<CertIssuersIter>( @@ -590,10 +443,9 @@ CompletionStatus CertPathIter::DoGetNextIssuerComplete() { // more for the previous cert. next_state_ = STATE_BACKTRACK; } - return CompletionStatus::SYNC; } -CompletionStatus CertPathIter::DoBackTrack() { +void CertPathIter::DoBackTrack() { DVLOG(1) << "CertPathIter backtracking..."; cur_path_.Pop(); if (cur_path_.Empty()) { @@ -603,17 +455,6 @@ CompletionStatus CertPathIter::DoBackTrack() { // Continue exploring issuers of the previous path. next_state_ = STATE_GET_NEXT_ISSUER; } - return CompletionStatus::SYNC; -} - -void CertPathIter::HandleGotNextIssuer(void) { - DCHECK(!callback_.is_null()); - CompletionStatus rv = DoLoop(true /* allow_async */); - if (rv == CompletionStatus::SYNC) { - // Clear the reference to the output parameter as a precaution. - out_path_ = nullptr; - base::ResetAndReturn(&callback_).Run(); - } } CertPathBuilder::ResultPath::ResultPath() = default; @@ -658,19 +499,10 @@ void CertPathBuilder::AddCertIssuerSource( cert_path_iter_->AddCertIssuerSource(cert_issuer_source); } -CompletionStatus CertPathBuilder::Run(const base::Closure& callback) { +// TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). +void CertPathBuilder::Run() { DCHECK_EQ(STATE_NONE, next_state_); next_state_ = STATE_GET_NEXT_PATH; - CompletionStatus rv = DoLoop(!callback.is_null()); - - if (rv == CompletionStatus::ASYNC) - callback_ = callback; - - return rv; -} - -CompletionStatus CertPathBuilder::DoLoop(bool allow_async) { - CompletionStatus result = CompletionStatus::SYNC; do { State state = next_state_; @@ -680,38 +512,25 @@ CompletionStatus CertPathBuilder::DoLoop(bool allow_async) { NOTREACHED(); break; case STATE_GET_NEXT_PATH: - result = DoGetNextPath(allow_async); + DoGetNextPath(); break; case STATE_GET_NEXT_PATH_COMPLETE: - result = DoGetNextPathComplete(); + DoGetNextPathComplete(); break; } - } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE); - - return result; + } while (next_state_ != STATE_NONE); } -CompletionStatus CertPathBuilder::DoGetNextPath(bool allow_async) { +void CertPathBuilder::DoGetNextPath() { next_state_ = STATE_GET_NEXT_PATH_COMPLETE; - CompletionStatus rv = cert_path_iter_->GetNextPath( - &next_path_, allow_async ? base::Bind(&CertPathBuilder::HandleGotNextPath, - base::Unretained(this)) - : base::Closure()); - return rv; -} - -void CertPathBuilder::HandleGotNextPath() { - DCHECK(!callback_.is_null()); - CompletionStatus rv = DoLoop(true /* allow_async */); - if (rv == CompletionStatus::SYNC) - base::ResetAndReturn(&callback_).Run(); + cert_path_iter_->GetNextPath(&next_path_); } -CompletionStatus CertPathBuilder::DoGetNextPathComplete() { +void CertPathBuilder::DoGetNextPathComplete() { if (next_path_.IsEmpty()) { // No more paths to check, signal completion. next_state_ = STATE_NONE; - return CompletionStatus::SYNC; + return; } // Verify the entire certificate chain. @@ -729,14 +548,13 @@ CompletionStatus CertPathBuilder::DoGetNextPathComplete() { // Found a valid path, return immediately. // TODO(mattm): add debug/test mode that tries all possible paths. next_state_ = STATE_NONE; - return CompletionStatus::SYNC; + return; } // Path did not verify. Try more paths. If there are no more paths, the result // will be returned next time DoGetNextPathComplete is called with next_path_ // empty. next_state_ = STATE_GET_NEXT_PATH; - return CompletionStatus::SYNC; } void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) { diff --git a/chromium/net/cert/internal/path_builder.h b/chromium/net/cert/internal/path_builder.h index 69784f333b0..ee39ed67ee5 100644 --- a/chromium/net/cert/internal/path_builder.h +++ b/chromium/net/cert/internal/path_builder.h @@ -9,11 +9,8 @@ #include <string> #include <vector> -#include "base/callback.h" -#include "net/base/completion_callback.h" #include "net/base/net_export.h" #include "net/cert/internal/cert_errors.h" -#include "net/cert/internal/completion_status.h" #include "net/cert/internal/parsed_certificate.h" #include "net/cert/internal/trust_store.h" #include "net/der/input.h" @@ -107,6 +104,9 @@ class NET_EXPORT CertPathBuilder { // TODO(mattm): allow caller specified hook/callback to extend path // verification. // + // TODO(eroman): The assumption is that |result| is default initialized. Can + // probably just internalize |result| into CertPathBuilder. + // // Creates a CertPathBuilder that attempts to find a path from |cert| to a // trust anchor in |trust_store|, which satisfies |signature_policy| and is // valid at |time|. Details of attempted path(s) are stored in |*result|. @@ -129,24 +129,12 @@ class NET_EXPORT CertPathBuilder { // it is a trust anchor or is directly signed by a trust anchor.) void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); - // Begins verification of the target certificate. - // - // If the return value is SYNC then the verification is complete and the - // |result| value can be inspected for the status, and |callback| will not be - // called. - // If the return value is ASYNC, the |callback| will be called asynchronously - // once the verification is complete. |result| should not be examined or - // modified until the |callback| is run. - // - // If |callback| is null, verification always completes synchronously, even if - // it fails to find a valid path and one could have been found asynchronously. + // Executes verification of the target certificate. // - // The CertPathBuilder may be deleted while an ASYNC verification is pending, - // in which case the verification is cancelled, |callback| will not be called, - // and the output Result will be in an undefined state. - // It is safe to delete the CertPathBuilder during the |callback|. - // Run must not be called more than once on each CertPathBuilder instance. - CompletionStatus Run(const base::Closure& callback); + // Upon return results are written to the |result| object passed into the + // constructor. Run must not be called more than once on each CertPathBuilder + // instance. + void Run(); private: enum State { @@ -155,16 +143,11 @@ class NET_EXPORT CertPathBuilder { STATE_GET_NEXT_PATH_COMPLETE, }; - CompletionStatus DoLoop(bool allow_async); - - CompletionStatus DoGetNextPath(bool allow_async); - void HandleGotNextPath(); - CompletionStatus DoGetNextPathComplete(); + void DoGetNextPath(); + void DoGetNextPathComplete(); void AddResultPath(std::unique_ptr<ResultPath> result_path); - base::Closure callback_; - std::unique_ptr<CertPathIter> cert_path_iter_; const SignaturePolicy* signature_policy_; const der::GeneralizedTime time_; diff --git a/chromium/net/cert/internal/path_builder_pkits_unittest.cc b/chromium/net/cert/internal/path_builder_pkits_unittest.cc index 4039428687e..b362519319d 100644 --- a/chromium/net/cert/internal/path_builder_pkits_unittest.cc +++ b/chromium/net/cert/internal/path_builder_pkits_unittest.cc @@ -90,8 +90,7 @@ class PathBuilderPkitsTestDelegate { &signature_policy, time, &result); path_builder.AddCertIssuerSource(&cert_issuer_source); - CompletionStatus rv = path_builder.Run(base::Closure()); - EXPECT_EQ(CompletionStatus::SYNC, rv); + path_builder.Run(); return result.HasValidPath(); } diff --git a/chromium/net/cert/internal/path_builder_unittest.cc b/chromium/net/cert/internal/path_builder_unittest.cc index 5f0a2eb6234..35fe1542905 100644 --- a/chromium/net/cert/internal/path_builder_unittest.cc +++ b/chromium/net/cert/internal/path_builder_unittest.cc @@ -5,18 +5,14 @@ #include "net/cert/internal/path_builder.h" #include "base/base_paths.h" -#include "base/cancelable_callback.h" #include "base/files/file_util.h" -#include "base/location.h" #include "base/path_service.h" -#include "base/threading/thread_task_runner_handle.h" -#include "net/base/test_completion_callback.h" #include "net/cert/internal/cert_issuer_source_static.h" #include "net/cert/internal/parsed_certificate.h" #include "net/cert/internal/signature_policy.h" #include "net/cert/internal/test_helpers.h" +#include "net/cert/internal/trust_store_collection.h" #include "net/cert/internal/trust_store_in_memory.h" -#include "net/cert/internal/trust_store_test_helpers.h" #include "net/cert/internal/verify_certificate_chain.h" #include "net/cert/pem_tokenizer.h" #include "net/der/input.h" @@ -44,32 +40,17 @@ class AsyncCertIssuerSourceStatic : public CertIssuerSource { public: class StaticAsyncRequest : public Request { public: - StaticAsyncRequest(const IssuerCallback& issuers_callback, - ParsedCertificateList&& issuers) - : cancelable_closure_(base::Bind(&StaticAsyncRequest::RunCallback, - base::Unretained(this))), - issuers_callback_(issuers_callback) { + StaticAsyncRequest(ParsedCertificateList&& issuers) { issuers_.swap(issuers); issuers_iter_ = issuers_.begin(); } ~StaticAsyncRequest() override {} - CompletionStatus GetNext( - scoped_refptr<ParsedCertificate>* out_cert) override { - if (issuers_iter_ == issuers_.end()) - *out_cert = nullptr; - else - *out_cert = std::move(*issuers_iter_++); - return CompletionStatus::SYNC; + void GetNext(ParsedCertificateList* out_certs) override { + if (issuers_iter_ != issuers_.end()) + out_certs->push_back(std::move(*issuers_iter_++)); } - base::Closure callback() { return cancelable_closure_.callback(); } - - private: - void RunCallback() { issuers_callback_.Run(this); } - - base::CancelableClosure cancelable_closure_; - IssuerCallback issuers_callback_; ParsedCertificateList issuers_; ParsedCertificateList::iterator issuers_iter_; @@ -85,14 +66,12 @@ class AsyncCertIssuerSourceStatic : public CertIssuerSource { void SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) override {} void AsyncGetIssuersOf(const ParsedCertificate* cert, - const IssuerCallback& issuers_callback, std::unique_ptr<Request>* out_req) override { num_async_gets_++; ParsedCertificateList issuers; static_cert_issuer_source_.SyncGetIssuersOf(cert, &issuers); std::unique_ptr<StaticAsyncRequest> req( - new StaticAsyncRequest(issuers_callback, std::move(issuers))); - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, req->callback()); + new StaticAsyncRequest(std::move(issuers))); *out_req = std::move(req); } int num_async_gets() const { return num_async_gets_; } @@ -131,21 +110,6 @@ class AsyncCertIssuerSourceStatic : public CertIssuerSource { return ::testing::AssertionSuccess(); } -// Run the path builder, and wait for async completion if necessary. The return -// value signifies whether the path builder completed synchronously or -// asynchronously, not that RunPathBuilder itself is asynchronous. -CompletionStatus RunPathBuilder(CertPathBuilder* path_builder) { - TestClosure callback; - CompletionStatus rv = path_builder->Run(callback.closure()); - - if (rv == CompletionStatus::ASYNC) { - DVLOG(1) << "waiting for async completion..."; - callback.WaitForResult(); - DVLOG(1) << "async completed."; - } - return rv; -} - class PathBuilderMultiRootTest : public ::testing::Test { public: PathBuilderMultiRootTest() : signature_policy_(1024) {} @@ -194,7 +158,7 @@ TEST_F(PathBuilderMultiRootTest, TargetHasNameAndSpkiOfTrustAnchor) { CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, &result); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); ASSERT_TRUE(result.HasValidPath()); const auto& path = result.GetBestValidPath()->path; @@ -214,7 +178,7 @@ TEST_F(PathBuilderMultiRootTest, TargetWithSameNameAsTrustAnchorFails) { CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, &result); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_FALSE(result.HasValidPath()); } @@ -245,7 +209,7 @@ TEST_F(PathBuilderMultiRootTest, SelfSignedTrustAnchorSupplementalCert) { expired_time, &result); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_FALSE(result.HasValidPath()); ASSERT_EQ(2U, result.paths.size()); @@ -277,7 +241,7 @@ TEST_F(PathBuilderMultiRootTest, TargetIsSelfSignedTrustAnchor) { CertPathBuilder path_builder(e_by_e_, &trust_store, &signature_policy_, time_, &result); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); ASSERT_TRUE(result.HasValidPath()); const auto& path = result.GetBestValidPath()->path; @@ -296,7 +260,7 @@ TEST_F(PathBuilderMultiRootTest, TargetDirectlySignedByTrustAnchor) { CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, &result); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); ASSERT_TRUE(result.HasValidPath()); const auto& path = result.GetBestValidPath()->path; @@ -325,35 +289,12 @@ TEST_F(PathBuilderMultiRootTest, TriesSyncFirst) { path_builder.AddCertIssuerSource(&async_certs); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_TRUE(result.HasValidPath()); EXPECT_EQ(0, async_certs.num_async_gets()); } -// Test that async cert queries are not made if no callback is provided. -TEST_F(PathBuilderMultiRootTest, SychronousOnlyMode) { - TrustStoreInMemory trust_store; - AddTrustedCertificate(e_by_e_, &trust_store); - - CertIssuerSourceStatic sync_certs; - sync_certs.AddCert(f_by_e_); - - AsyncCertIssuerSourceStatic async_certs; - async_certs.AddCert(b_by_f_); - - CertPathBuilder::Result result; - CertPathBuilder path_builder(a_by_b_, &trust_store, &signature_policy_, time_, - &result); - path_builder.AddCertIssuerSource(&async_certs); - path_builder.AddCertIssuerSource(&sync_certs); - - EXPECT_EQ(CompletionStatus::SYNC, path_builder.Run(base::Closure())); - - EXPECT_FALSE(result.HasValidPath()); - EXPECT_EQ(0, async_certs.num_async_gets()); -} - // If async queries are needed, all async sources will be queried // simultaneously. TEST_F(PathBuilderMultiRootTest, TestAsyncSimultaneous) { @@ -377,7 +318,7 @@ TEST_F(PathBuilderMultiRootTest, TestAsyncSimultaneous) { path_builder.AddCertIssuerSource(&async_certs2); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_TRUE(result.HasValidPath()); EXPECT_EQ(1, async_certs1.num_async_gets()); @@ -402,7 +343,7 @@ TEST_F(PathBuilderMultiRootTest, TestLongChain) { &result); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); ASSERT_TRUE(result.HasValidPath()); @@ -436,7 +377,7 @@ TEST_F(PathBuilderMultiRootTest, TestBacktracking) { path_builder.AddCertIssuerSource(&sync_certs); path_builder.AddCertIssuerSource(&async_certs); - EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); ASSERT_TRUE(result.HasValidPath()); @@ -474,7 +415,7 @@ TEST_F(PathBuilderMultiRootTest, TestCertIssuerOrdering) { time_, &result); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); ASSERT_TRUE(result.HasValidPath()); @@ -558,7 +499,7 @@ TEST_F(PathBuilderKeyRolloverTest, TestRolloverOnlyOldRootTrusted) { &result); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_TRUE(result.HasValidPath()); @@ -606,7 +547,7 @@ TEST_F(PathBuilderKeyRolloverTest, TestRolloverBothRootsTrusted) { &result); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_TRUE(result.HasValidPath()); @@ -630,141 +571,39 @@ TEST_F(PathBuilderKeyRolloverTest, TestRolloverBothRootsTrusted) { } } -// If trust anchors are provided both synchronously and asynchronously for the -// same cert, the synchronously provided ones should be tried first, and -// pathbuilder should finish synchronously. -TEST_F(PathBuilderKeyRolloverTest, TestSyncAnchorsPreferred) { - TrustStoreInMemoryAsync trust_store; - // Both oldintermediate and newintermediate are trusted, but oldintermediate - // is returned synchronously and newintermediate asynchronously. - trust_store.AddSyncTrustAnchor( - TrustAnchor::CreateFromCertificateNoConstraints(oldintermediate_)); - trust_store.AddAsyncTrustAnchor( - TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_)); - - CertPathBuilder::Result result; - CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, - &result); - - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); - - EXPECT_TRUE(result.HasValidPath()); - - ASSERT_EQ(1U, result.paths.size()); - const auto& path = result.paths[0]->path; - EXPECT_TRUE(result.paths[0]->valid); - ASSERT_EQ(1U, path.certs.size()); - EXPECT_EQ(target_, path.certs[0]); - EXPECT_EQ(oldintermediate_, path.trust_anchor->cert()); -} - -// Async trust anchor checks should be done before synchronous issuer checks are -// considered. (Avoiding creating unnecessarily long paths.) -// -// Two valid paths could be built: -// newintermediate <- newrootrollover <- oldroot -// newintermediate <- newroot -// One invalid path could be built: -// newintermediate <- oldroot -// -// First: newintermediate <- oldroot will be tried, since oldroot is -// available synchronously, but this path will not verify. -// Second: newintermediate <- newroot should be built, even though -// newrootrollover issuer is available synchronously and newroot is async. This -// path should verify and pathbuilder will stop. -TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsBeforeSyncIssuers) { - TrustStoreInMemoryAsync trust_store; - trust_store.AddSyncTrustAnchor(oldroot_); - trust_store.AddAsyncTrustAnchor( - TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); - - CertIssuerSourceStatic sync_certs; - sync_certs.AddCert(newrootrollover_); - - CertPathBuilder::Result result; - CertPathBuilder path_builder(newintermediate_, &trust_store, - &signature_policy_, time_, &result); - path_builder.AddCertIssuerSource(&sync_certs); - - EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); - - EXPECT_TRUE(result.HasValidPath()); - - ASSERT_EQ(2U, result.paths.size()); - { - const auto& path = result.paths[0]->path; - EXPECT_FALSE(result.paths[0]->valid); - ASSERT_EQ(1U, path.certs.size()); - EXPECT_EQ(newintermediate_, path.certs[0]); - EXPECT_EQ(oldroot_, path.trust_anchor); - } - { - const auto& path = result.paths[1]->path; - EXPECT_TRUE(result.paths[1]->valid); - ASSERT_EQ(1U, path.certs.size()); - EXPECT_EQ(newintermediate_, path.certs[0]); - EXPECT_EQ(newroot_, path.trust_anchor->cert()); - } -} - -// If async trust anchor query returned no results, and there are no issuer +// If trust anchor query returned no results, and there are no issuer // sources, path building should fail at that point. -TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsNoMatchAndNoIssuerSources) { - TrustStoreInMemoryAsync trust_store; - trust_store.AddAsyncTrustAnchor( +TEST_F(PathBuilderKeyRolloverTest, TestAnchorsNoMatchAndNoIssuerSources) { + TrustStoreInMemory trust_store; + trust_store.AddTrustAnchor( TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); CertPathBuilder::Result result; CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, &result); - EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_FALSE(result.HasValidPath()); ASSERT_EQ(0U, result.paths.size()); } -// Both trust store and issuer source are async. Should successfully build a -// path. -TEST_F(PathBuilderKeyRolloverTest, TestAsyncAnchorsAndAsyncIssuers) { - TrustStoreInMemoryAsync trust_store; - trust_store.AddAsyncTrustAnchor( - TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); - - AsyncCertIssuerSourceStatic async_certs; - async_certs.AddCert(newintermediate_); - - CertPathBuilder::Result result; - CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, - &result); - path_builder.AddCertIssuerSource(&async_certs); - - EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); - - EXPECT_TRUE(result.HasValidPath()); - - ASSERT_EQ(1U, result.paths.size()); - const auto& path = result.paths[0]->path; - EXPECT_TRUE(result.paths[0]->valid); - ASSERT_EQ(2U, path.certs.size()); - EXPECT_EQ(target_, path.certs[0]); - EXPECT_EQ(newintermediate_, path.certs[1]); - EXPECT_EQ(newroot_, path.trust_anchor->cert()); -} - // Tests that multiple trust root matches on a single path will be considered. // Both roots have the same subject but different keys. Only one of them will // verify. TEST_F(PathBuilderKeyRolloverTest, TestMultipleRootMatchesOnlyOneWorks) { - TrustStoreInMemoryAsync trust_store; - // Since FindTrustAnchorsByNormalizedName returns newroot synchronously, it - // should be tried first. - trust_store.AddSyncTrustAnchor( + TrustStoreCollection trust_store_collection; + TrustStoreInMemory trust_store1; + TrustStoreInMemory trust_store2; + trust_store_collection.AddTrustStore(&trust_store1); + trust_store_collection.AddTrustStore(&trust_store2); + // Add two trust anchors (newroot_ and oldroot_). Path building will attempt + // them in this same order, as trust_store1 was added to + // trust_store_collection first. + trust_store1.AddTrustAnchor( TrustAnchor::CreateFromCertificateNoConstraints(newroot_)); - // oldroot is returned asynchronously, so it should only be tried after the - // path built with newroot fails. - trust_store.AddAsyncTrustAnchor(oldroot_); + trust_store2.AddTrustAnchor(oldroot_); // Only oldintermediate is supplied, so the path with newroot should fail, // oldroot should succeed. @@ -772,11 +611,11 @@ TEST_F(PathBuilderKeyRolloverTest, TestMultipleRootMatchesOnlyOneWorks) { sync_certs.AddCert(oldintermediate_); CertPathBuilder::Result result; - CertPathBuilder path_builder(target_, &trust_store, &signature_policy_, time_, - &result); + CertPathBuilder path_builder(target_, &trust_store_collection, + &signature_policy_, time_, &result); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_TRUE(result.HasValidPath()); ASSERT_EQ(2U, result.paths.size()); @@ -827,7 +666,7 @@ TEST_F(PathBuilderKeyRolloverTest, TestRolloverLongChain) { path_builder.AddCertIssuerSource(&sync_certs); path_builder.AddCertIssuerSource(&async_certs); - EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_TRUE(result.HasValidPath()); ASSERT_EQ(3U, result.paths.size()); @@ -882,7 +721,7 @@ TEST_F(PathBuilderKeyRolloverTest, TestEndEntityIsTrustRoot) { CertPathBuilder path_builder(newintermediate_, &trust_store, &signature_policy_, time_, &result); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_FALSE(result.HasValidPath()); } @@ -907,7 +746,7 @@ TEST_F(PathBuilderKeyRolloverTest, time_, &result); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); // This could actually be OK, but CertPathBuilder does not build the // newroot <- newrootrollover <- oldroot path. @@ -927,7 +766,7 @@ TEST_F(PathBuilderKeyRolloverTest, CertPathBuilder path_builder(newroot_, &trust_store, &signature_policy_, time_, &result); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); ASSERT_TRUE(result.HasValidPath()); @@ -975,7 +814,7 @@ TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediates) { path_builder.AddCertIssuerSource(&sync_certs2); path_builder.AddCertIssuerSource(&async_certs); - EXPECT_EQ(CompletionStatus::ASYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_TRUE(result.HasValidPath()); ASSERT_EQ(2U, result.paths.size()); @@ -1024,7 +863,7 @@ TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediateAndRoot) { &result); path_builder.AddCertIssuerSource(&sync_certs); - EXPECT_EQ(CompletionStatus::SYNC, RunPathBuilder(&path_builder)); + path_builder.Run(); EXPECT_FALSE(result.HasValidPath()); ASSERT_EQ(2U, result.paths.size()); @@ -1044,17 +883,15 @@ TEST_F(PathBuilderKeyRolloverTest, TestDuplicateIntermediateAndRoot) { class MockCertIssuerSourceRequest : public CertIssuerSource::Request { public: - MOCK_METHOD1(GetNext, CompletionStatus(scoped_refptr<ParsedCertificate>*)); + MOCK_METHOD1(GetNext, void(ParsedCertificateList*)); }; class MockCertIssuerSource : public CertIssuerSource { public: MOCK_METHOD2(SyncGetIssuersOf, void(const ParsedCertificate*, ParsedCertificateList*)); - MOCK_METHOD3(AsyncGetIssuersOf, - void(const ParsedCertificate*, - const IssuerCallback&, - std::unique_ptr<Request>*)); + MOCK_METHOD2(AsyncGetIssuersOf, + void(const ParsedCertificate*, std::unique_ptr<Request>*)); }; // Helper class to pass the Request to the PathBuilder when it calls @@ -1065,7 +902,6 @@ class CertIssuerSourceRequestMover { CertIssuerSourceRequestMover(std::unique_ptr<CertIssuerSource::Request> req) : request_(std::move(req)) {} void MoveIt(const ParsedCertificate* cert, - const CertIssuerSource::IssuerCallback& issuers_callback, std::unique_ptr<CertIssuerSource::Request>* out_req) { *out_req = std::move(request_); } @@ -1074,10 +910,23 @@ class CertIssuerSourceRequestMover { std::unique_ptr<CertIssuerSource::Request> request_; }; +// Functor that when called with a ParsedCertificateList* will append the +// specified certificate. +class AppendCertToList { + public: + explicit AppendCertToList(const scoped_refptr<ParsedCertificate>& cert) + : cert_(cert) {} + + void operator()(ParsedCertificateList* out) { out->push_back(cert_); } + + private: + scoped_refptr<ParsedCertificate> cert_; +}; + // Test that a single CertIssuerSource returning multiple async batches of // issuers is handled correctly. Due to the StrictMocks, it also tests that path // builder does not request issuers of certs that it shouldn't. -TEST_F(PathBuilderKeyRolloverTest, TestMultipleAsyncCallbacksFromSingleSource) { +TEST_F(PathBuilderKeyRolloverTest, TestMultipleAsyncIssuersFromSingleSource) { StrictMock<MockCertIssuerSource> cert_issuer_source; // Only newroot is a trusted root. @@ -1089,7 +938,6 @@ TEST_F(PathBuilderKeyRolloverTest, TestMultipleAsyncCallbacksFromSingleSource) { &result); path_builder.AddCertIssuerSource(&cert_issuer_source); - CertIssuerSource::IssuerCallback target_issuers_callback; // Create the mock CertIssuerSource::Request... std::unique_ptr<StrictMock<MockCertIssuerSourceRequest>> target_issuers_req_owner(new StrictMock<MockCertIssuerSourceRequest>()); @@ -1102,26 +950,15 @@ TEST_F(PathBuilderKeyRolloverTest, TestMultipleAsyncCallbacksFromSingleSource) { { ::testing::InSequence s; EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(target_.get(), _)); - EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _, _)) - .WillOnce( - DoAll(SaveArg<1>(&target_issuers_callback), - Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt))); + EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _)) + .WillOnce(Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt)); } - TestClosure callback; - CompletionStatus rv = path_builder.Run(callback.closure()); - ASSERT_EQ(CompletionStatus::ASYNC, rv); - - ASSERT_FALSE(target_issuers_callback.is_null()); - - ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); - - // First async batch: return oldintermediate_. EXPECT_CALL(*target_issuers_req, GetNext(_)) - .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_), - Return(CompletionStatus::SYNC))) - .WillOnce( - DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); + // First async batch: return oldintermediate_. + .WillOnce(Invoke(AppendCertToList(oldintermediate_))) + // Second async batch: return newintermediate_. + .WillOnce(Invoke(AppendCertToList(newintermediate_))); { ::testing::InSequence s; // oldintermediate_ does not create a valid path, so both sync and async @@ -1129,30 +966,21 @@ TEST_F(PathBuilderKeyRolloverTest, TestMultipleAsyncCallbacksFromSingleSource) { EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(oldintermediate_.get(), _)); EXPECT_CALL(cert_issuer_source, - AsyncGetIssuersOf(oldintermediate_.get(), _, _)); + AsyncGetIssuersOf(oldintermediate_.get(), _)); } - target_issuers_callback.Run(target_issuers_req); - ::testing::Mock::VerifyAndClearExpectations(target_issuers_req); - ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); - // Second async batch: return newintermediate_. - EXPECT_CALL(*target_issuers_req, GetNext(_)) - .WillOnce(DoAll(SetArgPointee<0>(newintermediate_), - Return(CompletionStatus::SYNC))) - .WillOnce( - DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); // newroot_ is in the trust store, so this path will be completed // synchronously. AsyncGetIssuersOf will not be called on newintermediate_. EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(newintermediate_.get(), _)); - target_issuers_callback.Run(target_issuers_req); + + // Ensure pathbuilder finished and filled result. + path_builder.Run(); + // Note that VerifyAndClearExpectations(target_issuers_req) is not called // here. PathBuilder could have destroyed it already, so just let the // expectations get checked by the destructor. ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); - // Ensure pathbuilder finished and filled result. - callback.WaitForResult(); - EXPECT_TRUE(result.HasValidPath()); ASSERT_EQ(2U, result.paths.size()); @@ -1189,7 +1017,6 @@ TEST_F(PathBuilderKeyRolloverTest, TestDuplicateAsyncIntermediates) { &result); path_builder.AddCertIssuerSource(&cert_issuer_source); - CertIssuerSource::IssuerCallback target_issuers_callback; // Create the mock CertIssuerSource::Request... std::unique_ptr<StrictMock<MockCertIssuerSourceRequest>> target_issuers_req_owner(new StrictMock<MockCertIssuerSourceRequest>()); @@ -1202,26 +1029,22 @@ TEST_F(PathBuilderKeyRolloverTest, TestDuplicateAsyncIntermediates) { { ::testing::InSequence s; EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(target_.get(), _)); - EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _, _)) - .WillOnce( - DoAll(SaveArg<1>(&target_issuers_callback), - Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt))); + EXPECT_CALL(cert_issuer_source, AsyncGetIssuersOf(target_.get(), _)) + .WillOnce(Invoke(&req_mover, &CertIssuerSourceRequestMover::MoveIt)); } - TestClosure callback; - CompletionStatus rv = path_builder.Run(callback.closure()); - ASSERT_EQ(CompletionStatus::ASYNC, rv); - - ASSERT_FALSE(target_issuers_callback.is_null()); - - ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); + scoped_refptr<ParsedCertificate> oldintermediate_dupe( + ParsedCertificate::Create(oldintermediate_->der_cert().AsStringPiece(), + {}, nullptr)); - // First async batch: return oldintermediate_. EXPECT_CALL(*target_issuers_req, GetNext(_)) - .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_), - Return(CompletionStatus::SYNC))) - .WillOnce( - DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); + // First async batch: return oldintermediate_. + .WillOnce(Invoke(AppendCertToList(oldintermediate_))) + // Second async batch: return a different copy of oldintermediate_ again. + .WillOnce(Invoke(AppendCertToList(oldintermediate_dupe))) + // Third async batch: return newintermediate_. + .WillOnce(Invoke(AppendCertToList(newintermediate_))); + { ::testing::InSequence s; // oldintermediate_ does not create a valid path, so both sync and async @@ -1229,44 +1052,17 @@ TEST_F(PathBuilderKeyRolloverTest, TestDuplicateAsyncIntermediates) { EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(oldintermediate_.get(), _)); EXPECT_CALL(cert_issuer_source, - AsyncGetIssuersOf(oldintermediate_.get(), _, _)); + AsyncGetIssuersOf(oldintermediate_.get(), _)); } - target_issuers_callback.Run(target_issuers_req); - ::testing::Mock::VerifyAndClearExpectations(target_issuers_req); - ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); - - // Second async batch: return a different copy of oldintermediate_ again. - scoped_refptr<ParsedCertificate> oldintermediate_dupe( - ParsedCertificate::Create(oldintermediate_->der_cert().AsStringPiece(), - {}, nullptr)); - EXPECT_CALL(*target_issuers_req, GetNext(_)) - .WillOnce(DoAll(SetArgPointee<0>(oldintermediate_dupe), - Return(CompletionStatus::SYNC))) - .WillOnce( - DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); - target_issuers_callback.Run(target_issuers_req); - // oldintermediate was already processed above, it should not generate any - // more requests. - ::testing::Mock::VerifyAndClearExpectations(target_issuers_req); - ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); - // Third async batch: return newintermediate_. - EXPECT_CALL(*target_issuers_req, GetNext(_)) - .WillOnce(DoAll(SetArgPointee<0>(newintermediate_), - Return(CompletionStatus::SYNC))) - .WillOnce( - DoAll(SetArgPointee<0>(nullptr), Return(CompletionStatus::ASYNC))); // newroot_ is in the trust store, so this path will be completed // synchronously. AsyncGetIssuersOf will not be called on newintermediate_. EXPECT_CALL(cert_issuer_source, SyncGetIssuersOf(newintermediate_.get(), _)); - target_issuers_callback.Run(target_issuers_req); - // Note that VerifyAndClearExpectations(target_issuers_req) is not called - // here. PathBuilder could have destroyed it already, so just let the - // expectations get checked by the destructor. - ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); // Ensure pathbuilder finished and filled result. - callback.WaitForResult(); + path_builder.Run(); + + ::testing::Mock::VerifyAndClearExpectations(&cert_issuer_source); EXPECT_TRUE(result.HasValidPath()); ASSERT_EQ(2U, result.paths.size()); diff --git a/chromium/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc b/chromium/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc index 3bc20ef0819..003157b8dfa 100644 --- a/chromium/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc +++ b/chromium/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc @@ -37,9 +37,7 @@ class PathBuilderDelegate { time, &result); path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source); - CompletionStatus rv = path_builder.Run(base::Closure()); - EXPECT_EQ(CompletionStatus::SYNC, rv); - + path_builder.Run(); EXPECT_EQ(expected_result, result.HasValidPath()); } }; diff --git a/chromium/net/cert/internal/trust_store.cc b/chromium/net/cert/internal/trust_store.cc index 07eff04a326..7540cfdab8b 100644 --- a/chromium/net/cert/internal/trust_store.cc +++ b/chromium/net/cert/internal/trust_store.cc @@ -36,9 +36,6 @@ TrustAnchor::TrustAnchor(scoped_refptr<ParsedCertificate> cert, TrustAnchor::~TrustAnchor() = default; -TrustStore::Request::Request() = default; -TrustStore::Request::~Request() = default; - TrustStore::TrustStore() = default; TrustStore::~TrustStore() = default; diff --git a/chromium/net/cert/internal/trust_store.h b/chromium/net/cert/internal/trust_store.h index 8422fd5c96a..6985301f35c 100644 --- a/chromium/net/cert/internal/trust_store.h +++ b/chromium/net/cert/internal/trust_store.h @@ -7,7 +7,6 @@ #include <vector> -#include "base/callback.h" #include "base/memory/ref_counted.h" #include "net/base/net_export.h" #include "net/cert/internal/parsed_certificate.h" @@ -115,35 +114,14 @@ using TrustAnchors = std::vector<scoped_refptr<TrustAnchor>>; // Interface for finding trust anchors. class NET_EXPORT TrustStore { public: - class NET_EXPORT Request { - public: - Request(); - // Destruction of the Request cancels it. - virtual ~Request(); - }; - TrustStore(); virtual ~TrustStore(); - using TrustAnchorsCallback = base::Callback<void(TrustAnchors)>; - - // Returns the trust anchors that match |cert|'s issuer name in - // |*synchronous_matches| and/or through |callback|. |cert| and - // |synchronous_matches| must not be null. - // - // If results are available synchronously, they will be appended to - // |*synchronous_matches|. |*synchronous_matches| will not be modified - // asynchronously. - // - // If |callback| is not null and results may be available asynchronously, - // |*out_req| will be filled with a Request, and |callback| will be called - // when results are available. The Request may be destroyed to cancel - // the callback if it has not occurred yet. + // Appends the trust anchors that match |cert|'s issuer name to |*matches|. + // |cert| and |matches| must not be null. virtual void FindTrustAnchorsForCert( const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const = 0; + TrustAnchors* matches) const = 0; private: DISALLOW_COPY_AND_ASSIGN(TrustStore); diff --git a/chromium/net/cert/internal/trust_store_collection.cc b/chromium/net/cert/internal/trust_store_collection.cc index dc35306eee2..7e004ae1b72 100644 --- a/chromium/net/cert/internal/trust_store_collection.cc +++ b/chromium/net/cert/internal/trust_store_collection.cc @@ -9,29 +9,16 @@ namespace net { TrustStoreCollection::TrustStoreCollection() = default; TrustStoreCollection::~TrustStoreCollection() = default; -void TrustStoreCollection::SetPrimaryTrustStore(TrustStore* store) { - DCHECK(!primary_store_); +void TrustStoreCollection::AddTrustStore(TrustStore* store) { DCHECK(store); - primary_store_ = store; -} - -void TrustStoreCollection::AddTrustStoreSynchronousOnly(TrustStore* store) { - DCHECK(store); - sync_only_stores_.push_back(store); + stores_.push_back(store); } void TrustStoreCollection::FindTrustAnchorsForCert( const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const { - if (primary_store_) - primary_store_->FindTrustAnchorsForCert(cert, callback, synchronous_matches, - out_req); - - for (auto* store : sync_only_stores_) { - store->FindTrustAnchorsForCert(cert, TrustAnchorsCallback(), - synchronous_matches, nullptr); + TrustAnchors* matches) const { + for (auto* store : stores_) { + store->FindTrustAnchorsForCert(cert, matches); } } diff --git a/chromium/net/cert/internal/trust_store_collection.h b/chromium/net/cert/internal/trust_store_collection.h index ec9d49fd8e2..74ece5f97ba 100644 --- a/chromium/net/cert/internal/trust_store_collection.h +++ b/chromium/net/cert/internal/trust_store_collection.h @@ -9,50 +9,28 @@ #include "net/base/net_export.h" #include "net/cert/internal/trust_store.h" -namespace base { -class TaskRunner; -} - namespace net { // TrustStoreCollection is an implementation of TrustStore which combines the // results from multiple TrustStores. // -// The synchronous matches will be in order from the primary store, and then -// from the secondary stores in the order they were added to the -// TrustStoreCollection. -// -// Currently only one "primary" store can be added that supports async queries, -// any number of additional, synchronous-only stores can be used. (The -// assumption is that the async one would be useful for OS integration, while -// the sync only stores can be used for supplying additional anchors. If -// multiple async stores are desired, it might be worth changing the -// FindTrustAnchorsForCert interface so that it can return async results in -// multiple batches.) +// The order of the matches will correspond to a concatenation of matches in +// the order the stores were added. class NET_EXPORT TrustStoreCollection : public TrustStore { public: TrustStoreCollection(); ~TrustStoreCollection() override; - // Includes results from |store| in the combined output. Both sync and async - // queries to |store| will be allowed. |store| must outlive the - // TrustStoreCollection. - void SetPrimaryTrustStore(TrustStore* store); - - // Includes results from |store| in the combined output. |store| will only be - // queried synchronously. |store| must outlive the TrustStoreCollection. - void AddTrustStoreSynchronousOnly(TrustStore* store); + // Includes results from |store| in the combined output. |store| must + // outlive the TrustStoreCollection. + void AddTrustStore(TrustStore* store); // TrustStore implementation: - void FindTrustAnchorsForCert( - const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const override; + void FindTrustAnchorsForCert(const scoped_refptr<ParsedCertificate>& cert, + TrustAnchors* matches) const override; private: - TrustStore* primary_store_ = nullptr; - std::vector<TrustStore*> sync_only_stores_; + std::vector<TrustStore*> stores_; DISALLOW_COPY_AND_ASSIGN(TrustStoreCollection); }; diff --git a/chromium/net/cert/internal/trust_store_collection_unittest.cc b/chromium/net/cert/internal/trust_store_collection_unittest.cc index a7561d3f782..c9cd85ccab8 100644 --- a/chromium/net/cert/internal/trust_store_collection_unittest.cc +++ b/chromium/net/cert/internal/trust_store_collection_unittest.cc @@ -4,33 +4,14 @@ #include "net/cert/internal/trust_store_collection.h" -#include "base/bind.h" #include "net/cert/internal/test_helpers.h" -#include "net/cert/internal/trust_store_test_helpers.h" -#include "testing/gmock/include/gmock/gmock.h" +#include "net/cert/internal/trust_store_in_memory.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { namespace { -using ::testing::_; -using ::testing::Property; -using ::testing::StrictMock; - -void NotCalled(TrustAnchors anchors) { - ADD_FAILURE() << "NotCalled was called"; -} - -class MockTrustStore : public TrustStore { - public: - MOCK_CONST_METHOD4(FindTrustAnchorsForCert, - void(const scoped_refptr<ParsedCertificate>&, - const TrustAnchorsCallback&, - TrustAnchors*, - std::unique_ptr<Request>*)); -}; - class TrustStoreCollectionTest : public testing::Test { public: void SetUp() override { @@ -75,155 +56,46 @@ class TrustStoreCollectionTest : public testing::Test { scoped_refptr<ParsedCertificate> newintermediate_; }; -// Collection contains no stores, should return no results and complete -// synchronously. +// Collection contains no stores, should return no results. TEST_F(TrustStoreCollectionTest, NoStores) { - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; + TrustAnchors matches; TrustStoreCollection collection; - collection.FindTrustAnchorsForCert(target_, base::Bind(&NotCalled), - &sync_matches, &req); + collection.FindTrustAnchorsForCert(target_, &matches); - EXPECT_FALSE(req); - EXPECT_TRUE(sync_matches.empty()); + EXPECT_TRUE(matches.empty()); } -// Collection contains only one synchronous store, should complete -// synchronously. -TEST_F(TrustStoreCollectionTest, NoPrimaryStoreOneSyncStore) { - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; +// Collection contains only one store. +TEST_F(TrustStoreCollectionTest, OneStore) { + TrustAnchors matches; TrustStoreCollection collection; TrustStoreInMemory in_memory; in_memory.AddTrustAnchor(newroot_); - collection.AddTrustStoreSynchronousOnly(&in_memory); - collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled), - &sync_matches, &req); - - EXPECT_FALSE(req); - ASSERT_EQ(1U, sync_matches.size()); - EXPECT_EQ(newroot_, sync_matches[0]); -} - -// Collection contains two synchronous stores, should complete synchronously. -TEST_F(TrustStoreCollectionTest, NoPrimaryStoreTwoSyncStores) { - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; - - TrustStoreCollection collection; - TrustStoreInMemory in_memory1; - TrustStoreInMemory in_memory2; - in_memory1.AddTrustAnchor(newroot_); - in_memory2.AddTrustAnchor(oldroot_); - collection.AddTrustStoreSynchronousOnly(&in_memory1); - collection.AddTrustStoreSynchronousOnly(&in_memory2); - collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled), - &sync_matches, &req); - - EXPECT_FALSE(req); - ASSERT_EQ(2U, sync_matches.size()); - EXPECT_EQ(newroot_, sync_matches[0]); - EXPECT_EQ(oldroot_, sync_matches[1]); -} - -// The secondary stores in the collection should not be passed a callback to -// their FindTrustAnchorsForCert call. -TEST_F(TrustStoreCollectionTest, SyncStoresAreQueriedSynchronously) { - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; - - TrustStoreCollection collection; - StrictMock<MockTrustStore> store; - collection.AddTrustStoreSynchronousOnly(&store); + collection.AddTrustStore(&in_memory); + collection.FindTrustAnchorsForCert(newintermediate_, &matches); - EXPECT_CALL( - store, - FindTrustAnchorsForCert( - _, Property(&TrustStore::TrustAnchorsCallback::is_null, true), _, _)); - - collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled), - &sync_matches, &req); - - EXPECT_FALSE(req); - EXPECT_TRUE(sync_matches.empty()); + ASSERT_EQ(1U, matches.size()); + EXPECT_EQ(newroot_, matches[0]); } -// If the primary store completes synchronously, TrustStoreCollection should -// complete synchronously also. -TEST_F(TrustStoreCollectionTest, AllStoresAreSynchronous) { - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; +// Collection contains two stores. +TEST_F(TrustStoreCollectionTest, TwoStores) { + TrustAnchors matches; TrustStoreCollection collection; TrustStoreInMemory in_memory1; TrustStoreInMemory in_memory2; in_memory1.AddTrustAnchor(newroot_); in_memory2.AddTrustAnchor(oldroot_); - collection.SetPrimaryTrustStore(&in_memory1); - collection.AddTrustStoreSynchronousOnly(&in_memory2); - collection.FindTrustAnchorsForCert(newintermediate_, base::Bind(&NotCalled), - &sync_matches, &req); - - EXPECT_FALSE(req); - ASSERT_EQ(2U, sync_matches.size()); - EXPECT_EQ(newroot_, sync_matches[0]); - EXPECT_EQ(oldroot_, sync_matches[1]); -} - -// Primary store returns results asynchronously. No secondary stores registered. -TEST_F(TrustStoreCollectionTest, AsyncPrimaryStore) { - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; - - TrustStoreInMemoryAsync in_memory_async; - in_memory_async.AddAsyncTrustAnchor(newroot_); - - TrustStoreCollection collection; - collection.SetPrimaryTrustStore(&in_memory_async); - - TrustAnchorResultRecorder anchor_results; - collection.FindTrustAnchorsForCert( - newintermediate_, anchor_results.Callback(), &sync_matches, &req); - - ASSERT_TRUE(req); - EXPECT_TRUE(sync_matches.empty()); - - anchor_results.Run(); - ASSERT_EQ(1U, anchor_results.matches().size()); - EXPECT_EQ(newroot_, anchor_results.matches()[0]); -} - -// Primary store returns results both synchronously and asynchronously, and -// a secondary store returns results synchronously as well. -TEST_F(TrustStoreCollectionTest, SyncAndAsyncPrimaryStoreAndSyncStore) { - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; - - TrustStoreInMemoryAsync in_memory_async; - in_memory_async.AddAsyncTrustAnchor(newroot_); - in_memory_async.AddSyncTrustAnchor(newrootrollover_); - - TrustStoreInMemory in_memory; - in_memory.AddTrustAnchor(oldroot_); - - TrustStoreCollection collection; - collection.SetPrimaryTrustStore(&in_memory_async); - collection.AddTrustStoreSynchronousOnly(&in_memory); - - TrustAnchorResultRecorder anchor_results; - collection.FindTrustAnchorsForCert( - newintermediate_, anchor_results.Callback(), &sync_matches, &req); - - ASSERT_TRUE(req); - ASSERT_EQ(2U, sync_matches.size()); - EXPECT_EQ(newrootrollover_, sync_matches[0]); - EXPECT_EQ(oldroot_, sync_matches[1]); + collection.AddTrustStore(&in_memory1); + collection.AddTrustStore(&in_memory2); + collection.FindTrustAnchorsForCert(newintermediate_, &matches); - anchor_results.Run(); - ASSERT_EQ(1U, anchor_results.matches().size()); - EXPECT_EQ(newroot_, anchor_results.matches()[0]); + ASSERT_EQ(2U, matches.size()); + EXPECT_EQ(newroot_, matches[0]); + EXPECT_EQ(oldroot_, matches[1]); } } // namespace diff --git a/chromium/net/cert/internal/trust_store_in_memory.cc b/chromium/net/cert/internal/trust_store_in_memory.cc index 4cdab9672d2..3f94b6f0c49 100644 --- a/chromium/net/cert/internal/trust_store_in_memory.cc +++ b/chromium/net/cert/internal/trust_store_in_memory.cc @@ -21,12 +21,10 @@ void TrustStoreInMemory::AddTrustAnchor(scoped_refptr<TrustAnchor> anchor) { void TrustStoreInMemory::FindTrustAnchorsForCert( const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const { + TrustAnchors* matches) const { auto range = anchors_.equal_range(cert->normalized_issuer().AsStringPiece()); for (auto it = range.first; it != range.second; ++it) - synchronous_matches->push_back(it->second); + matches->push_back(it->second); } } // namespace net diff --git a/chromium/net/cert/internal/trust_store_in_memory.h b/chromium/net/cert/internal/trust_store_in_memory.h index fea4c87d314..45b5123caf1 100644 --- a/chromium/net/cert/internal/trust_store_in_memory.h +++ b/chromium/net/cert/internal/trust_store_in_memory.h @@ -14,10 +14,6 @@ namespace net { -namespace der { -class Input; -} - // A very simple implementation of a TrustStore, which contains a set of // trust anchors. class NET_EXPORT TrustStoreInMemory : public TrustStore { @@ -31,11 +27,8 @@ class NET_EXPORT TrustStoreInMemory : public TrustStore { void AddTrustAnchor(scoped_refptr<TrustAnchor> anchor); // TrustStore implementation: - void FindTrustAnchorsForCert( - const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const override; + void FindTrustAnchorsForCert(const scoped_refptr<ParsedCertificate>& cert, + TrustAnchors* matches) const override; private: // Multimap from normalized subject -> TrustAnchor. diff --git a/chromium/net/cert/internal/trust_store_nss.cc b/chromium/net/cert/internal/trust_store_nss.cc index 1a01875ecdf..dd214dca4cf 100644 --- a/chromium/net/cert/internal/trust_store_nss.cc +++ b/chromium/net/cert/internal/trust_store_nss.cc @@ -7,11 +7,7 @@ #include <cert.h> #include <certdb.h> -#include "base/bind.h" -#include "base/callback_helpers.h" #include "base/memory/ptr_util.h" -#include "base/memory/weak_ptr.h" -#include "base/task_runner.h" #include "crypto/nss_util.h" #include "net/cert/internal/cert_errors.h" #include "net/cert/internal/parsed_certificate.h" @@ -22,13 +18,14 @@ namespace net { -namespace { +TrustStoreNSS::TrustStoreNSS(SECTrustType trust_type) + : trust_type_(trust_type) {} -// Get all certs in NSS which have a subject matching |der_name| and which are -// marked as a trusted CA. -void GetAnchors(const scoped_refptr<ParsedCertificate>& cert, - SECTrustType trust_type, - TrustAnchors* out_anchors) { +TrustStoreNSS::~TrustStoreNSS() = default; + +void TrustStoreNSS::FindTrustAnchorsForCert( + const scoped_refptr<ParsedCertificate>& cert, + TrustAnchors* out_anchors) const { crypto::EnsureNSSInit(); SECItem name; @@ -54,7 +51,7 @@ void GetAnchors(const scoped_refptr<ParsedCertificate>& cert, // TODO(mattm): handle explicit distrust (blacklisting)? const int ca_trust = CERTDB_TRUSTED_CA; - if ((SEC_GET_TRUST_FLAGS(&trust, trust_type) & ca_trust) != ca_trust) + if ((SEC_GET_TRUST_FLAGS(&trust, trust_type_) & ca_trust) != ca_trust) continue; CertErrors errors; @@ -73,65 +70,4 @@ void GetAnchors(const scoped_refptr<ParsedCertificate>& cert, CERT_DestroyCertList(found_certs); } -class GetAnchorsRequest : public TrustStore::Request { - public: - explicit GetAnchorsRequest(const TrustStore::TrustAnchorsCallback& callback); - // Destruction of the Request cancels it. GetAnchors will still run, but the - // callback will not be called since the WeakPtr will be invalidated. - ~GetAnchorsRequest() override = default; - - void Start(const scoped_refptr<ParsedCertificate>& cert, - SECTrustType trust_type, - base::TaskRunner* task_runner); - - private: - void HandleGetAnchors(std::unique_ptr<TrustAnchors> anchors); - - TrustStore::TrustAnchorsCallback callback_; - base::WeakPtrFactory<GetAnchorsRequest> weak_ptr_factory_; -}; - -GetAnchorsRequest::GetAnchorsRequest( - const TrustStore::TrustAnchorsCallback& callback) - : callback_(callback), weak_ptr_factory_(this) {} - -void GetAnchorsRequest::Start(const scoped_refptr<ParsedCertificate>& cert, - SECTrustType trust_type, - base::TaskRunner* task_runner) { - auto anchors = base::MakeUnique<TrustAnchors>(); - - auto* anchors_ptr = anchors.get(); - task_runner->PostTaskAndReply( - FROM_HERE, base::Bind(&GetAnchors, cert, trust_type, anchors_ptr), - base::Bind(&GetAnchorsRequest::HandleGetAnchors, - weak_ptr_factory_.GetWeakPtr(), base::Passed(&anchors))); -} - -void GetAnchorsRequest::HandleGetAnchors( - std::unique_ptr<TrustAnchors> anchors) { - base::ResetAndReturn(&callback_).Run(std::move(*anchors)); - // |this| may be deleted here. -} - -} // namespace - -TrustStoreNSS::TrustStoreNSS(SECTrustType trust_type, - scoped_refptr<base::TaskRunner> nss_task_runner) - : trust_type_(trust_type), nss_task_runner_(std::move(nss_task_runner)) {} - -TrustStoreNSS::~TrustStoreNSS() = default; - -void TrustStoreNSS::FindTrustAnchorsForCert( - const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const { - if (callback.is_null()) - return; - - auto req = base::MakeUnique<GetAnchorsRequest>(callback); - req->Start(cert, trust_type_, nss_task_runner_.get()); - *out_req = std::move(req); -} - } // namespace net diff --git a/chromium/net/cert/internal/trust_store_nss.h b/chromium/net/cert/internal/trust_store_nss.h index d153dbc5fdf..760d49953c2 100644 --- a/chromium/net/cert/internal/trust_store_nss.h +++ b/chromium/net/cert/internal/trust_store_nss.h @@ -11,36 +11,23 @@ #include "net/base/net_export.h" #include "net/cert/internal/trust_store.h" -namespace base { -class TaskRunner; -} - namespace net { // TrustStoreNSS is an implementation of TrustStore which uses NSS to find trust // anchors for path building. -// TODO(mattm): also implement CertIssuerSource to return intermediates in NSS -// DB? Or have a separate CertIssuerSourceNSS for that? (implementing both in -// the same class could be more efficient with some caching/etc. Need to be -// careful about caching between different pathbuilder instances though.) class NET_EXPORT TrustStoreNSS : public TrustStore { public: // Creates a TrustStoreNSS which will find anchors that are trusted for - // |trust_type|. All NSS calls will be done on |nss_task_runner|. - TrustStoreNSS(SECTrustType trust_type, - scoped_refptr<base::TaskRunner> nss_task_runner); + // |trust_type|. + explicit TrustStoreNSS(SECTrustType trust_type); ~TrustStoreNSS() override; // TrustStore implementation: - void FindTrustAnchorsForCert( - const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const override; + void FindTrustAnchorsForCert(const scoped_refptr<ParsedCertificate>& cert, + TrustAnchors* matches) const override; private: SECTrustType trust_type_; - scoped_refptr<base::TaskRunner> nss_task_runner_; DISALLOW_COPY_AND_ASSIGN(TrustStoreNSS); }; diff --git a/chromium/net/cert/internal/trust_store_nss_unittest.cc b/chromium/net/cert/internal/trust_store_nss_unittest.cc index b74c5f97125..f9d1f272d74 100644 --- a/chromium/net/cert/internal/trust_store_nss_unittest.cc +++ b/chromium/net/cert/internal/trust_store_nss_unittest.cc @@ -7,14 +7,10 @@ #include <cert.h> #include <certdb.h> -#include "base/bind.h" #include "base/memory/ptr_util.h" -#include "base/run_loop.h" #include "base/strings/string_number_conversions.h" -#include "base/threading/thread_task_runner_handle.h" #include "crypto/scoped_test_nss_db.h" #include "net/cert/internal/test_helpers.h" -#include "net/cert/internal/trust_store_test_helpers.h" #include "net/cert/scoped_nss_types.h" #include "net/cert/x509_certificate.h" #include "testing/gtest/include/gtest/gtest.h" @@ -23,10 +19,6 @@ namespace net { namespace { -void NotCalled(TrustAnchors anchors) { - ADD_FAILURE() << "NotCalled was called"; -} - class TrustStoreNSSTest : public testing::Test { public: void SetUp() override { @@ -61,8 +53,7 @@ class TrustStoreNSSTest : public testing::Test { ASSERT_TRUE(newroot_); ASSERT_TRUE(newrootrollover_); - trust_store_nss_.reset( - new TrustStoreNSS(trustSSL, base::ThreadTaskRunnerHandle::Get())); + trust_store_nss_.reset(new TrustStoreNSS(trustSSL)); } std::string GetUniqueNickname() { @@ -112,31 +103,27 @@ class TrustStoreNSSTest : public testing::Test { } protected: - void ExpectTrustStoreContains(tracked_objects::Location loc, - scoped_refptr<ParsedCertificate> cert, - TrustAnchors expected_async_matches) { - SCOPED_TRACE(loc.ToString()); - - TrustAnchors sync_matches; - TrustAnchorResultRecorder anchor_results; - std::unique_ptr<TrustStore::Request> req; - trust_store_nss_->FindTrustAnchorsForCert(cert, anchor_results.Callback(), - &sync_matches, &req); - ASSERT_TRUE(req); - EXPECT_TRUE(sync_matches.empty()); - - anchor_results.Run(); + bool TrustStoreContains(scoped_refptr<ParsedCertificate> cert, + TrustAnchors expected_matches) { + TrustAnchors matches; + trust_store_nss_->FindTrustAnchorsForCert(cert, &matches); + std::vector<der::Input> der_result_matches; - for (const auto& it : anchor_results.matches()) + for (const auto& it : matches) der_result_matches.push_back(it->cert()->der_cert()); std::sort(der_result_matches.begin(), der_result_matches.end()); std::vector<der::Input> der_expected_matches; - for (const auto& it : expected_async_matches) + for (const auto& it : expected_matches) der_expected_matches.push_back(it->cert()->der_cert()); std::sort(der_expected_matches.begin(), der_expected_matches.end()); + if (der_expected_matches == der_result_matches) + return true; + + // Print some extra information for debugging. EXPECT_EQ(der_expected_matches, der_result_matches); + return false; } scoped_refptr<TrustAnchor> oldroot_; @@ -154,19 +141,19 @@ class TrustStoreNSSTest : public testing::Test { // Without adding any certs to the NSS DB, should get no anchor results for any // of the test certs. TEST_F(TrustStoreNSSTest, CertsNotPresent) { - ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors()); + EXPECT_TRUE(TrustStoreContains(target_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(newintermediate_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(newroot_->cert(), TrustAnchors())); } // If certs are present in NSS DB but aren't marked as trusted, should get no // anchor results for any of the test certs. TEST_F(TrustStoreNSSTest, CertsPresentButNotTrusted) { AddCertsToNSS(); - ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors()); + EXPECT_TRUE(TrustStoreContains(newintermediate_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(target_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(newintermediate_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(newroot_->cert(), TrustAnchors())); } // A self-signed CA certificate is trusted. FindTrustAnchorsForCert should @@ -175,12 +162,12 @@ TEST_F(TrustStoreNSSTest, CertsPresentButNotTrusted) { TEST_F(TrustStoreNSSTest, TrustedCA) { AddCertsToNSS(); TrustCert(newroot_.get()); - ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, newintermediate_, {newroot_}); - ExpectTrustStoreContains(FROM_HERE, oldintermediate_, {newroot_}); - ExpectTrustStoreContains(FROM_HERE, newrootrollover_, {newroot_}); - ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), {newroot_}); - ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), {newroot_}); + EXPECT_TRUE(TrustStoreContains(target_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(newintermediate_, {newroot_})); + EXPECT_TRUE(TrustStoreContains(oldintermediate_, {newroot_})); + EXPECT_TRUE(TrustStoreContains(newrootrollover_, {newroot_})); + EXPECT_TRUE(TrustStoreContains(oldroot_->cert(), {newroot_})); + EXPECT_TRUE(TrustStoreContains(newroot_->cert(), {newroot_})); } // When an intermediate certificate is trusted, FindTrustAnchorsForCert should @@ -189,14 +176,14 @@ TEST_F(TrustStoreNSSTest, TrustedCA) { TEST_F(TrustStoreNSSTest, TrustedIntermediate) { AddCertsToNSS(); TrustCert(newintermediate_.get()); - ExpectTrustStoreContains( - FROM_HERE, target_, - {TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_)}); - ExpectTrustStoreContains(FROM_HERE, newintermediate_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, oldintermediate_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, newrootrollover_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, newroot_->cert(), TrustAnchors()); + EXPECT_TRUE(TrustStoreContains( + target_, + {TrustAnchor::CreateFromCertificateNoConstraints(newintermediate_)})); + EXPECT_TRUE(TrustStoreContains(newintermediate_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(oldintermediate_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(newrootrollover_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(oldroot_->cert(), TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(newroot_->cert(), TrustAnchors())); } // Multiple self-signed CA certificates with the same name are trusted. @@ -206,41 +193,10 @@ TEST_F(TrustStoreNSSTest, MultipleTrustedCAWithSameSubject) { AddCertsToNSS(); TrustCert(oldroot_.get()); TrustCert(newroot_.get()); - ExpectTrustStoreContains(FROM_HERE, target_, TrustAnchors()); - ExpectTrustStoreContains(FROM_HERE, newintermediate_, {newroot_, oldroot_}); - ExpectTrustStoreContains(FROM_HERE, oldintermediate_, {newroot_, oldroot_}); - ExpectTrustStoreContains(FROM_HERE, oldroot_->cert(), {newroot_, oldroot_}); -} - -// Cancel a FindTrustAnchorsForCert request before it has returned any results. -// Callback should not be called. -TEST_F(TrustStoreNSSTest, CancelRequest) { - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; - trust_store_nss_->FindTrustAnchorsForCert(target_, base::Bind(&NotCalled), - &sync_matches, &req); - ASSERT_TRUE(req); - req.reset(); - base::RunLoop().RunUntilIdle(); -} - -// Cancel a FindTrustAnchorsForCert request during the callback. Should not -// crash. -TEST_F(TrustStoreNSSTest, CancelRequestDuringCallback) { - AddCertsToNSS(); - TrustCert(newroot_.get()); - - base::RunLoop run_loop; - std::unique_ptr<TrustStore::Request> req; - TrustAnchors sync_matches; - trust_store_nss_->FindTrustAnchorsForCert( - newintermediate_, - base::Bind(&TrustStoreRequestDeleter, &req, run_loop.QuitClosure()), - &sync_matches, &req); - ASSERT_TRUE(req); - run_loop.Run(); - ASSERT_FALSE(req); - base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(TrustStoreContains(target_, TrustAnchors())); + EXPECT_TRUE(TrustStoreContains(newintermediate_, {newroot_, oldroot_})); + EXPECT_TRUE(TrustStoreContains(oldintermediate_, {newroot_, oldroot_})); + EXPECT_TRUE(TrustStoreContains(oldroot_->cert(), {newroot_, oldroot_})); } } // namespace diff --git a/chromium/net/cert/internal/trust_store_test_helpers.cc b/chromium/net/cert/internal/trust_store_test_helpers.cc deleted file mode 100644 index 52edc4e61e4..00000000000 --- a/chromium/net/cert/internal/trust_store_test_helpers.cc +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/cert/internal/trust_store_test_helpers.h" - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/memory/ptr_util.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/thread_task_runner_handle.h" - -namespace net { - -namespace { - -class TrustStoreInMemoryAsyncRequest : public TrustStore::Request { - public: - explicit TrustStoreInMemoryAsyncRequest( - const TrustStore::TrustAnchorsCallback& callback) - : callback_(callback), weak_ptr_factory_(this) {} - - void PostTrustCallback(TrustAnchors anchors) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&TrustStoreInMemoryAsyncRequest::DoTrustCallback, - weak_ptr_factory_.GetWeakPtr(), std::move(anchors))); - } - - private: - void DoTrustCallback(TrustAnchors anchors) { - base::ResetAndReturn(&callback_).Run(std::move(anchors)); - // |this| may be deleted here. - } - - TrustStore::TrustAnchorsCallback callback_; - base::WeakPtrFactory<TrustStoreInMemoryAsyncRequest> weak_ptr_factory_; -}; - -} // namespace - -void TrustStoreRequestDeleter(std::unique_ptr<TrustStore::Request>* req_owner, - const base::Closure& done_callback, - TrustAnchors anchors) { - req_owner->reset(); - done_callback.Run(); -} - -TrustAnchorResultRecorder::TrustAnchorResultRecorder() = default; -TrustAnchorResultRecorder::~TrustAnchorResultRecorder() = default; - -TrustStore::TrustAnchorsCallback TrustAnchorResultRecorder::Callback() { - return base::Bind(&TrustAnchorResultRecorder::OnGotAnchors, - base::Unretained(this)); -} - -void TrustAnchorResultRecorder::OnGotAnchors(TrustAnchors anchors) { - anchors_ = std::move(anchors); - run_loop_.Quit(); -} - -TrustStoreInMemoryAsync::TrustStoreInMemoryAsync() = default; -TrustStoreInMemoryAsync::~TrustStoreInMemoryAsync() = default; - -void TrustStoreInMemoryAsync::AddSyncTrustAnchor( - scoped_refptr<TrustAnchor> anchor) { - sync_store_.AddTrustAnchor(std::move(anchor)); -} - -void TrustStoreInMemoryAsync::AddAsyncTrustAnchor( - scoped_refptr<TrustAnchor> anchor) { - async_store_.AddTrustAnchor(std::move(anchor)); -} - -void TrustStoreInMemoryAsync::FindTrustAnchorsForCert( - const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const { - sync_store_.FindTrustAnchorsForCert(cert, TrustAnchorsCallback(), - synchronous_matches, nullptr); - if (!callback.is_null()) { - TrustAnchors async_matches; - async_store_.FindTrustAnchorsForCert(cert, TrustAnchorsCallback(), - &async_matches, nullptr); - - std::unique_ptr<TrustStoreInMemoryAsyncRequest> req( - base::MakeUnique<TrustStoreInMemoryAsyncRequest>(callback)); - req->PostTrustCallback(std::move(async_matches)); - - *out_req = std::move(req); - } -} - -} // namespace net diff --git a/chromium/net/cert/internal/trust_store_test_helpers.h b/chromium/net/cert/internal/trust_store_test_helpers.h deleted file mode 100644 index 3d1d5a6594c..00000000000 --- a/chromium/net/cert/internal/trust_store_test_helpers.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_CERT_INTERNAL_TRUST_STORE_TEST_HELPERS_H_ -#define NET_CERT_INTERNAL_TRUST_STORE_TEST_HELPERS_H_ - -#include "base/callback.h" -#include "base/run_loop.h" -#include "net/cert/internal/trust_store.h" -#include "net/cert/internal/trust_store_in_memory.h" - -namespace net { - -// Deletes the Request owned by |*req_owner|, then calls done_callback. Intended -// to be passed as the TrustAnchorsCallback to FindTrustAnchorsForCert to test -// deleting the Request during the request callback. -void TrustStoreRequestDeleter(std::unique_ptr<TrustStore::Request>* req_owner, - const base::Closure& done_callback, - TrustAnchors anchors); - -// Helper to record async results from a FindTrustAnchorsForCert call. -class TrustAnchorResultRecorder { - public: - TrustAnchorResultRecorder(); - ~TrustAnchorResultRecorder(); - - TrustStore::TrustAnchorsCallback Callback(); - - void Run() { run_loop_.Run(); } - - const TrustAnchors& matches() const { return anchors_; } - - private: - void OnGotAnchors(TrustAnchors anchors); - - base::RunLoop run_loop_; - TrustAnchors anchors_; -}; - -// In-memory TrustStore that can return results synchronously, asynchronously, -// or both. -class TrustStoreInMemoryAsync : public TrustStore { - public: - TrustStoreInMemoryAsync(); - ~TrustStoreInMemoryAsync() override; - - // Adds |anchor| to the set of results that will be returned synchronously. - void AddSyncTrustAnchor(scoped_refptr<TrustAnchor> anchor); - - // Adds |anchor| to the set of results that will be returned asynchronously. - void AddAsyncTrustAnchor(scoped_refptr<TrustAnchor> anchor); - - // TrustStore implementation: - void FindTrustAnchorsForCert( - const scoped_refptr<ParsedCertificate>& cert, - const TrustAnchorsCallback& callback, - TrustAnchors* synchronous_matches, - std::unique_ptr<Request>* out_req) const override; - - private: - TrustStoreInMemory sync_store_; - TrustStoreInMemory async_store_; -}; - -} // namespace net - -#endif // NET_CERT_INTERNAL_TRUST_STORE_TEST_HELPERS_H_ diff --git a/chromium/net/cert/internal/verify_certificate_chain.h b/chromium/net/cert/internal/verify_certificate_chain.h index d1ea57e0575..428bd7b0214 100644 --- a/chromium/net/cert/internal/verify_certificate_chain.h +++ b/chromium/net/cert/internal/verify_certificate_chain.h @@ -22,7 +22,6 @@ struct GeneralizedTime; class SignaturePolicy; class TrustAnchor; -class TrustStore; // VerifyCertificateChain() verifies a certificate path (chain) based on the // rules in RFC 5280. The caller is responsible for building the path and diff --git a/chromium/net/cert/internal/verify_signed_data.cc b/chromium/net/cert/internal/verify_signed_data.cc index 37fc0eb0a9e..8fd045b2a91 100644 --- a/chromium/net/cert/internal/verify_signed_data.cc +++ b/chromium/net/cert/internal/verify_signed_data.cc @@ -6,6 +6,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" +#include "base/numerics/safe_math.h" #include "crypto/openssl_util.h" #include "net/cert/internal/cert_errors.h" #include "net/cert/internal/signature_algorithm.h" diff --git a/chromium/net/cert/multi_log_ct_verifier.cc b/chromium/net/cert/multi_log_ct_verifier.cc index 61c07b6d4e5..a372b05c8a9 100644 --- a/chromium/net/cert/multi_log_ct_verifier.cc +++ b/chromium/net/cert/multi_log_ct_verifier.cc @@ -81,10 +81,10 @@ void MultiLogCTVerifier::SetObserver(Observer* observer) { observer_ = observer; } -int MultiLogCTVerifier::Verify( +void MultiLogCTVerifier::Verify( X509Certificate* cert, - const std::string& stapled_ocsp_response, - const std::string& sct_list_from_tls_extension, + base::StringPiece stapled_ocsp_response, + base::StringPiece sct_list_from_tls_extension, SignedCertificateTimestampAndStatusList* output_scts, const NetLogWithSource& net_log) { DCHECK(cert); @@ -92,8 +92,6 @@ int MultiLogCTVerifier::Verify( output_scts->clear(); - bool has_verified_scts = false; - std::string embedded_scts; if (!cert->GetIntermediateCertificates().empty() && ct::ExtractEmbeddedSCTList( @@ -101,13 +99,13 @@ int MultiLogCTVerifier::Verify( &embedded_scts)) { ct::LogEntry precert_entry; - has_verified_scts = - ct::GetPrecertLogEntry(cert->os_cert_handle(), + if (ct::GetPrecertLogEntry(cert->os_cert_handle(), cert->GetIntermediateCertificates().front(), - &precert_entry) && - VerifySCTs(embedded_scts, precert_entry, - ct::SignedCertificateTimestamp::SCT_EMBEDDED, cert, - output_scts); + &precert_entry)) { + VerifySCTs(embedded_scts, precert_entry, + ct::SignedCertificateTimestamp::SCT_EMBEDDED, cert, + output_scts); + } } std::string sct_list_from_ocsp; @@ -121,23 +119,21 @@ int MultiLogCTVerifier::Verify( // Log to Net Log, after extracting SCTs but before possibly failing on // X.509 entry creation. NetLogParametersCallback net_log_callback = - base::Bind(&NetLogRawSignedCertificateTimestampCallback, &embedded_scts, - &sct_list_from_ocsp, &sct_list_from_tls_extension); + base::Bind(&NetLogRawSignedCertificateTimestampCallback, embedded_scts, + sct_list_from_ocsp, sct_list_from_tls_extension); net_log.AddEvent(NetLogEventType::SIGNED_CERTIFICATE_TIMESTAMPS_RECEIVED, net_log_callback); ct::LogEntry x509_entry; if (ct::GetX509LogEntry(cert->os_cert_handle(), &x509_entry)) { - has_verified_scts |= - VerifySCTs(sct_list_from_ocsp, x509_entry, - ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, cert, - output_scts); - - has_verified_scts |= - VerifySCTs(sct_list_from_tls_extension, x509_entry, - ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, cert, - output_scts); + VerifySCTs(sct_list_from_ocsp, x509_entry, + ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, cert, + output_scts); + + VerifySCTs(sct_list_from_tls_extension, x509_entry, + ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION, cert, + output_scts); } NetLogParametersCallback net_log_checked_callback = @@ -147,29 +143,22 @@ int MultiLogCTVerifier::Verify( net_log_checked_callback); LogNumSCTsToUMA(*output_scts); - - if (has_verified_scts) - return OK; - - return ERR_CT_NO_SCTS_VERIFIED_OK; } -bool MultiLogCTVerifier::VerifySCTs( - const std::string& encoded_sct_list, +void MultiLogCTVerifier::VerifySCTs( + base::StringPiece encoded_sct_list, const ct::LogEntry& expected_entry, ct::SignedCertificateTimestamp::Origin origin, X509Certificate* cert, SignedCertificateTimestampAndStatusList* output_scts) { if (logs_.empty()) - return false; + return; - base::StringPiece temp(encoded_sct_list); std::vector<base::StringPiece> sct_list; - if (!ct::DecodeSCTList(&temp, &sct_list)) - return false; + if (!ct::DecodeSCTList(encoded_sct_list, &sct_list)) + return; - bool verified = false; for (std::vector<base::StringPiece>::const_iterator it = sct_list.begin(); it != sct_list.end(); ++it) { base::StringPiece encoded_sct(*it); @@ -178,15 +167,12 @@ bool MultiLogCTVerifier::VerifySCTs( scoped_refptr<ct::SignedCertificateTimestamp> decoded_sct; if (!DecodeSignedCertificateTimestamp(&encoded_sct, &decoded_sct)) { LogSCTStatusToUMA(ct::SCT_STATUS_NONE); - // XXX(rsleevi): Should we really just skip over bad SCTs? continue; } decoded_sct->origin = origin; - verified |= VerifySingleSCT(decoded_sct, expected_entry, cert, output_scts); + VerifySingleSCT(decoded_sct, expected_entry, cert, output_scts); } - - return verified; } bool MultiLogCTVerifier::VerifySingleSCT( diff --git a/chromium/net/cert/multi_log_ct_verifier.h b/chromium/net/cert/multi_log_ct_verifier.h index 05c2c069264..d4cb56fc2ac 100644 --- a/chromium/net/cert/multi_log_ct_verifier.h +++ b/chromium/net/cert/multi_log_ct_verifier.h @@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/strings/string_piece.h" #include "net/base/net_export.h" #include "net/cert/ct_verifier.h" #include "net/cert/signed_certificate_timestamp.h" @@ -34,19 +35,19 @@ class NET_EXPORT MultiLogCTVerifier : public CTVerifier { const std::vector<scoped_refptr<const CTLogVerifier>>& log_verifiers); // CTVerifier implementation: - int Verify(X509Certificate* cert, - const std::string& stapled_ocsp_response, - const std::string& sct_list_from_tls_extension, - SignedCertificateTimestampAndStatusList* output_scts, - const NetLogWithSource& net_log) override; + void Verify(X509Certificate* cert, + base::StringPiece stapled_ocsp_response, + base::StringPiece sct_list_from_tls_extension, + SignedCertificateTimestampAndStatusList* output_scts, + const NetLogWithSource& net_log) override; void SetObserver(Observer* observer) override; private: // Verify a list of SCTs from |encoded_sct_list| over |expected_entry|, - // placing the verification results in |result|. The SCTs in the list + // placing the verification results in |output_scts|. The SCTs in the list // come from |origin| (as will be indicated in the origin field of each SCT). - bool VerifySCTs(const std::string& encoded_sct_list, + void VerifySCTs(base::StringPiece encoded_sct_list, const ct::LogEntry& expected_entry, ct::SignedCertificateTimestamp::Origin origin, X509Certificate* cert, diff --git a/chromium/net/cert/multi_log_ct_verifier_unittest.cc b/chromium/net/cert/multi_log_ct_verifier_unittest.cc index 2efd7012a46..aea27f97195 100644 --- a/chromium/net/cert/multi_log_ct_verifier_unittest.cc +++ b/chromium/net/cert/multi_log_ct_verifier_unittest.cc @@ -111,34 +111,29 @@ class MultiLogCTVerifierTest : public ::testing::Test { return true; } - bool VerifySinglePrecertificateChain( - scoped_refptr<X509Certificate> chain, - const NetLogWithSource& net_log, - SignedCertificateTimestampAndStatusList* output_scts) { - return verifier_->Verify(chain.get(), std::string(), std::string(), - output_scts, net_log) == OK; - } - + // Returns true is |chain| is a certificate with embedded SCTs that can be + // successfully extracted. bool VerifySinglePrecertificateChain(scoped_refptr<X509Certificate> chain) { SignedCertificateTimestampAndStatusList scts; - TestNetLog test_net_log; - NetLogWithSource net_log = - NetLogWithSource::Make(&test_net_log, NetLogSourceType::CONNECT_JOB); - - return verifier_->Verify(chain.get(), std::string(), std::string(), &scts, - net_log) == OK; + verifier_->Verify(chain.get(), base::StringPiece(), base::StringPiece(), + &scts, NetLogWithSource()); + return !scts.empty(); } + // Returns true if |chain| is a certificate with a single embedded SCT that + // can be successfully extracted and matched to the test log indicated by + // |kLogDescription|. bool CheckPrecertificateVerification(scoped_refptr<X509Certificate> chain) { SignedCertificateTimestampAndStatusList scts; TestNetLog test_net_log; - NetLogWithSource net_log = - NetLogWithSource::Make(&test_net_log, NetLogSourceType::CONNECT_JOB); - return (VerifySinglePrecertificateChain(chain, net_log, &scts) && - ct::CheckForSingleVerifiedSCTInResult(scts, kLogDescription) && - ct::CheckForSCTOrigin( - scts, ct::SignedCertificateTimestamp::SCT_EMBEDDED) && - CheckForEmbeddedSCTInNetLog(test_net_log)); + NetLogWithSource net_log = NetLogWithSource::Make( + &test_net_log, NetLogSourceType::SSL_CONNECT_JOB); + verifier_->Verify(chain.get(), base::StringPiece(), base::StringPiece(), + &scts, net_log); + return ct::CheckForSingleVerifiedSCTInResult(scts, kLogDescription) && + ct::CheckForSCTOrigin( + scts, ct::SignedCertificateTimestamp::SCT_EMBEDDED) && + CheckForEmbeddedSCTInNetLog(test_net_log); } // Histogram-related helper methods @@ -212,8 +207,8 @@ TEST_F(MultiLogCTVerifierTest, VerifiesSCTOverX509Cert) { std::string sct_list = ct::GetSCTListForTesting(); SignedCertificateTimestampAndStatusList scts; - EXPECT_EQ(OK, verifier_->Verify(chain_.get(), std::string(), sct_list, &scts, - NetLogWithSource())); + verifier_->Verify(chain_.get(), base::StringPiece(), sct_list, &scts, + NetLogWithSource()); ASSERT_TRUE(ct::CheckForSingleVerifiedSCTInResult(scts, kLogDescription)); ASSERT_TRUE(ct::CheckForSCTOrigin( scts, ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION)); @@ -223,8 +218,8 @@ TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog) { std::string sct_list = ct::GetSCTListWithInvalidSCT(); SignedCertificateTimestampAndStatusList scts; - EXPECT_NE(OK, verifier_->Verify(chain_.get(), std::string(), sct_list, &scts, - NetLogWithSource())); + verifier_->Verify(chain_.get(), base::StringPiece(), sct_list, &scts, + NetLogWithSource()); EXPECT_EQ(1U, scts.size()); EXPECT_EQ("", scts[0].sct->log_description); EXPECT_EQ(ct::SCT_STATUS_LOG_UNKNOWN, scts[0].status); @@ -246,8 +241,8 @@ TEST_F(MultiLogCTVerifierTest, CountsInvalidSCTsInStatusHistogram) { int num_invalid_scts = GetValueFromHistogram( "Net.CertificateTransparency.SCTStatus", ct::SCT_STATUS_LOG_UNKNOWN); - EXPECT_NE(OK, verifier_->Verify(chain_.get(), std::string(), sct_list, &scts, - NetLogWithSource())); + verifier_->Verify(chain_.get(), base::StringPiece(), sct_list, &scts, + NetLogWithSource()); ASSERT_EQ(num_valid_scts, NumValidSCTsInStatusHistogram()); ASSERT_EQ(num_invalid_scts + 1, diff --git a/chromium/net/cert/multi_threaded_cert_verifier.cc b/chromium/net/cert/multi_threaded_cert_verifier.cc index 061ecd973f9..8312d413933 100644 --- a/chromium/net/cert/multi_threaded_cert_verifier.cc +++ b/chromium/net/cert/multi_threaded_cert_verifier.cc @@ -24,6 +24,7 @@ #include "base/values.h" #include "net/base/hash_value.h" #include "net/base/net_errors.h" +#include "net/base/trace_constants.h" #include "net/cert/cert_verify_proc.h" #include "net/cert/cert_verify_result.h" #include "net/cert/crl_set.h" @@ -189,7 +190,7 @@ void DoVerifyOnWorkerThread(const scoped_refptr<CertVerifyProc>& verify_proc, const CertificateList& additional_trust_anchors, int* error, CertVerifyResult* result) { - TRACE_EVENT0("net", "DoVerifyOnWorkerThread"); + TRACE_EVENT0(kNetTracingCategory, "DoVerifyOnWorkerThread"); *error = verify_proc->Verify(cert.get(), hostname, ocsp_response, flags, crl_set.get(), additional_trust_anchors, result); @@ -308,7 +309,7 @@ class CertVerifierJob { } void OnJobCompleted(std::unique_ptr<ResultHelper> verify_result) { - TRACE_EVENT0("net", "CertVerifierJob::OnJobCompleted"); + TRACE_EVENT0(kNetTracingCategory, "CertVerifierJob::OnJobCompleted"); std::unique_ptr<CertVerifierJob> keep_alive = cert_verifier_->RemoveJob(this); diff --git a/chromium/net/cert/multi_threaded_cert_verifier.h b/chromium/net/cert/multi_threaded_cert_verifier.h index 6022984dac6..6b9dfadb7ae 100644 --- a/chromium/net/cert/multi_threaded_cert_verifier.h +++ b/chromium/net/cert/multi_threaded_cert_verifier.h @@ -25,7 +25,6 @@ namespace net { class CertVerifierJob; class CertVerifierRequest; -class CertVerifierWorker; class CertVerifyProc; // MultiThreadedCertVerifier is a CertVerifier implementation that runs diff --git a/chromium/net/cert/multi_threaded_cert_verifier_unittest.cc b/chromium/net/cert/multi_threaded_cert_verifier_unittest.cc index 1c1dbe43f31..aecbb51de08 100644 --- a/chromium/net/cert/multi_threaded_cert_verifier_unittest.cc +++ b/chromium/net/cert/multi_threaded_cert_verifier_unittest.cc @@ -10,7 +10,6 @@ #include "base/debug/leak_annotations.h" #include "base/files/file_path.h" #include "base/format_macros.h" -#include "base/strings/stringprintf.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/cert/cert_verify_proc.h" diff --git a/chromium/net/cert/nss_cert_database.cc b/chromium/net/cert/nss_cert_database.cc index 6842643d5f6..fc2ae61557a 100644 --- a/chromium/net/cert/nss_cert_database.cc +++ b/chromium/net/cert/nss_cert_database.cc @@ -143,16 +143,6 @@ crypto::ScopedPK11Slot NSSCertDatabase::GetPrivateSlot() const { return crypto::ScopedPK11Slot(PK11_ReferenceSlot(private_slot_.get())); } -CryptoModule* NSSCertDatabase::GetPublicModule() const { - crypto::ScopedPK11Slot slot(GetPublicSlot()); - return CryptoModule::CreateFromHandle(slot.get()); -} - -CryptoModule* NSSCertDatabase::GetPrivateModule() const { - crypto::ScopedPK11Slot slot(GetPrivateSlot()); - return CryptoModule::CreateFromHandle(slot.get()); -} - void NSSCertDatabase::ListModules(CryptoModuleList* modules, bool need_rw) const { modules->clear(); @@ -176,15 +166,15 @@ void NSSCertDatabase::ListModules(CryptoModuleList* modules, } } -int NSSCertDatabase::ImportFromPKCS12(CryptoModule* module, +int NSSCertDatabase::ImportFromPKCS12(PK11SlotInfo* slot_info, const std::string& data, const base::string16& password, bool is_extractable, CertificateList* imported_certs) { DVLOG(1) << __func__ << " " - << PK11_GetModuleID(module->os_module_handle()) << ":" - << PK11_GetSlotID(module->os_module_handle()); - int result = psm::nsPKCS12Blob_Import(module->os_module_handle(), + << PK11_GetModuleID(slot_info) << ":" + << PK11_GetSlotID(slot_info); + int result = psm::nsPKCS12Blob_Import(slot_info, data.data(), data.size(), password, is_extractable, diff --git a/chromium/net/cert/nss_cert_database.h b/chromium/net/cert/nss_cert_database.h index 2ee859dbb71..18e14768ac0 100644 --- a/chromium/net/cert/nss_cert_database.h +++ b/chromium/net/cert/nss_cert_database.h @@ -145,18 +145,6 @@ class NET_EXPORT NSSCertDatabase { // Can return NULL. crypto::ScopedPK11Slot GetPrivateSlot() const; - // Get the default module for public key data. - // The returned pointer must be stored in a scoped_refptr<CryptoModule>. - // DEPRECATED: use GetPublicSlot instead. - // TODO(mattm): remove usage of this method and remove it. - CryptoModule* GetPublicModule() const; - - // Get the default module for private key or mixed private/public key data. - // The returned pointer must be stored in a scoped_refptr<CryptoModule>. - // DEPRECATED: use GetPrivateSlot instead. - // TODO(mattm): remove usage of this method and remove it. - CryptoModule* GetPrivateModule() const; - // Get all modules. // If |need_rw| is true, only writable modules will be returned. // TODO(mattm): come up with better alternative to CryptoModuleList. @@ -168,7 +156,7 @@ class NET_EXPORT NSSCertDatabase { // Returns OK or a network error code such as ERR_PKCS12_IMPORT_BAD_PASSWORD // or ERR_PKCS12_IMPORT_ERROR. |imported_certs|, if non-NULL, returns a list // of certs that were imported. - int ImportFromPKCS12(CryptoModule* module, + int ImportFromPKCS12(PK11SlotInfo* slot_info, const std::string& data, const base::string16& password, bool is_extractable, diff --git a/chromium/net/cert/nss_cert_database_chromeos.h b/chromium/net/cert/nss_cert_database_chromeos.h index 4eb27a7fd48..fa440575fb0 100644 --- a/chromium/net/cert/nss_cert_database_chromeos.h +++ b/chromium/net/cert/nss_cert_database_chromeos.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_CERT_NSS_CERT_DATABASE_CHROMEOS_ -#define NET_CERT_NSS_CERT_DATABASE_CHROMEOS_ +#ifndef NET_CERT_NSS_CERT_DATABASE_CHROMEOS_H_ +#define NET_CERT_NSS_CERT_DATABASE_CHROMEOS_H_ #include "base/callback.h" #include "base/macros.h" @@ -51,4 +51,4 @@ class NET_EXPORT NSSCertDatabaseChromeOS : public NSSCertDatabase { } // namespace net -#endif // NET_CERT_NSS_CERT_DATABASE_CHROMEOS_ +#endif // NET_CERT_NSS_CERT_DATABASE_CHROMEOS_H_ diff --git a/chromium/net/cert/nss_cert_database_unittest.cc b/chromium/net/cert/nss_cert_database_unittest.cc index 9e20f886def..235ea44cc0d 100644 --- a/chromium/net/cert/nss_cert_database_unittest.cc +++ b/chromium/net/cert/nss_cert_database_unittest.cc @@ -68,7 +68,7 @@ class CertDatabaseNSSTest : public testing::Test { PK11_ReferenceSlot(test_nssdb_.slot())) /* public slot */, crypto::ScopedPK11Slot( PK11_ReferenceSlot(test_nssdb_.slot())) /* private slot */)); - public_module_ = cert_db_->GetPublicModule(); + public_slot_ = cert_db_->GetPublicSlot(); // Test db should be empty at start of test. EXPECT_EQ(0U, ListCerts().size()); @@ -82,7 +82,7 @@ class CertDatabaseNSSTest : public testing::Test { } protected: - CryptoModule* GetPublicModule() { return public_module_.get(); } + PK11SlotInfo* GetPublicSlot() { return public_slot_.get(); } static std::string ReadTestFile(const std::string& name) { std::string result; @@ -128,7 +128,7 @@ class CertDatabaseNSSTest : public testing::Test { std::unique_ptr<NSSCertDatabase> cert_db_; const CertificateList empty_cert_list_; crypto::ScopedTestNSSDB test_nssdb_; - scoped_refptr<CryptoModule> public_module_; + crypto::ScopedPK11Slot public_slot_; }; TEST_F(CertDatabaseNSSTest, ListCertsSync) { @@ -160,7 +160,7 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12WrongPassword) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(ERR_PKCS12_IMPORT_BAD_PASSWORD, - cert_db_->ImportFromPKCS12(GetPublicModule(), + cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, base::string16(), true, // is_extractable @@ -174,7 +174,7 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsExtractableAndExportAgain) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(OK, - cert_db_->ImportFromPKCS12(GetPublicModule(), + cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, ASCIIToUTF16("12345"), true, // is_extractable @@ -199,7 +199,7 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12Twice) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(OK, - cert_db_->ImportFromPKCS12(GetPublicModule(), + cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, ASCIIToUTF16("12345"), true, // is_extractable @@ -209,7 +209,7 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12Twice) { // NSS has a SEC_ERROR_PKCS12_DUPLICATE_DATA error, but it doesn't look like // it's ever used. This test verifies that. EXPECT_EQ(OK, - cert_db_->ImportFromPKCS12(GetPublicModule(), + cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, ASCIIToUTF16("12345"), true, // is_extractable @@ -221,7 +221,7 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsUnextractableAndExportAgain) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(OK, - cert_db_->ImportFromPKCS12(GetPublicModule(), + cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, ASCIIToUTF16("12345"), false, // is_extractable @@ -244,7 +244,7 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12AsUnextractableAndExportAgain) { TEST_F(CertDatabaseNSSTest, ImportFromPKCS12OnlyMarkIncludedKey) { std::string pkcs12_data = ReadTestFile("client.p12"); EXPECT_EQ(OK, - cert_db_->ImportFromPKCS12(GetPublicModule(), + cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, ASCIIToUTF16("12345"), true, // is_extractable @@ -256,7 +256,7 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12OnlyMarkIncludedKey) { // Now import a PKCS#12 file with just a certificate but no private key. pkcs12_data = ReadTestFile("client-nokey.p12"); EXPECT_EQ(OK, - cert_db_->ImportFromPKCS12(GetPublicModule(), + cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, ASCIIToUTF16("12345"), false, // is_extractable @@ -276,7 +276,7 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12InvalidFile) { std::string pkcs12_data = "Foobarbaz"; EXPECT_EQ(ERR_PKCS12_IMPORT_INVALID_FILE, - cert_db_->ImportFromPKCS12(GetPublicModule(), + cert_db_->ImportFromPKCS12(GetPublicSlot(), pkcs12_data, base::string16(), true, // is_extractable @@ -286,6 +286,30 @@ TEST_F(CertDatabaseNSSTest, ImportFromPKCS12InvalidFile) { EXPECT_EQ(0U, ListCerts().size()); } +TEST_F(CertDatabaseNSSTest, ImportFromPKCS12EmptyPassword) { + std::string pkcs12_data = ReadTestFile("client-empty-password.p12"); + + EXPECT_EQ(OK, + cert_db_->ImportFromPKCS12(GetPublicSlot(), + pkcs12_data, + base::string16(), + true, // is_extractable + NULL)); + EXPECT_EQ(1U, ListCerts().size()); +} + +TEST_F(CertDatabaseNSSTest, ImportFromPKCS12NullPassword) { + std::string pkcs12_data = ReadTestFile("client-null-password.p12"); + + EXPECT_EQ(OK, + cert_db_->ImportFromPKCS12(GetPublicSlot(), + pkcs12_data, + base::string16(), + true, // is_extractable + NULL)); + EXPECT_EQ(1U, ListCerts().size()); +} + TEST_F(CertDatabaseNSSTest, ImportCACert_SSLTrust) { CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "root_ca_cert.pem", diff --git a/chromium/net/cert/nss_profile_filter_chromeos.cc b/chromium/net/cert/nss_profile_filter_chromeos.cc index adb5defb6f8..71eeab20629 100644 --- a/chromium/net/cert/nss_profile_filter_chromeos.cc +++ b/chromium/net/cert/nss_profile_filter_chromeos.cc @@ -158,4 +158,3 @@ bool NSSProfileFilterChromeOS::ModuleNotAllowedForProfilePredicate::operator()( } } // namespace net - diff --git a/chromium/net/cert/ocsp_revocation_status.h b/chromium/net/cert/ocsp_revocation_status.h index 945104f26f6..c20dd2e2c83 100644 --- a/chromium/net/cert/ocsp_revocation_status.h +++ b/chromium/net/cert/ocsp_revocation_status.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_CERT_OCSP_REVOCATION_STATUS_H -#define NET_CERT_OCSP_REVOCATION_STATUS_H +#ifndef NET_CERT_OCSP_REVOCATION_STATUS_H_ +#define NET_CERT_OCSP_REVOCATION_STATUS_H_ namespace net { @@ -15,4 +15,4 @@ enum class OCSPRevocationStatus { } // namespace net -#endif // NET_CERT_OCSP_REVOCATION_STATUS_H +#endif // NET_CERT_OCSP_REVOCATION_STATUS_H_ diff --git a/chromium/net/cert/ocsp_verify_result.h b/chromium/net/cert/ocsp_verify_result.h index a2b8494b277..3a0bd7c26e3 100644 --- a/chromium/net/cert/ocsp_verify_result.h +++ b/chromium/net/cert/ocsp_verify_result.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_CERT_OCSP_VERIFY_RESULT_H -#define NET_CERT_OCSP_VERIFY_RESULT_H +#ifndef NET_CERT_OCSP_VERIFY_RESULT_H_ +#define NET_CERT_OCSP_VERIFY_RESULT_H_ #include <string> @@ -27,6 +27,9 @@ struct NET_EXPORT OCSPVerifyResult { bool operator==(const OCSPVerifyResult& other) const; enum ResponseStatus { + // OCSP verification was not checked on this connection. + NOT_CHECKED, + // No OCSPResponse was stapled. MISSING, @@ -56,7 +59,7 @@ struct NET_EXPORT OCSPVerifyResult { }; - ResponseStatus response_status = MISSING; + ResponseStatus response_status = NOT_CHECKED; // The strictest CertStatus matching the certificate (REVOKED > UNKNOWN > // GOOD). Only valid if |response_status| = PROVIDED. @@ -65,4 +68,4 @@ struct NET_EXPORT OCSPVerifyResult { } // namespace net -#endif // NET_CERT_OCSP_VERIFY_RESULT_H +#endif // NET_CERT_OCSP_VERIFY_RESULT_H_ diff --git a/chromium/net/cert/signed_tree_head.h b/chromium/net/cert/signed_tree_head.h index 2d65192fc54..2b97f744506 100644 --- a/chromium/net/cert/signed_tree_head.h +++ b/chromium/net/cert/signed_tree_head.h @@ -61,4 +61,4 @@ NET_EXPORT bool operator!=(const SignedTreeHead& lhs, } // namespace net -#endif +#endif // NET_CERT_SIGNED_TREE_HEAD_H_ diff --git a/chromium/net/cert/test_keychain_search_list_mac.h b/chromium/net/cert/test_keychain_search_list_mac.h index d0faffdbf54..4ae25729c93 100644 --- a/chromium/net/cert/test_keychain_search_list_mac.h +++ b/chromium/net/cert/test_keychain_search_list_mac.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_CERT_KEYCHAIN_SEARCH_LIST_MAC_H_ -#define NET_CERT_KEYCHAIN_SEARCH_LIST_MAC_H_ +#ifndef NET_CERT_TEST_KEYCHAIN_SEARCH_LIST_MAC_H_ +#define NET_CERT_TEST_KEYCHAIN_SEARCH_LIST_MAC_H_ #include <CoreServices/CoreServices.h> #include <Security/Security.h> @@ -43,4 +43,4 @@ class NET_EXPORT TestKeychainSearchList { } // namespace net -#endif // NET_CERT_KEYCHAIN_SEARCH_LIST_MAC_H_ +#endif // NET_CERT_TEST_KEYCHAIN_SEARCH_LIST_MAC_H_ diff --git a/chromium/net/cert/test_root_certs.h b/chromium/net/cert/test_root_certs.h index a77f0bf5f1d..53dd5f59106 100644 --- a/chromium/net/cert/test_root_certs.h +++ b/chromium/net/cert/test_root_certs.h @@ -150,7 +150,7 @@ class NET_EXPORT TestRootCerts { class NET_EXPORT_PRIVATE ScopedTestRoot { public: ScopedTestRoot(); - // Creates a ScopedTestRoot that will adds|cert| to the TestRootCerts store. + // Creates a ScopedTestRoot that will add |cert| to the TestRootCerts store. explicit ScopedTestRoot(X509Certificate* cert); ~ScopedTestRoot(); diff --git a/chromium/net/cert/x509_cert_types.cc b/chromium/net/cert/x509_cert_types.cc index e2ffb3d1b05..eec184a10f4 100644 --- a/chromium/net/cert/x509_cert_types.cc +++ b/chromium/net/cert/x509_cert_types.cc @@ -71,13 +71,9 @@ bool ParseCertificateDate(const base::StringPiece& raw_date, if (valid && year_length == 2) exploded.year += exploded.year < 50 ? 2000 : 1900; - valid &= exploded.HasValidValues(); - if (!valid) return false; - - *time = base::Time::FromUTCExploded(exploded); - return true; + return base::Time::FromUTCExploded(exploded, time); } } // namespace net diff --git a/chromium/net/cert/x509_cert_types.h b/chromium/net/cert/x509_cert_types.h index d2a55fe4b54..acb5b4fa3d5 100644 --- a/chromium/net/cert/x509_cert_types.h +++ b/chromium/net/cert/x509_cert_types.h @@ -30,8 +30,6 @@ class Time; namespace net { -class X509Certificate; - // CertPrincipal represents the issuer or subject field of an X.509 certificate. struct NET_EXPORT CertPrincipal { CertPrincipal(); diff --git a/chromium/net/cert/x509_cert_types_unittest.cc b/chromium/net/cert/x509_cert_types_unittest.cc index 50275f0eb01..cc9d88fbe9f 100644 --- a/chromium/net/cert/x509_cert_types_unittest.cc +++ b/chromium/net/cert/x509_cert_types_unittest.cc @@ -182,18 +182,21 @@ const struct CertDateTestData { "20120101123000Z", true, {2012, 1, 0, 1, 12, 30, 0}}, + // test 31st of April + {CERT_DATE_FORMAT_GENERALIZED_TIME, "20160431121000Z", false, {0}}, + // test 31st of February + {CERT_DATE_FORMAT_GENERALIZED_TIME, "20160231121000Z", false, {0}}, }; // GTest pretty printer. void PrintTo(const CertDateTestData& data, std::ostream* os) { + base::Time out_time; + bool result = base::Time::FromUTCExploded(data.expected_result, &out_time); *os << " format: " << data.format << "; date string: " << base::StringPiece(data.date_string) - << "; valid: " << data.is_valid - << "; expected date: " - << (data.is_valid ? - base::Time::FromUTCExploded(data.expected_result) - .ToInternalValue() : - 0U); + << "; valid: " << data.is_valid << "; expected date: " + << (data.is_valid ? out_time.ToInternalValue() : 0U) + << "; FromUTCExploded conversion result: " << result; } class X509CertTypesDateTest : public testing::TestWithParam<CertDateTestData> { @@ -202,24 +205,30 @@ class X509CertTypesDateTest : public testing::TestWithParam<CertDateTestData> { void SetUp() override { test_data_ = GetParam(); } protected: - CertDateTestData test_data_; + CertDateTestData test_data_; }; TEST_P(X509CertTypesDateTest, Parse) { base::Time parsed_date; bool parsed = ParseCertificateDate( test_data_.date_string, test_data_.format, &parsed_date); - EXPECT_EQ(test_data_.is_valid, parsed); + if (!parsed && test_data_.is_valid && + test_data_.expected_result.year >= 2038 && sizeof(time_t) == 4) { + // Some of the valid test data will fail on 32-bit POSIX systems + return; + } + if (!test_data_.is_valid) return; - // Convert the expected value to a base::Time(). This ensures that systems + // Convert the expected value to a base::Time(). This ensures that // systems that only support 32-bit times will pass the tests, by ensuring at - // least that the times have the same truncating behaviour. + // least that the times have the same truncating behavior. // Note: Compared as internal values so that mismatches can be cleanly - // printed by GTest (eg: without PrintTo overrides). - EXPECT_EQ(base::Time::FromUTCExploded(test_data_.expected_result) - .ToInternalValue(), - parsed_date.ToInternalValue()); + // printed by GTest (e.g.: without PrintTo overrides). + base::Time out_time; + EXPECT_TRUE( + base::Time::FromUTCExploded(test_data_.expected_result, &out_time)); + EXPECT_EQ(out_time.ToInternalValue(), parsed_date.ToInternalValue()); } INSTANTIATE_TEST_CASE_P(, X509CertTypesDateTest, diff --git a/chromium/net/cert/x509_certificate.cc b/chromium/net/cert/x509_certificate.cc index 7f23e7bf1d4..0d6fe95f134 100644 --- a/chromium/net/cert/x509_certificate.cc +++ b/chromium/net/cert/x509_certificate.cc @@ -25,6 +25,7 @@ #include "base/strings/string_util.h" #include "base/synchronization/lock.h" #include "base/time/time.h" +#include "base/trace_event/trace_event.h" #include "crypto/secure_hash.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "net/base/url_util.h" @@ -235,6 +236,8 @@ scoped_refptr<X509Certificate> X509Certificate::CreateFromHandle( // static scoped_refptr<X509Certificate> X509Certificate::CreateFromDERCertChain( const std::vector<base::StringPiece>& der_certs) { + TRACE_EVENT0("io", "X509Certificate::CreateFromDERCertChain"); + // TODO(cbentzel): Remove ScopedTracker below once crbug.com/424386 is fixed. tracked_objects::ScopedTracker tracking_profile( FROM_HERE_WITH_EXPLICIT_FUNCTION( diff --git a/chromium/net/cert/x509_certificate.h b/chromium/net/cert/x509_certificate.h index dde8ae0ad4e..0aff1be6100 100644 --- a/chromium/net/cert/x509_certificate.h +++ b/chromium/net/cert/x509_certificate.h @@ -42,8 +42,7 @@ class PickleIterator; namespace net { -class CRLSet; -class CertVerifyResult; +class X509Certificate; typedef std::vector<scoped_refptr<X509Certificate> > CertificateList; @@ -81,6 +80,14 @@ class NET_EXPORT X509Certificate kPublicKeyTypeECDH }; + enum SignatureHashAlgorithm { + kSignatureHashAlgorithmMd2, + kSignatureHashAlgorithmMd4, + kSignatureHashAlgorithmMd5, + kSignatureHashAlgorithmSha1, + kSignatureHashAlgorithmOther, + }; + enum Format { // The data contains a single DER-encoded certificate, or a PEM-encoded // DER certificate with the PEM encoding block name of "CERTIFICATE". @@ -146,20 +153,8 @@ class NET_EXPORT X509Certificate size_t length); #if defined(USE_NSS_CERTS) - // Create an X509Certificate from the DER-encoded representation. - // |nickname| can be NULL if an auto-generated nickname is desired. - // Returns NULL on failure. - // - // This function differs from CreateFromBytes in that it takes a - // nickname that will be used when the certificate is imported into PKCS#11. - static scoped_refptr<X509Certificate> CreateFromBytesWithNickname( - const char* data, - size_t length, - const char* nickname); - // The default nickname of the certificate, based on the certificate type - // passed in. If this object was created using CreateFromBytesWithNickname, - // then this will return the nickname specified upon creation. + // passed in. std::string GetDefaultNickname(CertType type) const; #endif @@ -328,6 +323,15 @@ class NET_EXPORT X509Certificate size_t* size_bits, PublicKeyType* type); + // Returns the digest algorithm used in |cert_handle|'s signature. + // If the digest algorithm cannot be determined, or if it is not one + // of the explicitly enumerated values, kSignatureHashAlgorithmOther + // will be returned. + // NOTE: No validation of the signature is performed, and thus invalid + // signatures may result in seemingly meaningful values. + static SignatureHashAlgorithm GetSignatureHashAlgorithm( + OSCertHandle cert_handle); + // Returns the OSCertHandle of this object. Because of caching, this may // differ from the OSCertHandle originally supplied during initialization. // Note: On Windows, CryptoAPI may return unexpected results if this handle @@ -462,14 +466,6 @@ class NET_EXPORT X509Certificate // that may be needed for chain building. OSCertHandles intermediate_ca_certs_; -#if defined(USE_NSS_CERTS) - // This stores any default nickname that has been set on the certificate - // at creation time with CreateFromBytesWithNickname. - // If this is empty, then GetDefaultNickname will return a generated name - // based on the type of the certificate. - std::string default_nickname_; -#endif - DISALLOW_COPY_AND_ASSIGN(X509Certificate); }; diff --git a/chromium/net/cert/x509_certificate_ios.cc b/chromium/net/cert/x509_certificate_ios.cc index 737970768fb..18ce828df72 100644 --- a/chromium/net/cert/x509_certificate_ios.cc +++ b/chromium/net/cert/x509_certificate_ios.cc @@ -358,6 +358,29 @@ void X509Certificate::GetPublicKeyInfo(OSCertHandle os_cert, *size_bits = EVP_PKEY_bits(key); } +// static +X509Certificate::SignatureHashAlgorithm +X509Certificate::GetSignatureHashAlgorithm(OSCertHandle cert_handle) { + bssl::UniquePtr<X509> cert = OSCertHandleToOpenSSL(cert_handle); + if (!cert) + return kSignatureHashAlgorithmOther; + + // TODO(eroman): This duplicates code with x509_certificate_openssl.cc + int sig_alg = OBJ_obj2nid(cert->sig_alg->algorithm); + if (sig_alg == NID_md2WithRSAEncryption) + return kSignatureHashAlgorithmMd2; + if (sig_alg == NID_md4WithRSAEncryption) + return kSignatureHashAlgorithmMd4; + if (sig_alg == NID_md5WithRSAEncryption || sig_alg == NID_md5WithRSA) + return kSignatureHashAlgorithmMd5; + if (sig_alg == NID_sha1WithRSAEncryption || sig_alg == NID_dsaWithSHA || + sig_alg == NID_dsaWithSHA1 || sig_alg == NID_dsaWithSHA1_2 || + sig_alg == NID_sha1WithRSA || sig_alg == NID_ecdsa_with_SHA1) { + return kSignatureHashAlgorithmSha1; + } + return kSignatureHashAlgorithmOther; +} + bool X509Certificate::SupportsSSLClientAuth() const { return false; } diff --git a/chromium/net/cert/x509_certificate_known_roots_win.h b/chromium/net/cert/x509_certificate_known_roots_win.h index eea3a6875ff..43ce812de9e 100644 --- a/chromium/net/cert/x509_certificate_known_roots_win.h +++ b/chromium/net/cert/x509_certificate_known_roots_win.h @@ -16,7 +16,7 @@ // // Note that these *are not* trust anchors for Chromium. They are only used to // distinguish `real' root CAs from roots that were user-installed. -static uint8_t kKnownRootCertSHA256Hashes[][32] = { +static const uint8_t kKnownRootCertSHA256Hashes[][32] = { // C=US, O=Network Solutions L.L.C., CN=Network Solutions Certificate // Authority {0x00, 0x16, 0x86, 0xCD, 0x18, 0x1F, 0x83, 0xA1, 0xB1, 0x21, 0x7D, 0x30, diff --git a/chromium/net/cert/x509_certificate_mac.cc b/chromium/net/cert/x509_certificate_mac.cc index 8e6ecf9fb42..6283d3658d2 100644 --- a/chromium/net/cert/x509_certificate_mac.cc +++ b/chromium/net/cert/x509_certificate_mac.cc @@ -518,6 +518,43 @@ void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, } } +X509Certificate::SignatureHashAlgorithm +X509Certificate::GetSignatureHashAlgorithm(OSCertHandle cert_handle) { + x509_util::CSSMCachedCertificate cached_cert; + OSStatus status = cached_cert.Init(cert_handle); + if (status) + return kSignatureHashAlgorithmOther; + + x509_util::CSSMFieldValue signature_field; + status = + cached_cert.GetField(&CSSMOID_X509V1SignatureAlgorithm, &signature_field); + if (status || !signature_field.field()) + return kSignatureHashAlgorithmOther; + + const CSSM_X509_ALGORITHM_IDENTIFIER* sig_algorithm = + signature_field.GetAs<CSSM_X509_ALGORITHM_IDENTIFIER>(); + if (!sig_algorithm) + return kSignatureHashAlgorithmOther; + + const CSSM_OID* alg_oid = &sig_algorithm->algorithm; + if (CSSMOIDEqual(alg_oid, &CSSMOID_MD2WithRSA)) + return kSignatureHashAlgorithmMd2; + if (CSSMOIDEqual(alg_oid, &CSSMOID_MD4WithRSA)) + return kSignatureHashAlgorithmMd4; + if (CSSMOIDEqual(alg_oid, &CSSMOID_MD5WithRSA)) + return kSignatureHashAlgorithmMd5; + if (CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithRSA) || + CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithRSA_OIW) || + CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA) || + CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_CMS) || + CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_JDK) || + CSSMOIDEqual(alg_oid, &CSSMOID_ECDSA_WithSHA1)) { + return kSignatureHashAlgorithmSha1; + } + + return kSignatureHashAlgorithmOther; +} + // static bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { x509_util::CSSMCachedCertificate cached_cert; diff --git a/chromium/net/cert/x509_certificate_net_log_param.h b/chromium/net/cert/x509_certificate_net_log_param.h index 01b46f95b15..a6721ab4782 100644 --- a/chromium/net/cert/x509_certificate_net_log_param.h +++ b/chromium/net/cert/x509_certificate_net_log_param.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NET_BASE_X509_CERT_NET_LOG_PARAM_H_ -#define NET_BASE_X509_CERT_NET_LOG_PARAM_H_ +#ifndef NET_CERT_X509_CERTIFICATE_NET_LOG_PARAM_H_ +#define NET_CERT_X509_CERTIFICATE_NET_LOG_PARAM_H_ #include <memory> @@ -23,4 +23,4 @@ std::unique_ptr<base::Value> NetLogX509CertificateCallback( } // namespace net -#endif // NET_BASE_X509_CERT_NET_LOG_PARAM_H_ +#endif // NET_CERT_X509_CERTIFICATE_NET_LOG_PARAM_H_ diff --git a/chromium/net/cert/x509_certificate_nss.cc b/chromium/net/cert/x509_certificate_nss.cc index abb6f20462e..2f2f9772662 100644 --- a/chromium/net/cert/x509_certificate_nss.cc +++ b/chromium/net/cert/x509_certificate_nss.cc @@ -36,31 +36,7 @@ void X509Certificate::Initialize() { serial_number_ = x509_util::ParseSerialNumber(cert_handle_); } -// static -scoped_refptr<X509Certificate> X509Certificate::CreateFromBytesWithNickname( - const char* data, - size_t length, - const char* nickname) { - OSCertHandle cert_handle = CreateOSCertHandleFromBytesWithNickname(data, - length, - nickname); - if (!cert_handle) - return NULL; - - scoped_refptr<X509Certificate> cert = - CreateFromHandle(cert_handle, OSCertHandles()); - FreeOSCertHandle(cert_handle); - - if (nickname) - cert->default_nickname_ = nickname; - - return cert; -} - std::string X509Certificate::GetDefaultNickname(CertType type) const { - if (!default_nickname_.empty()) - return default_nickname_; - std::string result; if (type == USER_CERT && cert_handle_->slot) { // Find the private key for this certificate and see if it has a @@ -263,6 +239,28 @@ void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, } // static +X509Certificate::SignatureHashAlgorithm +X509Certificate::GetSignatureHashAlgorithm(OSCertHandle cert_handle) { + SECAlgorithmID& signature = cert_handle->signature; + SECOidTag oid_tag = SECOID_FindOIDTag(&signature.algorithm); + switch (oid_tag) { + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + return kSignatureHashAlgorithmMd5; + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + return kSignatureHashAlgorithmMd2; + case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: + return kSignatureHashAlgorithmMd4; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: + case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: + return kSignatureHashAlgorithmSha1; + default: + return kSignatureHashAlgorithmOther; + } +} + +// static bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) { crypto::ScopedSECKEYPublicKey public_key(CERT_ExtractPublicKey(cert_handle)); if (!public_key.get()) diff --git a/chromium/net/cert/x509_certificate_openssl.cc b/chromium/net/cert/x509_certificate_openssl.cc index 30d9598a50a..730eef0d6ac 100644 --- a/chromium/net/cert/x509_certificate_openssl.cc +++ b/chromium/net/cert/x509_certificate_openssl.cc @@ -377,6 +377,24 @@ void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, } } +// static +X509Certificate::SignatureHashAlgorithm +X509Certificate::GetSignatureHashAlgorithm(OSCertHandle cert_handle) { + int sig_alg = OBJ_obj2nid(cert_handle->sig_alg->algorithm); + if (sig_alg == NID_md2WithRSAEncryption) + return kSignatureHashAlgorithmMd2; + if (sig_alg == NID_md4WithRSAEncryption) + return kSignatureHashAlgorithmMd4; + if (sig_alg == NID_md5WithRSAEncryption || sig_alg == NID_md5WithRSA) + return kSignatureHashAlgorithmMd5; + if (sig_alg == NID_sha1WithRSAEncryption || sig_alg == NID_dsaWithSHA || + sig_alg == NID_dsaWithSHA1 || sig_alg == NID_dsaWithSHA1_2 || + sig_alg == NID_sha1WithRSA || sig_alg == NID_ecdsa_with_SHA1) { + return kSignatureHashAlgorithmSha1; + } + return kSignatureHashAlgorithmOther; +} + bool X509Certificate::IsIssuedByEncoded( const std::vector<std::string>& valid_issuers) { if (valid_issuers.empty()) diff --git a/chromium/net/cert/x509_certificate_win.cc b/chromium/net/cert/x509_certificate_win.cc index c67011e06b9..ef3d040e5df 100644 --- a/chromium/net/cert/x509_certificate_win.cc +++ b/chromium/net/cert/x509_certificate_win.cc @@ -421,6 +421,33 @@ void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, } } +X509Certificate::SignatureHashAlgorithm +X509Certificate::GetSignatureHashAlgorithm(OSCertHandle cert_handle) { + const char* algorithm = cert_handle->pCertInfo->SignatureAlgorithm.pszObjId; + if (strcmp(algorithm, szOID_RSA_MD5RSA) == 0) { + // md5WithRSAEncryption: 1.2.840.113549.1.1.4 + return kSignatureHashAlgorithmMd5; + } + if (strcmp(algorithm, szOID_RSA_MD2RSA) == 0) { + // md2WithRSAEncryption: 1.2.840.113549.1.1.2 + return kSignatureHashAlgorithmMd2; + } + if (strcmp(algorithm, szOID_RSA_MD4RSA) == 0) { + // md4WithRSAEncryption: 1.2.840.113549.1.1.3 + return kSignatureHashAlgorithmMd4; + } + if (strcmp(algorithm, szOID_RSA_SHA1RSA) == 0 || + strcmp(algorithm, szOID_X957_SHA1DSA) == 0 || + strcmp(algorithm, szOID_ECDSA_SHA1) == 0) { + // sha1WithRSAEncryption: 1.2.840.113549.1.1.5 + // id-dsa-with-sha1: 1.2.840.10040.4.3 + // ecdsa-with-SHA1: 1.2.840.10045.4.1 + return kSignatureHashAlgorithmSha1; + } + + return kSignatureHashAlgorithmOther; +} + bool X509Certificate::IsIssuedByEncoded( const std::vector<std::string>& valid_issuers) { diff --git a/chromium/net/cert/x509_util.cc b/chromium/net/cert/x509_util.cc index 35913c19d2b..a5d583d0eb1 100644 --- a/chromium/net/cert/x509_util.cc +++ b/chromium/net/cert/x509_util.cc @@ -112,7 +112,7 @@ bool CreateKeyAndSelfSignedCert(const std::string& subject, not_valid_after, der_cert); if (success) - key->reset(new_key.release()); + *key = std::move(new_key); return success; } diff --git a/chromium/net/cert/x509_util.h b/chromium/net/cert/x509_util.h index 07f4e21b1d3..e29219d3eca 100644 --- a/chromium/net/cert/x509_util.h +++ b/chromium/net/cert/x509_util.h @@ -17,7 +17,6 @@ #include "net/base/net_export.h" namespace crypto { -class ECPrivateKey; class RSAPrivateKey; } |