| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/cert/cert_verify_proc_openssl.h" | |
| 6 | |
| 7 #include <openssl/x509v3.h> | |
| 8 | |
| 9 #include <string> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/logging.h" | |
| 13 #include "base/sha1.h" | |
| 14 #include "crypto/openssl_util.h" | |
| 15 #include "crypto/scoped_openssl_types.h" | |
| 16 #include "crypto/sha2.h" | |
| 17 #include "net/base/net_errors.h" | |
| 18 #include "net/cert/asn1_util.h" | |
| 19 #include "net/cert/cert_status_flags.h" | |
| 20 #include "net/cert/cert_verifier.h" | |
| 21 #include "net/cert/cert_verify_result.h" | |
| 22 #include "net/cert/test_root_certs.h" | |
| 23 #include "net/cert/x509_certificate.h" | |
| 24 | |
| 25 namespace net { | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 // Maps X509_STORE_CTX_get_error() return values to our cert status flags. | |
| 30 CertStatus MapCertErrorToCertStatus(int err) { | |
| 31 switch (err) { | |
| 32 case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: | |
| 33 return CERT_STATUS_COMMON_NAME_INVALID; | |
| 34 case X509_V_ERR_CERT_NOT_YET_VALID: | |
| 35 case X509_V_ERR_CERT_HAS_EXPIRED: | |
| 36 case X509_V_ERR_CRL_NOT_YET_VALID: | |
| 37 case X509_V_ERR_CRL_HAS_EXPIRED: | |
| 38 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: | |
| 39 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: | |
| 40 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: | |
| 41 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: | |
| 42 return CERT_STATUS_DATE_INVALID; | |
| 43 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: | |
| 44 case X509_V_ERR_UNABLE_TO_GET_CRL: | |
| 45 case X509_V_ERR_INVALID_CA: | |
| 46 case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: | |
| 47 case X509_V_ERR_INVALID_NON_CA: | |
| 48 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: | |
| 49 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: | |
| 50 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: | |
| 51 return CERT_STATUS_AUTHORITY_INVALID; | |
| 52 #if 0 | |
| 53 // TODO(bulach): what should we map to these status? | |
| 54 return CERT_STATUS_NO_REVOCATION_MECHANISM; | |
| 55 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; | |
| 56 #endif | |
| 57 case X509_V_ERR_CERT_REVOKED: | |
| 58 return CERT_STATUS_REVOKED; | |
| 59 // All these status are mapped to CERT_STATUS_INVALID. | |
| 60 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: | |
| 61 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: | |
| 62 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: | |
| 63 case X509_V_ERR_CERT_SIGNATURE_FAILURE: | |
| 64 case X509_V_ERR_CRL_SIGNATURE_FAILURE: | |
| 65 case X509_V_ERR_OUT_OF_MEM: | |
| 66 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: | |
| 67 case X509_V_ERR_CERT_CHAIN_TOO_LONG: | |
| 68 case X509_V_ERR_PATH_LENGTH_EXCEEDED: | |
| 69 case X509_V_ERR_INVALID_PURPOSE: | |
| 70 case X509_V_ERR_CERT_UNTRUSTED: | |
| 71 case X509_V_ERR_CERT_REJECTED: | |
| 72 case X509_V_ERR_AKID_SKID_MISMATCH: | |
| 73 case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: | |
| 74 case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: | |
| 75 case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: | |
| 76 case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: | |
| 77 case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: | |
| 78 case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: | |
| 79 case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: | |
| 80 case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: | |
| 81 case X509_V_ERR_INVALID_EXTENSION: | |
| 82 case X509_V_ERR_INVALID_POLICY_EXTENSION: | |
| 83 case X509_V_ERR_NO_EXPLICIT_POLICY: | |
| 84 case X509_V_ERR_UNNESTED_RESOURCE: | |
| 85 case X509_V_ERR_APPLICATION_VERIFICATION: | |
| 86 return CERT_STATUS_INVALID; | |
| 87 default: | |
| 88 NOTREACHED() << "Invalid X509 err " << err; | |
| 89 return CERT_STATUS_INVALID; | |
| 90 } | |
| 91 } | |
| 92 | |
| 93 // sk_X509_free is a function-style macro, so can't be used as a template | |
| 94 // param directly. | |
| 95 void sk_X509_free_fn(STACK_OF(X509)* st) { | |
| 96 sk_X509_free(st); | |
| 97 } | |
| 98 | |
| 99 void GetCertChainInfo(X509_STORE_CTX* store_ctx, | |
| 100 CertVerifyResult* verify_result) { | |
| 101 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); | |
| 102 X509* verified_cert = NULL; | |
| 103 std::vector<X509*> verified_chain; | |
| 104 for (size_t i = 0; i < sk_X509_num(chain); ++i) { | |
| 105 X509* cert = sk_X509_value(chain, i); | |
| 106 if (i == 0) { | |
| 107 verified_cert = cert; | |
| 108 } else { | |
| 109 verified_chain.push_back(cert); | |
| 110 } | |
| 111 | |
| 112 // Only check the algorithm status for certificates that are not in the | |
| 113 // trust store. | |
| 114 if (i < static_cast<size_t>(store_ctx->last_untrusted)) { | |
| 115 int sig_alg = OBJ_obj2nid(cert->sig_alg->algorithm); | |
| 116 if (sig_alg == NID_md2WithRSAEncryption) { | |
| 117 verify_result->has_md2 = true; | |
| 118 } else if (sig_alg == NID_md4WithRSAEncryption) { | |
| 119 verify_result->has_md4 = true; | |
| 120 } else if (sig_alg == NID_md5WithRSAEncryption || | |
| 121 sig_alg == NID_md5WithRSA) { | |
| 122 verify_result->has_md5 = true; | |
| 123 } else if (sig_alg == NID_sha1WithRSAEncryption || | |
| 124 sig_alg == NID_dsaWithSHA || sig_alg == NID_dsaWithSHA1 || | |
| 125 sig_alg == NID_dsaWithSHA1_2 || sig_alg == NID_sha1WithRSA || | |
| 126 sig_alg == NID_ecdsa_with_SHA1) { | |
| 127 verify_result->has_sha1 = true; | |
| 128 } | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 // Set verify_result->verified_cert and | |
| 133 // verify_result->is_issued_by_known_root. | |
| 134 if (verified_cert) { | |
| 135 verify_result->verified_cert = | |
| 136 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | |
| 137 | |
| 138 // For OpenSSL builds, only certificates used for unit tests are treated | |
| 139 // as not issued by known roots. The only way to determine whether a | |
| 140 // certificate is issued by a known root using OpenSSL is to examine | |
| 141 // distro-and-release specific hardcoded lists. | |
| 142 verify_result->is_issued_by_known_root = true; | |
| 143 if (TestRootCerts::HasInstance()) { | |
| 144 X509* root = NULL; | |
| 145 if (verified_chain.empty()) { | |
| 146 root = verified_cert; | |
| 147 } else { | |
| 148 root = verified_chain.back(); | |
| 149 } | |
| 150 TestRootCerts* root_certs = TestRootCerts::GetInstance(); | |
| 151 if (root_certs->Contains(root)) | |
| 152 verify_result->is_issued_by_known_root = false; | |
| 153 } | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx, | |
| 158 HashValueVector* hashes) { | |
| 159 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); | |
| 160 for (size_t i = 0; i < sk_X509_num(chain); ++i) { | |
| 161 X509* cert = sk_X509_value(chain, i); | |
| 162 | |
| 163 std::string der_data; | |
| 164 if (!X509Certificate::GetDEREncoded(cert, &der_data)) | |
| 165 continue; | |
| 166 | |
| 167 base::StringPiece der_bytes(der_data); | |
| 168 base::StringPiece spki_bytes; | |
| 169 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) | |
| 170 continue; | |
| 171 | |
| 172 HashValue sha1(HASH_VALUE_SHA1); | |
| 173 base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), | |
| 174 spki_bytes.size(), sha1.data()); | |
| 175 hashes->push_back(sha1); | |
| 176 | |
| 177 HashValue sha256(HASH_VALUE_SHA256); | |
| 178 crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length); | |
| 179 hashes->push_back(sha256); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 } // namespace | |
| 184 | |
| 185 CertVerifyProcOpenSSL::CertVerifyProcOpenSSL() {} | |
| 186 | |
| 187 CertVerifyProcOpenSSL::~CertVerifyProcOpenSSL() {} | |
| 188 | |
| 189 bool CertVerifyProcOpenSSL::SupportsAdditionalTrustAnchors() const { | |
| 190 return false; | |
| 191 } | |
| 192 | |
| 193 int CertVerifyProcOpenSSL::VerifyInternal( | |
| 194 X509Certificate* cert, | |
| 195 const std::string& hostname, | |
| 196 int flags, | |
| 197 CRLSet* crl_set, | |
| 198 const CertificateList& additional_trust_anchors, | |
| 199 CertVerifyResult* verify_result) { | |
| 200 crypto::EnsureOpenSSLInit(); | |
| 201 | |
| 202 if (!cert->VerifyNameMatch(hostname, | |
| 203 &verify_result->common_name_fallback_used)) { | |
| 204 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | |
| 205 } | |
| 206 | |
| 207 crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free>::Type ctx( | |
| 208 X509_STORE_CTX_new()); | |
| 209 | |
| 210 crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn>::Type intermediates( | |
| 211 sk_X509_new_null()); | |
| 212 if (!intermediates.get()) | |
| 213 return ERR_OUT_OF_MEMORY; | |
| 214 | |
| 215 const X509Certificate::OSCertHandles& os_intermediates = | |
| 216 cert->GetIntermediateCertificates(); | |
| 217 for (X509Certificate::OSCertHandles::const_iterator it = | |
| 218 os_intermediates.begin(); it != os_intermediates.end(); ++it) { | |
| 219 if (!sk_X509_push(intermediates.get(), *it)) | |
| 220 return ERR_OUT_OF_MEMORY; | |
| 221 } | |
| 222 if (X509_STORE_CTX_init(ctx.get(), X509Certificate::cert_store(), | |
| 223 cert->os_cert_handle(), intermediates.get()) != 1) { | |
| 224 NOTREACHED(); | |
| 225 return ERR_FAILED; | |
| 226 } | |
| 227 | |
| 228 if (X509_verify_cert(ctx.get()) != 1) { | |
| 229 int x509_error = X509_STORE_CTX_get_error(ctx.get()); | |
| 230 CertStatus cert_status = MapCertErrorToCertStatus(x509_error); | |
| 231 LOG(ERROR) << "X509 Verification error " | |
| 232 << X509_verify_cert_error_string(x509_error) | |
| 233 << " : " << x509_error | |
| 234 << " : " << X509_STORE_CTX_get_error_depth(ctx.get()) | |
| 235 << " : " << cert_status; | |
| 236 verify_result->cert_status |= cert_status; | |
| 237 } | |
| 238 | |
| 239 GetCertChainInfo(ctx.get(), verify_result); | |
| 240 AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes); | |
| 241 if (IsCertStatusError(verify_result->cert_status)) | |
| 242 return MapCertStatusToNetError(verify_result->cert_status); | |
| 243 | |
| 244 return OK; | |
| 245 } | |
| 246 | |
| 247 } // namespace net | |
| OLD | NEW |