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