aboutsummaryrefslogtreecommitdiff
path: root/scripts/rcynic-prototype.pl
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/rcynic-prototype.pl')
-rw-r--r--scripts/rcynic-prototype.pl139
1 files changed, 93 insertions, 46 deletions
diff --git a/scripts/rcynic-prototype.pl b/scripts/rcynic-prototype.pl
index 43690d02..67826df3 100644
--- a/scripts/rcynic-prototype.pl
+++ b/scripts/rcynic-prototype.pl
@@ -2,6 +2,11 @@
# This is a PROTOTYPE of rcynic, just to see whether I have the
# general algorithms and data flow right.
+#
+# Most bad things are fatal errors in the initial version of this
+# prototype. Many of them will need better error recovery later, once
+# I'm confident that I'm detecting errors in the certificates rather
+# than errors in my silly code.
use strict;
@@ -12,39 +17,25 @@ my $unauthenticated_tree = "$root/unauthenticated";
my $authenticated_tree = "$root/authenticated";
my $temporary_tree = "$root/temporary";
-# Read config
-
my @anchors;
my @preaggregated;
-
-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: $_\n");
- }
-}
+my %certs;
sub mkdir_maybe {
my $dir = shift;
$dir =~ s=[^/]+$==;
!system("mkdir", "-p", $dir)
- or die("Couldn't make $dir\n")
+ or die("Couldn't make $dir")
unless (-d $dir);
}
sub uri_to_filename {
local $_ = shift;
if ($_) {
- die("Not an rsync URI: $_\n")
+ die("Not an rsync URI: $_")
unless (m=^rsync://=);
s=^rsync://==;
- die("Evil character sequences in URI: $_\n")
+ die("Evil character sequences in URI: $_")
if (m=^/= || m=^\.\.$= || m=^\.\./= || m=/\.\./= || m=/\.\.$= || m=//=);
}
return $_;
@@ -58,7 +49,7 @@ sub extract_cert_uris {
my ($a, $s, $c);
local $_;
open(F, "-|", qw(openssl x509 -noout -inform DER -text -in), "$dir/$file")
- or die("Couldn't run openssl x509 on $file: $!\n");
+ or die("Couldn't run openssl x509 on $file: $!");
while (<F>) {
chomp;
s{^.+URI:rsync://}{};
@@ -77,7 +68,7 @@ sub extract_cert_uris {
}
close(F);
if ($res{sia} && $res{sia} !~ m=/$=) {
- warn("Badly formatted AIA URI, compensating: $res{sia}\n");
+ warn("Badly formatted AIA URI, compensating: $res{sia}");
$res{sia} .= "/";
}
return \%res;
@@ -89,7 +80,7 @@ sub copy_cert {
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\n");
+ or die("Couldn't copy $indir/$name to $outdir/$name");
}
sub copy_crl {
@@ -98,7 +89,82 @@ sub copy_crl {
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\n");
+ or die("Couldn't copy $indir/$name to $outdir/$name");
+}
+
+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: $_");
+}
+
+# $1: cert we're examining
+# &rest: ancestor certs and crls
+#
+sub check_cert {
+ my $cert = shift;
+ my @chain = @_;
+
+ 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);
+
+ 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});
+
+ # 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);
+ }
+}
+
+###
+
+# 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.
@@ -113,7 +179,7 @@ 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\n");
+ or die("Couldn't rsync from $uri");
}
# Update our unauthenticated tree from the pre-aggregated data. Will
@@ -121,37 +187,18 @@ for my $uri (@preaggregated) {
# overwrite newer stuff.
!system("rsync", "-ai", "$preaggregated_tree/", "$unauthenticated_tree/")
- or die("Couldn't rsync $preaggregated_tree/ to $unauthenticated_tree/\n");
+ or die("Couldn't rsync $preaggregated_tree/ to $unauthenticated_tree/");
# Local trust anchors always win over anything else, so seed our
# authenticated tree with them
-copy_cert($_, $trust_anchor_tree, $authenticated_tree)
+copy_cert(uri_to_filename($_), $trust_anchor_tree, $authenticated_tree)
foreach (@anchors);
-my %certs;
-
-sub check_crl {
- die "NIY";
-}
-
-# start with -verified- cert here (because we start with trust
-# anchors) pull uris, rsync cdp and check resulting crl, rsync sdp,
-# then walk through resulting certs, one at a time, verifying each
-# one, then calling this function recursively.
-#
-# $1: cert we're examining
-# &rest: ancestor certs (er, and crls?)
-
-sub check_cert {
- die "NIY";
-}
-
# Now start walking the tree, starting with our trust anchors.
-for my $anchor (@anchors) {
- check_cert($anchor);
-}
+check_cert($_)
+ foreach (@anchors);
die "NIY";