jetmore / swaks

Swaks - Swiss Army Knife for SMTP
http://jetmore.org/john/code/swaks/
GNU General Public License v2.0
848 stars 86 forks source link

Specifying hostname for --verify-tls #37

Closed kousu closed 6 months ago

kousu commented 3 years ago

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:

echo QUIT | timeout 30 openssl s_client -quiet -no_ign_eof -connect "$ip":25 -starttls smtp -verify_hostname "$mx" -verify_return_error 2>/dev/null

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

swaks -s "$mx" -tls --tls-verify -quit "HELO"

Being able to do something like

swaks -s "$ip" -tls --tls-verify --tls-verify-hostname "$mx" -quit "HELO"

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.

jetmore commented 3 years 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)
kousu commented 3 years ago

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!

kousu commented 2 years ago

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:

comms.kousu.ca.fullchain.pem ``` -----BEGIN CERTIFICATE----- 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 bHq6Q2pY -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG /kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX nLRbwHOoq7hHwg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK 4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5 bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4 FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1 c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx +tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC 5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW 9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5 -----END CERTIFICATE----- ```

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:

versions ``` $ swaks --version swaks version DEVRELEASE Copyright (c) 2003-2008,2010-2020 John Jetmore This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. $ pacman -Qi swaks Name : swaks Version : 20201014.0-1 Description : Swiss Army Knife SMTP; Command line SMTP testing, including TLS and AUTH Architecture : any URL : https://jetmore.org/john/code/swaks/ Licenses : GPL Groups : None Provides : None Depends On : perl-net-dns perl-net-ssleay Optional Deps : None Required By : None Optional For : None Conflicts With : None Replaces : None Installed Size : 169.57 KiB Packager : Florian Pritz Build Date : Sat 31 Oct 2020 09:56:48 AM Install Date : Sat 10 Jul 2021 01:07:29 AM Install Reason : Explicitly installed Install Script : No Validated By : Signature ```
kousu commented 2 years ago

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:

mikebeaton commented 2 years ago

Many 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.

jetmore commented 2 years ago

@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

mikebeaton commented 2 years ago

@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.)

mikebeaton commented 2 years ago

@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 commented 2 years ago

@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.)

Yeah, I jumped the gun. Still broken

mikebeaton commented 1 year ago

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
jetmore commented 6 months ago

This issue has some twists in it, but here's what I think I see as issues:

  1. Would like to validate a different hostname than the one in -s (also in cases of --pipe and --socket) (https://github.com/jetmore/swaks/issues/37#issue-899161065)

Solution: There is now a --tls-verify-target option that allows this

  1. --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

  1. Can swaks print more detail of tls verification failures (https://github.com/jetmore/swaks/issues/37#issuecomment-1120923133)

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)
  1. More detail about the server's certs (https://github.com/jetmore/swaks/issues/37#issuecomment-1425777419)

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