Nmap Development mailing list archives
Re: Request: public key retrieval in nmap.get_ssl_certificate
From: Brandon Enright <bmenrigh () ucsd edu>
Date: Thu, 28 Jan 2010 21:56:06 +0000
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Thu, 28 Jan 2010 12:36:03 -0700 David Fifield <david () bamsoftware com> wrote:
All, I got a request for ssl-cert.nse to return the length of the certificate's public key, so the scritp can be used to check for short keys. Who wants to add support for this? I think it will be straightforward to add a new accessor method in nse_ssl_cert.cc. I see the addition of a new function, ssl_cert_pubkey, that calls the function X509_get_pubkey and returns a table representing the key information. David Fifield
I wrote a perl script that pulls the cert out of the script output and
passes it through openssl like so:
# $ cat | openssl x509 -text -fingerprint -noout
my @cmd = ('openssl',
'x509', '-text', '-fingerprint', '-noout');
my ($ccode, $in, $out, $err, $rcode);
$in = $cert;
$ccode = run \@cmd, \$in, \$out, \$err, timeout(5);
$rcode = $?;
unless ((defined $ccode) && ($rcode == 0)) {
warn $err if ((defined $err) && ($err ne ''));
}
else {
$cert_text = $out;
#warn 'got ', $out, "\n";
}
While we're on the topic of SSL certs and checking for bad things, here
are the things I'm checking for in snippets of hopefully-readable
perl. I know some of this is out of context but when you see a "push
@warning" that is a message that will be reported by the script.
# The sig alg
if ($cert_text =~ m/Signature Algorithm: (\S+)/) {
my $sig_alg = $1;
if ($sig_alg =~ m/md5/i) {
push @warning, {('name'=>'SSLCERT_MD5',
'severity'=>4,
'text'=>'SSL Cert on '
. $ps_port . ' is signed with MD5')};
}
elsif ($sig_alg =~ m/md2/i) {
push @warning, {('name'=>'SSLCERT_MD2',
'severity'=>7,
'text'=>'SSL Cert on '
. $ps_port . ' is signed with MD2')};
}
elsif ($sig_alg =~ m/md4/i) {
push @warning, {('name'=>'SSLCERT_MD4',
'severity'=>6,
'text'=>'SSL Cert on '
. $ps_port . ' is signed with MD4')};
}
elsif ($sig_alg !~ m/sha[1235]/i) {
push @warning, {('name'=>'SSLCERT_NOTSHA',
'severity'=>5,
'text'=>'SSL Cert on '
. $ps_port . ' is signed with a '
. 'SHA family algorithm')};
}
}
# The RSA size
if ($cert_text =~ m/Modulus \((\d+) bit\):/) {
my $size = $1;
if ($size < 1024) {
push @warning, {('name'=>'SSLCERT_SMALL',
'severity'=>6,
'text'=>'SSL Cert on '
. $ps_port . ' uses a small key ('
. $size . ')')};
}
if (($size != 512) &&
($size != 1024) &&
($size != 1536) &&
($size != 2048) &&
($size != 3072) &&
($size != 4096)) {
push @warning, {('name'=>'SSLCERT_ODDSIZE',
'severity'=>2,
'text'=>'SSL Cert on '
. $ps_port . ' uses odd sized key ('
. $size . ')')};
}
}
# The issuer and subject
if ($cert_text =~ m/Issuer: ([^\r\n]+)/) {
my $issuer = $1;
if ($cert_text =~ m/Subject: ([^\r\n]+)/) {
my $subject = $1;
my $selfsigned = 0;
if ($issuer eq $subject) {
push @warning, {('name'=>'SSLCERT_SELFSIG',
'severity'=>4,
'text'=>'SSL Cert on '
. $ps_port . ' is self-signed')};
$selfsigned = 1;
}
if ($issuer =~ m/Globus\sSimple|DigiCert|Thawt|
Equifax|cacert|Go\sDaddy|
IPS\sCertification|Comodo\sCA|
VeriSign\sTrust|Entrust\.net
/ix) {
push @warning, {('name'=>'SSLCERT_CASIG',
'severity'=>1,
'text'=>'SSL Cert on '
. $ps_port . ' is not '
. 'self-signed and may hold '
. 'more trust')};
}
else {
if ($issuer ne $subject) {
# To try to find more CAs
#warn 'Issuer: ', $issuer, "\n";
}
}
if ($subject =~ m/CN=(.*?)(?:, |\/|$)/) {
my $cn = $1;
unless ($cn =~ m/^[a-zA-Z0-9@._*-]+$/) {
push @warning, {('name'=>'SSLCERT_BADCN',
'severity'=>4,
'text'=>'SSL Cert on '
. $ps_port . ' does not have '
. 'a well-formed CN')};
}
if ($cn =~ m/^\*/) {
push @warning, {('name'=>'SSLCERT_WILDCARD',
'severity'=>4,
'text'=>'SSL Cert on '
. $ps_port . ' has wildcard'
. ' CN (' . $cn . ')')};
}
# Look for evil or fake CNs
if ($selfsigned == 1) {
if ($cn =~ m/Microsoft/i) {
push @warning, {('name'=>'SSLCERT_FAKECN',
'severity'=>8,
'text'=>'SSL Cert on '
. $ps_port . ' appears to'
. ' be faking a company CN')};
}
if ($cn =~ m/\b(?:evil|
hack(?:ed)?|
[op]wn(?:ed)?
)\b/xi) {
push @warning, {('name'=>'SSLCERT_EVILCN',
'severity'=>8,
'text'=>'SSL Cert on '
. $ps_port . ' appears to '
. ' be indicate a malicious service')};
}
}
}
else {
push @warning, {('name'=>'SSLCERT_NOCN',
'severity'=>4,
'text'=>'SSL Cert on '
. $ps_port . ' does not have '
. 'a CN in the subject')};
#warn 'Subject: ', $subject, "\n";
}
}
}
# The validity dates
if ($cert_text =~ m/Not Before: ([^\r\n]+(\d{4}) GMT)/) {
my $sbadyear = 0;
my $starttime = 0;
if (($2 < 1970) || ($2 >= 2038)) {
$sbadyear = 1;
}
else {
#warn 'start: ', $1, "\n";
$starttime = str2time($1);
unless (defined $starttime) {
$sbadyear = 1;
}
}
if ($cert_text =~ m/Not After : ([^\r\n]+(\d{4}) GMT)/) {
my $ebadyear = 0;
my $endtime = 0;
if (($2 < 1970) || ($2 >= 2038)) {
$ebadyear = 1;
}
else {
#warn 'end: ', $1, "\n";
$endtime = str2time($1);
unless (defined $endtime) {
$ebadyear = 1;
}
}
if (($sbadyear == 1) || ($ebadyear == 1)) {
push @warning, {('name'=>'SSLCERT_BADYEAR',
'severity'=>2,
'text'=>'SSL Cert on '
. $ps_port . ' is valid for a '
. 'nonsensical date range')};
}
else {
if ($starttime >= $endtime) {
push @warning, {('name'=>'SSLCERT_NEVER',
'severity'=>2,
'text'=>'SSL Cert on '
. $ps_port . ' is never valid'
. ' based on date range')};
}
if ($starttime > $cur_time) {
push @warning, {('name'=>'SSLCERT_FUTURE',
L 'severity'=>2,
'text'=>'SSL Cert on '
. $ps_port . ' is only valid '
. 'in the future')};
}
if ($endtime < $cur_time) {
push @warning, {('name'=>'SSLCERT_EXPIRED',
'severity'=>3,
'text'=>'SSL Cert on '
. $ps_port . ' has expired')};
}
if (($endtime > $cur_time) &&
($endtime < $cur_time + 60 * 24 * 60 * 60)) {
push @warning, {('name'=>'SSLCERT_EXPIRESOON',
'severity'=>1,
'text'=>'SSL Cert on '
. $ps_port . ' will expire'
. ' soon')};
}
if (($endtime - $starttime) >
(10 * 356.4 * 24 * 60 * 60)) {
push @warning, {('name'=>'SSLCERT_DECADE',
'severity'=>3,
'text'=>'SSL Cert on '
. $ps_port . ' is valid for '
. 'more than a decade')};
}
} # End is good year in dates
}
Hopefully other people wanting to audit their organization's SSL
deployments will find this useful.
Brandon
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.11 (GNU/Linux)
iEYEARECAAYFAktiCAUACgkQqaGPzAsl94IqtwCeM+l660HJLUQ0/mMKuzuPj88n
l/4AoItH7/t6PWjAnucKsNCmLysXX9ha
=/kA4
-----END PGP SIGNATURE-----
_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://seclists.org/nmap-dev/
Current thread:
- Request: public key retrieval in nmap.get_ssl_certificate David Fifield (Jan 28)
- Re: Request: public key retrieval in nmap.get_ssl_certificate Ron (Jan 28)
- Re: Request: public key retrieval in nmap.get_ssl_certificate Brandon Enright (Jan 28)
