| 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/base/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/sha2.h" | |
| 16 #include "net/base/asn1_util.h" | |
| 17 #include "net/base/cert_status_flags.h" | |
| 18 #include "net/base/cert_verifier.h" | |
| 19 #include "net/base/cert_verify_result.h" | |
| 20 #include "net/base/net_errors.h" | |
| 21 #include "net/base/x509_certificate.h" | |
| 22 | |
| 23 namespace net { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 // Maps X509_STORE_CTX_get_error() return values to our cert status flags. | |
| 28 CertStatus MapCertErrorToCertStatus(int err) { | |
| 29 switch (err) { | |
| 30 case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: | |
| 31 return CERT_STATUS_COMMON_NAME_INVALID; | |
| 32 case X509_V_ERR_CERT_NOT_YET_VALID: | |
| 33 case X509_V_ERR_CERT_HAS_EXPIRED: | |
| 34 case X509_V_ERR_CRL_NOT_YET_VALID: | |
| 35 case X509_V_ERR_CRL_HAS_EXPIRED: | |
| 36 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: | |
| 37 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: | |
| 38 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: | |
| 39 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: | |
| 40 return CERT_STATUS_DATE_INVALID; | |
| 41 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: | |
| 42 case X509_V_ERR_UNABLE_TO_GET_CRL: | |
| 43 case X509_V_ERR_INVALID_CA: | |
| 44 case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: | |
| 45 case X509_V_ERR_INVALID_NON_CA: | |
| 46 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: | |
| 47 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: | |
| 48 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: | |
| 49 return CERT_STATUS_AUTHORITY_INVALID; | |
| 50 #if 0 | |
| 51 // TODO(bulach): what should we map to these status? | |
| 52 return CERT_STATUS_NO_REVOCATION_MECHANISM; | |
| 53 return CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; | |
| 54 #endif | |
| 55 case X509_V_ERR_CERT_REVOKED: | |
| 56 return CERT_STATUS_REVOKED; | |
| 57 // All these status are mapped to CERT_STATUS_INVALID. | |
| 58 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: | |
| 59 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: | |
| 60 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: | |
| 61 case X509_V_ERR_CERT_SIGNATURE_FAILURE: | |
| 62 case X509_V_ERR_CRL_SIGNATURE_FAILURE: | |
| 63 case X509_V_ERR_OUT_OF_MEM: | |
| 64 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: | |
| 65 case X509_V_ERR_CERT_CHAIN_TOO_LONG: | |
| 66 case X509_V_ERR_PATH_LENGTH_EXCEEDED: | |
| 67 case X509_V_ERR_INVALID_PURPOSE: | |
| 68 case X509_V_ERR_CERT_UNTRUSTED: | |
| 69 case X509_V_ERR_CERT_REJECTED: | |
| 70 case X509_V_ERR_AKID_SKID_MISMATCH: | |
| 71 case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: | |
| 72 case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: | |
| 73 case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: | |
| 74 case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: | |
| 75 case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: | |
| 76 case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: | |
| 77 case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: | |
| 78 case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: | |
| 79 case X509_V_ERR_INVALID_EXTENSION: | |
| 80 case X509_V_ERR_INVALID_POLICY_EXTENSION: | |
| 81 case X509_V_ERR_NO_EXPLICIT_POLICY: | |
| 82 case X509_V_ERR_UNNESTED_RESOURCE: | |
| 83 case X509_V_ERR_APPLICATION_VERIFICATION: | |
| 84 return CERT_STATUS_INVALID; | |
| 85 default: | |
| 86 NOTREACHED() << "Invalid X509 err " << err; | |
| 87 return CERT_STATUS_INVALID; | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 // sk_X509_free is a function-style macro, so can't be used as a template | |
| 92 // param directly. | |
| 93 void sk_X509_free_fn(STACK_OF(X509)* st) { | |
| 94 sk_X509_free(st); | |
| 95 } | |
| 96 | |
| 97 void GetCertChainInfo(X509_STORE_CTX* store_ctx, | |
| 98 CertVerifyResult* verify_result) { | |
| 99 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); | |
| 100 X509* verified_cert = NULL; | |
| 101 std::vector<X509*> verified_chain; | |
| 102 for (int i = 0; i < sk_X509_num(chain); ++i) { | |
| 103 X509* cert = sk_X509_value(chain, i); | |
| 104 if (i == 0) { | |
| 105 verified_cert = cert; | |
| 106 } else { | |
| 107 verified_chain.push_back(cert); | |
| 108 } | |
| 109 | |
| 110 // Only check the algorithm status for certificates that are not in the | |
| 111 // trust store. | |
| 112 if (i < store_ctx->last_untrusted) { | |
| 113 int sig_alg = OBJ_obj2nid(cert->sig_alg->algorithm); | |
| 114 if (sig_alg == NID_md2WithRSAEncryption) { | |
| 115 verify_result->has_md2 = true; | |
| 116 if (i != 0) | |
| 117 verify_result->has_md2_ca = true; | |
| 118 } else if (sig_alg == NID_md4WithRSAEncryption) { | |
| 119 verify_result->has_md4 = true; | |
| 120 } else if (sig_alg == NID_md5WithRSAEncryption) { | |
| 121 verify_result->has_md5 = true; | |
| 122 if (i != 0) | |
| 123 verify_result->has_md5_ca = true; | |
| 124 } | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 if (verified_cert) { | |
| 129 verify_result->verified_cert = | |
| 130 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx, | |
| 135 HashValueVector* hashes) { | |
| 136 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); | |
| 137 for (int i = 0; i < sk_X509_num(chain); ++i) { | |
| 138 X509* cert = sk_X509_value(chain, i); | |
| 139 | |
| 140 std::string der_data; | |
| 141 if (!X509Certificate::GetDEREncoded(cert, &der_data)) | |
| 142 continue; | |
| 143 | |
| 144 base::StringPiece der_bytes(der_data); | |
| 145 base::StringPiece spki_bytes; | |
| 146 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) | |
| 147 continue; | |
| 148 | |
| 149 HashValue sha1(HASH_VALUE_SHA1); | |
| 150 base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), | |
| 151 spki_bytes.size(), sha1.data()); | |
| 152 hashes->push_back(sha1); | |
| 153 | |
| 154 HashValue sha256(HASH_VALUE_SHA256); | |
| 155 crypto::SHA256HashString(spki_bytes, sha1.data(), crypto::kSHA256Length); | |
| 156 hashes->push_back(sha256); | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 } // namespace | |
| 161 | |
| 162 CertVerifyProcOpenSSL::CertVerifyProcOpenSSL() {} | |
| 163 | |
| 164 CertVerifyProcOpenSSL::~CertVerifyProcOpenSSL() {} | |
| 165 | |
| 166 bool CertVerifyProcOpenSSL::SupportsAdditionalTrustAnchors() const { | |
| 167 return false; | |
| 168 } | |
| 169 | |
| 170 int CertVerifyProcOpenSSL::VerifyInternal( | |
| 171 X509Certificate* cert, | |
| 172 const std::string& hostname, | |
| 173 int flags, | |
| 174 CRLSet* crl_set, | |
| 175 const CertificateList& additional_trust_anchors, | |
| 176 CertVerifyResult* verify_result) { | |
| 177 crypto::EnsureOpenSSLInit(); | |
| 178 | |
| 179 if (!cert->VerifyNameMatch(hostname)) | |
| 180 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | |
| 181 | |
| 182 crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx( | |
| 183 X509_STORE_CTX_new()); | |
| 184 | |
| 185 crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates( | |
| 186 sk_X509_new_null()); | |
| 187 if (!intermediates.get()) | |
| 188 return ERR_OUT_OF_MEMORY; | |
| 189 | |
| 190 const X509Certificate::OSCertHandles& os_intermediates = | |
| 191 cert->GetIntermediateCertificates(); | |
| 192 for (X509Certificate::OSCertHandles::const_iterator it = | |
| 193 os_intermediates.begin(); it != os_intermediates.end(); ++it) { | |
| 194 if (!sk_X509_push(intermediates.get(), *it)) | |
| 195 return ERR_OUT_OF_MEMORY; | |
| 196 } | |
| 197 if (X509_STORE_CTX_init(ctx.get(), X509Certificate::cert_store(), | |
| 198 cert->os_cert_handle(), intermediates.get()) != 1) { | |
| 199 NOTREACHED(); | |
| 200 return ERR_FAILED; | |
| 201 } | |
| 202 | |
| 203 if (X509_verify_cert(ctx.get()) != 1) { | |
| 204 int x509_error = X509_STORE_CTX_get_error(ctx.get()); | |
| 205 CertStatus cert_status = MapCertErrorToCertStatus(x509_error); | |
| 206 LOG(ERROR) << "X509 Verification error " | |
| 207 << X509_verify_cert_error_string(x509_error) | |
| 208 << " : " << x509_error | |
| 209 << " : " << X509_STORE_CTX_get_error_depth(ctx.get()) | |
| 210 << " : " << cert_status; | |
| 211 verify_result->cert_status |= cert_status; | |
| 212 } | |
| 213 | |
| 214 GetCertChainInfo(ctx.get(), verify_result); | |
| 215 AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes); | |
| 216 if (IsCertStatusError(verify_result->cert_status)) | |
| 217 return MapCertStatusToNetError(verify_result->cert_status); | |
| 218 | |
| 219 // Currently we only ues OpenSSL's default root CA paths, so treat all | |
| 220 // correctly verified certs as being from a known root. | |
| 221 // TODO(joth): if the motivations described in | |
| 222 // http://src.chromium.org/viewvc/chrome?view=rev&revision=80778 become an | |
| 223 // issue on OpenSSL builds, we will need to embed a hardcoded list of well | |
| 224 // known root CAs, as per the _mac and _win versions. | |
| 225 verify_result->is_issued_by_known_root = true; | |
| 226 | |
| 227 return OK; | |
| 228 } | |
| 229 | |
| 230 } // namespace net | |
| OLD | NEW |