#include <xmlsec/xmldsig.h>
#include <xmlsec/dl.h>
#include <xmlsec/app.h>
+#include <xmlsec/crypto.h>
#include "KM_util.h"
#include "KM_fileio.h"
#include "AS_DCP.h"
using std::min;
using std::max;
using std::list;
+using std::setw;
+using std::setfill;
using boost::shared_ptr;
using boost::lexical_cast;
using namespace libdcp;
/** Create a digest for a file.
* @param filename File name.
+ * @param progress Pointer to a progress reporting function, or 0. The function will be called
+ * with a progress value between 0 and 1.
* @return Digest.
*/
string
-libdcp::make_digest (string filename)
+libdcp::make_digest (string filename, boost::function<void (float)>* progress)
{
Kumu::FileReader reader;
if (ASDCP_FAILURE (reader.OpenRead (filename.c_str ()))) {
SHA_CTX sha;
SHA1_Init (&sha);
-
- Kumu::ByteString read_buffer (65536);
+
+ int const buffer_size = 65536;
+ Kumu::ByteString read_buffer (buffer_size);
+
+ Kumu::fsize_t done = 0;
+ Kumu::fsize_t const size = reader.Size ();
while (1) {
ui32_t read = 0;
Kumu::Result_t r = reader.Read (read_buffer.Data(), read_buffer.Capacity(), &read);
}
SHA1_Update (&sha, read_buffer.Data(), read);
+
+ if (progress) {
+ (*progress) (float (done) / size);
+ done += read;
+ }
}
- byte_t byte_buffer[20];
+ byte_t byte_buffer[SHA_DIGEST_LENGTH];
SHA1_Final (byte_buffer, &sha);
char digest[64];
- return Kumu::base64encode (byte_buffer, 20, digest, 64);
+ return Kumu::base64encode (byte_buffer, SHA_DIGEST_LENGTH, digest, 64);
}
/** Convert a content kind to a string which can be used in a
if (xmlSecInit() < 0) {
throw MiscError ("could not initialise xmlsec");
}
-}
-void
-libdcp::add_signature_value (xmlpp::Element* parent, CertificateChain const & certificates, string const & signer_key, string const & ns)
-{
- parent->add_child("SignatureValue", ns);
-
- xmlpp::Element* key_info = parent->add_child("KeyInfo", ns);
- list<shared_ptr<Certificate> > c = certificates.leaf_to_root ();
- for (list<shared_ptr<Certificate> >::iterator i = c.begin(); i != c.end(); ++i) {
- xmlpp::Element* data = key_info->add_child("X509Data", ns);
-
- {
- xmlpp::Element* serial = data->add_child("X509IssuerSerial", ns);
- serial->add_child("X509IssuerName", ns)->add_child_text((*i)->issuer ());
- serial->add_child("X509SerialNumber", ns)->add_child_text((*i)->serial ());
- }
-
- data->add_child("X509Certificate", ns)->add_child_text((*i)->certificate());
+#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
+ if (xmlSecCryptoDLLoadLibrary(BAD_CAST XMLSEC_CRYPTO) < 0) {
+ throw MiscError ("unable to load default xmlsec-crypto library");
}
+#endif
- xmlSecKeysMngrPtr keys_manager = xmlSecKeysMngrCreate();
- if (!keys_manager) {
- throw MiscError ("could not create keys manager");
- }
-
- xmlSecDSigCtx signature_context;
-
- if (xmlSecDSigCtxInitialize (&signature_context, keys_manager) < 0) {
- throw MiscError ("could not initialise XMLSEC context");
+ if (xmlSecCryptoAppInit(0) < 0) {
+ throw MiscError ("could not initialise crypto");
}
-
- if (xmlSecDSigCtxSign (&signature_context, parent->cobj()) < 0) {
- throw MiscError ("could not sign");
- }
-
- xmlSecDSigCtxFinalize (&signature_context);
- xmlSecKeysMngrDestroy (keys_manager);
-}
-
-
-void
-libdcp::add_signer (xmlpp::Element* parent, CertificateChain const & certificates, string const & ns)
-{
- xmlpp::Element* signer = parent->add_child("Signer");
-
- {
- xmlpp::Element* data = signer->add_child("X509Data", ns);
-
- {
- xmlpp::Element* serial_element = data->add_child("X509IssuerSerial", ns);
- serial_element->add_child("X509IssuerName", ns)->add_child_text (certificates.leaf()->issuer());
- serial_element->add_child("X509SerialNumber", ns)->add_child_text (certificates.leaf()->serial());
- }
-
- data->add_child("X509SubjectName", ns)->add_child_text (certificates.leaf()->subject());
- }
-}
-void
-libdcp::sign (xmlpp::Element* parent, CertificateChain const & certificates, string const & signer_key, bool interop)
-{
- add_signer (parent, certificates, "dsig");
-
- xmlpp::Element* signature = parent->add_child("Signature", "dsig");
-
- {
- xmlpp::Element* signed_info = signature->add_child ("SignedInfo", "dsig");
- signed_info->add_child("CanonicalizationMethod", "dsig")->set_attribute ("Algorithm", "http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
-
- if (interop) {
- signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#rsa-sha1");
- } else {
- signed_info->add_child("SignatureMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
- }
-
- {
- xmlpp::Element* reference = signed_info->add_child("Reference", "dsig");
- reference->set_attribute ("URI", "");
- {
- xmlpp::Element* transforms = reference->add_child("Transforms", "dsig");
- transforms->add_child("Transform", "dsig")->set_attribute (
- "Algorithm", "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
- );
- }
- reference->add_child("DigestMethod", "dsig")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
- /* This will be filled in by the signing later */
- reference->add_child("DigestValue", "dsig");
- }
+ if (xmlSecCryptoInit() < 0) {
+ throw MiscError ("could not initialise xmlsec-crypto");
}
-
- add_signature_value (signature, certificates, signer_key, "dsig");
}
bool libdcp::operator== (libdcp::Size const & a, libdcp::Size const & b)
return N;
}
+
+string
+libdcp::tm_to_string (struct tm* tm)
+{
+ char buffer[64];
+ strftime (buffer, 64, "%Y-%m-%dT%I:%M:%S", tm);
+
+ int offset = 0;
+
+#ifdef LIBDCP_POSIX
+ offset = tm->tm_gmtoff / 60;
+#else
+ TIME_ZONE_INFORMATION tz;
+ GetTimeZoneInformation (&tz);
+ offset = tz.Bias;
+#endif
+
+ return string (buffer) + utc_offset_to_string (offset);
+}
+
+/** @param b Offset from UTC to local time in minutes.
+ * @return string of the form e.g. -01:00.
+ */
+string
+libdcp::utc_offset_to_string (int b)
+{
+ bool const negative = (b < 0);
+ b = negative ? -b : b;
+
+ int const hours = b / 60;
+ int const minutes = b % 60;
+
+ stringstream o;
+ if (negative) {
+ o << "-";
+ } else {
+ o << "+";
+ }
+
+ o << setw(2) << setfill('0') << hours << ":" << setw(2) << setfill('0') << minutes;
+ return o.str ();
+}
+
+string
+libdcp::ptime_to_string (boost::posix_time::ptime t)
+{
+ struct tm t_tm = boost::posix_time::to_tm (t);
+ return tm_to_string (&t_tm);
+}