« Apache Tomcat 7.0.26 Released | Main | Fixing an IIS7/isapi_redirect/Tomcat "Service Unavailable" Issue »

03/05/2012

Validating SSL Certificates

Recently, @johngoggan notified me via tweet that (I am paraphrasing here) the insecure argument in cryptonark is still too secure in that cryptonark will still exit if the common name on the certificate does not match the host name that cryptonark is scanning. Although embarrassed that I missed this, I was also quite happy as this was the first bit of direct feedback on functionality that I have had with cryptonark since it was launched back in July, 2009.

insecure initially was set up to disable certificate verification and I was specifically thinking of those use cases where you are scanning a host using a self-signed certificate or when you have an invalid chain. My ultimate goal with it, however, was to emulate the insecure switch in cURL. As John pointed out, cryptonark version 0.4.6 and below will not perform the cipher scan if the hostname doesn't match the common name on the cert. I have addressed this by completely disabling host and certificate validation when insecure is used. While playing around with it though, I have come across some other functionality that I was not thrilled with, which required me slightly overhauling cryptonark's certificate verification functionality.

Typically, when you purchase a CA signed certificate, you specify a Common Name, like "www.somesite.com". Many CA's will automatically attach a Subject Alternative Name of "somesite.com" as part of your purchase, which allows browsers to connect using either the www.somesite.com name or the somesite.com name. In this example, www.somesite.com is the common name and somesite.com is a Subject Alternative Name. Although cryptonark still successfully validated the certificate if you specified the Subject Alternative Name as part of the host argument, if would only display the certificate Common Name in the output with no mention that a Subject Alternative Name of somesite.com exists for this cert. This might be confusing for some people scanning a host secured by an ssl crtificate that has a lot of Subject Alternative Names attached to it.

Below is a new script that you can use that will validate the certificate that secures a host or site and will display the Common Name and any Subject Alternative Names defined on the cert. Validation is performed against Mozilla's certificate store, included in the script using perl module Mozilla::CA. You will not need firefox installed on your machine but you will need to download Mozilla::CA from the CPAN. There is no insecure switch with this script as it's express purpose is to validate certificates but this script will be incorporated into CryptoNark 0.4.7. There are only two arguments, host and port. The script also makes use of my personal favorite module IO::Socket:SSL for connecting to ssl sites, Modern::Perl and Getopt::Long.

#!/usr/bin/env perl

use Modern::Perl;
use IO::Socket::SSL;
use Mozilla::CA;
use Getopt::Long;

my $host;
my $port;
my $verifymode = '0';

sub usage{
    say "Usage: chkcert.pl -h|--host <hostname> -p|--port <port number>";
    exit;
  }

usage() if ( ! GetOptions("h|host=s" => \$host, "p|port=s" => \$port) or ( ! defined $host) or ( ! defined $port) );

# Basic certificate checking
sub cert_info{
say "\nVerifying SSL Certificate...\n";
sleep 2;

my $certclient = IO::Socket::SSL->new(
  PeerHost => "$host:$port",
  SSL_ca_file => Mozilla::CA::SSL_ca_file(),
  SSL_verify_mode => $verifymode,
  SSL_version => 'TLSv1',
  SSL_cipher_list => 'RC4-SHA',
  Proto => 'tcp',
  Timeout => '5',
  ) 
    || die("Certificate Peer Verification Failed\n\nCertificate not trusted. This could be due to:\n  + An invalid certificate chain\n  + A self-signed certificate\n  + You are scanning the IP address and not the DNS hostname\n  + Host $host does not appear to be listening on port $port\n  + You misspelled the intended host to be scanned.\n  + The CA signing this cert is not trusted by your version of Mozilla::CA\n\n");

  $certclient->verify_hostname($host, "http")
    || die("Hostname Verification Failed.\n$host does not match certificate's common name.\n\n");
  say "Certificate appears to be valid.";
  my $cn = $certclient->peer_certificate("cn");
  if ( $cn eq "" ) {
    say "Certificate Common Name: none";
    }
    else {
      say "Certificate Commmon Name: " . $cn;
      }

  my @san = $certclient->peer_certificate("subjectAltNames");
  my $san_names = join(" ", grep { !( $_ eq 2 ) } @san);

  if ( $san_names eq "" ) {
    say "Subject Alternative Names: none";
    }
    else {
  say "Subject Alternative Names: " . $san_names;
  }
}

cert_info();

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a01156fbc6fe6970c0168e877347d970c

Listed below are links to weblogs that reference Validating SSL Certificates:

Comments