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