summaryrefslogtreecommitdiffstats
path: root/usr.sbin/httpd/src/modules/ssl/ssl_engine_ext.c
diff options
context:
space:
mode:
authorbeck <beck@openbsd.org>2000-03-19 11:16:13 +0000
committerbeck <beck@openbsd.org>2000-03-19 11:16:13 +0000
commit7162a7a1f02eb4e2e0065733ca2d04d7558e49e4 (patch)
tree97e4405d808cb4f9cd304e4ef041b1b542fdb0d8 /usr.sbin/httpd/src/modules/ssl/ssl_engine_ext.c
parentnew minty 0.9.5 openssl (diff)
downloadwireguard-openbsd-7162a7a1f02eb4e2e0065733ca2d04d7558e49e4.tar.xz
wireguard-openbsd-7162a7a1f02eb4e2e0065733ca2d04d7558e49e4.zip
apache 1.3.12 + mod_ssl 2.6.2 merge
Diffstat (limited to 'usr.sbin/httpd/src/modules/ssl/ssl_engine_ext.c')
-rw-r--r--usr.sbin/httpd/src/modules/ssl/ssl_engine_ext.c398
1 files changed, 384 insertions, 14 deletions
diff --git a/usr.sbin/httpd/src/modules/ssl/ssl_engine_ext.c b/usr.sbin/httpd/src/modules/ssl/ssl_engine_ext.c
index 87a550c2748..47092184c89 100644
--- a/usr.sbin/httpd/src/modules/ssl/ssl_engine_ext.c
+++ b/usr.sbin/httpd/src/modules/ssl/ssl_engine_ext.c
@@ -213,18 +213,27 @@ static char *ssl_ext_mr_lookup_variable(request_rec *r, char *var)
** _________________________________________________________________
*/
-static int ssl_ext_mp_canon(request_rec *r, char *url);
-static int ssl_ext_mp_handler(request_rec *r, void *cr, char *url, char *proxyhost, int proxyport, char *protocol);
-static int ssl_ext_mp_set_destport(request_rec *r);
-static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb);
-static void ssl_ext_mp_close_connection(void *_fb);
-static int ssl_ext_mp_write_host_header(request_rec *r, BUFF *fb, char *host, int port, char *portstr);
+static int ssl_ext_mp_canon(request_rec *, char *);
+static int ssl_ext_mp_handler(request_rec *, void *, char *, char *, int, char *);
+static int ssl_ext_mp_set_destport(request_rec *);
+static char *ssl_ext_mp_new_connection(request_rec *, BUFF *, char *);
+static void ssl_ext_mp_close_connection(void *);
+static int ssl_ext_mp_write_host_header(request_rec *, BUFF *, char *, int, char *);
+#ifdef SSL_EXPERIMENTAL
+static void ssl_ext_mp_init(server_rec *, pool *);
+static int ssl_ext_mp_verify_cb(int, X509_STORE_CTX *);
+static int ssl_ext_mp_clientcert_cb(SSL *, X509 **, EVP_PKEY **);
+#endif
/*
* register us ...
*/
static void ssl_ext_mp_register(void)
{
+#ifdef SSL_EXPERIMENTAL
+ ap_hook_register("ap::mod_proxy::init",
+ ssl_ext_mp_init, AP_HOOK_NOCTX);
+#endif
ap_hook_register("ap::mod_proxy::canon",
ssl_ext_mp_canon, AP_HOOK_NOCTX);
ap_hook_register("ap::mod_proxy::handler",
@@ -240,6 +249,9 @@ static void ssl_ext_mp_register(void)
static void ssl_ext_mp_unregister(void)
{
+#ifdef SSL_EXPERIMENTAL
+ ap_hook_unregister("ap::mod_proxy::init", ssl_ext_mp_init);
+#endif
ap_hook_unregister("ap::mod_proxy::canon", ssl_ext_mp_canon);
ap_hook_unregister("ap::mod_proxy::handler", ssl_ext_mp_handler);
ap_hook_unregister("ap::mod_proxy::http::handler::set_destport",
@@ -251,6 +263,145 @@ static void ssl_ext_mp_unregister(void)
return;
}
+/*
+ * SSL proxy initialization
+ */
+#ifdef SSL_EXPERIMENTAL
+static void ssl_ext_mp_init(server_rec *s, pool *p)
+{
+ SSLSrvConfigRec *sc;
+ char *cpVHostID;
+ int nVerify;
+ SSL_CTX *ctx;
+ char *cp;
+ STACK_OF(X509_INFO) *sk;
+
+ /*
+ * Initialize each virtual server
+ */
+ for (; s != NULL; s = s->next) {
+ sc = mySrvConfig(s);
+ cpVHostID = ssl_util_vhostid(p, s);
+
+ if (sc->bProxyVerify == UNSET)
+ sc->bProxyVerify = FALSE;
+
+ /*
+ * Create new SSL context and configure callbacks
+ */
+ if (sc->nProxyProtocol == SSL_PROTOCOL_NONE) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) No Proxy SSL protocols available [hint: SSLProxyProtocol]",
+ cpVHostID);
+ ssl_die();
+ }
+ cp = ap_pstrcat(p, (sc->nProxyProtocol & SSL_PROTOCOL_SSLV2 ? "SSLv2, " : ""),
+ (sc->nProxyProtocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""),
+ (sc->nProxyProtocol & SSL_PROTOCOL_TLSV1 ? "TLSv1, " : ""), NULL);
+ cp[strlen(cp)-2] = NUL;
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Creating new proxy SSL context (protocols: %s)",
+ cpVHostID, cp);
+ if (sc->nProxyProtocol == SSL_PROTOCOL_SSLV2)
+ ctx = SSL_CTX_new(SSLv2_client_method()); /* only SSLv2 is left */
+ else
+ ctx = SSL_CTX_new(SSLv23_client_method()); /* be more flexible */
+ if (ctx == NULL) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to create SSL Proxy context", cpVHostID);
+ ssl_die();
+ }
+ sc->pSSLProxyCtx = ctx;
+ SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ if (!(sc->nProxyProtocol & SSL_PROTOCOL_SSLV2))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+ if (!(sc->nProxyProtocol & SSL_PROTOCOL_SSLV3))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
+ if (!(sc->nProxyProtocol & SSL_PROTOCOL_TLSV1))
+ SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
+
+ if (sc->szProxyClientCertificateFile || sc->szProxyClientCertificatePath) {
+ sk = sk_X509_INFO_new_null();
+ if (sc->szProxyClientCertificateFile)
+ SSL_load_CrtAndKeyInfo_file(p, sk, sc->szProxyClientCertificateFile);
+ if (sc->szProxyClientCertificatePath)
+ SSL_load_CrtAndKeyInfo_path(p, sk, sc->szProxyClientCertificatePath);
+ ssl_log(s, SSL_LOG_TRACE, "Init: (%s) loaded %d client certs for SSL proxy",
+ cpVHostID, sk_X509_INFO_num(sk));
+ if (sk_X509_INFO_num(sk) > 0) {
+ SSL_CTX_set_client_cert_cb(ctx, ssl_ext_mp_clientcert_cb);
+ sc->skProxyClientCerts = sk;
+ }
+ }
+
+ /*
+ * Calculate OpenSSL verify type for verifying the remote server
+ * certificate. We either verify it against our list of CA's, or don't
+ * bother at all.
+ */
+ nVerify = SSL_VERIFY_NONE;
+ if (sc->bProxyVerify)
+ nVerify |= SSL_VERIFY_PEER;
+ if ( nVerify & SSL_VERIFY_PEER
+ && sc->szProxyCACertificateFile == NULL
+ && sc->szProxyCACertificatePath == NULL) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "Init: (%s) SSLProxyVerify set to On but no CA certificates configured",
+ cpVHostID);
+ ssl_die();
+ }
+ if ( nVerify & SSL_VERIFY_NONE
+ && ( sc->szProxyCACertificateFile != NULL
+ || sc->szProxyCACertificatePath != NULL)) {
+ ssl_log(s, SSL_LOG_WARN,
+ "init: (%s) CA certificates configured but ignored because SSLProxyVerify is Off",
+ cpVHostID);
+ }
+ SSL_CTX_set_verify(ctx, nVerify, ssl_ext_mp_verify_cb);
+
+ /*
+ * Enable session caching. We can safely use the same cache
+ * as used for communicating with the other clients.
+ */
+ SSL_CTX_sess_set_new_cb(sc->pSSLProxyCtx, ssl_callback_NewSessionCacheEntry);
+ SSL_CTX_sess_set_get_cb(sc->pSSLProxyCtx, ssl_callback_GetSessionCacheEntry);
+ SSL_CTX_sess_set_remove_cb(sc->pSSLProxyCtx, ssl_callback_DelSessionCacheEntry);
+
+ /*
+ * Configure SSL Cipher Suite
+ */
+ ssl_log(s, SSL_LOG_TRACE,
+ "Init: (%s) Configuring permitted SSL ciphers for SSL proxy", cpVHostID);
+ if (sc->szProxyCipherSuite != NULL) {
+ if (!SSL_CTX_set_cipher_list(sc->pSSLProxyCtx, sc->szProxyCipherSuite)) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure permitted SSL ciphers for SSL Proxy",
+ cpVHostID);
+ ssl_die();
+ }
+ }
+
+ /*
+ * Configure Client Authentication details
+ */
+ if (sc->szProxyCACertificateFile != NULL || sc->szProxyCACertificatePath != NULL) {
+ ssl_log(s, SSL_LOG_DEBUG,
+ "Init: (%s) Configuring client verification locations for SSL Proxy",
+ cpVHostID);
+ if (!SSL_CTX_load_verify_locations(sc->pSSLProxyCtx,
+ sc->szProxyCACertificateFile,
+ sc->szProxyCACertificatePath)) {
+ ssl_log(s, SSL_LOG_ERROR|SSL_ADD_SSLERR,
+ "Init: (%s) Unable to configure SSL verify locations for SSL proxy",
+ cpVHostID);
+ ssl_die();
+ }
+ }
+ }
+ return;
+}
+#endif /* SSL_EXPERIMENTAL */
+
static int ssl_ext_mp_canon(request_rec *r, char *url)
{
int rc;
@@ -289,39 +440,66 @@ static int ssl_ext_mp_set_destport(request_rec *r)
return DEFAULT_HTTP_PORT;
}
-static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb)
+static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb, char *peer)
{
+#ifndef SSL_EXPERIMENTAL
SSL_CTX *ssl_ctx;
+#endif
SSL *ssl;
char *errmsg;
int rc;
char *cpVHostID;
char *cpVHostMD5;
+#ifdef SSL_EXPERIMENTAL
+ SSLSrvConfigRec *sc;
+ char *cp;
+#endif
if (ap_ctx_get(r->ctx, "ssl::proxy::enabled") == PFALSE)
return NULL;
+
+ /*
+ * Find context
+ */
+#ifdef SSL_EXPERIMENTAL
+ sc = mySrvConfig(r->server);
+#endif
cpVHostID = ssl_util_vhostid(r->pool, r->server);
/*
* Create a SSL context and handle
*/
+#ifdef SSL_EXPERIMENTAL
+ ssl = SSL_new(sc->pSSLProxyCtx);
+#else
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
- if ((ssl = SSL_new(ssl_ctx)) == NULL) {
- errmsg = ap_pstrcat(r->pool, "SSL new failed (%s): ", cpVHostID,
- ERR_reason_error_string(ERR_get_error()), NULL);
+ ssl = SSL_new(ssl_ctx);
+#endif
+ if (ssl == NULL) {
+ errmsg = ap_psprintf(r->pool, "SSL proxy new failed (%s): peer %s: %s",
+ cpVHostID, peer, ERR_reason_error_string(ERR_get_error()));
ap_ctx_set(fb->ctx, "ssl", NULL);
return errmsg;
}
SSL_clear(ssl);
cpVHostMD5 = ap_md5(r->pool, cpVHostID);
if (!SSL_set_session_id_context(ssl, (unsigned char *)cpVHostMD5, strlen(cpVHostMD5))) {
- errmsg = ap_pstrcat(r->pool, "Unable to set session id context to `%s': ", cpVHostMD5,
- ERR_reason_error_string(ERR_get_error()), NULL);
+ errmsg = ap_psprintf(r->pool, "Unable to set session id context to `%s': peer %s: %s",
+ cpVHostMD5, peer, ERR_reason_error_string(ERR_get_error()));
ap_ctx_set(fb->ctx, "ssl", NULL);
return errmsg;
}
SSL_set_fd(ssl, fb->fd);
+#ifdef SSL_EXPERIMENTAL
+ SSL_set_app_data(ssl, fb->ctx);
+#endif
ap_ctx_set(fb->ctx, "ssl", ssl);
+#ifdef SSL_EXPERIMENTAL
+ ap_ctx_set(fb->ctx, "ssl::proxy::server_rec", r->server);
+ ap_ctx_set(fb->ctx, "ssl::proxy::peer", peer);
+ ap_ctx_set(fb->ctx, "ssl::proxy::servername", cpVHostID);
+ ap_ctx_set(fb->ctx, "ssl::proxy::verifyerror", NULL);
+#endif
/*
* Give us a chance to gracefully close the connection
@@ -333,8 +511,19 @@ static char *ssl_ext_mp_new_connection(request_rec *r, BUFF *fb)
* Establish the SSL connection
*/
if ((rc = SSL_connect(ssl)) <= 0) {
- errmsg = ap_pstrcat(r->pool, "SSL connect failed (%s): ", cpVHostID,
- ERR_reason_error_string(ERR_get_error()), NULL);
+#ifdef SSL_EXPERIMENTAL
+ if ((cp = (char *)ap_ctx_get(fb->ctx, "ssl::proxy::verifyerror")) != NULL) {
+ SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
+ SSL_smart_shutdown(ssl);
+ SSL_free(ssl);
+ ap_ctx_set(fb->ctx, "ssl", NULL);
+ ap_bsetflag(fb, B_EOF|B_EOUT, 1);
+ return NULL;
+ }
+#endif
+ errmsg = ap_psprintf(r->pool, "SSL proxy connect failed (%s): peer %s: %s",
+ cpVHostID, peer, ERR_reason_error_string(ERR_get_error()));
+ ssl_log(r->server, SSL_LOG_ERROR, errmsg);
SSL_free(ssl);
ap_ctx_set(fb->ctx, "ssl", NULL);
return errmsg;
@@ -347,13 +536,17 @@ static void ssl_ext_mp_close_connection(void *_fb)
{
BUFF *fb = _fb;
SSL *ssl;
+ SSL_CTX *ctx;
ssl = ap_ctx_get(fb->ctx, "ssl");
if (ssl != NULL) {
+ ctx = SSL_get_SSL_CTX(ssl);
SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
SSL_smart_shutdown(ssl);
SSL_free(ssl);
ap_ctx_set(fb->ctx, "ssl", NULL);
+ if (ctx != NULL)
+ SSL_CTX_free(ctx);
}
return;
}
@@ -371,6 +564,183 @@ static int ssl_ext_mp_write_host_header(
return DECLINED;
}
+#ifdef SSL_EXPERIMENTAL
+
+/*
+ * Callback for client certificate stuff.
+ * If the remote site sent us a SSLv3 list of acceptable CA's then trawl the
+ * table of client certs and send the first one that matches.
+ */
+static int ssl_ext_mp_clientcert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
+{
+ SSLSrvConfigRec *sc;
+ X509_NAME *xnx;
+ X509_NAME *issuer;
+ X509_INFO *xi;
+ char *peer;
+ char *servername;
+ server_rec *s;
+ ap_ctx *pCtx;
+ STACK_OF(X509_NAME) *sk;
+ STACK_OF(X509_INFO) *pcerts;
+ char *cp;
+ int i, j;
+
+ pCtx = (ap_ctx *)SSL_get_app_data(ssl);
+ s = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
+ peer = ap_ctx_get(pCtx, "ssl::proxy::peer");
+ servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
+
+ sc = mySrvConfig(s);
+ pcerts = sc->skProxyClientCerts;
+
+ ssl_log(s, SSL_LOG_DEBUG, "Proxy client certificate callback: (%s) entered");
+
+ if ((pcerts == NULL) || (sk_X509_INFO_num(pcerts) <= 0)) {
+ ssl_log(s, SSL_LOG_TRACE,
+ "Proxy client certificate callback: (%s) "
+ "site wanted client certificate but none available",
+ servername);
+ return 0;
+ }
+
+ sk = SSL_get_client_CA_list(ssl);
+
+ if ((sk == NULL) || (sk_X509_NAME_num(sk) <= 0)) {
+ /*
+ * remote site didn't send us a list of acceptable CA certs,
+ * so lets send the first one we came across
+ */
+ xi = sk_X509_INFO_value(pcerts, 0);
+ cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
+ ssl_log(s, SSL_LOG_DEBUG,
+ "SSL Proxy: (%s) no acceptable CA list, sending %s",
+ servername, cp != NULL ? cp : "-unknown-");
+ free(cp);
+ /* export structures to the caller */
+ *x509 = xi->x509;
+ *pkey = xi->x_pkey->dec_pkey;
+ /* prevent OpenSSL freeing these structures */
+ CRYPTO_add(&((*x509)->references), +1, CRYPTO_LOCK_X509_PKEY);
+ CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY);
+ return 1;
+ }
+
+ for (i = 0; i < sk_X509_NAME_num(sk); i++) {
+ xnx = sk_X509_NAME_value(sk, i);
+ for (j = 0; j < sk_X509_INFO_num(pcerts); j++) {
+ xi = sk_X509_INFO_value(pcerts,j);
+ issuer = X509_get_issuer_name(xi->x509);
+ if (X509_NAME_cmp(issuer, xnx) == 0) {
+ cp = X509_NAME_oneline(X509_get_subject_name(xi->x509), NULL, 0);
+ ssl_log(s, SSL_LOG_DEBUG, "SSL Proxy: (%s) sending %s",
+ servername, cp != NULL ? cp : "-unknown-");
+ free(cp);
+ /* export structures to the caller */
+ *x509 = xi->x509;
+ *pkey = xi->x_pkey->dec_pkey;
+ /* prevent OpenSSL freeing these structures */
+ CRYPTO_add(&((*x509)->references), +1, CRYPTO_LOCK_X509_PKEY);
+ CRYPTO_add(&((*pkey)->references), +1, CRYPTO_LOCK_X509_PKEY);
+ return 1;
+ }
+ }
+ }
+ ssl_log(s, SSL_LOG_TRACE,
+ "Proxy client certificate callback: (%s) "
+ "no client certificate found!?", servername);
+ return 0;
+}
+
+/*
+ * This is the verify callback when we are connecting to a remote SSL server
+ * from the proxy. Information is passed in via the SSL "ctx" app_data
+ * mechanism. We pass in an Apache context in this field, which contains
+ * server_rec of the server making the proxy connection from the
+ * "ssl::proxy::server_rec" context.
+ *
+ * The result of the verification is passed back out to SSLERR via the return
+ * value. We also store the error message in the "proxyverifyfailed" context,
+ * so the caller of SSL_connect() can log a detailed error message.
+ */
+static int ssl_ext_mp_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+ SSLSrvConfigRec *sc;
+ X509 *xs;
+ int errnum;
+ int errdepth;
+ char *cp, *cp2;
+ ap_ctx *pCtx;
+ server_rec *s;
+ SSL *ssl;
+ char *peer;
+ char *servername;
+
+ ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx);
+ pCtx = (ap_ctx *)SSL_get_app_data(ssl);
+ s = ap_ctx_get(pCtx, "ssl::proxy::server_rec");
+ peer = ap_ctx_get(pCtx, "ssl::proxy::peer");
+ servername = ap_ctx_get(pCtx, "ssl::proxy::servername");
+ sc = mySrvConfig(s);
+
+ /*
+ * Get verify ingredients
+ */
+ xs = X509_STORE_CTX_get_current_cert(ctx);
+ errnum = X509_STORE_CTX_get_error(ctx);
+ errdepth = X509_STORE_CTX_get_error_depth(ctx);
+
+ /*
+ * Log verification information
+ */
+ cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0);
+ cp2 = X509_NAME_oneline(X509_get_issuer_name(xs), NULL, 0);
+ ssl_log(s, SSL_LOG_DEBUG,
+ "SSL Proxy: (%s) Certificate Verification for remote server %s: "
+ "depth: %d, subject: %s, issuer: %s",
+ servername, peer != NULL ? peer : "-unknown-",
+ errdepth, cp != NULL ? cp : "-unknown-",
+ cp2 != NULL ? cp2 : "-unknown");
+ free(cp);
+ free(cp2);
+
+ /*
+ * If we already know it's not ok, log the real reason
+ */
+ if (!ok) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "SSL Proxy: (%s) Certificate Verification failed for %s: "
+ "Error (%d): %s", servername,
+ peer != NULL ? peer : "-unknown-",
+ errnum, X509_verify_cert_error_string(errnum));
+ ap_ctx_set(pCtx, "ssl::proxy::verifyerror",
+ (void *)X509_verify_cert_error_string(errnum));
+ return ok;
+ }
+
+ /*
+ * Check the depth of the certificate chain
+ */
+ if (sc->nProxyVerifyDepth > 0) {
+ if (errdepth > sc->nProxyVerifyDepth) {
+ ssl_log(s, SSL_LOG_ERROR,
+ "SSL Proxy: (%s) Certificate Verification failed for %s: "
+ "Certificate Chain too long "
+ "(chain has %d certificates, but maximum allowed are only %d)",
+ servername, peer, errdepth, sc->nProxyVerifyDepth);
+ ap_ctx_set(pCtx, "ssl::proxy::verifyerror",
+ (void *)X509_verify_cert_error_string(X509_V_ERR_CERT_CHAIN_TOO_LONG));
+ ok = FALSE;
+ }
+ }
+
+ /*
+ * And finally signal OpenSSL the (perhaps changed) state
+ */
+ return (ok);
+}
+
+#endif /* SSL_EXPERIMENTAL */
/* _________________________________________________________________
**