Switch to testing on Ubuntu 16.04 and 22.04.
[libdcp.git] / src / encrypted_kdm.cc
index 77345a5d9fb3a8f60b96e4943bfcda3a4d1ca1f4..465a657da2a60512791a91fff4e9bb571501e7e7 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++/document.h>
 #include <libxml++/nodes/element.h>
@@ -44,6 +51,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 +63,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:
@@ -82,6 +93,7 @@ public:
        string x509_serial_number;
 };
 
+
 class X509Data
 {
 public:
@@ -104,6 +116,7 @@ public:
        std::string x509_certificate;
 };
 
+
 class Reference
 {
 public:
@@ -131,6 +144,7 @@ public:
        string digest_value;
 };
 
+
 class SignedInfo
 {
 public:
@@ -171,6 +185,7 @@ private:
        Reference authenticated_private;
 };
 
+
 class Signature
 {
 public:
@@ -198,9 +213,10 @@ public:
 
        SignedInfo signed_info;
        string signature_value;
-       list<X509Data> x509_data;
+       vector<X509Data> x509_data;
 };
 
+
 class AuthenticatedPrivate
 {
 public:
@@ -232,9 +248,10 @@ public:
                }
        }
 
-       list<string> encrypted_key;
+       vector<string> encrypted_key;
 };
 
+
 class TypedKeyId
 {
 public:
@@ -254,7 +271,7 @@ public:
 
        void as_xml (xmlpp::Element* node) const
        {
-               xmlpp::Element* type = node->add_child("KeyType");
+               auto type = node->add_child("KeyType");
                type->add_child_text (key_type);
                node->add_child("KeyId")->add_child_text ("urn:uuid:" + key_id);
                /* XXX: this feels like a bit of a hack */
@@ -269,6 +286,7 @@ public:
        string key_id;
 };
 
+
 class KeyIdList
 {
 public:
@@ -288,9 +306,10 @@ public:
                }
        }
 
-       list<TypedKeyId> typed_key_id;
+       vector<TypedKeyId> typed_key_id;
 };
 
+
 class AuthorizedDeviceInfo
 {
 public:
@@ -320,9 +339,10 @@ public:
        /** DeviceListIdentifier without the urn:uuid: prefix */
        string device_list_identifier;
        boost::optional<string> device_list_description;
-       std::list<string> certificate_thumbprints;
+       std::vector<string> certificate_thumbprints;
 };
 
+
 class X509IssuerSerial
 {
 public:
@@ -345,6 +365,7 @@ public:
        string x509_serial_number;
 };
 
+
 class Recipient
 {
 public:
@@ -367,6 +388,7 @@ public:
        string x509_subject_name;
 };
 
+
 class KDMRequiredExtensions
 {
 public:
@@ -450,9 +472,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:
@@ -472,6 +496,7 @@ public:
        KDMRequiredExtensions kdm_required_extensions;
 };
 
+
 class AuthenticatedPublic
 {
 public:
@@ -516,6 +541,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.
  */
@@ -559,9 +585,11 @@ public:
        Signature signature;
 };
 
+
 }
 }
 
+
 EncryptedKDM::EncryptedKDM (string s)
 {
        try {
@@ -570,10 +598,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,
@@ -586,8 +618,8 @@ EncryptedKDM::EncryptedKDM (
        Formulation formulation,
        bool disable_forensic_marking_picture,
        optional<int> disable_forensic_marking_audio,
-       list<pair<string, string> > key_ids,
-       list<string> keys
+       vector<pair<string, string>> key_ids,
+       vector<string> keys
        )
        : _data (new data::EncryptedKDMData)
 {
@@ -602,7 +634,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;
@@ -612,7 +644,7 @@ EncryptedKDM::EncryptedKDM (
        kre.recipient.x509_issuer_serial.x509_serial_number = recipient.serial ();
        kre.recipient.x509_subject_name = recipient.subject ();
        kre.composition_playlist_id = cpl_id;
-       if (formulation == DCI_ANY || formulation == DCI_SPECIFIC) {
+       if (formulation == Formulation::DCI_ANY || formulation == Formulation::DCI_SPECIFIC) {
                kre.content_authenticator = signer->leaf().thumbprint ();
        }
        kre.content_title_text = content_title_text;
@@ -621,37 +653,35 @@ EncryptedKDM::EncryptedKDM (
        kre.disable_forensic_marking_picture = disable_forensic_marking_picture;
        kre.disable_forensic_marking_audio = disable_forensic_marking_audio;
 
-       if (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 == MODIFIED_TRANSITIONAL_1 || 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 == MULTIPLE_MODIFIED_TRANSITIONAL_1 || 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 +705,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 +725,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");
 }
 
-list<string>
+
+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 +827,7 @@ EncryptedKDM::signer_certificate_chain () const
        return chain;
 }
 
+
 bool
 dcp::operator== (EncryptedKDM const & a, EncryptedKDM const & b)
 {