Skip to content

Commit f671dc1

Browse files
committed
feature: ngx_http_lua_ffi_ssl_set_ciphers().
Sets the connection's TLS <= 1.2 cipher list and/or TLS 1.3 ciphersuites from ssl_client_hello_by_lua*, e.g. keyed on the client hello server name. Both strings are validated on a scratch SSL_CTX before being applied to the connection, because a failed SSL_set_cipher_list() still installs the parsed list on the connection (emptying the TLS <= 1.2 list on unknown tokens) and leaves the thread error queue dirty, which makes SSL_do_handshake() report failure after the callback returns. The guarantee: if ngx_http_lua_ffi_ssl_set_ciphers returns NGX_ERROR for an invalid ciphers and/or ciphersuites string, the connection's SSL object is left exactly as it was -- cipher list, ciphersuites, and thread error queue all untouched -- so the handshake proceeds with whatever the connection already had, which is the default list inherited from the vhost's SSL_CTX (ssl_ciphers/ssl_conf_command). See openssl/openssl#7759 for the check-after- install behaviour of SSL_set_cipher_list() and https://docs.openssl.org/3.0/man3/SSL_get_error/ for the empty-queue requirement.
1 parent bbed32a commit f671dc1

1 file changed

Lines changed: 81 additions & 0 deletions

File tree

‎src/ngx_http_lua_ssl_client_helloby.c‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,4 +838,85 @@ ngx_http_lua_ffi_ssl_set_protocols(ngx_http_request_t *r,
838838
return NGX_OK;
839839
}
840840

841+
842+
int
843+
ngx_http_lua_ffi_ssl_set_ciphers(ngx_http_request_t *r, const char *ciphers,
844+
const char *ciphersuites, char **err)
845+
{
846+
#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB
847+
ngx_ssl_conn_t *ssl_conn;
848+
849+
static SSL_CTX *scratch_ctx;
850+
851+
if (r->connection == NULL || r->connection->ssl == NULL) {
852+
*err = "bad request";
853+
return NGX_ERROR;
854+
}
855+
856+
ssl_conn = r->connection->ssl->connection;
857+
if (ssl_conn == NULL) {
858+
*err = "bad ssl conn";
859+
return NGX_ERROR;
860+
}
861+
862+
/*
863+
* a failed SSL_set_cipher_list() still installs the parsed list on the
864+
* connection and leaves the error queue dirty, which aborts the
865+
* handshake after the callback returns; validate on a scratch SSL_CTX
866+
* so failure is side-effect-free and callers can fall back to the
867+
* connection default
868+
*/
869+
870+
if (scratch_ctx == NULL) {
871+
scratch_ctx = SSL_CTX_new(TLS_method());
872+
if (scratch_ctx == NULL) {
873+
ERR_clear_error();
874+
*err = "SSL_CTX_new() failed";
875+
return NGX_ERROR;
876+
}
877+
}
878+
879+
if (ciphers != NULL && *ciphers != '\0') {
880+
if (SSL_CTX_set_cipher_list(scratch_ctx, ciphers) == 0) {
881+
ERR_clear_error();
882+
*err = "SSL_set_cipher_list() failed";
883+
return NGX_ERROR;
884+
}
885+
}
886+
887+
#ifdef TLS1_3_VERSION
888+
if (ciphersuites != NULL && *ciphersuites != '\0') {
889+
if (SSL_CTX_set_ciphersuites(scratch_ctx, ciphersuites) == 0) {
890+
ERR_clear_error();
891+
*err = "SSL_set_ciphersuites() failed";
892+
return NGX_ERROR;
893+
}
894+
}
895+
#endif
896+
897+
if (ciphers != NULL && *ciphers != '\0') {
898+
if (SSL_set_cipher_list(ssl_conn, ciphers) == 0) {
899+
ERR_clear_error();
900+
*err = "SSL_set_cipher_list() failed";
901+
return NGX_ERROR;
902+
}
903+
}
904+
905+
#ifdef TLS1_3_VERSION
906+
if (ciphersuites != NULL && *ciphersuites != '\0') {
907+
if (SSL_set_ciphersuites(ssl_conn, ciphersuites) == 0) {
908+
ERR_clear_error();
909+
*err = "SSL_set_ciphersuites() failed";
910+
return NGX_ERROR;
911+
}
912+
}
913+
#endif
914+
915+
return NGX_OK;
916+
#else
917+
*err = "OpenSSL too old to support this function";
918+
return NGX_ERROR;
919+
#endif
920+
}
921+
841922
#endif /* NGX_HTTP_SSL */

0 commit comments

Comments
 (0)