"OpenSSL configuration command")
#endif
+#if defined(HAVE_TLS_ALPN) || defined(HAVE_TLS_NPN)
+ SSL_CMD_SRV(AlpnPreference, ITERATE,
+ "Preference in Application-Layer Protocol Negotiation (ALPN), "
+ "protocols are chosed in the specified order")
+#endif
+
/* Deprecated directives. */
AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL,
"SSLLog directive is no longer supported - use ErrorLog."),
#endif
}
+static int modssl_register_alpn(conn_rec *c,
+ ssl_alpn_propose_protos advertisefn,
+ ssl_alpn_proto_negotiated negotiatedfn)
+{
+#if defined(HAVE_TLS_ALPN) || defined(HAVE_TLS_NPN)
+ SSLConnRec *sslconn = myConnConfig(c);
+
+ if (!sslconn) {
+ return DECLINED;
+ }
+
+ if (!sslconn->alpn_proposefns) {
+ sslconn->alpn_proposefns =
+ apr_array_make(c->pool, 5, sizeof(ssl_alpn_propose_protos));
+ sslconn->alpn_negofns =
+ apr_array_make(c->pool, 5, sizeof(ssl_alpn_proto_negotiated));
+ }
+
+ if (advertisefn)
+ APR_ARRAY_PUSH(sslconn->alpn_proposefns, ssl_alpn_propose_protos) =
+ advertisefn;
+ if (negotiatedfn)
+ APR_ARRAY_PUSH(sslconn->alpn_negofns, ssl_alpn_proto_negotiated) =
+ negotiatedfn;
+
+ return OK;
+#else
+ return DECLINED;
+#endif
+}
+
int ssl_init_ssl_connection(conn_rec *c, request_rec *r)
{
SSLSrvConfigRec *sc;
APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
APR_REGISTER_OPTIONAL_FN(modssl_register_npn);
+ APR_REGISTER_OPTIONAL_FN(modssl_register_alpn);
ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl",
AUTHZ_PROVIDER_VERSION,
ssl_npn_advertise_protos advertisefn,
ssl_npn_proto_negotiated negotiatedfn));
+/** The alpn_propose_proto callback allows other modules to propose
+ * the name of the protocol that will be chosen during the
+ * Application-Layer Protocol Negotiation (ALPN) portion of the SSL handshake.
+ * The callback is given the connection and a list of NULL-terminated
+ * protocol strings as supported by the client. If this client_protos is
+ * non-empty, it must pick its preferred protocol from that list. Otherwise
+ * it should add its supported protocols in order of precedence.
+ * The callback should not yet modify the connection or install any filters
+ * as its proposal(s) may be overridden by another callback or server
+ * configuration.
+ * It should return OK or, to prevent further processing of (other modules')
+ * callbacks, return DONE.
+ */
+typedef int (*ssl_alpn_propose_protos)(conn_rec *connection,
+ apr_array_header_t *client_protos,
+ apr_array_header_t *proposed_protos);
+
+/** The alpn_proto_negotiated callback allows other modules to discover
+ * the name of the protocol that was chosen during the Application-Layer
+ * Protocol Negotiation (ALPN) portion of the SSL handshake.
+ * The callback is given the connection, a
+ * non-NUL-terminated string containing the protocol name, and the
+ * length of the string; it should do something appropriate
+ * (i.e. insert or remove filters) and return OK. To prevent further
+ * processing of (other modules') callbacks, return DONE. */
+typedef int (*ssl_alpn_proto_negotiated)(conn_rec *connection,
+ const char *proto_name,
+ apr_size_t proto_name_len);
+
+/* An optional function which can be used to register a pair of callbacks
+ * for ALPN handling.
+ * This optional function should be invoked from a pre_connection hook
+ * which runs *after* mod_ssl.c's pre_connection hook. The function returns
+ * OK if the callbacks are registered, or DECLINED otherwise (for example if
+ * mod_ssl does not support ALPN).
+ */
+APR_DECLARE_OPTIONAL_FN(int, modssl_register_alpn,
+ (conn_rec *conn,
+ ssl_alpn_propose_protos proposefn,
+ ssl_alpn_proto_negotiated negotiatedfn));
+
#endif /* __MOD_SSL_H__ */
/** @} */
SSL_CONF_CTX_set_flags(mctx->ssl_ctx_config, SSL_CONF_FLAG_CERTIFICATE);
mctx->ssl_ctx_param = apr_array_make(p, 5, sizeof(ssl_ctx_param_t));
#endif
+#if defined(HAVE_TLS_ALPN) || defined(HAVE_TLS_NPN)
+ mctx->ssl_alpn_pref = apr_array_make(p, 5, sizeof(const char *));
+#endif
}
static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc,
#ifdef HAVE_SSL_CONF_CMD
cfgMergeArray(ssl_ctx_param);
#endif
+#if defined(HAVE_TLS_ALPN) || defined(HAVE_TLS_NPN)
+ cfgMergeArray(ssl_alpn_pref);
+#endif
}
static void modssl_ctx_cfg_merge_proxy(apr_pool_t *p,
}
#endif
+#if defined(HAVE_TLS_ALPN) || defined(HAVE_TLS_NPN)
+const char *ssl_cmd_SSLAlpnPreference(cmd_parms *cmd, void *dcfg,
+ const char *protocol)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ APR_ARRAY_PUSH(sc->server->ssl_alpn_pref, const char *) = protocol;
+ return NULL;
+}
+#endif
+
#ifdef HAVE_SRP
const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg,
char buffer[AP_IOBUFSIZE];
ssl_filter_ctx_t *filter_ctx;
int npn_finished; /* 1 if NPN has finished, 0 otherwise */
+ int alpn_finished; /* 1 if ALPN has finished, 0 otherwise */
} bio_filter_in_ctx_t;
/*
APR_BRIGADE_INSERT_TAIL(bb, bucket);
}
+#ifdef HAVE_TLS_ALPN
+ /* By this point, Application-Layer Protocol Negotiation (ALPN) should be
+ * completed (if our version of OpenSSL supports it). If we haven't already,
+ * find out which protocol was decided upon and inform other modules
+ * by calling alpn_proto_negotiated_hook.
+ */
+ if (!inctx->alpn_finished) {
+ SSLConnRec *sslconn = myConnConfig(f->c);
+ const unsigned char *next_proto = NULL;
+ unsigned next_proto_len = 0;
+ int n;
+
+ if (sslconn->alpn_negofns) {
+ SSL_get0_alpn_selected(inctx->ssl, &next_proto, &next_proto_len);
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, f->c,
+ APLOGNO() "SSL negotiated protocol: '%s'",
+ (next_proto && next_proto_len)?
+ apr_pstrmemdup(f->c->pool, (const char *)next_proto,
+ next_proto_len) : "(null)");
+ for (n = 0; n < sslconn->alpn_negofns->nelts; n++) {
+ ssl_alpn_proto_negotiated fn =
+ APR_ARRAY_IDX(sslconn->alpn_negofns, n, ssl_alpn_proto_negotiated);
+
+ if (fn(f->c, (const char *)next_proto, next_proto_len) == DONE)
+ break;
+ }
+ }
+ inctx->alpn_finished = 1;
+ }
+#endif
+
#ifdef HAVE_TLS_NPN
/* By this point, Next Protocol Negotiation (NPN) should be completed (if
* our version of OpenSSL supports it). If we haven't already, find out
inctx->pool = c->pool;
inctx->filter_ctx = filter_ctx;
inctx->npn_finished = 0;
+ inctx->alpn_finished = 0;
}
/* The request_rec pointer is passed in here only to ensure that the
#define HAVE_TLS_NPN
#endif
+/* ALPN Protocol Negotiation */
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_TLSEXT)
+#define HAVE_TLS_ALPN
+#endif
+
+/* Next Protocol Negotiation */
+#if !defined(OPENSSL_NO_NEXTPROTONEG) && !defined(OPENSSL_NO_TLSEXT) && defined(OPENSSL_NPN_NEGOTIATED)
+#define HAVE_TLS_NPN
+#endif
+
/* Secure Remote Password */
#if !defined(OPENSSL_NO_SRP) && defined(SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB)
#define HAVE_SRP
apr_array_header_t *npn_negofns; /* list of ssl_npn_proto_negotiated callbacks. */
#endif
+#if defined(HAVE_TLS_ALPN) || defined(HAVE_TLS_NPN)
+ /* Poor man's inter-module optional hooks for NPN. */
+ apr_array_header_t *alpn_proposefns; /* list of ssl_alpn_propose_protos callbacks */
+ apr_array_header_t *alpn_negofns; /* list of ssl_alpn_proto_negotiated callbacks. */
+#endif
+
server_rec *server;
} SSLConnRec;
SSL_CONF_CTX *ssl_ctx_config; /* Configuration context */
apr_array_header_t *ssl_ctx_param; /* parameters to pass to SSL_CTX */
#endif
+
+#if defined(HAVE_TLS_ALPN) || defined(HAVE_TLS_NPN)
+ apr_array_header_t *ssl_alpn_pref; /* protocol names in order of preference */
+#endif
} modssl_ctx_t;
struct SSLSrvConfigRec {
const char *ssl_cmd_SSLOpenSSLConfCmd(cmd_parms *cmd, void *dcfg, const char *arg1, const char *arg2);
#endif
+#if defined(HAVE_TLS_ALPN) || defined(HAVE_TLS_NPN)
+const char *ssl_cmd_SSLAlpnPreference(cmd_parms *cmd, void *dcfg, const char *protocol);
+#endif
+
#ifdef HAVE_SRP
const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg);
const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char *arg);
#endif
int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg);
+#ifdef HAVE_TLS_ALPN
+int ssl_callback_alpn_select(SSL *ssl, const unsigned char **out,
+ unsigned char *outlen, const unsigned char *in,
+ unsigned int inlen, void *arg);
+#endif
+#if defined(HAVE_TLS_NPN)
+int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg);
+#endif
+
/** Session Cache Support */
apr_status_t ssl_scache_init(server_rec *, apr_pool_t *);
void ssl_scache_status_register(apr_pool_t *p);