You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2015/04/08 20:51:18 UTC

svn commit: r1672140 - in /tomcat/native/trunk/native: include/ssl_private.h src/sslcontext.c src/sslext.c src/sslnetwork.c

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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Re: svn commit: r1672140 - in /tomcat/native/trunk/native: include/ssl_private.h src/sslcontext.c src/sslext.c src/sslnetwork.c

Posted by Mark Thomas <ma...@apache.org>.
On 08/04/2015 19:51, markt@apache.org wrote:
> 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.

This is heavily based on a ALPN patch for HTTPD and Costin's SPDY work.

This works but as always when it comes to C code that I have put
together it needs careful review.

Mark

> 
> 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-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: dev-help@tomcat.apache.org
> 


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