xsec/xenc/impl/XENCCipherImpl.cpp (598 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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 * * 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. */ /* * XSEC * * XENCCipherImpl := Implementation of the main encryption worker class * * $Id$ * */ // XSEC Includes #include <xsec/enc/XSECKeyInfoResolver.hpp> #include <xsec/enc/XSECCryptoException.hpp> #include <xsec/framework/XSECAlgorithmMapper.hpp> #include <xsec/framework/XSECAlgorithmHandler.hpp> #include <xsec/framework/XSECDefs.hpp> #include <xsec/framework/XSECEnv.hpp> #include <xsec/framework/XSECError.hpp> #include <xsec/enc/XSECCryptoKey.hpp> #include <xsec/transformers/TXFMChain.hpp> #include <xsec/transformers/TXFMBase.hpp> #include <xsec/transformers/TXFMC14n.hpp> #include <xsec/transformers/TXFMSB.hpp> #include <xsec/transformers/TXFMURL.hpp> #include <xsec/transformers/TXFMDocObject.hpp> #include <xsec/transformers/TXFMConcatChains.hpp> #include <xsec/utils/XSECPlatformUtils.hpp> #include <xsec/utils/XSECBinTXFMInputStream.hpp> #include "XENCCipherImpl.hpp" #include "XENCEncryptedDataImpl.hpp" #include "XENCEncryptedKeyImpl.hpp" #include "XENCEncryptionMethodImpl.hpp" #include "XENCAlgorithmHandlerDefault.hpp" #include "../../utils/XSECAutoPtr.hpp" #include "../../utils/XSECDOMUtils.hpp" #include <xercesc/dom/DOMNode.hpp> #include <xercesc/dom/DOMElement.hpp> #include <xercesc/util/XMLUniDefs.hpp> #include <xercesc/parsers/XercesDOMParser.hpp> #include <xercesc/framework/MemBufInputSource.hpp> #include <xercesc/util/Janitor.hpp> // With all the characters - just uplift entire thing XERCES_CPP_NAMESPACE_USE #include <iostream> using std::cout; // -------------------------------------------------------------------------------- // Constant Strings // -------------------------------------------------------------------------------- const XMLCh s_tagname[] = { chLatin_f, chLatin_r, chLatin_a, chLatin_g, chLatin_m, chLatin_e, chLatin_n, chLatin_t, chNull }; const XMLCh s_noData[] = { chLatin_n, chLatin_o, chLatin_D, chLatin_a, chLatin_t, chLatin_a, chNull }; const XMLCh s_ds[] = { chLatin_d, chLatin_s, chNull }; // -------------------------------------------------------------------------------- // Constructors // -------------------------------------------------------------------------------- XENCCipherImpl::XENCCipherImpl(DOMDocument * doc) : mp_doc(doc), mp_encryptedData(NULL), mp_key(NULL), mp_kek(NULL), mp_keyInfoResolver(NULL) { XSECnew(mp_env, XSECEnv(doc)); mp_env->setDSIGNSPrefix(s_ds); m_keyDerived = false; m_kekDerived = false; m_useExcC14nSerialisation = true; } XENCCipherImpl::~XENCCipherImpl() { if (mp_encryptedData != NULL) delete mp_encryptedData; if (mp_key != NULL) delete mp_key; if (mp_kek != NULL) delete mp_kek; if (mp_env != NULL) delete mp_env; if (mp_keyInfoResolver != NULL) delete mp_keyInfoResolver; } // -------------------------------------------------------------------------------- // Initialiser // -------------------------------------------------------------------------------- void XENCCipherImpl::Initialise(void) { XENCAlgorithmHandlerDefault def; // Register default encryption algorithm handlers XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURI3DES_CBC, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIAES128_CBC, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIAES192_CBC, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIAES256_CBC, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIAES128_GCM, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIAES192_GCM, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIAES256_GCM, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIKW_3DES, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIKW_AES128, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIKW_AES192, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIKW_AES256, def); //XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIKW_AES128_PAD, def); //XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIKW_AES192_PAD, def); //XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIKW_AES256_PAD, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_1_5, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, def); XSECPlatformUtils::registerAlgorithmHandler(DSIGConstants::s_unicodeStrURIRSA_OAEP, def); } // -------------------------------------------------------------------------------- // Set/get the namespace prefix to be used when creating nodes // -------------------------------------------------------------------------------- void XENCCipherImpl::setXENCNSPrefix(const XMLCh * prefix) { mp_env->setXENCNSPrefix(prefix); } const XMLCh * XENCCipherImpl::getXENCNSPrefix(void) const { return mp_env->getXENCNSPrefix(); } // -------------------------------------------------------------------------------- // Key Info resolvers // -------------------------------------------------------------------------------- void XENCCipherImpl::setKeyInfoResolver(const XSECKeyInfoResolver * resolver) { if (mp_keyInfoResolver != NULL) delete mp_keyInfoResolver; mp_keyInfoResolver = resolver->clone(); } // -------------------------------------------------------------------------------- // Key Info resolvers // -------------------------------------------------------------------------------- XENCEncryptedData * XENCCipherImpl::getEncryptedData() const { return mp_encryptedData; } // -------------------------------------------------------------------------------- // Keys // -------------------------------------------------------------------------------- void XENCCipherImpl::setKey(XSECCryptoKey * key) { if (mp_key != NULL) delete mp_key; mp_key = key; m_keyDerived = false; } void XENCCipherImpl::setKEK(XSECCryptoKey * key) { if (mp_kek != NULL) delete mp_kek; mp_kek = key; m_kekDerived = false; } // -------------------------------------------------------------------------------- // Serialise/Deserialise an element // -------------------------------------------------------------------------------- DOMDocumentFragment * XENCCipherImpl::deSerialise(safeBuffer &content, DOMNode * ctx) { DOMDocumentFragment * result; // Create the context to parse the document against safeBuffer sb, sbt; sb.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty); //sb.sbXMLChAppendCh(chUnicodeMarker); //sb.sbXMLChCat8("<?xml version=\"1.0\" encoding=\"UTF-16\"?><"); sb.sbXMLChAppendCh(chOpenAngle); sb.sbXMLChCat(s_tagname); // Run through each node up to the document node and find any // xmlns: nodes that may be needed during the parse of the decrypted content DOMNode * ctxParent = ctx->getParentNode(); DOMNode * wk = ctxParent; while (wk != NULL) { DOMNamedNodeMap * atts = wk->getAttributes(); XMLSize_t length; if (atts != NULL) length = atts->getLength(); else length = 0; for (XMLSize_t i = 0; i < length; ++i) { DOMNode * att = atts->item(i); if (strEquals(att->getNodeName(), DSIGConstants::s_unicodeStrXmlns) || (XMLString::compareNString(att->getNodeName(), DSIGConstants::s_unicodeStrXmlns, 5) == 0 && att->getNodeName()[5] == chColon)) { // Check to see if this node has already been found DOMNode * p = ctxParent; bool found = false; while (p != wk) { DOMNamedNodeMap * tstAtts = p->getAttributes(); if (tstAtts != NULL && tstAtts->getNamedItem(att->getNodeName()) != NULL) { found = true; break; } p = p->getParentNode(); } if (found == false) { // This is an attribute node that needs to be added sb.sbXMLChAppendCh(chSpace); sb.sbXMLChCat(att->getNodeName()); sb.sbXMLChAppendCh(chEqual); sb.sbXMLChAppendCh(chDoubleQuote); sb.sbXMLChCat(att->getNodeValue()); sb.sbXMLChAppendCh(chDoubleQuote); } } } wk = wk->getParentNode(); } sb.sbXMLChAppendCh(chCloseAngle); char* prefix = transcodeToUTF8(sb.rawXMLChBuffer()); sbt = prefix; XSEC_RELEASE_XMLCH(prefix); const char * crcb = content.rawCharBuffer(); int offset = 0; if (crcb[0] == '<' && crcb[1] == '?') { // Have a PI prefix - get rid of it int i = 2; while (crcb[i] != '\0' && crcb[i] != '>') ++i; if (crcb[i] == '>') offset = i + 1; } sbt.sbStrcatIn(&crcb[offset]); // Terminate the string sb.sbXMLChIn(DSIGConstants::s_unicodeStrEmpty); sb.sbXMLChAppendCh(chOpenAngle); sb.sbXMLChAppendCh(chForwardSlash); sb.sbXMLChCat(s_tagname); sb.sbXMLChAppendCh(chCloseAngle); char* trailer = transcodeToUTF8(sb.rawXMLChBuffer()); sbt.sbStrcatIn(trailer); XSEC_RELEASE_XMLCH(trailer); // Create an input source XMLSize_t bytes = XMLString::stringLen(sbt.rawCharBuffer()); MemBufInputSource memIS((const XMLByte*) sbt.rawBuffer(), bytes, "XSECMem"); XercesDOMParser parser; parser.setDoNamespaces(true); parser.setLoadExternalDTD(false); SecurityManager securityManager; securityManager.setEntityExpansionLimit(XSEC_ENTITY_EXPANSION_LIMIT); parser.setSecurityManager(&securityManager); parser.parse(memIS); XMLSize_t errorCount = parser.getErrorCount(); if (errorCount > 0) throw XSECException(XSECException::CipherError, "Errors occurred during de-serialisation of decrypted element content"); DOMDocument * doc = parser.getDocument(); // Create a DocumentFragment to hold the children of the parsed doc element DOMDocument *ctxDocument = ctx->getOwnerDocument(); result = ctxDocument->createDocumentFragment(); Janitor<DOMDocumentFragment> j_result(result); // Now get the children of the document into a DOC fragment DOMNode * fragElt = doc->getDocumentElement(); DOMNode * child; if (fragElt != NULL) { child = fragElt->getFirstChild(); } else { throw XSECException(XSECException::CipherError, "XENCCipher::deSerialse - re-parsed document unexpectedly empty"); } while (child != NULL) { result->appendChild(ctxDocument->importNode(child, true)); child = child->getNextSibling(); } // Done! j_result.release(); return result; } // -------------------------------------------------------------------------------- // Decrypt an Element and replace in original document // -------------------------------------------------------------------------------- XSECCryptoKey * XENCCipherImpl::decryptKeyFromKeyInfoList(DSIGKeyInfoList * kil) { XSECCryptoKey * ret = NULL; const XSECAlgorithmHandler *handler; int kLen = (int) kil->getSize(); for (int i = 0; ret == NULL && i < kLen; ++i) { if (kil->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_ENCRYPTEDKEY) { XENCEncryptedKey * ek = (XENCEncryptedKey*) (kil->item(i)); volatile XMLByte buffer[1024]; try { // Have to cast off volatile int keySize = decryptKey(ek, (XMLByte *) buffer, 1024); if (keySize > 0) { // Try to map the key XENCEncryptionMethod * encryptionMethod = mp_encryptedData->getEncryptionMethod(); if (encryptionMethod != NULL) { handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler( mp_encryptedData->getEncryptionMethod()->getAlgorithm()); if (handler != NULL) ret = handler->createKeyForURI(mp_encryptedData->getEncryptionMethod()->getAlgorithm(), (XMLByte *) buffer, keySize); } } } catch (const XSECCryptoException&) { /* Do nothing - this is likely to be a bad decrypt on a public key */ } catch (...) { memset((void *) buffer, 0, 1024); throw; } // Clear out the key buffer memset((void *) buffer, 0, 1024); } } return ret; } XENCEncryptedData * XENCCipherImpl::loadEncryptedData(DOMElement * element) { // First of all load the element if (mp_encryptedData != NULL) delete mp_encryptedData; XSECnew(mp_encryptedData, XENCEncryptedDataImpl(mp_env, element)); // Load mp_encryptedData->load(); return mp_encryptedData; } DOMDocument * XENCCipherImpl::decryptElement(DOMElement * element) { // First of all load the element if (mp_encryptedData != NULL) delete mp_encryptedData; XSECnew(mp_encryptedData, XENCEncryptedDataImpl(mp_env, element)); // Load mp_encryptedData->load(); return decryptElement(); } DOMNode * XENCCipherImpl::decryptElementDetached(DOMElement * element) { // First of all load the element if (mp_encryptedData != NULL) delete mp_encryptedData; XSECnew(mp_encryptedData, XENCEncryptedDataImpl(mp_env, element)); // Load mp_encryptedData->load(); return decryptElementDetached(); } DOMNode * XENCCipherImpl::decryptElementDetached() { const XSECAlgorithmHandler *handler; if (mp_encryptedData == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptElement - no element loaded for decryption"); } // Check that this is a valid type const XMLCh * typeURI = mp_encryptedData->getType(); if (typeURI != NULL && !strEquals(typeURI, DSIGConstants::s_unicodeStrURIXENC_ELEMENT) && !strEquals(typeURI, DSIGConstants::s_unicodeStrURIXENC_CONTENT)) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptElement - Type not Element or Content"); } if (m_keyDerived && mp_key) { delete mp_key; mp_key = NULL; } // Make sure we have a key before we do anything else too drastic if (mp_key == NULL) { if (mp_keyInfoResolver != NULL) mp_key = mp_keyInfoResolver->resolveKey(mp_encryptedData->getKeyInfoList()); if (mp_key == NULL) { mp_key = decryptKeyFromKeyInfoList(mp_encryptedData->getKeyInfoList()); } if (mp_key == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptElement - No key set and cannot resolve"); } m_keyDerived = true; } // Get the raw encrypted data TXFMChain * c = mp_encryptedData->createCipherTXFMChain(); Janitor<TXFMChain> j_c(c); // Get the Algorithm handler for the algorithm XENCEncryptionMethod * encryptionMethod = mp_encryptedData->getEncryptionMethod(); if (encryptionMethod != NULL) { handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(mp_encryptedData->getEncryptionMethod()->getAlgorithm()); } else { handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(XSECAlgorithmMapper::s_defaultEncryptionMapping); } safeBuffer sb(""); unsigned int decryptLen; if (handler != NULL) { decryptLen = handler->decryptToSafeBuffer(c, mp_encryptedData->getEncryptionMethod(), mp_key, mp_env->getParentDocument(), sb); } else { // Very strange if we get here - any problems should throw an // exception in the AlgorithmMapper. throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptElement - Error retrieving a handler for algorithm"); } sb[decryptLen] = '\0'; // Now de-serialise DOMElement * element = mp_encryptedData->getElement(); DOMDocumentFragment * frag = deSerialise(sb, element); return frag; } DOMDocument * XENCCipherImpl::decryptElement() { // Call the worker DOMElement * element = mp_encryptedData->getElement(); DOMDocumentFragment * frag = (DOMDocumentFragment *) decryptElementDetached(); if (frag != NULL) { // Have something to replace current element with DOMNode * p = element->getParentNode(); // By inserting the DocumentFragment, we effectively insert the children p->replaceChild(frag, element); // Delete the frag and the old element frag->release(); element->release(); } return mp_env->getParentDocument(); } // -------------------------------------------------------------------------------- // Decrypt data to an input stream // -------------------------------------------------------------------------------- XSECBinTXFMInputStream * XENCCipherImpl::decryptToBinInputStream( XERCES_CPP_NAMESPACE_QUALIFIER DOMElement * element ) { const XSECAlgorithmHandler *handler; // First of all load the element if (mp_encryptedData != NULL) delete mp_encryptedData; XSECnew(mp_encryptedData, XENCEncryptedDataImpl(mp_env, element)); // Load mp_encryptedData->load(); // Check key is valid if (m_keyDerived && mp_key) { delete mp_key; mp_key = NULL; } // Make sure we have a key before we do anything else too drastic if (mp_key == NULL) { if (mp_keyInfoResolver != NULL) mp_key = mp_keyInfoResolver->resolveKey(mp_encryptedData->getKeyInfoList()); if (mp_key == NULL) { mp_key = decryptKeyFromKeyInfoList(mp_encryptedData->getKeyInfoList()); } if (mp_key == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptToBinInputStream - No key set and cannot resolve"); } m_keyDerived = true; } // Get the raw encrypted data TXFMChain * c = mp_encryptedData->createCipherTXFMChain(); Janitor<TXFMChain> j_c(c); // Get the Algorithm handler for the algorithm XENCEncryptionMethod * encryptionMethod = mp_encryptedData->getEncryptionMethod(); if (encryptionMethod != NULL) { handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler( mp_encryptedData->getEncryptionMethod()->getAlgorithm()); } else { handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler( XSECAlgorithmMapper::s_defaultEncryptionMapping); } if (handler != NULL) { if (handler->appendDecryptCipherTXFM(c, mp_encryptedData->getEncryptionMethod(), mp_key, mp_env->getParentDocument()) != true) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptToBinInputStream - error appending final transform"); } } else { // Very strange if we get here - any problems should throw an // exception in the AlgorithmMapper. throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptElement - Error retrieving a handler for algorithm"); } // Wrap in a Bin input stream XSECBinTXFMInputStream * ret; ret = new XSECBinTXFMInputStream(c); // Probs with MSVC++ mean no XSECnew j_c.release(); // Now owned by "ret" return ret; } // -------------------------------------------------------------------------------- // Decrypt a key in an XENCEncryptedKey element // -------------------------------------------------------------------------------- int XENCCipherImpl::decryptKey(XENCEncryptedKey * encryptedKey, XMLByte * rawKey, int maxKeySize) { // Check KEK is valid if (m_kekDerived && mp_kek) { delete mp_kek; mp_kek = NULL; } // Make sure we have a key before we do anything else too drastic if (mp_kek == NULL) { if (mp_keyInfoResolver != NULL) mp_kek = mp_keyInfoResolver->resolveKey(encryptedKey->getKeyInfoList()); if (mp_kek == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptKey - No KEK set and cannot resolve"); } m_kekDerived = true; } // Get the raw encrypted data TXFMChain * c = ((XENCEncryptedKeyImpl *) encryptedKey)->createCipherTXFMChain(); Janitor<TXFMChain> j_c(c); // Get the Algorithm handler for the algorithm XENCEncryptionMethod * encryptionMethod = encryptedKey->getEncryptionMethod(); const XSECAlgorithmHandler *handler; if (encryptionMethod != NULL) { handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(encryptedKey->getEncryptionMethod()->getAlgorithm()); } else { handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(XSECAlgorithmMapper::s_defaultEncryptionMapping); } safeBuffer sb(""); unsigned int keySize; if (handler != NULL) { keySize = handler->decryptToSafeBuffer(c, encryptedKey->getEncryptionMethod(), mp_kek, mp_env->getParentDocument(), sb); } else { // Very strange if we get here - any problems should throw an // exception in the AlgorithmMapper. throw XSECException(XSECException::CipherError, "XENCCipherImpl::decryptElement - Error retrieving a handler for algorithm"); } keySize = (keySize < (unsigned int) maxKeySize ? keySize : (unsigned int) maxKeySize); memcpy(rawKey, sb.rawBuffer(), keySize); return keySize; } // -------------------------------------------------------------------------------- // Decrypt a key from a DOM structure // -------------------------------------------------------------------------------- int XENCCipherImpl::decryptKey(DOMElement * keyNode, XMLByte * rawKey, int maxKeySize) { XENCEncryptedKey * encryptedKey = loadEncryptedKey(keyNode); Janitor<XENCEncryptedKey> j_encryptedKey(encryptedKey); // Now decrypt! return decryptKey(encryptedKey, rawKey, maxKeySize); } XENCEncryptedKey * XENCCipherImpl::loadEncryptedKey(DOMElement * keyNode) { XENCEncryptedKeyImpl * encryptedKey; XSECnew(encryptedKey, XENCEncryptedKeyImpl(mp_env, keyNode)); Janitor<XENCEncryptedKeyImpl> j_encryptedKey(encryptedKey); // Load encryptedKey->load(); j_encryptedKey.release(); return encryptedKey; } // -------------------------------------------------------------------------------- // Encrypt a BinInputStream // -------------------------------------------------------------------------------- XENCEncryptedData * XENCCipherImpl::encryptBinInputStream( XERCES_CPP_NAMESPACE_QUALIFIER BinInputStream * plainText, const XMLCh * algorithmURI) { TXFMURL * uri; XSECnew(uri, TXFMURL(mp_doc, NULL)); uri->setInput(plainText); TXFMChain c(uri); return encryptTXFMChain(&c, algorithmURI); } // -------------------------------------------------------------------------------- // Encrypt a TXFMChain // -------------------------------------------------------------------------------- XENCEncryptedData * XENCCipherImpl::encryptTXFMChain(TXFMChain * plainText, const XMLCh * algorithmURI) { // Make sure we have a key before we do anything too drastic if (mp_key == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptTXFMChain - No key set"); } else if (algorithmURI == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptTXFMChain - No algorithm set"); } // Create the element with a dummy encrypted value if (mp_encryptedData != NULL) { delete mp_encryptedData; mp_encryptedData = NULL; } XSECnew(mp_encryptedData, XENCEncryptedDataImpl(mp_env)); mp_encryptedData->createBlankEncryptedData(XENCCipherData::VALUE_TYPE, algorithmURI, s_noData); // Perform the encryption const XSECAlgorithmHandler *handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithmURI); if (!handler) { // Very strange if we get here - any problems should throw an // exception in the AlgorithmMapper. throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptTXFMChain - Error retrieving a handler for algorithm"); } safeBuffer sb; handler->encryptToSafeBuffer(plainText, mp_encryptedData->getEncryptionMethod(), mp_key, mp_env->getParentDocument(), sb); // Set the value XENCCipherValue * val = mp_encryptedData->getCipherData()->getCipherValue(); val->setCipherString(sb.sbStrToXMLCh()); return mp_encryptedData; } // -------------------------------------------------------------------------------- // Encrypt a key // -------------------------------------------------------------------------------- XENCEncryptedKey * XENCCipherImpl::encryptKey( const unsigned char* keyBuffer, unsigned int keyLen, const XMLCh* algorithmURI, const XMLCh* mgfURI, unsigned char* oaepParams, unsigned int oaepParamsLen) { if (mp_kek == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptKey - No KEK set"); } else if (algorithmURI == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptKey - No algorithm set"); } // Create the element with a dummy encrypted value XENCEncryptedKeyImpl * encryptedKey; XSECnew(encryptedKey, XENCEncryptedKeyImpl(mp_env)); Janitor<XENCEncryptedKeyImpl> j_encryptedKey(encryptedKey); encryptedKey->createBlankEncryptedKey(XENCCipherData::VALUE_TYPE, algorithmURI, s_noData); if (mgfURI) encryptedKey->getEncryptionMethod()->setMGF(mgfURI); if (oaepParams != NULL && oaepParamsLen > 0) { unsigned char * oaepParamsB64; XSECnew(oaepParamsB64, unsigned char[oaepParamsLen * 2]); ArrayJanitor<unsigned char> j_oaepParamsB64(oaepParamsB64); XSECCryptoBase64 * b64 = XSECPlatformUtils::g_cryptoProvider->base64(); Janitor<XSECCryptoBase64> j_b64(b64); b64->encodeInit(); int sz = b64->encode(oaepParams, oaepParamsLen, oaepParamsB64, oaepParamsLen *2); sz += b64->encodeFinish(&oaepParamsB64[sz], (oaepParamsLen * 2) - sz); oaepParamsB64[sz] = '\0'; XSECAutoPtrXMLCh xBuf((char*) oaepParamsB64); encryptedKey->getEncryptionMethod()->setOAEPparams(xBuf.get()); } // Create a transform chain to do pass the key to the encryption. safeBuffer rawKey; rawKey.isSensitive(); rawKey.sbMemcpyIn(keyBuffer, keyLen); TXFMSB * tsb; XSECnew(tsb, TXFMSB(mp_doc)); TXFMChain * c; XSECnew(c, TXFMChain(tsb)); Janitor<TXFMChain> j_c(c); tsb->setInput(rawKey, keyLen); // Perform the encryption const XSECAlgorithmHandler *handler = XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithmURI); if (!handler) { // Very strange if we get here - any problems should throw an // exception in the AlgorithmMapper. throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptKey - Error retrieving a handler for algorithm"); } safeBuffer sb; handler->encryptToSafeBuffer(c, encryptedKey->getEncryptionMethod(), mp_kek, mp_env->getParentDocument(), sb); // Set the value XENCCipherValue * val = encryptedKey->getCipherData()->getCipherValue(); val->setCipherString(sb.sbStrToXMLCh()); j_encryptedKey.release(); return encryptedKey; } // -------------------------------------------------------------------------------- // Create an EncryptedData element // -------------------------------------------------------------------------------- XENCEncryptedData * XENCCipherImpl::createEncryptedData(XENCCipherData::XENCCipherDataType type, const XMLCh * algorithm, const XMLCh * value) { // Clean out anything currently being used if (mp_encryptedData != NULL) { delete mp_encryptedData; mp_encryptedData = NULL; } // Create a new EncryptedData element XSECnew(mp_encryptedData, XENCEncryptedDataImpl(mp_env)); mp_encryptedData->createBlankEncryptedData(type, algorithm, value); return mp_encryptedData; } // -------------------------------------------------------------------------------- // Encrypt an element // -------------------------------------------------------------------------------- DOMNode * XENCCipherImpl::encryptElementDetached(DOMElement * element, const XMLCh * algorithmURI) { // Make sure we have a key before we do anything too drastic if (mp_key == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptElement - No key set"); } else if (algorithmURI == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptElement - No algorithm set"); } // Create a transform chain to do the encryption TXFMDocObject * tdocObj; XSECnew(tdocObj, TXFMDocObject(mp_doc)); TXFMChain * c; XSECnew(c, TXFMChain(tdocObj)); Janitor<TXFMChain> j_c(c); tdocObj->setInput(mp_doc, element); // Now need to serialise the element - easiest to just use a canonicalizer TXFMC14n *tc14n; XSECnew(tc14n, TXFMC14n(mp_doc)); c->appendTxfm(tc14n); tc14n->activateComments(); if (m_useExcC14nSerialisation) tc14n->setExclusive(); // Do the hard work encryptTXFMChain(c, algorithmURI); mp_encryptedData->setType(DSIGConstants::s_unicodeStrURIXENC_ELEMENT); return mp_encryptedData->getElement(); } DOMDocument * XENCCipherImpl::encryptElement(DOMElement * element, const XMLCh * algorithmURI) { // Do the actual encryption work encryptElementDetached(element, algorithmURI); // Replace original element DOMNode * p = element->getParentNode(); if (p == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptElement - Passed in element has no parent"); } p->replaceChild(mp_encryptedData->getElement(), element); // Clear up the old child element->release(); return mp_doc; } // -------------------------------------------------------------------------------- // Encrypt an element's children // -------------------------------------------------------------------------------- DOMDocument * XENCCipherImpl::encryptElementContent( XERCES_CPP_NAMESPACE_QUALIFIER DOMElement * element, const XMLCh * algorithmURI) { // Do the work encryptElementContentDetached(element, algorithmURI); // Delete current children DOMNode * n = element->getFirstChild(); while (n != NULL) { element->removeChild(n); n->release(); n = element->getFirstChild(); } // Now add the EncryptedData element->appendChild(mp_encryptedData->getElement()); return mp_doc; } DOMNode * XENCCipherImpl::encryptElementContentDetached( XERCES_CPP_NAMESPACE_QUALIFIER DOMElement * element, const XMLCh * algorithmURI) { // Make sure we have a key before we do anything too drastic if (mp_key == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptElementContentDetached - No key set"); } else if (algorithmURI == NULL) { throw XSECException(XSECException::CipherError, "XENCCipherImpl::encryptElementContentDetached - No algorithm set"); } // Create a transform chain to do the encryption // We use a concat transformer so we can concatinate the bytestreams // from the serialisation of each child in turn TXFMConcatChains * tcat; XSECnew(tcat, TXFMConcatChains(mp_doc)); TXFMChain * c; XSECnew(c, TXFMChain(tcat)); Janitor<TXFMChain> j_c(c); DOMNode *n = element->getFirstChild(); while (n != NULL) { TXFMDocObject * tdocObj; XSECnew(tdocObj, TXFMDocObject(mp_doc)); TXFMChain * tc; XSECnew(tc, TXFMChain(tdocObj)); // Add to the concat object, which will own it, so if anything throws // the memory will be released. tcat->setInput(tc); tdocObj->setInput(mp_doc, n); // Now need to serialise the element - easiest to just use a canonicaliser TXFMC14n *tc14n; XSECnew(tc14n, TXFMC14n(mp_doc)); tc->appendTxfm(tc14n); tc14n->activateComments(); if (m_useExcC14nSerialisation) tc14n->setExclusive(); n = n->getNextSibling(); } encryptTXFMChain(c, algorithmURI); mp_encryptedData->setType(DSIGConstants::s_unicodeStrURIXENC_CONTENT); return mp_encryptedData->getElement(); } // -------------------------------------------------------------------------------- // Pretty Print functions // -------------------------------------------------------------------------------- void XENCCipherImpl::setExclusiveC14nSerialisation(bool flag) { m_useExcC14nSerialisation = flag; } bool XENCCipherImpl::getExclusiveC14nSerialisation() const { return m_useExcC14nSerialisation; } // -------------------------------------------------------------------------------- // Exclusive C14n serialisation setting // -------------------------------------------------------------------------------- void XENCCipherImpl::setPrettyPrint(bool flag) { mp_env->setPrettyPrintFlag(flag); } bool XENCCipherImpl::getPrettyPrint(void) const { return mp_env->getPrettyPrintFlag(); }