X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=xmltooling%2Fencryption%2Fimpl%2FDecrypter.cpp;h=47ed588ea5f4c39fb64e2a1d8cdbc834ea395064;hb=64dcaec957e9befd960779498d7fe35bbb62141a;hp=7a8d5533700dd73dacd8ed064421e5582aecd87c;hpb=1f87cef41f9948492e13d3d9dc1495652606c441;p=shibboleth%2Fcpp-xmltooling.git diff --git a/xmltooling/encryption/impl/Decrypter.cpp b/xmltooling/encryption/impl/Decrypter.cpp index 7a8d553..47ed588 100644 --- a/xmltooling/encryption/impl/Decrypter.cpp +++ b/xmltooling/encryption/impl/Decrypter.cpp @@ -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. @@ -21,14 +21,18 @@ */ #include "internal.h" +#include "logging.h" #include "encryption/Decrypter.h" #include "encryption/EncryptedKeyResolver.h" +#include "security/Credential.h" +#include "security/CredentialCriteria.h" +#include "security/CredentialResolver.h" -#include #include #include #include #include +#include #include #include @@ -41,75 +45,26 @@ Decrypter::~Decrypter() { if (m_cipher) XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); - delete m_resolver; - delete m_KEKresolver; } -DOMDocumentFragment* Decrypter::decryptData(EncryptedData* encryptedData) +DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, XSECCryptoKey* key) { - if (encryptedData->getDOM()==NULL) + if (encryptedData.getDOM()==NULL) 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()) { + if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) { XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); m_cipher=NULL; } if (!m_cipher) - m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData->getDOM()->getOwnerDocument()); - - try { - // Resolve decryption key. - XSECCryptoKey* key=NULL; - if (m_resolver) - key=m_resolver->resolveKey(encryptedData->getKeyInfo()); - - if (!key && m_KEKresolver) { - // See if there's an encrypted key available. We'll need the algorithm... - const XMLCh* algorithm= - encryptedData->getEncryptionMethod() ? encryptedData->getEncryptionMethod()->getAlgorithm() : NULL; - if (!algorithm) - throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed."); - - if (encryptedData->getKeyInfo()) { - const vector& others=const_cast(encryptedData->getKeyInfo())->getUnknownXMLObjects(); - for (vector::const_iterator i=others.begin(); i!=others.end(); i++) { - EncryptedKey* encKey=dynamic_cast(*i); - if (encKey) { - try { - key=decryptKey(encKey, algorithm); - } - catch (DecryptionException& e) { - log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(e.what()); - } - } - } - } - - if (!key) { - // Check for a non-trivial resolver. - EncryptedKeyResolver* ekr=dynamic_cast(m_resolver); - if (ekr) { - EncryptedKey* encKey=ekr->resolveKey(encryptedData); - if (encKey) { - try { - key=decryptKey(encKey, algorithm); - } - catch (DecryptionException& e) { - log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(e.what()); - } - } - } - } - } + m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); - if (!key) - throw DecryptionException("Unable to resolve a decryption key."); - - m_cipher->setKey(key); - DOMNode* ret=m_cipher->decryptElementDetached(encryptedData->getDOM()); + try { + m_cipher->setKey(key->clone()); + DOMNode* ret=m_cipher->decryptElementDetached(encryptedData.getDOM()); if (ret->getNodeType()!=DOMNode::DOCUMENT_FRAGMENT_NODE) { ret->release(); throw DecryptionException("Decryption operation did not result in DocumentFragment."); @@ -125,40 +80,96 @@ DOMDocumentFragment* Decrypter::decryptData(EncryptedData* encryptedData) } } -XSECCryptoKey* Decrypter::decryptKey(EncryptedKey* encryptedKey, const XMLCh* algorithm) +DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const XMLCh* recipient) { - if (encryptedKey->getDOM()==NULL) - throw DecryptionException("The object must be marshalled before decryption."); + 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 | + CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES; + if (m_criteria) { + m_criteria->setUsage(CredentialCriteria::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(CredentialCriteria::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(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() : NULL; + if (!algorithm) + throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed."); + // Check for external resolver. + const EncryptedKey* encKey=NULL; + 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."); + return decryptData(encryptedData, keywrapper.get()); +} + +void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key) +{ + if (encryptedData.getDOM()==NULL) + 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()!=encryptedKey->getDOM()->getOwnerDocument()) { + if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) { XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); m_cipher=NULL; } if (!m_cipher) - m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey->getDOM()->getOwnerDocument()); - + m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); + try { - // Resolve key decryption key. - XSECCryptoKey* key=NULL; - if (m_KEKresolver) - key=m_KEKresolver->resolveKey(encryptedKey->getKeyInfo()); - if (!key) - throw DecryptionException("Unable to resolve a key decryption key."); - m_cipher->setKEK(key); + m_cipher->setKey(key->clone()); + auto_ptr in(m_cipher->decryptToBinInputStream(encryptedData.getDOM())); - XMLByte buffer[1024]; - int keySize = m_cipher->decryptKey(encryptedKey->getDOM(), buffer, 1024); - if (keySize > 0) { - // 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."); - } - throw DecryptionException("Unable to decrypt key."); + XMLByte buf[8192]; + unsigned int count = in->readBytes(buf, sizeof(buf)); + while (count > 0) + out.write(reinterpret_cast(buf),count); } catch(XSECException& e) { auto_ptr_char temp(e.getMsg()); @@ -168,3 +179,150 @@ XSECCryptoKey* Decrypter::decryptKey(EncryptedKey* encryptedKey, const XMLCh* al 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 | + CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES; + if (m_criteria) { + m_criteria->setUsage(CredentialCriteria::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(CredentialCriteria::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() : NULL; + if (!algorithm) + throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed."); + + // Check for external resolver. + const EncryptedKey* encKey=NULL; + 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) + throw DecryptionException("The object must be marshalled before decryption."); + + XSECAlgorithmHandler* handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm); + if (!handler) + throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key."); + + // 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; + } + + if (!m_cipher) + m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument()); + + // Resolve key decryption keys. + int types = + CredentialCriteria::KEYINFO_EXTRACTION_KEY | + CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES | + CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES; + vector creds; + if (m_criteria) { + m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); + m_criteria->setKeyInfo(encryptedKey.getKeyInfo(), types); + const EncryptionMethod* meth = encryptedKey.getEncryptionMethod(); + 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(), types); + const EncryptionMethod* meth = encryptedKey.getEncryptionMethod(); + if (meth) + criteria.setXMLAlgorithm(meth->getAlgorithm()); + m_credResolver->resolve(creds, &criteria); + } + if (creds.empty()) + throw DecryptionException("Unable to resolve any key decryption keys."); + + 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."); +}