]> granicus.if.org Git - apache/commitdiff
implement proxy client certificate callback
authorDoug MacEachern <dougm@apache.org>
Sat, 30 Mar 2002 05:40:02 +0000 (05:40 +0000)
committerDoug MacEachern <dougm@apache.org>
Sat, 30 Mar 2002 05:40:02 +0000 (05:40 +0000)
(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
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_kernel.c

index 85d628732b85d2a9ff0ebdde674ff22f8f94b68e..de1d46773b6364c6c2036235800b1dbe191b1a15 100644 (file)
@@ -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 *);
index 4aa4bd93668c6df59acf3b35b366684571dba1e4..5cf106837c8ac207bffca3adca177c09c3e2f0ec 100644 (file)
@@ -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 {
index efd745cedf3db47c9cf74d40ae7925ecf0f47d08..96ec929674d15aa979cec01200848f7388387d1c 100644 (file)
@@ -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,