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