diff --git a/Makefile.am b/Makefile.am index 3be50d6..2124315 100644 --- a/Makefile.am +++ b/Makefile.am @@ -156,6 +156,7 @@ EXTRA_DIST += $(handwritten_tests) \ t/lib/ddclient/Test/Fake/HTTPD/dummy-ca-cert.pem \ t/lib/ddclient/Test/Fake/HTTPD/dummy-server-cert.pem \ t/lib/ddclient/Test/Fake/HTTPD/dummy-server-key.pem \ + t/lib/ddclient/Test/Fake/HTTPD/other-ca-cert.pem \ t/lib/ddclient/t.pm \ t/lib/ddclient/t/HTTPD.pm \ t/lib/ddclient/t/ip.pm \ diff --git a/t/lib/ddclient/Test/Fake/HTTPD/other-ca-cert.pem b/t/lib/ddclient/Test/Fake/HTTPD/other-ca-cert.pem new file mode 100644 index 0000000..c15b26c --- /dev/null +++ b/t/lib/ddclient/Test/Fake/HTTPD/other-ca-cert.pem @@ -0,0 +1,80 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6c:bf:34:52:19:4d:c9:29:2b:a6:8b:41:59:aa:c6:c5:1f:a2:bb:10 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Root Certification Authority + Validity + Not Before: Jan 8 08:24:32 2025 GMT + Not After : Jan 9 08:24:32 2125 GMT + Subject: CN=Root Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c3:3d:19:6b:72:0a:9e:87:c0:28:a1:ff:d0:08: + 21:55:52:71:92:f2:98:36:75:fc:95:b4:0c:5e:c9: + 98:b3:3c:a1:ee:cf:91:6f:07:bf:82:c9:d5:51:c0: + eb:f8:46:17:41:52:1d:c6:89:ec:63:dd:5c:30:87: + a7:b5:0d:dd:ae:bf:46:fd:de:1a:be:1d:69:83:0d: + fb:d9:5a:33:0b:8d:5f:63:76:fc:a8:b1:54:37:1e: + 0b:12:44:93:90:39:1c:48:ee:f0:f2:12:fe:dc:fb: + 58:a5:76:3b:e8:e8:94:44:1e:9d:03:22:5f:21:6a: + 17:66:d1:4a:bf:12:d7:3c:15:76:11:76:09:ab:bf: + 21:ef:0c:a5:a9:e0:08:99:63:19:26:e4:d8:5d:c2: + 40:8b:98:e6:5d:df:b3:8c:63:e2:01:7c:5e:fb:55: + 39:a8:67:78:80:d2:6b:61:b2:e2:2e:93:c0:9d:91: + 0e:a1:79:4f:fc:38:94:ff:6f:65:18:8f:3e:0b:8c: + 1f:cd:48:d7:46:5a:a2:76:d6:e0:bd:3c:aa:3d:44: + 9e:50:e6:fd:e1:12:1a:ee:a1:9a:69:48:60:63:da: + 41:ae:a7:3d:36:1b:95:fb:b7:f1:0d:60:cd:2f:e3: + b1:1f:b1:db:b4:98:a6:62:87:de:54:80:d1:45:43: + 5b:25 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + E1:7C:D3:C3:9E:C7:F5:2C:DA:7C:D7:85:78:91:BA:26:88:61:F9:D4 + X509v3 Authority Key Identifier: + E1:7C:D3:C3:9E:C7:F5:2C:DA:7C:D7:85:78:91:BA:26:88:61:F9:D4 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 9d:dc:49:c6:14:13:19:38:d9:14:b5:70:f0:3b:01:8e:d7:32: + a7:69:f0:21:68:ec:ad:8c:ee:53:7d:16:64:7d:3e:c2:d2:ac: + 5a:54:17:55:84:43:1e:46:1d:42:01:fb:89:e0:db:ec:e8:f0: + 3c:22:82:54:1d:38:12:21:45:3c:37:44:3b:2e:c9:4d:ed:8d: + 6e:46:f5:a5:cc:ba:39:61:ab:df:cf:1f:d2:c9:40:e2:db:3f: + 05:ea:83:14:93:5f:0e:3d:33:be:98:04:80:87:25:3a:6c:ff: + 8e:87:6a:32:ed:1e:ec:54:90:9b:2a:6e:12:05:6a:9d:15:48: + 3c:ea:c6:9e:ab:71:58:1e:34:95:3f:9b:9e:e3:e5:4b:fb:9e: + 32:f2:d6:59:bf:8d:09:d6:e4:9e:9e:47:b9:d6:78:5f:f3:0c: + 98:ab:56:f0:18:5d:63:8e:83:ee:c1:f2:84:da:0e:64:af:1c: + 18:ff:b3:f9:15:0b:02:50:77:d1:0b:6e:ba:61:bc:9e:c3:37: + 63:91:26:e8:ce:77:9a:47:8f:ef:38:8f:9c:7f:f1:ab:7b:65: + a5:96:b6:92:2e:c7:d3:c3:7a:54:0d:d6:76:f5:d6:88:13:3b: + 17:e2:02:4e:3b:4d:10:95:0a:bb:47:e9:48:25:76:1d:7b:19: + 5c:6f:b8:a1 +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgIUbL80UhlNySkrpotBWarGxR+iuxAwDQYJKoZIhvcNAQEL +BQAwJzElMCMGA1UEAwwcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAgFw0y +NTAxMDgwODI0MzJaGA8yMTI1MDEwOTA4MjQzMlowJzElMCMGA1UEAwwcUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMM9GWtyCp6HwCih/9AIIVVScZLymDZ1/JW0DF7JmLM8oe7PkW8Hv4LJ +1VHA6/hGF0FSHcaJ7GPdXDCHp7UN3a6/Rv3eGr4daYMN+9laMwuNX2N2/KixVDce +CxJEk5A5HEju8PIS/tz7WKV2O+jolEQenQMiXyFqF2bRSr8S1zwVdhF2Cau/Ie8M +pangCJljGSbk2F3CQIuY5l3fs4xj4gF8XvtVOahneIDSa2Gy4i6TwJ2RDqF5T/w4 +lP9vZRiPPguMH81I10ZaonbW4L08qj1EnlDm/eESGu6hmmlIYGPaQa6nPTYblfu3 +8Q1gzS/jsR+x27SYpmKH3lSA0UVDWyUCAwEAAaNjMGEwHQYDVR0OBBYEFOF808Oe +x/Us2nzXhXiRuiaIYfnUMB8GA1UdIwQYMBaAFOF808Oex/Us2nzXhXiRuiaIYfnU +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUA +A4IBAQCd3EnGFBMZONkUtXDwOwGO1zKnafAhaOytjO5TfRZkfT7C0qxaVBdVhEMe +Rh1CAfuJ4Nvs6PA8IoJUHTgSIUU8N0Q7LslN7Y1uRvWlzLo5Yavfzx/SyUDi2z8F +6oMUk18OPTO+mASAhyU6bP+Oh2oy7R7sVJCbKm4SBWqdFUg86saeq3FYHjSVP5ue +4+VL+54y8tZZv40J1uSenke51nhf8wyYq1bwGF1jjoPuwfKE2g5krxwY/7P5FQsC +UHfRC266YbyewzdjkSbozneaR4/vOI+cf/Gre2WllraSLsfTw3pUDdZ29daIEzsX +4gJOO00QlQq7R+lIJXYdexlcb7ih +-----END CERTIFICATE----- diff --git a/t/lib/ddclient/t/HTTPD.pm b/t/lib/ddclient/t/HTTPD.pm index f9a5f1a..94ab271 100644 --- a/t/lib/ddclient/t/HTTPD.pm +++ b/t/lib/ddclient/t/HTTPD.pm @@ -16,7 +16,7 @@ our @EXPORT = qw( httpd httpd_ipv6_ok httpd_ipv6_required $httpd_ipv6_supported $httpd_ipv6_support_error httpd_ssl_ok httpd_ssl_required $httpd_ssl_supported $httpd_ssl_support_error - $ca_file $certdir + $ca_file $certdir $other_ca_file $textplain ); @@ -104,6 +104,7 @@ sub reset { our $certdir = "$ENV{abs_top_srcdir}/t/lib/ddclient/Test/Fake/HTTPD"; our $ca_file = "$certdir/dummy-ca-cert.pem"; +our $other_ca_file = "$certdir/other-ca-cert.pem" my %daemons; diff --git a/t/ssl-validate.pl b/t/ssl-validate.pl index 1414c02..ac5f58f 100644 --- a/t/ssl-validate.pl +++ b/t/ssl-validate.pl @@ -12,9 +12,6 @@ local $ddclient::globals{verbose} = 1; httpd_ssl_required(); -# Note: $ddclient::globals{'ssl_ca_file'} is intentionally NOT set to "$certdir/dummy-ca-cert.pem" -# so that we can test what happens when certificate validation fails. - httpd('4', 1)->run(sub { return [200, $textplain, ['127.0.0.1']]; }); httpd('6', 1)->run(sub { return [200, $textplain, ['::1']]; }) if httpd('6', 1); my $h = 't/ssl-validate.pl'; @@ -77,6 +74,16 @@ for my $tc (@test_cases) { SKIP: { skip("IPv6 not supported on this system", 1) if $tc->{ipv6} && !$ipv6_supported; skip("HTTP::Daemon too old for IPv6 support", 1) if $tc->{ipv6} && !$httpd_ipv6_supported; + # $ddclient::globals{'ssl_ca_file'} is intentionally NOT set to $ca_file so that we can + # test what happens when certificate validation fails. However, if curl can't find any CA + # certificates (which may be the case in some minimal test environments, such as Docker + # images and Debian package builder chroots), it will immediately close the connection + # after it sends the TLS client hello and before it receives the server hello (in Debian + # sid as of 2025-01-08, anyway). This confuses IO::Socket::SSL (used by + # Test::Fake::HTTPD), causing it to hang in the middle of the TLS handshake waiting for + # input that will never arrive. To work around this, the CA certificate file is explicitly + # set to an unrelated certificate so that curl has something to read. + local $ddclient::globals{'ssl_ca_file'} = $other_ca_file; local $ddclient::config{$h} = $tc->{cfg}; %ddclient::config if 0; # suppress spurious warning "Name used only once: possible typo" is(ddclient::get_ipv4(ddclient::strategy_inputs('usev4', $h)), $tc->{want}, $tc->{desc})