Skip to content

Commit

Permalink
Stream: the "ssl_alpn" directive.
Browse files Browse the repository at this point in the history
The directive sets the server list of supported application protocols
and requires one of this protocols to be negotiated if client is using
ALPN.

--HG--
branch : nginx
  • Loading branch information
vlhomutov committed Oct 19, 2021
1 parent 252f8ea commit 7429caf
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/event/ngx_event_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3133,6 +3133,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
#endif
#ifdef SSL_R_CALLBACK_FAILED
|| n == SSL_R_CALLBACK_FAILED /* 234 */
#endif
#ifdef SSL_R_NO_APPLICATION_PROTOCOL
|| n == SSL_R_NO_APPLICATION_PROTOCOL /* 235 */
#endif
|| n == SSL_R_UNEXPECTED_MESSAGE /* 244 */
|| n == SSL_R_UNEXPECTED_RECORD /* 245 */
Expand Down
117 changes: 117 additions & 0 deletions src/stream/ngx_stream_ssl_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c);
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg);
#endif
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
static int ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg);
#endif
#ifdef SSL_R_CERT_CB_ERROR
static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg);
#endif
Expand All @@ -45,6 +50,8 @@ static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);

static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post,
void *data);
Expand Down Expand Up @@ -211,6 +218,13 @@ static ngx_command_t ngx_stream_ssl_commands[] = {
offsetof(ngx_stream_ssl_conf_t, conf_commands),
&ngx_stream_ssl_conf_command_post },

{ ngx_string("ssl_alpn"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
ngx_stream_ssl_alpn,
NGX_STREAM_SRV_CONF_OFFSET,
0,
NULL },

ngx_null_command
};

Expand Down Expand Up @@ -446,6 +460,46 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
#endif


#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation

static int
ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned int inlen,
void *arg)
{
ngx_str_t *alpn;
#if (NGX_DEBUG)
unsigned int i;
ngx_connection_t *c;

c = ngx_ssl_get_connection(ssl_conn);

for (i = 0; i < inlen; i += in[i] + 1) {
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0,
"SSL ALPN supported by client: %*s",
(size_t) in[i], &in[i + 1]);
}

#endif

alpn = arg;

if (SSL_select_next_proto((unsigned char **) out, outlen, alpn->data,
alpn->len, in, inlen)
!= OPENSSL_NPN_NEGOTIATED)
{
return SSL_TLSEXT_ERR_ALERT_FATAL;
}

ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0,
"SSL ALPN selected: %*s", (size_t) *outlen, *out);

return SSL_TLSEXT_ERR_OK;
}

#endif


#ifdef SSL_R_CERT_CB_ERROR

int
Expand Down Expand Up @@ -605,6 +659,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf)
* scf->client_certificate = { 0, NULL };
* scf->trusted_certificate = { 0, NULL };
* scf->crl = { 0, NULL };
* scf->alpn = { 0, NULL };
* scf->ciphers = { 0, NULL };
* scf->shm_zone = NULL;
*/
Expand Down Expand Up @@ -663,6 +718,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_str_value(conf->trusted_certificate,
prev->trusted_certificate, "");
ngx_conf_merge_str_value(conf->crl, prev->crl, "");
ngx_conf_merge_str_value(conf->alpn, prev->alpn, "");

ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
NGX_DEFAULT_ECDH_CURVE);
Expand Down Expand Up @@ -723,6 +779,13 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_stream_ssl_servername);
#endif

#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if (conf->alpn.len) {
SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_stream_ssl_alpn_select,
&conf->alpn);
}
#endif

if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
conf->prefer_server_ciphers)
!= NGX_OK)
Expand Down Expand Up @@ -1059,6 +1122,60 @@ ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}


static char *
ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation

ngx_stream_ssl_conf_t *scf = conf;

u_char *p;
size_t len;
ngx_str_t *value;
ngx_uint_t i;

if (scf->alpn.len) {
return "is duplicate";
}

value = cf->args->elts;

len = 0;

for (i = 1; i < cf->args->nelts; i++) {

if (value[i].len > 255) {
return "protocol too long";
}

len += value[i].len + 1;
}

scf->alpn.data = ngx_pnalloc(cf->pool, len);
if (scf->alpn.data == NULL) {
return NGX_CONF_ERROR;
}

p = scf->alpn.data;

for (i = 1; i < cf->args->nelts; i++) {
*p++ = value[i].len;
p = ngx_cpymem(p, value[i].data, value[i].len);
}

scf->alpn.len = len;

return NGX_CONF_OK;

#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"ssl_alpn\" directive requires OpenSSL "
"with ALPN support");
return NGX_CONF_ERROR;
#endif
}


static char *
ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data)
{
Expand Down
1 change: 1 addition & 0 deletions src/stream/ngx_stream_ssl_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ typedef struct {
ngx_str_t client_certificate;
ngx_str_t trusted_certificate;
ngx_str_t crl;
ngx_str_t alpn;

ngx_str_t ciphers;

Expand Down

0 comments on commit 7429caf

Please sign in to comment.