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