X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=xmltooling%2Fencryption%2Fimpl%2FDecrypter.cpp;h=ce9445f51d73e5ba2872a610e935ff62455f1480;hb=4189e5d4286de20f61077bc202eaf3772bc66748;hp=b29ca1328886a1bf6cd7b219e90cc545190af703;hpb=a5e86d37cf40004e6a43a21ab67d26695fa8619c;p=shibboleth%2Fcpp-xmltooling.git diff --git a/xmltooling/encryption/impl/Decrypter.cpp b/xmltooling/encryption/impl/Decrypter.cpp index b29ca13..ce9445f 100644 --- a/xmltooling/encryption/impl/Decrypter.cpp +++ b/xmltooling/encryption/impl/Decrypter.cpp @@ -1,17 +1,21 @@ -/* - * 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. - * You may obtain a copy of the License at +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the + * License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the License. */ /** @@ -24,6 +28,7 @@ #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" @@ -33,6 +38,7 @@ #include #include #include +#include #include #include @@ -42,30 +48,60 @@ using namespace xmltooling; using namespace xercesc; using namespace std; + +Decrypter::Decrypter( + const CredentialResolver* credResolver, + CredentialCriteria* criteria, + const EncryptedKeyResolver* EKResolver, + bool requireAuthenticatedCipher + ) : m_cipher(nullptr), m_credResolver(credResolver), m_criteria(criteria), m_EKResolver(EKResolver), + m_requireAuthenticatedCipher(requireAuthenticatedCipher) +{ +} + 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."); + XMLToolingInternalConfig& xmlconf = XMLToolingInternalConfig::getInternalConfig(); + if (m_requireAuthenticatedCipher) { + const XMLCh* alg = encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : nullptr; + if (!alg || !xmlconf.isXMLAlgorithmSupported(alg, XMLToolingConfig::ALGTYPE_AUTHNENCRYPT)) { + throw DecryptionException("Unauthenticated data encryption algorithm unsupported."); + } + } + // 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; + xmlconf.m_xsecProvider->releaseCipher(m_cipher); + m_cipher=nullptr; } if (!m_cipher) - m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); + m_cipher = xmlconf.m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); try { m_cipher->setKey(key->clone()); - DOMNode* ret=m_cipher->decryptElementDetached(encryptedData.getDOM()); + 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."); @@ -95,7 +131,7 @@ DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); if (meth) m_criteria->setXMLAlgorithm(meth->getAlgorithm()); - m_credResolver->resolve(creds,m_criteria); + m_credResolver->resolve(creds, m_criteria); } else { CredentialCriteria criteria; @@ -104,12 +140,12 @@ DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); if (meth) criteria.setXMLAlgorithm(meth->getAlgorithm()); - m_credResolver->resolve(creds,&criteria); + 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) { + for (vector::const_iterator cred = creds.begin(); cred != creds.end(); ++cred) { try { key = (*cred)->getPrivateKey(); if (!key) @@ -123,12 +159,12 @@ DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, // 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 { @@ -147,18 +183,26 @@ DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key) { - if (encryptedData.getDOM()==NULL) + if (encryptedData.getDOM() == nullptr) throw DecryptionException("The object must be marshalled before decryption."); + XMLToolingInternalConfig& xmlconf = XMLToolingInternalConfig::getInternalConfig(); + if (m_requireAuthenticatedCipher) { + const XMLCh* alg = encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : nullptr; + if (!alg || !xmlconf.isXMLAlgorithmSupported(alg, XMLToolingConfig::ALGTYPE_AUTHNENCRYPT)) { + throw DecryptionException("Unauthenticated data encryption algorithm unsupported."); + } + } + // 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; + if (m_cipher && m_cipher->getDocument() != encryptedData.getDOM()->getOwnerDocument()) { + xmlconf.m_xsecProvider->releaseCipher(m_cipher); + m_cipher = nullptr; } if (!m_cipher) - m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); + m_cipher = xmlconf.m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); try { m_cipher->setKey(key->clone()); @@ -206,7 +250,7 @@ void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, co // Loop over them and try each one. XSECCryptoKey* key; - for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) { + for (vector::const_iterator cred = creds.begin(); cred != creds.end(); ++cred) { try { key = (*cred)->getPrivateKey(); if (!key) @@ -220,12 +264,12 @@ void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, co // 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 { @@ -247,22 +291,32 @@ XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XML 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 = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithm); - if (!handler) - throw DecryptionException("Unrecognized algorithm, no way to build object around decrypted key."); + 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()); + m_cipher = XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedKey.getDOM()->getOwnerDocument()); // Resolve key decryption keys. int types = CredentialCriteria::KEYINFO_EXTRACTION_KEY | CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES; @@ -288,7 +342,7 @@ XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XML throw DecryptionException("Unable to resolve any key decryption keys."); XMLByte buffer[1024]; - for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) { + for (vector::const_iterator cred = creds.begin(); cred != creds.end(); ++cred) { try { if (!(*cred)->getPrivateKey()) throw DecryptionException("Credential did not contain a private key."); @@ -316,5 +370,24 @@ XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XML } } - throw DecryptionException("Unable to decrypt key."); + // Some algorithms are vulnerable to chosen ciphertext attacks, so we generate a random key + // to prevent discovery of the validity of the original candidate. + logging::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn( + "unable to decrypt key, generating random key for defensive purposes" + ); + pair mapped = XMLToolingConfig::getConfig().mapXMLAlgorithmToKeyAlgorithm(algorithm); + if (!mapped.second) + mapped.second = 256; + try { + if (XSECPlatformUtils::g_cryptoProvider->getRandom(reinterpret_cast(buffer),mapped.second) < mapped.second) + throw DecryptionException("Unable to generate random data; was PRNG seeded?"); + return handler->createKeyForURI(algorithm, buffer, mapped.second); + } + catch(XSECException& e) { + auto_ptr_char temp(e.getMsg()); + throw DecryptionException(string("XMLSecurity exception while generating key: ") + temp.get()); + } + catch (XSECCryptoException& e) { + throw DecryptionException(string("XMLSecurity exception while generating key: ") + e.getMsg()); + } }