2 Copyright (C) 2013-2021 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.
35 /** @file src/decrypted_kdm.cc
36 * @brief DecryptedKDM class
40 #include "certificate_chain.h"
41 #include "compose.hpp"
43 #include "dcp_assert.h"
44 #include "decrypted_kdm.h"
45 #include "decrypted_kdm_key.h"
46 #include "encrypted_kdm.h"
47 #include "exceptions.h"
48 #include "reel_asset.h"
49 #include "reel_file_asset.h"
51 #include <asdcp/AS_DCP.h>
52 #include <asdcp/KM_util.h>
53 #include <openssl/rsa.h>
54 #include <openssl/pem.h>
55 #include <openssl/err.h>
66 using std::shared_ptr;
67 using boost::optional;
71 /* Magic value specified by SMPTE S430-1-2006 */
72 static uint8_t smpte_structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
76 put (uint8_t ** d, string s)
78 memcpy (*d, s.c_str(), s.length());
84 put (uint8_t ** d, uint8_t const * s, int N)
92 DecryptedKDM::put_uuid (uint8_t ** d, string id)
94 /* 32 hex digits plus some hyphens */
95 DCP_ASSERT (id.length() == 36);
102 "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
103 *d + 0, *d + 1, *d + 2, *d + 3, *d + 4, *d + 5, *d + 6, *d + 7,
104 *d + 8, *d + 9, *d + 10, *d + 11, *d + 12, *d + 13, *d + 14, *d + 15
112 DecryptedKDM::get_uuid (unsigned char ** p)
115 #ifdef LIBDCP_WINDOWS
120 buffer, sizeof(buffer), "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
121 (*p)[0], (*p)[1], (*p)[2], (*p)[3], (*p)[4], (*p)[5], (*p)[6], (*p)[7],
122 (*p)[8], (*p)[9], (*p)[10], (*p)[11], (*p)[12], (*p)[13], (*p)[14], (*p)[15]
131 get (uint8_t ** p, int N)
134 for (int i = 0; i < N; ++i) {
143 DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
145 /* Read the private key */
147 auto bio = BIO_new_mem_buf (const_cast<char *>(private_key.c_str()), -1);
149 throw MiscError ("could not create memory BIO");
152 auto rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
154 throw FileError ("could not read RSA private key file", private_key, errno);
157 /* Use the private key to decrypt the keys */
161 for (auto const& i: kdm.keys()) {
162 /* Decode the base-64-encoded cipher value from the KDM */
163 unsigned char cipher_value[256];
164 int const cipher_value_len = base64_decode (i, cipher_value, sizeof (cipher_value));
167 auto decrypted = new unsigned char[RSA_size(rsa)];
168 int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
169 if (decrypted_len == -1) {
171 #if OPENSSL_VERSION_NUMBER > 0x10100000L
172 throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, RSA_bits(rsa));
174 throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, rsa->n->dmax);
178 dcp::LocalTime not_valid_before;
179 dcp::LocalTime not_valid_after;
181 unsigned char* p = decrypted;
182 switch (decrypted_len) {
186 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
188 /* 16 is is signer thumbprint [20 bytes] */
190 /* 36 is CPL id [16 bytes] */
191 string const cpl_id = get_uuid (&p);
192 /* 52 is key id [16 bytes] */
193 string const key_id = get_uuid (&p);
194 /* 68 is not-valid-before (a string) [25 bytes] */
195 not_valid_before = dcp::LocalTime(std::string(reinterpret_cast<char*>(p), 25));
197 /* 93 is not-valid-after (a string) [25 bytes] */
198 not_valid_after = dcp::LocalTime(std::string(reinterpret_cast<char*>(p), 25));
200 /* 118 is the key [ASDCP::KeyLen bytes] */
201 add_key (optional<string>(), key_id, Key(p), cpl_id, Standard::INTEROP);
207 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
208 DCP_ASSERT (memcmp (p, smpte_structure_id, 16) == 0);
210 /* 16 is is signer thumbprint [20 bytes] */
212 /* 36 is CPL id [16 bytes] */
213 string const cpl_id = get_uuid (&p);
214 /* 52 is key type [4 bytes] */
215 string const key_type = get (&p, 4);
216 /* 56 is key id [16 bytes] */
217 string const key_id = get_uuid (&p);
218 /* 72 is not-valid-before (a string) [25 bytes] */
219 not_valid_before = dcp::LocalTime(std::string(reinterpret_cast<char*>(p), 25));
221 /* 97 is not-valid-after (a string) [25 bytes] */
222 not_valid_after = dcp::LocalTime(std::string(reinterpret_cast<char*>(p), 25));
224 /* 112 is the key [ASDCP::KeyLen bytes] */
225 add_key (key_type, key_id, Key(p), cpl_id, Standard::SMPTE);
235 _not_valid_before = not_valid_before;
236 _not_valid_after = not_valid_after;
239 if (not_valid_before != _not_valid_before || not_valid_after != _not_valid_after) {
240 throw InconsistentValidityPeriodError();
248 _annotation_text = kdm.annotation_text ();
249 _content_title_text = kdm.content_title_text ();
250 _issue_date = kdm.issue_date ();
254 DecryptedKDM::DecryptedKDM (
255 LocalTime not_valid_before,
256 LocalTime not_valid_after,
257 string annotation_text,
258 string content_title_text,
261 : _not_valid_before (not_valid_before)
262 , _not_valid_after (not_valid_after)
263 , _annotation_text (annotation_text)
264 , _content_title_text (content_title_text)
265 , _issue_date (issue_date)
271 DecryptedKDM::DecryptedKDM (
273 map<shared_ptr<const ReelFileAsset>, Key> keys,
274 LocalTime not_valid_before,
275 LocalTime not_valid_after,
276 string annotation_text,
277 string content_title_text,
280 : _not_valid_before (not_valid_before)
281 , _not_valid_after (not_valid_after)
282 , _annotation_text (annotation_text)
283 , _content_title_text (content_title_text)
284 , _issue_date (issue_date)
286 for (auto const& i: keys) {
287 add_key (i.first->key_type(), i.first->key_id().get(), i.second, cpl_id, Standard::SMPTE);
292 DecryptedKDM::DecryptedKDM (
293 shared_ptr<const CPL> cpl,
295 LocalTime not_valid_before,
296 LocalTime not_valid_after,
297 string annotation_text,
298 string content_title_text,
301 : _not_valid_before (not_valid_before)
302 , _not_valid_after (not_valid_after)
303 , _annotation_text (annotation_text)
304 , _content_title_text (content_title_text)
305 , _issue_date (issue_date)
307 /* Create DecryptedKDMKey objects for each encryptable asset */
308 bool did_one = false;
309 for (auto i: cpl->reel_file_assets()) {
310 if (i->encryptable()) {
311 add_key (i->key_type().get(), i->key_id().get(), key, cpl->id(), Standard::SMPTE);
317 throw NotEncryptedError (cpl->id ());
323 DecryptedKDM::add_key (optional<string> type, string key_id, Key key, string cpl_id, Standard standard)
325 _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id, standard));
330 DecryptedKDM::add_key (DecryptedKDMKey key)
332 _keys.push_back (key);
337 DecryptedKDM::encrypt (
338 shared_ptr<const CertificateChain> signer,
339 Certificate recipient,
340 vector<string> trusted_devices,
341 Formulation formulation,
342 bool disable_forensic_marking_picture,
343 optional<int> disable_forensic_marking_audio
346 DCP_ASSERT (!_keys.empty ());
348 for (auto i: signer->leaf_to_root()) {
349 if (day_greater_than_or_equal(i.not_before(), _not_valid_before)) {
350 throw BadKDMDateError (true);
351 } else if (day_less_than_or_equal(i.not_after(), _not_valid_after)) {
352 throw BadKDMDateError (false);
356 vector<pair<string, string>> key_ids;
358 for (auto const& i: _keys) {
359 /* We're making SMPTE keys so we must have a type for each one */
360 DCP_ASSERT (i.type());
361 key_ids.push_back (make_pair (i.type().get(), i.id ()));
363 /* XXX: SMPTE only */
367 put (&p, smpte_structure_id, 16);
369 base64_decode (signer->leaf().thumbprint (), p, 20);
372 put_uuid (&p, i.cpl_id ());
373 put (&p, i.type().get());
374 put_uuid (&p, i.id ());
375 put (&p, _not_valid_before.as_string ());
376 put (&p, _not_valid_after.as_string ());
377 put (&p, i.key().value(), ASDCP::KeyLen);
379 /* Encrypt using the projector's public key */
380 RSA* rsa = recipient.public_key ();
381 unsigned char encrypted[RSA_size(rsa)];
382 int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
383 if (encrypted_len == -1) {
384 throw MiscError (String::compose ("Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
387 /* Lazy overallocation */
388 char out[encrypted_len * 2];
389 Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
390 int const N = strlen (out);
392 for (int i = 0; i < N; ++i) {
393 if (i > 0 && (i % 64) == 0) {
399 keys.push_back (lines);
402 return EncryptedKDM (
406 _keys.front().cpl_id (),
412 disable_forensic_marking_picture,
413 disable_forensic_marking_audio,