2 Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
34 #include "encrypted_kdm.h"
36 #include "certificate_chain.h"
37 #include "exceptions.h"
38 #include "compose.hpp"
39 #include <libcxml/cxml.h>
40 #include <libxml++/document.h>
41 #include <libxml++/nodes/element.h>
42 #include <libxml/parser.h>
43 #include <boost/algorithm/string.hpp>
44 #include <boost/date_time/posix_time/posix_time.hpp>
45 #include <boost/foreach.hpp>
46 #include <boost/format.hpp>
53 using boost::shared_ptr;
54 using boost::optional;
55 using boost::starts_with;
60 /** Namespace for classes used to hold our data; they are internal to this .cc file */
68 explicit Signer (shared_ptr<const cxml::Node> node)
69 : x509_issuer_name (node->string_child ("X509IssuerName"))
70 , x509_serial_number (node->string_child ("X509SerialNumber"))
75 void as_xml (xmlpp::Element* node) const
77 node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
78 node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
81 string x509_issuer_name;
82 string x509_serial_number;
90 explicit X509Data (boost::shared_ptr<const cxml::Node> node)
91 : x509_issuer_serial (Signer (node->node_child ("X509IssuerSerial")))
92 , x509_certificate (node->string_child ("X509Certificate"))
97 void as_xml (xmlpp::Element* node) const
99 x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial", "ds"));
100 node->add_child("X509Certificate", "ds")->add_child_text (x509_certificate);
103 Signer x509_issuer_serial;
104 std::string x509_certificate;
112 explicit Reference (string u)
116 explicit Reference (shared_ptr<const cxml::Node> node)
117 : uri (node->string_attribute ("URI"))
118 , digest_value (node->string_child ("DigestValue"))
123 void as_xml (xmlpp::Element* node) const
125 node->set_attribute ("URI", uri);
126 node->add_child("DigestMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
127 node->add_child("DigestValue", "ds")->add_child_text (digest_value);
138 : authenticated_public ("#ID_AuthenticatedPublic")
139 , authenticated_private ("#ID_AuthenticatedPrivate")
142 explicit SignedInfo (shared_ptr<const cxml::Node> node)
144 list<shared_ptr<cxml::Node> > references = node->node_children ("Reference");
145 for (list<shared_ptr<cxml::Node> >::const_iterator i = references.begin(); i != references.end(); ++i) {
146 if ((*i)->string_attribute ("URI") == "#ID_AuthenticatedPublic") {
147 authenticated_public = Reference (*i);
148 } else if ((*i)->string_attribute ("URI") == "#ID_AuthenticatedPrivate") {
149 authenticated_private = Reference (*i);
152 /* XXX: do something if we don't recognise the node */
156 void as_xml (xmlpp::Element* node) const
158 node->add_child ("CanonicalizationMethod", "ds")->set_attribute (
159 "Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
162 node->add_child ("SignatureMethod", "ds")->set_attribute (
163 "Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
166 authenticated_public.as_xml (node->add_child ("Reference", "ds"));
167 authenticated_private.as_xml (node->add_child ("Reference", "ds"));
171 Reference authenticated_public;
172 Reference authenticated_private;
180 explicit Signature (shared_ptr<const cxml::Node> node)
181 : signed_info (node->node_child ("SignedInfo"))
182 , signature_value (node->string_child ("SignatureValue"))
184 list<shared_ptr<cxml::Node> > x509_data_nodes = node->node_child("KeyInfo")->node_children ("X509Data");
185 for (list<shared_ptr<cxml::Node> >::const_iterator i = x509_data_nodes.begin(); i != x509_data_nodes.end(); ++i) {
186 x509_data.push_back (X509Data (*i));
190 void as_xml (xmlpp::Node* node) const
192 signed_info.as_xml (node->add_child ("SignedInfo", "ds"));
193 node->add_child("SignatureValue", "ds")->add_child_text (signature_value);
195 xmlpp::Element* key_info_node = node->add_child ("KeyInfo", "ds");
196 for (std::list<X509Data>::const_iterator i = x509_data.begin(); i != x509_data.end(); ++i) {
197 i->as_xml (key_info_node->add_child ("X509Data", "ds"));
201 SignedInfo signed_info;
202 string signature_value;
203 list<X509Data> x509_data;
206 class AuthenticatedPrivate
209 AuthenticatedPrivate () {}
211 explicit AuthenticatedPrivate (shared_ptr<const cxml::Node> node)
213 list<shared_ptr<cxml::Node> > encrypted_key_nodes = node->node_children ("EncryptedKey");
214 for (list<shared_ptr<cxml::Node> >::const_iterator i = encrypted_key_nodes.begin(); i != encrypted_key_nodes.end(); ++i) {
215 encrypted_key.push_back ((*i)->node_child("CipherData")->string_child ("CipherValue"));
219 void as_xml (xmlpp::Element* node, map<string, xmlpp::Attribute *>& references) const
221 references["ID_AuthenticatedPrivate"] = node->set_attribute ("Id", "ID_AuthenticatedPrivate");
223 for (list<string>::const_iterator i = encrypted_key.begin(); i != encrypted_key.end(); ++i) {
224 xmlpp::Element* encrypted_key = node->add_child ("EncryptedKey", "enc");
225 /* XXX: hack for testing with Dolby */
226 encrypted_key->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
227 xmlpp::Element* encryption_method = encrypted_key->add_child ("EncryptionMethod", "enc");
228 encryption_method->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
229 xmlpp::Element* digest_method = encryption_method->add_child ("DigestMethod", "ds");
230 /* XXX: hack for testing with Dolby */
231 digest_method->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
232 digest_method->set_attribute ("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
233 xmlpp::Element* cipher_data = encrypted_key->add_child ("CipherData", "enc");
234 cipher_data->add_child("CipherValue", "enc")->add_child_text (*i);
238 list<string> encrypted_key;
246 explicit TypedKeyId (shared_ptr<const cxml::Node> node)
247 : key_type (node->string_child ("KeyType"))
248 , key_id (remove_urn_uuid (node->string_child ("KeyId")))
253 TypedKeyId (string type, string id)
258 void as_xml (xmlpp::Element* node) const
260 xmlpp::Element* type = node->add_child("KeyType");
261 type->add_child_text (key_type);
262 node->add_child("KeyId")->add_child_text ("urn:uuid:" + key_id);
263 /* XXX: this feels like a bit of a hack */
264 if (key_type == "MDEK") {
265 type->set_attribute ("scope", "http://www.dolby.com/cp850/2012/KDM#kdm-key-type");
267 type->set_attribute ("scope", "http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type");
280 explicit KeyIdList (shared_ptr<const cxml::Node> node)
282 list<shared_ptr<cxml::Node> > typed_key_id_nodes = node->node_children ("TypedKeyId");
283 for (list<shared_ptr<cxml::Node> >::const_iterator i = typed_key_id_nodes.begin(); i != typed_key_id_nodes.end(); ++i) {
284 typed_key_id.push_back (TypedKeyId (*i));
288 void as_xml (xmlpp::Element* node) const
290 for (list<TypedKeyId>::const_iterator i = typed_key_id.begin(); i != typed_key_id.end(); ++i) {
291 i->as_xml (node->add_child("TypedKeyId"));
295 list<TypedKeyId> typed_key_id;
298 class AuthorizedDeviceInfo
301 AuthorizedDeviceInfo () {}
303 explicit AuthorizedDeviceInfo (shared_ptr<const cxml::Node> node)
304 : device_list_identifier (remove_urn_uuid (node->string_child ("DeviceListIdentifier")))
305 , device_list_description (node->optional_string_child ("DeviceListDescription"))
307 BOOST_FOREACH (cxml::ConstNodePtr i, node->node_child("DeviceList")->node_children("CertificateThumbprint")) {
308 certificate_thumbprints.push_back (i->content ());
312 void as_xml (xmlpp::Element* node) const
314 node->add_child ("DeviceListIdentifier")->add_child_text ("urn:uuid:" + device_list_identifier);
315 if (device_list_description) {
316 node->add_child ("DeviceListDescription")->add_child_text (device_list_description.get());
318 xmlpp::Element* device_list = node->add_child ("DeviceList");
319 BOOST_FOREACH (string i, certificate_thumbprints) {
320 device_list->add_child("CertificateThumbprint")->add_child_text (i);
324 /** DeviceListIdentifier without the urn:uuid: prefix */
325 string device_list_identifier;
326 boost::optional<string> device_list_description;
327 std::list<string> certificate_thumbprints;
330 class X509IssuerSerial
333 X509IssuerSerial () {}
335 explicit X509IssuerSerial (shared_ptr<const cxml::Node> node)
336 : x509_issuer_name (node->string_child ("X509IssuerName"))
337 , x509_serial_number (node->string_child ("X509SerialNumber"))
342 void as_xml (xmlpp::Element* node) const
344 node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
345 node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
348 string x509_issuer_name;
349 string x509_serial_number;
357 explicit Recipient (shared_ptr<const cxml::Node> node)
358 : x509_issuer_serial (node->node_child ("X509IssuerSerial"))
359 , x509_subject_name (node->string_child ("X509SubjectName"))
364 void as_xml (xmlpp::Element* node) const
366 x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial"));
367 node->add_child("X509SubjectName")->add_child_text (x509_subject_name);
370 X509IssuerSerial x509_issuer_serial;
371 string x509_subject_name;
374 class KDMRequiredExtensions
377 KDMRequiredExtensions () {}
379 explicit KDMRequiredExtensions (shared_ptr<const cxml::Node> node)
380 : recipient (node->node_child ("Recipient"))
381 , composition_playlist_id (remove_urn_uuid (node->string_child ("CompositionPlaylistId")))
382 , content_title_text (node->string_child ("ContentTitleText"))
383 , not_valid_before (node->string_child ("ContentKeysNotValidBefore"))
384 , not_valid_after (node->string_child ("ContentKeysNotValidAfter"))
385 , authorized_device_info (node->node_child ("AuthorizedDeviceInfo"))
386 , key_id_list (node->node_child ("KeyIdList"))
388 disable_forensic_marking_picture = false;
389 disable_forensic_marking_audio = optional<int>();
390 if (node->optional_node_child("ForensicMarkFlagList")) {
391 BOOST_FOREACH (cxml::ConstNodePtr i, node->node_child("ForensicMarkFlagList")->node_children("ForensicMarkFlag")) {
392 if (i->content() == picture_disable) {
393 disable_forensic_marking_picture = true;
394 } else if (starts_with(i->content(), audio_disable)) {
395 disable_forensic_marking_audio = 0;
396 string const above = audio_disable + "-above-channel-";
397 if (starts_with(i->content(), above)) {
398 string above_number = i->content().substr(above.length());
399 if (above_number == "") {
400 throw KDMFormatError("Badly-formatted ForensicMarkFlag");
402 disable_forensic_marking_audio = atoi(above_number.c_str());
409 void as_xml (xmlpp::Element* node) const
411 node->set_attribute ("xmlns", "http://www.smpte-ra.org/schemas/430-1/2006/KDM");
413 recipient.as_xml (node->add_child ("Recipient"));
414 node->add_child("CompositionPlaylistId")->add_child_text ("urn:uuid:" + composition_playlist_id);
415 node->add_child("ContentTitleText")->add_child_text (content_title_text);
416 if (content_authenticator) {
417 node->add_child("ContentAuthenticator")->add_child_text (content_authenticator.get ());
419 node->add_child("ContentKeysNotValidBefore")->add_child_text (not_valid_before.as_string ());
420 node->add_child("ContentKeysNotValidAfter")->add_child_text (not_valid_after.as_string ());
421 if (authorized_device_info) {
422 authorized_device_info->as_xml (node->add_child ("AuthorizedDeviceInfo"));
424 key_id_list.as_xml (node->add_child ("KeyIdList"));
426 if (disable_forensic_marking_picture || disable_forensic_marking_audio) {
427 xmlpp::Element* forensic_mark_flag_list = node->add_child ("ForensicMarkFlagList");
428 if (disable_forensic_marking_picture) {
429 forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text(picture_disable);
431 if (disable_forensic_marking_audio) {
432 string mrkflg = audio_disable;
433 if (*disable_forensic_marking_audio > 0) {
434 mrkflg += String::compose ("-above-channel-%1", *disable_forensic_marking_audio);
436 forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text (mrkflg);
442 string composition_playlist_id;
443 boost::optional<string> content_authenticator;
444 string content_title_text;
445 LocalTime not_valid_before;
446 LocalTime not_valid_after;
447 bool disable_forensic_marking_picture;
448 optional<int> disable_forensic_marking_audio;
449 boost::optional<AuthorizedDeviceInfo> authorized_device_info;
450 KeyIdList key_id_list;
453 static const string picture_disable;
454 static const string audio_disable;
457 const string KDMRequiredExtensions::picture_disable = "http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-picture-disable";
458 const string KDMRequiredExtensions::audio_disable = "http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-audio-disable";
460 class RequiredExtensions
463 RequiredExtensions () {}
465 explicit RequiredExtensions (shared_ptr<const cxml::Node> node)
466 : kdm_required_extensions (node->node_child ("KDMRequiredExtensions"))
471 void as_xml (xmlpp::Element* node) const
473 kdm_required_extensions.as_xml (node->add_child ("KDMRequiredExtensions"));
476 KDMRequiredExtensions kdm_required_extensions;
479 class AuthenticatedPublic
482 AuthenticatedPublic ()
483 : message_id (make_uuid ())
484 /* XXX: hack for Dolby to see if there must be a not-empty annotation text */
485 , annotation_text ("none")
486 , issue_date (LocalTime().as_string ())
489 explicit AuthenticatedPublic (shared_ptr<const cxml::Node> node)
490 : message_id (remove_urn_uuid (node->string_child ("MessageId")))
491 , annotation_text (node->optional_string_child ("AnnotationText"))
492 , issue_date (node->string_child ("IssueDate"))
493 , signer (node->node_child ("Signer"))
494 , required_extensions (node->node_child ("RequiredExtensions"))
499 void as_xml (xmlpp::Element* node, map<string, xmlpp::Attribute *>& references) const
501 references["ID_AuthenticatedPublic"] = node->set_attribute ("Id", "ID_AuthenticatedPublic");
503 node->add_child("MessageId")->add_child_text ("urn:uuid:" + message_id);
504 node->add_child("MessageType")->add_child_text ("http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type");
505 if (annotation_text) {
506 node->add_child("AnnotationText")->add_child_text (annotation_text.get ());
508 node->add_child("IssueDate")->add_child_text (issue_date);
510 signer.as_xml (node->add_child ("Signer"));
511 required_extensions.as_xml (node->add_child ("RequiredExtensions"));
513 node->add_child ("NonCriticalExtensions");
517 optional<string> annotation_text;
520 RequiredExtensions required_extensions;
523 /** Class to describe our data. We use a class hierarchy as it's a bit nicer
524 * for XML data than a flat description.
526 class EncryptedKDMData
534 explicit EncryptedKDMData (shared_ptr<const cxml::Node> node)
535 : authenticated_public (node->node_child ("AuthenticatedPublic"))
536 , authenticated_private (node->node_child ("AuthenticatedPrivate"))
537 , signature (node->node_child ("Signature"))
542 shared_ptr<xmlpp::Document> as_xml () const
544 shared_ptr<xmlpp::Document> document (new xmlpp::Document ());
545 xmlpp::Element* root = document->create_root_node ("DCinemaSecurityMessage", "http://www.smpte-ra.org/schemas/430-3/2006/ETM");
546 root->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
547 root->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
548 map<string, xmlpp::Attribute *> references;
549 authenticated_public.as_xml (root->add_child ("AuthenticatedPublic"), references);
550 authenticated_private.as_xml (root->add_child ("AuthenticatedPrivate"), references);
551 signature.as_xml (root->add_child ("Signature", "ds"));
553 for (map<string, xmlpp::Attribute*>::const_iterator i = references.begin(); i != references.end(); ++i) {
554 xmlAddID (0, document->cobj(), (const xmlChar *) i->first.c_str(), i->second->cobj ());
557 indent (document->get_root_node(), 0);
561 AuthenticatedPublic authenticated_public;
562 AuthenticatedPrivate authenticated_private;
569 EncryptedKDM::EncryptedKDM (string s)
572 shared_ptr<cxml::Document> doc (new cxml::Document ("DCinemaSecurityMessage"));
573 doc->read_string (s);
574 _data = new data::EncryptedKDMData (doc);
575 } catch (xmlpp::parse_error& e) {
576 throw KDMFormatError (e.what ());
580 /** @param trusted_devices Trusted device thumbprints */
581 EncryptedKDM::EncryptedKDM (
582 shared_ptr<const CertificateChain> signer,
583 Certificate recipient,
584 vector<string> trusted_devices,
586 string content_title_text,
587 optional<string> annotation_text,
588 LocalTime not_valid_before,
589 LocalTime not_valid_after,
590 Formulation formulation,
591 bool disable_forensic_marking_picture,
592 optional<int> disable_forensic_marking_audio,
593 list<pair<string, string> > key_ids,
596 : _data (new data::EncryptedKDMData)
598 /* Fill our XML-ish description in with the juicy bits that the caller has given */
600 /* Our ideas, based on http://isdcf.com/papers/ISDCF-Doc5-kdm-certs.pdf, about the KDM types are:
602 * Type Trusted-device thumb ContentAuthenticator
603 * MODIFIED_TRANSITIONAL_1 assume-trust No
604 * MULTIPLE_MODIFIED_TRANSITIONAL_1 as specified No
605 * DCI_ANY assume-trust Yes
606 * DCI_SPECIFIC as specified Yes
609 data::AuthenticatedPublic& aup = _data->authenticated_public;
610 aup.signer.x509_issuer_name = signer->leaf().issuer ();
611 aup.signer.x509_serial_number = signer->leaf().serial ();
612 aup.annotation_text = annotation_text;
614 data::KDMRequiredExtensions& kre = _data->authenticated_public.required_extensions.kdm_required_extensions;
615 kre.recipient.x509_issuer_serial.x509_issuer_name = recipient.issuer ();
616 kre.recipient.x509_issuer_serial.x509_serial_number = recipient.serial ();
617 kre.recipient.x509_subject_name = recipient.subject ();
618 kre.composition_playlist_id = cpl_id;
619 if (formulation == DCI_ANY || formulation == DCI_SPECIFIC) {
620 kre.content_authenticator = signer->leaf().thumbprint ();
622 kre.content_title_text = content_title_text;
623 kre.not_valid_before = not_valid_before;
624 kre.not_valid_after = not_valid_after;
625 kre.disable_forensic_marking_picture = disable_forensic_marking_picture;
626 kre.disable_forensic_marking_audio = disable_forensic_marking_audio;
628 if (formulation != MODIFIED_TRANSITIONAL_TEST) {
629 kre.authorized_device_info = data::AuthorizedDeviceInfo ();
630 kre.authorized_device_info->device_list_identifier = make_uuid ();
631 string n = recipient.subject_common_name ();
632 if (n.find (".") != string::npos) {
633 n = n.substr (n.find (".") + 1);
635 kre.authorized_device_info->device_list_description = n;
637 if (formulation == MODIFIED_TRANSITIONAL_1 || formulation == DCI_ANY) {
638 /* Use the "assume trust" thumbprint */
639 kre.authorized_device_info->certificate_thumbprints.push_back ("2jmj7l5rSw0yVb/vlWAYkK/YBwk=");
640 } else if (formulation == MULTIPLE_MODIFIED_TRANSITIONAL_1 || formulation == DCI_SPECIFIC) {
641 if (trusted_devices.empty ()) {
642 /* Fall back on the "assume trust" thumbprint so we
643 can generate "modified-transitional-1" KDMs
644 together with "multiple-modified-transitional-1"
645 KDMs in one go, and similarly for "dci-any" etc.
647 kre.authorized_device_info->certificate_thumbprints.push_back ("2jmj7l5rSw0yVb/vlWAYkK/YBwk=");
649 /* As I read the standard we should use the
650 recipient /and/ other trusted device thumbprints
651 here. MJD reports that this doesn't work with
652 his setup; a working KDM does not include the
653 recipient's thumbprint (recipient.thumbprint()).
654 Waimea uses only the trusted devices here, too.
656 BOOST_FOREACH (string i, trusted_devices) {
657 kre.authorized_device_info->certificate_thumbprints.push_back (i);
663 for (list<pair<string, string> >::const_iterator i = key_ids.begin(); i != key_ids.end(); ++i) {
664 kre.key_id_list.typed_key_id.push_back (data::TypedKeyId (i->first, i->second));
667 _data->authenticated_private.encrypted_key = keys;
669 /* Read the XML so far and sign it */
670 shared_ptr<xmlpp::Document> doc = _data->as_xml ();
671 xmlpp::Node::NodeList children = doc->get_root_node()->get_children ();
672 for (xmlpp::Node::NodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
673 if ((*i)->get_name() == "Signature") {
674 signer->add_signature_value (dynamic_cast<xmlpp::Element*>(*i), "ds", false);
678 /* Read the bits that add_signature_value did back into our variables */
679 shared_ptr<cxml::Node> signed_doc (new cxml::Node (doc->get_root_node ()));
680 _data->signature = data::Signature (signed_doc->node_child ("Signature"));
683 EncryptedKDM::EncryptedKDM (EncryptedKDM const & other)
684 : _data (new data::EncryptedKDMData (*other._data))
690 EncryptedKDM::operator= (EncryptedKDM const & other)
692 if (this == &other) {
697 _data = new data::EncryptedKDMData (*other._data);
701 EncryptedKDM::~EncryptedKDM ()
707 EncryptedKDM::as_xml (boost::filesystem::path path) const
709 FILE* f = fopen_boost (path, "w");
710 string const x = as_xml ();
711 fwrite (x.c_str(), 1, x.length(), f);
716 EncryptedKDM::as_xml () const
718 return _data->as_xml()->write_to_string ("UTF-8");
722 EncryptedKDM::keys () const
724 return _data->authenticated_private.encrypted_key;
728 EncryptedKDM::id () const
730 return _data->authenticated_public.message_id;
734 EncryptedKDM::annotation_text () const
736 return _data->authenticated_public.annotation_text;
740 EncryptedKDM::content_title_text () const
742 return _data->authenticated_public.required_extensions.kdm_required_extensions.content_title_text;
746 EncryptedKDM::cpl_id () const
748 return _data->authenticated_public.required_extensions.kdm_required_extensions.composition_playlist_id;
752 EncryptedKDM::issue_date () const
754 return _data->authenticated_public.issue_date;
758 EncryptedKDM::not_valid_before () const
760 return _data->authenticated_public.required_extensions.kdm_required_extensions.not_valid_before;
764 EncryptedKDM::not_valid_after () const
766 return _data->authenticated_public.required_extensions.kdm_required_extensions.not_valid_after;
770 EncryptedKDM::recipient_x509_subject_name () const
772 return _data->authenticated_public.required_extensions.kdm_required_extensions.recipient.x509_subject_name;
776 EncryptedKDM::signer_certificate_chain () const
778 CertificateChain chain;
779 BOOST_FOREACH (data::X509Data const & i, _data->signature.x509_data) {
780 string s = "-----BEGIN CERTIFICATE-----\n" + i.x509_certificate + "\n-----END CERTIFICATE-----";
781 chain.add (Certificate(s));
787 dcp::operator== (EncryptedKDM const & a, EncryptedKDM const & b)
789 /* Not exactly efficient... */
790 return a.as_xml() == b.as_xml();