Add SMPTE Bv2.1 ExtensionMetadata.
[libdcp.git] / src / encrypted_kdm.cc
index d7a2bcc6ca6899404fc76b0edc4cd3a476012c7c..e8e8987085014297831f97880c2edcd90c783272 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2017 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
@@ -35,6 +35,7 @@
 #include "util.h"
 #include "certificate_chain.h"
 #include "exceptions.h"
+#include "compose.hpp"
 #include <libcxml/cxml.h>
 #include <libxml++/document.h>
 #include <libxml++/nodes/element.h>
@@ -384,14 +385,14 @@ public:
                , authorized_device_info (node->node_child ("AuthorizedDeviceInfo"))
                , key_id_list (node->node_child ("KeyIdList"))
        {
-               disable_forensic_marking_picture = 0;
-               disable_forensic_marking_audio = 0;
+               disable_forensic_marking_picture = false;
+               disable_forensic_marking_audio = optional<int>();
                if (node->optional_node_child("ForensicMarkFlagList")) {
                        BOOST_FOREACH (cxml::ConstNodePtr i, node->node_child("ForensicMarkFlagList")->node_children("ForensicMarkFlag")) {
                                if (i->content() == picture_disable) {
-                                       disable_forensic_marking_picture = -1;
+                                       disable_forensic_marking_picture = true;
                                } else if (starts_with(i->content(), audio_disable)) {
-                                       disable_forensic_marking_audio = -1;
+                                       disable_forensic_marking_audio = 0;
                                        string const above = audio_disable + "-above-channel-";
                                        if (starts_with(i->content(), above)) {
                                                string above_number = i->content().substr(above.length());
@@ -429,8 +430,8 @@ public:
                        }
                        if (disable_forensic_marking_audio) {
                                string mrkflg = audio_disable;
-                               if (disable_forensic_marking_audio != -1) {
-                                       mrkflg = str (boost::format (mrkflg + "-above-channel-%u") % disable_forensic_marking_audio);
+                               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);
                        }
@@ -443,8 +444,8 @@ public:
        string content_title_text;
        LocalTime not_valid_before;
        LocalTime not_valid_after;
-       int disable_forensic_marking_picture;
-       int disable_forensic_marking_audio;
+       bool disable_forensic_marking_picture;
+       optional<int> disable_forensic_marking_audio;
        boost::optional<AuthorizedDeviceInfo> authorized_device_info;
        KeyIdList key_id_list;
 
@@ -553,6 +554,7 @@ public:
                        xmlAddID (0, document->cobj(), (const xmlChar *) i->first.c_str(), i->second->cobj ());
                }
 
+               indent (document->get_root_node(), 0);
                return document;
        }
 
@@ -575,18 +577,19 @@ EncryptedKDM::EncryptedKDM (string s)
        }
 }
 
+/** @param trusted_devices Trusted device thumbprints */
 EncryptedKDM::EncryptedKDM (
        shared_ptr<const CertificateChain> signer,
        Certificate recipient,
-       vector<Certificate> trusted_devices,
+       vector<string> trusted_devices,
        string cpl_id,
        string content_title_text,
        optional<string> annotation_text,
        LocalTime not_valid_before,
        LocalTime not_valid_after,
        Formulation formulation,
-       int disable_forensic_marking_picture,
-       int disable_forensic_marking_audio,
+       bool disable_forensic_marking_picture,
+       optional<int> disable_forensic_marking_audio,
        list<pair<string, string> > key_ids,
        list<string> keys
        )
@@ -650,8 +653,8 @@ EncryptedKDM::EncryptedKDM (
                                   recipient's thumbprint (recipient.thumbprint()).
                                   Waimea uses only the trusted devices here, too.
                                */
-                               BOOST_FOREACH (Certificate const & i, trusted_devices) {
-                                       kre.authorized_device_info->certificate_thumbprints.push_back (i.thumbprint ());
+                               BOOST_FOREACH (string i, trusted_devices) {
+                                       kre.authorized_device_info->certificate_thumbprints.push_back (i);
                                }
                        }
                }
@@ -668,7 +671,7 @@ EncryptedKDM::EncryptedKDM (
        xmlpp::Node::NodeList children = doc->get_root_node()->get_children ();
        for (xmlpp::Node::NodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
                if ((*i)->get_name() == "Signature") {
-                       signer->add_signature_value (*i, "ds");
+                       signer->add_signature_value (dynamic_cast<xmlpp::Element*>(*i), "ds", false);
                }
        }
 
@@ -704,9 +707,15 @@ void
 EncryptedKDM::as_xml (boost::filesystem::path path) const
 {
        FILE* f = fopen_boost (path, "w");
+       if (!f) {
+               throw FileError ("Could not open KDM file for writing", path, errno);
+       }
        string const x = as_xml ();
-       fwrite (x.c_str(), 1, x.length(), f);
+       size_t const written = fwrite (x.c_str(), 1, x.length(), f);
        fclose (f);
+       if (written != x.length()) {
+               throw FileError ("Could not write to KDM file", path, errno);
+       }
 }
 
 string
@@ -769,6 +778,17 @@ 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
+{
+       CertificateChain chain;
+       BOOST_FOREACH (data::X509Data const & i, _data->signature.x509_data) {
+               string s = "-----BEGIN CERTIFICATE-----\n" + i.x509_certificate + "\n-----END CERTIFICATE-----";
+               chain.add (Certificate(s));
+       }
+       return chain;
+}
+
 bool
 dcp::operator== (EncryptedKDM const & a, EncryptedKDM const & b)
 {