2 Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
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.
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.
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/>.
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
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.
34 #include "decrypted_kdm.h"
35 #include "decrypted_kdm_key.h"
36 #include "encrypted_kdm.h"
38 #include "reel_asset.h"
40 #include "exceptions.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>
55 using std::stringstream;
60 using boost::shared_ptr;
64 put (uint8_t ** d, string s)
66 memcpy (*d, s.c_str(), s.length());
71 put (uint8_t ** d, uint8_t const * s, int N)
78 put_uuid (uint8_t ** d, string id)
80 id.erase (std::remove (id.begin(), id.end(), '-'));
81 for (int i = 0; i < 32; i += 2) {
83 s << id[i] << id[i + 1];
92 get_uuid (unsigned char ** p)
96 for (int i = 0; i < 16; ++i) {
97 g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
99 if (i == 3 || i == 5 || i == 7 || i == 9) {
108 get (uint8_t ** p, int N)
111 for (int i = 0; i < N; ++i) {
119 DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
121 /* Read the private key */
123 BIO* bio = BIO_new_mem_buf (const_cast<char *> (private_key.c_str ()), -1);
125 throw MiscError ("could not create memory BIO");
128 RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
130 throw FileError ("could not read RSA private key file", private_key, errno);
133 /* Use the private key to decrypt the keys */
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));
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) {
145 throw MiscError (String::compose ("Could not decrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
148 unsigned char* p = decrypted;
149 switch (decrypted_len) {
153 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
155 /* 16 is is signer thumbprint [20 bytes] */
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] */
163 /* 93 is not-valid-after (a string) [25 bytes] */
165 /* 118 is the key [ASDCP::KeyLen bytes] */
166 _keys.push_back (DecryptedKDMKey ("", key_id, Key (p), cpl_id));
172 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
174 /* 16 is is signer thumbprint [20 bytes] */
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] */
184 /* 97 is not-valid-after (a string) [25 bytes] */
186 /* 112 is the key [ASDCP::KeyLen bytes] */
187 _keys.push_back (DecryptedKDMKey (key_type, key_id, Key (p), cpl_id));
200 _annotation_text = kdm.annotation_text ();
201 _content_title_text = kdm.content_title_text ();
202 _issue_date = kdm.issue_date ();
205 DecryptedKDM::DecryptedKDM (
206 LocalTime not_valid_before,
207 LocalTime not_valid_after,
208 string annotation_text,
209 string content_title_text,
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)
221 DecryptedKDM::DecryptedKDM (
222 boost::shared_ptr<const CPL> cpl,
224 LocalTime not_valid_before,
225 LocalTime not_valid_after,
226 string annotation_text,
227 string content_title_text,
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)
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);
241 if (!mxf->key_id ()) {
242 throw NotEncryptedError (asset->id ());
244 _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id().get(), key, cpl->id ()));
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.
255 DecryptedKDM::add_key (string type, string key_id, Key key, string cpl_id)
257 _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id));
261 DecryptedKDM::add_key (DecryptedKDMKey key)
263 _keys.push_back (key);
267 DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, vector<Certificate> trusted_devices, Formulation formulation) const
269 list<pair<string, string> > key_ids;
271 BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
272 key_ids.push_back (make_pair (i.type(), i.id ()));
274 /* XXX: SMPTE only */
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);
282 base64_decode (signer->leaf().thumbprint (), p, 20);
285 put_uuid (&p, i.cpl_id ());
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);
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)));
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);
305 for (int i = 0; i < N; ++i) {
306 if (i > 0 && (i % 64) == 0) {
312 keys.push_back (lines.str ());
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);
320 return EncryptedKDM (
324 device_list_description,
325 _keys.front().cpl_id (),