2 Copyright (C) 2013-2017 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/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
34 #include "decrypted_kdm.h"
35 #include "decrypted_kdm_key.h"
36 #include "encrypted_kdm.h"
38 #include "reel_asset.h"
40 #include "exceptions.h"
42 #include "certificate_chain.h"
43 #include "dcp_assert.h"
44 #include "compose.hpp"
45 #include <asdcp/AS_DCP.h>
46 #include <asdcp/KM_util.h>
47 #include <openssl/rsa.h>
48 #include <openssl/pem.h>
49 #include <openssl/err.h>
50 #include <boost/foreach.hpp>
60 using boost::shared_ptr;
64 put (uint8_t ** d, string s)
66 memcpy (*d, s.c_str(), s.length());
71 put (uint8_t ** d, uint8_t const * s, int N)
78 DecryptedKDM::put_uuid (uint8_t ** d, string id)
80 /* 32 hex digits plus some hyphens */
81 DCP_ASSERT (id.length() == 36);
88 "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
89 *d + 0, *d + 1, *d + 2, *d + 3, *d + 4, *d + 5, *d + 6, *d + 7,
90 *d + 8, *d + 9, *d + 10, *d + 11, *d + 12, *d + 13, *d + 14, *d + 15
97 DecryptedKDM::get_uuid (unsigned char ** p)
101 buffer, sizeof(buffer), "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
102 (*p)[0], (*p)[1], (*p)[2], (*p)[3], (*p)[4], (*p)[5], (*p)[6], (*p)[7],
103 (*p)[8], (*p)[9], (*p)[10], (*p)[11], (*p)[12], (*p)[13], (*p)[14], (*p)[15]
111 get (uint8_t ** p, int N)
114 for (int i = 0; i < N; ++i) {
122 DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
124 /* Read the private key */
126 BIO* bio = BIO_new_mem_buf (const_cast<char *> (private_key.c_str ()), -1);
128 throw MiscError ("could not create memory BIO");
131 RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
133 throw FileError ("could not read RSA private key file", private_key, errno);
136 /* Use the private key to decrypt the keys */
138 BOOST_FOREACH (string const & i, kdm.keys ()) {
139 /* Decode the base-64-encoded cipher value from the KDM */
140 unsigned char cipher_value[256];
141 int const cipher_value_len = base64_decode (i, cipher_value, sizeof (cipher_value));
144 unsigned char * decrypted = new unsigned char[RSA_size(rsa)];
145 int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
146 if (decrypted_len == -1) {
148 throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0));
151 unsigned char* p = decrypted;
152 switch (decrypted_len) {
156 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
158 /* 16 is is signer thumbprint [20 bytes] */
160 /* 36 is CPL id [16 bytes] */
161 string const cpl_id = get_uuid (&p);
162 /* 52 is key id [16 bytes] */
163 string const key_id = get_uuid (&p);
164 /* 68 is not-valid-before (a string) [25 bytes] */
166 /* 93 is not-valid-after (a string) [25 bytes] */
168 /* 118 is the key [ASDCP::KeyLen bytes] */
169 add_key ("", key_id, Key (p), cpl_id);
175 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
177 /* 16 is is signer thumbprint [20 bytes] */
179 /* 36 is CPL id [16 bytes] */
180 string const cpl_id = get_uuid (&p);
181 /* 52 is key type [4 bytes] */
182 string const key_type = get (&p, 4);
183 /* 56 is key id [16 bytes] */
184 string const key_id = get_uuid (&p);
185 /* 72 is not-valid-before (a string) [25 bytes] */
187 /* 97 is not-valid-after (a string) [25 bytes] */
189 /* 112 is the key [ASDCP::KeyLen bytes] */
190 add_key (key_type, key_id, Key (p), cpl_id);
203 _annotation_text = kdm.annotation_text ();
204 _content_title_text = kdm.content_title_text ();
205 _issue_date = kdm.issue_date ();
208 DecryptedKDM::DecryptedKDM (
209 LocalTime not_valid_before,
210 LocalTime not_valid_after,
211 string annotation_text,
212 string content_title_text,
215 : _not_valid_before (not_valid_before)
216 , _not_valid_after (not_valid_after)
217 , _annotation_text (annotation_text)
218 , _content_title_text (content_title_text)
219 , _issue_date (issue_date)
224 DecryptedKDM::DecryptedKDM (
226 map<shared_ptr<const ReelMXF>, Key> keys,
227 LocalTime not_valid_before,
228 LocalTime not_valid_after,
229 string annotation_text,
230 string content_title_text,
233 : _not_valid_before (not_valid_before)
234 , _not_valid_after (not_valid_after)
235 , _annotation_text (annotation_text)
236 , _content_title_text (content_title_text)
237 , _issue_date (issue_date)
239 for (map<shared_ptr<const ReelMXF>, Key>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
240 add_key (i->first->key_type(), i->first->key_id().get(), i->second, cpl_id);
244 DecryptedKDM::DecryptedKDM (
245 shared_ptr<const CPL> cpl,
247 LocalTime not_valid_before,
248 LocalTime not_valid_after,
249 string annotation_text,
250 string content_title_text,
253 : _not_valid_before (not_valid_before)
254 , _not_valid_after (not_valid_after)
255 , _annotation_text (annotation_text)
256 , _content_title_text (content_title_text)
257 , _issue_date (issue_date)
259 /* Create DecryptedKDMKey objects for each encryptable asset */
260 bool did_one = false;
261 BOOST_FOREACH(shared_ptr<const ReelAsset> i, cpl->reel_assets ()) {
262 shared_ptr<const ReelMXF> mxf = boost::dynamic_pointer_cast<const ReelMXF> (i);
263 if (mxf && mxf->key_id ()) {
264 add_key (mxf->key_type(), mxf->key_id().get(), key, cpl->id ());
270 throw NotEncryptedError (cpl->id ());
274 /** @param type (MDIK, MDAK etc.)
275 * @param key_id Key ID.
276 * @param key The actual symmetric key.
277 * @param cpl_id ID of CPL that the key is for.
280 DecryptedKDM::add_key (string type, string key_id, Key key, string cpl_id)
282 _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id));
286 DecryptedKDM::add_key (DecryptedKDMKey key)
288 _keys.push_back (key);
292 DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, vector<Certificate> trusted_devices, Formulation formulation) const
294 list<pair<string, string> > key_ids;
296 BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
297 key_ids.push_back (make_pair (i.type(), i.id ()));
299 /* XXX: SMPTE only */
303 /* Magic value specified by SMPTE S430-1-2006 */
304 uint8_t structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
305 put (&p, structure_id, 16);
307 base64_decode (signer->leaf().thumbprint (), p, 20);
310 put_uuid (&p, i.cpl_id ());
312 put_uuid (&p, i.id ());
313 put (&p, _not_valid_before.as_string ());
314 put (&p, _not_valid_after.as_string ());
315 put (&p, i.key().value(), ASDCP::KeyLen);
317 /* Encrypt using the projector's public key */
318 RSA* rsa = recipient.public_key ();
319 unsigned char encrypted[RSA_size(rsa)];
320 int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
321 if (encrypted_len == -1) {
322 throw MiscError (String::compose ("Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
325 /* Lazy overallocation */
326 char out[encrypted_len * 2];
327 Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
328 int const N = strlen (out);
330 for (int i = 0; i < N; ++i) {
331 if (i > 0 && (i % 64) == 0) {
337 keys.push_back (lines);
340 string device_list_description = recipient.subject_common_name ();
341 if (device_list_description.find (".") != string::npos) {
342 device_list_description = device_list_description.substr (device_list_description.find (".") + 1);
345 return EncryptedKDM (
349 _keys.front().cpl_id (),