#!/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