X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=xmltooling%2Fencryption%2Fimpl%2FDecrypter.cpp;h=3f4adb9acbf97a5cec0662fa762e6bf676c1dff0;hb=a0d768778a8f5f539b909baf5b115e70ea765f0f;hp=aaeed9d5bac48ba3e19b9cd5dbf7359f96bd8fde;hpb=6505807a62569ce65803b448b07a6872c6af2512;p=shibboleth%2Fcpp-xmltooling.git diff --git a/xmltooling/encryption/impl/Decrypter.cpp b/xmltooling/encryption/impl/Decrypter.cpp index aaeed9d..3f4adb9 100644 --- a/xmltooling/encryption/impl/Decrypter.cpp +++ b/xmltooling/encryption/impl/Decrypter.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,41 +21,61 @@ */ #include "internal.h" +#include "logging.h" #include "encryption/Decrypter.h" #include "encryption/EncryptedKeyResolver.h" +#include "encryption/Encryption.h" #include "security/Credential.h" #include "security/CredentialCriteria.h" #include "security/CredentialResolver.h" -#include #include #include #include #include +#include +#include #include #include using namespace xmlencryption; using namespace xmlsignature; using namespace xmltooling; +using namespace xercesc; using namespace std; +Decrypter::Decrypter(const CredentialResolver* credResolver, CredentialCriteria* criteria, const EncryptedKeyResolver* EKResolver) + : m_cipher(nullptr), m_credResolver(credResolver), m_criteria(criteria), m_EKResolver(EKResolver) +{ +} + Decrypter::~Decrypter() { if (m_cipher) XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); } +void Decrypter::setEncryptedKeyResolver(const EncryptedKeyResolver* EKResolver) +{ + m_EKResolver=EKResolver; +} + +void Decrypter::setKEKResolver(const CredentialResolver* resolver, CredentialCriteria* criteria) +{ + m_credResolver=resolver; + m_criteria=criteria; +} + DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key) { - if (encryptedData.getDOM()==NULL) + if (encryptedData.getDOM()==nullptr) throw DecryptionException("The object must be marshalled before decryption."); // We can reuse the cipher object if the document hasn't changed. if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) { XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); - m_cipher=NULL; + m_cipher=nullptr; } if (!m_cipher) @@ -86,25 +106,22 @@ DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, // Resolve a decryption key directly. vector creds; + int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES; if (m_criteria) { - m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); - m_criteria->setKeyInfo(encryptedData.getKeyInfo()); + m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL); + m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types); const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); - if (meth) { - auto_ptr_char alg(meth->getAlgorithm()); - m_criteria->setKeyAlgorithm(alg.get()); - } + if (meth) + m_criteria->setXMLAlgorithm(meth->getAlgorithm()); m_credResolver->resolve(creds,m_criteria); } else { CredentialCriteria criteria; - criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); - criteria.setKeyInfo(encryptedData.getKeyInfo()); + criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL); + criteria.setKeyInfo(encryptedData.getKeyInfo(), types); const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); - if (meth) { - auto_ptr_char alg(meth->getAlgorithm()); - criteria.setKeyAlgorithm(alg.get()); - } + if (meth) + criteria.setXMLAlgorithm(meth->getAlgorithm()); m_credResolver->resolve(creds,&criteria); } @@ -118,18 +135,18 @@ DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, return decryptData(encryptedData, key); } catch(DecryptionException& ex) { - log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what()); + logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what()); } } // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm... const XMLCh* algorithm= - encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL; + encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : nullptr; if (!algorithm) throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed."); // Check for external resolver. - const EncryptedKey* encKey=NULL; + const EncryptedKey* encKey=nullptr; if (m_EKResolver) encKey = m_EKResolver->resolveKey(encryptedData, recipient); else { @@ -146,70 +163,186 @@ DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, return decryptData(encryptedData, keywrapper.get()); } +void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key) +{ + if (encryptedData.getDOM()==nullptr) + throw DecryptionException("The object must be marshalled before decryption."); + + // We can reuse the cipher object if the document hasn't changed. + + if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) { + XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); + m_cipher=nullptr; + } + + if (!m_cipher) + m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); + + try { + m_cipher->setKey(key->clone()); + auto_ptr in(m_cipher->decryptToBinInputStream(encryptedData.getDOM())); + + XMLByte buf[8192]; + xsecsize_t count = in->readBytes(buf, sizeof(buf)); + while (count > 0) + out.write(reinterpret_cast(buf),count); + } + catch(XSECException& e) { + auto_ptr_char temp(e.getMsg()); + throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get()); + } + catch(XSECCryptoException& e) { + throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg()); + } +} + +void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, const XMLCh* recipient) +{ + if (!m_credResolver) + throw DecryptionException("No CredentialResolver supplied to provide decryption keys."); + + // Resolve a decryption key directly. + vector creds; + int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES; + if (m_criteria) { + m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL); + m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types); + const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); + if (meth) + m_criteria->setXMLAlgorithm(meth->getAlgorithm()); + m_credResolver->resolve(creds,m_criteria); + } + else { + CredentialCriteria criteria; + criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL); + criteria.setKeyInfo(encryptedData.getKeyInfo(), types); + const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); + if (meth) + criteria.setXMLAlgorithm(meth->getAlgorithm()); + m_credResolver->resolve(creds,&criteria); + } + + // Loop over them and try each one. + XSECCryptoKey* key; + for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) { + try { + key = (*cred)->getPrivateKey(); + if (!key) + continue; + return decryptData(out, encryptedData, key); + } + catch(DecryptionException& ex) { + logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what()); + } + } + + // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm... + const XMLCh* algorithm= + encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : nullptr; + if (!algorithm) + throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed."); + + // Check for external resolver. + const EncryptedKey* encKey=nullptr; + if (m_EKResolver) + encKey = m_EKResolver->resolveKey(encryptedData, recipient); + else { + EncryptedKeyResolver ekr; + encKey = ekr.resolveKey(encryptedData, recipient); + } + + if (!encKey) + throw DecryptionException("Unable to locate an encrypted key."); + + auto_ptr keywrapper(decryptKey(*encKey, algorithm)); + if (!keywrapper.get()) + throw DecryptionException("Unable to decrypt the encrypted key."); + decryptData(out, encryptedData, keywrapper.get()); +} + XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm) { if (!m_credResolver) throw DecryptionException("No CredentialResolver supplied to provide decryption keys."); - if (encryptedKey.getDOM()==NULL) + if (encryptedKey.getDOM()==nullptr) throw DecryptionException("The object must be marshalled before decryption."); + + XSECAlgorithmHandler* handler; + try { + handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm); + if (!handler) + throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key."); + } + catch(XSECException& e) { + auto_ptr_char temp(e.getMsg()); + throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get()); + } + catch(XSECCryptoException& e) { + throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg()); + } // We can reuse the cipher object if the document hasn't changed. if (m_cipher && m_cipher->getDocument()!=encryptedKey.getDOM()->getOwnerDocument()) { XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); - m_cipher=NULL; + m_cipher=nullptr; } if (!m_cipher) m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument()); - // Resolve key decryption key. We can't loop over possible credentials because - // we can't tell a valid decrypt from an invalid one. - const Credential* cred=NULL; + // Resolve key decryption keys. + int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES; + vector creds; if (m_criteria) { - m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); - m_criteria->setKeyInfo(encryptedKey.getKeyInfo()); + m_criteria->setUsage(Credential::ENCRYPTION_CREDENTIAL); + m_criteria->setKeyInfo(encryptedKey.getKeyInfo(), types); const EncryptionMethod* meth = encryptedKey.getEncryptionMethod(); - if (meth) { - auto_ptr_char alg(meth->getAlgorithm()); - m_criteria->setKeyAlgorithm(alg.get()); - } - cred = m_credResolver->resolve(m_criteria); + if (meth) + m_criteria->setXMLAlgorithm(meth->getAlgorithm()); + m_credResolver->resolve(creds, m_criteria); } else { CredentialCriteria criteria; - criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); - criteria.setKeyInfo(encryptedKey.getKeyInfo()); + criteria.setUsage(Credential::ENCRYPTION_CREDENTIAL); + criteria.setKeyInfo(encryptedKey.getKeyInfo(), types); const EncryptionMethod* meth = encryptedKey.getEncryptionMethod(); - if (meth) { - auto_ptr_char alg(meth->getAlgorithm()); - criteria.setKeyAlgorithm(alg.get()); - } - cred = m_credResolver->resolve(&criteria); + if (meth) + criteria.setXMLAlgorithm(meth->getAlgorithm()); + m_credResolver->resolve(creds, &criteria); } - if (!cred || !cred->getPrivateKey()) - throw DecryptionException("Unable to resolve a key decryption key."); + if (creds.empty()) + throw DecryptionException("Unable to resolve any key decryption keys."); - try { - m_cipher->setKEK(cred->getPrivateKey()->clone()); - XMLByte buffer[1024]; - memset(buffer,0,sizeof(buffer)); - int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024); - if (keySize<=0) - throw DecryptionException("Unable to decrypt key."); - - // Try to map the key. - XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm); - if (handler != NULL) - return handler->createKeyForURI(algorithm, buffer, keySize); - throw DecryptionException("Unrecognized algorithm, could not build object around decrypted key."); - } - catch(XSECException& e) { - auto_ptr_char temp(e.getMsg()); - throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get()); - } - catch(XSECCryptoException& e) { - throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg()); + XMLByte buffer[1024]; + for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) { + try { + if (!(*cred)->getPrivateKey()) + throw DecryptionException("Credential did not contain a private key."); + memset(buffer,0,sizeof(buffer)); + m_cipher->setKEK((*cred)->getPrivateKey()->clone()); + + try { + int keySize = m_cipher->decryptKey(encryptedKey.getDOM(), buffer, 1024); + if (keySize<=0) + throw DecryptionException("Unable to decrypt key."); + + // Try to wrap the key. + return handler->createKeyForURI(algorithm, buffer, keySize); + } + catch(XSECException& e) { + auto_ptr_char temp(e.getMsg()); + throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + temp.get()); + } + catch(XSECCryptoException& e) { + throw DecryptionException(string("XMLSecurity exception while decrypting key: ") + e.getMsg()); + } + } + catch(DecryptionException& ex) { + logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what()); + } } + + throw DecryptionException("Unable to decrypt key."); }