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: [email protected]
For additional commands, e-mail: [email protected]