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 248