summaryrefslogtreecommitdiff
path: root/src/kdm.cc
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-09-24 18:54:09 +0100
committerCarl Hetherington <cth@carlh.net>2013-09-24 18:54:09 +0100
commit725c1f0ead60e73e9dbc17337c416ac4d2720c55 (patch)
tree132b82fbdb44320e74289ee6400c4a39d162439e /src/kdm.cc
parentb0b83d69f38a8239f3df1e2872b6cfebf9f84af8 (diff)
Various KDM work.
Diffstat (limited to 'src/kdm.cc')
-rw-r--r--src/kdm.cc151
1 files changed, 126 insertions, 25 deletions
diff --git a/src/kdm.cc b/src/kdm.cc
index b35c34b5..9e49fcab 100644
--- a/src/kdm.cc
+++ b/src/kdm.cc
@@ -18,15 +18,22 @@
*/
#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;
@@ -39,6 +46,7 @@ using boost::shared_ptr;
using namespace libdcp;
KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
+ : xml_kdm (new xml::DCinemaSecurityMessage (kdm))
{
/* Read the private key */
@@ -53,24 +61,15 @@ KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path 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)];
@@ -87,17 +86,81 @@ KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
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)
@@ -131,6 +194,34 @@ 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
@@ -144,10 +235,10 @@ 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 */
@@ -168,7 +259,7 @@ KDMKey::get (uint8_t const ** p, int N) const
}
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;
@@ -198,12 +289,22 @@ KDMKey::put (uint8_t ** d, uint8_t const * s, int N) const
}
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)++;
}
}