Author: markt
Date: Wed Apr  8 18:51:17 2015
New Revision: 1672140

URL: http://svn.apache.org/r1672140
Log:
First pass at native changes required to support ALPN.

Removed:
    tomcat/native/trunk/native/src/sslext.c
Modified:
    tomcat/native/trunk/native/include/ssl_private.h
    tomcat/native/trunk/native/src/sslcontext.c
    tomcat/native/trunk/native/src/sslnetwork.c

Modified: tomcat/native/trunk/native/include/ssl_private.h
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/native/include/ssl_private.h?rev=1672140&r1=1672139&r2=1672140&view=diff
==============================================================================
--- tomcat/native/trunk/native/include/ssl_private.h (original)
+++ tomcat/native/trunk/native/include/ssl_private.h Wed Apr  8 18:51:17 2015
@@ -256,10 +256,11 @@ struct tcn_ssl_ctxt_t {
     int             verify_mode;
     tcn_pass_cb_t   *cb_data;
 
-    /* for client: send request NPN.
-     * for server: accept requested NPN.
+    /* for client: List of protocols to request via ALPN.
+     * for server: List of protocols to accept via ALPN.
      */
-    char *npn;
+    char *alpn;
+    int alpnlen;
 };
 
   

Modified: tomcat/native/trunk/native/src/sslcontext.c
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslcontext.c?rev=1672140&r1=1672139&r2=1672140&view=diff
==============================================================================
--- tomcat/native/trunk/native/src/sslcontext.c (original)
+++ tomcat/native/trunk/native/src/sslcontext.c Wed Apr  8 18:51:17 2015
@@ -629,6 +629,153 @@ cleanup:
     return rv;
 }
 
+static int ssl_array_index(apr_array_header_t *array,
+                           const char *s)
+{
+    int i;
+    for (i = 0; i < array->nelts; i++) {
+        const char *p = APR_ARRAY_IDX(array, i, const char*);
+        if (!strcmp(p, s)) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static int ssl_cmp_alpn_protos(apr_array_header_t *array,
+                               const char *proto1,
+                               const char *proto2)
+{
+    int index1 = ssl_array_index(array, proto1);
+    int index2 = ssl_array_index(array, proto2);
+    if (index2 > index1) {
+        return (index1 >= 0)? 1 : -1;
+    }
+    else if (index1 > index2) {
+        return (index2 >= 0)? -1 : 1;
+    }
+
+    /* Both have the same index (-1 so neither listed by cient) compare
+     * the names so that spdy3 gets precedence over spdy2. That makes
+     * the outcome at least deterministic. */
+    return strcmp((const char *)proto1, (const char *)proto2);
+}
+
+/*
+ * This callback function is executed when the TLS Application Layer
+ * Protocol Negotiate Extension (ALPN, RFC 7301) is triggered by the client
+ * hello, giving a list of desired protocol names (in descending preference)
+ * to the server.
+ * The callback has to select a protocol name or return an error if none of
+ * the clients preferences is supported.
+ * The selected protocol does not have to be on the client list, according
+ * to RFC 7301, so no checks are performed.
+ * The client protocol list is serialized as length byte followed by ascii
+ * characters (not null-terminated), followed by the next protocol name.
+ */
+int cb_server_alpn(SSL *ssl,
+                   const unsigned char **out, unsigned char *outlen,
+                   const unsigned char *in, unsigned int inlen, void *arg)
+{
+    tcn_ssl_ctxt_t *tcsslctx = (tcn_ssl_ctxt_t *)arg;
+    tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)SSL_get_app_data(ssl);
+    apr_array_header_t *client_protos;
+    apr_array_header_t *proposed_protos;
+    int i;
+    unsigned short splen;
+
+    printf("inlen [%d]\n", inlen);
+    
+    if (inlen == 0) {
+        // Client specified an empty protocol list. Nothing to negotiate.
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+    
+    client_protos = apr_array_make(con->pool , 0, sizeof(char *));
+    for (i = 0; i < inlen; /**/) {
+        unsigned int plen = in[i++];
+        if (plen + i > inlen) {
+            // The protocol name extends beyond the declared length
+            // of the protocol list.
+            return SSL_TLSEXT_ERR_ALERT_FATAL;
+        }
+        APR_ARRAY_PUSH(client_protos, char*) = apr_pstrndup(con->pool, (const 
char *)in+i, plen);
+        i += plen;
+    }
+
+    if (tcsslctx->alpn == NULL) {
+        // Server supported protocol names not set.
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+    
+    if (tcsslctx->alpnlen == 0) {
+        // Server supported protocols is an empty list
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+    
+    printf("A\n");
+
+    proposed_protos = apr_array_make(con->pool, 0, sizeof(char *));
+    for (i = 0; i < tcsslctx->alpnlen; /**/) {
+        unsigned int plen = tcsslctx->alpn[i++];
+        if (plen + i > tcsslctx->alpnlen) {
+            // The protocol name extends beyond the declared length
+            // of the protocol list.
+            return SSL_TLSEXT_ERR_ALERT_FATAL;
+        }
+        APR_ARRAY_PUSH(proposed_protos, char*) = apr_pstrndup(con->pool, 
(const char *)tcsslctx->alpn+i, plen);
+        i += plen;
+    }
+    
+    printf("E\n");
+
+    if (proposed_protos->nelts <= 0) {
+        // Should never happen. The server did not specify any protocols.
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+    
+    /* Now select the most preferred protocol from the proposals. */
+    *out = APR_ARRAY_IDX(proposed_protos, 0, const unsigned char *);
+    for (i = 1; i < proposed_protos->nelts; ++i) {
+        const char *proto = APR_ARRAY_IDX(proposed_protos, i, const char*);
+        /* Do we prefer it over existing candidate? */
+        if (ssl_cmp_alpn_protos(client_protos, (const char *)*out, proto) < 0) 
{
+            *out = (const unsigned char*)proto;
+        }
+    }
+
+    printf("F\n");
+
+    size_t len = strlen((const char*)*out);
+    if (len > 255) {
+        // Agreed protocol name too long
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+    
+    *outlen = (unsigned char)len;
+
+    return SSL_TLSEXT_ERR_OK;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLContext, setALPN)(TCN_STDARGS, jlong ctx,
+                                          jbyteArray buf, jint len)
+{
+    tcn_ssl_ctxt_t *sslctx = J2P(ctx, tcn_ssl_ctxt_t *);
+    
+    sslctx->alpn = apr_pcalloc(sslctx->pool, len);
+    (*e)->GetByteArrayRegion(e, buf, 0, len, &sslctx->alpn[0]);
+    sslctx->alpnlen = len;
+    
+    if (sslctx->mode == SSL_MODE_SERVER) {
+        SSL_CTX_set_alpn_select_cb(sslctx->ctx, cb_server_alpn, sslctx);
+    } else {
+        // TODO: Implement client side call-back
+        // SSL_CTX_set_next_proto_select_cb(sslctx->ctx, cb_request_alpn, 
sslctx);
+        return APR_ENOTIMPL;
+    }
+    return 0;
+}
+
 #else
 /* OpenSSL is not supported.
  * Create empty stubs.
@@ -773,4 +920,13 @@ TCN_IMPLEMENT_CALL(jboolean, SSLContext,
     return JNI_FALSE;
 }
 
+TCN_IMPLEMENT_CALL(jint, SSLExt, setALPN)(TCN_STDARGS, jlong ctx,
+                                          jbyteArray buf, jint len)
+{
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(ctx);
+    UNREFERENCED(buf);
+    UNREFERENCED(len);
+    return APR_ENOTIMPL;
+}
 #endif

Modified: tomcat/native/trunk/native/src/sslnetwork.c
URL: 
http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslnetwork.c?rev=1672140&r1=1672139&r2=1672140&view=diff
==============================================================================
--- tomcat/native/trunk/native/src/sslnetwork.c (original)
+++ tomcat/native/trunk/native/src/sslnetwork.c Wed Apr  8 18:51:17 2015
@@ -686,6 +686,26 @@ TCN_IMPLEMENT_CALL(void, SSLSocket, setV
     SSL_set_verify(con->ssl, verify, NULL);
 }
 
+TCN_IMPLEMENT_CALL(jint, SSLSocket, getALPN)(TCN_STDARGS, jlong sock, 
jbyteArray buf)
+{
+    const unsigned char *alpn;
+    unsigned alpn_len;
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    tcn_ssl_conn_t *tcssl = (tcn_ssl_conn_t *)s->opaque;
+    int bufLen = (*e)->GetArrayLength(e, buf);
+    
+    SSL_get0_alpn_selected(tcssl->ssl, &alpn, &alpn_len);
+    
+    if (alpn_len == 0 || bufLen < alpn_len) {
+        return 0;
+    }
+    int len = alpn_len;
+    (*e)->SetByteArrayRegion(e, buf, 0, len, alpn);
+    
+    return len;
+}
+
+
 #else
 /* OpenSSL is not supported.
  * Create empty stubs.
@@ -715,4 +735,11 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, rene
     return (jint)APR_ENOTIMPL;
 }
 
+TCN_IMPLEMENT_CALL(jint, SSLSocket, getALPN)(TCN_STDARGS, jlong sock, 
jbyteArray buf)
+{
+    UNREFERENCED(sock);
+    UNREFERENCED(buf);
+    return (jint)APR_ENOTIMPL;
+}
+
 #endif



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to