Copying this ticket over from Sourceforge for visibility, as it's fairly important.
Original creation date: 2014-07-17
Tcl tls doesn't provide any mechanism for checking that the subject of the peer's certificate matches the hostname to which the connection has been made.
For example, suppose bogus_site.org returns a certificate with a subject field containing 'CN=some_other_site.org'.
As of tls 1.6, even if I specify certificate validation with "-require 1", tls::socket won't complain about the server hostname not matching the server certificate's subject name - e.g.
set sock [tls::socket -require 1 bogus_site.org 443]
would return 1 (handshake OK) even if the certificate presented by bogus_site.org has a subject name for a totally different domain.
Now, I acknowledge that:
* folks often use tls::import instead of tls::socket so tls won't necessarily have access to the peer hostname; and
* making the above example reject the connection might cause backwards compatibility problems;
But doesn't it feel like the tls package should offer something to help application developers check the certificate subject? Otherwise it's giving a false sense of security - yes, my connection is encrypted, and yes, the server has a certificate - but there's no assurance that I'm not talking to an impostor!
As a workaround, an application could (and probably should!) call the tls::status command after the handshake to retrieve the subject DN, parse it for CN entries, then perform their own validation. The application could also do this using its own custom verify callback (set-up with the -command option to tls::socket/tls::import).
However, there are two problems with this workaround:
1) tls::status does not return the "X509v3 Subject Alternative Name" information from the certificate (http://tools.ietf.org/html/rfc3280#section-184.108.40.206) - nowadays certificates often put the subject identity information there instead of the Subject DN (particulaly with multi-domain certificates used by cloud providers).
2) This academic paper - http://www.cs.utexas.edu/~shmat/shmat_ccs12.pdf - calls "Validating SSL Certificates in Non-Browser Software" the "Most Dangerous Code in the World" since applications get it wrong so often. I'm not sure I'd go quite that far, but relying on application code to perform these checks seems unwise - parsing DN strings robustly is quite fiddly, and I'm not sure many developers would even think about the need to check the subject against the hostname - they'd expect tls/OpenSSL to do that for them.
So I suggest that to fix this problem, tls should be modified to:
(A) Expose the "X509v3 Subject Alternative Name" extension information (if present in the certificate) via a new entry "subjectAltName" in the tls::status command to allow client applications to perform their own validation. This information should also appear in the cert argument to the verify callback.
(B) Provide a mechanism for checking the peer certificate subject (including any Subject Alternative Names) against a caller-provided hostname.
I'm afraid I don't have a patch to do either of those things!
I guess the usage for (B) might be a new option to tls::import / tls::socket along the lines of:
If specified, then - following certificate validation - the
given hostname will be matched against the DNS names found in
the subjectAltName extension of the peer certificate, or if no
subjectAltName extension is present, against the commonName(s)
found in the subject field of the certificate.
If no match is found, the certificate will be rejected.
Note that if this option is specified then -require must also be
set to true.
Default is "" (no hostname matching).
The official subject identity matching rules are fairly complex - see http://tools.ietf.org/html/rfc6125 - but providing support for the most common case of testing a domain name against the domain names in subjectAltName (or the CN in the subject field) should hopefully cover 99% of uses - with the other 1% satisfied by the option to do custom matching via the new subjectAltName info returned from tls::status.