41 #include "compose.hpp"
51 #include <asdcp/AS_DCP.h>
52 #include <asdcp/KM_util.h>
53 #include <openssl/rsa.h>
54 #include <openssl/pem.h>
55 #include <openssl/err.h>
66 using std::shared_ptr;
67 using boost::optional;
72 static uint8_t smpte_structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab };
76 put (uint8_t ** d,
string s)
78 memcpy (*d, s.c_str(), s.length());
84 put (uint8_t ** d, uint8_t
const * s,
int N)
92 DecryptedKDM::put_uuid (uint8_t ** d,
string id)
95 DCP_ASSERT (
id.length() == 36);
102 "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
103 *d + 0, *d + 1, *d + 2, *d + 3, *d + 4, *d + 5, *d + 6, *d + 7,
104 *d + 8, *d + 9, *d + 10, *d + 11, *d + 12, *d + 13, *d + 14, *d + 15
112 DecryptedKDM::get_uuid (
unsigned char ** p)
115 #ifdef LIBDCP_WINDOWS
120 buffer,
sizeof(buffer),
"%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
121 (*p)[0], (*p)[1], (*p)[2], (*p)[3], (*p)[4], (*p)[5], (*p)[6], (*p)[7],
122 (*p)[8], (*p)[9], (*p)[10], (*p)[11], (*p)[12], (*p)[13], (*p)[14], (*p)[15]
131 get (uint8_t ** p,
int N)
134 for (
int i = 0; i < N; ++i) {
147 auto bio = BIO_new_mem_buf (
const_cast<char *
>(private_key.c_str()), -1);
149 throw MiscError (
"could not create memory BIO");
152 auto rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
154 throw FileError (
"could not read RSA private key file", private_key, errno);
159 for (
auto const& i: kdm.
keys()) {
161 unsigned char cipher_value[256];
162 int const cipher_value_len =
base64_decode (i, cipher_value,
sizeof (cipher_value));
165 auto decrypted =
new unsigned char[RSA_size(rsa)];
166 int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
167 if (decrypted_len == -1) {
169 #if OPENSSL_VERSION_NUMBER > 0x10100000L
170 throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, RSA_bits(rsa));
172 throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, rsa->n->dmax);
176 unsigned char* p = decrypted;
177 switch (decrypted_len) {
186 string const cpl_id = get_uuid (&p);
188 string const key_id = get_uuid (&p);
194 add_key (optional<string>(), key_id,
Key(p), cpl_id, Standard::INTEROP);
201 DCP_ASSERT (memcmp (p, smpte_structure_id, 16) == 0);
206 string const cpl_id = get_uuid (&p);
208 string const key_type = get (&p, 4);
210 string const key_id = get_uuid (&p);
216 add_key (key_type, key_id,
Key(p), cpl_id, Standard::SMPTE);
229 _annotation_text = kdm.annotation_text ();
230 _content_title_text = kdm.content_title_text ();
231 _issue_date = kdm.issue_date ();
238 string annotation_text,
239 string content_title_text,
242 : _not_valid_before (not_valid_before)
243 , _not_valid_after (not_valid_after)
244 , _annotation_text (annotation_text)
245 , _content_title_text (content_title_text)
246 , _issue_date (issue_date)
254 map<shared_ptr<const ReelFileAsset>,
Key> keys,
257 string annotation_text,
258 string content_title_text,
261 : _not_valid_before (not_valid_before)
262 , _not_valid_after (not_valid_after)
263 , _annotation_text (annotation_text)
264 , _content_title_text (content_title_text)
265 , _issue_date (issue_date)
267 for (
auto const& i:
keys) {
268 add_key (i.first->key_type(), i.first->key_id().get(), i.second, cpl_id, Standard::SMPTE);
274 shared_ptr<const CPL> cpl,
278 string annotation_text,
279 string content_title_text,
282 : _not_valid_before (not_valid_before)
283 , _not_valid_after (not_valid_after)
284 , _annotation_text (annotation_text)
285 , _content_title_text (content_title_text)
286 , _issue_date (issue_date)
289 bool did_one =
false;
290 for (
auto i: cpl->reel_file_assets()) {
291 if (i->encryptable()) {
292 add_key (i->key_type().get(), i->key_id().get(), key, cpl->id(), Standard::SMPTE);
306 _keys.push_back (
DecryptedKDMKey (type, key_id, key, cpl_id, standard));
313 _keys.push_back (key);
319 shared_ptr<const CertificateChain> signer,
321 vector<string> trusted_devices,
323 bool disable_forensic_marking_picture,
324 optional<int> disable_forensic_marking_audio
327 DCP_ASSERT (!_keys.empty ());
329 for (
auto i: signer->leaf_to_root()) {
337 vector<pair<string, string>> key_ids;
339 for (
auto const& i: _keys) {
341 DCP_ASSERT (i.type());
342 key_ids.push_back (make_pair (i.type().get(), i.id ()));
348 put (&p, smpte_structure_id, 16);
353 put_uuid (&p, i.cpl_id ());
354 put (&p, i.type().get());
355 put_uuid (&p, i.id ());
356 put (&p, _not_valid_before.
as_string ());
358 put (&p, i.key().value(), ASDCP::KeyLen);
362 unsigned char encrypted[RSA_size(rsa)];
363 int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
364 if (encrypted_len == -1) {
365 throw MiscError (String::compose (
"Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
369 char out[encrypted_len * 2];
370 Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
371 int const N = strlen (out);
373 for (
int i = 0; i < N; ++i) {
374 if (i > 0 && (i % 64) == 0) {
380 keys.push_back (lines);
383 string device_list_description = recipient.subject_common_name ();
384 if (device_list_description.find (
".") != string::npos) {
385 device_list_description = device_list_description.substr (device_list_description.find (
".") + 1);
392 _keys.front().cpl_id (),
398 disable_forensic_marking_picture,
399 disable_forensic_marking_audio,
A wrapper for an X509 certificate.
An un- or de-crypted key from a KDM.
DecryptedKDM(EncryptedKDM const &kdm, std::string private_key)
void add_key(boost::optional< std::string > type, std::string key_id, Key key, std::string cpl_id, Standard standard)
std::vector< DecryptedKDMKey > keys() const
EncryptedKDM encrypt(std::shared_ptr< const CertificateChain > signer, Certificate recipient, std::vector< std::string > trusted_devices, Formulation formulation, bool disable_forensic_marking_picture, boost::optional< int > disable_forensic_marking_audio) const
std::vector< std::string > keys() const
An exception related to a file.
A key for decrypting/encrypting assets.
A representation of a local time (down to the second), including its offset from GMT (equivalent to x...
std::string as_string(bool with_millisecond=false) const
A miscellaneous exception.
An error raised when creating a DecryptedKDM object for assets that are not encrypted.
Exceptions thrown by libdcp.
Namespace for everything in libdcp.
int base64_decode(std::string const &in, unsigned char *out, int out_length)
bool day_less_than_or_equal(LocalTime a, LocalTime b)
bool day_greater_than_or_equal(LocalTime a, LocalTime b)
Utility methods and classes.