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