-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Suite of scripts to look at certificate expiry on endpoints belonging…
… to no-key (PKIX-only) entities.
- Loading branch information
Showing
4 changed files
with
429 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!-- | ||
| extract_nk_cert_locs.xsl | ||
| XSL stylesheet that takes a SAML 2.0 metadata file and extracts | ||
| a list of service locations that require certificates to be | ||
| presented to them. | ||
| Author: Ian A. Young <ian@iay.org.uk> | ||
| --> | ||
| <xsl:stylesheet version="1.0" | ||
| xmlns:ds="http://www.w3.org/2000/09/xmldsig#" | ||
| xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | ||
| xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| exclude-result-prefixes="md"> | ||
|
|
||
| <!-- Output is plain text --> | ||
| <xsl:output method="text"/> | ||
|
|
||
| <!-- | ||
| Exclude entities which have embedded certificates. | ||
| I.e., restrict output to entities which only have PKIX trust. | ||
| --> | ||
| <xsl:template match="md:EntityDescriptor[descendant::ds:X509Data]"> | ||
| <!-- do nothing --> | ||
| </xsl:template> | ||
|
|
||
| <xsl:template match="//md:AttributeService"> | ||
| <xsl:value-of select="ancestor::md:EntityDescriptor/@ID"/> | ||
| <xsl:text> </xsl:text> | ||
| <xsl:value-of select="@Location"/> | ||
| <xsl:text>
</xsl:text> | ||
| </xsl:template> | ||
|
|
||
| <!-- | ||
| ArtifactResolutionService endpoints on IdPs are assumed to be | ||
| authenticated by TLS; those on SPs are assumed to be authenticated | ||
| using other mechanisms. | ||
| --> | ||
| <xsl:template match="//md:IDPSSODescriptor/md:ArtifactResolutionService"> | ||
| <xsl:value-of select="ancestor::md:EntityDescriptor/@ID"/> | ||
| <xsl:text> </xsl:text> | ||
| <xsl:value-of select="@Location"/> | ||
| <xsl:text>
</xsl:text> | ||
| </xsl:template> | ||
|
|
||
| <xsl:template match="text()"> | ||
| <!-- do nothing --> | ||
| </xsl:template> | ||
| </xsl:stylesheet> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!-- | ||
| extract_nk_nocert_locs.xsl | ||
| XSL stylesheet that takes a SAML 2.0 metadata file and extracts | ||
| a list of service locations that do not require certificates to be | ||
| presented to them. | ||
| Author: Ian A. Young <ian@iay.org.uk> | ||
| --> | ||
| <xsl:stylesheet version="1.0" | ||
| xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | ||
| xmlns:ds="http://www.w3.org/2000/09/xmldsig#" | ||
| xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xmlns:wayf="http://sdss.ac.uk/2006/06/WAYF" | ||
| exclude-result-prefixes="md ds wayf"> | ||
|
|
||
| <!-- Output is plain text --> | ||
| <xsl:output method="text"/> | ||
|
|
||
| <!-- | ||
| Exclude entities which have embedded certificates. | ||
| I.e., restrict output to entities which only have PKIX trust. | ||
| --> | ||
| <xsl:template match="md:EntityDescriptor[descendant::ds:X509Data]"> | ||
| <!-- do nothing --> | ||
| </xsl:template> | ||
|
|
||
| <xsl:template match="//md:SingleSignOnService"> | ||
| <xsl:value-of select="ancestor::md:EntityDescriptor/@ID"/> | ||
| <xsl:text> </xsl:text> | ||
| <xsl:value-of select="@Location"/> | ||
| <xsl:text>
</xsl:text> | ||
| </xsl:template> | ||
|
|
||
| <xsl:template match="//md:AssertionConsumerService"> | ||
| <xsl:value-of select="ancestor::md:EntityDescriptor/@ID"/> | ||
| <xsl:text> </xsl:text> | ||
| <xsl:value-of select="@Location"/> | ||
| <xsl:text>
</xsl:text> | ||
| </xsl:template> | ||
|
|
||
| <xsl:template match="//md:SPSSODescriptor/md:ArtifactResolutionService"> | ||
| <xsl:value-of select="ancestor::md:EntityDescriptor/@ID"/> | ||
| <xsl:text> </xsl:text> | ||
| <xsl:value-of select="@Location"/> | ||
| <xsl:text>
</xsl:text> | ||
| </xsl:template> | ||
|
|
||
| <xsl:template match="text()"> | ||
| <!-- do nothing --> | ||
| </xsl:template> | ||
| </xsl:stylesheet> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 (<XML>) { | ||
| 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 (<SSL>) { | ||
| 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; |
Oops, something went wrong.