Skip to content

Commit

Permalink
HRCPP-284 # Client auth for openssl
Browse files Browse the repository at this point in the history
  • Loading branch information
rigazilla authored and tristantarrant committed Feb 3, 2017
1 parent e2e740a commit c2b25a7
Show file tree
Hide file tree
Showing 8 changed files with 451 additions and 42 deletions.
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.

0 comments on commit c2b25a7

Please sign in to comment.