return true;
}
-shared_ptr<xmlpp::Document>
-CPL::make_kdm (
- shared_ptr<const Signer> signer,
- shared_ptr<const Certificate> recipient_cert,
- boost::posix_time::ptime from,
- boost::posix_time::ptime until,
- bool interop,
- MXFMetadata const & mxf_metadata,
- XMLMetadata const & xml_metadata
- ) const
-{
- assert (recipient_cert);
-
- shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
- xmlpp::Element* root = doc->create_root_node ("DCinemaSecurityMessage");
- root->set_namespace_declaration ("http://www.smpte-ra.org/schemas/430-3/2006/ETM", "");
- root->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
- root->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
-
- {
- xmlpp::Element* authenticated_public = root->add_child("AuthenticatedPublic");
- authenticated_public->set_attribute("Id", "ID_AuthenticatedPublic");
- xmlAddID (0, doc->cobj(), (const xmlChar *) "ID_AuthenticatedPublic", authenticated_public->get_attribute("Id")->cobj());
-
- authenticated_public->add_child("MessageId")->add_child_text ("urn:uuid:" + make_uuid());
- /* XXX: this should probably be different if interop == true */
- authenticated_public->add_child("MessageType")->add_child_text ("http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type");
- authenticated_public->add_child("AnnotationText")->add_child_text (mxf_metadata.product_name);
- authenticated_public->add_child("IssueDate")->add_child_text (xml_metadata.issue_date);
-
- {
- xmlpp::Element* xml_signer = authenticated_public->add_child("Signer");
- xml_signer->add_child("X509IssuerName", "ds")->add_child_text (signer->certificates().leaf()->issuer());
- xml_signer->add_child("X509SerialNumber", "ds")->add_child_text (signer->certificates().leaf()->serial());
- }
-
- {
- xmlpp::Element* required_extensions = authenticated_public->add_child("RequiredExtensions");
-
- {
- xmlpp::Element* kdm_required_extensions = required_extensions->add_child("KDMRequiredExtensions");
- kdm_required_extensions->set_namespace_declaration ("http://www.smpte-ra.org/schemas/430-1/2006/KDM");
- {
- xmlpp::Element* recipient = kdm_required_extensions->add_child("Recipient");
- {
- xmlpp::Element* serial_element = recipient->add_child("X509IssuerSerial");
- serial_element->add_child("X509IssuerName", "ds")->add_child_text (recipient_cert->issuer());
- serial_element->add_child("X509SerialNumber", "ds")->add_child_text (recipient_cert->serial());
- }
-
- recipient->add_child("X509SubjectName")->add_child_text (recipient_cert->subject());
- }
-
- 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(signer->certificates().leaf()->thumbprint());
- 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");
- authorized_device_info->add_child("DeviceListIdentifier")->add_child_text("urn:uuid:" + make_uuid());
- authorized_device_info->add_child("DeviceListDescription")->add_child_text(recipient_cert->subject());
- {
- xmlpp::Element* device_list = authorized_device_info->add_child("DeviceList");
- device_list->add_child("CertificateThumbprint")->add_child_text(recipient_cert->thumbprint());
- }
- }
-
- {
- xmlpp::Element* key_id_list = kdm_required_extensions->add_child("KeyIdList");
- list<shared_ptr<const Asset> > a = assets();
- for (list<shared_ptr<const Asset> >::iterator i = a.begin(); i != a.end(); ++i) {
- /* XXX: non-MXF assets? */
- shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
- if (mxf) {
- mxf->add_typed_key_id (key_id_list);
- }
- }
- }
-
- {
- xmlpp::Element* forensic_mark_flag_list = kdm_required_extensions->add_child("ForensicMarkFlagList");
- forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text (
- "http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-picture-disable"
- );
- forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text (
- "http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-audio-disable"
- );
- }
- }
- }
-
- authenticated_public->add_child("NonCriticalExtensions");
- }
-
- {
- xmlpp::Element* authenticated_private = root->add_child("AuthenticatedPrivate");
- authenticated_private->set_attribute ("Id", "ID_AuthenticatedPrivate");
- xmlAddID (0, doc->cobj(), (const xmlChar *) "ID_AuthenticatedPrivate", authenticated_private->get_attribute("Id")->cobj());
-
- list<shared_ptr<const Asset> > a = assets();
- for (list<shared_ptr<const Asset> >::iterator i = a.begin(); i != a.end(); ++i) {
- /* XXX: non-MXF assets? */
- shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
- if (!mxf) {
- continue;
- }
-
- xmlpp::Element* encrypted_key = authenticated_private->add_child ("EncryptedKey", "enc");
- xmlpp::Element* encryption_method = encrypted_key->add_child ("EncryptionMethod", "enc");
- encryption_method->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
- encryption_method->add_child("DigestMethod", "ds")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
- xmlpp::Element* cipher_data = encrypted_key->add_child ("CipherData", "enc");
-
- KDMKey kkey (signer, _id, mxf->key_id (), from, until, mxf->key ());
- cipher_data->add_child("CipherValue", "enc")->add_child_text (kkey.base64 ());
- }
- }
-
- {
- xmlpp::Element* signature = root->add_child("Signature", "ds");
-
- {
- xmlpp::Element* signed_info = signature->add_child("SignedInfo", "ds");
- signed_info->add_child("CanonicalizationMethod", "ds")->set_attribute(
- "Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
- );
-
- if (interop) {
- signed_info->add_child("SignatureMethod", "ds")->set_attribute(
- "Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
- );
- } else {
- signed_info->add_child("SignatureMethod", "ds")->set_attribute(
- "Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
- );
- }
-
- {
- xmlpp::Element* reference = signed_info->add_child("Reference", "ds");
- reference->set_attribute("URI", "#ID_AuthenticatedPublic");
- reference->add_child("DigestMethod", "ds")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
- reference->add_child("DigestValue", "ds");
- }
-
- {
- xmlpp::Element* reference = signed_info->add_child("Reference", "ds");
- reference->set_attribute("URI", "#ID_AuthenticatedPrivate");
- reference->add_child("DigestMethod", "ds")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
- reference->add_child("DigestValue", "ds");
- }
- }
-
- signer->add_signature_value (signature, "ds");
- }
-
- return doc;
-}
-
/** @return true if we have any encrypted content */
bool
CPL::encrypted () const
void write_to_assetmap (xmlpp::Node *) const;
void write_to_pkl (xmlpp::Node *) const;
- /** Make a KDM for this CPL.
- * @param signer Details of the certificates and 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 which is used to encrypt the content keys.
- * @param from Time that the KDM should be valid from.
- * @param until Time that the KDM should be valid until.
- * @param interop true to generate an interop KDM, false for SMPTE.
- */
- boost::shared_ptr<xmlpp::Document> make_kdm (
- boost::shared_ptr<const Signer> signer,
- boost::shared_ptr<const Certificate> recipient_cert,
- boost::posix_time::ptime from,
- boost::posix_time::ptime until,
- bool interop,
- MXFMetadata const &,
- XMLMetadata const &
- ) const;
-
void add_kdm (KDM const &);
private:
*/
#include <iomanip>
+#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <libcxml/cxml.h>
+#include "AS_DCP.h"
+#include "KM_util.h"
#include "util.h"
#include "kdm.h"
#include "compose.hpp"
#include "exceptions.h"
+#include "signer.h"
+#include "cpl.h"
+#include "mxf_asset.h"
+#include "xml/kdm_smpte.h"
using std::list;
using std::string;
using namespace libdcp;
KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
+ : xml_kdm (new xml::DCinemaSecurityMessage (kdm))
{
/* Read the private key */
throw FileError ("could not read RSA private key file", private_key);
}
-
- /* Read the KDM, decrypting it */
-
- cxml::Document f ("DCinemaSecurityMessage");
- f.read_file (kdm.string ());
-
- shared_ptr<cxml::Node> authenticated_private = f.node_child ("AuthenticatedPrivate");
- list<shared_ptr<cxml::Node> > encrypted_keys = authenticated_private->node_children ("EncryptedKey");
+ /* Use it to decrypt the keys */
- for (list<shared_ptr<cxml::Node> >::iterator i = encrypted_keys.begin(); i != encrypted_keys.end(); ++i) {
+ list<string> encrypted_keys = xml_kdm->authenticated_private.encrypted_keys;
- /* Get the base-64-encoded cipher value from the KDM */
- shared_ptr<cxml::Node> cipher_data = (*i)->node_child ("CipherData");
- shared_ptr<cxml::Node> cipher_value_base64 = cipher_data->node_child ("CipherValue");
+ for (list<string>::iterator i = encrypted_keys.begin(); i != encrypted_keys.end(); ++i) {
- /* Decode it from base-64 */
+ /* Decode the base-64-encoded cipher value from the KDM */
unsigned char cipher_value[256];
- int const cipher_value_len = base64_decode (cipher_value_base64->content(), cipher_value, sizeof (cipher_value));
+ int const cipher_value_len = base64_decode (*i, cipher_value, sizeof (cipher_value));
/* Decrypt it */
unsigned char* decrypted = new unsigned char[RSA_size(rsa)];
RSA_free (rsa);
}
+KDM::KDM (
+ shared_ptr<const CPL> cpl, shared_ptr<const Signer> signer, shared_ptr<const Certificate> recipient_cert,
+ boost::posix_time::ptime not_valid_before, boost::posix_time::ptime not_valid_after,
+ MXFMetadata mxf_metadata, XMLMetadata xml_metadata
+ )
+ : xml_kdm (new xml::DCinemaSecurityMessage)
+{
+ xml::AuthenticatedPublic& apu = xml_kdm->authenticated_public;
+
+ /* AuthenticatedPublic */
+
+ apu.message_type = "urn:uuid:" + make_uuid ();
+ apu.annotation_text = mxf_metadata.product_name;
+ apu.issue_date = xml_metadata.issue_date;
+ apu.signer.x509_issuer_name = signer->certificates().leaf()->issuer ();
+ apu.signer.x509_serial_number = signer->certificates().leaf()->serial ();
+ apu.recipient.x509_issuer_serial.x509_issuer_name = recipient_cert->issuer ();
+ apu.recipient.x509_issuer_serial.x509_serial_number = recipient_cert->serial ();
+ apu.recipient.x509_subject_name = recipient_cert->subject ();
+ apu.composition_playlist_id = "urn:uuid:" + cpl->id ();
+ apu.content_title_text = cpl->name ();
+ apu.content_keys_not_valid_before = ptime_to_string (not_valid_before);
+ apu.content_keys_not_valid_after = ptime_to_string (not_valid_after);
+ apu.authorized_device_info.device_list_identifier = "urn:uuid:" + make_uuid ();
+ apu.authorized_device_info.device_list_description = recipient_cert->subject ();
+ apu.authorized_device_info.device_list.push_back (recipient_cert->thumbprint ());
+
+ list<shared_ptr<const Asset> > assets = cpl->assets ();
+ for (list<shared_ptr<const Asset> >::iterator i = assets.begin(); i != assets.end(); ++i) {
+ /* XXX: non-MXF assets? */
+ shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
+ if (mxf) {
+ apu.key_id_list.push_back (xml::TypedKeyId (mxf->key_type(), "urn:uuid:" + mxf->key_id()));
+ }
+ }
+
+ apu.forensic_mark_flag_list.push_back ("http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-picture-disable");
+ apu.forensic_mark_flag_list.push_back ("http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-audio-disable");
+
+ /* AuthenticatedPrivate */
+
+ for (list<shared_ptr<const Asset> >::iterator i = assets.begin(); i != assets.end(); ++i) {
+ /* XXX: non-MXF assets? */
+ shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
+ if (mxf) {
+ xml_kdm->authenticated_private.encrypted_keys.push_back (
+ KDMKey (signer, cpl->id (), mxf->key_id (), not_valid_before, not_valid_after, mxf->key().get()).base64 ()
+ );
+ }
+ }
+
+ /* Signature */
+
+ shared_ptr<xmlpp::Document> doc = xml_kdm->as_xml ();
+ shared_ptr<cxml::Node> root (new cxml::Node (doc->get_root_node ()));
+ xmlpp::Node* signature = root->node_child("Signature")->node();
+ signer->add_signature_value (signature, "ds");
+ xml_kdm->signature = xml::Signature (shared_ptr<cxml::Node> (new cxml::Node (signature)));
+}
+
+void
+KDM::as_xml (boost::filesystem::path path) const
+{
+ shared_ptr<xmlpp::Document> doc = xml_kdm->as_xml ();
+ doc->write_to_file_formatted (path.string(), "UTF-8");
+}
+
KDMKey::KDMKey (shared_ptr<const Signer> signer, string cpl_id, string key_id, boost::posix_time::ptime from, boost::posix_time::ptime until, Key key)
: _cpl_id (cpl_id)
- , _key_id (key_id),
+ , _key_id (key_id)
, _not_valid_before (ptime_to_string (from))
, _not_valid_after (ptime_to_string (until))
, _key (key)
{
- /* Magic value specified by SMPTE S430-1-2006 */
- _structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
-
- base64_decode (signer->certificates()->leaf()->thumbprint (), _signer_thumbprint, 20);
+ base64_decode (signer->certificates().leaf()->thumbprint (), _signer_thumbprint, 20);
}
KDMKey::KDMKey (uint8_t const * raw, int len)
}
}
+KDMKey::KDMKey (KDMKey const & other)
+ : _cpl_id (other._cpl_id)
+ , _key_type (other._key_type)
+ , _key_id (other._key_id)
+ , _not_valid_before (other._not_valid_before)
+ , _not_valid_after (other._not_valid_after)
+ , _key (other._key)
+{
+ memcpy (_signer_thumbprint, other._signer_thumbprint, 20);
+}
+
+KDMKey &
+KDMKey::operator= (KDMKey const & other)
+{
+ if (&other == this) {
+ return *this;
+ }
+
+ _cpl_id = other._cpl_id;
+ _key_type = other._key_type;
+ _key_id = other._key_id;
+ _not_valid_before = other._not_valid_before;
+ _not_valid_after = other._not_valid_after;
+ _key = other._key;
+ memcpy (_signer_thumbprint, other._signer_thumbprint, 20);
+
+ return *this;
+}
string
KDMKey::base64 () const
put (&p, structure_id, 16);
put (&p, _signer_thumbprint, 20);
put_uuid (&p, _cpl_id);
- put (&p, _key_type, 4);
+ put (&p, _key_type);
put_uuid (&p, _key_id);
- put (&p, _not_valid_before.c_str(), 25);
- put (&p, _not_valid_after.c_str(), 25);
+ put (&p, _not_valid_before);
+ put (&p, _not_valid_after);
put (&p, _key.value(), ASDCP::KeyLen);
/* Lazy overallocation */
}
void
-KDMKey::get (uint8_t const * o, uint8_t const ** p, int N) const
+KDMKey::get (uint8_t* o, uint8_t const ** p, int N) const
{
memcpy (o, *p, N);
*p += N;
(*d) += N;
}
+void
+KDMKey::put (uint8_t ** d, string s) const
+{
+ memcpy (*d, s.c_str(), s.length());
+ (*d) += s.length();
+}
+
void
KDMKey::put_uuid (uint8_t ** d, string id) const
{
- id.erase (id.remove (id.begin(), id.end(), "-"));
+ id.erase (std::remove (id.begin(), id.end(), '-'));
for (int i = 0; i < 32; i += 2) {
stringstream s;
s << id[i] << id[i + 1];
- s >> *d++;
+ int h;
+ s >> h;
+ **d = h;
+ (*d)++;
}
}
#define LIBDCP_KDM_H
#include <boost/filesystem.hpp>
+#include <boost/scoped_ptr.hpp>
#include "key.h"
+#include "metadata.h"
namespace libdcp {
+namespace xml {
+ class DCinemaSecurityMessage;
+};
+
+class Signer;
+class Certificate;
+class CPL;
+
/** A single key for encrypting or decrypting an MXF. One or more of these
* are delivered in a KDM.
*/
-class KDMKey : public boost::noncopyable
+class KDMKey
{
public:
KDMKey (uint8_t const *, int);
+ KDMKey (
+ boost::shared_ptr<const Signer> signer,
+ std::string cpl_id, std::string key_id, boost::posix_time::ptime from, boost::posix_time::ptime until, Key key
+ );
+
+ KDMKey (KDMKey const &);
+
+ KDMKey& operator= (KDMKey const &);
+
+ std::string cpl_id () const {
+ return _cpl_id;
+ }
+
+ std::string key_id () const {
+ return _key_id;
+ }
+
+ std::string not_valid_before () const {
+ return _not_valid_before;
+ }
+
+ std::string not_valid_after () const {
+ return _not_valid_after;
+ }
+
Key key () const {
return _key;
}
+
+ std::string base64 () const;
private:
void get (uint8_t *, uint8_t const **, int) const;
std::string get (uint8_t const **, int) const;
std::string get_uuid (uint8_t const **) const;
void put (uint8_t **, uint8_t const *, int) const;
+ void put (uint8_t **, std::string) const;
void put_uuid (uint8_t **, std::string) const;
uint8_t _signer_thumbprint[20];
std::string _cpl_id;
- std::string _not_valid_before;
- std::string _not_valid_after;
std::string _key_type;
std::string _key_id;
+ std::string _not_valid_before;
+ std::string _not_valid_after;
Key _key;
};
public:
KDM (boost::filesystem::path, boost::filesystem::path);
+ KDM (
+ boost::shared_ptr<const CPL> cpl, boost::shared_ptr<const Signer>, boost::shared_ptr<const Certificate> recipient_cert,
+ boost::posix_time::ptime not_valid_before, boost::posix_time::ptime not_valid_after,
+ MXFMetadata mxf_metadata, XMLMetadata xml_metadata
+ );
+
std::list<KDMKey> keys () const {
return _keys;
}
+ void as_xml (boost::filesystem::path) const;
+
private:
+ std::string _message_id;
std::list<KDMKey> _keys;
+
+ boost::shared_ptr<xml::DCinemaSecurityMessage> xml_kdm;
};
return true;
}
-void
-MXFAsset::add_typed_key_id (xmlpp::Element* parent) const
-{
- xmlpp::Element* typed_key_id = parent->add_child("TypedKeyId");
- typed_key_id->add_child("KeyType")->add_child_text(key_type ());
- typed_key_id->add_child("KeyId")->add_child_text("urn:uuid:" + _key_id);
-}
-
void
MXFAsset::write_to_cpl (xmlpp::Element* node, bool interop) const
{
*/
void fill_writer_info (ASDCP::WriterInfo* w, std::string uuid, bool interop, MXFMetadata const & metadata);
- void add_typed_key_id (xmlpp::Element *) const;
-
bool encrypted () const {
return !_key_id.empty ();
}
ASDCP::AESEncContext* encryption_context () const {
return _encryption_context;
}
+
+ virtual std::string key_type () const = 0;
protected:
- virtual std::string key_type () const = 0;
virtual std::string cpl_node_name () const = 0;
virtual std::pair<std::string, std::string> cpl_node_attribute (bool) const {
return std::make_pair ("", "");
#include <xmlsec/xmldsig.h>
#include <xmlsec/dl.h>
#include <xmlsec/app.h>
+#include <libcxml/cxml.h>
#include "signer.h"
#include "exceptions.h"
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 (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");
- }
+ 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 (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. This function takes a certificate chain (to prove that the sender is bona fide) and
- * a private key with which to sign the node.
+/** Sign an XML 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
-Signer::add_signature_value (xmlpp::Element* parent, string ns) const
+Signer::add_signature_value (xmlpp::Node* parent, string ns) const
{
- parent->add_child("SignatureValue", ns);
+ cxml::Node cp (parent);
+ xmlpp::Node* key_info = cp.node_child("KeyInfo")->node ();
- /* Add the certificate chain to a KeyInfo child node of parent */
- xmlpp::Element* key_info = parent->add_child("KeyInfo", ns);
+ /* Add the certificate chain to the KeyInfo child node of parent */
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", ns);
{}
void sign (xmlpp::Element* parent, bool interop) const;
- void add_signature_value (xmlpp::Element* parent, std::string ns) const;
+ void add_signature_value (xmlpp::Node* parent, std::string ns) const;
CertificateChain const & certificates () const {
return _certificates;
+from waflib import TaskGen
+
def build(bld):
if bld.env.STATIC:
obj = bld(features = 'cxx cxxstlib')
parse/cpl.cc
parse/pkl.cc
parse/subtitle.cc
+ xml/kdm_smpte.cc
"""
headers = """
bld.install_files('${PREFIX}/include/libdcp', headers)
if bld.env.STATIC:
bld.install_files('${PREFIX}/lib', 'libdcp.a')
-
*/
+#include <libxml/parser.h>
#include <libxml++/libxml++.h>
#include <libcxml/cxml.h>
#include "kdm_smpte.h"
+#include "../exceptions.h"
+#include "../util.h"
using std::list;
using std::string;
using boost::shared_ptr;
using namespace libdcp::xml;
+Writer::Writer ()
+ : document (new xmlpp::Document)
+{
+
+}
+
DCinemaSecurityMessage::DCinemaSecurityMessage (boost::filesystem::path file)
{
cxml::Document f ("DCinemaSecurityMessage");
f.done ();
}
-void
-DCinemaSecurityMessage::as_xml (boost::filesystem::path file) const
+shared_ptr<xmlpp::Document>
+DCinemaSecurityMessage::as_xml () const
{
- xmlpp::Document doc;
- xmlpp::Element* root = doc.create_root_node ("DCinemaSecurityMessage", "http://www.smpte-ra.org/schemas/430-3/2006/ETM");
+ Writer writer;
+
+ xmlpp::Element* root = writer.document->create_root_node ("DCinemaSecurityMessage", "http://www.smpte-ra.org/schemas/430-3/2006/ETM");
root->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
root->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
- authenticated_public.as_xml (root->add_child ("AuthenticatedPublic"));
- authenticated_private.as_xml (root->add_child ("AuthenticatedPrivate"));
- signature.as_xml (root->add_child ("Signature", "ds"));
+ authenticated_public.as_xml (writer, root->add_child ("AuthenticatedPublic"));
+ authenticated_private.as_xml (writer, root->add_child ("AuthenticatedPrivate"));
+ signature.as_xml (writer, root->add_child ("Signature", "ds"));
+
+ return writer.document;
+}
+
+AuthenticatedPublic::AuthenticatedPublic ()
+ : message_id ("urn:uuid:" + make_uuid ())
+{
- doc.write_to_file_formatted (file.string (), "UTF-8");
}
AuthenticatedPublic::AuthenticatedPublic (shared_ptr<const cxml::Node> node)
key_id_list.push_back (TypedKeyId (*i));
}
- list<shared_ptr<cxml::Node> > fmf = c->node_child("ForensicMarkFlagList")->node_children("ForensicMarkFlag");
- for (list<shared_ptr<cxml::Node> >::iterator i = fmf.begin(); i != fmf.end(); ++i) {
- forensic_mark_flag_list.push_back ((*i)->content ());
+ shared_ptr<cxml::Node> fmfl = c->optional_node_child("ForensicMarkFlagList");
+ if (fmfl) {
+ list<shared_ptr<cxml::Node> > fmf = fmfl->node_children("ForensicMarkFlag");
+ for (list<shared_ptr<cxml::Node> >::iterator i = fmf.begin(); i != fmf.end(); ++i) {
+ forensic_mark_flag_list.push_back ((*i)->content ());
+ }
}
node->ignore_child ("NonCriticalExtensions");
}
void
-AuthenticatedPublic::as_xml (xmlpp::Element* node) const
+AuthenticatedPublic::as_xml (Writer& writer, xmlpp::Element* node) const
{
- node->set_attribute ("Id", "ID_AuthenticatedPublic");
+ writer.references["ID_AuthenticatedPublic"] = node->set_attribute ("Id", "ID_AuthenticatedPublic");
node->add_child("MessageId")->add_child_text (message_id);
node->add_child("MessageType")->add_child_text (message_type);
}
void
-AuthenticatedPrivate::as_xml (xmlpp::Element* node) const
+AuthenticatedPrivate::as_xml (Writer& writer, xmlpp::Element* node) const
{
- node->set_attribute ("Id", "ID_AuthenticatedPrivate");
+ writer.references["ID_AuthenticatedPrivate"] = node->set_attribute ("Id", "ID_AuthenticatedPrivate");
for (list<string>::const_iterator i = encrypted_keys.begin(); i != encrypted_keys.end(); ++i) {
xmlpp::Element* encrypted_key = node->add_child ("EncryptedKey", "enc");
{
list<shared_ptr<cxml::Node> > refs = node->node_child("SignedInfo")->node_children ("Reference");
for (list<shared_ptr<cxml::Node> >::const_iterator i = refs.begin(); i != refs.end(); ++i) {
- signed_info.push_back (Reference (*i));
+ if ((*i)->string_attribute("URI") == "#ID_AuthenticatedPublic") {
+ authenticated_public = Reference (*i);
+ } else if ((*i)->string_attribute("URI") == "#ID_AuthenticatedPrivate") {
+ authenticated_private = Reference (*i);
+ } else {
+ throw XMLError ("unrecognised reference URI");
+ }
}
list<shared_ptr<cxml::Node> > data = node->node_child("KeyInfo")->node_children ("X509Data");
node->done ();
}
+Signature::Signature ()
+ : authenticated_public ("#ID_AuthenticatedPublic")
+ , authenticated_private ("#ID_AuthenticatedPrivate")
+{
+
+}
+
void
-Signature::as_xml (xmlpp::Element* node) const
+Signature::as_xml (Writer& writer, xmlpp::Element* node) const
{
xmlpp::Element* si = node->add_child ("SignedInfo", "ds");
si->add_child ("CanonicalizationMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
si->add_child ("SignatureMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
- for (list<Reference>::const_iterator i = signed_info.begin(); i != signed_info.end(); ++i) {
- i->as_xml (si);
- }
+
+ authenticated_public.as_xml (writer, si);
+ authenticated_private.as_xml (writer, si);
node->add_child("SignatureValue", "ds")->add_child_text (signature_value);
}
void
-Reference::as_xml (xmlpp::Element* node) const
+Reference::as_xml (Writer& writer, xmlpp::Element* node) const
{
xmlpp::Element* reference = node->add_child ("Reference", "ds");
reference->set_attribute ("URI", uri);
reference->add_child("DigestMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
reference->add_child("DigestValue", "ds")->add_child_text (digest_value);
+
+ if (!uri.empty ()) {
+ xmlAddID (0, writer.document->cobj(), (const xmlChar *) uri.substr(1).c_str(), writer.references[uri.substr(1)]->cobj ());
+ }
}
X509Data::X509Data (shared_ptr<const cxml::Node> node)
#include <boost/filesystem.hpp>
namespace libdcp {
-namespace xml {
+namespace xml {
+
+class Writer
+{
+public:
+ Writer ();
+
+ boost::shared_ptr<xmlpp::Document> document;
+ std::map<std::string, xmlpp::Attribute *> references;
+};
class Signer
{
{
public:
TypedKeyId () {}
+
+ TypedKeyId (std::string t, std::string i)
+ : key_type (t)
+ , key_id (i)
+ {}
+
TypedKeyId (boost::shared_ptr<const cxml::Node>);
void as_xml (xmlpp::Element *) const;
class AuthenticatedPublic
{
public:
- AuthenticatedPublic () {}
+ AuthenticatedPublic ();
AuthenticatedPublic (boost::shared_ptr<const cxml::Node>);
- void as_xml (xmlpp::Element *) const;
+ void as_xml (Writer &, xmlpp::Element *) const;
std::string message_id;
std::string message_type;
AuthenticatedPrivate () {}
AuthenticatedPrivate (boost::shared_ptr<const cxml::Node>);
- void as_xml (xmlpp::Element *) const;
+ void as_xml (Writer &, xmlpp::Element *) const;
std::list<std::string> encrypted_keys;
};
{
public:
Reference () {}
+ Reference (std::string u)
+ : uri (u)
+ {}
+
Reference (boost::shared_ptr<const cxml::Node>);
- void as_xml (xmlpp::Element *) const;
+ void as_xml (Writer& writer, xmlpp::Element *) const;
std::string uri;
std::string digest_value;
class Signature
{
public:
- Signature () {}
+ Signature ();
Signature (boost::shared_ptr<const cxml::Node>);
- void as_xml (xmlpp::Element *) const;
-
- std::list<Reference> signed_info;
+ void as_xml (Writer &, xmlpp::Element *) const;
+
+ Reference authenticated_public;
+ Reference authenticated_private;
std::string signature_value;
std::list<X509Data> key_info;
};
class DCinemaSecurityMessage
{
public:
+ DCinemaSecurityMessage () {}
DCinemaSecurityMessage (boost::filesystem::path);
- void as_xml (boost::filesystem::path) const;
+ boost::shared_ptr<xmlpp::Document> as_xml () const;
AuthenticatedPublic authenticated_public;
AuthenticatedPrivate authenticated_private;
*/
+#include "kdm.h"
+
/* Load a certificate chain from build/test/data/ *.pem and then build
an encrypted DCP and a KDM using it.
*/
d.write_xml (false, xml_metadata, signer);
- shared_ptr<xmlpp::Document> kdm = cpl->make_kdm (
+ libdcp::KDM kdm (
+ cpl,
signer,
signer->certificates().leaf(),
- key,
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
);
- kdm->write_to_file_formatted ("build/test/bar.kdm.xml", "UTF-8");
+ kdm.as_xml ("build/test/bar.kdm.xml");
system ("xmllint --path schema --nonet --noout --schema schema/SMPTE-430-1-2006-Amd-1-2009-KDM.xsd build/test/bar.kdm.xml");
}
"test/data/kdm_TONEPLATES-SMPTE-ENC_.smpte-430-2.ROOT.NOT_FOR_PRODUCTION_20130706_20230702_CAR_OV_t1_8971c838.xml"
);
- kdm.as_xml ("build/kdm.xml");
+ shared_ptr<xmlpp::Document> doc = kdm.as_xml ();
+ doc->write_to_file_formatted ("build/kdm.xml", "UTF-8");
int const r = system (
"xmldiff -c test/data/kdm_TONEPLATES-SMPTE-ENC_.smpte-430-2.ROOT.NOT_FOR_PRODUCTION_20130706_20230702_CAR_OV_t1_8971c838.xml build/kdm.xml"
);