diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-01-11 00:25:11 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-01-11 00:25:11 +0000 |
| commit | 67cf9c95d190b1f2a67d73c0a7f712e213b6e71a (patch) | |
| tree | 5330aa403ea22459ed257ee577aaeec84053c0a4 | |
| parent | 5265670cb158bee669e62a2953b41a624d324a36 (diff) | |
Tweaks to management of crypto information.
| -rw-r--r-- | src/certificates.cc | 44 | ||||
| -rw-r--r-- | src/certificates.h | 6 | ||||
| -rw-r--r-- | src/crypt_chain.cc | 34 | ||||
| -rw-r--r-- | src/dcp.cc | 31 | ||||
| -rw-r--r-- | src/dcp.h | 51 | ||||
| -rw-r--r-- | src/wscript | 2 | ||||
| -rw-r--r-- | test/tests.cc | 43 | ||||
| -rw-r--r-- | wscript | 9 |
8 files changed, 132 insertions, 88 deletions
diff --git a/src/certificates.cc b/src/certificates.cc index 6ed32dca..c1b15c51 100644 --- a/src/certificates.cc +++ b/src/certificates.cc @@ -42,6 +42,19 @@ Certificate::Certificate (X509* c) } +Certificate::Certificate (string const & filename) + : _certificate (0) +{ + FILE* f = fopen (filename.c_str(), "r"); + if (!f) { + throw FileError ("could not open file", filename); + } + + if (!PEM_read_X509 (f, &_certificate, 0, 0)) { + throw MiscError ("could not read X509 certificate"); + } +} + Certificate::~Certificate () { X509_free (_certificate); @@ -147,32 +160,6 @@ Certificate::thumbprint () const return Kumu::base64encode (digest, 20, digest_base64, 64); } -/** @param filename Text file of PEM-format certificates, - * in the order: - * - * 1. self-signed root certificate - * 2. intermediate certificate signed by root certificate - * ... - * n. leaf certificate signed by previous intermediate. - */ - -CertificateChain::CertificateChain (string const & filename) -{ - FILE* f = fopen (filename.c_str(), "r"); - if (!f) { - throw FileError ("could not open file", filename); - } - - while (1) { - X509* c = 0; - if (!PEM_read_X509 (f, &c, 0, 0)) { - break; - } - - _certificates.push_back (shared_ptr<Certificate> (new Certificate (c))); - } -} - shared_ptr<Certificate> CertificateChain::root () const { @@ -195,3 +182,8 @@ CertificateChain::leaf_to_root () const return c; } +void +CertificateChain::add (shared_ptr<Certificate> c) +{ + _certificates.push_back (c); +} diff --git a/src/certificates.h b/src/certificates.h index db19a9db..e1a572ec 100644 --- a/src/certificates.h +++ b/src/certificates.h @@ -40,7 +40,8 @@ public: Certificate () : _certificate (0) {} - + + Certificate (std::string const &); Certificate (X509 *); ~Certificate (); @@ -61,7 +62,8 @@ class CertificateChain { public: CertificateChain () {} - CertificateChain (std::string const &); + + void add (boost::shared_ptr<Certificate>); boost::shared_ptr<Certificate> root () const; boost::shared_ptr<Certificate> leaf () const; diff --git a/src/crypt_chain.cc b/src/crypt_chain.cc index 853d8c50..d0777859 100644 --- a/src/crypt_chain.cc +++ b/src/crypt_chain.cc @@ -3,17 +3,29 @@ #include <boost/filesystem.hpp> #include <boost/algorithm/string.hpp> #include "crypt_chain.h" +#include "exceptions.h" using std::string; using std::ofstream; using std::ifstream; using std::stringstream; +using std::cout; + +static void command (char const * c) +{ + int const r = system (c); + if (WEXITSTATUS (r)) { + stringstream s; + s << "error in " << c << "\n"; + throw libdcp::MiscError (s.str()); + } +} void libdcp::make_crypt_chain (string directory) { boost::filesystem::current_path (directory); - system ("openssl genrsa -out ca.key 2048"); + command ("openssl genrsa -out ca.key 2048"); { ofstream f ("ca.cnf"); @@ -31,7 +43,7 @@ libdcp::make_crypt_chain (string directory) << "CN = Entity and dnQualifier\n"; } - system ("openssl rsa -outform PEM -pubout -in ca.key | openssl base64 -d | dd bs=1 skip=24 2>/dev/null | openssl sha1 -binary | openssl base64 > ca_dnq"); + command ("openssl rsa -outform PEM -pubout -in ca.key | openssl base64 -d | dd bs=1 skip=24 2>/dev/null | openssl sha1 -binary | openssl base64 > ca_dnq"); string ca_dnq; @@ -46,10 +58,10 @@ libdcp::make_crypt_chain (string directory) { stringstream c; c << "openssl req -new -x509 -sha256 -config ca.cnf -days 3650 -set_serial 5 -subj " << ca_subject << " -key ca.key -outform PEM -out ca.self-signed.pem"; - system (c.str().c_str()); + command (c.str().c_str()); } - system ("openssl genrsa -out intermediate.key 2048"); + command ("openssl genrsa -out intermediate.key 2048"); { ofstream f ("intermediate.cnf"); @@ -67,7 +79,7 @@ libdcp::make_crypt_chain (string directory) << "CN = Entity and dnQualifier\n"; } - system ("openssl rsa -outform PEM -pubout -in intermediate.key | openssl base64 -d | dd bs=1 skip=24 2>/dev/null | openssl sha1 -binary | openssl base64 > inter_dnq"); + command ("openssl rsa -outform PEM -pubout -in intermediate.key | openssl base64 -d | dd bs=1 skip=24 2>/dev/null | openssl sha1 -binary | openssl base64 > inter_dnq"); string inter_dnq; @@ -82,13 +94,13 @@ libdcp::make_crypt_chain (string directory) { stringstream s; s << "openssl req -new -config intermediate.cnf -days 3649 -subj " << inter_subject << " -key intermediate.key -out intermediate.csr"; - system (s.str().c_str()); + command (s.str().c_str()); } - system ("openssl x509 -req -sha256 -days 3649 -CA ca.self-signed.pem -CAkey ca.key -set_serial 6 -in intermediate.csr -extfile intermediate.cnf -extensions v3_ca -out intermediate.signed.pem"); + command ("openssl x509 -req -sha256 -days 3649 -CA ca.self-signed.pem -CAkey ca.key -set_serial 6 -in intermediate.csr -extfile intermediate.cnf -extensions v3_ca -out intermediate.signed.pem"); - system ("openssl genrsa -out leaf.key 2048"); + command ("openssl genrsa -out leaf.key 2048"); { ofstream f ("leaf.cnf"); @@ -106,7 +118,7 @@ libdcp::make_crypt_chain (string directory) << "CN = Entity and dnQualifier\n"; } - system ("openssl rsa -outform PEM -pubout -in leaf.key | openssl base64 -d | dd bs=1 skip=24 2>/dev/null | openssl sha1 -binary | openssl base64 > leaf_dnq"); + command ("openssl rsa -outform PEM -pubout -in leaf.key | openssl base64 -d | dd bs=1 skip=24 2>/dev/null | openssl sha1 -binary | openssl base64 > leaf_dnq"); string leaf_dnq; @@ -121,8 +133,8 @@ libdcp::make_crypt_chain (string directory) { stringstream s; s << "openssl req -new -config leaf.cnf -days 3648 -subj " << leaf_subject << " -key leaf.key -outform PEM -out leaf.csr"; - system (s.str().c_str()); + command (s.str().c_str()); } - system ("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"); + 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"); } @@ -54,27 +54,26 @@ using namespace libdcp; DCP::DCP (string directory) : _directory (directory) - , _encrypted (false) { boost::filesystem::create_directories (directory); } void -DCP::write_xml () const +DCP::write_xml (shared_ptr<Encryption> crypt) const { for (list<shared_ptr<const CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) { - (*i)->write_xml (_encrypted, _certificates, _signer_key); + (*i)->write_xml (crypt); } string pkl_uuid = make_uuid (); - string pkl_path = write_pkl (pkl_uuid); + string pkl_path = write_pkl (pkl_uuid, crypt); write_volindex (); write_assetmap (pkl_uuid, boost::filesystem::file_size (pkl_path)); } std::string -DCP::write_pkl (string pkl_uuid) const +DCP::write_pkl (string pkl_uuid, shared_ptr<Encryption> crypt) const { assert (!_cpls.empty ()); @@ -86,7 +85,7 @@ DCP::write_pkl (string pkl_uuid) const xmlpp::Document doc; xmlpp::Element* pkl = doc.create_root_node("PackingList", "http://www.smpte-ra.org/schemas/429-8/2007/PKL"); - if (_encrypted) { + if (crypt) { pkl->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "dsig"); } @@ -109,8 +108,8 @@ DCP::write_pkl (string pkl_uuid) const } } - if (_encrypted) { - sign (pkl, _certificates, _signer_key); + if (crypt) { + sign (pkl, crypt->certificates, crypt->signer_key); } doc.write_to_file_formatted (p.string(), "UTF-8"); @@ -435,7 +434,7 @@ CPL::add_reel (shared_ptr<const Reel> reel) } void -CPL::write_xml (bool encrypted, CertificateChain const & certificates, string const & signer_key) const +CPL::write_xml (shared_ptr<Encryption> crypt) const { boost::filesystem::path p; p /= _directory; @@ -446,7 +445,7 @@ CPL::write_xml (bool encrypted, CertificateChain const & certificates, string co xmlpp::Document doc; xmlpp::Element* cpl = doc.create_root_node("CompositionPlaylist", "http://www.smpte-ra.org/schemas/429-7/2006/CPL"); - if (encrypted) { + if (crypt) { cpl->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "dsig"); } @@ -470,8 +469,8 @@ CPL::write_xml (bool encrypted, CertificateChain const & certificates, string co (*i)->write_to_cpl (reel_list); } - if (encrypted) { - sign (cpl, certificates, signer_key); + if (crypt) { + sign (cpl, crypt->certificates, crypt->signer_key); } doc.write_to_file_formatted (p.string(), "UTF-8"); @@ -570,7 +569,13 @@ CPL::equals (CPL const & other, EqualityOptions opt, list<string>& notes) const } shared_ptr<xmlpp::Document> -CPL::make_kdm (CertificateChain const & certificates, string const & signer_key, shared_ptr<const Certificate> recipient_cert) const +CPL::make_kdm ( + CertificateChain const & certificates, + string const & signer_key, + shared_ptr<const Certificate> recipient_cert, + boost::posix_time::ptime from, + boost::posix_time::ptime until + ) const { shared_ptr<xmlpp::Document> doc (new xmlpp::Document); xmlpp::Element* root = doc->create_root_node ("DCinemaSecurityMessage"); @@ -28,6 +28,7 @@ #include <vector> #include <boost/shared_ptr.hpp> #include <boost/signals2.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> #include "types.h" #include "certificates.h" @@ -47,6 +48,18 @@ class SubtitleAsset; class Reel; class AssetMap; +class Encryption +{ +public: + Encryption (CertificateChain c, std::string const & k) + : certificates (c) + , signer_key (k) + {} + + CertificateChain certificates; + std::string signer_key; +}; + class CPL { public: @@ -87,11 +100,17 @@ public: bool equals (CPL const & other, EqualityOptions options, std::list<std::string>& notes) const; - void write_xml (bool, CertificateChain const &, std::string const &) const; + void write_xml (boost::shared_ptr<Encryption>) const; void write_to_assetmap (std::ostream& s) const; void write_to_pkl (xmlpp::Element* p) const; - boost::shared_ptr<xmlpp::Document> make_kdm (CertificateChain const &, std::string const &, boost::shared_ptr<const Certificate>) const; + boost::shared_ptr<xmlpp::Document> make_kdm ( + CertificateChain const &, + std::string const &, + boost::shared_ptr<const Certificate>, + boost::posix_time::ptime from, + boost::posix_time::ptime until + ) const; private: std::string _directory; @@ -138,7 +157,7 @@ public: /** Write the required XML files to the directory that was * passed into the constructor. */ - void write_xml () const; + void write_xml (boost::shared_ptr<Encryption> crypt = boost::shared_ptr<Encryption> ()) const; /** Compare this DCP with another, according to various options. * @param other DCP to compare this one to. @@ -154,26 +173,6 @@ public: return _cpls; } - void set_encrypted (bool e) { - _encrypted = e; - } - - void set_certificates (CertificateChain const & c) { - _certificates = c; - } - - CertificateChain certificates () const { - return _certificates; - } - - void set_signer_key (std::string const & s) { - _signer_key = s; - } - - std::string signer_key () const { - return _signer_key; - } - /** Emitted with a parameter between 0 and 1 to indicate progress * for long jobs. */ @@ -184,7 +183,7 @@ private: /** Write the PKL file. * @param pkl_uuid UUID to use. */ - std::string write_pkl (std::string pkl_uuid) const; + std::string write_pkl (std::string pkl_uuid, boost::shared_ptr<Encryption>) const; /** Write the VOLINDEX file */ void write_volindex () const; @@ -206,10 +205,6 @@ private: /** the directory that we are writing to */ std::string _directory; std::list<boost::shared_ptr<const CPL> > _cpls; - - bool _encrypted; - CertificateChain _certificates; - std::string _signer_key; }; } diff --git a/src/wscript b/src/wscript index 41ebf7a7..0922cb56 100644 --- a/src/wscript +++ b/src/wscript @@ -7,7 +7,7 @@ def build(bld): obj.name = 'libdcp' obj.target = 'dcp' obj.export_includes = ['.'] - obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 OPENSSL SIGC++ LIBXML++ OPENJPEG XMLSEC1' + obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 BOOST_DATETIME OPENSSL SIGC++ LIBXML++ OPENJPEG XMLSEC1' obj.use = 'libkumu-libdcp libasdcp-libdcp' obj.source = """ asset.cc diff --git a/test/tests.cc b/test/tests.cc index 7c3144a1..b15556c1 100644 --- a/test/tests.cc +++ b/test/tests.cc @@ -31,6 +31,7 @@ #include "sound_asset.h" #include "reel.h" #include "certificates.h" +#include "crypt_chain.h" #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE libdcp_test @@ -601,9 +602,19 @@ BOOST_AUTO_TEST_CASE (encryption) boost::filesystem::remove_all ("build/test/bar"); boost::filesystem::create_directories ("build/test/bar"); libdcp::DCP d ("build/test/bar"); - d.set_encrypted (true); - d.set_certificates (libdcp::CertificateChain ("test/data/certificate_chain")); - d.set_signer_key ("test/data/signer.key"); + + libdcp::CertificateChain chain; + chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/data/ca.self-signed.pem"))); + chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/data/intermediate.signed.pem"))); + chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/data/leaf.signed.pem"))); + + shared_ptr<libdcp::Encryption> crypt ( + new libdcp::Encryption ( + chain, + "test/data/signer.key" + ) + ); + shared_ptr<libdcp::CPL> cpl (new libdcp::CPL ("build/test/bar", "A Test DCP", libdcp::FEATURE, 24, 24)); shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ( @@ -632,16 +643,27 @@ BOOST_AUTO_TEST_CASE (encryption) cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (mp, ms, shared_ptr<libdcp::SubtitleAsset> ()))); d.add_cpl (cpl); - d.write_xml (); + d.write_xml (crypt); - cpl->make_kdm(d.certificates(), d.signer_key(), d.certificates().leaf())->write_to_file_formatted ("build/test/bar.kdm.xml", "UTF-8"); + shared_ptr<xmlpp::Document> kdm = cpl->make_kdm ( + crypt->certificates, + crypt->signer_key, + 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") + ); + + kdm->write_to_file_formatted ("build/test/bar.kdm.xml", "UTF-8"); } BOOST_AUTO_TEST_CASE (certificates) { - libdcp::CertificateChain c ("test/data/certificate_chain"); - BOOST_CHECK_EQUAL (c._certificates.size(), 3); + libdcp::CertificateChain c; + c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/data/ca.self-signed.pem"))); + c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/data/intermediate.signed.pem"))); + c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/data/leaf.signed.pem"))); + BOOST_CHECK_EQUAL ( c.root()->issuer(), "/O=example.org/OU=example.org/CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION/dnQualifier=rTeK7x+nopFkyphflooz6p2ZM7A=" @@ -659,3 +681,10 @@ BOOST_AUTO_TEST_CASE (certificates) "dnQualifier=rTeK7x\\+nopFkyphflooz6p2ZM7A=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org" ); } + +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"); +} @@ -73,6 +73,15 @@ def configure(conf): msg = 'Checking for boost signals2 library', uselib_store = 'BOOST_SIGNALS2') + conf.check_cxx(fragment = """ + #include <boost/date_time.hpp>\n + int main() { boost::gregorian::day_clock::local_day(); }\n + """, + msg = 'Checking for boost datetime library', + libpath = '/usr/local/lib', + lib = ['boost_date_time%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix], + uselib_store = 'BOOST_DATETIME') + lut.make_luts() conf.recurse('test') |
