Merge Signer into CertificateChain.
authorCarl Hetherington <cth@carlh.net>
Thu, 30 Jul 2015 01:10:09 +0000 (02:10 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 30 Jul 2015 01:10:09 +0000 (02:10 +0100)
19 files changed:
src/certificate.cc
src/certificate.h
src/certificate_chain.cc
src/certificate_chain.h
src/cpl.cc
src/cpl.h
src/dcp.cc
src/dcp.h
src/decrypted_kdm.cc
src/decrypted_kdm.h
src/encrypted_kdm.cc
src/encrypted_kdm.h
src/signer.cc [deleted file]
src/signer.h [deleted file]
src/util.h
src/wscript
test/certificates_test.cc
test/encryption_test.cc
test/round_trip_test.cc

index fcc7b0ae5bda8e807fa1fc3f4ad61823302e7568..73f403bfbd16ebc8ed6bb221f97314a168730b59 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -17,8 +17,8 @@
 
 */
 
-/** @file  src/certificates.cc
- *  @brief Certificate and CertificateChain classes.
+/** @file  src/certificate.cc
+ *  @brief Certificate class.
  */
 
 #include "KM_util.h"
index c2121a8315d77e0f21c97309ed45492c645a4117..6225cf31012c424b02990ae1cfb5669e6478b694 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 
 */
 
-/** @file  src/certificates.h
- *  @brief Certificate and CertificateChain classes.
+/** @file  src/certificate.h
+ *  @brief Certificate class.
  */
 
-#ifndef LIBDCP_CERTIFICATES_H
-#define LIBDCP_CERTIFICATES_H
+#ifndef LIBDCP_CERTIFICATE_H
+#define LIBDCP_CERTIFICATE_H
 
 #undef X509_NAME
 #include <openssl/x509.h>
index e7de5bd8a2fe39fd7abae5c8411007dd22ebd553..c0bfd52f2752057a1dad5d8f5a9dc87239b726e4 100644 (file)
 #include "util.h"
 #include "dcp_assert.h"
 #include "KM_util.h"
+#include "compose.hpp"
+#include <libcxml/cxml.h>
+#include <libxml++/libxml++.h>
+#include <xmlsec/xmldsig.h>
+#include <xmlsec/dl.h>
+#include <xmlsec/app.h>
+#include <xmlsec/crypto.h>
 #include <openssl/sha.h>
 #include <openssl/bio.h>
 #include <openssl/evp.h>
+#include <openssl/pem.h>
 #include <boost/filesystem.hpp>
 #include <boost/algorithm/string.hpp>
+#include <boost/foreach.hpp>
 #include <fstream>
 #include <sstream>
 
@@ -157,8 +166,7 @@ public_key_digest (boost::filesystem::path private_key, boost::filesystem::path
        return dig;
 }
 
-boost::filesystem::path
-dcp::make_certificate_chain (
+CertificateChain::CertificateChain (
        boost::filesystem::path openssl,
        string organisation,
        string organisational_unit,
@@ -280,7 +288,13 @@ dcp::make_certificate_chain (
 
        boost::filesystem::current_path (cwd);
 
-       return directory;
+       _certificates.push_back (dcp::Certificate (dcp::file_to_string (directory / "ca.self-signed.pem")));
+       _certificates.push_back (dcp::Certificate (dcp::file_to_string (directory / "intermediate.signed.pem")));
+       _certificates.push_back (dcp::Certificate (dcp::file_to_string (directory / "leaf.signed.pem")));
+
+       _key = dcp::file_to_string (directory / "leaf.key");
+
+       boost::filesystem::remove_all (directory);
 }
 
 /** @return Root certificate */
@@ -351,12 +365,15 @@ CertificateChain::remove (int i)
 }
 
 /** Check to see if the chain is valid (i.e. root signs the intermediate, intermediate
- *  signs the leaf and so on).
+ *  signs the leaf and so on) and that the private key (if there is one) matches the
+ *  leaf certificate.
  *  @return true if it's ok, false if not.
  */
 bool
 CertificateChain::valid () const
 {
+       /* Check the certificate chain */
+
        X509_STORE* store = X509_STORE_new ();
        if (!store) {
                return false;
@@ -398,7 +415,24 @@ CertificateChain::valid () const
        }
 
        X509_STORE_free (store);
-       return true;
+
+       /* Check that the leaf certificate matches the private key, if there is one */
+
+       if (!_key) {
+               return true;
+       }
+
+       BIO* bio = BIO_new_mem_buf (const_cast<char *> (_key->c_str ()), -1);
+       if (!bio) {
+               throw MiscError ("could not create memory BIO");
+       }
+
+       RSA* private_key = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
+       RSA* public_key = leaf().public_key ();
+       bool const valid = !BN_cmp (private_key->n, public_key->n);
+       BIO_free (bio);
+
+       return valid;
 }
 
 /** @return true if the chain is now in order from root to leaf,
@@ -418,3 +452,101 @@ CertificateChain::attempt_reorder ()
        _certificates = original;
        return false;
 }
+
+/** Add a &lt;Signer&gt; and &lt;ds:Signature&gt; nodes to an XML node.
+ *  @param parent XML node to add to.
+ *  @param standard INTEROP or SMPTE.
+ */
+void
+CertificateChain::sign (xmlpp::Element* parent, Standard standard) const
+{
+       /* <Signer> */
+
+       xmlpp::Element* signer = parent->add_child("Signer");
+       xmlpp::Element* data = signer->add_child("X509Data", "dsig");
+       xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", "dsig");
+       serial_element->add_child("X509IssuerName", "dsig")->add_child_text (leaf().issuer());
+       serial_element->add_child("X509SerialNumber", "dsig")->add_child_text (leaf().serial());
+       data->add_child("X509SubjectName", "dsig")->add_child_text (leaf().subject());
+
+       /* <Signature> */
+
+       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");
+
+       if (standard == INTEROP) {
+               signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
+       } else {
+               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");
+
+       signature->add_child("SignatureValue", "dsig");
+       signature->add_child("KeyInfo", "dsig");
+       add_signature_value (signature, "dsig");
+}
+
+
+/** Sign an XML node.
+ *
+ *  @param parent Node to sign.
+ *  @param ns Namespace to use for the signature XML nodes.
+ */
+void
+CertificateChain::add_signature_value (xmlpp::Node* parent, string ns) const
+{
+       cxml::Node cp (parent);
+       xmlpp::Node* key_info = cp.node_child("KeyInfo")->node ();
+
+       /* Add the certificate chain to the KeyInfo child node of parent */
+       CertificateChain::List c = leaf_to_root ();
+       BOOST_FOREACH (Certificate const & i, leaf_to_root ()) {
+               xmlpp::Element* data = key_info->add_child("X509Data", ns);
+
+               {
+                       xmlpp::Element* serial = data->add_child("X509IssuerSerial", ns);
+                       serial->add_child("X509IssuerName", ns)->add_child_text (i.issuer ());
+                       serial->add_child("X509SerialNumber", ns)->add_child_text (i.serial ());
+               }
+
+               data->add_child("X509Certificate", ns)->add_child_text (i.certificate());
+       }
+
+       xmlSecDSigCtxPtr signature_context = xmlSecDSigCtxCreate (0);
+       if (signature_context == 0) {
+               throw MiscError ("could not create signature context");
+       }
+
+       signature_context->signKey = xmlSecCryptoAppKeyLoadMemory (
+               reinterpret_cast<const unsigned char *> (_key->c_str()), _key->size(), xmlSecKeyDataFormatPem, 0, 0, 0
+               );
+
+       if (signature_context->signKey == 0) {
+               throw StringError ("could not read private key");
+       }
+
+       /* XXX: set key name to the PEM string: this can't be right! */
+       if (xmlSecKeySetName (signature_context->signKey, reinterpret_cast<const xmlChar *> (_key->c_str())) < 0) {
+               throw MiscError ("could not set key name");
+       }
+
+       int const r = xmlSecDSigCtxSign (signature_context, parent->cobj ());
+       if (r < 0) {
+               throw MiscError (String::compose ("could not sign (%1)", r));
+       }
+
+       xmlSecDSigCtxDestroy (signature_context);
+}
index b4cc24851f93ac994230550ca91288e9cd306a1c..4e13d6ee1590e460cf0d78746a84e116b1967f23 100644 (file)
 #define LIBDCP_CERTIFICATE_CHAIN_H
 
 #include "certificate.h"
+#include "types.h"
 #include <boost/filesystem.hpp>
+#include <boost/optional.hpp>
+
+namespace xmlpp {
+       class Node;
+}
 
 namespace dcp {
 
@@ -37,6 +43,23 @@ class CertificateChain
 public:
        CertificateChain () {}
 
+       /** Create a chain of certificates for signing things.
+        *  @param openssl Name of openssl binary (if it is on the path) or full path.
+        *  @return Directory (which should be deleted by the caller) containing:
+        *    - ca.self-signed.pem      self-signed root certificate
+        *    - intermediate.signed.pem intermediate certificate
+        *    - leaf.key                leaf certificate private key
+        *    - leaf.signed.pem         leaf certificate
+        */
+       CertificateChain (
+               boost::filesystem::path openssl,
+               std::string organisation = "example.org",
+               std::string organisational_unit = "example.org",
+               std::string root_common_name = ".smpte-430-2.ROOT.NOT_FOR_PRODUCTION",
+               std::string intermediate_common_name = ".smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION",
+               std::string leaf_common_name = "CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION"
+               );
+
        void add (Certificate c);
        void remove (Certificate c);
        void remove (int);
@@ -52,29 +75,25 @@ public:
        bool valid () const;
        bool attempt_reorder ();
 
+       void sign (xmlpp::Element* parent, Standard standard) const;
+       void add_signature_value (xmlpp::Node* parent, std::string ns) const;
+
+       boost::optional<std::string> key () const {
+               return _key;
+       }
+
+       void set_key (std::string k) {
+               _key = k;
+       }
+
 private:
        friend class ::certificates;
 
        List _certificates;
+       /** Leaf certificate's private key, if known */
+       boost::optional<std::string> _key;
 };
 
-/** Create a chain of certificates for signing things.
- *  @param openssl Name of openssl binary (if it is on the path) or full path.
- *  @return Directory (which should be deleted by the caller) containing:
- *    - ca.self-signed.pem      self-signed root certificate
- *    - intermediate.signed.pem intermediate certificate
- *    - leaf.key                leaf certificate private key
- *    - leaf.signed.pem         leaf certificate
- */
-boost::filesystem::path make_certificate_chain (
-       boost::filesystem::path openssl,
-       std::string organisation = "example.org",
-       std::string organisational_unit = "example.org",
-       std::string root_common_name = ".smpte-430-2.ROOT.NOT_FOR_PRODUCTION",
-       std::string intermediate_common_name = ".smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION",
-       std::string leaf_common_name = "CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION"
-       );
-
 }
 
 #endif
index 766b91c315660d858880dac57aa57414b5d4aa95..78f498853c18469b2a157774ce5d70c78acf4f67 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
 #include "util.h"
 #include "reel.h"
 #include "metadata.h"
-#include "signer.h"
+#include "certificate_chain.h"
 #include "xml.h"
 #include "reel_picture_asset.h"
 #include "reel_sound_asset.h"
@@ -107,7 +107,7 @@ CPL::add (boost::shared_ptr<Reel> reel)
  *  @param signer Signer to sign the CPL, or 0 to add no signature.
  */
 void
-CPL::write_xml (boost::filesystem::path file, Standard standard, shared_ptr<const Signer> signer) const
+CPL::write_xml (boost::filesystem::path file, Standard standard, shared_ptr<const CertificateChain> signer) const
 {
        xmlpp::Document doc;
        xmlpp::Element* root;
@@ -255,4 +255,3 @@ CPL::pkl_type (Standard standard) const
                DCP_ASSERT (false);
        }
 }
-
index 7716464d960fc2e6b045cad0df57284c9b963fd1..fe123fd3d3cc5dc38281f89d49cf4da3c8e7918a 100644 (file)
--- a/src/cpl.h
+++ b/src/cpl.h
@@ -42,7 +42,7 @@ class ReelAsset;
 class Reel;
 class XMLMetadata;
 class MXFMetadata;
-class Signer;
+class CertificateChain;
 class DecryptedKDM;
 
 /** @class CPL
@@ -108,7 +108,7 @@ public:
        void write_xml (
                boost::filesystem::path file,
                Standard standard,
-               boost::shared_ptr<const Signer>
+               boost::shared_ptr<const CertificateChain>
                ) const;
 
        void resolve_refs (std::list<boost::shared_ptr<Object> >);
index 7a521141565d9855e7fc0a814b8f262e3e6f2f60..4f1f07df2f3d65fb99d807ed43fc97d768ee289f 100644 (file)
@@ -34,7 +34,7 @@
 #include "metadata.h"
 #include "exceptions.h"
 #include "cpl.h"
-#include "signer.h"
+#include "certificate_chain.h"
 #include "compose.hpp"
 #include "AS_DCP.h"
 #include "decrypted_kdm.h"
@@ -245,7 +245,7 @@ DCP::add (DecryptedKDM const & kdm)
 }
 
 boost::filesystem::path
-DCP::write_pkl (Standard standard, string pkl_uuid, XMLMetadata metadata, shared_ptr<const Signer> signer) const
+DCP::write_pkl (Standard standard, string pkl_uuid, XMLMetadata metadata, shared_ptr<const CertificateChain> signer) const
 {
        boost::filesystem::path p = _directory;
        p /= String::compose ("pkl_%1.xml", pkl_uuid);
@@ -400,7 +400,7 @@ void
 DCP::write_xml (
        Standard standard,
        XMLMetadata metadata,
-       shared_ptr<const Signer> signer
+       shared_ptr<const CertificateChain> signer
        )
 {
        BOOST_FOREACH (shared_ptr<CPL> i, cpls ()) {
index 44fe7621ed38e6b95041528d665c6818f7ae64d2..f852b6eba4bf324364878ee923d72e1a7ed39612 100644 (file)
--- a/src/dcp.h
+++ b/src/dcp.h
@@ -45,7 +45,7 @@ class Content;
 class Reel;
 class CPL;
 class XMLMetadata;
-class Signer;
+class CertificateChain;
 class DecryptedKDM;
 class Asset;
 class DCPReadError;
@@ -94,7 +94,7 @@ public:
        void write_xml (
                Standard standard,
                XMLMetadata metadata = XMLMetadata (),
-               boost::shared_ptr<const Signer> signer = boost::shared_ptr<const Signer> ()
+               boost::shared_ptr<const CertificateChain> signer = boost::shared_ptr<const CertificateChain> ()
        );
 
 private:
@@ -106,7 +106,7 @@ private:
                Standard standard,
                std::string pkl_uuid,
                XMLMetadata metadata,
-               boost::shared_ptr<const Signer> signer
+               boost::shared_ptr<const CertificateChain> signer
                ) const;
 
        void write_volindex (Standard standard) const;
index 62058fee564dd0494bd64c326997d1621501cd95..949db72bdcc6e763767e7c24fea85d1af3d7ddae 100644 (file)
@@ -25,7 +25,7 @@
 #include "util.h"
 #include "exceptions.h"
 #include "cpl.h"
-#include "signer.h"
+#include "certificate_chain.h"
 #include "dcp_assert.h"
 #include "AS_DCP.h"
 #include "KM_util.h"
@@ -212,7 +212,7 @@ DecryptedKDM::DecryptedKDM (
 }
 
 EncryptedKDM
-DecryptedKDM::encrypt (shared_ptr<const Signer> signer, Certificate recipient, Formulation formulation) const
+DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, Formulation formulation) const
 {
        list<pair<string, string> > key_ids;
        list<string> keys;
@@ -227,7 +227,7 @@ DecryptedKDM::encrypt (shared_ptr<const Signer> signer, Certificate recipient, F
                uint8_t structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
                put (&p, structure_id, 16);
 
-               base64_decode (signer->certificates().leaf().thumbprint (), p, 20);
+               base64_decode (signer->leaf().thumbprint (), p, 20);
                p += 20;
 
                put_uuid (&p, i.cpl_id ());
index 710de519a7d1fc1d106b49016fe3d2bc06f16778..45ad8fa6c2cfeab66e6ffabbd8184d800913c077 100644 (file)
@@ -35,7 +35,7 @@ namespace dcp {
 
 class DecryptedKDMKey;
 class EncryptedKDM;
-class Signer;
+class CertificateChain;
 class CPL;
 
 /** @class DecryptedKDM
@@ -72,12 +72,12 @@ public:
                );
 
        /** Encrypt this KDM's keys and sign the whole KDM.
-        *  @param signer Signer.
+        *  @param signer Chain to sign with.
         *  @param recipient Certificate of the projector/server which should receive this KDM's keys.
         *  @param formulation Formulation to use for the encrypted KDM.
         *  @return Encrypted KDM.
         */
-       EncryptedKDM encrypt (boost::shared_ptr<const Signer> signer, Certificate recipient, Formulation formulation) const;
+       EncryptedKDM encrypt (boost::shared_ptr<const CertificateChain> signer, Certificate recipient, Formulation formulation) const;
 
        /** @return This KDM's (decrypted) keys, which could be used to decrypt assets. */
        std::list<DecryptedKDMKey> keys () const {
index 948e26a5bb64a021225bc8a8e9e8744e03cb59bc..c3d8a618eca5d07ef011ade159af9a39f97cb9b6 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "encrypted_kdm.h"
 #include "util.h"
-#include "signer.h"
+#include "certificate_chain.h"
 #include <libcxml/cxml.h>
 #include <libxml++/document.h>
 #include <libxml++/nodes/element.h>
@@ -492,7 +492,7 @@ EncryptedKDM::EncryptedKDM (string s)
 }
 
 EncryptedKDM::EncryptedKDM (
-       shared_ptr<const Signer> signer,
+       shared_ptr<const CertificateChain> signer,
        Certificate recipient,
        string device_list_description,
        string cpl_id,
@@ -508,8 +508,8 @@ EncryptedKDM::EncryptedKDM (
        /* Fill our XML-ish description in with the juicy bits that the caller has given */
 
        data::AuthenticatedPublic& aup = _data->authenticated_public;
-       aup.signer.x509_issuer_name = signer->certificates().leaf().issuer ();
-       aup.signer.x509_serial_number = signer->certificates().leaf().serial ();
+       aup.signer.x509_issuer_name = signer->leaf().issuer ();
+       aup.signer.x509_serial_number = signer->leaf().serial ();
 
        data::KDMRequiredExtensions& kre = _data->authenticated_public.required_extensions.kdm_required_extensions;
        kre.recipient.x509_issuer_serial.x509_issuer_name = recipient.issuer ();
@@ -518,7 +518,7 @@ EncryptedKDM::EncryptedKDM (
        kre.authorized_device_info.device_list_description = device_list_description;
        kre.composition_playlist_id = cpl_id;
        if (formulation == DCI_ANY || formulation == DCI_SPECIFIC) {
-               kre.content_authenticator = signer->certificates().leaf().thumbprint ();
+               kre.content_authenticator = signer->leaf().thumbprint ();
        }
        kre.content_title_text = content_title_text;
        kre.not_valid_before = not_valid_before;
index dc98e1f122edc782496f5b08ceee3f577aab4184..247d6678045098d7cac57e47f0328bda4c241657 100644 (file)
@@ -39,7 +39,7 @@ namespace data {
        class EncryptedKDMData;
 }
 
-class Signer;
+class CertificateChain;
 class Certificate;
 
 /** @class EncryptedKDM
@@ -77,7 +77,7 @@ private:
 
        /** Construct an EncryptedKDM from a set of details */
        EncryptedKDM (
-               boost::shared_ptr<const Signer> signer,
+               boost::shared_ptr<const CertificateChain> signer,
                Certificate recipient,
                std::string device_list_description,
                std::string cpl_id,
diff --git a/src/signer.cc b/src/signer.cc
deleted file mode 100644 (file)
index c04ac12..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file  src/signer.cc
- *  @brief Signer class.
- */
-
-#include "signer.h"
-#include "exceptions.h"
-#include "certificate_chain.h"
-#include "util.h"
-#include <libcxml/cxml.h>
-#include <libxml++/libxml++.h>
-#include <xmlsec/xmldsig.h>
-#include <xmlsec/dl.h>
-#include <xmlsec/app.h>
-#include <xmlsec/crypto.h>
-#include <openssl/pem.h>
-#include "compose.hpp"
-
-using std::string;
-using std::list;
-using boost::shared_ptr;
-using namespace dcp;
-
-Signer::Signer (boost::filesystem::path openssl)
-{
-       create (make_certificate_chain (openssl));
-}
-
-Signer::Signer (boost::filesystem::path openssl,
-               string organisation,
-               string organisational_unit,
-               string root_common_name,
-               string intermediate_common_name,
-               string leaf_common_name
-       )
-{
-       create (
-               make_certificate_chain (
-                       openssl,
-                       organisation,
-                       organisational_unit,
-                       root_common_name,
-                       intermediate_common_name,
-                       leaf_common_name
-                       )
-               );
-}
-
-void
-Signer::create (boost::filesystem::path directory)
-{
-       _certificates.add (dcp::Certificate (dcp::file_to_string (directory / "ca.self-signed.pem")));
-       _certificates.add (dcp::Certificate (dcp::file_to_string (directory / "intermediate.signed.pem")));
-       _certificates.add (dcp::Certificate (dcp::file_to_string (directory / "leaf.signed.pem")));
-
-       _key = dcp::file_to_string (directory / "leaf.key");
-
-       boost::filesystem::remove_all (directory);
-}
-
-/** Add a &lt;Signer&gt; and &lt;ds:Signature&gt; nodes to an XML node.
- *  @param parent XML node to add to.
- *  @param standard INTEROP or SMPTE.
- */
-void
-Signer::sign (xmlpp::Element* parent, Standard standard) const
-{
-       /* <Signer> */
-
-       xmlpp::Element* signer = parent->add_child("Signer");
-       xmlpp::Element* data = signer->add_child("X509Data", "dsig");
-       xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", "dsig");
-       serial_element->add_child("X509IssuerName", "dsig")->add_child_text (_certificates.leaf().issuer());
-       serial_element->add_child("X509SerialNumber", "dsig")->add_child_text (_certificates.leaf().serial());
-       data->add_child("X509SubjectName", "dsig")->add_child_text (_certificates.leaf().subject());
-
-       /* <Signature> */
-
-       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");
-
-       if (standard == INTEROP) {
-               signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
-       } else {
-               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");
-
-       signature->add_child("SignatureValue", "dsig");
-       signature->add_child("KeyInfo", "dsig");
-       add_signature_value (signature, "dsig");
-}
-
-
-/** Sign an XML node.
- *
- *  @param parent Node to sign.
- *  @param ns Namespace to use for the signature XML nodes.
- */
-void
-Signer::add_signature_value (xmlpp::Node* parent, string ns) const
-{
-       cxml::Node cp (parent);
-       xmlpp::Node* key_info = cp.node_child("KeyInfo")->node ();
-
-       /* Add the certificate chain to the KeyInfo child node of parent */
-       CertificateChain::List c = _certificates.leaf_to_root ();
-       for (CertificateChain::List::iterator i = c.begin(); i != c.end(); ++i) {
-               xmlpp::Element* data = key_info->add_child("X509Data", ns);
-
-               {
-                       xmlpp::Element* serial = data->add_child("X509IssuerSerial", ns);
-                       serial->add_child("X509IssuerName", ns)->add_child_text (i->issuer ());
-                       serial->add_child("X509SerialNumber", ns)->add_child_text (i->serial ());
-               }
-
-               data->add_child("X509Certificate", ns)->add_child_text (i->certificate());
-       }
-
-       xmlSecDSigCtxPtr signature_context = xmlSecDSigCtxCreate (0);
-       if (signature_context == 0) {
-               throw MiscError ("could not create signature context");
-       }
-
-       signature_context->signKey = xmlSecCryptoAppKeyLoadMemory (
-               reinterpret_cast<const unsigned char *> (_key.c_str()), _key.size(), xmlSecKeyDataFormatPem, 0, 0, 0
-               );
-
-       if (signature_context->signKey == 0) {
-               throw FileError ("could not load private key file", _key, 0);
-       }
-
-       /* XXX: set key name to the file name: is this right? */
-       if (xmlSecKeySetName (signature_context->signKey, reinterpret_cast<const xmlChar *> (_key.c_str())) < 0) {
-               throw MiscError ("could not set key name");
-       }
-
-       int const r = xmlSecDSigCtxSign (signature_context, parent->cobj ());
-       if (r < 0) {
-               throw MiscError (String::compose ("could not sign (%1)", r));
-       }
-
-       xmlSecDSigCtxDestroy (signature_context);
-}
-
-bool
-Signer::valid () const
-{
-       if (!_certificates.valid ()) {
-               return false;
-       }
-
-       BIO* bio = BIO_new_mem_buf (const_cast<char *> (_key.c_str ()), -1);
-       if (!bio) {
-               throw MiscError ("could not create memory BIO");
-       }
-
-       RSA* private_key = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
-       RSA* public_key = _certificates.leaf().public_key ();
-       bool const valid = !BN_cmp (private_key->n, public_key->n);
-       BIO_free (bio);
-
-       return valid;
-}
diff --git a/src/signer.h b/src/signer.h
deleted file mode 100644 (file)
index b8bd564..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
-    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef LIBDCP_SIGNER_H
-#define LIBDCP_SIGNER_H
-
-/** @file  src/signer.h
- *  @brief Signer class.
- */
-
-#include "certificate.h"
-#include "certificate_chain.h"
-#include "types.h"
-#include <boost/filesystem.hpp>
-
-namespace xmlpp {
-       class Element;
-       class Node;
-}
-
-namespace dcp {
-
-/** @class Signer
- *  @brief A class which can sign XML files.
- */
-class Signer
-{
-public:
-       Signer (boost::filesystem::path openssl);
-
-       Signer (
-               boost::filesystem::path openssl,
-               std::string organisation,
-               std::string organisational_unit,
-               std::string root_common_name,
-               std::string intermediate_common_name,
-               std::string leaf_common_name
-               );
-
-       /** @param c Certificate chain to sign with.
-        *  @param k Key to sign with as a PEM-format string.
-        */
-       Signer (CertificateChain c, std::string k)
-               : _certificates (c)
-               , _key (k)
-       {}
-
-       void sign (xmlpp::Element* parent, Standard standard) const;
-       void add_signature_value (xmlpp::Node* parent, std::string ns) const;
-
-       CertificateChain const & certificates () const {
-               return _certificates;
-       }
-
-       CertificateChain& certificates () {
-               return _certificates;
-       }
-
-       std::string key () const {
-               return _key;
-       }
-
-       void set_key (std::string k) {
-               _key = k;
-       }
-
-       bool valid () const;
-
-private:
-       void create (boost::filesystem::path directory);
-
-       /** Certificate chain to sign with */
-       CertificateChain _certificates;
-       /** Key to sign with as a PEM-format string */
-       std::string _key;
-};
-
-}
-
-#endif
index 97ef2c55cd0c12780089abbda82747c9e4ce48da..8b72e7e07ec3b9de31d734b9e9429110b485a542 100644 (file)
@@ -59,10 +59,6 @@ extern bool ids_equal (std::string a, std::string b);
 
 extern void init ();
 
-extern void sign (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, Standard standard);
-extern void add_signature_value (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, std::string const & ns);
-extern void add_signer (xmlpp::Element* parent, CertificateChain const & certificates, std::string const & ns);
-
 extern int base64_decode (std::string const & in, unsigned char* out, int out_length);
 extern boost::optional<boost::filesystem::path> relative_to_root (boost::filesystem::path root, boost::filesystem::path file);
 extern FILE * fopen_boost (boost::filesystem::path, std::string);
index 15d1b7811831e4f2a859f52a1508cdcb04f905a9..6a2be8943074c38c41532a88fdc099de2ebca447 100644 (file)
@@ -43,7 +43,6 @@ def build(bld):
              reel_stereo_picture_asset.cc
              reel_subtitle_asset.cc
              rgb_xyz.cc
-             signer.cc
              smpte_load_font_node.cc
              smpte_subtitle_asset.cc
              sound_asset.cc
@@ -105,7 +104,6 @@ def build(bld):
               reel_stereo_picture_asset.h
               reel_subtitle_asset.h
               ref.h
-              signer.h
               smpte_load_font_node.h
               smpte_subtitle_asset.h
               sound_frame.h
index 3926c7103effcd32a33b1662d72ffaad1195bd0b..166ebb2d8057ac5a74b1b94da5bf5e5806253d8b 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <boost/test/unit_test.hpp>
 #include "certificate.h"
-#include "signer.h"
+#include "certificate_chain.h"
 #include "util.h"
 
 using std::list;
@@ -141,11 +141,11 @@ BOOST_AUTO_TEST_CASE (signer_validation)
        chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
        chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
        chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-       dcp::Signer signer (chain, dcp::file_to_string ("test/ref/crypt/leaf.key"));
-       BOOST_CHECK (signer.valid ());
+       chain.set_key (dcp::file_to_string ("test/ref/crypt/leaf.key"));
+       BOOST_CHECK (chain.valid ());
 
        /* Put in an unrelated key and the signer should no longer be valid */
-       dcp::Signer another_signer ("openssl");
-       signer.set_key (another_signer.key ());
-       BOOST_CHECK (!signer.valid ());
+       dcp::CertificateChain another_chain ("openssl");
+       chain.set_key (another_chain.key().get ());
+       BOOST_CHECK (!chain.valid ());
 }
index 0f3aa69e866bd2eb43ab63a753d39924006e20b7..bab209589abc3bc46ca785332618d2657d83a275 100644 (file)
@@ -21,7 +21,7 @@
 #include "metadata.h"
 #include "certificate.h"
 #include "dcp.h"
-#include "signer.h"
+#include "certificate_chain.h"
 #include "cpl.h"
 #include "mono_picture_asset.h"
 #include "picture_asset_writer.h"
@@ -66,17 +66,11 @@ BOOST_AUTO_TEST_CASE (encryption_test)
        dcp::DCP d ("build/test/DCP/encryption_test");
 
        /* Use test/ref/crypt so this test is repeatable */
-       dcp::CertificateChain chain;
-       chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
-       chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
-       chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-
-       shared_ptr<dcp::Signer> signer (
-               new dcp::Signer (
-                       chain,
-                       dcp::file_to_string ("test/ref/crypt/leaf.key")
-                       )
-               );
+       shared_ptr<dcp::CertificateChain> signer (new dcp::CertificateChain ());
+       signer->add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       signer->add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
+       signer->add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
+       signer->set_key (dcp::file_to_string ("test/ref/crypt/leaf.key"));
 
        shared_ptr<dcp::CPL> cpl (new dcp::CPL ("A Test DCP", dcp::FEATURE));
 
@@ -138,7 +132,7 @@ BOOST_AUTO_TEST_CASE (encryption_test)
                "2012-07-17T04:45:18+00:00"
                );
 
-       kdm.encrypt (signer, signer->certificates().leaf(), dcp::MODIFIED_TRANSITIONAL_1).as_xml ("build/test/encryption_test.kdm.xml");
+       kdm.encrypt (signer, signer->leaf(), dcp::MODIFIED_TRANSITIONAL_1).as_xml ("build/test/encryption_test.kdm.xml");
 
        int r = system (
                "xmllint --path schema --nonet --noout --schema schema/SMPTE-430-1-2006-Amd-1-2009-KDM.xsd build/test/encryption_test.kdm.xml "
index 38d1037a46992394d6d9fa1888ae1b9f3d37003c..a1f44a3eaceb8e6f54bc16053bbe2d72fe867adb 100644 (file)
@@ -20,7 +20,7 @@
 #include "certificate.h"
 #include "decrypted_kdm.h"
 #include "encrypted_kdm.h"
-#include "signer.h"
+#include "certificate_chain.h"
 #include "mono_picture_asset.h"
 #include "sound_asset.h"
 #include "reel.h"
@@ -46,7 +46,7 @@ using boost::scoped_array;
 /** Build an encrypted picture asset and a KDM for it and check that the KDM can be decrypted */
 BOOST_AUTO_TEST_CASE (round_trip_test)
 {
-       shared_ptr<dcp::Signer> signer (new dcp::Signer ("openssl"));
+       shared_ptr<dcp::CertificateChain> signer (new dcp::CertificateChain ("openssl"));
 
        boost::filesystem::path work_dir = "build/test/round_trip_test";
        boost::filesystem::create_directory (work_dir);
@@ -81,10 +81,10 @@ BOOST_AUTO_TEST_CASE (round_trip_test)
 
        boost::filesystem::path const kdm_file = work_dir / "kdm.xml";
 
-       kdm_A.encrypt(signer, signer->certificates().leaf(), dcp::MODIFIED_TRANSITIONAL_1).as_xml (kdm_file);
+       kdm_A.encrypt(signer, signer->leaf(), dcp::MODIFIED_TRANSITIONAL_1).as_xml (kdm_file);
 
        /* Reload the KDM, using our private key to decrypt it */
-       dcp::DecryptedKDM kdm_B (dcp::EncryptedKDM (dcp::file_to_string (kdm_file)), signer->key ());
+       dcp::DecryptedKDM kdm_B (dcp::EncryptedKDM (dcp::file_to_string (kdm_file)), signer->key().get ());
 
        /* Check that the decrypted KDMKeys are the same as the ones we started with */
        BOOST_CHECK_EQUAL (kdm_A.keys().size(), kdm_B.keys().size());