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