Hello dev,

I have been working for a little while on making it possible to use
channel bindings within an Apache server.
In order to do that some support to extract information form the TLS
layer is necessary in the server.

The attached patch adds a new function call that modules can call in
order to obtain the channel binding data defined in RFC 5929.

I've tested that the patch works (at least for tls-server-end-point)
with the following:
- Apache 2.4.10 + patch
- mod_auth_gssapi [1] with support for the new function
- gss-ntlmssp [2]
- Internet Explorer on a modern Windows machine, performing
SPNEGO/GSSAPI/NTLMSSP auth + channel bindings

Any feedback is welcome,
Simo.


[1] https://github.com/modauthgssapi/mod_auth_gssapi
[2] https://fedorahosted.org/gss-ntlmssp/

-- 
Simo Sorce * Red Hat, Inc * New York
>From 2584c7e8ad22744a917052bb8c060bf138c9bc12 Mon Sep 17 00:00:00 2001
From: Simo Sorce <s...@redhat.com>
Date: Sun, 23 Mar 2014 14:14:01 -0400
Subject: [PATCH] Add function to get tls channel bindings (RFC5929)

This is needed to allow authentication modules to perform channel
binding to the outer TLS channel.
---
 modules/ssl/mod_ssl.h         |  8 ++++++
 modules/ssl/ssl_engine_vars.c | 67 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h
index 829fd1504a622257277939d9ce09e5818a719abc..fb6db9c24cd58d232c3c3715ef746965be4c5b5a 100644
--- a/modules/ssl/mod_ssl.h
+++ b/modules/ssl/mod_ssl.h
@@ -76,6 +76,14 @@ APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_ext_list,
  * is using SSL/TLS. */
 APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
 
+/** A function that returns the tls channel binding data as per
+ * RFC5929. A buffer containing the Channel Binding Token will be
+ * allocated on the pool and returned to the caller.
+ * On error DECLINED is returned and no buffer is allocated. */
+APR_DECLARE_OPTIONAL_FN(int, ssl_get_tls_cb,
+                        (apr_pool_t *p, conn_rec *, const char *,
+                         void **, apr_size_t *));
+
 /** The ssl_proxy_enable() and ssl_engine_disable() optional functions
  * are used by mod_proxy to enable use of SSL for outgoing
  * connections. */
diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c
index 97ff211d9cbfcbc675e97213fccf32950b292e6a..eef0434619218c2eed9bc574c4134dc2c2101a10 100644
--- a/modules/ssl/ssl_engine_vars.c
+++ b/modules/ssl/ssl_engine_vars.c
@@ -59,6 +59,72 @@ static int ssl_is_https(conn_rec *c)
     return sslconn && sslconn->ssl;
 }
 
+/* SSLv3 uses 36 bytes for Finishd messages, TLS1.0 12 bytes,
+ * So tls-unique is max 36 bytes, however with tls-server-end-point,
+ * the CB data is the certificate signature, so we use the maximum
+ * hash size known to the library (currently 64).
+ * */
+#define TLS_CB_MAX EVP_MAX_MD_SIZE
+#define TLS_UNIQUE_PREFIX "tls-unique:"
+#define TLS_SERVER_END_POINT_PREFIX "tls-server-end-point:"
+
+static int ssl_get_tls_cb(apr_pool_t *p, conn_rec *c, const char *type,
+                          void **buf, apr_size_t *size)
+{
+    SSLConnRec *sslconn = myConnConfig(c);
+    const char *prefix;
+    apr_size_t preflen;
+    const char *data;
+    char cb[TLS_CB_MAX];
+    char *retbuf;
+    apr_size_t l = 0;
+    X509 *x = NULL;
+
+    if (!sslconn || !sslconn->ssl) {
+        return APR_EGENERAL;
+    }
+    if (strcEQ(type, "SERVER_TLS_UNIQUE")) {
+        l = SSL_get_peer_finished(sslconn->ssl, cb, TLS_CB_MAX);
+    } else if (strcEQ(type, "CLIENT_TLS_UNIQUE")) {
+        l = SSL_get_finished(sslconn->ssl, cb, TLS_CB_MAX);
+    } else if (strcEQ(type, "SERVER_TLS_SERVER_END_POINT")) {
+        x = SSL_get_certificate(sslconn->ssl);
+    } else if (strcEQ(type, "CLIENT_TLS_SERVER_END_POINT")) {
+        x = SSL_get_peer_certificate(sslconn->ssl);
+    }
+    if (l > 0) {
+        preflen = sizeof(TLS_UNIQUE_PREFIX) -1;
+        prefix = TLS_UNIQUE_PREFIX;
+        data = cb;
+    } else if (x != NULL) {
+        const EVP_MD *md;
+
+        md = EVP_get_digestbynid(OBJ_obj2nid(x->sig_alg->algorithm));
+        if (md == NULL ||
+            md == EVP_md5() ||
+            md == EVP_sha1()) {
+            md = EVP_sha256();
+        }
+        if (!X509_digest(x, md, cb, &l)) {
+            return APR_EGENERAL;
+        }
+
+        preflen = sizeof(TLS_SERVER_END_POINT_PREFIX) - 1;
+        prefix = TLS_SERVER_END_POINT_PREFIX;
+        data = cb;
+    } else {
+        return APR_EGENERAL;
+    }
+
+    retbuf = apr_palloc(p, preflen + l);
+    memcpy(retbuf, prefix, preflen);
+    memcpy(&retbuf[preflen], data, l);
+    *size = preflen + l;
+    *buf = retbuf;
+
+    return APR_SUCCESS;
+}
+
 static const char var_interface[] = "mod_ssl/" AP_SERVER_BASEREVISION;
 static char var_library_interface[] = SSL_LIBRARY_TEXT;
 static char *var_library = NULL;
@@ -107,6 +173,7 @@ void ssl_var_register(apr_pool_t *p)
     char *cp, *cp2;
 
     APR_REGISTER_OPTIONAL_FN(ssl_is_https);
+    APR_REGISTER_OPTIONAL_FN(ssl_get_tls_cb);
     APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
     APR_REGISTER_OPTIONAL_FN(ssl_ext_list);
 
-- 
1.9.3

Reply via email to