WinTLS: Fix PKCS12 loading

It appears that, contrary to most documentation, CERT_CONTEXT* is eaten
alive by AcquireCredentialsHandle(). Hence you cannot really reuse that.
pull/138/head
Nils Maier 2013-09-30 15:16:42 +02:00
parent 50ac6afe36
commit 4c84af31be
1 changed files with 31 additions and 20 deletions

View File

@ -78,7 +78,7 @@ TLSContext* TLSContext::make(TLSSessionSide side)
WinTLSContext::~WinTLSContext() WinTLSContext::~WinTLSContext()
{ {
if (store_) { if (store_) {
CertCloseStore(store_, 0); ::CertCloseStore(store_, 0);
store_ = 0; store_ = 0;
} }
} }
@ -104,11 +104,7 @@ void WinTLSContext::setVerifyPeer(bool verify)
SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_IGNORE_REVOCATION_OFFLINE |
SCH_CRED_NO_SERVERNAME_CHECK; SCH_CRED_NO_SERVERNAME_CHECK;
} }
// Need to initialize cred_ early, because later on it will segfault deep
// within AcquireCredentialsHandle for whatever reason.
cred_.reset(); cred_.reset();
getCredHandle();
} }
CredHandle* WinTLSContext::getCredHandle() CredHandle* WinTLSContext::getCredHandle()
@ -119,6 +115,20 @@ CredHandle* WinTLSContext::getCredHandle()
TimeStamp ts; TimeStamp ts;
cred_.reset(new CredHandle()); cred_.reset(new CredHandle());
const CERT_CONTEXT* ctx = nullptr;
if (store_) {
ctx = ::CertEnumCertificatesInStore(store_, nullptr);
if (!ctx) {
throw DL_ABORT_EX("Failed to load certificate");
}
credentials_.cCreds = 1;
credentials_.paCred = &ctx;
}
else {
credentials_.cCreds = 0;
credentials_.paCred = nullptr;
}
SECURITY_STATUS status = ::AcquireCredentialsHandleW( SECURITY_STATUS status = ::AcquireCredentialsHandleW(
nullptr, nullptr,
(SEC_WCHAR*)UNISP_NAME_W, (SEC_WCHAR*)UNISP_NAME_W,
@ -129,6 +139,9 @@ CredHandle* WinTLSContext::getCredHandle()
nullptr, nullptr,
cred_.get(), cred_.get(),
&ts); &ts);
if (ctx) {
::CertFreeCertificateContext(ctx);
}
if (status != SEC_E_OK) { if (status != SEC_E_OK) {
cred_.reset(); cred_.reset();
throw DL_ABORT_EX("Failed to initialize WinTLS context handle"); throw DL_ABORT_EX("Failed to initialize WinTLS context handle");
@ -146,35 +159,33 @@ bool WinTLSContext::addCredentialFile(const std::string& certfile,
(DWORD)data.length(), (DWORD)data.length(),
(BYTE*)data.c_str() (BYTE*)data.c_str()
}; };
if (!PFXIsPFXBlob(&blob)) { if (!::PFXIsPFXBlob(&blob)) {
A2_LOG_ERROR("Not a valid PKCS12 file"); A2_LOG_ERROR("Not a valid PKCS12 file");
return false; return false;
} }
store_ = ::PFXImportCertStore(&blob, L"", HCERTSTORE store = ::PFXImportCertStore(&blob, L"",
CRYPT_EXPORTABLE | CRYPT_USER_KEYSET); CRYPT_EXPORTABLE | CRYPT_USER_KEYSET);
if (!store_) { if (!store_) {
store_ = ::PFXImportCertStore(&blob, nullptr, store = ::PFXImportCertStore(&blob, nullptr,
CRYPT_EXPORTABLE | CRYPT_USER_KEYSET); CRYPT_EXPORTABLE | CRYPT_USER_KEYSET);
} }
if (!store_) { if (!store) {
A2_LOG_ERROR("Failed to import PKCS12 store"); A2_LOG_ERROR("Failed to import PKCS12 store");
return false; return false;
} }
auto ctx = ::CertEnumCertificatesInStore(store, nullptr);
const CERT_CONTEXT* ctx = ::CertEnumCertificatesInStore(store_, nullptr);
if (!ctx) { if (!ctx) {
A2_LOG_ERROR("Failed to read any certificates from the PKCS12 store"); A2_LOG_ERROR("PKCS12 file does not contain certificates");
::CertCloseStore(store, 0);
return false; return false;
} }
credentials_.cCreds = 1; ::CertFreeCertificateContext(ctx);
credentials_.paCred = &ctx;
// Need to initialize cred_ early, because later on it will segfault deep if (store_) {
// within AcquireCredentialsHandle for whatever reason. ::CertCloseStore(store_, 0);
}
store_ = store;
cred_.reset(); cred_.reset();
getCredHandle();
CertFreeCertificateContext(ctx);
return true; return true;
} }