X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fdecrypted_kdm.cc;h=1f68c2835cfc68861249a582d273a07756345f92;hb=d0ed9dd836b270d6bf75b302535de0f0f8f376e5;hp=4ffad92323c2a820c1120c663ca4e9fcc48d9f79;hpb=455475575bcfa30aa60a377235bfaf2fd7bc2da7;p=libdcp.git diff --git a/src/decrypted_kdm.cc b/src/decrypted_kdm.cc index 4ffad923..1f68c283 100644 --- a/src/decrypted_kdm.cc +++ b/src/decrypted_kdm.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2016 Carl Hetherington + Copyright (C) 2013-2017 Carl Hetherington This file is part of libdcp. @@ -56,9 +56,14 @@ using std::setw; using std::setfill; using std::hex; using std::pair; +using std::map; using boost::shared_ptr; +using boost::optional; using namespace dcp; +/* Magic value specified by SMPTE S430-1-2006 */ +static uint8_t smpte_structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab }; + static void put (uint8_t ** d, string s) { @@ -73,34 +78,41 @@ put (uint8_t ** d, uint8_t const * s, int N) (*d) += N; } -static void -put_uuid (uint8_t ** d, string id) +void +DecryptedKDM::put_uuid (uint8_t ** d, string id) { - id.erase (std::remove (id.begin(), id.end(), '-')); - for (int i = 0; i < 32; i += 2) { - locked_stringstream s; - s << id[i] << id[i + 1]; - int h; - s >> hex >> h; - **d = h; - (*d)++; - } + /* 32 hex digits plus some hyphens */ + DCP_ASSERT (id.length() == 36); +#ifdef LIBDCP_WINDOWS + __mingw_sscanf ( +#else + sscanf ( +#endif + id.c_str(), + "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", + *d + 0, *d + 1, *d + 2, *d + 3, *d + 4, *d + 5, *d + 6, *d + 7, + *d + 8, *d + 9, *d + 10, *d + 11, *d + 12, *d + 13, *d + 14, *d + 15 + ); + + *d += 16; } -static string -get_uuid (unsigned char ** p) +string +DecryptedKDM::get_uuid (unsigned char ** p) { - locked_stringstream g; - - for (int i = 0; i < 16; ++i) { - g << setw(2) << setfill('0') << hex << static_cast (**p); - (*p)++; - if (i == 3 || i == 5 || i == 7 || i == 9) { - g << '-'; - } - } + char buffer[37]; +#ifdef LIBDCP_WINDOWS + __mingw_snprintf ( +#else + snprintf ( +#endif + buffer, sizeof(buffer), "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", + (*p)[0], (*p)[1], (*p)[2], (*p)[3], (*p)[4], (*p)[5], (*p)[6], (*p)[7], + (*p)[8], (*p)[9], (*p)[10], (*p)[11], (*p)[12], (*p)[13], (*p)[14], (*p)[15] + ); - return g.str (); + *p += 16; + return buffer; } static string @@ -141,7 +153,11 @@ DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key) int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING); if (decrypted_len == -1) { delete[] decrypted; - throw MiscError (String::compose ("Could not decrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0))); +#if OPENSSL_VERSION_NUMBER > 0x10100000L + throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, RSA_bits(rsa)); +#else + throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, rsa->n->dmax); +#endif } unsigned char* p = decrypted; @@ -162,13 +178,14 @@ DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key) /* 93 is not-valid-after (a string) [25 bytes] */ p += 25; /* 118 is the key [ASDCP::KeyLen bytes] */ - _keys.push_back (DecryptedKDMKey ("", key_id, Key (p), cpl_id)); + add_key (optional(), key_id, Key (p), cpl_id, INTEROP); break; } case 138: { /* SMPTE */ /* 0 is structure id (fixed sequence specified by standard) [16 bytes] */ + DCP_ASSERT (memcmp (p, smpte_structure_id, 16) == 0); p += 16; /* 16 is is signer thumbprint [20 bytes] */ p += 20; @@ -183,7 +200,7 @@ DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key) /* 97 is not-valid-after (a string) [25 bytes] */ p += 25; /* 112 is the key [ASDCP::KeyLen bytes] */ - _keys.push_back (DecryptedKDMKey (key_type, key_id, Key (p), cpl_id)); + add_key (key_type, key_id, Key (p), cpl_id, SMPTE); break; } default: @@ -218,7 +235,27 @@ DecryptedKDM::DecryptedKDM ( } DecryptedKDM::DecryptedKDM ( - boost::shared_ptr cpl, + string cpl_id, + map, Key> keys, + LocalTime not_valid_before, + LocalTime not_valid_after, + string annotation_text, + string content_title_text, + string issue_date + ) + : _not_valid_before (not_valid_before) + , _not_valid_after (not_valid_after) + , _annotation_text (annotation_text) + , _content_title_text (content_title_text) + , _issue_date (issue_date) +{ + for (map, Key>::const_iterator i = keys.begin(); i != keys.end(); ++i) { + add_key (i->first->key_type(), i->first->key_id().get(), i->second, cpl_id, SMPTE); + } +} + +DecryptedKDM::DecryptedKDM ( + shared_ptr cpl, Key key, LocalTime not_valid_before, LocalTime not_valid_after, @@ -233,16 +270,17 @@ DecryptedKDM::DecryptedKDM ( , _issue_date (issue_date) { /* Create DecryptedKDMKey objects for each encryptable asset */ - BOOST_FOREACH(shared_ptr i, cpl->reel_assets ()) { - shared_ptr mxf = boost::dynamic_pointer_cast (i); - shared_ptr asset = boost::dynamic_pointer_cast (i); - if (asset && mxf) { - if (!mxf->key_id ()) { - throw NotEncryptedError (asset->id ()); - } - _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id().get(), key, cpl->id ())); + bool did_one = false; + BOOST_FOREACH(shared_ptr i, cpl->reel_mxfs()) { + if (i->key_id()) { + add_key (i->key_type(), i->key_id().get(), key, cpl->id(), SMPTE); + did_one = true; } } + + if (!did_one) { + throw NotEncryptedError (cpl->id ()); + } } /** @param type (MDIK, MDAK etc.) @@ -251,9 +289,9 @@ DecryptedKDM::DecryptedKDM ( * @param cpl_id ID of CPL that the key is for. */ void -DecryptedKDM::add_key (string type, string key_id, Key key, string cpl_id) +DecryptedKDM::add_key (optional type, string key_id, Key key, string cpl_id, Standard standard) { - _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id)); + _keys.push_back (DecryptedKDMKey (type, key_id, key, cpl_id, standard)); } void @@ -263,26 +301,43 @@ DecryptedKDM::add_key (DecryptedKDMKey key) } EncryptedKDM -DecryptedKDM::encrypt (shared_ptr signer, Certificate recipient, vector trusted_devices, Formulation formulation) const +DecryptedKDM::encrypt ( + shared_ptr signer, + Certificate recipient, + vector trusted_devices, + Formulation formulation, + bool disable_forensic_marking_picture, + optional disable_forensic_marking_audio + ) const { + DCP_ASSERT (!_keys.empty ()); + + BOOST_FOREACH (dcp::Certificate i, signer->leaf_to_root()) { + if (day_greater_than_or_equal(dcp::LocalTime(i.not_before()), _not_valid_before)) { + throw BadKDMDateError (true); + } else if (day_less_than_or_equal(dcp::LocalTime(i.not_after()), _not_valid_after)) { + throw BadKDMDateError (false); + } + } + list > key_ids; list keys; BOOST_FOREACH (DecryptedKDMKey const & i, _keys) { - key_ids.push_back (make_pair (i.type(), i.id ())); + /* We're making SMPTE keys so we must have a type for each one */ + DCP_ASSERT (i.type()); + key_ids.push_back (make_pair (i.type().get(), i.id ())); /* XXX: SMPTE only */ uint8_t block[138]; uint8_t* p = block; - /* Magic value specified by SMPTE S430-1-2006 */ - uint8_t structure_id[] = { 0xf1, 0xdc, 0x12, 0x44, 0x60, 0x16, 0x9a, 0x0e, 0x85, 0xbc, 0x30, 0x06, 0x42, 0xf8, 0x66, 0xab }; - put (&p, structure_id, 16); + put (&p, smpte_structure_id, 16); base64_decode (signer->leaf().thumbprint (), p, 20); p += 20; put_uuid (&p, i.cpl_id ()); - put (&p, i.type ()); + put (&p, i.type().get()); put_uuid (&p, i.id ()); put (&p, _not_valid_before.as_string ()); put (&p, _not_valid_after.as_string ()); @@ -300,15 +355,15 @@ DecryptedKDM::encrypt (shared_ptr signer, Certificate re char out[encrypted_len * 2]; Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2); int const N = strlen (out); - locked_stringstream lines; + string lines; for (int i = 0; i < N; ++i) { if (i > 0 && (i % 64) == 0) { - lines << "\n"; + lines += "\n"; } - lines << out[i]; + lines += out[i]; } - keys.push_back (lines.str ()); + keys.push_back (lines); } string device_list_description = recipient.subject_common_name (); @@ -320,13 +375,14 @@ DecryptedKDM::encrypt (shared_ptr signer, Certificate re signer, recipient, trusted_devices, - device_list_description, _keys.front().cpl_id (), _content_title_text, _annotation_text, _not_valid_before, _not_valid_after, formulation, + disable_forensic_marking_picture, + disable_forensic_marking_audio, key_ids, keys );