From 9ee8bc12b5939fa8d917705cba63f954f9342253 Mon Sep 17 00:00:00 2001 From: Doug MacEachern Date: Sat, 30 Mar 2002 05:40:02 +0000 Subject: [PATCH] implement proxy client certificate callback (uses SSLProxyMachineCertificate{File,Cert} when downstream server requires a client certificate) git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@94329 13f79535-47bb-0310-9956-ffa450edef68 --- modules/ssl/mod_ssl.h | 1 + modules/ssl/ssl_engine_init.c | 4 ++ modules/ssl/ssl_engine_kernel.c | 98 +++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h index 85d628732b..de1d46773b 100644 --- a/modules/ssl/mod_ssl.h +++ b/modules/ssl/mod_ssl.h @@ -628,6 +628,7 @@ RSA *ssl_callback_TmpRSA(SSL *, int, int); DH *ssl_callback_TmpDH(SSL *, int, int); int ssl_callback_SSLVerify(int, X509_STORE_CTX *); int ssl_callback_SSLVerify_CRL(int, X509_STORE_CTX *, server_rec *); +int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey); int ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *); SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, int, int *); void ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *); diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index 4aa4bd9366..5cf106837c 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -908,6 +908,9 @@ static void ssl_init_proxy_certs(server_rec *s, STACK_OF(X509_INFO) *sk; modssl_pk_proxy_t *pkp = mctx->pkp; + SSL_CTX_set_client_cert_cb(mctx->ssl_ctx, + ssl_callback_proxy_cert); + if (!(pkp->cert_file || pkp->cert_path)) { return; } @@ -926,6 +929,7 @@ static void ssl_init_proxy_certs(server_rec *s, ssl_log(s, SSL_LOG_TRACE|SSL_INIT, "loaded %d client certs for SSL proxy", ncerts); + pkp->certs = sk; } else { diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index efd745cedf..96ec929674 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -1543,6 +1543,104 @@ int ssl_callback_SSLVerify_CRL(int ok, X509_STORE_CTX *ctx, server_rec *s) return ok; } +#define SSLPROXY_CERT_CB_LOG_FMT \ + "Proxy client certificate callback: (%s) " + +static void modssl_proxy_info_log(server_rec *s, + X509_INFO *info, + const char *msg) +{ + SSLSrvConfigRec *sc = mySrvConfig(s); + char name_buf[256]; + X509_NAME *name; + const char *dn; + + if (sc->log_level < SSL_LOG_TRACE) { + return; + } + + name = X509_get_subject_name(info->x509); + dn = X509_NAME_oneline(name, name_buf, sizeof(name_buf)); + + ssl_log(s, SSL_LOG_TRACE, + SSLPROXY_CERT_CB_LOG_FMT "%s, sending %s", + sc->vhost_id, msg, dn ? dn : "-uknown-"); +} + +/* + * caller will decrement the cert and key reference + * so we need to increment here to prevent them from + * being freed. + */ +#define modssl_set_cert_info(info, cert, pkey) \ + *cert = info->x509; \ + *pkey = info->x_pkey->dec_pkey; \ + CRYPTO_add(&((*cert)->references), +1, CRYPTO_LOCK_X509_PKEY); \ + CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY) + +int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey) +{ + conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); + server_rec *s = c->base_server; + SSLSrvConfigRec *sc = mySrvConfig(s); + X509_NAME *ca_name, *issuer; + X509_INFO *info; + STACK_OF(X509_NAME) *ca_list; + STACK_OF(X509_INFO) *certs = sc->proxy->pkp->certs; + int i, j; + + ssl_log(s, SSL_LOG_TRACE, + SSLPROXY_CERT_CB_LOG_FMT "entered", + sc->vhost_id); + + if (!certs || (sk_X509_INFO_num(certs) <= 0)) { + ssl_log(s, SSL_LOG_WARN, + SSLPROXY_CERT_CB_LOG_FMT + "downstream server wanted client certificate " + "but none are configured", sc->vhost_id); + return FALSE; + } + + ca_list = SSL_get_client_CA_list(ssl); + + if (!ca_list || (sk_X509_NAME_num(ca_list) <= 0)) { + /* + * downstream server didn't send us a list of acceptable CA certs, + * so we send the first client cert in the list. + */ + info = sk_X509_INFO_value(certs, 0); + + modssl_proxy_info_log(s, info, "no acceptable CA list"); + + modssl_set_cert_info(info, x509, pkey); + + return TRUE; + } + + for (i = 0; i < sk_X509_NAME_num(ca_list); i++) { + ca_name = sk_X509_NAME_value(ca_list, i); + + for (j = 0; j < sk_X509_INFO_num(certs); j++) { + info = sk_X509_INFO_value(certs, j); + issuer = X509_get_issuer_name(info->x509); + + if (X509_NAME_cmp(issuer, ca_name) == 0) { + modssl_proxy_info_log(s, info, "found acceptable cert"); + + modssl_set_cert_info(info, x509, pkey); + + return TRUE; + } + } + } + + ssl_log(s, SSL_LOG_TRACE, + SSLPROXY_CERT_CB_LOG_FMT + "no client certificate found!?", sc->vhost_id); + + return FALSE; +} + static void ssl_session_log(server_rec *s, const char *request, unsigned char *id, -- 2.50.1