Merge master
[libdcp.git] / src / util.cc
index 6769cc41f86debfbf31555c30c59e068c6e0af9d..8277b2bf0893f46f17b1b94c24c1cf8e87c8f3db 100644 (file)
 #include <iomanip>
 #include <boost/filesystem.hpp>
 #include <openssl/sha.h>
+#include <libxml++/nodes/element.h>
+#include <libxml++/document.h>
+#include <xmlsec/xmldsig.h>
+#include <xmlsec/dl.h>
+#include <xmlsec/app.h>
 #include "KM_util.h"
 #include "KM_fileio.h"
 #include "AS_DCP.h"
 #include "types.h"
 #include "argb_frame.h"
 #include "lut.h"
+#include "certificates.h"
 
 using std::string;
+using std::cout;
 using std::stringstream;
 using std::min;
 using std::max;
+using std::list;
 using boost::shared_ptr;
 using namespace libdcp;
 
@@ -91,7 +99,6 @@ libdcp::make_digest (string filename)
        byte_t byte_buffer[20];
        SHA1_Final (byte_buffer, &sha);
 
-       stringstream s;
        char digest[64];
        return Kumu::base64encode (byte_buffer, 20, digest, 64);
 }
@@ -277,3 +284,131 @@ libdcp::empty_or_white_space (string s)
 
        return true;
 }
+
+void
+libdcp::init ()
+{
+       if (xmlSecInit() < 0) {
+               throw MiscError ("could not initialise xmlsec");
+       }
+
+#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING
+       if (xmlSecCryptoDLLoadLibrary (BAD_CAST XMLSEC_CRYPTO) < 0) {
+               throw MiscError ("unable to load default xmlsec-crypto library");
+       }
+#endif
+       
+       if (xmlSecCryptoAppInit (0) < 0) {
+               throw MiscError ("could not initialise crypto library");
+       }
+       
+       if (xmlSecCryptoInit() < 0) {
+               throw MiscError ("could not initialise xmlsec-crypto");
+       }
+}
+
+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(
+                               Certificate::name_for_xml ((*i)->issuer())
+                               );
+                       serial->add_child("X509SerialNumber", ns)->add_child_text((*i)->serial());
+               }
+               
+               data->add_child("X509Certificate", ns)->add_child_text((*i)->certificate());
+       }
+
+       xmlSecKeysMngrPtr keys_manager = xmlSecKeysMngrCreate();
+       if (!keys_manager) {
+               throw MiscError ("could not create keys manager");
+       }
+       if (xmlSecCryptoAppDefaultKeysMngrInit (keys_manager) < 0) {
+               throw MiscError ("could not initialise keys manager");
+       }
+       
+       xmlSecKeyPtr const key = xmlSecCryptoAppKeyLoad (signer_key.c_str(), xmlSecKeyDataFormatPem, 0, 0, 0);
+       if (key == 0) {
+               throw MiscError ("could not load signer key");
+               }
+       
+       if (xmlSecCryptoAppDefaultKeysMngrAdoptKey (keys_manager, key) < 0) {
+               xmlSecKeyDestroy (key);
+               throw MiscError ("could not use signer key");
+       }
+       
+       xmlSecDSigCtx signature_context;
+       
+       if (xmlSecDSigCtxInitialize (&signature_context, keys_manager) < 0) {
+               throw MiscError ("could not initialise XMLSEC context");
+       }
+       
+       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 (
+                               Certificate::name_for_xml (certificates.leaf()->issuer())
+                               );
+                       serial_element->add_child("X509SerialNumber", ns)->add_child_text (
+                               certificates.leaf()->serial()
+                               );
+               }
+               
+               data->add_child("X509SubjectName", ns)->add_child_text (Certificate::name_for_xml (certificates.leaf()->subject()));
+       }
+}
+
+void
+libdcp::sign (xmlpp::Element* parent, CertificateChain const & certificates, string const & signer_key)
+{
+       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");
+               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");
+               }
+       }
+       
+       add_signature_value (signature, certificates, signer_key, "dsig");
+}
+