From 781982ea9a78f88fef130dc08cd028b7e5f47937 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 18 Sep 2013 18:46:58 +0100 Subject: [PATCH] A few encryption-related fixes and comments. --- src/cpl.cc | 6 ++-- src/cpl.h | 5 ++-- src/crypt_chain.cc | 4 +++ src/encryption.h | 7 +++-- src/exceptions.h | 10 ++++--- src/util.cc | 66 +++++++++++++++++++++++++++++++---------- src/util.h | 7 +++-- test/encryption_test.cc | 13 ++++---- test/tests.cc | 14 ++++----- 9 files changed, 90 insertions(+), 42 deletions(-) diff --git a/src/cpl.cc b/src/cpl.cc index bd29573a..d70bee25 100644 --- a/src/cpl.cc +++ b/src/cpl.cc @@ -347,7 +347,7 @@ CPL::equals (CPL const & other, EqualityOptions opt, boost::function CPL::make_kdm ( CertificateChain const & certificates, - string const & signer_key, + boost::filesystem::path signer_key, shared_ptr recipient_cert, boost::posix_time::ptime from, boost::posix_time::ptime until, @@ -401,8 +401,8 @@ CPL::make_kdm ( kdm_required_extensions->add_child("CompositionPlaylistId")->add_child_text("urn:uuid:" + _id); kdm_required_extensions->add_child("ContentTitleText")->add_child_text(_name); kdm_required_extensions->add_child("ContentAuthenticator")->add_child_text(certificates.leaf()->thumbprint()); - kdm_required_extensions->add_child("ContentKeysNotValidBefore")->add_child_text("XXX"); - kdm_required_extensions->add_child("ContentKeysNotValidAfter")->add_child_text("XXX"); + kdm_required_extensions->add_child("ContentKeysNotValidBefore")->add_child_text(ptime_to_string (from)); + kdm_required_extensions->add_child("ContentKeysNotValidAfter")->add_child_text(ptime_to_string (until)); { xmlpp::Element* authorized_device_info = kdm_required_extensions->add_child("AuthorizedDeviceInfo"); diff --git a/src/cpl.h b/src/cpl.h index d3b4e544..aa07036d 100644 --- a/src/cpl.h +++ b/src/cpl.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "types.h" #include "certificates.h" @@ -96,7 +97,7 @@ public: /** Make a KDM for this CPL. * @param certificates - * @param signer_key + * @param signer_key Filename of private key to sign the KDM with. * @param recipient_cert The certificate of the projector that this KDM is targeted at. This will contain the * projector's public key (P) which is used to encrypt the content keys. * @param from Time that the KDM should be valid from. @@ -105,7 +106,7 @@ public: */ boost::shared_ptr make_kdm ( CertificateChain const & certificates, - std::string const & signer_key, + boost::filesystem::path signer_key, boost::shared_ptr recipient_cert, boost::posix_time::ptime from, boost::posix_time::ptime until, diff --git a/src/crypt_chain.cc b/src/crypt_chain.cc index d495c970..2737f12c 100644 --- a/src/crypt_chain.cc +++ b/src/crypt_chain.cc @@ -47,6 +47,8 @@ static void command (char const * c) void libdcp::make_crypt_chain (boost::filesystem::path directory) { + boost::filesystem::path const cwd = boost::filesystem::current_path (); + boost::filesystem::current_path (directory); command ("openssl genrsa -out ca.key 2048"); @@ -161,4 +163,6 @@ libdcp::make_crypt_chain (boost::filesystem::path directory) } command ("openssl x509 -req -sha256 -days 3648 -CA intermediate.signed.pem -CAkey intermediate.key -set_serial 7 -in leaf.csr -extfile leaf.cnf -extensions v3_ca -out leaf.signed.pem"); + + boost::filesystem::current_path (cwd); } diff --git a/src/encryption.h b/src/encryption.h index f143f0df..b6d79b19 100644 --- a/src/encryption.h +++ b/src/encryption.h @@ -17,7 +17,7 @@ */ -#include +#include #include "certificates.h" namespace libdcp { @@ -25,13 +25,14 @@ namespace libdcp { class Encryption { public: - Encryption (CertificateChain c, std::string const & k) + Encryption (CertificateChain c, boost::filesystem::path k) : certificates (c) , signer_key (k) {} CertificateChain certificates; - std::string signer_key; + /** Filename of signer key */ + boost::filesystem::path signer_key; }; } diff --git a/src/exceptions.h b/src/exceptions.h index 4c53a66d..de744812 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -20,6 +20,8 @@ #ifndef LIBDCP_EXCEPTIONS_H #define LIBDCP_EXCEPTIONS_H +#include + /** @file src/exceptions.h * @brief Exceptions thrown by libdcp. */ @@ -31,7 +33,7 @@ namespace libdcp class FileError : public std::exception { public: - FileError (std::string const & message, std::string const & filename) + FileError (std::string const & message, boost::filesystem::path filename) : _message (message) , _filename (filename) {} @@ -44,7 +46,7 @@ public: } /** @return filename of file that was involved */ - std::string filename () const { + boost::filesystem::path filename () const { return _filename; } @@ -52,14 +54,14 @@ private: /** error message */ std::string _message; /** filename of file that was involved */ - std::string _filename; + boost::filesystem::path _filename; }; /** @brief An exception related to an MXF file */ class MXFFileError : public FileError { public: - MXFFileError (std::string const & message, std::string const & filename) + MXFFileError (std::string const & message, boost::filesystem::path filename) : FileError (message, filename) {} }; diff --git a/src/util.cc b/src/util.cc index 4035ffd1..f2728a38 100644 --- a/src/util.cc +++ b/src/util.cc @@ -239,13 +239,36 @@ libdcp::init () if (xmlSecInit() < 0) { throw MiscError ("could not initialise xmlsec"); } + +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) { + throw MiscError ("unable to load default xmlsec-crypto library"); + } +#endif + + if (xmlSecCryptoAppInit(0) < 0) { + throw MiscError ("could not initialise crypto"); + } + + if (xmlSecCryptoInit() < 0) { + throw MiscError ("could not initialise xmlsec-crypto"); + } } +/** Sign an XML node. This function takes a certificate chain (to prove that the sender is bona fide) and + * a private key with which to sign the node. + * + * @param parent Node to sign. + * @param certificates Certificate chain for the signer. + * @param signer_key Filename of the private key of the signer. + * @param ns Namespace to use for the signature XML nodes. + */ void -libdcp::add_signature_value (xmlpp::Element* parent, CertificateChain const & certificates, string const & signer_key, string const & ns) +libdcp::add_signature_value (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, string const & ns) { parent->add_child("SignatureValue", ns); - + + /* Add the certificate chain to a KeyInfo child node of parent */ xmlpp::Element* key_info = parent->add_child("KeyInfo", ns); list > c = certificates.leaf_to_root (); for (list >::iterator i = c.begin(); i != c.end(); ++i) { @@ -260,23 +283,26 @@ libdcp::add_signature_value (xmlpp::Element* parent, CertificateChain const & ce data->add_child("X509Certificate", ns)->add_child_text((*i)->certificate()); } - xmlSecKeysMngrPtr keys_manager = xmlSecKeysMngrCreate(); - if (!keys_manager) { - throw MiscError ("could not create keys manager"); + xmlSecDSigCtxPtr signature_context = xmlSecDSigCtxCreate (0); + if (signature_context == 0) { + throw MiscError ("could not create signature context"); } - - xmlSecDSigCtx signature_context; - - if (xmlSecDSigCtxInitialize (&signature_context, keys_manager) < 0) { - throw MiscError ("could not initialise XMLSEC context"); + + signature_context->signKey = xmlSecCryptoAppKeyLoad (signer_key.c_str(), xmlSecKeyDataFormatPem, 0, 0, 0); + if (signature_context->signKey == 0) { + throw FileError ("could not load private key file", signer_key); } - - if (xmlSecDSigCtxSign (&signature_context, parent->cobj()) < 0) { + + /* XXX: set key name to the file name: is this right? */ + if (xmlSecKeySetName (signature_context->signKey, reinterpret_cast (signer_key.c_str())) < 0) { + throw MiscError ("could not set key name"); + } + + if (xmlSecDSigCtxSign (signature_context, parent->cobj ()) < 0) { throw MiscError ("could not sign"); } - - xmlSecDSigCtxFinalize (&signature_context); - xmlSecKeysMngrDestroy (keys_manager); + + xmlSecDSigCtxDestroy (signature_context); } @@ -298,8 +324,9 @@ libdcp::add_signer (xmlpp::Element* parent, CertificateChain const & certificate } } +/** @param signer_key Filename of private key to sign with */ void -libdcp::sign (xmlpp::Element* parent, CertificateChain const & certificates, string const & signer_key, bool interop) +libdcp::sign (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, bool interop) { add_signer (parent, certificates, "dsig"); @@ -412,3 +439,10 @@ libdcp::utc_offset_to_string (int b) o << setw(2) << setfill('0') << hours << ":" << setw(2) << setfill('0') << minutes; return o.str (); } + +string +libdcp::ptime_to_string (boost::posix_time::ptime t) +{ + struct tm t_tm = boost::posix_time::to_tm (t); + return tm_to_string (&t_tm); +} diff --git a/src/util.h b/src/util.h index 80015593..4f590198 100644 --- a/src/util.h +++ b/src/util.h @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include "types.h" @@ -69,14 +71,15 @@ extern boost::shared_ptr decompress_j2k (uint8_t* data, int64_t size, extern void init (); -extern void sign (xmlpp::Element* parent, CertificateChain const & certificates, std::string const & signer_key, bool interop); -extern void add_signature_value (xmlpp::Element* parent, CertificateChain const & certificates, std::string const & signer_key, std::string const & ns); +extern void sign (xmlpp::Element* parent, CertificateChain const & certificates, boost::filesystem::path signer_key, bool interop); +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 std::string tm_to_string (struct tm *); extern std::string utc_offset_to_string (int); +extern std::string ptime_to_string (boost::posix_time::ptime); } diff --git a/test/encryption_test.cc b/test/encryption_test.cc index eb32afaa..0df798f2 100644 --- a/test/encryption_test.cc +++ b/test/encryption_test.cc @@ -17,7 +17,7 @@ */ -/* Load a certificate chain from build/test/data/*.pem and then build +/* Load a certificate chain from build/test/data/ *.pem and then build an encrypted DCP and a KDM using it. */ BOOST_AUTO_TEST_CASE (encryption) @@ -39,9 +39,9 @@ BOOST_AUTO_TEST_CASE (encryption) libdcp::DCP d ("build/test/DCP/bar"); libdcp::CertificateChain chain; - chain.add (shared_ptr (new libdcp::Certificate ("build/test/data/ca.self-signed.pem"))); - chain.add (shared_ptr (new libdcp::Certificate ("build/test/data/intermediate.signed.pem"))); - chain.add (shared_ptr (new libdcp::Certificate ("build/test/data/leaf.signed.pem"))); + chain.add (shared_ptr (new libdcp::Certificate ("build/test/crypt/ca.self-signed.pem"))); + chain.add (shared_ptr (new libdcp::Certificate ("build/test/crypt/intermediate.signed.pem"))); + chain.add (shared_ptr (new libdcp::Certificate ("build/test/crypt/leaf.signed.pem"))); shared_ptr crypt ( new libdcp::Encryption ( @@ -61,6 +61,7 @@ BOOST_AUTO_TEST_CASE (encryption) 24, true, libdcp::Size (32, 32), + false, mxf_metadata )); @@ -73,13 +74,14 @@ BOOST_AUTO_TEST_CASE (encryption) 24, 2, true, + false, mxf_metadata )); cpl->add_reel (shared_ptr (new libdcp::Reel (mp, ms, shared_ptr ()))); d.add_cpl (cpl); - d.write_xml (xml_metadata, crypt); + d.write_xml (false, xml_metadata, crypt); shared_ptr kdm = cpl->make_kdm ( crypt->certificates, @@ -87,6 +89,7 @@ BOOST_AUTO_TEST_CASE (encryption) crypt->certificates.leaf(), boost::posix_time::time_from_string ("2013-01-01 00:00:00"), boost::posix_time::time_from_string ("2013-01-08 00:00:00"), + false, mxf_metadata, xml_metadata ); diff --git a/test/tests.cc b/test/tests.cc index 2543d025..42198abd 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -84,11 +84,11 @@ static string test_corpus = "../libdcp-test"; #include "recovery_test.cc" #include "certificates_test.cc" -//BOOST_AUTO_TEST_CASE (crypt_chain) -//{ -// boost::filesystem::remove_all ("build/test/crypt"); -// boost::filesystem::create_directory ("build/test/crypt"); -// libdcp::make_crypt_chain ("build/test/crypt"); -//} +BOOST_AUTO_TEST_CASE (crypt_chain) +{ + boost::filesystem::remove_all ("build/test/crypt"); + boost::filesystem::create_directory ("build/test/crypt"); + libdcp::make_crypt_chain ("build/test/crypt"); +} -//#include "encryption_test.cc" +#include "encryption_test.cc" -- 2.30.2