Bump version
[libdcp.git] / src / decrypted_kdm.cc
index 8a714b1e05a086f44d6e1199300fd9c71e9c91a6..949db72bdcc6e763767e7c24fea85d1af3d7ddae 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include "decrypted_kdm.h"
 #include "decrypted_kdm_key.h"
 #include "encrypted_kdm.h"
+#include "reel_mxf.h"
+#include "reel_asset.h"
 #include "util.h"
 #include "exceptions.h"
 #include "cpl.h"
-#include "mxf.h"
-#include "signer.h"
+#include "certificate_chain.h"
+#include "dcp_assert.h"
 #include "AS_DCP.h"
 #include "KM_util.h"
 #include "compose.hpp"
 #include <openssl/rsa.h>
 #include <openssl/pem.h>
 #include <openssl/err.h>
+#include <boost/foreach.hpp>
 
 using std::list;
 using std::string;
@@ -74,7 +77,7 @@ static string
 get_uuid (unsigned char ** p)
 {
        stringstream g;
-       
+
        for (int i = 0; i < 16; ++i) {
                g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
                (*p)++;
@@ -98,29 +101,26 @@ get (uint8_t ** p, int N)
        return g;
 }
 
-DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, boost::filesystem::path private_key)
+DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
 {
        /* Read the private key */
-          
-       FILE* private_key_file = fopen_boost (private_key, "r");
-       if (!private_key_file) {
-               throw FileError ("could not find RSA private key file", private_key, errno);
+
+       BIO* bio = BIO_new_mem_buf (const_cast<char *> (private_key.c_str ()), -1);
+       if (!bio) {
+               throw MiscError ("could not create memory BIO");
        }
-       
-       RSA* rsa = PEM_read_RSAPrivateKey (private_key_file, 0, 0, 0);
-       fclose (private_key_file);      
+
+       RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
        if (!rsa) {
                throw FileError ("could not read RSA private key file", private_key, errno);
        }
 
        /* Use the private key to decrypt the keys */
 
-       list<string> const encrypted_keys = kdm.keys ();
-       for (list<string>::const_iterator i = encrypted_keys.begin(); i != encrypted_keys.end(); ++i) {
-
+       BOOST_FOREACH (string const & i, kdm.keys ()) {
                /* Decode the base-64-encoded cipher value from the KDM */
                unsigned char cipher_value[256];
-               int const cipher_value_len = base64_decode (*i, 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)];
@@ -173,17 +173,19 @@ DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, boost::filesystem::path pr
                        break;
                }
                default:
-                       assert (false);
-               }               
-               
+                       DCP_ASSERT (false);
+               }
+
                delete[] decrypted;
        }
 
        RSA_free (rsa);
+       BIO_free (bio);
 }
 
 DecryptedKDM::DecryptedKDM (
        boost::shared_ptr<const CPL> cpl,
+       Key key,
        LocalTime not_valid_before,
        LocalTime not_valid_after,
        string annotation_text,
@@ -196,28 +198,26 @@ DecryptedKDM::DecryptedKDM (
        , _content_title_text (content_title_text)
        , _issue_date (issue_date)
 {
-       /* Create DecryptedKDMKey objects for each MXF asset */
-       list<shared_ptr<const Content> > content = cpl->content ();
-       for (list<shared_ptr<const Content> >::iterator i = content.begin(); i != content.end(); ++i) {
-               /* XXX: do non-MXF assets need keys? */
-               shared_ptr<const MXF> mxf = boost::dynamic_pointer_cast<const MXF> (*i);
-               if (mxf) {
-                       if (mxf->key_id().empty ()) {
-                               throw NotEncryptedError (mxf->file().string ());
+       /* Create DecryptedKDMKey objects for each encryptable asset */
+       BOOST_FOREACH(shared_ptr<const ReelAsset> i, cpl->reel_assets ()) {
+               shared_ptr<const ReelMXF> mxf = boost::dynamic_pointer_cast<const ReelMXF> (i);
+               shared_ptr<const ReelAsset> asset = boost::dynamic_pointer_cast<const ReelAsset> (i);
+               if (asset && mxf) {
+                       if (!mxf->key_id ()) {
+                               throw NotEncryptedError (asset->id ());
                        }
-                       _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id(), mxf->key().get (), cpl->id ()));
+                       _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id().get(), key, cpl->id ()));
                }
        }
 }
 
 EncryptedKDM
-DecryptedKDM::encrypt (shared_ptr<const Signer> signer, shared_ptr<const Certificate> recipient, Formulation formulation) const
+DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, Formulation formulation) const
 {
        list<pair<string, string> > key_ids;
        list<string> keys;
-       for (list<DecryptedKDMKey>::const_iterator i = _keys.begin(); i != _keys.end(); ++i) {
-
-               key_ids.push_back (make_pair (i->type(), i->id ()));
+       BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
+               key_ids.push_back (make_pair (i.type(), i.id ()));
 
                /* XXX: SMPTE only */
                uint8_t block[138];
@@ -227,24 +227,24 @@ DecryptedKDM::encrypt (shared_ptr<const Signer> signer, shared_ptr<const Certifi
                uint8_t structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
                put (&p, structure_id, 16);
 
-               base64_decode (signer->certificates().leaf()->thumbprint (), p, 20);
+               base64_decode (signer->leaf().thumbprint (), p, 20);
                p += 20;
-               
-               put_uuid (&p, i->cpl_id ());
-               put (&p, i->type ());
-               put_uuid (&p, i->id ());
+
+               put_uuid (&p, i.cpl_id ());
+               put (&p, i.type ());
+               put_uuid (&p, i.id ());
                put (&p, _not_valid_before.as_string ());
                put (&p, _not_valid_after.as_string ());
-               put (&p, i->key().value(), ASDCP::KeyLen);
-               
+               put (&p, i.key().value(), ASDCP::KeyLen);
+
                /* Encrypt using the projector's public key */
-               RSA* rsa = recipient->public_key ();
+               RSA* rsa = recipient.public_key ();
                unsigned char encrypted[RSA_size(rsa)];
                int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
                if (encrypted_len == -1) {
                        throw MiscError (String::compose ("Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
                }
-               
+
                /* Lazy overallocation */
                char out[encrypted_len * 2];
                Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
@@ -256,11 +256,11 @@ DecryptedKDM::encrypt (shared_ptr<const Signer> signer, shared_ptr<const Certifi
                        }
                        lines << out[i];
                }
-               
+
                keys.push_back (lines.str ());
        }
 
-       string device_list_description = recipient->common_name ();
+       string device_list_description = recipient.subject_common_name ();
        if (device_list_description.find (".") != string::npos) {
                device_list_description = device_list_description.substr (device_list_description.find (".") + 1);
        }