This source file includes following definitions.
- ClientCertFindCallback
- GetClientCertsImpl
- GetClientCerts
- SelectClientCertsForTesting
#include "net/ssl/client_cert_store_win.h"
#include <algorithm>
#include <string>
#define SECURITY_WIN32
#include <windows.h>
#include <wincrypt.h>
#include <security.h>
#include "base/callback.h"
#include "base/logging.h"
#include "crypto/scoped_capi_types.h"
#include "net/cert/x509_util.h"
namespace net {
namespace {
static BOOL WINAPI ClientCertFindCallback(PCCERT_CONTEXT cert_context,
void* find_arg) {
BYTE key_usage;
if (CertGetIntendedKeyUsage(X509_ASN_ENCODING, cert_context->pCertInfo,
&key_usage, 1)) {
if (!(key_usage & CERT_DIGITAL_SIGNATURE_KEY_USAGE))
return FALSE;
} else {
DWORD err = GetLastError();
if (err) {
DLOG(ERROR) << "CertGetIntendedKeyUsage failed: " << err;
return FALSE;
}
}
if (CertVerifyTimeValidity(NULL, cert_context->pCertInfo) != 0)
return FALSE;
DWORD size = 0;
if (!CertGetCertificateContextProperty(
cert_context, CERT_KEY_PROV_INFO_PROP_ID, NULL, &size)) {
return FALSE;
}
return TRUE;
}
void GetClientCertsImpl(HCERTSTORE cert_store,
const SSLCertRequestInfo& request,
CertificateList* selected_certs) {
selected_certs->clear();
const size_t auth_count = request.cert_authorities.size();
std::vector<CERT_NAME_BLOB> issuers(auth_count);
for (size_t i = 0; i < auth_count; ++i) {
issuers[i].cbData = static_cast<DWORD>(request.cert_authorities[i].size());
issuers[i].pbData = reinterpret_cast<BYTE*>(
const_cast<char*>(request.cert_authorities[i].data()));
}
CERT_CHAIN_FIND_BY_ISSUER_PARA find_by_issuer_para;
memset(&find_by_issuer_para, 0, sizeof(find_by_issuer_para));
find_by_issuer_para.cbSize = sizeof(find_by_issuer_para);
find_by_issuer_para.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
find_by_issuer_para.cIssuer = static_cast<DWORD>(auth_count);
find_by_issuer_para.rgIssuer =
reinterpret_cast<CERT_NAME_BLOB*>(issuers.data());
find_by_issuer_para.pfnFindCallback = ClientCertFindCallback;
PCCERT_CHAIN_CONTEXT chain_context = NULL;
DWORD find_flags = CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG |
CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG;
for (;;) {
chain_context = CertFindChainInStore(cert_store,
X509_ASN_ENCODING,
find_flags,
CERT_CHAIN_FIND_BY_ISSUER,
&find_by_issuer_para,
chain_context);
if (!chain_context) {
if (GetLastError() != CRYPT_E_NOT_FOUND)
DPLOG(ERROR) << "CertFindChainInStore failed: ";
break;
}
PCCERT_CONTEXT cert_context =
chain_context->rgpChain[0]->rgpElement[0]->pCertContext;
PCCERT_CONTEXT cert_context2 = NULL;
BOOL ok = CertAddCertificateContextToStore(NULL, cert_context,
CERT_STORE_ADD_USE_EXISTING,
&cert_context2);
if (!ok) {
NOTREACHED();
continue;
}
X509Certificate::OSCertHandles intermediates;
for (DWORD i = 1; i < chain_context->rgpChain[0]->cElement; ++i) {
PCCERT_CONTEXT chain_intermediate =
chain_context->rgpChain[0]->rgpElement[i]->pCertContext;
PCCERT_CONTEXT copied_intermediate = NULL;
ok = CertAddCertificateContextToStore(NULL, chain_intermediate,
CERT_STORE_ADD_USE_EXISTING,
&copied_intermediate);
if (ok)
intermediates.push_back(copied_intermediate);
}
scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
cert_context2, intermediates);
selected_certs->push_back(cert);
CertFreeCertificateContext(cert_context2);
for (size_t i = 0; i < intermediates.size(); ++i)
CertFreeCertificateContext(intermediates[i]);
}
std::sort(selected_certs->begin(), selected_certs->end(),
x509_util::ClientCertSorter());
}
}
ClientCertStoreWin::ClientCertStoreWin() {}
ClientCertStoreWin::~ClientCertStoreWin() {}
void ClientCertStoreWin::GetClientCerts(const SSLCertRequestInfo& request,
CertificateList* selected_certs,
const base::Closure& callback) {
HCERTSTORE my_cert_store = CertOpenSystemStore(NULL, L"MY");
if (!my_cert_store) {
PLOG(ERROR) << "Could not open the \"MY\" system certificate store: ";
selected_certs->clear();
callback.Run();
return;
}
GetClientCertsImpl(my_cert_store, request, selected_certs);
if (!CertCloseStore(my_cert_store, CERT_CLOSE_STORE_CHECK_FLAG))
PLOG(ERROR) << "Could not close the \"MY\" system certificate store: ";
callback.Run();
}
bool ClientCertStoreWin::SelectClientCertsForTesting(
const CertificateList& input_certs,
const SSLCertRequestInfo& request,
CertificateList* selected_certs) {
typedef crypto::ScopedCAPIHandle<
HCERTSTORE,
crypto::CAPIDestroyerWithFlags<HCERTSTORE,
CertCloseStore, 0> > ScopedHCERTSTORE;
ScopedHCERTSTORE test_store(CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0,
NULL));
if (!test_store)
return false;
for (size_t i = 0; i < input_certs.size(); ++i) {
PCCERT_CONTEXT cert = NULL;
if (!CertAddCertificateContextToStore(test_store,
input_certs[i]->os_cert_handle(),
CERT_STORE_ADD_NEW, &cert)) {
return false;
}
CRYPT_KEY_PROV_INFO private_key_data;
memset(&private_key_data, 0, sizeof(private_key_data));
if (!CertSetCertificateContextProperty(cert,
CERT_KEY_PROV_INFO_PROP_ID,
0, &private_key_data)) {
return false;
}
if (!CertFreeCertificateContext(cert))
return false;
}
GetClientCertsImpl(test_store.get(), request, selected_certs);
return true;
}
}