# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(10140); #workers(1); #log_level('warn'); repeat_each(2); # All these tests need to have new openssl my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); } else { plan tests => repeat_each() * (blocks() * 6 - 2) - 4; } no_long_string(); #no_diff(); env_to_nginx("PATH=" . $ENV{'PATH'}); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); run_tests(); __DATA__ === TEST 1: read SNI name via ssl.clienthello.get_client_hello_server_name() --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" print("read SNI name from Lua: ", ssl_clt.get_client_hello_server_name()) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" read SNI name from Lua: test.com --- no_error_log [error] [alert] === TEST 2: read SNI name via ssl.clienthello.get_client_hello_server_name() when no SNI name specified --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local name = ssl_clt.get_client_hello_server_name() print("read SNI name from Lua: ", name, ", type: ", type(name)) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log read SNI name from Lua: nil, type: nil --- no_error_log [error] [alert] [emerg] === TEST 3: read SNI name via ssl.clienthello.get_client_hello_ext() --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local byte = string.byte local ext = ssl_clt.get_client_hello_ext(0) if not ext then print("failed to get_client_hello_ext(0)") ngx.exit(ngx.ERROR) end local total_len = string.len(ext) if total_len <= 2 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end local len = byte(ext, 1) * 256 + byte(ext, 2) if len + 2 ~= total_len then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end if byte(ext, 3) ~= 0 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end if total_len <= 5 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end len = byte(ext, 4) * 256 + byte(ext, 5) if len + 5 > total_len then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end local name = string.sub(ext, 6, 6 + len -1) print("read SNI name from Lua: ", name) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" read SNI name from Lua: test.com --- no_error_log [error] [alert] === TEST 4: read SNI name via ssl.clienthello.get_client_hello_ext() when no SNI name specified --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ext = ssl_clt.get_client_hello_ext(0) print("read SNI name from Lua: ", ext, ", type: ", type(ext)) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log read SNI name from Lua: nil, type: nil --- no_error_log [error] [alert] [emerg] === TEST 5: dynamically set ssl protocol - allow TLSv1.2 --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ok = ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) if not ok then print("failed to set_protocols") ngx.exit(ngx.ERROR) end } ssl_protocols TLSv1 TLSv1.1; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1.2; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log eval [qr/SSL: TLSv1.2, cipher:/] --- no_error_log [error] [alert] [emerg] === TEST 6: dynamically set ssl protocol - allow TLSv1.3 --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ok = ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) if not ok then print("failed to set_protocols") ngx.exit(ngx.ERROR) end } ssl_protocols TLSv1 TLSv1.1; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1.3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log eval [qr/SSL: TLSv1.3, cipher:/] --- no_error_log [error] [alert] [emerg] === TEST 7: dynamically set ssl protocol - deny TLSv1.1 --- skip_nginx: 5: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ok = ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) if not ok then print("failed to set_protocols") ngx.exit(ngx.ERROR) end } ssl_protocols TLSv1 TLSv1.1; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1.1; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log eval [qr/SSL_do_handshake\(\) failed .*?tls_early_post_process_client_hello:unsupported protocol/] --- no_error_log [alert] [emerg] === TEST 8: dynamically set ssl protocol - deny TLSv1 --- skip_nginx: 5: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ok = ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) if not ok then print("failed to set_protocols") ngx.exit(ngx.ERROR) end } ssl_protocols TLSv1 TLSv1.1; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log eval [qr/SSL_do_handshake\(\) failed .*?tls_early_post_process_client_hello:unsupported protocol/] --- no_error_log [alert] [emerg] === TEST 9: get client hello supported versions - allow TLSv1.2 --- skip_nginx: 4: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local types, err = ssl_clt.get_supported_versions() if not err and types then for _, ssl_type in pairs(types) do if ssl_type == "TLSv1.2" then ngx.exit(ngx.OK) end end end ngx.log(ngx.ERR, "failed to get_supported_versions") ngx.exit(ngx.ERROR) } ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1 TLSv1.1 ; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log failed to get_supported_versions --- no_error_log [alert]