Mercurial > hg > nginx
comparison src/stream/ngx_stream_ssl_module.c @ 7936:b9e02e9b2f1d
Stream: the "ssl_alpn" directive.
The directive sets the server list of supported application protocols
and requires one of this protocols to be negotiated if client is using
ALPN.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Tue, 19 Oct 2021 12:19:59 +0300 |
parents | eb6c77e6d55d |
children | 46a02ed7c966 |
comparison
equal
deleted
inserted
replaced
7935:eb6c77e6d55d | 7936:b9e02e9b2f1d |
---|---|
22 static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, | 22 static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, |
23 ngx_connection_t *c); | 23 ngx_connection_t *c); |
24 static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); | 24 static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); |
25 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME | 25 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
26 int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); | 26 int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); |
27 #endif | |
28 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation | |
29 static int ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, | |
30 const unsigned char **out, unsigned char *outlen, | |
31 const unsigned char *in, unsigned int inlen, void *arg); | |
27 #endif | 32 #endif |
28 #ifdef SSL_R_CERT_CB_ERROR | 33 #ifdef SSL_R_CERT_CB_ERROR |
29 static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); | 34 static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); |
30 #endif | 35 #endif |
31 static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, | 36 static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, |
42 ngx_stream_ssl_conf_t *conf); | 47 ngx_stream_ssl_conf_t *conf); |
43 | 48 |
44 static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, | 49 static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, |
45 void *conf); | 50 void *conf); |
46 static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, | 51 static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, |
52 void *conf); | |
53 static char *ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, | |
47 void *conf); | 54 void *conf); |
48 | 55 |
49 static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, | 56 static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, |
50 void *data); | 57 void *data); |
51 | 58 |
208 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, | 215 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, |
209 ngx_conf_set_keyval_slot, | 216 ngx_conf_set_keyval_slot, |
210 NGX_STREAM_SRV_CONF_OFFSET, | 217 NGX_STREAM_SRV_CONF_OFFSET, |
211 offsetof(ngx_stream_ssl_conf_t, conf_commands), | 218 offsetof(ngx_stream_ssl_conf_t, conf_commands), |
212 &ngx_stream_ssl_conf_command_post }, | 219 &ngx_stream_ssl_conf_command_post }, |
220 | |
221 { ngx_string("ssl_alpn"), | |
222 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, | |
223 ngx_stream_ssl_alpn, | |
224 NGX_STREAM_SRV_CONF_OFFSET, | |
225 0, | |
226 NULL }, | |
213 | 227 |
214 ngx_null_command | 228 ngx_null_command |
215 }; | 229 }; |
216 | 230 |
217 | 231 |
444 } | 458 } |
445 | 459 |
446 #endif | 460 #endif |
447 | 461 |
448 | 462 |
463 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation | |
464 | |
465 static int | |
466 ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, | |
467 unsigned char *outlen, const unsigned char *in, unsigned int inlen, | |
468 void *arg) | |
469 { | |
470 ngx_str_t *alpn; | |
471 #if (NGX_DEBUG) | |
472 unsigned int i; | |
473 ngx_connection_t *c; | |
474 | |
475 c = ngx_ssl_get_connection(ssl_conn); | |
476 | |
477 for (i = 0; i < inlen; i += in[i] + 1) { | |
478 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, | |
479 "SSL ALPN supported by client: %*s", | |
480 (size_t) in[i], &in[i + 1]); | |
481 } | |
482 | |
483 #endif | |
484 | |
485 alpn = arg; | |
486 | |
487 if (SSL_select_next_proto((unsigned char **) out, outlen, alpn->data, | |
488 alpn->len, in, inlen) | |
489 != OPENSSL_NPN_NEGOTIATED) | |
490 { | |
491 return SSL_TLSEXT_ERR_ALERT_FATAL; | |
492 } | |
493 | |
494 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, | |
495 "SSL ALPN selected: %*s", (size_t) *outlen, *out); | |
496 | |
497 return SSL_TLSEXT_ERR_OK; | |
498 } | |
499 | |
500 #endif | |
501 | |
502 | |
449 #ifdef SSL_R_CERT_CB_ERROR | 503 #ifdef SSL_R_CERT_CB_ERROR |
450 | 504 |
451 int | 505 int |
452 ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) | 506 ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) |
453 { | 507 { |
603 * scf->dhparam = { 0, NULL }; | 657 * scf->dhparam = { 0, NULL }; |
604 * scf->ecdh_curve = { 0, NULL }; | 658 * scf->ecdh_curve = { 0, NULL }; |
605 * scf->client_certificate = { 0, NULL }; | 659 * scf->client_certificate = { 0, NULL }; |
606 * scf->trusted_certificate = { 0, NULL }; | 660 * scf->trusted_certificate = { 0, NULL }; |
607 * scf->crl = { 0, NULL }; | 661 * scf->crl = { 0, NULL }; |
662 * scf->alpn = { 0, NULL }; | |
608 * scf->ciphers = { 0, NULL }; | 663 * scf->ciphers = { 0, NULL }; |
609 * scf->shm_zone = NULL; | 664 * scf->shm_zone = NULL; |
610 */ | 665 */ |
611 | 666 |
612 scf->handshake_timeout = NGX_CONF_UNSET_MSEC; | 667 scf->handshake_timeout = NGX_CONF_UNSET_MSEC; |
661 ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, | 716 ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, |
662 ""); | 717 ""); |
663 ngx_conf_merge_str_value(conf->trusted_certificate, | 718 ngx_conf_merge_str_value(conf->trusted_certificate, |
664 prev->trusted_certificate, ""); | 719 prev->trusted_certificate, ""); |
665 ngx_conf_merge_str_value(conf->crl, prev->crl, ""); | 720 ngx_conf_merge_str_value(conf->crl, prev->crl, ""); |
721 ngx_conf_merge_str_value(conf->alpn, prev->alpn, ""); | |
666 | 722 |
667 ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, | 723 ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, |
668 NGX_DEFAULT_ECDH_CURVE); | 724 NGX_DEFAULT_ECDH_CURVE); |
669 | 725 |
670 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); | 726 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); |
721 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME | 777 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
722 SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx, | 778 SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx, |
723 ngx_stream_ssl_servername); | 779 ngx_stream_ssl_servername); |
724 #endif | 780 #endif |
725 | 781 |
782 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation | |
783 if (conf->alpn.len) { | |
784 SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_stream_ssl_alpn_select, | |
785 &conf->alpn); | |
786 } | |
787 #endif | |
788 | |
726 if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, | 789 if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, |
727 conf->prefer_server_ciphers) | 790 conf->prefer_server_ciphers) |
728 != NGX_OK) | 791 != NGX_OK) |
729 { | 792 { |
730 return NGX_CONF_ERROR; | 793 return NGX_CONF_ERROR; |
1058 return NGX_CONF_ERROR; | 1121 return NGX_CONF_ERROR; |
1059 } | 1122 } |
1060 | 1123 |
1061 | 1124 |
1062 static char * | 1125 static char * |
1126 ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
1127 { | |
1128 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation | |
1129 | |
1130 ngx_stream_ssl_conf_t *scf = conf; | |
1131 | |
1132 u_char *p; | |
1133 size_t len; | |
1134 ngx_str_t *value; | |
1135 ngx_uint_t i; | |
1136 | |
1137 if (scf->alpn.len) { | |
1138 return "is duplicate"; | |
1139 } | |
1140 | |
1141 value = cf->args->elts; | |
1142 | |
1143 len = 0; | |
1144 | |
1145 for (i = 1; i < cf->args->nelts; i++) { | |
1146 | |
1147 if (value[i].len > 255) { | |
1148 return "protocol too long"; | |
1149 } | |
1150 | |
1151 len += value[i].len + 1; | |
1152 } | |
1153 | |
1154 scf->alpn.data = ngx_pnalloc(cf->pool, len); | |
1155 if (scf->alpn.data == NULL) { | |
1156 return NGX_CONF_ERROR; | |
1157 } | |
1158 | |
1159 p = scf->alpn.data; | |
1160 | |
1161 for (i = 1; i < cf->args->nelts; i++) { | |
1162 *p++ = value[i].len; | |
1163 p = ngx_cpymem(p, value[i].data, value[i].len); | |
1164 } | |
1165 | |
1166 scf->alpn.len = len; | |
1167 | |
1168 return NGX_CONF_OK; | |
1169 | |
1170 #else | |
1171 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1172 "the \"ssl_alpn\" directive requires OpenSSL " | |
1173 "with ALPN support"); | |
1174 return NGX_CONF_ERROR; | |
1175 #endif | |
1176 } | |
1177 | |
1178 | |
1179 static char * | |
1063 ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) | 1180 ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) |
1064 { | 1181 { |
1065 #ifndef SSL_CONF_FLAG_FILE | 1182 #ifndef SSL_CONF_FLAG_FILE |
1066 return "is not supported on this platform"; | 1183 return "is not supported on this platform"; |
1067 #else | 1184 #else |