aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2006-08-29 20:16:17 +0000
committerRob Austein <sra@hactrn.net>2006-08-29 20:16:17 +0000
commitd77d8838fbe14def02d9deb2dc21f5b9eb9e44bc (patch)
tree62744c9773f8a7bc20af549535d00a2c9881c6a4
parentc17eff1749287c1aa0b6068b7410da6ea1f18e49 (diff)
Now far enough along to break in interesting (as opposed to totally
stupid) ways. svn path=/scripts/rcynic-prototype.pl; revision=240
-rw-r--r--scripts/rcynic-prototype.pl251
1 files changed, 159 insertions, 92 deletions
diff --git a/scripts/rcynic-prototype.pl b/scripts/rcynic-prototype.pl
index 67826df3..e536a227 100644
--- a/scripts/rcynic-prototype.pl
+++ b/scripts/rcynic-prototype.pl
@@ -10,12 +10,15 @@
use strict;
+my $openssl = "/u/sra/isc/route-pki/subvert-rpki.hactrn.net/openssl/trunk/apps/openssl";
+
my $root = "rcynic-data";
my $trust_anchor_tree = "$root/trust-anchors";
my $preaggregated_tree = "$root/preaggregated";
my $unauthenticated_tree = "$root/unauthenticated";
my $authenticated_tree = "$root/authenticated";
my $temporary_tree = "$root/temporary";
+my $cafile = "$root/CAfile.pem";
my @anchors;
my @preaggregated;
@@ -29,6 +32,31 @@ sub mkdir_maybe {
unless (-d $dir);
}
+sub rsync {
+ !system("rsync", "-ai", @_)
+ or die("Couldn't rsync @_");
+}
+
+sub openssl {
+ !system($openssl, @_)
+ or die("Couldn't openssl @_");
+}
+
+sub openssl_pipe {
+ my $pid = open(F, "-|");
+ if ($pid) {
+ my @result = <F>;
+ close(F);
+ chomp(@result);
+ return @result;
+ } else {
+ open(STDERR, ">&STDOUT")
+ or die("Couldn't dup() STDOUT: $!");
+ exec($openssl, @_)
+ or die("Couldn't exec() openssl @_: $!");
+ }
+}
+
sub uri_to_filename {
local $_ = shift;
if ($_) {
@@ -43,30 +71,23 @@ sub uri_to_filename {
sub extract_cert_uris {
my $uri = shift;
- my $dir = shift;
+ my $dir = shift || $authenticated_tree;
my $file = uri_to_filename($uri);
my %res = (file => $file, uri => $uri);
my ($a, $s, $c);
+ my @txt = openssl_pipe(qw(x509 -noout -text -in), "$dir/$file");
local $_;
- open(F, "-|", qw(openssl x509 -noout -inform DER -text -in), "$dir/$file")
- or die("Couldn't run openssl x509 on $file: $!");
- while (<F>) {
- chomp;
- s{^.+URI:rsync://}{};
- $a = $. + 1
+ s=^.+URI:==
+ foreach (@txt);
+ for (my $i = 0; $i < @txt; ++$i) {
+ $_ = $txt[$i];
+ $res{aia} = $txt[$i+1]
if (/Authority Information Access:/);
- $s = $. + 1
+ $res{sia} = $txt[$i+1]
if (/Subject Information Access:/);
- $c = $. + 1
+ $res{cdp} = $txt[$i+1]
if (/X509v3 CRL Distribution Points:/);
- $res{aia} = $_
- if ($a && $. == $a);
- $res{sia} = $_
- if ($s && $. == $s);
- $res{cdp} = $_
- if ($c && $. == $c);
}
- close(F);
if ($res{sia} && $res{sia} !~ m=/$=) {
warn("Badly formatted AIA URI, compensating: $res{sia}");
$res{sia} .= "/";
@@ -79,8 +100,16 @@ sub copy_cert {
my $indir = shift || $unauthenticated_tree;
my $outdir = shift || $temporary_tree;
mkdir_maybe("$outdir/$name");
- !system("openssl", "x509", "-inform", "DER", "-in", "$indir/$name", "-outform", "PEM", "-out", "$outdir/$name")
- or die("Couldn't copy $indir/$name to $outdir/$name");
+ openssl("x509", "-inform", "DER", "-in", "$indir/$name", "-outform", "PEM", "-out", "$outdir/$name");
+}
+
+sub install_cert {
+ my $name = shift;
+ my $indir = shift || $temporary_tree;
+ my $outdir = shift || $authenticated_tree;
+ mkdir_maybe("$outdir/$name");
+ rename("$indir/$name", "$outdir/$name")
+ or die("Couldn't rename $indir/$name to $outdir/$name");
}
sub copy_crl {
@@ -88,89 +117,142 @@ sub copy_crl {
my $indir = shift || $unauthenticated_tree;
my $outdir = shift || $authenticated_tree;
mkdir_maybe("$outdir/$name");
- !system("openssl", "crl", "-inform", "DER", "-in", "$indir/$name", "-outform", "PEM", "-out", "$outdir/$name")
- or die("Couldn't copy $indir/$name to $outdir/$name");
+ openssl("crl", "-inform", "DER", "-in", "$indir/$name", "-outform", "PEM", "-out", "$outdir/$name");
+}
+
+sub setup_cafile {
+ local $_;
+ open(OUT, ">$cafile")
+ or die("Couldn't open $cafile: $!");
+ for my $f (@_) {
+ open(IN, "$authenticated_tree/$f")
+ or die("Couldn't open $authenticated_tree/$f: $!");
+ print(OUT $_)
+ foreach (<IN>);
+ close(IN);
+ }
+ close(OUT);
}
sub check_crl {
my $uri = shift;
my $crl = shift;
- my $cert = shift;
mkdir_maybe("$unauthenticated_tree/$crl");
- !system("rsync", "-ai", $uri, "$unauthenticated_tree/$crl")
- or die("Couldn't rsync $uri");
- local $_ = `openssl crl -inform DER -in $unauthenticated_tree/$crl -CApath $authenticated_tree/$cert 2>&1`;
- chomp;
- return 1 if (/verify OK/);
- return 0 if (/verify failure/);
- die("Don't understand openssl crl verification result: $_");
+ rsync($uri, "$unauthenticated_tree/$crl");
+ setup_cafile(@_);
+ my @result = openssl_pipe("crl", "-inform", "DER", "-CAfile", $cafile, "-in", "$unauthenticated_tree/$crl");
+ local $_;
+ for (@result) {
+ return 1 if (/verify OK/);
+ return 0 if (/verify failure/);
+ warn("Unexpected verification result: $_");
+ }
+ die("Don't understand openssl crl verification results");
}
-# $1: cert we're examining
+sub verify_cert {
+ my $cert = shift;
+ setup_cafile(@_);
+ my @result = openssl_pipe(qw(verify -verbose -crl_check_all -policy_check -explicit_policy -policy 1.3.6.1.5.5.7.14.2 -x509_strict -CAfile), $cafile,
+ "$temporary_tree/$cert");
+ local $_;
+ my $ok;
+ for (@result) {
+ $ok = 1 if (/OK$/);
+ }
+ return $ok;
+}
+
+# $1: -verified- cert we're examining (we start from a trust anchor)
# &rest: ancestor certs and crls
#
sub check_cert {
my $cert = shift;
my @chain = @_;
+ print("Starting check of $cert\n");
+
my $u = extract_cert_uris($cert);
die("Couldn't extract URIs from certificate: $cert")
unless ($u);
- die("CDP missing for cert: $cert")
- unless ($u->{cdp});
- my $crl = uri_to_filename($u->{cdp});
- die ("Problem with CRL signature: $u->{cdp}")
- unless (check_crl($u->{cdp}, $crl, $u->{file}));
- copy_crl($crl);
+ my $crl;
+ if ($u->{cdp}) {
+ $crl = uri_to_filename($u->{cdp});
+ die ("Problem with CRL signature: $u->{cdp}")
+ unless (check_crl($u->{cdp}, $crl, $u->{file}, @chain));
+ copy_crl($crl);
+ } else {
+ warn("CDP missing for cert: $cert");
+ }
+
+ if (@chain && !$u->{aia}) {
+ warn("Non-trust-anchor certificate missing AIA extension: $cert");
+ } elsif (@chain && $chain[0] ne $u->{aia}) {
+ warn("AIA does not match parent URI: $cert");
+ }
- die("Non-trust-anchor certificate missing AIA extension: $cert")
- if (@chain && !$u->{aia});
- die("AIA does not match parent URI: $cert")
- if (@chain && $chain[0] ne $u->{aia});
- unshift(@chain, $crl, $u->{file});
+ unshift(@chain, $crl)
+ if ($crl);
+ unshift(@chain, $u->{file});
# Should check whether certificate is a CA here: SIA must be set
# if it's a CA and must not be set if it's not a CA.
- return unless ($u->{sia});
-
- my $sia = uri_to_filename($u->{sia});
- mkdir_maybe("$unauthenticated_tree/$sia");
- !system("rsync", "-ai", $u->{sia}, "$unauthenticated_tree/$sia")
- or die("Couldn't rsync $u->{sia}");
-
- my @files = map({s=^$unauthenticated_tree/==} glob("$unauthenticated_tree/$sia/*.cer"));
- for my $file (@files) {
- my $uri = "rsync://" . $file;
- copy_cert($file);
- die("Couldn't verify certificate $uri")
- unless (verify_cert($file, @chain));
- check_cert($uri, @chain);
+ if ($u->{sia}) {
+ my $sia = uri_to_filename($u->{sia});
+ mkdir_maybe("$unauthenticated_tree/$sia");
+ rsync($u->{sia}, "$unauthenticated_tree/$sia");
+ for my $file (glob("$unauthenticated_tree/${sia}*.cer")) {
+ $file =~ s=^$unauthenticated_tree/==;
+ my $uri = "rsync://" . $file;
+ print("Found cert $uri\n");
+ copy_cert($file);
+ if (!verify_cert($file, @chain)) {
+ warn("Verification failure for $file, skipping");
+ next;
+ }
+ install_cert($file);
+ check_cert($uri, @chain);
+ }
}
+
+ print("Finished check of $cert\n");
}
###
-# Read config
-
-while (<>) {
- chomp;
- next if (/^\s*$/ || /^\s*[;\#]/);
- my @argv = split;
- if ($argv[0] eq "anchor") {
- push(@anchors, $argv[1]);
- } elsif ($argv[0] eq "preaggregated") {
- push(@preaggregated, $argv[1]);
- } else {
- die("Could not parse: $_");
+# Easier to wire parameters into this script for initial debugging
+
+if (1) {
+ push(@anchors, qw(rsync://ca-trial.ripe.net/ARIN/root/root.cer
+ rsync://ca-trial.ripe.net/RIPE/root/root.cer
+ rsync://ca-trial.ripe.net/arinroot/repos/root.cer
+ rsync://ca-trial.ripe.net/riperoot/repos/root.cer
+ rsync://repository.apnic.net/APNIC/APNIC.cer
+ rsync://repository.apnic.net/trust-anchor.cer));
+# push(@preaggregated, qw());
+} else {
+ # Read config
+ while (<>) {
+ chomp;
+ next if (/^\s*$/ || /^\s*[;\#]/);
+ my @argv = split;
+ if ($argv[0] eq "anchor") {
+ push(@anchors, $argv[1]);
+ } elsif ($argv[0] eq "preaggregated") {
+ push(@preaggregated, $argv[1]);
+ } else {
+ die("Could not parse: $_");
+ }
}
}
# Create any missing directories.
-mkdir_maybe("$_/")
- foreach (($trust_anchor_tree, $preaggregated_tree, $unauthenticated_tree, $authenticated_tree, $temporary_tree));
+for my $dir (($trust_anchor_tree, $preaggregated_tree, $unauthenticated_tree, $authenticated_tree, $temporary_tree)) {
+ mkdir_maybe("$dir/");
+}
# Pull over any pre-aggregated data. We'll still have to check
# signatures in all of this, it's just a convenience to get us
@@ -178,43 +260,28 @@ mkdir_maybe("$_/")
for my $uri (@preaggregated) {
my $dir = uri_to_filename($uri);
- !system("rsync", "-ai", $uri, "$preaggregated_tree/$dir")
- or die("Couldn't rsync from $uri");
+ mkdir_maybe("$preaggregated_tree/$dir");
+ rsync($uri, "$preaggregated_tree/$dir");
}
# Update our unauthenticated tree from the pre-aggregated data. Will
# need to pay attention to rsync parameters here to make sure we don't
# overwrite newer stuff.
-!system("rsync", "-ai", "$preaggregated_tree/", "$unauthenticated_tree/")
- or die("Couldn't rsync $preaggregated_tree/ to $unauthenticated_tree/");
+rsync("$preaggregated_tree/", "$unauthenticated_tree/");
# Local trust anchors always win over anything else, so seed our
# authenticated tree with them
-copy_cert(uri_to_filename($_), $trust_anchor_tree, $authenticated_tree)
- foreach (@anchors);
+for my $anchor (@anchors) {
+ copy_cert(uri_to_filename($anchor), $trust_anchor_tree, $authenticated_tree);
+}
# Now start walking the tree, starting with our trust anchors.
-check_cert($_)
- foreach (@anchors);
-
-die "NIY";
-
-# for now will need to fix up sia urls as they are missing trailing slashes.
-# have asked about this on rescert.
-
-# walk tree starting from trust anchors, do the validate/fetch cycle
-#
-# still probably easiest to build the chains using the aia uris.
-
-# hmm, may need to have config file tell us the uris associated with
-# our trust anchors, otherwise (a) how do we name them in uri space
-# and (b) how do we check that their children have the right sia uri?
-# taking the children's word for what the parent's uri should be seems
-# wrong. maybe we just insist that our trust anchors have filenames
-# that match our mapping of uris to filenames....
+for my $anchor (@anchors) {
+ check_cert($anchor);
+}
################################################################