Index: net/cert/x509_util_win.cc |
diff --git a/net/cert/x509_util_win.cc b/net/cert/x509_util_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4b1f74df4ced351fd92308eacc991aecbb98c11b |
--- /dev/null |
+++ b/net/cert/x509_util_win.cc |
@@ -0,0 +1,149 @@ |
+// Copyright 2017 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/x509_util_win.h" |
+ |
+#include "crypto/scoped_capi_types.h" |
+#include "crypto/sha2.h" |
+#include "net/cert/x509_certificate.h" |
+#include "net/net_features.h" |
+#include "third_party/boringssl/src/include/openssl/pool.h" |
+ |
+namespace net { |
+ |
+namespace x509_util { |
+ |
+namespace { |
+ |
+using ScopedHCERTSTORE = crypto::ScopedCAPIHandle< |
+ HCERTSTORE, |
+ crypto::CAPIDestroyerWithFlags<HCERTSTORE, CertCloseStore, 0>>; |
+ |
+} // namespace |
+ |
+scoped_refptr<X509Certificate> CreateX509CertificateFromCertContexts( |
+ PCCERT_CONTEXT os_cert, |
+ const std::vector<PCCERT_CONTEXT>& os_chain) { |
+#if BUILDFLAG(USE_BYTE_CERTS) |
+ if (!os_cert || !os_cert->pbCertEncoded || !os_cert->cbCertEncoded) |
+ return nullptr; |
+ bssl::UniquePtr<CRYPTO_BUFFER> cert_handle( |
+ X509Certificate::CreateOSCertHandleFromBytes( |
+ reinterpret_cast<const char*>(os_cert->pbCertEncoded), |
+ os_cert->cbCertEncoded)); |
+ if (!cert_handle) |
+ return nullptr; |
+ std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates; |
+ X509Certificate::OSCertHandles intermediates_raw; |
+ for (PCCERT_CONTEXT os_intermediate : os_chain) { |
+ if (!os_intermediate || !os_intermediate->pbCertEncoded || |
+ !os_intermediate->cbCertEncoded) |
+ return nullptr; |
+ bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle( |
+ X509Certificate::CreateOSCertHandleFromBytes( |
+ reinterpret_cast<const char*>(os_intermediate->pbCertEncoded), |
+ os_intermediate->cbCertEncoded)); |
+ if (!intermediate_cert_handle) |
+ return nullptr; |
+ intermediates_raw.push_back(intermediate_cert_handle.get()); |
+ intermediates.push_back(std::move(intermediate_cert_handle)); |
+ } |
+ scoped_refptr<X509Certificate> result( |
+ X509Certificate::CreateFromHandle(cert_handle.get(), intermediates_raw)); |
+ return result; |
+#else |
+ return X509Certificate::CreateFromHandle(os_cert, os_chain); |
+#endif |
+} |
+ |
+ScopedPCCERT_CONTEXT CreateCertContextWithChain(const X509Certificate* cert) { |
+ // Create an in-memory certificate store to hold the certificate and its |
+ // intermediate certificates. The store will be referenced in the returned |
+ // PCCERT_CONTEXT, and will not be freed until the PCCERT_CONTEXT is freed. |
+ ScopedHCERTSTORE store( |
+ CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, |
+ CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL)); |
+ if (!store.get()) |
+ return nullptr; |
+ |
+ PCCERT_CONTEXT primary_cert = nullptr; |
+ |
+#if BUILDFLAG(USE_BYTE_CERTS) |
+ BOOL ok = CertAddEncodedCertificateToStore( |
+ store.get(), X509_ASN_ENCODING, |
+ CRYPTO_BUFFER_data(cert->os_cert_handle()), |
+ base::checked_cast<DWORD>(CRYPTO_BUFFER_len(cert->os_cert_handle())), |
+ CERT_STORE_ADD_ALWAYS, &primary_cert); |
+ if (!ok || !primary_cert) |
+ return nullptr; |
+ ScopedPCCERT_CONTEXT scoped_primary_cert(primary_cert); |
+ |
+ for (X509Certificate::OSCertHandle intermediate : |
+ cert->GetIntermediateCertificates()) { |
+ ok = CertAddEncodedCertificateToStore( |
+ store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(intermediate), |
+ base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate)), |
+ CERT_STORE_ADD_ALWAYS, NULL); |
+ if (!ok) |
+ return nullptr; |
+ } |
+#else |
+ PCCERT_CONTEXT os_cert_handle = cert->os_cert_handle(); |
+ const std::vector<PCCERT_CONTEXT>& intermediate_ca_certs = |
+ cert->GetIntermediateCertificates(); |
+ |
+ // NOTE: This preserves all of the properties of |os_cert_handle| except |
+ // for CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID - the two |
+ // properties that hold access to already-opened private keys. If a handle |
+ // has already been unlocked (eg: PIN prompt), then the first time that the |
+ // identity is used for client auth, it may prompt the user again. |
+ BOOL ok = CertAddCertificateContextToStore( |
+ store.get(), os_cert_handle, CERT_STORE_ADD_ALWAYS, &primary_cert); |
+ if (!ok || !primary_cert) |
+ return nullptr; |
+ ScopedPCCERT_CONTEXT scoped_primary_cert(primary_cert); |
+ |
+ for (PCCERT_CONTEXT intermediate : intermediate_ca_certs) { |
+ CertAddCertificateContextToStore(store.get(), intermediate, |
+ CERT_STORE_ADD_ALWAYS, NULL); |
+ } |
+#endif |
+ |
+ // Note: |primary_cert| retains a reference to |store|, so the store will |
+ // actually be freed when |primary_cert| is freed. |
+ return scoped_primary_cert; |
+} |
+ |
+SHA256HashValue CalculateFingerprint256(PCCERT_CONTEXT cert) { |
+ DCHECK(NULL != cert->pbCertEncoded); |
+ DCHECK_NE(0u, cert->cbCertEncoded); |
+ |
+ SHA256HashValue sha256; |
+ |
+ // Use crypto::SHA256HashString for two reasons: |
+ // * < Windows Vista does not have universal SHA-256 support. |
+ // * More efficient on Windows > Vista (less overhead since non-default CSP |
+ // is not needed). |
+ base::StringPiece der_cert(reinterpret_cast<const char*>(cert->pbCertEncoded), |
+ cert->cbCertEncoded); |
+ crypto::SHA256HashString(der_cert, sha256.data, sizeof(sha256.data)); |
+ return sha256; |
+} |
+ |
+bool IsSelfSigned(PCCERT_CONTEXT cert_handle) { |
+ bool valid_signature = !!CryptVerifyCertificateSignatureEx( |
+ NULL, X509_ASN_ENCODING, CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, |
+ reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)), |
+ CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, |
+ reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)), 0, NULL); |
+ if (!valid_signature) |
+ return false; |
+ return !!CertCompareCertificateName(X509_ASN_ENCODING, |
+ &cert_handle->pCertInfo->Subject, |
+ &cert_handle->pCertInfo->Issuer); |
+} |
+ |
+} // namespace x509_util |
+ |
+} // namespace net |