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 23namespace net { 24 25namespace { 26 27// Maps X509_STORE_CTX_get_error() return values to our cert status flags. 28CertStatus 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. 93void sk_X509_free_fn(STACK_OF(X509)* st) { 94 sk_X509_free(st); 95} 96 97void 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 130void 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 158CertVerifyProcOpenSSL::CertVerifyProcOpenSSL() {} 159 160CertVerifyProcOpenSSL::~CertVerifyProcOpenSSL() {} 161 162bool CertVerifyProcOpenSSL::SupportsAdditionalTrustAnchors() const { 163 return false; 164} 165 166int 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->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; 177 178 crypto::ScopedOpenSSL<X509_STORE_CTX, X509_STORE_CTX_free> ctx( 179 X509_STORE_CTX_new()); 180 181 crypto::ScopedOpenSSL<STACK_OF(X509), sk_X509_free_fn> intermediates( 182 sk_X509_new_null()); 183 if (!intermediates.get()) 184 return ERR_OUT_OF_MEMORY; 185 186 const X509Certificate::OSCertHandles& os_intermediates = 187 cert->GetIntermediateCertificates(); 188 for (X509Certificate::OSCertHandles::const_iterator it = 189 os_intermediates.begin(); it != os_intermediates.end(); ++it) { 190 if (!sk_X509_push(intermediates.get(), *it)) 191 return ERR_OUT_OF_MEMORY; 192 } 193 if (X509_STORE_CTX_init(ctx.get(), X509Certificate::cert_store(), 194 cert->os_cert_handle(), intermediates.get()) != 1) { 195 NOTREACHED(); 196 return ERR_FAILED; 197 } 198 199 if (X509_verify_cert(ctx.get()) != 1) { 200 int x509_error = X509_STORE_CTX_get_error(ctx.get()); 201 CertStatus cert_status = MapCertErrorToCertStatus(x509_error); 202 LOG(ERROR) << "X509 Verification error " 203 << X509_verify_cert_error_string(x509_error) 204 << " : " << x509_error 205 << " : " << X509_STORE_CTX_get_error_depth(ctx.get()) 206 << " : " << cert_status; 207 verify_result->cert_status |= cert_status; 208 } 209 210 GetCertChainInfo(ctx.get(), verify_result); 211 AppendPublicKeyHashes(ctx.get(), &verify_result->public_key_hashes); 212 if (IsCertStatusError(verify_result->cert_status)) 213 return MapCertStatusToNetError(verify_result->cert_status); 214 215 // Currently we only ues OpenSSL's default root CA paths, so treat all 216 // correctly verified certs as being from a known root. 217 // TODO(joth): if the motivations described in 218 // http://src.chromium.org/viewvc/chrome?view=rev&revision=80778 become an 219 // issue on OpenSSL builds, we will need to embed a hardcoded list of well 220 // known root CAs, as per the _mac and _win versions. 221 verify_result->is_issued_by_known_root = true; 222 223 return OK; 224} 225 226} // namespace net 227