Still more licence fixups.
[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
20 #include "decrypted_kdm.h"
21 #include "decrypted_kdm_key.h"
22 #include "encrypted_kdm.h"
23 #include "reel_mxf.h"
24 #include "reel_asset.h"
25 #include "util.h"
26 #include "exceptions.h"
27 #include "cpl.h"
28 #include "certificate_chain.h"
29 #include "dcp_assert.h"
30 #include "AS_DCP.h"
31 #include "KM_util.h"
32 #include "compose.hpp"
33 #include <openssl/rsa.h>
34 #include <openssl/pem.h>
35 #include <openssl/err.h>
36 #include <boost/foreach.hpp>
37
38 using std::list;
39 using std::vector;
40 using std::string;
41 using std::stringstream;
42 using std::setw;
43 using std::setfill;
44 using std::hex;
45 using std::pair;
46 using boost::shared_ptr;
47 using namespace dcp;
48
49 static void
50 put (uint8_t ** d, string s)
51 {
52         memcpy (*d, s.c_str(), s.length());
53         (*d) += s.length();
54 }
55
56 static void
57 put (uint8_t ** d, uint8_t const * s, int N)
58 {
59         memcpy (*d, s, N);
60         (*d) += N;
61 }
62
63 static void
64 put_uuid (uint8_t ** d, string id)
65 {
66         id.erase (std::remove (id.begin(), id.end(), '-'));
67         for (int i = 0; i < 32; i += 2) {
68                 stringstream s;
69                 s << id[i] << id[i + 1];
70                 int h;
71                 s >> hex >> h;
72                 **d = h;
73                 (*d)++;
74         }
75 }
76
77 static string
78 get_uuid (unsigned char ** p)
79 {
80         stringstream g;
81
82         for (int i = 0; i < 16; ++i) {
83                 g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
84                 (*p)++;
85                 if (i == 3 || i == 5 || i == 7 || i == 9) {
86                         g << '-';
87                 }
88         }
89
90         return g.str ();
91 }
92
93 static string
94 get (uint8_t ** p, int N)
95 {
96         string g;
97         for (int i = 0; i < N; ++i) {
98                 g += **p;
99                 (*p)++;
100         }
101
102         return g;
103 }
104
105 DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
106 {
107         /* Read the private key */
108
109         BIO* bio = BIO_new_mem_buf (const_cast<char *> (private_key.c_str ()), -1);
110         if (!bio) {
111                 throw MiscError ("could not create memory BIO");
112         }
113
114         RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
115         if (!rsa) {
116                 throw FileError ("could not read RSA private key file", private_key, errno);
117         }
118
119         /* Use the private key to decrypt the keys */
120
121         BOOST_FOREACH (string const & i, kdm.keys ()) {
122                 /* Decode the base-64-encoded cipher value from the KDM */
123                 unsigned char cipher_value[256];
124                 int const cipher_value_len = base64_decode (i, cipher_value, sizeof (cipher_value));
125
126                 /* Decrypt it */
127                 unsigned char * decrypted = new unsigned char[RSA_size(rsa)];
128                 int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
129                 if (decrypted_len == -1) {
130                         delete[] decrypted;
131                         throw MiscError (String::compose ("Could not decrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
132                 }
133
134                 unsigned char* p = decrypted;
135                 switch (decrypted_len) {
136                 case 134:
137                 {
138                         /* Inter-op */
139                         /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
140                         p += 16;
141                         /* 16 is is signer thumbprint [20 bytes] */
142                         p += 20;
143                         /* 36 is CPL id [16 bytes] */
144                         string const cpl_id = get_uuid (&p);
145                         /* 52 is key id [16 bytes] */
146                         string const key_id = get_uuid (&p);
147                         /* 68 is not-valid-before (a string) [25 bytes] */
148                         p += 25;
149                         /* 93 is not-valid-after (a string) [25 bytes] */
150                         p += 25;
151                         /* 118 is the key [ASDCP::KeyLen bytes] */
152                         _keys.push_back (DecryptedKDMKey ("", key_id, Key (p), cpl_id));
153                         break;
154                 }
155                 case 138:
156                 {
157                         /* SMPTE */
158                         /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
159                         p += 16;
160                         /* 16 is is signer thumbprint [20 bytes] */
161                         p += 20;
162                         /* 36 is CPL id [16 bytes] */
163                         string const cpl_id = get_uuid (&p);
164                         /* 52 is key type [4 bytes] */
165                         string const key_type = get (&p, 4);
166                         /* 56 is key id [16 bytes] */
167                         string const key_id = get_uuid (&p);
168                         /* 72 is not-valid-before (a string) [25 bytes] */
169                         p += 25;
170                         /* 97 is not-valid-after (a string) [25 bytes] */
171                         p += 25;
172                         /* 112 is the key [ASDCP::KeyLen bytes] */
173                         _keys.push_back (DecryptedKDMKey (key_type, key_id, Key (p), cpl_id));
174                         break;
175                 }
176                 default:
177                         DCP_ASSERT (false);
178                 }
179
180                 delete[] decrypted;
181         }
182
183         RSA_free (rsa);
184         BIO_free (bio);
185
186         _annotation_text = kdm.annotation_text ();
187         _content_title_text = kdm.content_title_text ();
188         _issue_date = kdm.issue_date ();
189 }
190
191 DecryptedKDM::DecryptedKDM (
192         LocalTime not_valid_before,
193         LocalTime not_valid_after,
194         string annotation_text,
195         string content_title_text,
196         string issue_date
197         )
198         : _not_valid_before (not_valid_before)
199         , _not_valid_after (not_valid_after)
200         , _annotation_text (annotation_text)
201         , _content_title_text (content_title_text)
202         , _issue_date (issue_date)
203 {
204
205 }
206
207 DecryptedKDM::DecryptedKDM (
208         boost::shared_ptr<const CPL> cpl,
209         Key key,
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         /* Create DecryptedKDMKey objects for each encryptable asset */
223         BOOST_FOREACH(shared_ptr<const ReelAsset> i, cpl->reel_assets ()) {
224                 shared_ptr<const ReelMXF> mxf = boost::dynamic_pointer_cast<const ReelMXF> (i);
225                 shared_ptr<const ReelAsset> asset = boost::dynamic_pointer_cast<const ReelAsset> (i);
226                 if (asset && mxf) {
227                         if (!mxf->key_id ()) {
228                                 throw NotEncryptedError (asset->id ());
229                         }
230                         _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id().get(), key, cpl->id ()));
231                 }
232         }
233 }
234
235 /** @param type (MDIK, MDAK etc.)
236  *  @param key_id Key ID.
237  *  @param key The actual symmetric key.
238  *  @param cpl_id ID of CPL that the key is for.
239  */
240 void
241 DecryptedKDM::add_key (string type, string key_id, Key key, string cpl_id)
242 {
243         _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id));
244 }
245
246 void
247 DecryptedKDM::add_key (DecryptedKDMKey key)
248 {
249         _keys.push_back (key);
250 }
251
252 EncryptedKDM
253 DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, vector<Certificate> trusted_devices, Formulation formulation) const
254 {
255         list<pair<string, string> > key_ids;
256         list<string> keys;
257         BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
258                 key_ids.push_back (make_pair (i.type(), i.id ()));
259
260                 /* XXX: SMPTE only */
261                 uint8_t block[138];
262                 uint8_t* p = block;
263
264                 /* Magic value specified by SMPTE S430-1-2006 */
265                 uint8_t structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
266                 put (&p, structure_id, 16);
267
268                 base64_decode (signer->leaf().thumbprint (), p, 20);
269                 p += 20;
270
271                 put_uuid (&p, i.cpl_id ());
272                 put (&p, i.type ());
273                 put_uuid (&p, i.id ());
274                 put (&p, _not_valid_before.as_string ());
275                 put (&p, _not_valid_after.as_string ());
276                 put (&p, i.key().value(), ASDCP::KeyLen);
277
278                 /* Encrypt using the projector's public key */
279                 RSA* rsa = recipient.public_key ();
280                 unsigned char encrypted[RSA_size(rsa)];
281                 int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
282                 if (encrypted_len == -1) {
283                         throw MiscError (String::compose ("Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
284                 }
285
286                 /* Lazy overallocation */
287                 char out[encrypted_len * 2];
288                 Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
289                 int const N = strlen (out);
290                 stringstream lines;
291                 for (int i = 0; i < N; ++i) {
292                         if (i > 0 && (i % 64) == 0) {
293                                 lines << "\n";
294                         }
295                         lines << out[i];
296                 }
297
298                 keys.push_back (lines.str ());
299         }
300
301         string device_list_description = recipient.subject_common_name ();
302         if (device_list_description.find (".") != string::npos) {
303                 device_list_description = device_list_description.substr (device_list_description.find (".") + 1);
304         }
305
306         return EncryptedKDM (
307                 signer,
308                 recipient,
309                 trusted_devices,
310                 device_list_description,
311                 _keys.front().cpl_id (),
312                 _content_title_text,
313                 _annotation_text,
314                 _not_valid_before,
315                 _not_valid_after,
316                 formulation,
317                 key_ids,
318                 keys
319                 );
320 }