{
my($date1,$date2,$date3,$expired) = ($1,$2,$3,$4);
$expired = '' if !defined $expired;
- my($increment) = date_seconds($date3) - date_seconds($date2);
+
+ # Round the time-difference up to nearest even value
+ my($increment) = ((date_seconds($date3) - date_seconds($date2) + 1) >> 1) << 1;
# We used to use globally unique replacement values, but timing
# differences make this impossible. Just show the increment on the
# more_errno values in exim_dumpdb output which are times
s/T:(\S+)\s-22\s(\S+)\s/T:$1 -22 xxxx /;
+ # port numbers in dumpdb output
+ s/T:([a-z.]+(:[0-9.]+)?):$parm_port_n /T:$1:PORT_N /;
+
+ # port numbers in stderr
+ s/^set_process_info: .*\]:\K$parm_port_d /PORT_D /;
+ s/^set_process_info: .*\]:\K$parm_port_s /PORT_S /;
+
# ======== Dates and times ========
# Date/time in header lines and SMTP responses
s/[A-Z][a-z]{2},\s\d\d?\s[A-Z][a-z]{2}\s\d\d\d\d\s\d\d\:\d\d:\d\d\s[-+]\d{4}
/Tue, 2 Mar 1999 09:44:33 +0000/gx;
+ # and in a French locale
+ s/\S{4},\s\d\d?\s[^,]+\s\d\d\d\d\s\d\d\:\d\d:\d\d\s[-+]\d{4}
+ /dim., 10 f\xE9vr 2019 20:05:49 +0000/gx;
# Date/time in logs and in one instance of a filter test
s/^\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(\s[+-]\d\d\d\d)?\s/1999-03-02 09:44:33 /gx;
my($next) = $3 - $2;
$_ = " first failed=dddd last try=dddd next try=+$next $4\n";
}
- s/^(\s*)now=\d+ first_failed=\d+ next_try=\d+ expired=(\d)/$1now=tttt first_failed=tttt next_try=tttt expired=$2/;
+ s/^(\s*)now=\d+ first_failed=\d+ next_try=\d+ expired=(\w)/$1now=tttt first_failed=tttt next_try=tttt expired=$2/;
s/^(\s*)received_time=\d+ diff=\d+ timeout=(\d+)/$1received_time=tttt diff=tttt timeout=$2/;
# Time to retry may vary
s/(could not connect to .*: Connection) reset by peer$/$1 refused/;
# ======== TLS certificate algorithms ========
+ #
+ # In Received: headers, convert RFC 8314 style ciphersuite to
+ # the older (comment) style, keeping only the Auth element
+ # (discarding kex, cipher, mac). For TLS 1.3 there is no kex
+ # element (and no _WITH); insert a spurious "RSA".
+
+ s/^\s+by .+ with .+ \K tls TLS_.*?([^_]+)_WITH.+$/(TLS1.x:ke-$1-AES256-SHAnnn:xxx)/;
+ s/^\s+by .+ with .+ \K tls TLS_.+$/(TLS1.x:ke-RSA-AES256-SHAnnn:xxx)/;
+
# Test machines might have various different TLS library versions supporting
# different protocols; can't rely upon TLS 1.2's AES256-GCM-SHA384, so we
# treat the standard algorithms the same.
+ #
+ # TLSversion : KeyExchange? - Authentication/Signature - C_iph_er - MAC : ???
+ #
# So far, have seen:
# TLSv1:AES128-GCM-SHA256:128
# TLSv1:AES256-SHA:256
#
# Retain the authentication algorith field as we want to test that.
- s/( (?: (?:\b|\s) [\(=] ) | \s )TLSv1\.[123]:/$1TLSv1:/xg;
- s/((EC)?DHE-)?(RSA|ECDSA)-AES(128|256)-(GCM-SHA(256|384)|SHA)(?!:)/ke-$3-AES256-SHA/g;
- s/((EC)?DHE-)?(RSA|ECDSA)-AES(128|256)-(GCM-SHA(256|384)|SHA):(128|256)/ke-$3-AES256-SHA:xxx/g;
+ s/( (?: (?:\b|\s) [\(=] ) | \s )TLSv1(\.[123])?:/$1TLS1.x:/xg;
+ s/(?<!ke-)((EC)?DHE-)?(RSA|ECDSA)-AES(128|256)-(GCM-SHA(256|384)|SHA)(?!:)/ke-$3-AES256-SHAnnn/g;
+ s/(?<!ke-)((EC)?DHE-)?(RSA|ECDSA)-AES(128|256)-(GCM-SHA(256|384)|SHA):(128|256)/ke-$3-AES256-SHAnnn:xxx/g;
# OpenSSL TLSv1.3 - unsure what to do about the authentication-variant testcases now,
- # as it seems the protocol no longer supports a user choice.
- s/TLS_AES(_256)_GCM_SHA384:256/TLS-AES256-SHA:xxx/g;
+ # as it seems the protocol no longer supports a user choice. Replace the "TLS" field with "RSA".
+ # Also insert a key-exchange field for back-compat, even though 1.3 doesn't do that.
+ #
+ # TLSversion : "TLS" - C_iph_er - MAC : ???
+ #
+ s/TLS_AES(_256)?_GCM_SHA384(?!:)/ke-RSA-AES256-SHAnnn/g;
+ s/:TLS_AES(_256)?_GCM_SHA384:256/:ke-RSA-AES256-SHAnnn:xxx/g;
# LibreSSL
# TLSv1:AES256-GCM-SHA384:256
# AES256-GCM-SHA384
s/(?<!-)(AES256-GCM-SHA384)/RSA-$1/;
- s/((EC)?DHE-)?(RSA|ECDSA)-(AES256|CHACHA20)-(GCM-SHA384|POLY1305)(?!:)/ke-$3-AES256-SHA/g;
- s/((EC)?DHE-)?(RSA|ECDSA)-(AES256|CHACHA20)-(GCM-SHA384|POLY1305):256/ke-$3-AES256-SHA:xxx/g;
+ s/(?<!ke-)((EC)?DHE-)?(RSA|ECDSA)-(AES256|CHACHA20)-(GCM-SHA384|POLY1305)(?!:)/ke-$3-AES256-SHAnnn/g;
+ s/(?<!ke-)((EC)?DHE-)?(RSA|ECDSA)-(AES256|CHACHA20)-(GCM-SHA384|POLY1305):256/ke-$3-AES256-SHAnnn:xxx/g;
# GnuTLS have seen:
+ # TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256
+ # TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM__AEAD:256
+ # TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256
+ # TLS1.3:ECDHE_PSK_SECP256R1__AES_256_GCM__AEAD:256
+ #
# TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256
# TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128
# TLS1.2:RSA_AES_256_CBC_SHA1:256 (canonical)
# TLS1.2:DHE_RSA_AES_128_CBC_SHA1:128
+ # TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_256_GCM:256
+ # TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_128_CBC__SHA256:128
+ # TLS1.2:ECDHE_SECP256R1__ECDSA_SHA512__AES_256_GCM:256
+ # TLS1.2:RSA__CAMELLIA_256_GCM:256 (leave the cipher name)
#
# X=TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256
# X=TLS1.2:RSA_AES_256_CBC_SHA1:256
# DHE-RSA-AES256-SHA256
# DHE-RSA-AES256-SHA
# picking latter as canonical simply because regex easier that way.
- s/\bDHE_RSA_AES_128_CBC_SHA1:128/RSA_AES_256_CBC_SHA1:256/g;
- s/TLS1.[012]:((EC)?DHE_)?(RSA|ECDSA)_AES_(256|128)_(CBC|GCM)_SHA(1|256|384):(256|128)/TLS1.x:ke_$3_AES_256_CBC_SHAnnn:256/g;
- s/\b(ECDHE-(RSA|ECDSA)-AES256-SHA|DHE-RSA-AES256-SHA256)\b/ke-$2-AES256-SHAxx/g;
+ s/\bDHE_RSA_AES_128_CBC_SHA1:128/RSA-AES256-SHA1:256/g;
+ s/TLS1.[0123]: # TLS version
+ ((EC)?DHE(_((?<psk>PSK)_)?(SECP256R1|X25519))?__?)? # key-exchange
+ ((?<auth>RSA|ECDSA)((_PSS_RSAE)?_SHA(512|256))?__?)? # authentication
+ AES_(256|128)_(CBC|GCM) # cipher
+ (__?SHA(1|256|384))?: # PRF
+ (256|128) # cipher strength
+ /"TLS1.x:ke-"
+ . (defined($+{psk}) ? $+{psk} : "")
+ . (defined($+{auth}) ? $+{auth} : "")
+ . "-AES256-SHAnnn:xxx"/genx;
+ s/TLS1.2:RSA__CAMELLIA_256_GCM(_SHA384)?:256/TLS1.2:RSA_CAMELLIA_256_GCM-SHAnnn:256/g;
+ s/\b(ECDHE-(RSA|ECDSA)-AES256-SHA|DHE-RSA-AES256-SHA256)\b/ke-$2-AES256-SHAnnn/g;
# GnuTLS library error message changes
- s/No certificate was found/The peer did not send any certificate/g;
+ s/(No certificate was found|Certificate is required)/The peer did not send any certificate/g;
#(dodgy test?) s/\(certificate verification failed\): invalid/\(gnutls_handshake\): The peer did not send any certificate./g;
s/\(gnutls_priority_set\): No or insufficient priorities were set/\(gnutls_handshake\): Could not negotiate a supported cipher suite/g;
+ s/\(gnutls_handshake\): \KNo supported cipher suites have been found.$/Could not negotiate a supported cipher suite./;
# (this new one is a generic channel-read error, but the testsuite
# only hits it in one place)
s/waiting for children of \d+/waiting for children of pppp/;
s/waiting for (\S+) \(\d+\)/waiting for $1 (pppp)/;
- # The spool header file name varies with PID
- s%^(Writing spool header file: .*/hdr).[0-9]{1,5}%$1.pppp%;
-
# ======== Port numbers ========
# Incoming port numbers may vary, but not in daemon startup line.
s/SSL3_READ_BYTES/ssl3_read_bytes/i;
s/CONNECT_CR_FINISHED/ssl3_read_bytes/i;
s/^\d+:error:\d+(?:E\d+)?(:SSL routines:ssl3_read_bytes:[^:]+:).*(:SSL alert number \d\d)$/pppp:error:dddddddd$1\[...\]$2/;
+ s/^error:[^:]*:(SSL routines:ssl3_read_bytes:(tls|ssl)v\d+ alert)/error:dddddddd:$1/;
# gnutls version variances
next if /^Error in the pull function./;
s/^waiting for server to shut down\.+ done$/waiting for server to shut down.... done/;
s/^\/.*postgres /POSTGRES /;
+ # DMARC is not always supported by the build
+ next if /^dmarc_tld_file =/;
+
# ARC is not always supported by the build
next if /^arc_sign =/;
}
# Some DBM libraries seem to make DBM files on opening with O_RDWR without
# O_CREAT; other's don't. In the latter case there is some debugging output
# which is not present in the former. Skip the relevant lines (there are
- # two of them).
+ # three of them).
- if (/TESTSUITE\/spool\/db\/\S+ appears not to exist: trying to create/)
+ if (/returned from EXIM_DBOPEN: \(nil\)/)
{
- $_ = <IN>;
- next;
+ $_ .= <IN>;
+ s?\Q$parm_cwd\E?TESTSUITE?g;
+ if (/TESTSUITE\/spool\/db\/\S+ appears not to exist: trying to create/)
+ { $_ = <IN>; next; }
}
# Some tests turn on +expand debugging to check on expansions.
# Skip hosts_require_dane checks when the options
# are unset, because dane ain't always there.
-
next if /in\shosts_require_dane\?\sno\s\(option\sunset\)/x;
+ # DISABLE_OCSP
+ next if /in hosts_requ(est|ire)_ocsp\? (no|yes)/;
+
# SUPPORT_PROXY
next if /host in hosts_proxy\?/;
# Experimental_REQUIRETLS
next if / in tls_advertise_requiretls?\? no \(end of list\)/;
+ # TCP Fast Open
+ next if /^(ppppp )?setsockopt FASTOPEN: Network Error/;
+
+ # Experimental_PIPE_CONNECT
+ next if / in (pipelining_connect_advertise_hosts|hosts_pipe_connect)?\? no /;
+
# Environment cleaning
next if /\w+ in keep_environment\? (yes|no)/;
s/Address family not supported by protocol family/Network Error/;
s/Network is unreachable/Network Error/;
}
-
next if /^(ppppp )?setsockopt FASTOPEN: Protocol not available$/;
+ s/^(Connecting to .* \.\.\. sending) \d+ (nonTFO early-data)$/$1 dd $2/;
# Specific pointer values reported for DB operations change from run to run
- s/^(returned from EXIM_DBOPEN: )(0x)?[0-9a-f]+/${1}0xAAAAAAAA/;
- s/^(EXIM_DBCLOSE.)(0x)?[0-9a-f]+/${1}0xAAAAAAAA/;
+ s/^(\s*returned from EXIM_DBOPEN: )(0x)?[0-9a-f]+/${1}0xAAAAAAAA/;
+ s/^(\s*EXIM_DBCLOSE.)(0x)?[0-9a-f]+/${1}0xAAAAAAAA/;
# Platform-dependent output during MySQL startup
next if /PerconaFT file system space/;
s/(TLS error on connection [^:]*: error:)[0-9A-F]{8}(:system library):(?:fopen|func\(4095\)):(No such file or directory)$/$1xxxxxxxx$2:fopen:$3/;
s/(DANE attempt failed.*error:)[0-9A-F]{8}(:SSL routines:)(ssl3_get_server_certificate|tls_process_server_certificate|CONNECT_CR_CERT)(?=:certificate verify failed$)/$1xxxxxxxx$2ssl3_get_server_certificate/;
s/(DKIM: validation error: )error:[0-9A-F]{8}:rsa routines:(?:(?i)int_rsa_verify|CRYPTO_internal):(?:bad signature|algorithm mismatch)$/$1Public key signature verification has failed./;
+ s/ARC: AMS signing: privkey PEM-block import: error:\K[0-9A-F]{8}:(PEM routines):get_name:(no start line)/0906D06C:$1:PEM_read_bio:$2/;
+
+ # gnutls version variances
+ if (/TLS error on connection \(recv\): .* (Decode error|peer did not send any certificate)/)
+ {
+ my $prev = $_;
+ $_ = <IN>;
+ if (/error on first read/)
+ {
+ s/TLS session: \Kerror on first read:/(gnutls_handshake): A TLS fatal alert has been received.:/;
+ goto RESET_AFTER_EXTRA_LINE_READ;
+ }
+ else
+ { $_ = $prev; }
+ }
# DKIM timestamps
if ( /(DKIM: d=.*) t=([0-9]*) x=([0-9]*) / )
my ($prefix, $t_diff) = ($1, $3 - $2);
s/DKIM: d=.* t=[0-9]* x=[0-9]* /${prefix} t=T x=T+${t_diff} /;
}
+
+ # port numbers
+ s/(?:\[[^\]]*\]:|port )\K$parm_port_d/PORT_D/;
+ s/(?:\[[^\]]*\]:|port )\K$parm_port_d2/PORT_D2/;
+ s/(?:\[[^\]]*\]:|port )\K$parm_port_d3/PORT_D3/;
+ s/(?:\[[^\]]*\]:|port )\K$parm_port_d4/PORT_D4/;
+ s/(?:\[[^\]]*\]:|port )\K$parm_port_s/PORT_S/;
+ s/(?:\[[^\]]*\]:|port )\K$parm_port_n/PORT_N/;
+ s/I=\[[^\]]*\]:\K\d+/ppppp/;
+
}
# ======== mail ========
'gnutls_handshake' =>
{ 'mainlog' => 's/\(gnutls_handshake\): Error in the push function/\(gnutls_handshake\): A TLS packet with unexpected length was received/' },
+ 'gnutls_bad_clientcert' =>
+ { 'mainlog' => 's/\(certificate verification failed\): certificate invalid/\(gnutls_handshake\): The peer did not send any certificate./',
+ 'stdout' => 's/Succeeded in starting TLS/A TLS fatal alert has been received.\nFailed to start TLS'
+ },
+
'optional_events' =>
{ 'stdout' => '/event_action =/' },
s! DN="[^,"]*\K,!/!;
',
'rejectlog' => 's/ X=TLS\S+ / X=TLS_proto_and_cipher /',
- 'mail' => 's/ \(TLS[^)]*\)/ (TLS_proto_and_cipher)/',
+ 'mail' => 's/^\s+by .+ with .+ \K tls TLS_.+$/(TLS_proto_and_cipher)/;
+ s/ \(TLS[^)]*\)/ (TLS_proto_and_cipher)/;
+ ',
},
'debug_pid' =>
{ 'stdout' => '/^(
dkim_(canon|domain|private_key|selector|sign_headers|strict|hash|identity|timestamps)
|gnutls_require_(kx|mac|protocols)
+ |hosts_pipe_connect
|hosts_(requ(est|ire)|try)_(dane|ocsp)
|dane_require_tls_ciphers
|hosts_(avoid|nopass|noproxy|require|verify_avoid)_tls
+ |pipelining_connect_advertise_hosts
|socks_proxy
|tls_[^ ]*
+ |utf8_downconvert
)($|[ ]=)/x'
},
# The "munge" command selects one of a hardwired set of test-result modifications
-# to be made before result compares are run agains the golden set. This lets
+# to be made before result compares are run against the golden set. This lets
# us account for test-system dependent things which only affect a few, but known,
# test-cases.
# Currently only the last munge takes effect.
'valgrind' => \$valgrind,
'range=s{2}' => \my @range_wanted,
'test=i@' => \my @tests_wanted,
- 'flavor|flavour=s' => $flavour,
+ 'flavor|flavour=s' => \$flavour,
'help' => sub { pod2usage(-exit => 0) },
'man' => sub {
pod2usage(
my $git = `git describe --dirty=-XX --match 'exim-4*'`;
if (defined $git and $? == 0) {
chomp $git;
- $version =~ s/^\d+\K\./_/;
$git =~ s/^exim-//i;
$git =~ s/.*-\Kg([[:xdigit:]]+(?:-XX)?)/$1/;
print <<___
if 0020 & (stat "$parm_cwd/test-config")[2]
and $parm_configure_group != $);
-die "aux-fixed file is world-writeable; best to strip them all, recursively\n"
+die "aux-fixed file is group-writeable; best to strip them all, recursively\n"
if 0020 & (stat "aux-fixed/0037.f-1")[2];
$parm_ipv4 = $1;
}
- if (not $parm_ipv6 and /^\s*inet6(?:\saddr)?:?\s?([abcdef\d:]+)(?:\/\d+)/i)
+ if (not $parm_ipv6 and /^\s*inet6(?:\saddr)?:?\s?([abcdef\d:]+)(?:%[^ \/]+)?(?:\/\d+)?/i)
{
next if $1 eq '::1' or $1 =~ /^fe80/i;
$parm_ipv6 = $1;
print "IPv4 address is $parm_ipv4\n";
print "IPv6 address is $parm_ipv6\n";
+$parm_ipv6 =~ /^[^%\/]*/;
# For munging test output, we need the reversed IP addresses.
print "\n*** Host name has upper case characters: this may cause problems ***\n\n";
}
+if ($parm_hostname =~ /\.example\.com$/)
+ {
+ die "\n*** Host name ends in .example.com; this conflicts with the testsuite use of that domain.\n"
+ . " Please change the host's name (or comment out this check, and fail several testcases)\n";
+ }
+
##################################################