Add new constructor. Remove believed unnecessary check for KDM assets being ReelAsse...
[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 namespace dcp;
62
63 static void
64 put (uint8_t ** d, string s)
65 {
66         memcpy (*d, s.c_str(), s.length());
67         (*d) += s.length();
68 }
69
70 static void
71 put (uint8_t ** d, uint8_t const * s, int N)
72 {
73         memcpy (*d, s, N);
74         (*d) += N;
75 }
76
77 void
78 DecryptedKDM::put_uuid (uint8_t ** d, string id)
79 {
80         /* 32 hex digits plus some hyphens */
81         DCP_ASSERT (id.length() == 36);
82 #ifdef LIBDCP_WINDOWS
83         __mingw_sscanf (
84 #else
85         sscanf (
86 #endif
87                 id.c_str(),
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
91                 );
92
93         *d += 16;
94 }
95
96 string
97 DecryptedKDM::get_uuid (unsigned char ** p)
98 {
99         char buffer[37];
100         snprintf (
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]
104                 );
105
106         *p += 16;
107         return buffer;
108 }
109
110 static string
111 get (uint8_t ** p, int N)
112 {
113         string g;
114         for (int i = 0; i < N; ++i) {
115                 g += **p;
116                 (*p)++;
117         }
118
119         return g;
120 }
121
122 DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
123 {
124         /* Read the private key */
125
126         BIO* bio = BIO_new_mem_buf (const_cast<char *> (private_key.c_str ()), -1);
127         if (!bio) {
128                 throw MiscError ("could not create memory BIO");
129         }
130
131         RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
132         if (!rsa) {
133                 throw FileError ("could not read RSA private key file", private_key, errno);
134         }
135
136         /* Use the private key to decrypt the keys */
137
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));
142
143                 /* Decrypt it */
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) {
147                         delete[] decrypted;
148                         throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0));
149                 }
150
151                 unsigned char* p = decrypted;
152                 switch (decrypted_len) {
153                 case 134:
154                 {
155                         /* Inter-op */
156                         /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
157                         p += 16;
158                         /* 16 is is signer thumbprint [20 bytes] */
159                         p += 20;
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] */
165                         p += 25;
166                         /* 93 is not-valid-after (a string) [25 bytes] */
167                         p += 25;
168                         /* 118 is the key [ASDCP::KeyLen bytes] */
169                         add_key ("", key_id, Key (p), cpl_id);
170                         break;
171                 }
172                 case 138:
173                 {
174                         /* SMPTE */
175                         /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
176                         p += 16;
177                         /* 16 is is signer thumbprint [20 bytes] */
178                         p += 20;
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] */
186                         p += 25;
187                         /* 97 is not-valid-after (a string) [25 bytes] */
188                         p += 25;
189                         /* 112 is the key [ASDCP::KeyLen bytes] */
190                         add_key (key_type, key_id, Key (p), cpl_id);
191                         break;
192                 }
193                 default:
194                         DCP_ASSERT (false);
195                 }
196
197                 delete[] decrypted;
198         }
199
200         RSA_free (rsa);
201         BIO_free (bio);
202
203         _annotation_text = kdm.annotation_text ();
204         _content_title_text = kdm.content_title_text ();
205         _issue_date = kdm.issue_date ();
206 }
207
208 DecryptedKDM::DecryptedKDM (
209         LocalTime not_valid_before,
210         LocalTime not_valid_after,
211         string annotation_text,
212         string content_title_text,
213         string issue_date
214         )
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)
220 {
221
222 }
223
224 DecryptedKDM::DecryptedKDM (
225         string cpl_id,
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,
231         string issue_date
232         )
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)
238 {
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);
241         }
242 }
243
244 DecryptedKDM::DecryptedKDM (
245         shared_ptr<const CPL> cpl,
246         Key key,
247         LocalTime not_valid_before,
248         LocalTime not_valid_after,
249         string annotation_text,
250         string content_title_text,
251         string issue_date
252         )
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)
258 {
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 ());
265                         did_one = true;
266                 }
267         }
268
269         if (!did_one) {
270                 throw NotEncryptedError (cpl->id ());
271         }
272 }
273
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.
278  */
279 void
280 DecryptedKDM::add_key (string type, string key_id, Key key, string cpl_id)
281 {
282         _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id));
283 }
284
285 void
286 DecryptedKDM::add_key (DecryptedKDMKey key)
287 {
288         _keys.push_back (key);
289 }
290
291 EncryptedKDM
292 DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, vector<Certificate> trusted_devices, Formulation formulation) const
293 {
294         list<pair<string, string> > key_ids;
295         list<string> keys;
296         BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
297                 key_ids.push_back (make_pair (i.type(), i.id ()));
298
299                 /* XXX: SMPTE only */
300                 uint8_t block[138];
301                 uint8_t* p = block;
302
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);
306
307                 base64_decode (signer->leaf().thumbprint (), p, 20);
308                 p += 20;
309
310                 put_uuid (&p, i.cpl_id ());
311                 put (&p, i.type ());
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);
316
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)));
323                 }
324
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);
329                 string lines;
330                 for (int i = 0; i < N; ++i) {
331                         if (i > 0 && (i % 64) == 0) {
332                                 lines += "\n";
333                         }
334                         lines += out[i];
335                 }
336
337                 keys.push_back (lines);
338         }
339
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);
343         }
344
345         return EncryptedKDM (
346                 signer,
347                 recipient,
348                 trusted_devices,
349                 _keys.front().cpl_id (),
350                 _content_title_text,
351                 _annotation_text,
352                 _not_valid_before,
353                 _not_valid_after,
354                 formulation,
355                 key_ids,
356                 keys
357                 );
358 }