Attempts to fix Windows build.
[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 MiscError (String::compose ("Could not decrypt KDM (%1)", 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         BOOST_FOREACH(shared_ptr<const ReelAsset> i, cpl->reel_assets ()) {
240                 shared_ptr<const ReelMXF> mxf = boost::dynamic_pointer_cast<const ReelMXF> (i);
241                 shared_ptr<const ReelAsset> asset = boost::dynamic_pointer_cast<const ReelAsset> (i);
242                 if (asset && mxf) {
243                         if (!mxf->key_id ()) {
244                                 throw NotEncryptedError (asset->id ());
245                         }
246                         _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id().get(), key, cpl->id ()));
247                 }
248         }
249 }
250
251 /** @param type (MDIK, MDAK etc.)
252  *  @param key_id Key ID.
253  *  @param key The actual symmetric key.
254  *  @param cpl_id ID of CPL that the key is for.
255  */
256 void
257 DecryptedKDM::add_key (string type, string key_id, Key key, string cpl_id)
258 {
259         _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id));
260 }
261
262 void
263 DecryptedKDM::add_key (DecryptedKDMKey key)
264 {
265         _keys.push_back (key);
266 }
267
268 EncryptedKDM
269 DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, vector<Certificate> trusted_devices, Formulation formulation) const
270 {
271         list<pair<string, string> > key_ids;
272         list<string> keys;
273         BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
274                 key_ids.push_back (make_pair (i.type(), i.id ()));
275
276                 /* XXX: SMPTE only */
277                 uint8_t block[138];
278                 uint8_t* p = block;
279
280                 /* Magic value specified by SMPTE S430-1-2006 */
281                 uint8_t structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
282                 put (&p, structure_id, 16);
283
284                 base64_decode (signer->leaf().thumbprint (), p, 20);
285                 p += 20;
286
287                 put_uuid (&p, i.cpl_id ());
288                 put (&p, i.type ());
289                 put_uuid (&p, i.id ());
290                 put (&p, _not_valid_before.as_string ());
291                 put (&p, _not_valid_after.as_string ());
292                 put (&p, i.key().value(), ASDCP::KeyLen);
293
294                 /* Encrypt using the projector's public key */
295                 RSA* rsa = recipient.public_key ();
296                 unsigned char encrypted[RSA_size(rsa)];
297                 int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
298                 if (encrypted_len == -1) {
299                         throw MiscError (String::compose ("Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
300                 }
301
302                 /* Lazy overallocation */
303                 char out[encrypted_len * 2];
304                 Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
305                 int const N = strlen (out);
306                 string lines;
307                 for (int i = 0; i < N; ++i) {
308                         if (i > 0 && (i % 64) == 0) {
309                                 lines += "\n";
310                         }
311                         lines += out[i];
312                 }
313
314                 keys.push_back (lines);
315         }
316
317         string device_list_description = recipient.subject_common_name ();
318         if (device_list_description.find (".") != string::npos) {
319                 device_list_description = device_list_description.substr (device_list_description.find (".") + 1);
320         }
321
322         return EncryptedKDM (
323                 signer,
324                 recipient,
325                 trusted_devices,
326                 device_list_description,
327                 _keys.front().cpl_id (),
328                 _content_title_text,
329                 _annotation_text,
330                 _not_valid_before,
331                 _not_valid_after,
332                 formulation,
333                 key_ids,
334                 keys
335                 );
336 }