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);
161 for (
auto const& i: kdm.
keys()) {
163 unsigned char cipher_value[256];
164 int const cipher_value_len =
base64_decode (i, cipher_value,
sizeof (cipher_value));
167 auto decrypted =
new unsigned char[RSA_size(rsa)];
168 int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
169 if (decrypted_len == -1) {
171 #if OPENSSL_VERSION_NUMBER > 0x10100000L
172 throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, RSA_bits(rsa));
174 throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0), cipher_value_len, rsa->n->dmax);
181 unsigned char* p = decrypted;
182 switch (decrypted_len) {
191 string const cpl_id = get_uuid (&p);
193 string const key_id = get_uuid (&p);
195 not_valid_before =
dcp::LocalTime(std::string(
reinterpret_cast<char*
>(p), 25));
198 not_valid_after =
dcp::LocalTime(std::string(
reinterpret_cast<char*
>(p), 25));
201 add_key (optional<string>(), key_id,
Key(p), cpl_id, Standard::INTEROP);
208 DCP_ASSERT (memcmp (p, smpte_structure_id, 16) == 0);
213 string const cpl_id = get_uuid (&p);
215 string const key_type = get (&p, 4);
217 string const key_id = get_uuid (&p);
219 not_valid_before =
dcp::LocalTime(std::string(
reinterpret_cast<char*
>(p), 25));
222 not_valid_after =
dcp::LocalTime(std::string(
reinterpret_cast<char*
>(p), 25));
225 add_key (key_type, key_id,
Key(p), cpl_id, Standard::SMPTE);
235 _not_valid_before = not_valid_before;
236 _not_valid_after = not_valid_after;
239 if (not_valid_before != _not_valid_before || not_valid_after != _not_valid_after) {
248 _annotation_text = kdm.annotation_text ();
249 _content_title_text = kdm.content_title_text ();
250 _issue_date = kdm.issue_date ();
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)
273 map<shared_ptr<const ReelFileAsset>,
Key> keys,
276 string annotation_text,
277 string content_title_text,
280 : _not_valid_before (not_valid_before)
281 , _not_valid_after (not_valid_after)
282 , _annotation_text (annotation_text)
283 , _content_title_text (content_title_text)
284 , _issue_date (issue_date)
286 for (
auto const& i:
keys) {
287 add_key (i.first->key_type(), i.first->key_id().get(), i.second, cpl_id, Standard::SMPTE);
293 shared_ptr<const CPL> cpl,
297 string annotation_text,
298 string content_title_text,
301 : _not_valid_before (not_valid_before)
302 , _not_valid_after (not_valid_after)
303 , _annotation_text (annotation_text)
304 , _content_title_text (content_title_text)
305 , _issue_date (issue_date)
308 bool did_one =
false;
309 for (
auto i: cpl->reel_file_assets()) {
310 if (i->encryptable()) {
311 add_key (i->key_type().get(), i->key_id().get(), key, cpl->id(), Standard::SMPTE);
325 _keys.push_back (
DecryptedKDMKey (type, key_id, key, cpl_id, standard));
332 _keys.push_back (key);
338 shared_ptr<const CertificateChain> signer,
340 vector<string> trusted_devices,
341 Formulation formulation,
342 bool disable_forensic_marking_picture,
343 optional<int> disable_forensic_marking_audio
346 DCP_ASSERT (!_keys.empty ());
348 for (
auto i: signer->leaf_to_root()) {
356 vector<pair<string, string>> key_ids;
358 for (
auto const& i: _keys) {
360 DCP_ASSERT (i.type());
361 key_ids.push_back (make_pair (i.type().get(), i.id ()));
367 put (&p, smpte_structure_id, 16);
372 put_uuid (&p, i.cpl_id ());
373 put (&p, i.type().get());
374 put_uuid (&p, i.id ());
375 put (&p, _not_valid_before.
as_string ());
377 put (&p, i.key().value(), ASDCP::KeyLen);
381 unsigned char encrypted[RSA_size(rsa)];
382 int const encrypted_len = RSA_public_encrypt (p - block, block, encrypted, rsa, RSA_PKCS1_OAEP_PADDING);
383 if (encrypted_len == -1) {
384 throw MiscError (String::compose (
"Could not encrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
388 char out[encrypted_len * 2];
389 Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
390 int const N = strlen (out);
392 for (
int i = 0; i < N; ++i) {
393 if (i > 0 && (i % 64) == 0) {
399 keys.push_back (lines);
406 _keys.front().cpl_id (),
412 disable_forensic_marking_picture,
413 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, bool with_timezone=true) 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.