2 Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <openssl/rsa.h>
22 #include <openssl/pem.h>
23 #include <libcxml/cxml.h>
26 #include "exceptions.h"
30 using std::stringstream;
34 using boost::shared_ptr;
35 using namespace libdcp;
37 KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
39 /* Read the private key */
41 FILE* private_key_file = fopen (private_key.string().c_str(), "r");
42 if (!private_key_file) {
43 throw FileError ("could not find RSA private key file", private_key.string ());
46 RSA* rsa = PEM_read_RSAPrivateKey (private_key_file, 0, 0, 0);
47 fclose (private_key_file);
49 throw FileError ("could not read RSA private key file", private_key.string ());
53 /* Read the KDM, decrypting it */
55 cxml::File f (kdm.string (), "DCinemaSecurityMessage");
57 shared_ptr<cxml::Node> authenticated_private = f.node_child ("AuthenticatedPrivate");
58 list<shared_ptr<cxml::Node> > encrypted_keys = authenticated_private->node_children ("EncryptedKey");
60 for (list<shared_ptr<cxml::Node> >::iterator i = encrypted_keys.begin(); i != encrypted_keys.end(); ++i) {
62 /* Get the base-64-encoded cipher value from the KDM */
63 shared_ptr<cxml::Node> cipher_data = (*i)->node_child ("CipherData");
64 shared_ptr<cxml::Node> cipher_value_base64 = cipher_data->node_child ("CipherValue");
66 /* Decode it from base-64 */
67 unsigned char cipher_value[256];
68 ui32_t cipher_value_len;
69 if (Kumu::base64decode (cipher_value_base64->content().c_str(), cipher_value, sizeof (cipher_value), &cipher_value_len)) {
71 throw MiscError ("could not base-64-decode CipherValue from KDM");
75 unsigned char decrypted[256];
76 unsigned int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
77 assert (decrypted_len < sizeof (decrypted));
79 _ciphers.push_back (KDMCipher (decrypted, decrypted_len));
86 KDMCipher::KDMCipher (unsigned char const * raw, int len)
91 _structure_id = get (&raw, 16);
92 _signer_thumbprint = get (&raw, 20);
93 _cpl_id = get_uuid (&raw, 16);
94 _key_id = get_uuid (&raw, 16);
95 _not_valid_before = get (&raw, 25);
96 _not_valid_after = get (&raw, 25);
97 _key_data = get_hex (&raw, 16);
101 _structure_id = get (&raw, 16);
102 _signer_thumbprint = get (&raw, 20);
103 _cpl_id = get_uuid (&raw, 16);
104 _key_type = get (&raw, 4);
105 _key_id = get_uuid (&raw, 16);
106 _not_valid_before = get (&raw, 25);
107 _not_valid_after = get (&raw, 25);
108 _key_data = get_hex (&raw, 16);
116 KDMCipher::get (unsigned char const ** p, int N) const
119 for (int i = 0; i < N; ++i) {
128 KDMCipher::get_uuid (unsigned char const ** p, int N) const
132 for (int i = 0; i < N; ++i) {
133 g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
135 if (i == 3 || i == 5 || i == 7 || i == 9) {
144 KDMCipher::get_hex (unsigned char const ** p, int N) const
148 for (int i = 0; i < N; ++i) {
149 g << setw(2) << setfill('0') << hex << static_cast<int> (**p);