diff --git a/README.markdown b/README.markdown index dd864f1..882ba82 100644 --- a/README.markdown +++ b/README.markdown @@ -54,8 +54,13 @@ http { local ok, err = hc.spawn_checker{ shm = "healthcheck", -- defined by "lua_shared_dict" upstream = "foo.com", -- defined by "upstream" + type = "http", - + -- type = "https", + -- ssl_verify = true, -- verify SSL certs + -- ssl_server_name = "custom_server_name" -- if given, will be passed to tcpsock:sslhandshake as server_name instead of peer.name + -- ssl_reuse_session = true, -- this makes sure SSL session will be reused + http_req = "GET /status HTTP/1.0\r\nHost: foo.com\r\n\r\n", -- raw HTTP request for checking diff --git a/lib/resty/upstream/healthcheck.lua b/lib/resty/upstream/healthcheck.lua index 2118282..6f27de9 100644 --- a/lib/resty/upstream/healthcheck.lua +++ b/lib/resty/upstream/healthcheck.lua @@ -20,7 +20,7 @@ local wait = ngx.thread.wait local pcall = pcall local _M = { - _VERSION = '0.03' + _VERSION = '0.05' } if not ngx.config @@ -230,16 +230,29 @@ local function check_peer(ctx, id, peer, is_backup) ok, err = sock:connect(name) end if not ok then - if not peer.down then - errlog("failed to connect to ", name, ": ", err) + return peer_error(ctx, is_backup, id, peer, + "failed to connect to ", name, ": ", err) + end + + if ctx.type == "https" then + local session, err = sock:sslhandshake(ctx.session, + ctx.ssl_server_name or name, + ctx.ssl_verify) + if not session then + peer_error(ctx, is_backup, id, peer, + "failed to do SSL handshake: ", name, ": ", err) + return sock:close() + end + if ctx.ssl_reuse_session then + ctx.session = session end - return peer_fail(ctx, is_backup, id, peer) end local bytes, err = sock:send(req) if not bytes then - return peer_error(ctx, is_backup, id, peer, - "failed to send request to ", name, ": ", err) + peer_error(ctx, is_backup, id, peer, + "failed to send request to ", name, ": ", err) + return sock:close() end local status_line, err = sock:receive() @@ -260,16 +273,15 @@ local function check_peer(ctx, id, peer, is_backup) peer_error(ctx, is_backup, id, peer, "bad status line from ", name, ": ", status_line) - sock:close() - return + return sock:close() end local status = tonumber(sub(status_line, from, to)) if not statuses[status] then - peer_error(ctx, is_backup, id, peer, "bad status code from ", - name, ": ", status) - sock:close() - return + peer_error(ctx, is_backup, id, peer, + "bad status code from ", name, ": ", + status) + return sock:close() end end @@ -530,10 +542,14 @@ function _M.spawn_checker(opts) return nil, "\"type\" option required" end - if typ ~= "http" then - return nil, "only \"http\" type is supported right now" + if typ ~= "http" and typ ~= "https" then + return nil, "no support for this protocol type" end + local ssl_verify = opts.ssl_verify and true + + local ssl_reuse_session = opts.ssl_reuse_session and true + local http_req = opts.http_req if not http_req then return nil, "\"http_req\" option required" @@ -611,6 +627,10 @@ function _M.spawn_checker(opts) upstream = u, primary_peers = preprocess_peers(ppeers), backup_peers = preprocess_peers(bpeers), + type = typ, + ssl_verify = ssl_verify, + ssl_reuse_session = ssl_reuse_session, + ssl_server_name = opts.ssl_server_name, http_req = http_req, timeout = timeout, interval = interval, @@ -620,6 +640,7 @@ function _M.spawn_checker(opts) statuses = statuses, version = 0, concurrency = concur, + session = nil, } local ok, err = new_timer(0, check, ctx) @@ -701,4 +722,67 @@ function _M.status_page() return concat(bits) end +local function gen_peers_status_table(dict, peers, name, is_backup) + local npeers = #peers + + for i = 1, npeers do + local peer = peers[i] + + local oks, err = dict:get(gen_peer_key("ok:", name, is_backup, i - 1)) + if oks then + peer.checks_ok = oks + if oks > 0 then + peer.unhealthy = false + peer.checks_fail = 0 + end + end + + if peer.unhealthy == nil then + local key = gen_peer_key("nok:", name, is_backup, i - 1) + local fails, err = dict:get(key) + if fails then + peer.checks_fail = fails + if fails > 0 then + peer.unhealthy = true + peer.checks_ok = 0 + end + end + end + end +end + +function _M.status_table(shm) + local result = {} + local dict = shared[shm] + + local us, err = get_upstreams() + if not us then + return nil, "failed to get upstream names: " .. err + end + + local n = #us + for i = 1, n do + local u = us[i] + + local ppeers, err = get_primary_peers(u) + if not ppeers then + return nil, "failed to get primary peers: " .. err + end + gen_peers_status_table(dict, ppeers, u, false) + + local bpeers, err = get_backup_peers(u) + if not bpeers then + return nil, "failed to get backup peers: " .. err + end + gen_peers_status_table(dict, bpeers, u, true) + + result[u] = { + primary_peers = ppeers, + backup_peers = bpeers, + } + end + + return result +end + return _M diff --git a/t/sanity.t b/t/sanity.t index 31df7f6..7b501d7 100644 --- a/t/sanity.t +++ b/t/sanity.t @@ -9,7 +9,7 @@ use Cwd qw(cwd); #repeat_each(2); -plan tests => repeat_each() * (blocks() * 6 + 9); +plan tests => repeat_each() * (blocks() * 6 - 18); my $pwd = cwd(); @@ -1372,3 +1372,597 @@ healthcheck: peer \[0:0::1\]:12356 was checked to be ok ){3,7}$/ --- timeout: 6 --- skip_eval: 8: system("ping6 -c 1 ::1 >/dev/null 2>&1") ne 0 + + + +=== TEST 15: SSL health check without server certificate verification +--- http_config eval +"$::HttpConfig" +. q{ +upstream foo.com { + server 127.0.0.1:12355; +} + +server { + listen 12355; + ssl on; + ssl_certificate ../../ssl/nginx.crt; + ssl_certificate_key ../../ssl/nginx.key; + location = /status { + return 200; + } +} + +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = "foo.com", + type = "https", + ssl_reuse_session = true, + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + + local hc = require "resty.upstream.healthcheck" + ngx.print(hc.status_page()) + } + } +--- request +GET /t + +--- response_body +Upstream foo.com + Primary Peers + 127.0.0.1:12355 up + Backup Peers + +--- error_log +SSL reused session + + + +=== TEST 16: normal health check against SSL only upstream +--- http_config eval +"$::HttpConfig" +. q{ +upstream foo.com { + server 127.0.0.1:12355; +} + +server { + listen 12355; + ssl on; + ssl_certificate ../../ssl/nginx.crt; + ssl_certificate_key ../../ssl/nginx.key; + location = /status { + return 200; + } +} + +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = "foo.com", + type = "http", + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + + local hc = require "resty.upstream.healthcheck" + ngx.print(hc.status_page()) + } + } +--- request +GET /t + +--- response_body +Upstream foo.com + Primary Peers + 127.0.0.1:12355 DOWN + Backup Peers + +--- error_log +healthcheck: bad status code from 127.0.0.1:12355: 400, context: ngx.timer + + + +=== TEST 17: SSL health check with server certificate verification +--- http_config eval +"$::HttpConfig" +. q{ +lua_ssl_trusted_certificate ../../ssl/nginx.crt; + +upstream foo.com { + server 127.0.0.1:12355; +} + +server { + listen 12355; + ssl on; + ssl_certificate ../../ssl/nginx.crt; + ssl_certificate_key ../../ssl/nginx.key; + location = /status { + return 200; + } +} + +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = "foo.com", + type = "https", + ssl_verify = true, + ssl_reuse_session = true, + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + + local hc = require "resty.upstream.healthcheck" + ngx.print(hc.status_page()) + } + } +--- request +GET /t + +--- response_body +Upstream foo.com + Primary Peers + 127.0.0.1:12355 up + Backup Peers + +--- error_log +SSL reused session + + + +=== TEST 18: SSL health check with server certificate verification, failure scenario +--- http_config eval +"$::HttpConfig" +. q{ +lua_ssl_trusted_certificate ../../ssl/nginx_other.crt; + +upstream foo.com { + server 127.0.0.1:12355; +} + +server { + listen 12355; + ssl on; + ssl_certificate ../../ssl/nginx.crt; + ssl_certificate_key ../../ssl/nginx.key; + location = /status { + return 200; + } +} + +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = "foo.com", + type = "https", + ssl_verify = true, + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + + local hc = require "resty.upstream.healthcheck" + ngx.print(hc.status_page()) + } + } +--- request +GET /t + +--- response_body +Upstream foo.com + Primary Peers + 127.0.0.1:12355 DOWN + Backup Peers + +--- error_log +healthcheck: failed to do SSL handshake: 127.0.0.1:12355: 18: self signed certificate, context: ngx.timer + + + +=== TEST 19: SSL health check without session reuse +--- http_config eval +"$::HttpConfig" +. q{ +upstream foo.com { + server 127.0.0.1:12355; +} + +server { + listen 12355; + ssl on; + ssl_certificate ../../ssl/nginx.crt; + ssl_certificate_key ../../ssl/nginx.key; + location = /status { + return 200; + } +} + +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = "foo.com", + type = "https", + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + + local hc = require "resty.upstream.healthcheck" + ngx.print(hc.status_page()) + } + } +--- request +GET /t + +--- response_body +Upstream foo.com + Primary Peers + 127.0.0.1:12355 up + Backup Peers + +--- no_error_log +SSL reused session + + + +=== TEST 20: SSL health check with certificate created with a different server name should work when ssl_verify is false +--- http_config eval +"$::HttpConfig" +. q{ +lua_ssl_trusted_certificate ../../ssl/foo_bar.crt; + +upstream foo.com { + server 127.0.0.1:12355; +} + +server { + listen 12355; + ssl on; + ssl_certificate ../../ssl/foo_bar.crt; + ssl_certificate_key ../../ssl/foo_bar.key; + location = /status { + return 200; + } +} + +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = "foo.com", + type = "https", + ssl_verify = false, + ssl_reuse_session = true, + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + + local hc = require "resty.upstream.healthcheck" + ngx.print(hc.status_page()) + } + } +--- request +GET /t + +--- response_body +Upstream foo.com + Primary Peers + 127.0.0.1:12355 up + Backup Peers + +--- error_log +SSL reused session + +--- no_error_log +certificate host mismatch + + + +=== TEST 21: SSL health check with certificate created with a different server name should fail when ssl_verify is true +--- http_config eval +"$::HttpConfig" +. q{ +lua_ssl_trusted_certificate ../../ssl/foo_bar.crt; + +upstream foo.com { + server 127.0.0.1:12355; +} + +server { + listen 12355; + ssl on; + ssl_certificate ../../ssl/foo_bar.crt; + ssl_certificate_key ../../ssl/foo_bar.key; + location = /status { + return 200; + } +} + +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = "foo.com", + type = "https", + ssl_verify = true, + ssl_reuse_session = true, + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + + local hc = require "resty.upstream.healthcheck" + ngx.print(hc.status_page()) + } + } +--- request +GET /t + +--- response_body +Upstream foo.com + Primary Peers + 127.0.0.1:12355 DOWN + Backup Peers + +--- error_log +certificate host mismatch + + + +=== TEST 22: SSL health check with certificate created with a different server name should work when ssl_verify is true and correct server name is given +--- http_config eval +"$::HttpConfig" +. q{ +lua_ssl_trusted_certificate ../../ssl/foo_bar.crt; + +upstream foo.com { + server 127.0.0.1:12355; +} + +server { + listen 12355; + ssl on; + ssl_certificate ../../ssl/foo_bar.crt; + ssl_certificate_key ../../ssl/foo_bar.key; + location = /status { + return 200; + } +} + +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = "foo.com", + type = "https", + ssl_verify = true, + ssl_reuse_session = true, + ssl_server_name = "foo.bar", + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + + local hc = require "resty.upstream.healthcheck" + ngx.print(hc.status_page()) + } + } +--- request +GET /t + +--- response_body +Upstream foo.com + Primary Peers + 127.0.0.1:12355 up + Backup Peers + +--- error_log +SSL reused session + +--- no_error_log +certificate host mismatch + + + +=== TEST 23: status_table should return peers with correct properties +--- http_config eval +"$::HttpConfig" +. q{ +upstream foo.com { + server 127.0.0.1:12355; +} +upstream bar.com { + server 127.0.0.1:12356; + server 127.0.0.1:12357 backup; +} +server { + listen 12355; + location = /status { + return 200; + } +} +server { + listen 12356; + location = /status { + return 404; + } +} +server { + listen 12357; + location = /status { + return 200; + } +} +lua_shared_dict healthcheck 1m; +init_worker_by_lua_block { + ngx.shared.healthcheck:flush_all() + local hc = require "resty.upstream.healthcheck" + upstreams = {"foo.com", "bar.com"} + for i = 1,2 do + local ok, err = hc.spawn_checker{ + shm = "healthcheck", + upstream = upstreams[i], + type = "http", + http_req = "GET /status HTTP/1.0\r\nHost: localhost\r\n\r\n", + interval = 100, -- 100ms + fall = 2, + valid_statuses = {200}, + } + if not ok then + ngx.log(ngx.ERR, "failed to spawn health checker: ", err) + return + end + end +} +} +--- config + location = /t { + access_log off; + content_by_lua_block { + ngx.sleep(0.52) + local hc = require "resty.upstream.healthcheck" + local status_table = hc.status_table("healthcheck") + local p12355 = status_table["foo.com"].primary_peers[1] + if p12355.checks_ok ~= 6 or p12355.unhealthy ~= false or p12355.checks_fail ~= 0 then + ngx.exit(500) + end + ngx.sleep(0.21) + status_table = hc.status_table("healthcheck") + local p12356 = status_table["bar.com"].primary_peers[1] + if p12356.checks_fail ~= 8 or p12356.unhealthy ~= true or p12356.checks_ok ~= 0 then + ngx.exit(500) + end + local p12357 = status_table["bar.com"].backup_peers[1] + if p12357.checks_ok ~= 8 or p12357.unhealthy ~= false or p12357.checks_fail ~= 0 then + ngx.exit(500) + end + } + } +--- request +GET /t diff --git a/t/ssl/foo_bar.crt b/t/ssl/foo_bar.crt new file mode 100644 index 0000000..74c4f81 --- /dev/null +++ b/t/ssl/foo_bar.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7TCCAtWgAwIBAgIJAICJM4WgN4tdMA0GCSqGSIb3DQEBBQUAMFcxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxEDAOBgNVBAMTB2Zvby5iYXIwHhcNMTcwMjIyMjIwOTIx +WhcNMjcwMjIwMjIwOTIxWjBXMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1T +dGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYDVQQD +Ewdmb28uYmFyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArI75zE4O +cwwZ0wFz6aC17hgDd+GdhcRxhQFyY+TMCaq1cffOvgeoFdz33vWoWK6bxWlaY6ik +6J1YvYZwtXmhtevVCGGhNAGb/4P/ebexYZt2ZnqLokLeZwzcWhcJdZxhxAMPO4pH +ah+fL8SlOeYh+DZ44lUkVK2LPfywcxAEdXTxTzKaplXtoNyUbTEV8KYVZRejOqZw +I7gamUhih7ETYYbjEAtcPszfftAsFn4BBPqOxfCsDRMo3zgTeMkENpp6mrSDSVXh +ZB3tHrph7ZxZYVHgimswVlHFHuzKGKVSXwMh+IW3nPAJuEE21a4UkZv3/bd30eGc +YLZraclhUzKNvQIDAQABo4G7MIG4MB0GA1UdDgQWBBTzWsRjCS+iM9IFKRkRObEp +MzIMvTCBiAYDVR0jBIGAMH6AFPNaxGMJL6Iz0gUpGRE5sSkzMgy9oVukWTBXMQsw +CQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJu +ZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYDVQQDEwdmb28uYmFyggkAgIkzhaA3i10w +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAQTOtOjA8cRpVO7Pn8Cr7 +e0Zw7wb8vM4oLND50KmK1V7xz2FG1Mn6He7ppc7tWAs3KAy0+hjudk8rk4TEYc5G +eVYljDVG3kv05N/PjVpoyYGpOq/ZQZJvK3tMGfz8arHyq4u1GDBZ4Y8v/uJ09Qq4 +Zub88DN71MLdE+duv1LH4LrqsCGch0piZC9azP4meJ/HE2xLvRVyo4lSEKJTMnx/ +7kXTsGEEuXzJ0HBqLT0jp7nSEZK+SoCD1k9DE9T793gn8OWyhsQgq8B7ve3we6DL +ePTxz0rtiZHu2xKwcEqfMMJZt2xAKKmZQ2F0ADXvuXvln9Bn02z/Z5PB03V770Pc +aA== +-----END CERTIFICATE----- diff --git a/t/ssl/foo_bar.key b/t/ssl/foo_bar.key new file mode 100644 index 0000000..d1c817a --- /dev/null +++ b/t/ssl/foo_bar.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEArI75zE4OcwwZ0wFz6aC17hgDd+GdhcRxhQFyY+TMCaq1cffO +vgeoFdz33vWoWK6bxWlaY6ik6J1YvYZwtXmhtevVCGGhNAGb/4P/ebexYZt2ZnqL +okLeZwzcWhcJdZxhxAMPO4pHah+fL8SlOeYh+DZ44lUkVK2LPfywcxAEdXTxTzKa +plXtoNyUbTEV8KYVZRejOqZwI7gamUhih7ETYYbjEAtcPszfftAsFn4BBPqOxfCs +DRMo3zgTeMkENpp6mrSDSVXhZB3tHrph7ZxZYVHgimswVlHFHuzKGKVSXwMh+IW3 +nPAJuEE21a4UkZv3/bd30eGcYLZraclhUzKNvQIDAQABAoIBAQCrOeiHoYDXCk/p +wExLrIw6qRtv7rGHVgmrCGeA1jzc7sbDQzmj+ScCItTXKf6VmRW7CzKFJ4gTxmaT +Ef9vJDWhtlUazv3OBDbOkiWEmxFpoIEZaUp7hUz5Bpr0zl01liqw/LQ1yZ3ZoW0t +Ujz9ue1FRpAnToMRf29m4AIa+u7huLkghgQBieerfDMfVyXo18U4NdwcJMdDUiQC +P77qwkoSnlN7fpVbKCUtKNMDkOzxWt/VEkiIYaPzSphv4dCYBUXkjJ+TewMDmuCO +gBMTgIgXKlz8+vRAPLUAtjNQWS3c1Gc1tp70TZKOVckhXfKQrDN6prCjngFcERN0 +9ZB8jZMlAoGBAOXBp95wZBOoR4l37qFUTwdCIOKtIohq1EMpG6grcR9NAiwwzSjs +fTapO6NGDE8EE5tLLZ9sEMNZS4Eg7551emipDc7LGBGcO0bmh5vhSY5TFrmoTNsj +ymNUCMp/EdKgMNIPFTOqMphKu6cv7SCcYQSlk17GznpvkCikBzfEBjaTAoGBAMBE +yRGk69vxFF+HjMPy2wpvrwO4Ada9Sh3ctRIm7Y+3oRO4lN5wH/htSMs7Ehfno0vV +GybSAuMo1GHlzi0knXZi97kwZqvjdyoG1MICyF1kNEszasO9Zl5t1jtrBy69A3rd +DT91tkdvx6yZtyCkwnF5GPC+RPpK3MxVFN5DhgxvAoGACGygXhya3smlzdmS62Fv +AGIhWI5mnL/mBoxkUjc9j5tAQCSN8TkyoiV0ZVk1LFSG74PDKXxJ5Q/KH/L4NkQy +d9HzCqkRuduTpNbhFAsfqlNLmwUbxFE8o4W6SMp9+c4b3CfnbByKfGEJHmk4daCm +QghcLfZ2LbEXhRX2mcnbPHcCgYAuP11uFRF2siKIZ/6AE6aEeCDM8DHhCV8Ol8wm +NZ7m9vCT4c5NQwMtqnvcBrVvcpRg5T3GtLVlFqkfczuIuEn39A5KSU4pAmnjfgkn +MawoarX5cMC5nJFHHXxuhmwP3f88SnepUBMsU8LfzYmzHG55BPvuzJWi7ub1b3G5 +lNxlmQKBgQCuoTK8E95zIzfI5xdjhLGuHGOPY6iKUBJ45etcaDpW8xzzk5qPehOn +a6A5C9owcoGUcYhyU3qFZ3Ah7a7++wPQFvrs1ayUHaP+yVLkbcKxi7L1AcsBCOSX +D8N9Z7w4nWjel50x+UOSUCr+hQmy9XrGevQzfkmFWc8I2G+QVH614A== +-----END RSA PRIVATE KEY----- diff --git a/t/ssl/nginx.crt b/t/ssl/nginx.crt new file mode 100644 index 0000000..0934091 --- /dev/null +++ b/t/ssl/nginx.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMjCCAhqgAwIBAgIJANLC+rE1dykaMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV +BAMTDzEyNy4wLjAuMToxMjM1NTAeFw0xNzAxMjcxODE4MTdaFw0yNzAxMjUxODE4 +MTdaMBoxGDAWBgNVBAMTDzEyNy4wLjAuMToxMjM1NTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAOVHwuFvjgsgb59/mpr08Ca2J3AQgHAK4LdVPB8c164y +asD94zWuQanfucE3svA4m9ALFleHZ6HGxH2b7PdjJZcQqL1Sc5gh/Omd3XQJ+rr4 +nfASdkdtGIBjC4gePoemFAEEWf9JA9CbqjWm7YmWI3TBgDfp8igJloP7NLYXmNky +B7DuxHiDMfWKZ4pW9ChcI00y6NKSk6AkIuPfPYWR3RVf7v4WiwjjzG49OD4F0m6E +0veppBf12CbpVmqvYiDrIMOnnn24ZOUn2RLmKcrtxzFHfQ0+u5GoZQ3jSn/xlCZO +yi4yPzJbVvAkdV1b5p2Cr5zpfN+iAbT2vYg/rH8RansCAwEAAaN7MHkwHQYDVR0O +BBYEFHh1zegG5/8v1Jpriaq8SwPX7+9GMEoGA1UdIwRDMEGAFHh1zegG5/8v1Jpr +iaq8SwPX7+9GoR6kHDAaMRgwFgYDVQQDEw8xMjcuMC4wLjE6MTIzNTWCCQDSwvqx +NXcpGjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAFmm3ilX15/RC9 +XtV5YJwE7JETfnTfZEeVCmHWtNldaxuYFTmW4TDU/bW1YHJCnvXm8I2wv5RVCCO3 +kA8a+/IVAMqgTufo9CazN+ptPSlvmoieru2pirMpMKllMJKLIYtqYXCJqbwtoKkj +Nti8gfb/+5XlhqJC6JB4tzj5CsxCJ8TpwAXnTkWuezT1kCl860otE5ON9KRznBLr +xnRlTrsp6BbNove/0EgwI7jbwOP1v7ZKnBX2KXy8EpnlsjE1TDijXDtT5UPxptSs +TMUW37l6UkUCqcNfB3rlJYb0/j9ab2LwoVIQ18gf9+KGOTo50IkVbgH/sE0X9/FC +4HBdN1UQ +-----END CERTIFICATE----- diff --git a/t/ssl/nginx.key b/t/ssl/nginx.key new file mode 100644 index 0000000..ec04642 --- /dev/null +++ b/t/ssl/nginx.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA5UfC4W+OCyBvn3+amvTwJrYncBCAcArgt1U8HxzXrjJqwP3j +Na5Bqd+5wTey8Dib0AsWV4dnocbEfZvs92MllxCovVJzmCH86Z3ddAn6uvid8BJ2 +R20YgGMLiB4+h6YUAQRZ/0kD0JuqNabtiZYjdMGAN+nyKAmWg/s0theY2TIHsO7E +eIMx9Ypnilb0KFwjTTLo0pKToCQi4989hZHdFV/u/haLCOPMbj04PgXSboTS96mk +F/XYJulWaq9iIOsgw6eefbhk5SfZEuYpyu3HMUd9DT67kahlDeNKf/GUJk7KLjI/ +MltW8CR1XVvmnYKvnOl836IBtPa9iD+sfxFqewIDAQABAoIBAQCZKQXa2E1Xy3Ql +ZPVfXA3snjPcHXne3rVcYrjFw9ukBxPfFfqoil5c3xHUK6QB6p7TLAThtZcZr5Dk +o7t5Sqb6ses2hRSo5NNxL76WXHA8ZAYFMCAI+KysXv1+EU4OCXhFcaW47gp5WPMr +4fW9uii3Pueq8kGMU1NTmQSOO1ckho57UIsj/ZFYpP0tQ6gFNHuNFqW0xS6E/OYA +apKP9hIquwGYytoOwoG6T/MCkF5dkPj/t4MRwzgiC+6B+5KrYIdxGEeBeOIYYR55 +t+2VGTA938v8Dj3gQ8ZiCfpu3vzISGM6kqirmQWuh26kbPVllC9/IJ8dFILiAX+2 +2Y6Cv4ZJAoGBAPXNmTB91+fJhoaMOVln2piE92Pl+PtuhqZ+wmQd3eWC6vMgeRsw +xGhZxMdevH+mf9iVq2RrWJPJXQGsLEFGFSN4r0dZAFRBisbvgZPv9O3ZmpqLgkEc +OPwRoC5Ivok1Gw4hxeOKgBOJM3vKiXrMw45WoKOHugEJlav5ljkGSQZPAoGBAO7K +sUtTeMPRPFyGzByBDqCgEgI3n+56s4gAIkCj+FL/7w+wqAiVpnLyDD3j512Whha1 +zBtyc+/p3ByesHpnj9rdWn5wwKDbE4sJj9mC6kTg7EpmryP28Wc7ct1KfmzyEod3 +soD8Jph+EtTLEmf27v3joTu8bYmcOdbID1YyejoVAoGAc00MLNj7LDk2J2sjg7LZ +sW299lhsINVJyFPxr7Dq47wzpfR3mq+XkjN5wOPJnD9n/RrIGQTZuglc3Wn8IGpV +hBwabGdtZhiQlpzGtbR7ug63HQOQCCbK/ELwVoW9CvOkS07AWuofBgr34XuyXa4r +lVtBYzRJpi7uzIr5UqqGGrUCgYBN2XsPqbj3biGVsMSejlysdUMpweS8JPie4BxK +oqp0tMfFf7xogBFx7AOdsc1eL5KrmL1gPWIa101Rb1LttRGrMvsruaqzRnkKnSVu +rkWeCw49+1giC4IMO89o4b5x2kG8NIPXlV0n3gJZqZLonhKwZyPLi9TSRkJ9CWAm +o/JBOQKBgEOO9fT3bFIQu4fVHTiW1ubH4vC40Le1Vv5/Ii/7suOopX8zNsKNu8LE +MBSdLUfB+CMkxQvqwWxEfpV3qyokxvcCWvhkMPq7ELclNhmZHmKOfM8ykyGrHyrY +DCNItozkW3iLg1B6Nj2vzJ4ImQ9cxAw9HdKj2cUzKHNHYwjEhpk/ +-----END RSA PRIVATE KEY----- diff --git a/t/ssl/nginx_other.crt b/t/ssl/nginx_other.crt new file mode 100644 index 0000000..8a8d6a1 --- /dev/null +++ b/t/ssl/nginx_other.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMjCCAhqgAwIBAgIJAKLbW+TQ5LoQMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV +BAMTDzEyNy4wLjAuMToxMjM1NTAeFw0xNzAxMjcxODE5NTNaFw0yNzAxMjUxODE5 +NTNaMBoxGDAWBgNVBAMTDzEyNy4wLjAuMToxMjM1NTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAMlKiXqLnwKkhrjpKJiu+L6/gy6R157fy8FY57aGlgsN +KHlRb7TZsEWB0XKgIne/cHZAGI4ccPldXCj9pIMEeyRVEIvz/UNW7BHDurAzQfQa +NrJo5rxDfdCP1wbiM5W3HRNOhnN5jCTzuisAoymIIrE11sP36hhubrrCigY0mrol +bGuxe99voPlXUC5I7xR2igJuKCKqsIGhx5QMfSpZ/ppDbfT0wEpLawyDouqqFtCp +K0S1/I+VEsfFPy6DiVnMxnYsaSmg65DNOxsQRSrFgyOU3pLa96Ep/jSwTqgUVsM1 +MLxZ+3NIy7YaDt2qAjSQ7iUWuADZLx3aNefJziVuHksCAwEAAaN7MHkwHQYDVR0O +BBYEFPNNo2vp5xJfBUBIu43NsUDOwXJqMEoGA1UdIwRDMEGAFPNNo2vp5xJfBUBI +u43NsUDOwXJqoR6kHDAaMRgwFgYDVQQDEw8xMjcuMC4wLjE6MTIzNTWCCQCi21vk +0OS6EDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQA/5wFyFtnJKjdB +vxlTEoLdffp8akcWEZp49xpMSr/H4mI2A+vezwAZ5Z349HYFmrTxoeYN/iswSgav +M8pNOIOYgIYiRjTWJRaAMdq+D72uaTJmN/QGSlwbZ+yOBnyOJrbk/bftE4UemqYK +b6llRBUpggISiSPRAF++uwb3UE396iklrZSQ3qqjmYZAbxCDCmbANg7kyiMA12kO +qIYXmX6SDEkQzdf1pWm9fsbaykKOGblNQmsicHIsrKi5BiZPmjOeCYPyVCv+QRO/ +3nDR55rVFVkyTBBEcNdLy8Kx/oAT2PSGFB8ZA+7BH1ANMPhRJvhfITwkMpCu68yw +PQtQfrmO +-----END CERTIFICATE-----