Write PKL using libxml++ and sign them.
authorCarl Hetherington <cth@carlh.net>
Thu, 3 Jan 2013 22:00:04 +0000 (22:00 +0000)
committerCarl Hetherington <cth@carlh.net>
Thu, 3 Jan 2013 22:00:04 +0000 (22:00 +0000)
src/asset.cc
src/asset.h
src/dcp.cc
src/dcp.h
test/data/certificate_chain [new file with mode: 0644]
test/data/signer.key [new file with mode: 0644]

index 5ecc2e9f72c5b4f6072c3b8a9991baae9671ddb8..ac8f8b8ed446dc8735cace506c59cb30ef4c5315 100644 (file)
@@ -24,6 +24,8 @@
 #include <iostream>
 #include <fstream>
 #include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+#include <libxml++/nodes/element.h>
 #include "AS_DCP.h"
 #include "KM_util.h"
 #include "asset.h"
@@ -45,15 +47,14 @@ Asset::Asset (string directory, string file_name)
 }
 
 void
-Asset::write_to_pkl (ostream& s) const
+Asset::write_to_pkl (xmlpp::Element* p) const
 {
-       s << "    <Asset>\n"
-         << "      <Id>urn:uuid:" << _uuid << "</Id>\n"
-         << "      <AnnotationText>" << _file_name << "</AnnotationText>\n"
-         << "      <Hash>" << digest() << "</Hash>\n"
-         << "      <Size>" << filesystem::file_size(path()) << "</Size>\n"
-         << "      <Type>application/mxf</Type>\n"
-         << "    </Asset>\n";
+       xmlpp::Element* asset = p->add_child("Asset");
+       asset->add_child("Id")->add_child_text("urn:uuid:" + _uuid);
+       asset->add_child("AnnotationText")->add_child_text (_file_name);
+       asset->add_child("Hash")->add_child_text (digest());
+       asset->add_child("Size")->add_child_text (boost::lexical_cast<string> (filesystem::file_size(path())));
+       asset->add_child("Type")->add_child_text ("application/mxf");
 }
 
 void
index 4a52e819b8447e90e4332a98fe52057b515e6c2d..5436e05cde27f76f7afdc178f1477e11ec5e00e4 100644 (file)
@@ -60,10 +60,10 @@ public:
         */
        virtual void write_to_cpl (xmlpp::Element* p) const = 0;
 
-       /** Write details of the asset to a PKL stream.
-        *  @param s Stream.
+       /** Write details of the asset to a PKL AssetList node.
+        *  @param p Parent node.
         */
-       void write_to_pkl (std::ostream& s) const;
+       void write_to_pkl (xmlpp::Element* p) const;
 
        /** Write details of the asset to a ASSETMAP stream.
         *  @param s Stream.
index aa7bb46a2164a0a66514196d5c8cffca2294dd87..2ece0eacaec75b50793a8f0c6fbc8d0aaa2045fc 100644 (file)
@@ -27,6 +27,7 @@
 #include <cassert>
 #include <iostream>
 #include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
 #include <libxml++/libxml++.h>
 #include <xmlsec/xmldsig.h>
 #include <xmlsec/app.h>
@@ -82,29 +83,37 @@ DCP::write_pkl (string pkl_uuid) const
        stringstream s;
        s << pkl_uuid << "_pkl.xml";
        p /= s.str();
-       ofstream pkl (p.string().c_str());
-
-       pkl << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-           << "<PackingList xmlns=\"http://www.smpte-ra.org/schemas/429-8/2007/PKL\">\n"
-           << "  <Id>urn:uuid:" << pkl_uuid << "</Id>\n"
-               /* XXX: this is a bit of a hack */
-           << "  <AnnotationText>" << _cpls.front()->name() << "</AnnotationText>\n"
-           << "  <IssueDate>" << Metadata::instance()->issue_date << "</IssueDate>\n"
-           << "  <Issuer>" << Metadata::instance()->issuer << "</Issuer>\n"
-           << "  <Creator>" << Metadata::instance()->creator << "</Creator>\n"
-           << "  <AssetList>\n";
 
-       list<shared_ptr<const Asset> > a = assets ();
-       for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) {
-               (*i)->write_to_pkl (pkl);
+       xmlpp::Document doc;
+       xmlpp::Element* pkl = doc.create_root_node("PackingList", "http://www.smpte-ra.org/schemas/429-8/2007/PKL");
+       if (_encrypted) {
+               pkl->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "dsig");
        }
 
-       for (list<shared_ptr<const CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
-               (*i)->write_to_pkl (pkl);
+       pkl->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid);
+       /* XXX: this is a bit of a hack */
+       pkl->add_child("AnnotationText")->add_child_text(_cpls.front()->name());
+       pkl->add_child("IssueDate")->add_child_text (Metadata::instance()->issue_date);
+       pkl->add_child("Issuer")->add_child_text (Metadata::instance()->issuer);
+       pkl->add_child("Creator")->add_child_text (Metadata::instance()->creator);
+
+       {
+               xmlpp::Element* asset_list = pkl->add_child("AssetList");
+               list<shared_ptr<const Asset> > a = assets ();
+               for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) {
+                       (*i)->write_to_pkl (asset_list);
+               }
+
+               for (list<shared_ptr<const CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
+                       (*i)->write_to_pkl (asset_list);
+               }
        }
 
-       pkl << "  </AssetList>\n"
-           << "</PackingList>\n";
+       if (_encrypted) {
+               sign (pkl, _certificates, _signer_key);
+       }
+               
+       doc.write_to_file_formatted (p.string(), "UTF-8");
 
        return p.string ();
 }
@@ -462,111 +471,115 @@ CPL::write_xml (bool encrypted, CertificateChain const & certificates, string co
        }
 
        if (encrypted) {
-               xmlpp::Element* signer = cpl->add_child("Signer");
-               {
-                       xmlpp::Element* data = signer->add_child("X509Data", "dsig");
-                       {
-                               xmlpp::Element* serial = data->add_child("X509IssuerSerial", "dsig");
-                               serial->add_child("X509IssuerName", "dsig")->add_child_text (
-                                       Certificate::name_for_xml (certificates.leaf()->issuer())
-                                       );
-                               serial->add_child("X509SerialNumber", "dsig")->add_child_text (
-                                       certificates.leaf()->serial()
-                                       );
-                       }
-                       data->add_child("X509SubjectName", "dsig")->add_child_text (
-                               Certificate::name_for_xml (certificates.leaf()->subject())
-                               );
-               }
+               DCP::sign (cpl, certificates, signer_key);
+       }
 
-               xmlpp::Element* signature = cpl->add_child("Signature", "dsig");
-               
-               {
-                       xmlpp::Element* signed_info = signature->add_child ("SignedInfo", "dsig");
-                       signed_info->add_child("CanonicalizationMethod", "dsig")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
-                       signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
-                       {
-                               xmlpp::Element* reference = signed_info->add_child("Reference", "dsig");
-                               reference->set_attribute ("URI", "");
-                               {
-                                       xmlpp::Element* transforms = reference->add_child("Transforms", "dsig");
-                                       transforms->add_child("Transform", "dsig")->set_attribute (
-                                               "Algorithm", "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
-                                               );
-                               }
-                               reference->add_child("DigestMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
-                               /* This will be filled in by the signing later */
-                               reference->add_child("DigestValue", "dsig");
-                       }
-               }
+       doc.write_to_file_formatted (p.string(), "UTF-8");
 
-               signature->add_child("SignatureValue", "dsig");
+       _digest = make_digest (p.string (), 0);
+       _length = boost::filesystem::file_size (p.string ());
+}
 
-               xmlpp::Element* key_info = signature->add_child("KeyInfo", "dsig");
-               list<shared_ptr<Certificate> > c = certificates.leaf_to_root ();
-               for (list<shared_ptr<Certificate> >::iterator i = c.begin(); i != c.end(); ++i) {
-                       xmlpp::Element* data = key_info->add_child("X509Data", "dsig");
+void
+DCP::sign (xmlpp::Element* parent, CertificateChain const & certificates, string const & signer_key)
+{
+       xmlpp::Element* signer = parent->add_child("Signer");
 
+       {
+               xmlpp::Element* data = signer->add_child("X509Data", "dsig");
+               {
+                       xmlpp::Element* serial = data->add_child("X509IssuerSerial", "dsig");
+                       serial->add_child("X509IssuerName", "dsig")->add_child_text (
+                               Certificate::name_for_xml (certificates.leaf()->issuer())
+                               );
+                       serial->add_child("X509SerialNumber", "dsig")->add_child_text (
+                               certificates.leaf()->serial()
+                               );
+               }
+               data->add_child("X509SubjectName", "dsig")->add_child_text (
+                       Certificate::name_for_xml (certificates.leaf()->subject())
+                       );
+       }
+       
+       xmlpp::Element* signature = parent->add_child("Signature", "dsig");
+       
+       {
+               xmlpp::Element* signed_info = signature->add_child ("SignedInfo", "dsig");
+               signed_info->add_child("CanonicalizationMethod", "dsig")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
+               signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
+               {
+                       xmlpp::Element* reference = signed_info->add_child("Reference", "dsig");
+                       reference->set_attribute ("URI", "");
                        {
-                               xmlpp::Element* serial = data->add_child("X509IssuerSerial", "dsig");
-                               serial->add_child("X509IssuerName", "dsig")->add_child_text(
-                                       Certificate::name_for_xml ((*i)->issuer())
+                               xmlpp::Element* transforms = reference->add_child("Transforms", "dsig");
+                               transforms->add_child("Transform", "dsig")->set_attribute (
+                                       "Algorithm", "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
                                        );
-                               serial->add_child("X509SerialNumber", "dsig")->add_child_text((*i)->serial());
                        }
-                       
-                       data->add_child("X509Certificate", "dsig")->add_child_text((*i)->certificate());
-               }
-
-               doc.write_to_file_formatted ("/home/carl/fuckwit.xml", "UTF-8");
-
-               xmlSecKeysMngrPtr keys_manager = xmlSecKeysMngrCreate();
-               if (!keys_manager) {
-                       throw MiscError ("could not create keys manager");
-               }
-               if (xmlSecCryptoAppDefaultKeysMngrInit (keys_manager) < 0) {
-                       throw MiscError ("could not initialise keys manager");
+                       reference->add_child("DigestMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
+                       /* This will be filled in by the signing later */
+                       reference->add_child("DigestValue", "dsig");
                }
-
-               xmlSecKeyPtr const key = xmlSecCryptoAppKeyLoad (signer_key.c_str(), xmlSecKeyDataFormatPem, 0, 0, 0);
-               if (key == 0) {
-                       throw MiscError ("could not load signer key");
-               }
-
-               if (xmlSecCryptoAppDefaultKeysMngrAdoptKey (keys_manager, key) < 0) {
-                       xmlSecKeyDestroy (key);
-                       throw MiscError ("could not use signer key");
-               }
-
-               xmlSecDSigCtx signature_context;
-
-               if (xmlSecDSigCtxInitialize (&signature_context, keys_manager) < 0) {
-                       throw MiscError ("could not initialise XMLSEC context");
+       }
+       
+       signature->add_child("SignatureValue", "dsig");
+       
+       xmlpp::Element* key_info = signature->add_child("KeyInfo", "dsig");
+       list<shared_ptr<Certificate> > c = certificates.leaf_to_root ();
+       for (list<shared_ptr<Certificate> >::iterator i = c.begin(); i != c.end(); ++i) {
+               xmlpp::Element* data = key_info->add_child("X509Data", "dsig");
+               
+               {
+                       xmlpp::Element* serial = data->add_child("X509IssuerSerial", "dsig");
+                       serial->add_child("X509IssuerName", "dsig")->add_child_text(
+                               Certificate::name_for_xml ((*i)->issuer())
+                               );
+                       serial->add_child("X509SerialNumber", "dsig")->add_child_text((*i)->serial());
                }
-
-               if (xmlSecDSigCtxSign (&signature_context, signature->cobj()) < 0) {
-                       throw MiscError ("could not sign CPL");
+               
+               data->add_child("X509Certificate", "dsig")->add_child_text((*i)->certificate());
+       }
+       
+       xmlSecKeysMngrPtr keys_manager = xmlSecKeysMngrCreate();
+       if (!keys_manager) {
+               throw MiscError ("could not create keys manager");
+       }
+       if (xmlSecCryptoAppDefaultKeysMngrInit (keys_manager) < 0) {
+               throw MiscError ("could not initialise keys manager");
+       }
+       
+       xmlSecKeyPtr const key = xmlSecCryptoAppKeyLoad (signer_key.c_str(), xmlSecKeyDataFormatPem, 0, 0, 0);
+       if (key == 0) {
+               throw MiscError ("could not load signer key");
                }
-
-               xmlSecDSigCtxFinalize (&signature_context);
-               xmlSecKeysMngrDestroy (keys_manager);
+       
+       if (xmlSecCryptoAppDefaultKeysMngrAdoptKey (keys_manager, key) < 0) {
+               xmlSecKeyDestroy (key);
+               throw MiscError ("could not use signer key");
        }
-
-       doc.write_to_file_formatted (p.string(), "UTF-8");
-
-       _digest = make_digest (p.string (), 0);
-       _length = boost::filesystem::file_size (p.string ());
+       
+       xmlSecDSigCtx signature_context;
+       
+       if (xmlSecDSigCtxInitialize (&signature_context, keys_manager) < 0) {
+               throw MiscError ("could not initialise XMLSEC context");
+       }
+       
+       if (xmlSecDSigCtxSign (&signature_context, signature->cobj()) < 0) {
+               throw MiscError ("could not sign CPL");
+       }
+       
+       xmlSecDSigCtxFinalize (&signature_context);
+       xmlSecKeysMngrDestroy (keys_manager);
 }
 
 void
-CPL::write_to_pkl (ostream& s) const
+CPL::write_to_pkl (xmlpp::Element* p) const
 {
-       s << "    <Asset>\n"
-         << "      <Id>urn:uuid:" << _uuid << "</Id>\n"
-         << "      <Hash>" << _digest << "</Hash>\n"
-         << "      <Size>" << _length << "</Size>\n"
-         << "      <Type>text/xml</Type>\n"
-         << "    </Asset>\n";
+       xmlpp::Element* asset = p->add_child("Asset");
+       asset->add_child("Id")->add_child_text("urn:uuid:" + _uuid);
+       asset->add_child("Hash")->add_child_text(_digest);
+       asset->add_child("Size")->add_child_text(boost::lexical_cast<string> (_length));
+       asset->add_child("Type")->add_child_text("text/xml");
 }
 
 list<shared_ptr<const Asset> >
index e2e2314f8aded7b5c961605c3f04a8f0c00cb540..0ee4a8fc8bd23856461f6b3c80f5c296e984abac 100644 (file)
--- a/src/dcp.h
+++ b/src/dcp.h
@@ -32,7 +32,7 @@
 #include "certificates.h"
 
 namespace xmlpp {
-       class Node;
+       class Element;
 }
 
 /** @brief Namespace for everything in libdcp */
@@ -88,7 +88,7 @@ public:
        
        void write_xml (bool, CertificateChain const &, std::string const &) const;
        void write_to_assetmap (std::ostream& s) const;
-       void write_to_pkl (std::ostream& s) const;
+       void write_to_pkl (xmlpp::Element* p) const;
        
 private:
        std::string _directory;
@@ -168,6 +168,8 @@ public:
         */
        boost::signals2::signal<void (float)> Progress;
 
+       static void sign (xmlpp::Element* parent, CertificateChain const & certificates, std::string const & signer_key);
+
 private:
 
        /** Write the PKL file.
diff --git a/test/data/certificate_chain b/test/data/certificate_chain
new file mode 100644 (file)
index 0000000..0aa8880
--- /dev/null
@@ -0,0 +1,79 @@
+-----BEGIN CERTIFICATE-----
+MIIEdzCCA1+gAwIBAgIBBTANBgkqhkiG9w0BAQsFADCBgjEUMBIGA1UEChMLZXhh
+bXBsZS5vcmcxFDASBgNVBAsTC2V4YW1wbGUub3JnMS0wKwYDVQQDFCQuc21wdGUt
+NDMwLTIuUk9PVC5OT1RfRk9SX1BST0RVQ1RJT04xJTAjBgNVBC4THHJUZUs3eCtu
+b3BGa3lwaGZsb296NnAyWk03QT0wHhcNMTIxMjI2MTAyMTE4WhcNMjIxMjI0MTAy
+MTE4WjCBgjEUMBIGA1UEChMLZXhhbXBsZS5vcmcxFDASBgNVBAsTC2V4YW1wbGUu
+b3JnMS0wKwYDVQQDFCQuc21wdGUtNDMwLTIuUk9PVC5OT1RfRk9SX1BST0RVQ1RJ
+T04xJTAjBgNVBC4THHJUZUs3eCtub3BGa3lwaGZsb296NnAyWk03QT0wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWxcyyhakSyyBDBznaA0di/TYQ49k+
+mwY7s3IsGDPEuP4JpQD7sqPwcBIe0LrJJioggWo92C8rpx4Sa2WP1h31gn7g9ceU
+juFcOS2AjX60srQC3Us17o/sewKfyt2F0Fe1iB1e0qptyhH7X8yn4Z7MrRSVY8KA
+TQ4Flo649EM4u27QnH2oavfTUEmj56ZsY37aULHvK/fyF1vYHKgf5/nmBj9Nfcue
+dUAPX/uztETBhGpljlqY8tLuPL6L5ToqxYX6SCtx28N6KpBuhnRl7VuYxs5JvrHn
+2CyjZ5BU6fLz9GsEJqU8p+RVS2cFHJeDLY0GgGACRnZ+0WvgBQC7bjQzAgMBAAGj
+gfUwgfIwEgYDVR0TAQH/BAgwBgEB/wIBAzALBgNVHQ8EBAMCAQYwHQYDVR0OBBYE
+FK03iu8fp6KRZMqYX5aKM+qdmTOwMIGvBgNVHSMEgacwgaSAFK03iu8fp6KRZMqY
+X5aKM+qdmTOwoYGIpIGFMIGCMRQwEgYDVQQKEwtleGFtcGxlLm9yZzEUMBIGA1UE
+CxMLZXhhbXBsZS5vcmcxLTArBgNVBAMUJC5zbXB0ZS00MzAtMi5ST09ULk5PVF9G
+T1JfUFJPRFVDVElPTjElMCMGA1UELhMcclRlSzd4K25vcEZreXBoZmxvb3o2cDJa
+TTdBPYIBBTANBgkqhkiG9w0BAQsFAAOCAQEAeXAk+HIPX2xyt/XSwwwHVPOKehQF
+pEX945nCYLum7LjiDvYy8fV14ByLuyjzrb369huSW75+efTvLhe7MwA3aDlD0TsX
+pf5yW/TRR0CFZ2xdkvvXF00zc4ZpESGjoIB6J3pMGsLg0PoSzG/5JHuS4S96WSrJ
+StApvNTISE+DEsaSV/MEi61ZKXieA3cZwaVzGlMlHfTs5O5ggJjwsAxS6Tw7/oAO
+yvclCVyPqXSygQcPjSZXtV4DRnjMx7xU4WC05aHlRVTMNJ8KRt8f/rktYA3MV5lm
+RczqMKOEn7cHQS7i5LZWL00HPiwn3TNATlE86t5YdKZWoALrX/wAncH9vA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEfzCCA2egAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBgjEUMBIGA1UEChMLZXhh
+bXBsZS5vcmcxFDASBgNVBAsTC2V4YW1wbGUub3JnMS0wKwYDVQQDFCQuc21wdGUt
+NDMwLTIuUk9PVC5OT1RfRk9SX1BST0RVQ1RJT04xJTAjBgNVBC4THHJUZUs3eCtu
+b3BGa3lwaGZsb296NnAyWk03QT0wHhcNMTIxMjI2MTAyMTE4WhcNMjIxMjIzMTAy
+MTE4WjCBijEUMBIGA1UEChMLZXhhbXBsZS5vcmcxFDASBgNVBAsTC2V4YW1wbGUu
+b3JnMTUwMwYDVQQDFCwuc21wdGUtNDMwLTIuSU5URVJNRURJQVRFLk5PVF9GT1Jf
+UFJPRFVDVElPTjElMCMGA1UELhMcbG1xN0FJY1pvWWwyU3RJNkVvb2RnejRrR2s4
+PTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPwL+vvNvDZ78dsoF6Ov
+jgByKfsOFATQleNi5ZRWs39CLHdbYFycIjB2JXZbGZ/2GiPbHB82EOmMUN8NZFkt
+ksXttOPafYKGTFu1hQWW/b3D2v37X8QvmqMIZCBd1AFu3nDgjQjofDPrCTauPnuu
+jxH+0dBD2WLzi7a1nPDB7HaFkHegLpgOADD7XfFEvdsBXv0GjclRtnv3Sc7/6kYP
+/9vsjbzwF9CjbU/MAa/DnQvbUsW2TNAqs7nCUm+uFPqg4PKFnI0iLvnOjB18GX2u
+2U1yX2nGEF6P7LfhC9Sq1UO2e/H9bQ8H/aZRO4fl8jV457NEmNERbpmHQM8T83PF
+TMECAwEAAaOB9TCB8jASBgNVHRMBAf8ECDAGAQH/AgECMAsGA1UdDwQEAwIBBjAd
+BgNVHQ4EFgQUlmq7AIcZoYl2StI6Eoodgz4kGk8wga8GA1UdIwSBpzCBpIAUrTeK
+7x+nopFkyphflooz6p2ZM7ChgYikgYUwgYIxFDASBgNVBAoTC2V4YW1wbGUub3Jn
+MRQwEgYDVQQLEwtleGFtcGxlLm9yZzEtMCsGA1UEAxQkLnNtcHRlLTQzMC0yLlJP
+T1QuTk9UX0ZPUl9QUk9EVUNUSU9OMSUwIwYDVQQuExxyVGVLN3grbm9wRmt5cGhm
+bG9vejZwMlpNN0E9ggEFMA0GCSqGSIb3DQEBCwUAA4IBAQADsc9UuYZQRiqj1Raj
+9Z21b9KpIpqfOBcPuNK1E4bpCfKT4J9gNP+k33iG73QBL2C/7+XSfYRGwCDk4URt
+OAxK34A6SU2zyrPpaBKBc2OoyNiiA/GGhXe9X+9/HOO3OUpdqpSwAho6rFIjYjNP
+0MCoH7HXzCCM+Zl7lt9Nb4LHTjhi2OaSyj8yfxrNRjfHP2EbTSUTlwAJyfaVtLeF
+o8j8hXiGxx1tYlfDw74qdzFbymBjWNHatFm8W7j+MiT0awAqpKs6fTV3iqFA87rl
+nJN1rlcKYnmU9SDqwgivaUSViagQucgk9yzK7hof3NAITL01mHuc5huRea+ZVCRR
+68Ag
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEezCCA2OgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBijEUMBIGA1UEChMLZXhh
+bXBsZS5vcmcxFDASBgNVBAsTC2V4YW1wbGUub3JnMTUwMwYDVQQDFCwuc21wdGUt
+NDMwLTIuSU5URVJNRURJQVRFLk5PVF9GT1JfUFJPRFVDVElPTjElMCMGA1UELhMc
+bG1xN0FJY1pvWWwyU3RJNkVvb2RnejRrR2s4PTAeFw0xMjEyMjYxMDIxMThaFw0y
+MjEyMjIxMDIxMThaMIGEMRQwEgYDVQQKEwtleGFtcGxlLm9yZzEUMBIGA1UECxML
+ZXhhbXBsZS5vcmcxLzAtBgNVBAMUJkNTLnNtcHRlLTQzMC0yLkxFQUYuTk9UX0ZP
+Ul9QUk9EVUNUSU9OMSUwIwYDVQQuExxXT1ZYRkJxd1QwNXl2WUJzbzVCSHRVbjkr
+Vjg9MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt6QreIDAQheQZVel
+n9+7z/M2ssr2iCTmcmFEJU2anRhuCUDACp9QFfT+5tcPNi7qO5mz0IoPQ8jzvYSa
+QysWGGofQiSbPMRP0J3fhP6wK4KCD4EST6zLzGQ84DaQOLJoncom4lNZrS56ugVJ
+rm3ekUoWGCZ9YfBHH1A8eWUm5yJiJN0FAuvhQojS0hBqcWbwfOJDogR2NvBSaL6k
+zVlTGPcgu+27SQ+AIMJT8V5hqmMixWc+etEYzsg7hFM8EQj3KoaPi70yJ8ELfK3y
+y1tpnOCkg9RtGWXS2eKEGR9AMI2424Z59dcbunZkE0sRzEXp+kBKyc/qIAWVrkEb
+liBXcwIDAQABo4HvMIHsMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgWgMB0GA1Ud
+DgQWBBRY5VcUGrBPTnK9gGyjkEe1Sf35XzCBrwYDVR0jBIGnMIGkgBSWarsAhxmh
+iXZK0joSih2DPiQaT6GBiKSBhTCBgjEUMBIGA1UEChMLZXhhbXBsZS5vcmcxFDAS
+BgNVBAsTC2V4YW1wbGUub3JnMS0wKwYDVQQDFCQuc21wdGUtNDMwLTIuUk9PVC5O
+T1RfRk9SX1BST0RVQ1RJT04xJTAjBgNVBC4THHJUZUs3eCtub3BGa3lwaGZsb296
+NnAyWk03QT2CAQYwDQYJKoZIhvcNAQELBQADggEBAGTvqRuLZp1fTGnAoKMeGzo3
+G+jRz26vNVKYa09RwifNLEI5V0MlAHWm4YWIj9Ml+AF7CEhYbw69/v0ygK9NXVPk
+Hl3+JBCoveaB0Fz73IQRHJVTDKlfH54aDoDFayQK6dZ1pfpvZa72ih3IXva9PsRT
+5xx4ILIatJb9JsE3zmW3fYk/93YMTq3ewUdWi7ldpwwLFVs89TNOQOcAMIwvPpYW
+kqmtwIG6as2SiV0fJ0PpcxYZN3jvsHB/wRy2f5pSlAw6NBeVZNoKX4Zxue77TrAC
+cmsEtjOEApFv+mKdmOPjB5qXurZEzgyzdm8xdKw4UnblGzA81/7xMchPK0P66To=
+-----END CERTIFICATE-----
diff --git a/test/data/signer.key b/test/data/signer.key
new file mode 100644 (file)
index 0000000..2cd376d
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAt6QreIDAQheQZVeln9+7z/M2ssr2iCTmcmFEJU2anRhuCUDA
+Cp9QFfT+5tcPNi7qO5mz0IoPQ8jzvYSaQysWGGofQiSbPMRP0J3fhP6wK4KCD4ES
+T6zLzGQ84DaQOLJoncom4lNZrS56ugVJrm3ekUoWGCZ9YfBHH1A8eWUm5yJiJN0F
+AuvhQojS0hBqcWbwfOJDogR2NvBSaL6kzVlTGPcgu+27SQ+AIMJT8V5hqmMixWc+
+etEYzsg7hFM8EQj3KoaPi70yJ8ELfK3yy1tpnOCkg9RtGWXS2eKEGR9AMI2424Z5
+9dcbunZkE0sRzEXp+kBKyc/qIAWVrkEbliBXcwIDAQABAoIBAGHIOJ1hcP3ALlLH
+6JjIOOjxSB7Lk5nKjCo7QF3chIdBitXCdH8zdSE74r5npOHk+TPjE6vm11nwllhD
+UyCQwKMfXqWJeF9S6GzcozfdpVCFnVtEDsv95kZe2UtJwmFuHeZmzW2VlBpytUZ3
+qlQGjIwwNrOFSx3rIvO5dXnuMli/PyQqEqXE4agQj1ZSHXgc//crzRX/XWKNY+bA
+cWAVinjl+TIR6OOLLLu6X9lPU+Ai9TuhzMQCCMocR0w81fG2pflh37buAzfzdvms
+MunZL8Le4/S6fuMTMslx12AHL55PIAiLF6uApah48rGfL7sZsDEhoPQk7b1Y7pHW
+A6C7AYECgYEA3wYIT59lIhEaMgagyUfb5xX8Zk2TOq6qJwkRwiSdep2D5bL8l9eL
+63bwi5ZMxuPMCnb3bw18J6bV7e7NERjQAz7deL7WxxB68muDXw44cyBHkpgBs2i3
+Qg01tTFyUqB7LHlQ9J9ZTXoHrpgmySXfu3DLWlFCjqt0dv7qsNgEhQcCgYEA0sts
+5aHMah3uZdIdrB7nAFVShlcM96yU/+np+re1E+L5Qpr+yox7IKTWZI7WlZ11QDmb
+//qLqdGjECIcoS3jkCZKpqPzuZKWoGyUef0ixmQTccq77Xitd1pu07QoS06VydVG
+TeMqdZCchYN2NAiTK/4d1H4kpJCSNMpM/JfaizUCgYEAsbIDwzUUBk2sGnnPeDBK
+FNger4BVs2bhaZK/VHmKA90m70hqG62A7U5qID3T1JBBzYC2awRKjOlQAHDJcTrc
+2gknuwIK7LbDzw08sesJrSjl/fYhPMpNYVJXHZRVK2J0YZ4Tk6S3KZT2M/VEyfXk
+Slt3mvGt3zDa7cj0Q40KJNcCgYA8BLfI2jy9qjAKxby1GUdkjOamYXrLulPiWdPJ
+Ey13sBSQplkNitoz/Tsd/p2Sk/aihsSoKcpCW/I10cCdE9fLX1u5/sySde51VvUf
+lrekDTKMH9FKWCXr6c/Mb2tZpdJ4WUVfP+MC/l3Slg+92QMub3hG3HPKd29poIAz
+G3maUQKBgGgqigBTrmOcZuEPxcC2eei7m4wckv0pCmTbuvZ479jsoWZRkSE8jm9X
+V+ZjLRbwCCcdEky7CW/iif5Zc0WW2Z2Y86KPPApESnhkMVyZDt4sjjo9maMAxAI6
+ajdpjTszRZvJaeTYDOTZM9bPRFiMHJlAQp0+lt8zrlHUhohl2yT2
+-----END RSA PRIVATE KEY-----