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