Rename ReelMXF -> ReelFileAsset.
[libdcp.git] / src / decrypted_kdm.cc
1 /*
2     Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
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.
10
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.
15
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/>.
18
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
23     including the two.
24
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.
32 */
33
34
35 /** @file  src/decrypted_kdm.cc
36  *  @brief DecryptedKDM class
37  */
38
39
40 #include "decrypted_kdm.h"
41 #include "decrypted_kdm_key.h"
42 #include "encrypted_kdm.h"
43 #include "reel_file_asset.h"
44 #include "reel_asset.h"
45 #include "util.h"
46 #include "exceptions.h"
47 #include "cpl.h"
48 #include "certificate_chain.h"
49 #include "dcp_assert.h"
50 #include "compose.hpp"
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>
56
57
58 using std::list;
59 using std::vector;
60 using std::string;
61 using std::setw;
62 using std::setfill;
63 using std::hex;
64 using std::pair;
65 using std::map;
66 using std::shared_ptr;
67 using boost::optional;
68 using namespace dcp;
69
70
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 };
73
74
75 static void
76 put (uint8_t ** d, string s)
77 {
78         memcpy (*d, s.c_str(), s.length());
79         (*d) += s.length();
80 }
81
82
83 static void
84 put (uint8_t ** d, uint8_t const * s, int N)
85 {
86         memcpy (*d, s, N);
87         (*d) += N;
88 }
89
90
91 void
92 DecryptedKDM::put_uuid (uint8_t ** d, string id)
93 {
94         /* 32 hex digits plus some hyphens */
95         DCP_ASSERT (id.length() == 36);
96 #ifdef LIBDCP_WINDOWS
97         __mingw_sscanf (
98 #else
99         sscanf (
100 #endif
101                 id.c_str(),
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
105                 );
106
107         *d += 16;
108 }
109
110
111 string
112 DecryptedKDM::get_uuid (unsigned char ** p)
113 {
114         char buffer[37];
115 #ifdef LIBDCP_WINDOWS
116         __mingw_snprintf (
117 #else
118         snprintf (
119 #endif
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]
123                 );
124
125         *p += 16;
126         return buffer;
127 }
128
129
130 static string
131 get (uint8_t ** p, int N)
132 {
133         string g;
134         for (int i = 0; i < N; ++i) {
135                 g += **p;
136                 (*p)++;
137         }
138
139         return g;
140 }
141
142
143 DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
144 {
145         /* Read the private key */
146
147         auto bio = BIO_new_mem_buf (const_cast<char *>(private_key.c_str()), -1);
148         if (!bio) {
149                 throw MiscError ("could not create memory BIO");
150         }
151
152         auto rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
153         if (!rsa) {
154                 throw FileError ("could not read RSA private key file", private_key, errno);
155         }
156
157         /* Use the private key to decrypt the keys */
158
159         for (auto const& i: kdm.keys()) {
160                 /* Decode the base-64-encoded cipher value from the KDM */
161                 unsigned char cipher_value[256];
162                 int const cipher_value_len = base64_decode (i, cipher_value, sizeof (cipher_value));
163
164                 /* Decrypt it */
165                 auto decrypted = new unsigned char[RSA_size(rsa)];
166                 int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
167                 if (decrypted_len == -1) {
168                         delete[] decrypted;
169 #if OPENSSL_VERSION_NUMBER > 0x10100000L
170                         throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, RSA_bits(rsa));
171 #else
172                         throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, rsa->n->dmax);
173 #endif
174                 }
175
176                 unsigned char* p = decrypted;
177                 switch (decrypted_len) {
178                 case 134:
179                 {
180                         /* Inter-op */
181                         /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
182                         p += 16;
183                         /* 16 is is signer thumbprint [20 bytes] */
184                         p += 20;
185                         /* 36 is CPL id [16 bytes] */
186                         string const cpl_id = get_uuid (&p);
187                         /* 52 is key id [16 bytes] */
188                         string const key_id = get_uuid (&p);
189                         /* 68 is not-valid-before (a string) [25 bytes] */
190                         p += 25;
191                         /* 93 is not-valid-after (a string) [25 bytes] */
192                         p += 25;
193                         /* 118 is the key [ASDCP::KeyLen bytes] */
194                         add_key (optional<string>(), key_id, Key(p), cpl_id, Standard::INTEROP);
195                         break;
196                 }
197                 case 138:
198                 {
199                         /* SMPTE */
200                         /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
201                         DCP_ASSERT (memcmp (p, smpte_structure_id, 16) == 0);
202                         p += 16;
203                         /* 16 is is signer thumbprint [20 bytes] */
204                         p += 20;
205                         /* 36 is CPL id [16 bytes] */
206                         string const cpl_id = get_uuid (&p);
207                         /* 52 is key type [4 bytes] */
208                         string const key_type = get (&p, 4);
209                         /* 56 is key id [16 bytes] */
210                         string const key_id = get_uuid (&p);
211                         /* 72 is not-valid-before (a string) [25 bytes] */
212                         p += 25;
213                         /* 97 is not-valid-after (a string) [25 bytes] */
214                         p += 25;
215                         /* 112 is the key [ASDCP::KeyLen bytes] */
216                         add_key (key_type, key_id, Key(p), cpl_id, Standard::SMPTE);
217                         break;
218                 }
219                 default:
220                         DCP_ASSERT (false);
221                 }
222
223                 delete[] decrypted;
224         }
225
226         RSA_free (rsa);
227         BIO_free (bio);
228
229         _annotation_text = kdm.annotation_text ();
230         _content_title_text = kdm.content_title_text ();
231         _issue_date = kdm.issue_date ();
232 }
233
234
235 DecryptedKDM::DecryptedKDM (
236         LocalTime not_valid_before,
237         LocalTime not_valid_after,
238         string annotation_text,
239         string content_title_text,
240         string issue_date
241         )
242         : _not_valid_before (not_valid_before)
243         , _not_valid_after (not_valid_after)
244         , _annotation_text (annotation_text)
245         , _content_title_text (content_title_text)
246         , _issue_date (issue_date)
247 {
248
249 }
250
251
252 DecryptedKDM::DecryptedKDM (
253         string cpl_id,
254         map<shared_ptr<const ReelFileAsset>, Key> keys,
255         LocalTime not_valid_before,
256         LocalTime not_valid_after,
257         string annotation_text,
258         string content_title_text,
259         string issue_date
260         )
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)
266 {
267         for (map<shared_ptr<const ReelFileAsset>, Key>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
268                 add_key (i->first->key_type(), i->first->key_id().get(), i->second, cpl_id, Standard::SMPTE);
269         }
270 }
271
272
273 DecryptedKDM::DecryptedKDM (
274         shared_ptr<const CPL> cpl,
275         Key key,
276         LocalTime not_valid_before,
277         LocalTime not_valid_after,
278         string annotation_text,
279         string content_title_text,
280         string issue_date
281         )
282         : _not_valid_before (not_valid_before)
283         , _not_valid_after (not_valid_after)
284         , _annotation_text (annotation_text)
285         , _content_title_text (content_title_text)
286         , _issue_date (issue_date)
287 {
288         /* Create DecryptedKDMKey objects for each encryptable asset */
289         bool did_one = false;
290         for (auto i: cpl->reel_file_assets()) {
291                 if (i->key_id()) {
292                         add_key (i->key_type(), i->key_id().get(), key, cpl->id(), Standard::SMPTE);
293                         did_one = true;
294                 }
295         }
296
297         if (!did_one) {
298                 throw NotEncryptedError (cpl->id ());
299         }
300 }
301
302
303 void
304 DecryptedKDM::add_key (optional<string> type, string key_id, Key key, string cpl_id, Standard standard)
305 {
306         _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id, standard));
307 }
308
309
310 void
311 DecryptedKDM::add_key (DecryptedKDMKey key)
312 {
313         _keys.push_back (key);
314 }
315
316
317 EncryptedKDM
318 DecryptedKDM::encrypt (
319         shared_ptr<const CertificateChain> signer,
320         Certificate recipient,
321         vector<string> trusted_devices,
322         Formulation formulation,
323         bool disable_forensic_marking_picture,
324         optional<int> disable_forensic_marking_audio
325         ) const
326 {
327         DCP_ASSERT (!_keys.empty ());
328
329         for (auto i: signer->leaf_to_root()) {
330                 if (day_greater_than_or_equal(dcp::LocalTime(i.not_before()), _not_valid_before)) {
331                         throw BadKDMDateError (true);
332                 } else if (day_less_than_or_equal(dcp::LocalTime(i.not_after()), _not_valid_after)) {
333                         throw BadKDMDateError (false);
334                 }
335         }
336
337         vector<pair<string, string>> key_ids;
338         vector<string> keys;
339         for (auto const& i: _keys) {
340                 /* We're making SMPTE keys so we must have a type for each one */
341                 DCP_ASSERT (i.type());
342                 key_ids.push_back (make_pair (i.type().get(), i.id ()));
343
344                 /* XXX: SMPTE only */
345                 uint8_t block[138];
346                 uint8_t* p = block;
347
348                 put (&p, smpte_structure_id, 16);
349
350                 base64_decode (signer->leaf().thumbprint (), p, 20);
351                 p += 20;
352
353                 put_uuid (&p, i.cpl_id ());
354                 put (&p, i.type().get());
355                 put_uuid (&p, i.id ());
356                 put (&p, _not_valid_before.as_string ());
357                 put (&p, _not_valid_after.as_string ());
358                 put (&p, i.key().value(), ASDCP::KeyLen);
359
360                 /* Encrypt using the projector's public key */
361                 RSA* rsa = recipient.public_key ();
362                 unsigned char encrypted[RSA_size(rsa)];
363                 int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
364                 if (encrypted_len == -1) {
365                         throw MiscError (String::compose ("Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
366                 }
367
368                 /* Lazy overallocation */
369                 char out[encrypted_len * 2];
370                 Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
371                 int const N = strlen (out);
372                 string lines;
373                 for (int i = 0; i < N; ++i) {
374                         if (i > 0 && (i % 64) == 0) {
375                                 lines += "\n";
376                         }
377                         lines += out[i];
378                 }
379
380                 keys.push_back (lines);
381         }
382
383         string device_list_description = recipient.subject_common_name ();
384         if (device_list_description.find (".") != string::npos) {
385                 device_list_description = device_list_description.substr (device_list_description.find (".") + 1);
386         }
387
388         return EncryptedKDM (
389                 signer,
390                 recipient,
391                 trusted_devices,
392                 _keys.front().cpl_id (),
393                 _content_title_text,
394                 _annotation_text,
395                 _not_valid_before,
396                 _not_valid_after,
397                 formulation,
398                 disable_forensic_marking_picture,
399                 disable_forensic_marking_audio,
400                 key_ids,
401                 keys
402                 );
403 }