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