diff --git a/build/extract_nk_cert_locs.xsl b/build/extract_nk_cert_locs.xsl new file mode 100644 index 00000000..b18d937d --- /dev/null +++ b/build/extract_nk_cert_locs.xsl @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/extract_nk_nocert_locs.xsl b/build/extract_nk_nocert_locs.xsl new file mode 100644 index 00000000..fae05589 --- /dev/null +++ b/build/extract_nk_nocert_locs.xsl @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/probe_nk_certs.pl b/build/probe_nk_certs.pl new file mode 100755 index 00000000..6d44f298 --- /dev/null +++ b/build/probe_nk_certs.pl @@ -0,0 +1,156 @@ +#!/usr/bin/perl -w + +use POSIX qw(floor); +use Date::Parse; +use ExtractCert; +use Xalan; + +sub error { + my($s) = @_; + print ' *** ' . $s . ' ***' . "\n"; + $printme = 1; +} + +sub warning { + my ($s) = @_; + print ' ' . $s . "\n"; + $printme = 1; +} + +sub comment { + my($s) = @_; + print ' (' . $s . ')' . "\n"; +} + +# +# Number of days in the past we should regard as "long expired". +# +my $longExpiredDays = 30*3; # about three months + +print "Loading endpoint locations...\n"; +open(XML, xalanCall . " -IN ../xml/ukfederation-metadata.xml -XSL extract_nk_cert_locs.xsl|") || die "could not open input file"; +while () { + my ($entity, $url) = split; + if ($url =~ /^https:\/\/([^\/:]+(:\d+)?)\//) { + my $location = $1; + $location .= ":443" unless defined $2; + $locations{$location} = $entity; + } else { + print "bad location: $_"; + } +} +close XML; + +$count = scalar keys %locations; +print "Unique SSL with-certificate locations: $count\n"; + +# +# Temporary output file for certificate extraction tool. +# +$temp_der = '/tmp/probe_certs.der'; + +# +# Extract the certificate from each location. +# +foreach $loc (sort keys %locations) { + my $entity = $locations{$loc}; + print "$count: probing $entity: $loc\n"; + $count--; + + # + # Remove any old copy of the DER file. + # + unlink $temp_der; + + # + # Separate location into host and port. + # + my ($host, $port) = split(/:/, $loc); + #print "host: $host, port: $port\n"; + my $hostPort = "$host:$port"; + + # + # Attempt certificate extraction + # + system extractCertCall . " $host $port $temp_der"; + + # + # If the output file doesn't exist, the extraction failed. + # + if (!-e $temp_der) { + print "*** $hostPort: certificate extraction failed\n"; + $failed{$loc} = 1; + next; + } + + # + # Use openssl to convert the certificate to text + # + my(@lines, $subject, $issuer); + $cmd = "openssl x509 -in $temp_der -inform der -noout -text -nameopt RFC2253 -modulus |"; + open(SSL, $cmd) || die "could not open openssl subcommand"; + while () { + push @lines, $_; + + if (/^\s*Issuer:\s*(.*)$/) { + $issuer = $1; + #print "$hostPort: issuer is $issuer\n"; + } + + if (/^\s*Subject:\s*(.*)$/) { + $subject = $1; + } + + if (/Not After : (.*)$/) { + $notAfter = $1; + $notAfterTime = str2time($notAfter); + $days = ($notAfterTime-time())/86400.0; + if ($days < -$longExpiredDays) { + my $d = floor(-$days); + error("EXPIRED LONG AGO ($d days; $notAfter)"); + } elsif ($days < 0) { + error("EXPIRED ($notAfter)"); + } elsif ($days < 18) { + $days = int($days); + error("expires in $days days ($notAfter)"); + } elsif ($days < 36) { + $days = int($days); + warning("expires in $days days ($notAfter)"); + } + next; + } + + } + + if ($subject eq $issuer) { + $issuer = "(self-signed certificate)"; + } + + $issuers{$issuer}{$loc} = 1; + $numissued++; +} +print "\n\n"; + +$count = scalar keys %failed; +print "\n\nProbes that failed: $count\n"; +foreach $loc (sort keys %failed) { + print " $loc\n"; +} +print "\n\n"; + +print "Probes we got an issuer back from: $numissued\n"; +$count = scalar keys %issuers; +print "Unique issuers: $count\n"; +foreach $issuer (sort keys %issuers) { + %locs = %{ $issuers{$issuer} }; + $n = scalar keys %locs; + print "$n: $issuer\n"; + foreach $loc (sort keys %locs) { + print " $loc\n"; + } +} + +# +# Clean up +# +unlink $temp_der; diff --git a/build/probe_nk_nocerts.pl b/build/probe_nk_nocerts.pl new file mode 100755 index 00000000..9d850118 --- /dev/null +++ b/build/probe_nk_nocerts.pl @@ -0,0 +1,162 @@ +#!/usr/bin/perl -w + +use POSIX qw(floor); +use Date::Parse; +use ExtractCert; +use Xalan; + +sub error { + my($s) = @_; + print ' *** ' . $s . ' ***' . "\n"; + $printme = 1; +} + +sub warning { + my ($s) = @_; + print ' ' . $s . "\n"; + $printme = 1; +} + +sub comment { + my($s) = @_; + print ' (' . $s . ')' . "\n"; +} + +$known_bad{'census.data-archive.ac.uk:8080'} = 1; # it is really http, not https + +# +# Number of days in the past we should regard as "long expired". +# +my $longExpiredDays = 30*3; # about three months + +print "Loading endpoint locations...\n"; +open(XML, xalanCall . " -IN ../xml/ukfederation-metadata.xml -XSL extract_nk_nocert_locs.xsl|") || die "could not open input file"; +while () { + my ($entity, $url) = split; + if ($url =~ /^https:\/\/([^\/:]+(:\d+)?)(\/|$)/) { + my $location = $1; + $location .= ":443" unless defined $2; + if ($known_bad{$location}) { + print "skipping known bad location: $_\n"; + } else { + $locations{$location} = $entity; + } + } else { + print "bad location: $_\n"; + } +} +close XML; + +$count = scalar keys %locations; +print "Unique SSL non-certificate locations: $count\n"; + +# +# Temporary output file for certificate extraction tool. +# +$temp_der = '/tmp/probe_nocerts.der'; + +# +# Extract the certificate from each location. +# +foreach $loc (sort keys %locations) { + my $entity = $locations{$loc}; + print "$count: probing $entity: $loc\n"; + $count--; + + # + # Remove any old copy of the DER file. + # + unlink $temp_der; + + # + # Separate location into host and port. + # + my ($host, $port) = split(/:/, $loc); + #print "host: $host, port: $port\n"; + my $hostPort = "$host:$port"; + + # + # Attempt certificate extraction + # + system extractCertCall . " $host $port $temp_der"; + + # + # If the output file doesn't exist, the extraction failed. + # + if (!-e $temp_der) { + print "*** $hostPort: certificate extraction failed\n"; + $failed{$loc} = 1; + next; + } + + # + # Use openssl to convert the certificate to text + # + my(@lines, $issuer, $subjectCN, $issuerCN); + $cmd = "openssl x509 -in $temp_der -inform der -noout -text -nameopt RFC2253 -modulus |"; + open(SSL, $cmd) || die "could not open openssl subcommand"; + while () { + push @lines, $_; + + if (/^\s*Issuer:\s*(.*)$/) { + $issuer = $1; + #print "$hostPort: issuer is $issuer\n"; + } + + if (/^\s*Subject:\s*(.*)$/) { + $subject = $1; + } + + if (/Not After : (.*)$/) { + $notAfter = $1; + $notAfterTime = str2time($notAfter); + $days = ($notAfterTime-time())/86400.0; + if ($days < -$longExpiredDays) { + my $d = floor(-$days); + error("EXPIRED LONG AGO ($d days; $notAfter)"); + } elsif ($days < 0) { + error("EXPIRED ($notAfter)"); + } elsif ($days < 18) { + $days = int($days); + error("expires in $days days ($notAfter)"); + } elsif ($days < 36) { + $days = int($days); + warning("expires in $days days ($notAfter)"); + } + next; + } + + } + + if ($subject eq $issuer) { + $issuer = "(self-signed certificate)"; + } + + $issuers{$issuer}{$loc} = 1; + $numissued++; +} +print "\n\n"; + +$count = scalar keys %failed; +print "\n\nProbes that failed: $count\n"; +foreach $loc (sort keys %failed) { + print " $loc\n"; +} +print "\n\n"; + +print "Probes we got an issuer back from: $numissued\n"; +$count = scalar keys %issuers; +print "Unique issuers: $count\n"; +foreach $issuer (sort keys %issuers) { + %locs = %{ $issuers{$issuer} }; + $n = scalar keys %locs; + print "$n: $issuer\n"; + foreach $loc (sort keys %locs) { + print " $loc\n"; + } +} + +# +# Clean up +# +unlink $temp_der;