2 Copyright (C) 2013-2016 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/>.
20 #include "decrypted_kdm.h"
21 #include "decrypted_kdm_key.h"
22 #include "encrypted_kdm.h"
24 #include "reel_asset.h"
26 #include "exceptions.h"
28 #include "certificate_chain.h"
29 #include "dcp_assert.h"
32 #include "compose.hpp"
33 #include <openssl/rsa.h>
34 #include <openssl/pem.h>
35 #include <openssl/err.h>
36 #include <boost/foreach.hpp>
41 using std::stringstream;
46 using boost::shared_ptr;
50 put (uint8_t ** d, string s)
52 memcpy (*d, s.c_str(), s.length());
57 put (uint8_t ** d, uint8_t const * s, int N)
64 put_uuid (uint8_t ** d, string id)
66 id.erase (std::remove (id.begin(), id.end(), '-'));
67 for (int i = 0; i < 32; i += 2) {
69 s << id[i] << id[i + 1];
78 get_uuid (unsigned char ** p)
82 for (int i = 0; i < 16; ++i) {
83 g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
85 if (i == 3 || i == 5 || i == 7 || i == 9) {
94 get (uint8_t ** p, int N)
97 for (int i = 0; i < N; ++i) {
105 DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
107 /* Read the private key */
109 BIO* bio = BIO_new_mem_buf (const_cast<char *> (private_key.c_str ()), -1);
111 throw MiscError ("could not create memory BIO");
114 RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
116 throw FileError ("could not read RSA private key file", private_key, errno);
119 /* Use the private key to decrypt the keys */
121 BOOST_FOREACH (string const & i, kdm.keys ()) {
122 /* Decode the base-64-encoded cipher value from the KDM */
123 unsigned char cipher_value[256];
124 int const cipher_value_len = base64_decode (i, cipher_value, sizeof (cipher_value));
127 unsigned char * decrypted = new unsigned char[RSA_size(rsa)];
128 int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
129 if (decrypted_len == -1) {
131 throw MiscError (String::compose ("Could not decrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
134 unsigned char* p = decrypted;
135 switch (decrypted_len) {
139 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
141 /* 16 is is signer thumbprint [20 bytes] */
143 /* 36 is CPL id [16 bytes] */
144 string const cpl_id = get_uuid (&p);
145 /* 52 is key id [16 bytes] */
146 string const key_id = get_uuid (&p);
147 /* 68 is not-valid-before (a string) [25 bytes] */
149 /* 93 is not-valid-after (a string) [25 bytes] */
151 /* 118 is the key [ASDCP::KeyLen bytes] */
152 _keys.push_back (DecryptedKDMKey ("", key_id, Key (p), cpl_id));
158 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
160 /* 16 is is signer thumbprint [20 bytes] */
162 /* 36 is CPL id [16 bytes] */
163 string const cpl_id = get_uuid (&p);
164 /* 52 is key type [4 bytes] */
165 string const key_type = get (&p, 4);
166 /* 56 is key id [16 bytes] */
167 string const key_id = get_uuid (&p);
168 /* 72 is not-valid-before (a string) [25 bytes] */
170 /* 97 is not-valid-after (a string) [25 bytes] */
172 /* 112 is the key [ASDCP::KeyLen bytes] */
173 _keys.push_back (DecryptedKDMKey (key_type, key_id, Key (p), cpl_id));
186 _annotation_text = kdm.annotation_text ();
187 _content_title_text = kdm.content_title_text ();
188 _issue_date = kdm.issue_date ();
191 DecryptedKDM::DecryptedKDM (
192 LocalTime not_valid_before,
193 LocalTime not_valid_after,
194 string annotation_text,
195 string content_title_text,
198 : _not_valid_before (not_valid_before)
199 , _not_valid_after (not_valid_after)
200 , _annotation_text (annotation_text)
201 , _content_title_text (content_title_text)
202 , _issue_date (issue_date)
207 DecryptedKDM::DecryptedKDM (
208 boost::shared_ptr<const CPL> cpl,
210 LocalTime not_valid_before,
211 LocalTime not_valid_after,
212 string annotation_text,
213 string content_title_text,
216 : _not_valid_before (not_valid_before)
217 , _not_valid_after (not_valid_after)
218 , _annotation_text (annotation_text)
219 , _content_title_text (content_title_text)
220 , _issue_date (issue_date)
222 /* Create DecryptedKDMKey objects for each encryptable asset */
223 BOOST_FOREACH(shared_ptr<const ReelAsset> i, cpl->reel_assets ()) {
224 shared_ptr<const ReelMXF> mxf = boost::dynamic_pointer_cast<const ReelMXF> (i);
225 shared_ptr<const ReelAsset> asset = boost::dynamic_pointer_cast<const ReelAsset> (i);
227 if (!mxf->key_id ()) {
228 throw NotEncryptedError (asset->id ());
230 _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id().get(), key, cpl->id ()));
235 /** @param type (MDIK, MDAK etc.)
236 * @param key_id Key ID.
237 * @param key The actual symmetric key.
238 * @param cpl_id ID of CPL that the key is for.
241 DecryptedKDM::add_key (string type, string key_id, Key key, string cpl_id)
243 _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id));
247 DecryptedKDM::add_key (DecryptedKDMKey key)
249 _keys.push_back (key);
253 DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, vector<Certificate> trusted_devices, Formulation formulation) const
255 list<pair<string, string> > key_ids;
257 BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
258 key_ids.push_back (make_pair (i.type(), i.id ()));
260 /* XXX: SMPTE only */
264 /* Magic value specified by SMPTE S430-1-2006 */
265 uint8_t structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
266 put (&p, structure_id, 16);
268 base64_decode (signer->leaf().thumbprint (), p, 20);
271 put_uuid (&p, i.cpl_id ());
273 put_uuid (&p, i.id ());
274 put (&p, _not_valid_before.as_string ());
275 put (&p, _not_valid_after.as_string ());
276 put (&p, i.key().value(), ASDCP::KeyLen);
278 /* Encrypt using the projector's public key */
279 RSA* rsa = recipient.public_key ();
280 unsigned char encrypted[RSA_size(rsa)];
281 int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
282 if (encrypted_len == -1) {
283 throw MiscError (String::compose ("Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
286 /* Lazy overallocation */
287 char out[encrypted_len * 2];
288 Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
289 int const N = strlen (out);
291 for (int i = 0; i < N; ++i) {
292 if (i > 0 && (i % 64) == 0) {
298 keys.push_back (lines.str ());
301 string device_list_description = recipient.subject_common_name ();
302 if (device_list_description.find (".") != string::npos) {
303 device_list_description = device_list_description.substr (device_list_description.find (".") + 1);
306 return EncryptedKDM (
310 device_list_description,
311 _keys.front().cpl_id (),