On 08/04/2015 19:51, ma...@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-unsubscr...@tomcat.apache.org > For additional commands, e-mail: dev-h...@tomcat.apache.org > --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org