| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/cert/cert_verify_proc_android.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "base/sha1.h" |
| #include "base/strings/string_piece.h" |
| #include "crypto/sha2.h" |
| #include "net/android/cert_verify_result_android.h" |
| #include "net/android/network_library.h" |
| #include "net/base/net_errors.h" |
| #include "net/cert/asn1_util.h" |
| #include "net/cert/cert_status_flags.h" |
| #include "net/cert/cert_verify_result.h" |
| #include "net/cert/x509_certificate.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| // Returns true if the certificate verification call was successful (regardless |
| // of its result), i.e. if |verify_result| was set. Otherwise returns false. |
| bool VerifyFromAndroidTrustManager(const std::vector<std::string>& cert_bytes, |
| const std::string& hostname, |
| CertVerifyResult* verify_result) { |
| android::CertVerifyStatusAndroid status; |
| std::vector<std::string> verified_chain; |
| |
| // TODO(joth): Fetch the authentication type from SSL rather than hardcode. |
| android::VerifyX509CertChain(cert_bytes, "RSA", hostname, |
| &status, &verify_result->is_issued_by_known_root, |
| &verified_chain); |
| switch (status) { |
| case android::VERIFY_FAILED: |
| return false; |
| case android::VERIFY_OK: |
| break; |
| case android::VERIFY_NO_TRUSTED_ROOT: |
| verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; |
| break; |
| case android::VERIFY_EXPIRED: |
| case android::VERIFY_NOT_YET_VALID: |
| verify_result->cert_status |= CERT_STATUS_DATE_INVALID; |
| break; |
| case android::VERIFY_UNABLE_TO_PARSE: |
| verify_result->cert_status |= CERT_STATUS_INVALID; |
| break; |
| case android::VERIFY_INCORRECT_KEY_USAGE: |
| verify_result->cert_status |= CERT_STATUS_INVALID; |
| break; |
| default: |
| NOTREACHED(); |
| verify_result->cert_status |= CERT_STATUS_INVALID; |
| break; |
| } |
| |
| // Save the verified chain. |
| if (!verified_chain.empty()) { |
| std::vector<base::StringPiece> verified_chain_pieces(verified_chain.size()); |
| for (size_t i = 0; i < verified_chain.size(); i++) { |
| verified_chain_pieces[i] = base::StringPiece(verified_chain[i]); |
| } |
| scoped_refptr<X509Certificate> verified_cert = |
| X509Certificate::CreateFromDERCertChain(verified_chain_pieces); |
| if (verified_cert) |
| verify_result->verified_cert = verified_cert; |
| } |
| |
| // Extract the public key hashes. |
| for (size_t i = 0; i < verified_chain.size(); i++) { |
| base::StringPiece spki_bytes; |
| if (!asn1::ExtractSPKIFromDERCert(verified_chain[i], &spki_bytes)) |
| continue; |
| |
| HashValue sha1(HASH_VALUE_SHA1); |
| base::SHA1HashBytes(reinterpret_cast<const uint8*>(spki_bytes.data()), |
| spki_bytes.size(), sha1.data()); |
| verify_result->public_key_hashes.push_back(sha1); |
| |
| HashValue sha256(HASH_VALUE_SHA256); |
| crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length); |
| verify_result->public_key_hashes.push_back(sha256); |
| } |
| |
| return true; |
| } |
| |
| bool GetChainDEREncodedBytes(X509Certificate* cert, |
| std::vector<std::string>* chain_bytes) { |
| X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); |
| X509Certificate::OSCertHandles cert_handles = |
| cert->GetIntermediateCertificates(); |
| |
| // Make sure the peer's own cert is the first in the chain, if it's not |
| // already there. |
| if (cert_handles.empty() || cert_handles[0] != cert_handle) |
| cert_handles.insert(cert_handles.begin(), cert_handle); |
| |
| chain_bytes->reserve(cert_handles.size()); |
| for (X509Certificate::OSCertHandles::const_iterator it = |
| cert_handles.begin(); it != cert_handles.end(); ++it) { |
| std::string cert_bytes; |
| if(!X509Certificate::GetDEREncoded(*it, &cert_bytes)) |
| return false; |
| chain_bytes->push_back(cert_bytes); |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| CertVerifyProcAndroid::CertVerifyProcAndroid() {} |
| |
| CertVerifyProcAndroid::~CertVerifyProcAndroid() {} |
| |
| bool CertVerifyProcAndroid::SupportsAdditionalTrustAnchors() const { |
| return false; |
| } |
| |
| int CertVerifyProcAndroid::VerifyInternal( |
| X509Certificate* cert, |
| const std::string& hostname, |
| int flags, |
| CRLSet* crl_set, |
| const CertificateList& additional_trust_anchors, |
| CertVerifyResult* verify_result) { |
| if (!cert->VerifyNameMatch(hostname, |
| &verify_result->common_name_fallback_used)) { |
| verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| } |
| |
| std::vector<std::string> cert_bytes; |
| if (!GetChainDEREncodedBytes(cert, &cert_bytes)) |
| return ERR_CERT_INVALID; |
| if (!VerifyFromAndroidTrustManager(cert_bytes, hostname, verify_result)) { |
| NOTREACHED(); |
| return ERR_FAILED; |
| } |
| if (IsCertStatusError(verify_result->cert_status)) |
| return MapCertStatusToNetError(verify_result->cert_status); |
| |
| return OK; |
| } |
| |
| } // namespace net |