aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2007-09-16 19:16:30 +0000
committerRob Austein <sra@hactrn.net>2007-09-16 19:16:30 +0000
commit7991e300c1154bbd6dd4093bc032b0f79a2e8e8f (patch)
tree495db9f4e121b539a890df264d60b74c399c251a
parent48d4d897d3156b082de029666ddf48cebe8f535d (diff)
Cleanup
svn path=/scripts/rcynic-prototype.pl; revision=971
-rw-r--r--scripts/rcynic-prototype.pl649
-rw-r--r--scripts/xmlsec-demo.sh152
2 files changed, 0 insertions, 801 deletions
diff --git a/scripts/rcynic-prototype.pl b/scripts/rcynic-prototype.pl
deleted file mode 100644
index 0b3ec695..00000000
--- a/scripts/rcynic-prototype.pl
+++ /dev/null
@@ -1,649 +0,0 @@
-# $Id$
-
-# This is a PROTOTYPE of rcynic, to see whether I have the general
-# algorithms and data flow right.
-#
-# Some bad things that are fatal errors here will need better error
-# recovery once I'm confident that I'm detecting errors in the data
-# rather than in my silly code.
-
-use strict;
-
-my $openssl = "../openssl/openssl-0.9.8e/apps/openssl";
-
-my $trust_anchor_tree = "rcynic-trust-anchors";
-
-my $root = "rcynic-data";
-my $authenticated_pem = "$root/authenticated_pem";
-my $old_authenticated_pem = "$authenticated_pem.old";
-my $preaggregated_der = "$root/preaggregated_der";
-my $unauthenticated_der = "$root/unauthenticated_der";
-my $unauthenticated_pem = "$root/unauthenticated_pem";
-my $cafile = "$root/CAfile.pem";
-
-my @anchors; # Trust anchor URIs
-my @preaggregated; # Pre-aggregation source URIs
-my %rsync_cache; # URIs from which we've already rsynced
-my %parse_cache; # Certs we've already parsed
-
-my $verbose_run = 0; # Log all external programs
-my $verbose_cache = 0; # Log various cache hits
-my $verbose_walk = 0; # Log more info during certificate walk
-my $verbose_aia = 0; # Log more info for AIA errors
-my $verbose_accept = 1; # Log when accepting an object
-
-my $disable_network = 0; # Return immediate failure for all rsync commands
-my $retain_old_certs = 1; # Retain old valid certificates from previous runs
-my $fix_broken_sia = 0; # Fix broken SIA URIs
-
-sub logmsg {
- my @t = gmtime;
- my $t = sprintf("%02d:%02d:%02d ", $t[2], $t[1], $t[0]);
- print($t, @_, "\n");
-}
-
-sub run { # Run a program
- logmsg(join(" ", "Running", @_))
- if ($verbose_run);
- system(@_);
- logmsg(join(" ", @_, "returned", $?))
- if ($? != 0);
- return $? == 0;
-}
-
-sub run_pipe { # Run a program and hand back its output
- logmsg(join(" ", "Running", @_))
- if ($verbose_run);
- my $pid = open(F, "-|");
- if ($pid) {
- my @result = <F>;
- close(F);
- chomp(@result);
- logmsg(join(" ", @_, "returned", $?))
- if ($? != 0);
- return @result;
- } else {
- open(STDERR, ">&STDOUT")
- or die("Couldn't dup() STDOUT: $!");
- exec(@_)
- or die("Couldn't exec() ", join(" ", @_), ": $!");
- }
-}
-
-sub mkdir_maybe { # Create missing directories
- my $dir = shift;
- $dir =~ s=[^/]+$==;
- run("mkdir", "-p", $dir)
- unless (-d $dir);
-}
-
-sub rsync { # Run rsync with our preferred options
- # --copy-dirlinks apparently not needed
- return 0 if ($disable_network);
- return run(qw(rsync --update --times --copy-links --itemize-changes), @_);
-}
-
-sub rsync_cache { # Run rsync unless we've already done so for a URI covering this one
- my $uri = (grep({!/^-/} @_))[0];
- die("Can't find source URI in rsync command: @_")
- unless ($uri);
- my @path = split("/", uri_to_filename($uri));
- my $path = join("/", @path);
- pop(@path)
- while (@path && !$rsync_cache{join("/", @path)});
- if (@path) {
- logmsg("Cache hit ($path, ", join("/", @path), "), skipping rsync")
- if ($verbose_cache);
- return 1;
- } else {
- my $result = rsync(@_);
- $rsync_cache{$path} = 1;
- return $result;
- }
-}
-
-sub openssl { # Run our version of openssl
- run($openssl, @_);
-}
-
-sub openssl_pipe { # Run our version of opessl with output
- run_pipe($openssl, @_);
-}
-
-sub uri_to_filename { # Check a URI and conver it to a filename
- local $_ = shift;
- if ($_) {
- die("Not an rsync URI: $_")
- unless (m=^rsync://=);
- s=^rsync://==;
- die("Evil character sequences in URI: $_")
- if (m=^/= || m=^\.\.$= || m=^\.\./= || m=/\.\./= || m=/\.\.$= || m=//=);
- }
- return $_;
-}
-
-sub parse_cert { # Parse interesting fields from a certificate
- my $uri = shift;
- my $dir = shift;
- my $file = uri_to_filename($uri);
- my $path = "$dir/$file";
- if ($parse_cache{$path}) {
- logmsg("Already parsed certificate $uri")
- if ($verbose_cache);
- return $parse_cache{$path};
- }
- my %res = (file => $file, uri => $uri);
- my ($a, $s, $c);
- my @txt = openssl_pipe(qw(x509 -noout -text -in), "$dir/$file");
- local $_;
- s=^.+URI:==
- foreach (@txt);
- for (my $i = 0; $i < @txt; ++$i) {
- $_ = $txt[$i];
- $res{aia} = $txt[$i+1]
- if (/Authority Information Access:/);
- $res{sia} = $txt[$i+1]
- if (/Subject Information Access:/);
- $res{cdp} = $txt[$i+1]
- if (/X509v3 CRL Distribution Points:/);
- $res{ca} = 1
- if (/X509v3 Basic Constraints/ && $txt[$i+1] =~ /^\s*CA:TRUE\s*$/);
- }
- if ($res{sia} && $res{sia} !~ m=/$= && $fix_broken_sia) {
- logmsg("Malformed SIA URI, compensating: $res{sia}");
- $res{sia} .= "/";
- }
- return $parse_cache{$path} = \%res;
-}
-
-sub log_cert {
- my $obj = shift;
- logmsg("URI: $obj->{uri}");
- logmsg("CA: ", ($obj->{ca} ? "Yes" : "No"));
- logmsg("TA: ", ($obj->{ta} ? "Yes" : "No"));
- logmsg("AIA: $obj->{aia}") if ($obj->{aia});
- logmsg("SIA: $obj->{sia}") if ($obj->{sia});
- logmsg("CDP: $obj->{cdp}") if ($obj->{cdp});
-}
-
-sub setup_cafile { # Set up -CAfile data for verification
- local $_;
- my %saw; # This shouldn't be necessary, something's confused
- open(OUT, ">$cafile")
- or die("Couldn't open $cafile: $!");
- for my $f (@_) {
- next if ($saw{$f});
- $saw{$f} = 1;
- open(IN, "$authenticated_pem/$f")
- or die("Couldn't open $authenticated_pem/$f: $!");
- print(OUT $_)
- foreach (<IN>);
- close(IN);
- }
- close(OUT);
-}
-
-sub copy_cert { # Convert a certificate from DER to PEM
- my $name = shift;
- my $indir = shift;
- my $outdir = shift;
- if (-f "$outdir/$name") {
- logmsg("Already copied certificate rsync://$name")
- if ($verbose_cache);
- return;
- }
- mkdir_maybe("$outdir/$name");
- openssl("x509", "-inform", "DER", "-in", "$indir/$name", "-outform", "PEM", "-out", "$outdir/$name");
-}
-
-sub mv { # Move an object from one tree to another
- my $source = shift;
- my $destination = shift;
- mkdir_maybe($destination);
- rename($source, $destination)
- or die("Couldn't rename $source to $destination");
-}
-
-sub ln { # Link an object from one tree to another
- my $source = shift;
- my $destination = shift;
- mkdir_maybe($destination);
- link($source, $destination)
- or die("Couldn't link $source to $destination");
-}
-
-sub check_crl { # Check signature chain on a CRL, install CRL if all is well
- my $uri = shift;
- return undef
- unless ($uri);
- my $file = uri_to_filename($uri);
- if (-f "$authenticated_pem/$file") {
- logmsg("Already checked CRL $uri")
- if ($verbose_cache);
- return $file;
- }
- mkdir_maybe("$unauthenticated_der/$file");
- rsync_cache($uri, "$unauthenticated_der/$file");
- return undef
- unless (-f "$unauthenticated_der/$file" ||
- -f "$old_authenticated_pem/$file");
- setup_cafile(@_);
- local $_;
- for my $source (($unauthenticated_der, $old_authenticated_pem)) {
- next unless (-f "$source/$file");
- logmsg("Checking saved old CRL $uri")
- if ($source eq $old_authenticated_pem);
- my @result = openssl_pipe("crl", "-CAfile", $cafile, "-noout",
- "-in", "$source/$file", "-inform",
- ($source eq $old_authenticated_pem ? "PEM" : "DER"));
- if (grep(/verify OK/, @result)) {
- logmsg("Accepting CRL $uri")
- if ($verbose_accept);
- if ($source eq $old_authenticated_pem) {
- ln("$old_authenticated_pem/$file", "$authenticated_pem/$file");
- } else {
- mkdir_maybe("$authenticated_pem/$file");
- openssl("crl", "-inform", "DER", "-in", "$source/$file",
- "-outform", "PEM", "-out", "$authenticated_pem/$file");
- }
- return $file;
- } elsif (grep(/certificate revoked/, @result)) {
- logmsg("Revoked certificate in path for CRL $uri");
- } else {
- logmsg("Verification failure for CRL $uri:");
- logmsg(" Inputs:");
- logmsg(" $_")
- foreach (($file, @_));
- logmsg(" Result:");
- logmsg(" $_")
- foreach (@result);
- }
- }
- return undef;
-}
-
-sub check_cert { # Check signature chain etc on a certificate, install if all's well
- my $uri = shift;
- my $file = shift;
- my $source = shift;
- die("No certificate to process!")
- unless (-f "$source/$file");
- 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, "$source/$file");
- local $_;
- if (grep(/OK$/, @result)) {
- logmsg("Accepting certificate $uri")
- if ($verbose_accept);
- if ($source eq $old_authenticated_pem) {
- ln("$source/$file", "$authenticated_pem/$file");
- } else {
- mv("$source/$file", "$authenticated_pem/$file");
- }
- return 1;
- } elsif (grep(/certificate revoked/, @result)) {
- logmsg("Revoked certificate in path for certificate $uri");
- } else {
- logmsg("Verification failure for certificate $uri:");
- logmsg(" Inputs:");
- logmsg(" $_")
- foreach (($file, @_));
- logmsg(" Result:");
- logmsg(" $_")
- foreach (@result);
- }
- return 0;
-}
-
-sub walk_cert { # Process a certificate -- core of the program
- my $p = shift;
-
- die("No certificate to process!")
- unless ($p);
-
- logmsg("Starting walk of $p->{uri}");
- log_cert($p)
- if ($verbose_walk);
-
- if ($p->{sia}) {
- my @chain = (uri_to_filename($p->{cdp}), $p->{file}, @_);
- my $sia = uri_to_filename($p->{sia});
- mkdir_maybe("$unauthenticated_der/$sia");
- rsync_cache(qw(--recursive --delete),
- $p->{sia}, "$unauthenticated_der/$sia");
- my @files = do {
- my %files;
- for my $f (glob("$unauthenticated_der/${sia}*.cer")) {
- $f =~ s=^$unauthenticated_der/==;
- $files{$f} = 1;
- }
- if ($retain_old_certs) {
- for my $f (glob("$old_authenticated_pem/${sia}*.cer")) {
- $f =~ s=^$old_authenticated_pem/==;
- $files{$f} = 1;
- }
- }
- keys(%files);
- };
- for my $file (@files) {
- my $uri = "rsync://" . $file;
- logmsg("Found certificate $uri");
- if (-f "$authenticated_pem/$file") {
- logmsg("Already checked certificate $uri, skipping")
- if ($verbose_cache);
- next;
- }
- die("Certificate $uri is its own ancestor?!?")
- if (grep({$file eq $_} @chain));
- copy_cert($file, $unauthenticated_der, $unauthenticated_pem)
- if (-f "$unauthenticated_der/$file");
- my $cert;
- for my $source (($unauthenticated_pem, $old_authenticated_pem)) {
- next
- unless (-f "$source/$file");
- logmsg("Checking saved old certificate $uri")
- if ($source eq $old_authenticated_pem);
- my $c = parse_cert($uri, $source);
- if (!$c) {
- logmsg("Parse failure for $uri, skipping");
- next;
- }
- log_cert($c)
- if ($verbose_walk);
- if ($c->{sia} && $c->{sia} !~ m=/$=) {
- logmsg("Malformed SIA for $uri, skipping");
- next;
- }
- if (!$c->{aia}) {
- logmsg("AIA missing for $uri, skipping");
- next;
- }
- if (!$p->{ta} && $c->{aia} ne $p->{uri}) {
- logmsg("AIA of $uri doesn't match parent, skipping");
- if ($verbose_aia) {
- logmsg("\tSubject AIA: $c->{aia}");
- logmsg("\t Issuer URI: $p->{uri}");
- }
- next;
- }
- if ($c->{ca} && !$c->{sia}) {
- logmsg("CA certificate $uri without SIA extension, skipping");
- next;
- }
- if (!$c->{ca} && $c->{sia}) {
- logmsg("EE certificate $uri with SIA extension, skipping");
- next;
- }
- if (!$c->{cdp}) {
- logmsg("CDP missing for $uri, skipping");
- next;
- }
- my $crl = check_crl($c->{cdp}, @chain);
- if (!$crl) {
- logmsg("Problem with CRL for $uri, skipping");
- next;
- }
- if (!check_cert($uri, $file, $source, $crl, @chain)) {
- logmsg("Verification failure for $uri, skipping");
- next;
- }
- $cert = $c; # If we get here, we found a good cert,
- last; # so remember it and get out of inner loop
- }
-
- next unless ($cert);
- walk_cert($cert, @chain);
- }
- }
-
- logmsg("Finished walk of $p->{uri}");
-}
-
-sub main { # Main program
-
- my $start_time = time;
- logmsg("Started at ", scalar(gmtime($start_time)), " UTC");
-
- # We should read a configuration file, but for debugging it's
- # easier just to wire the parameters into the script.
-
- if (1) {
- push(@anchors, qw(rsync://ca-trial.ripe.net/arinroot/repos/root.cer
- rsync://ca-trial.ripe.net/riperoot/repos/root.cer
- rsync://repository.apnic.net/trust-anchor.cer));
- push(@preaggregated, qw());
- } else {
- 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: $_");
- }
- }
- }
-
- # Initial cleanup.
-
- run("rm", "-rf", $unauthenticated_pem, $old_authenticated_pem);
- rename($authenticated_pem, $old_authenticated_pem);
- die("Couldn't clear $authenticated_pem from previous run")
- if (-d $authenticated_pem);
-
- # Create any missing directories.
-
- for my $dir (($preaggregated_der, $unauthenticated_der,
- $authenticated_pem, $unauthenticated_pem)) {
- 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
- # started.
-
- for my $uri (@preaggregated) {
- my $dir = uri_to_filename($uri);
- mkdir_maybe("$preaggregated_der/$dir");
- rsync("--recursive", $uri, "$preaggregated_der/$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.
-
- rsync("--recursive", "$preaggregated_der/", "$unauthenticated_der/");
-
- # Local trust anchors always win over anything else, so seed our
- # authenticated tree with them
-
- for my $anchor (@anchors) {
- copy_cert(uri_to_filename($anchor), $trust_anchor_tree, $authenticated_pem);
- }
-
- # Now start walking the tree, starting with our trust anchors.
-
- for my $anchor (@anchors) {
- my $t = parse_cert($anchor, $authenticated_pem);
- die("Couldn't parse trust anchor! $anchor\n")
- unless($t);
- $t->{ta} = 1;
- if (!$t->{cdp}) {
- logmsg("Trust anchor $anchor has no CRL distribution point, skipping");
- next;
- }
- if (!check_crl($t->{cdp}, $t->{file})) {
- logmsg("Problem with trust anchor $anchor CRL $t->{cdp}, skipping");
- next;
- }
- walk_cert($t);
- }
-
- unlink($cafile);
-
- my $stop_time = time;
- logmsg("Finished at ", scalar(gmtime($stop_time)), " UTC");
-
- my $elapsed = $stop_time - $start_time;
- my $seconds = $elapsed % 60; $elapsed /= 60;
- my $minutes = $elapsed % 60; $elapsed /= 60;
- my $hours = $elapsed;
-
- logmsg("Elapsed time: ", sprintf("%d:%02d:%02d", $hours, $minutes, $seconds));
-
-}
-
-main()
-
-################################################################
-#
-# Stuff that still needs work:
-#
-# 1) Trust anchors don't really have origin URIs in the sense we're
-# using for everything else. Perhaps just should not live in
-# the authenticated tree at all?
-#
-# 2) Need to rework walk_cert() to allow us to walk the old
-# authenticated tree after we're done checking everything else, to
-# pick up old stuff that's still valid in the old tree and is now
-# bogus or missing in the updated unauthenticated tree.
-#
-################################################################
-#
-# Date: Sat, 19 Aug 2006 02:53:25 -0400
-# From: Rob Austein <sra@hactrn.net>
-# Subject: rcynic design
-# Message-Id: <20060819065325.B4C525C53@thrintun.hactrn.net>
-#
-# overall tasks: collect certificates from publication points, assemble
-# them into a local certificate store, perform validation checks on all
-# of them, discarding the ones that don't pass. output is a valid
-# repository containing a snapshot of all the (valid, accessible)
-# certificates in the rpki system. also want to provide ability for
-# others to synchronize from this repository, so mustn't do anything
-# that precludes serving results via rsync. code should also support
-# building a validated repository purely from locally maintained data.
-#
-# inputs to the process:
-#
-# - a (small) set of trust anchors
-#
-# - zero or more rsync uris for pre-aggregated object collections
-#
-# - a configuration file containing or pointing to the above inputs and
-# whatever other parameters we turn out to need.
-#
-# i was initially arguing for a collection phase followed by a
-# validation phase after fetching all the data. randy convinced me that
-# we don't want to follow uris that didn't come from local config or a
-# cert we've already checked. most paranoid version of this would
-# involve pulling one directory at a time via rsync, but that's wasteful
-# of tcp connections and process forks, so we compromised on allowing
-# rsync of everything under a given uri once we've validated it.
-#
-# so we end up with a two phase model that looks like this:
-#
-# 1) fetch pre-aggregated stuff from zero or more uris specified in
-# config file. listing a uri in this part of the config file is
-# construed as willingness to rsync data from it without further
-# checks. we will validate all of this later, we just don't have to
-# validate it while we're fetching it.
-#
-# 2) walk the tree starting with the trust anchors, checking stuff, and
-# examining uris. optionally follow rsync sia uris from validated
-# certs, fetching more stuff that's missing or stale in our store,
-# applying this process recursively until we run out of new uris to
-# follow or decide that we've followed too many uris ("too many" is a
-# configurable parameter with a relatively high default).
-#
-# if we don't fetch anything in either phase, this is just a check of a
-# pre-existing tree, which is an operation we want to have anyway.
-#
-# we need to maintain two separate collections:
-#
-# a) everything we got via rsync from whichever parties we were willing
-# to ask, and
-#
-# b) only the stuff we've blessed.
-#
-# there may be transient states in which we have both old and new
-# versions of each of these, although probably not of both at once.
-#
-# we need to perform certain sanity checks on any uris we use
-# (principally checking for "/../" sequences and any other pathnames
-# which are potentially dangerous and which we don't there's any sane
-# reason for us ever to see), and if possible we want to run rsync
-# inside a chroot jail with restricted permissions and a paranoid set of
-# client options (in particular, we don't want to receive symlinks).
-# the chroot code should be written in such a way that it is easy for a
-# paranoid administrator to verify, and so that it can be omitted if the
-# administrator's paranoia trusts rsync more than they trust our chroot
-# code (which, by definition, has to run as root).
-#
-# output of the collection stage is a local disk mirror of all the
-# candidate certificates and crls we could fetch. some may not have
-# been accessible, in which case we may have to fall back to previously
-# fetched data from an earlier pass, if we have any and if it's still
-# valid. if a validation pass finds that we're broken badly enough, we
-# may need to disable distribution of our results to others (ie, disable
-# rsync server), but we may not have a lot of choice about using some of
-# the new data, as clocks will be ticking and old stuff will time out.
-#
-# unless i think of a better way to do it, local store will be organized
-# in approximately the way that wget would organize such a collection: a
-# top level directory, each first level subdirectory of which is named
-# for the hostname portion of the publication uri, second (and lower)
-# level subdirectories track the directory structure at each of the
-# publication points.
-#
-# when validating our candidate set of certificates and crls, we need to
-# walk through them, probably top down, checking each one (signature,
-# revocation, path validation including well-formed 3779 extensions).
-# we build a parallel tree (same directory structure) containing only
-# objects that pass our checks. if we have not already pruned out all
-# non-file, non-directory objects at an earlier stage, we check for this
-# (posix stat() call) before we open any object file.
-#
-# rsync efficiency issue: any changes we make to our local copy to
-# correct a remote problem will be overwritten by the same remote
-# problem the next time we run rsync unless the problem has been
-# corrected. it'd be nice to avoid continually fetching the same
-# mistakes. so we don't want to delete stuff from our raw unvalidated
-# mirror, we just don't copy it to our validated mirror. there may be
-# other ways to deal with this, eg, having three local trees: one
-# maintained by rsync, a second which is a copy of the first with
-# symlinks etc cleaned out, and a third which we've validated.
-#
-# failure mode: can't get new copies of stuff we already had. recovery:
-# reuse old stuff if still valid. we want to use our old unvalidated
-# copies (a) for this, since some time skew problems may have fixed
-# themselves by now and there might be now-valid stuff in our old
-# unvalidated store that didn't pass validation last time.
-#
-# failure mode: pulled new broken copies of stuff for which we had old
-# valid copies. recovery: reuse the old valid copies (b), unless we got
-# to a three step model just to preserve old unvalidated stuff for this
-# case too (probably unnecessary).
-#
-# additional check we should perform: do we get the same answer if we
-# follow the aia uris upwards within our local store as we get when we
-# follow the sia uris downwards? not clear how we should handle this if
-# the answer is "no": warning at minimum, but probably should reject at
-# least some of the certificates involved if this check fails. whether
-# we should reject all the certificates that mismatch or only the
-# children is a tricky, as rejecting all could be an invitation to
-# denial of service attacks (bozo-isp intentionally or through
-# incompetence generates bogus uri, arin's validator stops running,
-# oops!), so this may need to be a configurable choice. randy suspects
-# that most mismatches will be due to time skews, for which "retry
-# later" might be a plausible recovery.
-#
-################################################################
-
-# Local Variables:
-# compile-command: "perl rcynic-prototype.pl"
-# End:
diff --git a/scripts/xmlsec-demo.sh b/scripts/xmlsec-demo.sh
deleted file mode 100644
index dde26db3..00000000
--- a/scripts/xmlsec-demo.sh
+++ /dev/null
@@ -1,152 +0,0 @@
-#!/bin/sh -
-# $Id$
-
-# Demo of how one could use the xmlsec package to sign and verify XML
-# messages. On FreeBSD, the xmlsec 1.x command line program is called
-# "xmlsec1" to distinuish it from the old xmlsec 0.x program, which
-# had a somewhat different command line syntax. YMMV.
-#
-# Basic idea of the demo is to create a four level deep cert chain,
-# use that to sign an XML document, then demonstrate that it verifies.
-
-# Subsequent discussion on the mailing list concluded that xmlsec (the
-# protocol, not just this particular implementation) is hopelessly
-# broken and that we should just use CMS (aka PKCS#7 ng). Done.
-
-set -xe
-
-: ${input=input.xml} ${unsigned=unsigned.xml} ${signed=signed.xml}
-: ${alice=alice} ${bob=bob} ${carol=carol} ${dave=dave}
-: ${xmlsec=xmlsec1}
-
-# Some input with which to work. Feel free to supply your own instead.
-
-test -r $input || cat >$input <<'EOF'
- <reference anchor="RFC3779">
- <front>
- <title>X.509 Extensions for IP Addresses and AS Identifiers</title>
- <author fullname="C. Lynn" initials="C." surname="Lynn">
- <organization/>
- </author>
- <author fullname="S. Kent" initials="S." surname="Kent">
- <organization/>
- </author>
- <author fullname="K. Seo" initials="K." surname="Seo">
- <organization/>
- </author>
- <date month="June" year="2004"/>
- <keyword>allocation</keyword>
- <keyword>atrribute certificate</keyword>
- <keyword>authorization</keyword>
- <keyword>autonomous system number authorization</keyword>
- <keyword>certificate</keyword>
- <keyword>delegation</keyword>
- <keyword>internet registry</keyword>
- <keyword>ip address authorization</keyword>
- <keyword>public key infrastructure</keyword>
- <keyword>right-to-use</keyword>
- <keyword>secure allocation </keyword>
- <abstract>
- <t>This document defines two X.509 v3 certificate extensions. The
- first binds a list of IP address blocks, or prefixes, to the
- subject of a certificate. The second binds a list of autonomous
- system identifiers to the subject of a certificate. These
- extensions may be used to convey the authorization of the
- subject to use the IP addresses and autonomous system
- identifiers contained in the extensions. [STANDARDS TRACK]
- </t>
- </abstract>
- </front>
- <seriesInfo name="RFC" value="3779"/>
- <format type="TXT" octets="60732" target="http://www.rfc-editor.org/rfc/rfc3779.txt"/>
- <!-- current-status PROPOSED STANDARD -->
- <!-- publication-status PROPOSED STANDARD -->
- </reference>
-EOF
-
-# Set up a simple chain of certs.
-
-for i in $alice $bob $carol $dave
-do
- test -r $i.cnf || cat >$i.cnf <<EOF
-
- [ req ]
- distinguished_name = req_dn
- x509_extensions = req_x509_ext
- prompt = no
- default_md = sha1
-
- [ req_dn ]
- CN = Test Certificate $i
-
- [ req_x509_ext ]
- basicConstraints = CA:true
- subjectKeyIdentifier = hash
- authorityKeyIdentifier = keyid:always
-
-EOF
-
- test -r $i.key -a -r $i.req ||
- openssl req -new -newkey rsa:2048 -nodes -keyout $i.key -out $i.req -config $i.cnf
-
-done
-
-test -r $alice.cer || openssl x509 -req -in $alice.req -out $alice.cer -extfile $alice.cnf -extensions req_x509_ext -signkey $alice.key
-test -r $bob.cer || openssl x509 -req -in $bob.req -out $bob.cer -extfile $bob.cnf -extensions req_x509_ext -CA $alice.cer -CAkey $alice.key -CAcreateserial
-test -r $carol.cer || openssl x509 -req -in $carol.req -out $carol.cer -extfile $carol.cnf -extensions req_x509_ext -CA $bob.cer -CAkey $bob.key -CAcreateserial
-test -r $dave.cer || openssl x509 -req -in $dave.req -out $dave.cer -extfile $dave.cnf -extensions req_x509_ext -CA $carol.cer -CAkey $carol.key -CAcreateserial
-
-# The xmlsec command line tool takes most of its instructions in the
-# form of an XML template. XSLT was designed for this kind of work,
-# so just use an XSL transform to wrap our input with the template.
-#
-# NB: The XML signature specification supports several different
-# signing modes. In theory, which one of them I get is determined by
-# the template. Documentation is a bit sparse, though, so I just went
-# with the first halfway sane thing I found in the supplied examples.
-
-test -r $unsigned ||
-xsltproc --output $unsigned - $input <<'EOF'
-
- <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
- <xsl:output method="xml" encoding="us-ascii" indent="yes"/>
- <xsl:template match="/">
- <Envelope xmlns="urn:envelope">
- <xsl:copy-of select="/"/>
- <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
- <SignedInfo>
- <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
- <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
- <Reference>
- <Transforms>
- <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
- </Transforms>
- <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
- <DigestValue/>
- </Reference>
- </SignedInfo>
- <SignatureValue/>
- <KeyInfo>
- <X509Data>
- <X509Certificate/>
- </X509Data>
- </KeyInfo>
- </Signature>
- </Envelope>
- </xsl:template>
- </xsl:stylesheet>
-
-EOF
-
-# Sign the template we generated. We sign with the bottommost key,
-# and include the two bottommost certs in the signed document.
-
-test -r $signed ||
-$xmlsec sign --privkey-pem $dave.key,$dave.cer,$carol.cer --output $signed $unsigned
-
-# Verify the signed message. We tell xmlsec to trust the root cert,
-# and supply the second level cert as it's not in the signed message.
-# This should be enough for xmlsec to verify the signature; removing
-# any these should cause verification to fail (try it!).
-
-$xmlsec verify --trusted-pem $alice.cer --untrusted-pem $bob.cer $signed