Merge remote-tracking branch 'origin/main' into v1.9.x
[libdcp.git] / src / encrypted_kdm.cc
index d7326e89f70ad51e23105c83580f050e3a6a5e4c..d1089c0be8d2eab62aba039e7b69c836d89ab597 100644 (file)
     files in the program, then also delete it here.
 */
 
-#include "encrypted_kdm.h"
-#include "util.h"
+
+/** @file  src/encrypted_kdm.cc
+ *  @brief EncryptedKDM class
+ */
+
+
 #include "certificate_chain.h"
-#include "exceptions.h"
 #include "compose.hpp"
+#include "encrypted_kdm.h"
+#include "exceptions.h"
+#include "file.h"
+#include "util.h"
 #include <libcxml/cxml.h>
+#include <libxml++/attributenode.h>
 #include <libxml++/document.h>
 #include <libxml++/nodes/element.h>
 #include <libxml/parser.h>
@@ -44,6 +52,7 @@
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/format.hpp>
 
+
 using std::list;
 using std::vector;
 using std::string;
@@ -55,11 +64,14 @@ using boost::optional;
 using boost::starts_with;
 using namespace dcp;
 
+
 namespace dcp {
 
+
 /** Namespace for classes used to hold our data; they are internal to this .cc file */
 namespace data {
 
+
 class Signer
 {
 public:
@@ -74,14 +86,15 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
-               node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
+               cxml::add_child(node, "X509IssuerName", string("ds"))->add_child_text(x509_issuer_name);
+               cxml::add_child(node, "X509SerialNumber", string("ds"))->add_child_text(x509_serial_number);
        }
 
        string x509_issuer_name;
        string x509_serial_number;
 };
 
+
 class X509Data
 {
 public:
@@ -96,14 +109,15 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial", "ds"));
-               node->add_child("X509Certificate", "ds")->add_child_text (x509_certificate);
+               x509_issuer_serial.as_xml(cxml::add_child(node, "X509IssuerSerial", string("ds")));
+               cxml::add_child(node, "X509Certificate", string("ds"))->add_child_text(x509_certificate);
        }
 
        Signer x509_issuer_serial;
        std::string x509_certificate;
 };
 
+
 class Reference
 {
 public:
@@ -123,14 +137,15 @@ public:
        void as_xml (xmlpp::Element* node) const
        {
                node->set_attribute ("URI", uri);
-               node->add_child("DigestMethod", "ds")->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
-               node->add_child("DigestValue", "ds")->add_child_text (digest_value);
+               cxml::add_child(node, "DigestMethod", string("ds"))->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");
+               cxml::add_child(node, "DigestValue", string("ds"))->add_child_text(digest_value);
        }
 
        string uri;
        string digest_value;
 };
 
+
 class SignedInfo
 {
 public:
@@ -154,16 +169,16 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               node->add_child ("CanonicalizationMethod", "ds")->set_attribute (
+               cxml::add_child(node, "CanonicalizationMethod", string("ds"))->set_attribute(
                        "Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"
                        );
 
-               node->add_child ("SignatureMethod", "ds")->set_attribute (
+               cxml::add_child(node, "SignatureMethod", string("ds"))->set_attribute(
                        "Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
                        );
 
-               authenticated_public.as_xml (node->add_child ("Reference", "ds"));
-               authenticated_private.as_xml (node->add_child ("Reference", "ds"));
+               authenticated_public.as_xml(cxml::add_child(node, "Reference", string("ds")));
+               authenticated_private.as_xml(cxml::add_child(node, "Reference", string("ds")));
        }
 
 private:
@@ -171,6 +186,7 @@ private:
        Reference authenticated_private;
 };
 
+
 class Signature
 {
 public:
@@ -185,14 +201,14 @@ public:
                }
        }
 
-       void as_xml (xmlpp::Node* node) const
+       void as_xml(xmlpp::Element* element) const
        {
-               signed_info.as_xml (node->add_child ("SignedInfo", "ds"));
-               node->add_child("SignatureValue", "ds")->add_child_text (signature_value);
+               signed_info.as_xml(cxml::add_child(element, "SignedInfo", string("ds")));
+               cxml::add_child(element, "SignatureValue", string("ds"))->add_child_text(signature_value);
 
-               auto key_info_node = node->add_child("KeyInfo", "ds");
+               auto key_info_node = cxml::add_child(element, "KeyInfo", string("ds"));
                for (auto i: x509_data) {
-                       i.as_xml (key_info_node->add_child("X509Data", "ds"));
+                       i.as_xml(cxml::add_child(key_info_node, "X509Data", string("ds")));
                }
        }
 
@@ -201,6 +217,7 @@ public:
        vector<X509Data> x509_data;
 };
 
+
 class AuthenticatedPrivate
 {
 public:
@@ -213,28 +230,29 @@ public:
                }
        }
 
-       void as_xml (xmlpp::Element* node, map<string, xmlpp::Attribute *>& references) const
+       void as_xml (xmlpp::Element* node, map<string, xmlpp::AttributeNode*>& references) const
        {
-               references["ID_AuthenticatedPrivate"] = node->set_attribute ("Id", "ID_AuthenticatedPrivate");
+               references["ID_AuthenticatedPrivate"] = dynamic_cast<xmlpp::AttributeNode*>(node->set_attribute("Id", "ID_AuthenticatedPrivate"));
 
                for (auto i: encrypted_key) {
-                       auto encrypted_key = node->add_child ("EncryptedKey", "enc");
+                       auto encrypted_key = cxml::add_child(node, "EncryptedKey", string("enc"));
                        /* XXX: hack for testing with Dolby */
                        encrypted_key->set_namespace_declaration ("http://www.w3.org/2001/04/xmlenc#", "enc");
-                       auto encryption_method = encrypted_key->add_child("EncryptionMethod", "enc");
+                       auto encryption_method = cxml::add_child(encrypted_key, "EncryptionMethod", string("enc"));
                        encryption_method->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
-                       auto digest_method = encryption_method->add_child ("DigestMethod", "ds");
+                       auto digest_method = cxml::add_child(encryption_method, "DigestMethod", string("ds"));
                        /* XXX: hack for testing with Dolby */
                        digest_method->set_namespace_declaration ("http://www.w3.org/2000/09/xmldsig#", "ds");
                        digest_method->set_attribute ("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
-                       auto cipher_data = encrypted_key->add_child("CipherData", "enc");
-                       cipher_data->add_child("CipherValue", "enc")->add_child_text (i);
+                       auto cipher_data = cxml::add_child(encrypted_key, "CipherData", string("enc"));
+                       cxml::add_child(cipher_data, "CipherValue", string("enc"))->add_child_text(i);
                }
        }
 
        vector<string> encrypted_key;
 };
 
+
 class TypedKeyId
 {
 public:
@@ -254,9 +272,9 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               xmlpp::Element* type = node->add_child("KeyType");
+               auto type = cxml::add_child(node, "KeyType");
                type->add_child_text (key_type);
-               node->add_child("KeyId")->add_child_text ("urn:uuid:" + key_id);
+               cxml::add_text_child(node, "KeyId", "urn:uuid:" + key_id);
                /* XXX: this feels like a bit of a hack */
                if (key_type == "MDEK") {
                        type->set_attribute ("scope", "http://www.dolby.com/cp850/2012/KDM#kdm-key-type");
@@ -269,6 +287,7 @@ public:
        string key_id;
 };
 
+
 class KeyIdList
 {
 public:
@@ -284,13 +303,14 @@ public:
        void as_xml (xmlpp::Element* node) const
        {
                for (auto const& i: typed_key_id) {
-                       i.as_xml (node->add_child("TypedKeyId"));
+                       i.as_xml(cxml::add_child(node, ("TypedKeyId")));
                }
        }
 
        vector<TypedKeyId> typed_key_id;
 };
 
+
 class AuthorizedDeviceInfo
 {
 public:
@@ -307,13 +327,13 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               node->add_child ("DeviceListIdentifier")->add_child_text ("urn:uuid:" + device_list_identifier);
+               cxml::add_text_child(node, "DeviceListIdentifier", "urn:uuid:" + device_list_identifier);
                if (device_list_description) {
-                       node->add_child ("DeviceListDescription")->add_child_text (device_list_description.get());
+                       cxml::add_text_child(node, "DeviceListDescription", device_list_description.get());
                }
-               auto device_list = node->add_child ("DeviceList");
+               auto device_list = cxml::add_child(node, "DeviceList");
                for (auto i: certificate_thumbprints) {
-                       device_list->add_child("CertificateThumbprint")->add_child_text (i);
+                       cxml::add_text_child(device_list, "CertificateThumbprint", i);
                }
        }
 
@@ -323,6 +343,7 @@ public:
        std::vector<string> certificate_thumbprints;
 };
 
+
 class X509IssuerSerial
 {
 public:
@@ -337,14 +358,15 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               node->add_child("X509IssuerName", "ds")->add_child_text (x509_issuer_name);
-               node->add_child("X509SerialNumber", "ds")->add_child_text (x509_serial_number);
+               cxml::add_child(node, "X509IssuerName", string("ds"))->add_child_text(x509_issuer_name);
+               cxml::add_child(node, "X509SerialNumber", string("ds"))->add_child_text(x509_serial_number);
        }
 
        string x509_issuer_name;
        string x509_serial_number;
 };
 
+
 class Recipient
 {
 public:
@@ -359,14 +381,15 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               x509_issuer_serial.as_xml (node->add_child ("X509IssuerSerial"));
-               node->add_child("X509SubjectName")->add_child_text (x509_subject_name);
+               x509_issuer_serial.as_xml(cxml::add_child(node, "X509IssuerSerial"));
+               cxml::add_text_child(node, "X509SubjectName", x509_subject_name);
        }
 
        X509IssuerSerial x509_issuer_serial;
        string x509_subject_name;
 };
 
+
 class KDMRequiredExtensions
 {
 public:
@@ -406,30 +429,30 @@ public:
        {
                node->set_attribute ("xmlns", "http://www.smpte-ra.org/schemas/430-1/2006/KDM");
 
-               recipient.as_xml (node->add_child ("Recipient"));
-               node->add_child("CompositionPlaylistId")->add_child_text ("urn:uuid:" + composition_playlist_id);
-               node->add_child("ContentTitleText")->add_child_text (content_title_text);
+               recipient.as_xml(cxml::add_child(node, "Recipient"));
+               cxml::add_text_child(node, "CompositionPlaylistId", "urn:uuid:" + composition_playlist_id);
+               cxml::add_text_child(node, "ContentTitleText", content_title_text);
                if (content_authenticator) {
-                       node->add_child("ContentAuthenticator")->add_child_text (content_authenticator.get ());
+                       cxml::add_text_child(node, "ContentAuthenticator", content_authenticator.get());
                }
-               node->add_child("ContentKeysNotValidBefore")->add_child_text (not_valid_before.as_string ());
-               node->add_child("ContentKeysNotValidAfter")->add_child_text (not_valid_after.as_string ());
+               cxml::add_text_child(node, "ContentKeysNotValidBefore", not_valid_before.as_string());
+               cxml::add_text_child(node, "ContentKeysNotValidAfter", not_valid_after.as_string());
                if (authorized_device_info) {
-                       authorized_device_info->as_xml (node->add_child ("AuthorizedDeviceInfo"));
+                       authorized_device_info->as_xml(cxml::add_child(node, "AuthorizedDeviceInfo"));
                }
-               key_id_list.as_xml (node->add_child ("KeyIdList"));
+               key_id_list.as_xml(cxml::add_child(node, "KeyIdList"));
 
                if (disable_forensic_marking_picture || disable_forensic_marking_audio) {
-                       auto forensic_mark_flag_list = node->add_child ("ForensicMarkFlagList");
+                       auto forensic_mark_flag_list = cxml::add_child(node, "ForensicMarkFlagList");
                        if (disable_forensic_marking_picture) {
-                               forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text(picture_disable);
+                               cxml::add_text_child(forensic_mark_flag_list, "ForensicMarkFlag", picture_disable);
                        }
                        if (disable_forensic_marking_audio) {
                                auto mrkflg = audio_disable;
                                if (*disable_forensic_marking_audio > 0) {
                                        mrkflg += String::compose ("-above-channel-%1", *disable_forensic_marking_audio);
                                }
-                               forensic_mark_flag_list->add_child("ForensicMarkFlag")->add_child_text (mrkflg);
+                               cxml::add_text_child(forensic_mark_flag_list, "ForensicMarkFlag", mrkflg);
                        }
                }
        }
@@ -450,9 +473,11 @@ private:
        static const string audio_disable;
 };
 
+
 const string KDMRequiredExtensions::picture_disable = "http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-picture-disable";
 const string KDMRequiredExtensions::audio_disable = "http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-audio-disable";
 
+
 class RequiredExtensions
 {
 public:
@@ -466,12 +491,13 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               kdm_required_extensions.as_xml (node->add_child ("KDMRequiredExtensions"));
+               kdm_required_extensions.as_xml(cxml::add_child(node, "KDMRequiredExtensions"));
        }
 
        KDMRequiredExtensions kdm_required_extensions;
 };
 
+
 class AuthenticatedPublic
 {
 public:
@@ -492,21 +518,21 @@ public:
 
        }
 
-       void as_xml (xmlpp::Element* node, map<string, xmlpp::Attribute *>& references) const
+       void as_xml (xmlpp::Element* node, map<string, xmlpp::AttributeNode*>& references) const
        {
-               references["ID_AuthenticatedPublic"] = node->set_attribute ("Id", "ID_AuthenticatedPublic");
+               references["ID_AuthenticatedPublic"] = dynamic_cast<xmlpp::AttributeNode*>(node->set_attribute("Id", "ID_AuthenticatedPublic"));
 
-               node->add_child("MessageId")->add_child_text ("urn:uuid:" + message_id);
-               node->add_child("MessageType")->add_child_text ("http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type");
+               cxml::add_text_child(node, "MessageId", "urn:uuid:" + message_id);
+               cxml::add_text_child(node, "MessageType", "http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type");
                if (annotation_text) {
-                       node->add_child("AnnotationText")->add_child_text (annotation_text.get ());
+                       cxml::add_text_child(node, "AnnotationText", annotation_text.get());
                }
-               node->add_child("IssueDate")->add_child_text (issue_date);
+               cxml::add_text_child(node, "IssueDate", issue_date);
 
-               signer.as_xml (node->add_child ("Signer"));
-               required_extensions.as_xml (node->add_child ("RequiredExtensions"));
+               signer.as_xml(cxml::add_child(node, "Signer"));
+               required_extensions.as_xml(cxml::add_child(node, "RequiredExtensions"));
 
-               node->add_child ("NonCriticalExtensions");
+               cxml::add_child(node, "NonCriticalExtensions");
        }
 
        string message_id;
@@ -516,6 +542,7 @@ public:
        RequiredExtensions required_extensions;
 };
 
+
 /** Class to describe our data.  We use a class hierarchy as it's a bit nicer
  *  for XML data than a flat description.
  */
@@ -537,14 +564,14 @@ public:
 
        shared_ptr<xmlpp::Document> as_xml () const
        {
-               shared_ptr<xmlpp::Document> document (new xmlpp::Document ());
-               xmlpp::Element* root = document->create_root_node ("DCinemaSecurityMessage", "http://www.smpte-ra.org/schemas/430-3/2006/ETM");
+               auto document = make_shared<xmlpp::Document>();
+               auto root = 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");
-               map<string, xmlpp::Attribute *> references;
-               authenticated_public.as_xml (root->add_child ("AuthenticatedPublic"), references);
-               authenticated_private.as_xml (root->add_child ("AuthenticatedPrivate"), references);
-               signature.as_xml (root->add_child ("Signature", "ds"));
+               map<string, xmlpp::AttributeNode*> references;
+               authenticated_public.as_xml(cxml::add_child(root, "AuthenticatedPublic"), references);
+               authenticated_private.as_xml(cxml::add_child(root, "AuthenticatedPrivate"), references);
+               signature.as_xml(cxml::add_child(root, "Signature", string("ds")));
 
                for (auto i: references) {
                        xmlAddID (0, document->cobj(), (const xmlChar *) i.first.c_str(), i.second->cobj());
@@ -559,9 +586,11 @@ public:
        Signature signature;
 };
 
+
 }
 }
 
+
 EncryptedKDM::EncryptedKDM (string s)
 {
        try {
@@ -570,10 +599,14 @@ EncryptedKDM::EncryptedKDM (string s)
                _data = new data::EncryptedKDMData (doc);
        } catch (xmlpp::parse_error& e) {
                throw KDMFormatError (e.what ());
+       } catch (xmlpp::internal_error& e) {
+               throw KDMFormatError(e.what());
+       } catch (cxml::Error& e) {
+               throw KDMFormatError(e.what());
        }
 }
 
-/** @param trusted_devices Trusted device thumbprints */
+
 EncryptedKDM::EncryptedKDM (
        shared_ptr<const CertificateChain> signer,
        Certificate recipient,
@@ -602,7 +635,7 @@ EncryptedKDM::EncryptedKDM (
         * DCI_SPECIFIC                       as specified          Yes
         */
 
-       data::AuthenticatedPublic& aup = _data->authenticated_public;
+       auto& aup = _data->authenticated_public;
        aup.signer.x509_issuer_name = signer->leaf().issuer ();
        aup.signer.x509_serial_number = signer->leaf().serial ();
        aup.annotation_text = annotation_text;
@@ -621,37 +654,35 @@ EncryptedKDM::EncryptedKDM (
        kre.disable_forensic_marking_picture = disable_forensic_marking_picture;
        kre.disable_forensic_marking_audio = disable_forensic_marking_audio;
 
-       if (formulation != Formulation::MODIFIED_TRANSITIONAL_TEST) {
-               kre.authorized_device_info = data::AuthorizedDeviceInfo ();
-               kre.authorized_device_info->device_list_identifier = make_uuid ();
-               auto n = recipient.subject_common_name ();
-               if (n.find (".") != string::npos) {
-                       n = n.substr (n.find (".") + 1);
-               }
-               kre.authorized_device_info->device_list_description = n;
-
-               if (formulation == Formulation::MODIFIED_TRANSITIONAL_1 || formulation == Formulation::DCI_ANY) {
-                       /* Use the "assume trust" thumbprint */
+       kre.authorized_device_info = data::AuthorizedDeviceInfo ();
+       kre.authorized_device_info->device_list_identifier = make_uuid ();
+       auto n = recipient.subject_common_name ();
+       if (n.find (".") != string::npos) {
+               n = n.substr (n.find (".") + 1);
+       }
+       kre.authorized_device_info->device_list_description = n;
+
+       if (formulation == Formulation::MODIFIED_TRANSITIONAL_1 || formulation == Formulation::DCI_ANY) {
+               /* Use the "assume trust" thumbprint */
+               kre.authorized_device_info->certificate_thumbprints.push_back ("2jmj7l5rSw0yVb/vlWAYkK/YBwk=");
+       } else if (formulation == Formulation::MULTIPLE_MODIFIED_TRANSITIONAL_1 || formulation == Formulation::DCI_SPECIFIC) {
+               if (trusted_devices.empty ()) {
+                       /* Fall back on the "assume trust" thumbprint so we
+                          can generate "modified-transitional-1" KDMs
+                          together with "multiple-modified-transitional-1"
+                          KDMs in one go, and similarly for "dci-any" etc.
+                       */
                        kre.authorized_device_info->certificate_thumbprints.push_back ("2jmj7l5rSw0yVb/vlWAYkK/YBwk=");
-               } else if (formulation == Formulation::MULTIPLE_MODIFIED_TRANSITIONAL_1 || formulation == Formulation::DCI_SPECIFIC) {
-                       if (trusted_devices.empty ()) {
-                               /* Fall back on the "assume trust" thumbprint so we
-                                  can generate "modified-transitional-1" KDMs
-                                  together with "multiple-modified-transitional-1"
-                                  KDMs in one go, and similarly for "dci-any" etc.
-                               */
-                               kre.authorized_device_info->certificate_thumbprints.push_back ("2jmj7l5rSw0yVb/vlWAYkK/YBwk=");
-                       } else {
-                               /* As I read the standard we should use the
-                                  recipient /and/ other trusted device thumbprints
-                                  here. MJD reports that this doesn't work with
-                                  his setup; a working KDM does not include the
-                                  recipient's thumbprint (recipient.thumbprint()).
-                                  Waimea uses only the trusted devices here, too.
-                               */
-                               for (auto i: trusted_devices) {
-                                       kre.authorized_device_info->certificate_thumbprints.push_back(i);
-                               }
+               } else {
+                       /* As I read the standard we should use the
+                          recipient /and/ other trusted device thumbprints
+                          here. MJD reports that this doesn't work with
+                          his setup; a working KDM does not include the
+                          recipient's thumbprint (recipient.thumbprint()).
+                          Waimea uses only the trusted devices here, too.
+                       */
+                       for (auto i: trusted_devices) {
+                               kre.authorized_device_info->certificate_thumbprints.push_back(i);
                        }
                }
        }
@@ -675,12 +706,14 @@ EncryptedKDM::EncryptedKDM (
        _data->signature = data::Signature (signed_doc->node_child ("Signature"));
 }
 
+
 EncryptedKDM::EncryptedKDM (EncryptedKDM const & other)
        : _data (new data::EncryptedKDMData (*other._data))
 {
 
 }
 
+
 EncryptedKDM &
 EncryptedKDM::operator= (EncryptedKDM const & other)
 {
@@ -693,86 +726,97 @@ EncryptedKDM::operator= (EncryptedKDM const & other)
        return *this;
 }
 
+
 EncryptedKDM::~EncryptedKDM ()
 {
        delete _data;
 }
 
+
 void
 EncryptedKDM::as_xml (boost::filesystem::path path) const
 {
-       auto f = fopen_boost (path, "w");
+       File f(path, "w");
        if (!f) {
                throw FileError ("Could not open KDM file for writing", path, errno);
        }
        auto const x = as_xml ();
-       size_t const written = fwrite (x.c_str(), 1, x.length(), f);
-       fclose (f);
-       if (written != x.length()) {
+       if (f.write(x.c_str(), 1, x.length()) != x.length()) {
                throw FileError ("Could not write to KDM file", path, errno);
        }
 }
 
+
 string
 EncryptedKDM::as_xml () const
 {
        return _data->as_xml()->write_to_string ("UTF-8");
 }
 
+
 vector<string>
 EncryptedKDM::keys () const
 {
        return _data->authenticated_private.encrypted_key;
 }
 
+
 string
 EncryptedKDM::id () const
 {
        return _data->authenticated_public.message_id;
 }
 
+
 optional<string>
 EncryptedKDM::annotation_text () const
 {
        return _data->authenticated_public.annotation_text;
 }
 
+
 string
 EncryptedKDM::content_title_text () const
 {
        return _data->authenticated_public.required_extensions.kdm_required_extensions.content_title_text;
 }
 
+
 string
 EncryptedKDM::cpl_id () const
 {
        return _data->authenticated_public.required_extensions.kdm_required_extensions.composition_playlist_id;
 }
 
+
 string
 EncryptedKDM::issue_date () const
 {
        return _data->authenticated_public.issue_date;
 }
 
+
 LocalTime
 EncryptedKDM::not_valid_before () const
 {
        return _data->authenticated_public.required_extensions.kdm_required_extensions.not_valid_before;
 }
 
+
 LocalTime
 EncryptedKDM::not_valid_after () const
 {
        return _data->authenticated_public.required_extensions.kdm_required_extensions.not_valid_after;
 }
 
+
 string
 EncryptedKDM::recipient_x509_subject_name () const
 {
        return _data->authenticated_public.required_extensions.kdm_required_extensions.recipient.x509_subject_name;
 }
 
+
 CertificateChain
 EncryptedKDM::signer_certificate_chain () const
 {
@@ -784,6 +828,7 @@ EncryptedKDM::signer_certificate_chain () const
        return chain;
 }
 
+
 bool
 dcp::operator== (EncryptedKDM const & a, EncryptedKDM const & b)
 {