blob: 9e27c8382a3ec5e16deb1c5353d0ccf1efa78b41 [file] [log] [blame]
/**
* 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/enc/XSECCryptoUtils.hpp>
#include <xsec/enc/XSECCryptoKey.hpp>
#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/xenc/XENCEncryptedData.hpp>
#include <xsec/xenc/XENCEncryptionMethod.hpp>
#include <xsec/xenc/XENCCipher.hpp>
#ifdef XSEC_XKMS_ENABLED
#include "../../utils/XSECDOMUtils.hpp"
#include "XKMSRecoverResultImpl.hpp"
#include "XKMSKeyBindingImpl.hpp"
#include "XKMSRSAKeyPairImpl.hpp"
#include <xsec/xkms/XKMSConstants.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
const XSECAlgorithmHandler *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
const 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 */