Skip to content

Commit

Permalink
Start investigating and charting 1024-bit embedded keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
iay committed Jul 31, 2012
1 parent 209e19e commit fc7f707
Show file tree
Hide file tree
Showing 2 changed files with 330 additions and 0 deletions.
47 changes: 47 additions & 0 deletions charting/shortkeys.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/perl -w

#
# shortkeys.pl
#
# Extracts statistics about short embedded keys from the published metadata.
#
use lib "../build";
use Xalan;
use Months;

# Parse command line arguments
use Getopt::Long;
my $allMonths;
GetOptions('all' => \$allMonths);

# By default, only show results for the most recent month
if (!$allMonths) {
# reduce months table to one element
my $oneMonth = pop @months;
@months = ( $oneMonth );
}

# ingest files
foreach $month (@months) {
print "processing $month\n";
my $fn = "cache/$month.xml";
my $command = xalanCall . " -IN $fn -XSL ../build/extract_embedded.xsl -OUT temp.tmp";
# print "command is $command\n";
system($command); # || print "ignoring claimed failure in sub command\n";
#print "Xalan run on $fn\n";
open(TXT, "perl shortkeys_inner.pl -q <temp.tmp|") || die "could not open input file";
my $count = 0;
while (<TXT>) {
if (/^ 1024: (\d+)$/) {
$count = $1;
}
#print $_;
}
push @counts, "$month: $count";
close TXT;
}

print "Key count:\n";
foreach $count (@counts) {
print "$count\n";
}
283 changes: 283 additions & 0 deletions charting/shortkeys_inner.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
#!/usr/bin/perl -w
use POSIX qw(floor);
use File::Temp qw(tempfile);
use Date::Parse;
use Digest::SHA1 qw(sha1 sha1_hex sha1_base64);

#
# Perform checks on a series of certificates that are to be, or have been, embedded in the
# UK federation metadata.
#
# The certificates are provided on standard input in PEM format with header lines
# indicating the entity with which they are associated.
#
# Command line options:
#
# -q quiet don't print anything out if there are no problems detected
#

sub error {
my($s) = @_;
push(@olines, ' *** ' . $s . ' ***');
$printme = 1;
}

sub warning {
my ($s) = @_;
push(@olines, ' ' . $s);
$printme = 1;
}

sub comment {
my($s) = @_;
push(@olines, ' (' . $s . ')');
}

#
# Process command-line options.
#
while (@ARGV) {
$arg = shift @ARGV;
$quiet = 1 if $arg eq '-q';
}

#
# Hash of already-seen blobs.
#
# Each entry in the hash is indexed by the blob itself. Each blob is a concatenated
# sequence of information that uniquely identifies an already checked key. This is
# used to avoid processing the same blob more than once.
#
my %blobs;

#
# Blob currently being constructed.
#
my $blob;

#
# Size of expiry statistical bins.
#
my $binSize = 90;

#
# Proposed evolution deadline.
#
my $deadline = "2014-01-01T00:00:00";
my $deadlineTime = str2time($deadline);

while (<>) {

#
# Discard blank lines.
#
next if /^\s*$/;

#
# Handle Entity/KeyName header line.
#
if (/^Entity:/) {
@olines = ();
$printme = 0;
@args = split;
$entity = $args[1];
$keyname = $args[3];

#
# Output header line.
#
$oline = "Entity $entity ";
$hasKeyName = !($keyname eq '(none)');
if ($hasKeyName) {
$oline .= "has KeyName $keyname";
} else {
$oline .= "has no KeyName";
}
push(@olines, $oline);
$blob = $oline; # start building a new blob

#
# Create a temporary file for this certificate in PEM format.
#
($fh, $filename) = tempfile(UNLINK => 1);
#print "temp file is: $filename\n";

# do not buffer output to the temporary file
select((select($fh), $|=1)[0]);
next;
}

#
# Put other lines into a temporary file.
#
print $fh $_;
$blob .= '|' . $_;

#
# If this is the last line of the certificate, actually do
# something with it.
#
if (/END CERTIFICATE/) {
#
# Have we seen this blob before? If so, close (and delete) the
# temporary file, and go and look for a new certificate to process.
#
$total_certs++;
if (defined($blobs{$blob})) {
# print "skipping a blob\n";
close $fh;
next;
}

#
# Otherwise, remember this blob so that we won't process it again.
#
$blobs{$blob} = 1;
$distinct_certs++;

#
# Don't close the temporary file yet, because that would cause it
# to be deleted. We've already arranged for buffering to be
# disabled, so the file can simply be passed to other applications
# as input, perhaps multiple times.
#

#
# Collection of names this certificate contains
#
my %names;

#
# Use openssl to convert the certificate to text
#
my(@lines, $issuer, $subjectCN, $issuerCN);
$cmd = "openssl x509 -in $filename -noout -text -nameopt RFC2253 -modulus |";
open(SSL, $cmd) || die "could not open openssl subcommand: $!";
$expiryBin = -1;
while (<SSL>) {
push @lines, $_;

if (/^\s*Issuer:\s*(.*)$/) {
$issuer = $1;
if ($issuer =~ /CN=([^,]+)/) {
$issuerCN = $1;
} else {
$issuerCN = $issuer;
}
next;
}

if (/^\s*Subject:\s*.*?CN=([a-zA-Z0-9\-\.]+).*$/) {
$subjectCN = $1;
$names{lc $subjectCN}++;
# print "subjectCN = $subjectCN\n";
next;
}

#
# Extract the public key size. This is displayed differently
# in different versions of OpenSSL.
#
if (/RSA Public Key: \((\d+) bit\)/) { # OpenSSL 0.9x
$pubSize = $1;
$pubSizeCount{$pubSize}++;
# print " Public key size: $pubSize\n";
if ($pubSize < 1024) {
error('PUBLIC KEY TOO SHORT');
}
next;
} elsif (/^\s*Public-Key: \((\d+) bit\)/) { # OpenSSL 1.0
$pubSize = $1;
$pubSizeCount{$pubSize}++;
# print " Public key size: $pubSize\n";
if ($pubSize < 1024) {
error('PUBLIC KEY TOO SHORT');
}
next;
}

if (/Not After : (.*)$/) {
$notAfter = $1;
$notAfterTime = str2time($notAfter);
$days = (str2time($notAfter)-time())/86400.0;
next;
}

}
close SSL;

#
# Check KeyName if one has been supplied.
#
if ($hasKeyName && !defined($names{lc $keyname})) {
my $nameList = join ", ", sort keys %names;
error("KeyName mismatch: $keyname not in {$nameList}");
}

#
# Use openssl to ask whether this matches our trust fabric or not.
#
my $error = '';

#
# Close the temporary file, which will also cause
# it to be deleted.
#
close $fh;

#
# Record expiry bin if 1024-bit key.
#
if ($pubSize == 1024) {
if ($days < 0) {
$expiryBin = -1;
print "expired 1024-bit certificate on $entity\n";
} else {
$expiryBin = floor($days/$binSize);
}
if ($expiryBin == 0) {
print "Expiry bin 0 dated $notAfter on $entity\n";
} elsif ($notAfterTime > $deadlineTime) {
print "Long expiry dated $notAfter on $entity\n";
$expiryBin = 99;
print " issued by $issuerCN\n";
}
$expiryBinned{$expiryBin}++;
}

#
# Print any interesting things related to this certificate.
#
if ($printme || !$quiet) {
foreach $oline (@olines) {
print $oline, "\n";
}
print "\n";
}
}
}

sub numerically {
$a <=> $b;
}

if ($total_certs > 1) {
print "Total certificates: $total_certs\n";
if ($distinct_certs != $total_certs) {
print "Distinct certificates: $distinct_certs\n";
}
print "Key size distribution:\n";
for $pubSize (sort keys %pubSizeCount) {
$count = $pubSizeCount{$pubSize};
print " $pubSize: $count\n";
}
print "Expiry bins:\n";
$total = 0;
for $bin (sort numerically keys %expiryBinned) {
$days = $binSize * $bin;
$count = $expiryBinned{$bin};
$total += $count;
print " $bin: $count\n";
}
print "Total: $total\n";
}

0 comments on commit fc7f707

Please sign in to comment.