Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HRCPP-284 # Client auth for openssl and schannel #266

Merged
merged 1 commit into from
Feb 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,16 @@ else (NOT ((EXISTS "${HOTROD_JBOSS_HOME}/bin/standalone.sh") AND (EXISTS "${HOTR
add_test (simple-tls simple-tls ${CMAKE_CURRENT_SOURCE_DIR}/test/data/infinispan-ca.pem)
add_test (simple-tls-sni simple-tls-sni ${CMAKE_CURRENT_SOURCE_DIR}/test/data/keystore_server_cert.pem)
add_test (stop_ssl_server ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/bin/server_ctl.py stop)
add_test (start_ssl_server_client_auth ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/bin/server_ctl.py start ${JAVA_RUNTIME} ${HOTROD_JBOSS_HOME} standalone-hotrod-ssl-client-auth.xml)
add_test (probe_ssl_port_client_auth ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/bin/probe_port.py localhost 11222 60)
if (WIN32)
add_test (simple-tls-client-auth simple-tls ${CMAKE_CURRENT_SOURCE_DIR}/test/data/infinispan-ca.pem ${CMAKE_CURRENT_SOURCE_DIR}/test/data/truststore_client.p12)
add_test (simple-tls-sni-client-auth simple-tls-sni ${CMAKE_CURRENT_SOURCE_DIR}/test/data/keystore_server_cert.pem ${CMAKE_CURRENT_SOURCE_DIR}/test/data/truststore_client.p12)
else (WIN32)
add_test (simple-tls-client-auth simple-tls ${CMAKE_CURRENT_SOURCE_DIR}/test/data/infinispan-ca.pem ${CMAKE_CURRENT_SOURCE_DIR}/test/data/truststore_client.pem)
add_test (simple-tls-sni-client-auth simple-tls-sni ${CMAKE_CURRENT_SOURCE_DIR}/test/data/keystore_server_cert.pem ${CMAKE_CURRENT_SOURCE_DIR}/test/data/truststore_client.pem)
endif(WIN32)
add_test (stop_ssl_server_client_auth ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/bin/server_ctl.py stop)
endif (NOT ((EXISTS "${HOTROD_JBOSS_HOME}/bin/standalone.sh") AND (EXISTS "${HOTROD_JBOSS_HOME}/bin/standalone.bat")))

if (ENABLE_SWIG_TESTING)
Expand Down
117 changes: 84 additions & 33 deletions src/hotrod/sys/SChannelSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "hotrod/sys/Log.h"
#include "SChannelSocket.h"
#include "WinDef.h"
#include "Cryptuiapi.h"

#pragma comment(lib, "Cryptui.lib")


#define IO_BUFFER_SIZE 0x10000
Expand Down Expand Up @@ -516,6 +519,13 @@ DWORD SChannelSocket::verifyServerCertificate(HCERTSTORE hCertStore, PCCERT_CONT
}
}

bool is_pem_filename(const std::string &str)
{
static const std::string &suffix = ".pem";
return str.size() >= 4 &&
str.compare(str.size() - 4, 4, suffix) == 0;
}

void SChannelSocket::connect(const std::string & host, int port, int timeout)
{
SCHANNEL_CRED SchannelCred;
Expand All @@ -527,7 +537,7 @@ void SChannelSocket::connect(const std::string & host, int port, int timeout)
TimeStamp tsExpiry;
SecBuffer ExtraData;
HANDLE hFile, hClientFile;
char pemServCert[8192], pemClientCert[8192];
char servCert[8192], pemClientCert[8192];
BYTE derServCert[8192], derClientCert[8192];
DWORD derCertLen = 8192;
DWORD readLen;
Expand All @@ -542,61 +552,102 @@ void SChannelSocket::connect(const std::string & host, int port, int timeout)
fprintf(stderr, "**** Error %d. Failed to open server certificate file %s.\n", GetLastError(), m_serverCAFile.c_str());
}

if (!ReadFile(hFile, pemServCert, 8192, &readLen, NULL))
if (!ReadFile(hFile, servCert, 8192, &readLen, NULL))
{
fprintf(stderr, "**** Error %d. Failed to open read certificate file %s.\n", GetLastError(), m_serverCAFile.c_str());
}
CloseHandle(hFile);
CryptStringToBinary(pemServCert, readLen, CRYPT_STRING_BASE64_ANY, derServCert, &derCertLen, NULL, NULL);
pServerContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
(BYTE*)derServCert,
derCertLen);
if (pServerContext == NULL)
{
printf("**** Error 0x%x returned by CertCreateCertificateContext. Cannot create certificate. File corrupted?\n", GetLastError());
logAndThrow(host, port, "ERROR");
}
if (!(hMemStore = CertOpenStore(
CERT_STORE_PROV_MEMORY, // The memory provider type
0, // The encoding type is not needed
NULL, // Use the default HCRYPTPROV
0, // Accept the default dwFlags
NULL // pvPara is not used
)))

// .pem if pem all others are supposed to be p12 pfx
if (is_pem_filename(m_serverCAFile.c_str()))
{
printf("**** Error 0x%x returned by CertOpenStore\n", GetLastError());
logAndThrow(host, port, "ERROR");
if (!CryptStringToBinary(servCert, readLen, CRYPT_STRING_BASE64_ANY, derServCert, &derCertLen, NULL, NULL))
{
printf("**** Error 0x%x returned by CryptStringToBinary server cert\n", GetLastError());
logAndThrow(host, port, "ERROR");
}
pServerContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
(BYTE*)derServCert,
derCertLen);
if (pServerContext == NULL)
{
printf("**** Error 0x%x returned by CertCreateCertificateContext. Cannot create certificate. File corrupted?\n", GetLastError());
logAndThrow(host, port, "ERROR");
}
if (!(hMemStore = CertOpenStore(
CERT_STORE_PROV_MEMORY, // The memory provider type
0, // The encoding type is not needed
NULL, // Use the default HCRYPTPROV
0, // Accept the default dwFlags
NULL // pvPara is not used
)))
{
printf("**** Error 0x%x returned by CertOpenStore\n", GetLastError());
logAndThrow(host, port, "ERROR");
}
if (!CertAddCertificateContextToStore(hMemStore, pServerContext,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL
))
{
printf("**** Error 0x%x returned by CertAddCertificateContextToStore\n", GetLastError());
logAndThrow(host, port, "ERROR");
}
}
if (!CertAddCertificateContextToStore(hMemStore, pServerContext,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL
))
else
{
printf("**** Error 0x%x returned by CertAddCertificateContextToStore\n", GetLastError());
logAndThrow(host, port, "ERROR");
// p12 can be imported directly as certstore
CRYPT_DATA_BLOB sblob;
sblob.cbData = (DWORD)readLen;
sblob.pbData = (BYTE*)servCert;

// Importing the cert. The file cannot be password protected
HCERTSTORE servCertStore = PFXImportCertStore(&sblob, L"", CRYPT_MACHINE_KEYSET);
if (servCertStore == NULL) {
printf("PFXImportCertStore failed. hr=0x%x\n", GetLastError());
logAndThrow(host, port, "ERROR");
}
}
}

ZeroMemory(&SchannelCred, sizeof(SchannelCred));
SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
if (pClientContext==NULL && !m_clientCertificateFile.empty())
{
// User provided the certificate to validate the client against the server
// Read it and build certificate and set credentials for the schannel
hClientFile = CreateFile(m_clientCertificateFile.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hClientFile == INVALID_HANDLE_VALUE)
BYTE clientCertStore[8192];
DWORD clientCertStoreLen = 8192;
DWORD readLen;
CRYPT_DATA_BLOB blob;
// User provided the certificate to validate the server in a file
// Read it and build certificate and certificates store
hFile = CreateFile(m_clientCertificateFile.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "**** Error %d. Failed to open server certificate file %s.\n", GetLastError(), m_clientCertificateFile.c_str());
}

if (!ReadFile(hClientFile, pemClientCert, 8192, &readLen, NULL))
if (!ReadFile(hFile, clientCertStore, 8192, &clientCertStoreLen, NULL))
{
fprintf(stderr, "**** Error %d. Failed to open read certificate file %s.\n", GetLastError(), m_clientCertificateFile.c_str());
}
CloseHandle(hClientFile);
CryptStringToBinary(pemClientCert, readLen, CRYPT_STRING_BASE64_ANY, derClientCert, &derCertLen, NULL, NULL);
pClientContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CloseHandle(hFile);
blob.cbData = (DWORD)clientCertStoreLen;
blob.pbData = clientCertStore;

HCERTSTORE certStore = PFXImportCertStore(&blob, L"", CRYPT_EXPORTABLE);
if (certStore == NULL) {
printf("PFXImportCertStore failed. hr=0x%x\n", GetLastError());
logAndThrow(host, port, "ERROR");
}

pClientContext = CertFindCertificateInStore(certStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
, 0, CERT_FIND_HAS_PRIVATE_KEY, NULL, NULL);

/* pClientContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
(BYTE*)derClientCert,
derCertLen);
derCertLen); */
if (pClientContext == NULL)
{
printf("**** Error 0x%x returned by CertCreateCertificateContext. Cannot create certificate. File corrupted?\n", GetLastError());
Expand Down
19 changes: 10 additions & 9 deletions src/hotrod/sys/SSLSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,6 @@ void SSLSocket::connect(const std::string& host, int port, int timeout) {
logAndThrow(host, port, "SSL_CTX_new");
}
SSL_CTX_set_verify(m_ctx, SSL_VERIFY_PEER, 0);
if (!m_clientCertificateFile.empty()) {
DEBUG("Using user-supplied client certificate %s", m_clientCertificateFile.c_str());
if (!SSL_CTX_use_certificate_file(m_ctx, m_clientCertificateFile.c_str(), SSL_FILETYPE_PEM)) {
if(m_ctx != 0)
SSL_CTX_free(m_ctx);
m_socket->close();
logAndThrow(host, port, "SSL_CTX_use_certificate_file");
}
}
SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
if (m_serverCAFile.empty() && m_serverCAPath.empty()) {
if(!SSL_CTX_set_default_verify_paths(m_ctx)) {
Expand All @@ -60,6 +51,16 @@ void SSLSocket::connect(const std::string& host, int port, int timeout) {
logAndThrow(host, port, "SSL_CTX_load_verify_locations");
}

if (!m_clientCertificateFile.empty()) {
DEBUG("Using user-supplied client certificate %s", m_clientCertificateFile.c_str());
if (!SSL_CTX_use_certificate_file(m_ctx, m_clientCertificateFile.c_str(), SSL_FILETYPE_PEM)) {
logAndThrow(host, port, "SSL_CTX_use_certificate_file");
}
if (!SSL_CTX_use_PrivateKey_file(m_ctx, m_clientCertificateFile.c_str(), SSL_FILETYPE_PEM)) {
logAndThrow(host, port, "SSL_CTX_use_certificate_file");
}
}

m_ssl = SSL_new(m_ctx);
if (!m_ssl) {
if(m_ctx != 0)
Expand Down
Binary file added test/data/infinispan-ca.p12
Binary file not shown.