Merge pull request #889 from redis/wincert

Add support for Wincert CA store in Windows
This commit is contained in:
Michael Grunder 2020-10-18 14:55:42 -07:00 committed by GitHub
commit 297f6551da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 1 deletions

View File

@ -56,7 +56,9 @@ typedef enum {
REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */ REDIS_SSL_CTX_CERT_KEY_REQUIRED, /* Client cert and key must both be specified or skipped */
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */ REDIS_SSL_CTX_CA_CERT_LOAD_FAILED, /* Failed to load CA Certificate or CA Path */
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */ REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED, /* Failed to load client certificate */
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED /* Failed to load private key */ REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED, /* Failed to load private key */
REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED, /* Failed to open system certifcate store */
REDIS_SSL_CTX_OS_CERT_ADD_FAILED /* Failed to add CA certificates obtained from system to the SSL context */
} redisSSLContextError; } redisSSLContextError;
/** /**

39
ssl.c
View File

@ -38,6 +38,7 @@
#include <string.h> #include <string.h>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include <wincrypt.h>
#else #else
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -182,6 +183,10 @@ const char *redisSSLContextGetError(redisSSLContextError error)
return "Failed to load client certificate"; return "Failed to load client certificate";
case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED: case REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED:
return "Failed to load private key"; return "Failed to load private key";
case REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED:
return "Failed to open system certifcate store";
case REDIS_SSL_CTX_OS_CERT_ADD_FAILED:
return "Failed to add CA certificates obtained from system to the SSL context";
default: default:
return "Unknown error code"; return "Unknown error code";
} }
@ -214,6 +219,11 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
const char *cert_filename, const char *private_key_filename, const char *cert_filename, const char *private_key_filename,
const char *server_name, redisSSLContextError *error) const char *server_name, redisSSLContextError *error)
{ {
#ifdef _WIN32
HCERTSTORE win_store = NULL;
PCCERT_CONTEXT win_ctx = NULL;
#endif
redisSSLContext *ctx = hi_calloc(1, sizeof(redisSSLContext)); redisSSLContext *ctx = hi_calloc(1, sizeof(redisSSLContext));
if (ctx == NULL) if (ctx == NULL)
goto error; goto error;
@ -234,6 +244,31 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
} }
if (capath || cacert_filename) { if (capath || cacert_filename) {
#ifdef _WIN32
if (0 == strcmp(cacert_filename, "wincert")) {
win_store = CertOpenSystemStore(NULL, "Root");
if (!win_store) {
if (error) *error = REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED;
goto error;
}
X509_STORE* store = SSL_CTX_get_cert_store(ctx->ssl_ctx);
while (win_ctx = CertEnumCertificatesInStore(win_store, win_ctx)) {
X509* x509 = NULL;
x509 = d2i_X509(NULL, (const unsigned char**)&win_ctx->pbCertEncoded, win_ctx->cbCertEncoded);
if (x509) {
if ((1 != X509_STORE_add_cert(store, x509)) ||
(1 != SSL_CTX_add_client_CA(ctx->ssl_ctx, x509)))
{
if (error) *error = REDIS_SSL_CTX_OS_CERT_ADD_FAILED;
goto error;
}
X509_free(x509);
}
}
CertFreeCertificateContext(win_ctx);
CertCloseStore(win_store, 0);
} else
#endif
if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, cacert_filename, capath)) { if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, cacert_filename, capath)) {
if (error) *error = REDIS_SSL_CTX_CA_CERT_LOAD_FAILED; if (error) *error = REDIS_SSL_CTX_CA_CERT_LOAD_FAILED;
goto error; goto error;
@ -257,6 +292,10 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
return ctx; return ctx;
error: error:
#ifdef _WIN32
CertFreeCertificateContext(win_ctx);
CertCloseStore(win_store, 0);
#endif
redisFreeSSLContext(ctx); redisFreeSSLContext(ctx);
return NULL; return NULL;
} }