Major revamp of credential and trust handling code, PKIX engine still needs work.
[shibboleth/cpp-xmltooling.git] / xmltooling / encryption / impl / Encrypter.cpp
index 4f5b354..45e9e07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2006 Internet2
+ *  Copyright 2001-2007 Internet2
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include "internal.h"
 #include "encryption/Encrypter.h"
+#include "security/Credential.h"
 
-#include <xsec/enc/openssl/OpenSSLCryptoSymmetricKey.hpp>
 #include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/framework/XSECException.hpp>
+#include <xsec/framework/XSECAlgorithmMapper.hpp>
+#include <xsec/framework/XSECAlgorithmHandler.hpp>
 #include <xsec/xenc/XENCEncryptedData.hpp>
 #include <xsec/xenc/XENCEncryptedKey.hpp>
 
@@ -43,11 +45,11 @@ Encrypter::~Encrypter()
 void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
 {
     if (encParams.m_keyBufferSize==0) {
-        if (encParams.m_key) {
+        if (encParams.m_credential) {
             if (kencParams)
                 throw EncryptionException("Generating EncryptedKey inline requires the encryption key in raw form.");
         }
-        else if (!encParams.m_key) {
+        else if (!encParams.m_credential) {
             if (!kencParams)
                 throw EncryptionException("Using a generated encryption key requires a KeyEncryptionParams object.");
 
@@ -59,28 +61,27 @@ void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* ke
         }
     }
     
-    if (!encParams.m_key) {
+    XSECCryptoKey* key=NULL;
+    if (encParams.m_credential) {
+        key = encParams.m_credential->getPrivateKey();
+        if (!key)
+            throw EncryptionException("Credential in EncryptionParams structure did not supply a private/secret key.");
+        // Set the encryption key.
+        m_cipher->setKey(key->clone());
+    }
+    else {
         // We have to have a raw key now, so we need to build a wrapper around it.
-        if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURI3DES_CBC)) {
-            encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_3DES_192);
-        }
-        else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES128_CBC)) {
-            encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_128);
-        }
-        else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES192_CBC)) {
-            encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_192);
-        }
-        else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES256_CBC)) {
-            encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_256);
-        }
-        else {
-            throw EncryptionException("Unrecognized encryption algorithm, unable to build key wrapper.");
-        }
-        static_cast<OpenSSLCryptoSymmetricKey*>(encParams.m_key)->setKey(encParams.m_keyBuffer, encParams.m_keyBufferSize);
+        XSECAlgorithmHandler* handler =XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(encParams.m_algorithm);
+        if (handler != NULL)
+            key = handler->createKeyForURI(
+                encParams.m_algorithm,const_cast<unsigned char*>(encParams.m_keyBuffer),encParams.m_keyBufferSize
+                );
+
+        if (!key)
+            throw EncryptionException("Unable to build wrapper for key, unknown algorithm?");
+        // Set the encryption key.
+        m_cipher->setKey(key);
     }
-    
-    // Set the encryption key.
-    m_cipher->setKey(encParams.m_key->clone());
 }
 
 EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
@@ -92,8 +93,10 @@ EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams&
         m_cipher=NULL;
     }
     
-    if (!m_cipher)
+    if (!m_cipher) {
         m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
+        m_cipher->setExclusiveC14nSerialisation(false);
+    }
     
     try {
         checkParams(encParams,kencParams);
@@ -118,8 +121,10 @@ EncryptedData* Encrypter::encryptElementContent(DOMElement* element, EncryptionP
         m_cipher=NULL;
     }
     
-    if (!m_cipher)
+    if (!m_cipher) {
         m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
+        m_cipher->setExclusiveC14nSerialisation(false);
+    }
     
     try {
         checkParams(encParams,kencParams);
@@ -147,28 +152,22 @@ EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encPar
     DOMDocument* doc=NULL;
     try {
         doc=XMLToolingConfig::getConfig().getParser().newDocument();
+        XercesJanitor<DOMDocument> janitor(doc);
         m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
+        m_cipher->setExclusiveC14nSerialisation(false);
         
         checkParams(encParams,kencParams);
         StreamInputSource::StreamBinInputStream xstream(input);
         m_cipher->encryptBinInputStream(&xstream, ENCRYPT_NONE, encParams.m_algorithm);
-        EncryptedData* xmlEncData = decorateAndUnmarshall(encParams, kencParams);
-        doc->release();
-        return xmlEncData;
+        return decorateAndUnmarshall(encParams, kencParams);
     }
     catch(XSECException& e) {
-        doc->release();
         auto_ptr_char temp(e.getMsg());
         throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
     }
     catch(XSECCryptoException& e) {
-        doc->release();
         throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
     }
-    catch (...) {
-        doc->release();
-        throw;
-    }
 }
 
 EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
@@ -187,14 +186,17 @@ EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, Key
     xmlEncData->releaseThisAndChildrenDOM();
     
     // KeyInfo?
-    if (encParams.m_keyInfo) {
-        xmlEncData->setKeyInfo(encParams.m_keyInfo);
-        encParams.m_keyInfo=NULL;   // transfer ownership
-    }
+    const KeyInfo* kinfo = encParams.m_credential ? encParams.m_credential->getKeyInfo(encParams.m_compact) : NULL;
+    if (kinfo)
+        xmlEncData->setKeyInfo(kinfo->cloneKeyInfo());
     
     // Are we doing a key encryption?
     if (kencParams) {
-        m_cipher->setKEK(kencParams->m_key->clone());
+        XSECCryptoKey* kek = kencParams->m_credential.getPublicKey();
+        if (!kek)
+            throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
+
+        m_cipher->setKEK(kek->clone());
         // ownership of this belongs to us, for some reason...
         auto_ptr<XENCEncryptedKey> encKey(
             m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm)
@@ -206,19 +208,72 @@ EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, Key
         
         xmlEncKey->releaseThisAndChildrenDOM();
         
+        // Recipient?
+        if (kencParams->m_recipient)
+            xmlEncKey->setRecipient(kencParams->m_recipient);
+        
         // KeyInfo?
-        if (kencParams->m_keyInfo) {
-            xmlEncKey->setKeyInfo(kencParams->m_keyInfo);
-            kencParams->m_keyInfo=NULL;   // transfer ownership
-        }
+        kinfo = kencParams->m_credential.getKeyInfo(encParams.m_compact);
+        if (kinfo)
+            xmlEncKey->setKeyInfo(kinfo->cloneKeyInfo());
         
-        // Add the EncryptedKey.
+        // Add the EncryptedKey inline.
         if (!xmlEncData->getKeyInfo())
             xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo());
-        xmlEncData->getKeyInfo()->getOthers().push_back(xmlEncKey);
+        xmlEncData->getKeyInfo()->getUnknownXMLObjects().push_back(xmlEncKey);
         xmlObjectKey.release();
     }
     
     xmlObject.release();
     return xmlEncData;
 }
+
+EncryptedKey* Encrypter::encryptKey(const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact)
+{
+    // Get a fresh cipher object and document.
+
+    if (m_cipher) {
+        XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+        m_cipher=NULL;
+    }
+
+    XSECCryptoKey* kek = kencParams.m_credential.getPublicKey();
+    if (!kek)
+        throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
+
+    DOMDocument* doc=NULL;
+    try {
+        doc=XMLToolingConfig::getConfig().getParser().newDocument();
+        XercesJanitor<DOMDocument> janitor(doc);
+        m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
+        m_cipher->setExclusiveC14nSerialisation(false);
+        m_cipher->setKEK(kek->clone());
+        auto_ptr<XENCEncryptedKey> encKey(m_cipher->encryptKey(keyBuffer, keyBufferSize, ENCRYPT_NONE, kencParams.m_algorithm));
+        
+        EncryptedKey* xmlEncKey=NULL;
+        auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
+        if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
+            throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
+        
+        xmlEncKey->releaseThisAndChildrenDOM();
+        
+        // Recipient?
+        if (kencParams.m_recipient)
+            xmlEncKey->setRecipient(kencParams.m_recipient);
+
+        // KeyInfo?
+        const KeyInfo* kinfo = kencParams.m_credential.getKeyInfo(compact);
+        if (kinfo)
+            xmlEncKey->setKeyInfo(kinfo->cloneKeyInfo());
+
+        xmlObjectKey.release();
+        return xmlEncKey;
+    }
+    catch(XSECException& e) {
+        auto_ptr_char temp(e.getMsg());
+        throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
+    }
+    catch(XSECCryptoException& e) {
+        throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
+    }
+}