Closed kousu closed 6 months ago
That's funny, I actually have this implemented in a branch where I've kind of gutted and reworked TLS. It's still not quite working and I'm not sure when I'll get back to it, but when I do this option will exist:
=item --tls-verify-target <verification-string>
When set, the argument to this option will be used as the host to be verified for C<--tls-verify-host>.
This is necessary when using C<--tls-verify-host> with either the C<--pipe> or C<--socket> transports,
which do not have a verifiable target by default. It can also be used to override the default target lookup
when using the C<--server> transport. For instance, it can be used to verify that the certificate of a
server explicitly connect to via IP contains a specific certificate. (Arg-Required)
Hey that's great news! I'll look forward to it some day, and I can keep using openssl for now.
Thanks again for the great tool!
Curiously, the current version of --tls-verify
doesn't seem to verify the CN at all.
I have a valid cert for CN=comms.kousu.ca
with SAN=["comms.kousu.ca", "comms3.kousu.ca"]
attached too:
But if I connect to it by IP address it successfully negotiates TLS:
$ swaks --tls --tls-verify --to joe@example.com --server 46.23.90.174
=== Trying 46.23.90.174:25...
=== Connected to 46.23.90.174.
<- 220 LOL.com ESMTP spamd IP-based SPAM blocker; Sat Jul 10 07:17:18 2021
-> EHLO radio.kousu.ca
<- 250-LOL.com
<- 250 STARTTLS
-> STARTTLS
<- 220 glad you want to burn more CPU cycles on your spam
=== TLS started with cipher TLSv1.3:TLS_AES_256_GCM_SHA384:256
=== TLS no local certificate set
=== TLS peer DN="/CN=comms.kousu.ca"
~> EHLO radio.kousu.ca
<~ 250 Hello, spam sender. Pleased to be wasting your time.
~> MAIL FROM:<kousu@radio.kousu.ca>
<~ 250 You are about to try to deliver spam. Your time will be spent, for nothing.
~> RCPT TO:<joe@example.com>
<~ 250 This is hurting you more than it is hurting me.
~> DATA
<~* 451 Temporary failure, please try again later.
~> QUIT
*** Remote host closed connection unexpectedly.
It also does it if I give it a fake domain name on the sending side by hacking /etc/hosts, and a fake domain name on the receiving side by running doas hostname LOL.com
.
$ tail -n 1 /etc/hosts
46.23.90.174 mollycakes.buttons
$ swaks --tls --tls-verify --to joe@example.com --server mollycakes.buttons
=== Trying mollycakes.buttons:25...
=== Connected to mollycakes.buttons.
<- 220 LOL.com ESMTP spamd IP-based SPAM blocker; Sat Jul 10 07:20:06 2021
-> EHLO radio.kousu.ca
<- 250-LOL.com
<- 250 STARTTLS
-> STARTTLS
<- 220 glad you want to burn more CPU cycles on your spam
=== TLS started with cipher TLSv1.3:TLS_AES_256_GCM_SHA384:256
=== TLS no local certificate set
=== TLS peer DN="/CN=comms.kousu.ca"
~> EHLO radio.kousu.ca
<~ 250 Hello, spam sender. Pleased to be wasting your time.
~> MAIL FROM:<kousu@radio.kousu.ca>
<~ 250 You are about to try to deliver spam. Your time will be spent, for nothing.
~> RCPT TO:<joe@example.com>
<~ 250 This is hurting you more than it is hurting me.
~> DATA
<~* 451 Temporary failure, please try again later.
~> QUIT
*** Remote host closed connection unexpectedly.
None of these names fit together, so swaks should be failing to verify.
This is the most recent release, https://github.com/jetmore/swaks/releases/tag/v20201014.0:
Curiously, the current version of --tls-verify doesn't seem to verify the CN at all.
By the way, I've fixed up that server into "production" now, so you can't use it to reproduce this, but it should be easy enough to do:
certbot
to get a certMany thanks for the openssl command above @kousu (since it's more or less impossible to fix installed cert errors without knowing how to get this additional info), and for the extremely useful mail tool @jetmore.
@kouso I believe this to be fixed in the head of the develop branch (https://github.com/jetmore/swaks/blob/develop/swaks). Any chance you could test this and let me know what you think? Specifically, I now believe mismatched ca should be an error and that you should be able to use --tls-verify-target to specify an alternate domain name to use for CA verification. My notes say this is true, but I did this over a year ago so I thought I might ask you to test since I don't really remember doing it
@jetmore - If I can ask, is there any way to prompt swaks
to give a more verbose error when --tls-verify
fails?
E.g. After re-creating my now fixed error condition, if I use --tls-verify
I get:
-> STARTTLS
<- 220 2.0.0 Ready to start TLS
*** TLS startup failed (connect(): error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed)
*** STARTTLS attempted but failed
But if I use @kousu's command I can get:
Can't use SSL_get_servername
depth=0 CN = *.[redacted].com
verify error:num=20:unable to get local issuer certificate
139657689179968:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1915:
Where I believe one is just a more verbose version of the other? If so, it would be very helpful to be able to prompt swaks
to give the more verbose version. "unable to get local issuer certificate"
is what I needed, to know where to look next, and it would be great if swaks
itself gave (or could be asked to give) that extra detail. (EDIT: I can see you're using SSLeay, so not sure how/whether/if this info would be available via that.)
@jetmore - I just tested the new version of swaks
which you linked above, and actually I'm getting a different result on the develop version: --tls-verify
is succeeding on the current version of swaks
but failing on the develop version, called with the same params, running from the same location.
Just to confirm I haven't done something stupid: in order to get the develop version to run, I downloaded the script, chmod +x
ofc, and then manually sudo apt-get install libnet-ssleay-perl
and sudo apt-get install libcrypt-ssleay-perl
in order to get it to work. It starts up, sends test emails fine, etc., but it fails the --tls-verify
test against a server where the old version succeeds (and so does the above openssl
test).
If that sounds like it should have passed, then there may be a problem with the new version around this? (I can provide more info and do tests, if needed.)
@jetmore - I just tested the new version of
swaks
which you linked above, and actually I'm getting a different result on the develop version:--tls-verify
is succeeding on the current version ofswaks
but failing on the develop version, called with the same params, running from the same location.Just to confirm I haven't done something stupid: in order to get the develop version to run, I downloaded the script,
chmod +x
ofc, and then manuallysudo apt-get install libnet-ssleay-perl
andsudo apt-get install libcrypt-ssleay-perl
in order to get it to work. It starts up, sends test emails fine, etc., but it fails the--tls-verify
test against a server where the old version succeeds (and so does the aboveopenssl
test).If that sounds like it should have passed, then there may be a problem with the new version around this? (I can provide more info and do tests, if needed.)
Yeah, I jumped the gun. Still broken
Based on @kousu's suggestion, this can be useful for verifying which certificate is in use for incoming TLS connections on an SMTP server:
echo QUIT | openssl s_client -connect "$mx":587 -starttls smtp 2>/dev/null | openssl x509 -in - -text | grep -E "(Not (Before|After )|Subject):"
Example output:
Not Before: Jan 26 00:00:00 2023 GMT
Not After : Feb 23 23:59:59 2024 GMT
Subject: CN = *.[redacted].com
This issue has some twists in it, but here's what I think I see as issues:
Solution: There is now a --tls-verify-target
option that allows this
--tls-verify
didn't actually properly verify the hostname (https://github.com/jetmore/swaks/issues/37#issuecomment-877571023)Solution: --tls-verify
now does CN/SAN verification. Can also do --tls-verify-ca
for just signing/time verification and --tle-verify-host
for just CN/SAN validation
Solution: swaks now always prints the openssl detailed error message when verification fails. Some examples (specifically the part in parens after "failed CA verification":
=== TLS peer certificate failed CA verification (unable to get local issuer certificate), failed host verification (no host string available to verify)
=== TLS peer certificate failed CA verification (self-signed certificate in certificate chain), failed host verification (no host string available to verify)
=== TLS peer certificate failed CA verification (self-signed certificate), failed host verification (no host string available to verify)
=== TLS peer certificate failed CA verification (certificate has expired), failed host verification (no host string available to verify)
Solution: Every cert received from the server is now displayed, and additional detail is displayed (notAfter, CN, SAN):
=== TLS peer[0] subject=[/C=US/ST=Indiana/O=Swaks Development (signed-intermediate.example.com, with-SAN)/CN=signed-intermediate.example.com/emailAddress=proj-swaks@jetmore.net]
=== commonName=[signed-intermediate.example.com], subjectAltName=[DNS:signed-intermediate.example.com] notAfter=[2033-09-15T22:49:58Z]
=== TLS peer[1] subject=[/C=US/ST=Indiana/O=Swaks Development (ca-intermediate, without-SAN)/emailAddress=proj-swaks@jetmore.net]
=== commonName=[], subjectAltName=[] notAfter=[2033-09-15T22:49:32Z]
=== TLS peer[2] subject=[/C=US/ST=Indiana/O=Swaks Development/CN=Swaks Root CA/emailAddress=proj-swaks@jetmore.net]
=== commonName=[Swaks Root CA], subjectAltName=[] notAfter=[2030-12-11T15:28:17Z]
=== TLS peer certificate passed CA verification, passed host verification (using host signed-intermediate.example.com to verify)
These changes will be in the next release
In multiple MX situations or if you're not sure if your DNS is working yet, it is hard to test if a specific server has its TLS done correctly. It would be helpful to separate the hostname used in
--verify-tls
from the hostname given by-s
so that a specific server can be targetted with-s
.openssl lets you do this, but it's arcane:
swaks has timeouts built in and consistent I/O choices, but the closest I can get to this specific command, unless I've misread something, is
Being able to do something like
would make pinpointing deployment issues easier.
This is a very niche issue, and I wouldn't be surprised if you think it's out of scope for swaks! It's already been very helpful in its current form.