// 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>; } // namespace scoped_refptr CreateX509CertificateFromCertContexts( PCCERT_CONTEXT os_cert, const std::vector& os_chain) { return CreateX509CertificateFromCertContexts(os_cert, os_chain, {}); } scoped_refptr CreateX509CertificateFromCertContexts( PCCERT_CONTEXT os_cert, const std::vector& os_chain, X509Certificate::UnsafeCreateOptions options) { if (!os_cert || !os_cert->pbCertEncoded || !os_cert->cbCertEncoded) return nullptr; bssl::UniquePtr cert_handle( X509Certificate::CreateOSCertHandleFromBytes( reinterpret_cast(os_cert->pbCertEncoded), os_cert->cbCertEncoded)); if (!cert_handle) return nullptr; std::vector> 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 intermediate_cert_handle( X509Certificate::CreateOSCertHandleFromBytes( reinterpret_cast(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 result( X509Certificate::CreateFromHandleUnsafeOptions( cert_handle.get(), intermediates_raw, options)); return result; } ScopedPCCERT_CONTEXT CreateCertContextWithChain(const X509Certificate* cert) { return CreateCertContextWithChain(cert, InvalidIntermediateBehavior::kFail); } ScopedPCCERT_CONTEXT CreateCertContextWithChain( const X509Certificate* cert, InvalidIntermediateBehavior invalid_intermediate_behavior) { // 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; BOOL ok = CertAddEncodedCertificateToStore( store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->os_cert_handle()), base::checked_cast(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(CRYPTO_BUFFER_len(intermediate)), CERT_STORE_ADD_ALWAYS, NULL); if (!ok) { if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail) return nullptr; LOG(WARNING) << "error parsing intermediate"; } } // 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(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(const_cast(cert_handle)), CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, reinterpret_cast(const_cast(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