Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

Using a command line website downloader, such as wget, curl or any other one... In a script...

I have the SHA-1 and the SHA-256 certficate fingerprint of a website. Due to security concerns (1) (2), I don't want to use the public SSL certificate authority system. The fingerprint must be hard coded.

Can a wget like application check the SSL fingerprint?

wget does not have such a functionality. (3)

Using wget --ca-certificate or curl --cacert I would have to run my own local certificate authority, which I'd like to prevent, because that adds a lot complexity. It's also ultra difficult and no one did that ever before. (4)

Isn't there any tool, like
download --tlsv1 --serial-number xx:yy:zz --fingerprint xxyyzz https://site.com?

The solution must of course not be vulnerable to TOCTOU. (5) The MITM could let return a valid fingerprint for the openssl client request and tamper with the following wget request.

share|improve this question
    
I don't have time to write out a usable answer now, but this should be doable in Perl or Python. Check out LWP, ssl/twisted, ssl+httplib –  Gilles Sep 19 '12 at 23:24
    
Visitors: do note that this was cross-posted to the askubuntu SE. The answer below was copied there. This is frowned-upon behaviour, btw. –  Félix Saparelli yesterday

1 Answer 1

up vote 6 down vote accepted

NEW ANSWER:

Reviewing your link #4, it seems like you've investigated existing utilities and received the answer that what you want would have to be programmed. Doing so is relatively trivial. The following Perl script will do what you want:

#!/usr/bin/perl
# Code snippets taken from Net::SSLeay documentation and mildly modified.
# Requires a newer version of SSLeay (tested with 1.48)
# Needless to say, verify correct $host and $fingerprint before testing!!!

use Net::SSLeay qw(get_https3);

$host = "www.google.com";
$port = 443;
$fingerprint = "C1:95:6D:C8:A7:DF:B2:A5:A5:69:34:DA:09:77:8E:3A:11:02:33:58";

($p, $resp, $hdrs, $server_cert) = get_https3($host, $port, '/');
if (!defined($server_cert) || ($server_cert == 0)) {
    warn "Subject Name: undefined, Issuer  Name: undefined";
} elsif (Net::SSLeay::X509_get_fingerprint($server_cert, "sha1") ne $fingerprint) {
    warn 'Invalid certificate fingerprint '
        .  Net::SSLeay::X509_get_fingerprint($server_cert, "sha1")
        . ' for ' . Net::SSLeay::X509_NAME_oneline(
             Net::SSLeay::X509_get_subject_name($server_cert));
} else {
    print $p;
}

As is outlined in the Net::SSLeay documentation, this method means verification after the HTTP transaction, and so should not be used if you want to verify you're talking to the right server before sending them data. But if all you're doing is deciding whether or not to trust what you just downloaded (which is sounds like you are from your reference #4) this is fine.

OLD ANSWER:

You can use openssl as described here:

To wit,

openssl s_client -connect <host>:<port> < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin

(Old answer was) Updated

As @Gilles has pointed out, this doesn't meet the requirement to combine the certificate verification with the actual content retrieval.

Because openssl s_client combines the certificate information and the server response into the stdout stream, it cannot be simply used for this purpose. It is probably possible to write a script that would slurp up the combined output and separate the two based on some simple test parsing, but that's not exactly a turnkey solution.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.