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>
59 using boost::shared_ptr;
63 put (uint8_t ** d, string s)
65 memcpy (*d, s.c_str(), s.length());
70 put (uint8_t ** d, uint8_t const * s, int N)
77 put_uuid (uint8_t ** d, string id)
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];
91 get_uuid (unsigned char ** p)
93 locked_stringstream g;
95 for (int i = 0; i < 16; ++i) {
96 g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
98 if (i == 3 || i == 5 || i == 7 || i == 9) {
107 get (uint8_t ** p, int N)
110 for (int i = 0; i < N; ++i) {
118 DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
120 /* Read the private key */
122 BIO* bio = BIO_new_mem_buf (const_cast<char *> (private_key.c_str ()), -1);
124 throw MiscError ("could not create memory BIO");
127 RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
129 throw FileError ("could not read RSA private key file", private_key, errno);
132 /* Use the private key to decrypt the keys */
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));
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) {
144 throw MiscError (String::compose ("Could not decrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
147 unsigned char* p = decrypted;
148 switch (decrypted_len) {
152 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
154 /* 16 is is signer thumbprint [20 bytes] */
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] */
162 /* 93 is not-valid-after (a string) [25 bytes] */
164 /* 118 is the key [ASDCP::KeyLen bytes] */
165 _keys.push_back (DecryptedKDMKey ("", key_id, Key (p), cpl_id));
171 /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */
173 /* 16 is is signer thumbprint [20 bytes] */
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] */
183 /* 97 is not-valid-after (a string) [25 bytes] */
185 /* 112 is the key [ASDCP::KeyLen bytes] */
186 _keys.push_back (DecryptedKDMKey (key_type, key_id, Key (p), cpl_id));
199 _annotation_text = kdm.annotation_text ();
200 _content_title_text = kdm.content_title_text ();
201 _issue_date = kdm.issue_date ();
204 DecryptedKDM::DecryptedKDM (
205 LocalTime not_valid_before,
206 LocalTime not_valid_after,
207 string annotation_text,
208 string content_title_text,
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)
220 DecryptedKDM::DecryptedKDM (
221 boost::shared_ptr<const CPL> cpl,
223 LocalTime not_valid_before,
224 LocalTime not_valid_after,
225 string annotation_text,
226 string content_title_text,
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)
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);
240 if (!mxf->key_id ()) {
241 throw NotEncryptedError (asset->id ());
243 _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id().get(), key, cpl->id ()));
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.
254 DecryptedKDM::add_key (string type, string key_id, Key key, string cpl_id)
256 _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id));
260 DecryptedKDM::add_key (DecryptedKDMKey key)
262 _keys.push_back (key);
266 DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate recipient, vector<Certificate> trusted_devices, Formulation formulation) const
268 list<pair<string, string> > key_ids;
270 BOOST_FOREACH (DecryptedKDMKey const & i, _keys) {
271 key_ids.push_back (make_pair (i.type(), i.id ()));
273 /* XXX: SMPTE only */
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);
281 base64_decode (signer->leaf().thumbprint (), p, 20);
284 put_uuid (&p, i.cpl_id ());
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);
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)));
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) {
311 keys.push_back (lines.str ());
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);
319 return EncryptedKDM (
323 device_list_description,
324 _keys.front().cpl_id (),