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/sha2.h" 16 #include "net/base/net_errors.h" 17 #include "net/cert/asn1_util.h" 18 #include "net/cert/cert_status_flags.h" 19 #include "net/cert/cert_verifier.h" 20 #include "net/cert/cert_verify_result.h" 21 #include "net/cert/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 } else if (sig_alg == NID_md4WithRSAEncryption) { 117 verify_result->has_md4 = true; 118 } else if (sig_alg == NID_md5WithRSAEncryption) { 119 verify_result->has_md5 = true; 120 } 121 } 122 } 123 124 if (verified_cert) { 125 verify_result->verified_cert = 126 X509Certificate::CreateFromHandle(verified_cert, verified_chain); 127 } 128 } 129 130 void AppendPublicKeyHashes(X509_STORE_CTX* store_ctx, 131 HashValueVector* hashes) { 132 STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(store_ctx); 133 for (int i = 0; i < sk_X509_num(chain); ++i) { 134 X509* cert = sk_X509_value(chain, i); 135 136 std::string der_data; 137 if (!X509Certificate::GetDEREncoded(cert, &der_data)) 138 continue; 139 140 base::StringPiece der_bytes(der_data); 141 base::StringPiece spki_bytes; 142 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes)) 143 continue; 144 145 HashValue sha1(HASH_VALUE_SHA1); 146 base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), 147 spki_bytes.size(), sha1.data()); 148 hashes->push_back(sha1); 149 150 HashValue sha256(HASH_VALUE_SHA256); 151 crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length); 152 hashes->push_back(sha256); 153 } 154 } 155 156 } // namespace 157 158 CertVerifyProcOpenSSL::CertVerifyProcOpenSSL() {} 159 160 CertVerifyProcOpenSSL::~CertVerifyProcOpenSSL() {} 161 162 bool CertVerifyProcOpenSSL::SupportsAdditionalTrustAnchors() const { 163 return false; 164 } 165 166 int CertVerifyProcOpenSSL::VerifyInternal( 167 X509Certificate* cert, 168 const std::string& hostname, 169 int flags, 170 CRLSet* crl_set, 171 const CertificateList& additional_trust_anchors, 172 CertVerifyResult* verify_result) { 173 crypto::EnsureOpenSSLInit(); 174 175 if (!cert->VerifyNameMatch(hostname, 176 &verify_result->common_name_fallback_used)) { 177 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; 178 } 179 180 crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx( 181 X509_STORE_CTX_new()); 182 183 crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates( 184 sk_X509_new_null()); 185 if (!intermediates.get()) 186 return ERR_OUT_OF_MEMORY; 187 188 const X509Certificate::OSCertHandles& os_intermediates = 189 cert->GetIntermediateCertificates(); 190 for (X509Certificate::OSCertHandles::const_iterator it = 191 os_intermediates.begin(); it != os_intermediates.end(); ++it) { 192 if (!sk_X509_push(intermediates.get(), *it)) 193 return ERR_OUT_OF_MEMORY; 194 } 195 if (X509_STORE_CTX_init(ctx.get(), X509Certificate::cert_store(), 196 cert->os_cert_handle(), intermediates.get()) != 1) { 197 NOTREACHED(); 198 return ERR_FAILED; 199 } 200 201 if (X509_verify_cert(ctx.get()) != 1) { 202 int x509_error = X509_STORE_CTX_get_error(ctx.get()); 203 CertStatus cert_status = MapCertErrorToCertStatus(x509_error); 204 LOG(ERROR) << "X509 Verification error " 205 << X509_verify_cert_error_string(x509_error) 206 << " : " << x509_error 207 << " : " << X509_STORE_CTX_get_error_depth(ctx.get()) 208 << " : " << cert_status; 209 verify_result->cert_status |= cert_status; 210 } 211 212 GetCertChainInfo(ctx.get(), verify_result); 213 AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes); 214 if (IsCertStatusError(verify_result->cert_status)) 215 return MapCertStatusToNetError(verify_result->cert_status); 216 217 // Currently we only ues OpenSSL's default root CA paths, so treat all 218 // correctly verified certs as being from a known root. 219 // TODO(joth): if the motivations described in 220 // http://src.chromium.org/viewvc/chrome?view=rev&revision=80778 become an 221 // issue on OpenSSL builds, we will need to embed a hardcoded list of well 222 // known root CAs, as per the _mac and _win versions. 223 verify_result->is_issued_by_known_root = true; 224 225 return OK; 226 } 227 228 } // namespace net 229