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