/** | |
* 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 | |
* | |
* XKMSRecoverResultImpl := Implementation of RecoverResult Messages | |
* | |
* $Id$ | |
* | |
*/ | |
#include <xsec/framework/XSECDefs.hpp> | |
#include <xsec/framework/XSECError.hpp> | |
#include <xsec/framework/XSECEnv.hpp> | |
#include <xsec/framework/XSECAlgorithmMapper.hpp> | |
#include <xsec/framework/XSECAlgorithmHandler.hpp> | |
#include <xsec/utils/XSECDOMUtils.hpp> | |
#include <xsec/xkms/XKMSConstants.hpp> | |
#include <xsec/enc/XSECCryptoUtils.hpp> | |
#include <xsec/enc/XSECCryptoKey.hpp> | |
#include <xsec/xenc/XENCEncryptedData.hpp> | |
#include <xsec/xenc/XENCEncryptionMethod.hpp> | |
#include <xsec/xenc/XENCCipher.hpp> | |
#ifdef XSEC_XKMS_ENABLED | |
#include "XKMSRecoverResultImpl.hpp" | |
#include "XKMSKeyBindingImpl.hpp" | |
#include "XKMSRSAKeyPairImpl.hpp" | |
#include <xercesc/dom/DOM.hpp> | |
XERCES_CPP_NAMESPACE_USE | |
// -------------------------------------------------------------------------------- | |
// Construct/Destruct | |
// -------------------------------------------------------------------------------- | |
XKMSRecoverResultImpl::XKMSRecoverResultImpl( | |
const XSECEnv * env) : | |
m_result(env), | |
m_msg(m_result.m_msg), | |
mp_RSAKeyPair(NULL), | |
mp_privateKeyElement(NULL) { | |
} | |
XKMSRecoverResultImpl::XKMSRecoverResultImpl( | |
const XSECEnv * env, | |
XERCES_CPP_NAMESPACE_QUALIFIER DOMElement * node) : | |
m_result(env, node), | |
m_msg(m_result.m_msg), | |
mp_RSAKeyPair(NULL), | |
mp_privateKeyElement(NULL) { | |
} | |
XKMSRecoverResultImpl::~XKMSRecoverResultImpl() { | |
XKMSRecoverResultImpl::KeyBindingVectorType::iterator i; | |
for (i = m_keyBindingList.begin() ; i != m_keyBindingList.end(); ++i) { | |
delete (*i); | |
} | |
if (mp_RSAKeyPair != NULL) | |
delete mp_RSAKeyPair; | |
} | |
// -------------------------------------------------------------------------------- | |
// Load from DOM | |
// -------------------------------------------------------------------------------- | |
// Load elements | |
void XKMSRecoverResultImpl::load() { | |
if (m_msg.mp_messageAbstractTypeElement == NULL) { | |
// Attempt to load an empty element | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::load - called on empty DOM"); | |
} | |
if (!strEquals(getXKMSLocalName(m_msg.mp_messageAbstractTypeElement), | |
XKMSConstants::s_tagRecoverResult)) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::load - called incorrect node"); | |
} | |
// Get any UnverifiedKeyBinding elements | |
DOMNodeList * nl = m_msg.mp_messageAbstractTypeElement->getElementsByTagNameNS( | |
XKMSConstants::s_unicodeStrURIXKMS, | |
XKMSConstants::s_tagKeyBinding); | |
if (nl != NULL) { | |
XKMSKeyBindingImpl * kb; | |
for (unsigned int i = 0; i < nl->getLength() ; ++ i) { | |
XSECnew(kb, XKMSKeyBindingImpl(m_msg.mp_env, (DOMElement *) nl->item(i))); | |
m_keyBindingList.push_back(kb); | |
kb->load(); | |
} | |
} | |
nl = m_msg.mp_messageAbstractTypeElement->getElementsByTagNameNS( | |
XKMSConstants::s_unicodeStrURIXKMS, | |
XKMSConstants::s_tagPrivateKey); | |
if (nl != NULL) | |
mp_privateKeyElement = (DOMElement *) nl->item(0); | |
// Load the base message | |
m_result.load(); | |
} | |
// -------------------------------------------------------------------------------- | |
// Create a blank one | |
// -------------------------------------------------------------------------------- | |
DOMElement * XKMSRecoverResultImpl::createBlankRecoverResult( | |
const XMLCh * service, | |
const XMLCh * id, | |
ResultMajor rmaj, | |
ResultMinor rmin) { | |
return m_result.createBlankResultType( | |
XKMSConstants::s_tagRecoverResult, service, id, rmaj, rmin); | |
} | |
// -------------------------------------------------------------------------------- | |
// Get interface methods | |
// -------------------------------------------------------------------------------- | |
XKMSMessageAbstractType::messageType XKMSRecoverResultImpl::getMessageType(void) { | |
return XKMSMessageAbstractTypeImpl::RecoverResult; | |
} | |
// -------------------------------------------------------------------------------- | |
// UnverifiedKeyBinding handling | |
// -------------------------------------------------------------------------------- | |
int XKMSRecoverResultImpl::getKeyBindingSize(void) const { | |
return (int) m_keyBindingList.size(); | |
} | |
XKMSKeyBinding * XKMSRecoverResultImpl::getKeyBindingItem(int item) const { | |
if (item < 0 || item >= (int) m_keyBindingList.size()) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::getKeyBindingItem - item out of range"); | |
} | |
return m_keyBindingList[item]; | |
} | |
XKMSKeyBinding * XKMSRecoverResultImpl::appendKeyBindingItem(XKMSStatus::StatusValue status) { | |
XKMSKeyBindingImpl * u; | |
XSECnew(u, XKMSKeyBindingImpl(m_msg.mp_env)); | |
m_keyBindingList.push_back(u); | |
DOMElement * e = u->createBlankKeyBinding(status); | |
// Append the element | |
DOMElement * c = findFirstElementChild(m_msg.mp_messageAbstractTypeElement); | |
while (c != NULL) { | |
if (strEquals(getXKMSLocalName(c), XKMSConstants::s_tagPrivateKey)) | |
break; | |
} | |
if (c != NULL) { | |
m_msg.mp_messageAbstractTypeElement->insertBefore(e, c); | |
if (m_msg.mp_env->getPrettyPrintFlag()) { | |
m_msg.mp_messageAbstractTypeElement->insertBefore( | |
m_msg.mp_env->getParentDocument()->createTextNode(DSIGConstants::s_unicodeStrNL), c); | |
} | |
} | |
else { | |
m_msg.mp_messageAbstractTypeElement->appendChild(e); | |
m_msg.mp_env->doPrettyPrint(m_msg.mp_messageAbstractTypeElement); | |
} | |
return u; | |
} | |
// -------------------------------------------------------------------------------- | |
// RSAKeyPair handling | |
// -------------------------------------------------------------------------------- | |
XKMSRSAKeyPair * XKMSRecoverResultImpl::getRSAKeyPair(const char * passPhrase) { | |
// Already done? | |
if (mp_RSAKeyPair != NULL) | |
return mp_RSAKeyPair; | |
// Nope - can we do it? | |
if (mp_privateKeyElement == NULL) | |
return NULL; | |
// Yep! Load the key | |
unsigned char kbuf[XSEC_MAX_HASH_SIZE]; | |
unsigned int len = CalculateXKMSKEK((unsigned char *) passPhrase, (int) strlen(passPhrase), kbuf, XSEC_MAX_HASH_SIZE); | |
if (len == 0) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::getRSAKeyPair - error deriving KEK"); | |
} | |
XSECProvider prov; | |
XENCCipher * cipher = prov.newCipher(m_msg.mp_env->getParentDocument()); | |
// Find the encrypted info | |
DOMNode * n = findXENCNode(mp_privateKeyElement, "EncryptedData"); | |
// Load into the Cipher class | |
XENCEncryptedData * xed = cipher->loadEncryptedData((DOMElement *) n); | |
if (xed == NULL) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::getRSAKeyPair - error loading encrypted data"); | |
} | |
// Setup the appropriate key | |
if (xed->getEncryptionMethod() == NULL) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::getRSAKeyPair - no <EncryptionMethod> in EncryptedData"); | |
} | |
// Now find if we can get an algorithm for this URI | |
XSECAlgorithmHandler *handler; | |
handler = | |
XSECPlatformUtils::g_algorithmMapper->mapURIToHandler( | |
xed->getEncryptionMethod()->getAlgorithm()); | |
if (handler == NULL) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::getRSAKeyPair - unable to handle algorithm in EncryptedData"); | |
} | |
XSECCryptoKey * sk = handler->createKeyForURI( | |
xed->getEncryptionMethod()->getAlgorithm(), | |
(XMLByte *) kbuf, | |
len); | |
memset(kbuf, 0, XSEC_MAX_HASH_SIZE); | |
cipher->setKey(sk); | |
cipher->decryptElement(); | |
// WooHoo - if we get this far things are looking good! | |
DOMElement * kp = findFirstElementChild(mp_privateKeyElement); | |
if (kp == NULL || !strEquals(getXKMSLocalName(kp), XKMSConstants::s_tagRSAKeyPair)) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::getRSAKeyPair - private key did not decrypt to RSAKeyPair"); | |
} | |
XSECnew(mp_RSAKeyPair, XKMSRSAKeyPairImpl(m_msg.mp_env, kp)); | |
mp_RSAKeyPair->load(); | |
return mp_RSAKeyPair; | |
} | |
XENCEncryptedData * XKMSRecoverResultImpl::setRSAKeyPair(const char * passPhrase, | |
XMLCh * Modulus, | |
XMLCh * Exponent, | |
XMLCh * P, | |
XMLCh * Q, | |
XMLCh * DP, | |
XMLCh * DQ, | |
XMLCh * InverseQ, | |
XMLCh * D, | |
const XMLCh * algorithmURI) { | |
// Try to set up the key first - if this fails, don't want to have added the | |
// XML | |
// Find if we can get an algorithm for this URI | |
XSECAlgorithmHandler *handler = | |
XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(algorithmURI); | |
if (handler == NULL) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::setRSAKeyPair - unable to handle algorithm"); | |
} | |
unsigned char kbuf[XSEC_MAX_HASH_SIZE]; | |
unsigned int len = CalculateXKMSKEK((unsigned char *) passPhrase, (int) strlen(passPhrase), kbuf, XSEC_MAX_HASH_SIZE); | |
if (len == 0) { | |
throw XSECException(XSECException::XKMSError, | |
"XKMSRecoverResult::setRSAKeyPair - error deriving KEK"); | |
} | |
XSECCryptoKey * sk = handler->createKeyForURI( | |
algorithmURI, | |
(XMLByte *) kbuf, | |
len); | |
memset(kbuf, 0, XSEC_MAX_HASH_SIZE); | |
// Get some setup values | |
safeBuffer str; | |
DOMDocument *doc = m_msg.mp_env->getParentDocument(); | |
const XMLCh * prefix = m_msg.mp_env->getXKMSNSPrefix(); | |
makeQName(str, prefix, XKMSConstants::s_tagPrivateKey); | |
// Create a PrivateKey to add this to | |
DOMElement * pk = doc->createElementNS(XKMSConstants::s_unicodeStrURIXKMS, | |
str.rawXMLChBuffer()); | |
m_msg.mp_env->doPrettyPrint(pk); | |
// Add it to the request doc | |
m_msg.mp_messageAbstractTypeElement->appendChild(pk); | |
m_msg.mp_env->doPrettyPrint(m_msg.mp_messageAbstractTypeElement); | |
// Now create the RSA structure | |
XKMSRSAKeyPairImpl * rsa; | |
XSECnew(rsa, XKMSRSAKeyPairImpl(m_msg.mp_env)); | |
DOMElement * e = | |
rsa->createBlankXKMSRSAKeyPairImpl(Modulus, Exponent, P, Q, DP, DQ, InverseQ, D); | |
// Add it to the PrivateKey | |
pk->appendChild(e); | |
m_msg.mp_env->doPrettyPrint(pk); | |
// Encrypt all of this for future use | |
XENCCipher * cipher = m_prov.newCipher(m_msg.mp_env->getParentDocument()); | |
cipher->setKey(sk); | |
cipher->encryptElementContent(pk, algorithmURI); | |
// Now load the encrypted data back in | |
return cipher->loadEncryptedData(findFirstElementChild(pk)); | |
} | |
#endif /* XSEC_XKMS_ENABLED */ |