blob: 31191e87513d1f146abc6eff18494156d29310e5 [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
*
* DSIGKeyInfoList := Class for Loading and storing a list of KeyInfo elements
*
* Author(s): Berin Lautenbach
*
* $Id$
*
*/
// XSEC Includes
#include <xsec/dsig/DSIGKeyInfoList.hpp>
#include <xsec/dsig/DSIGKeyInfoX509.hpp>
#include <xsec/dsig/DSIGKeyInfoName.hpp>
#include <xsec/dsig/DSIGKeyInfoValue.hpp>
#include <xsec/dsig/DSIGKeyInfoDEREncoded.hpp>
#include <xsec/dsig/DSIGKeyInfoPGPData.hpp>
#include <xsec/dsig/DSIGKeyInfoSPKIData.hpp>
#include <xsec/dsig/DSIGKeyInfoMgmtData.hpp>
#include <xsec/dsig/DSIGKeyInfoExt.hpp>
#include <xsec/framework/XSECError.hpp>
#include <xsec/dsig/DSIGSignature.hpp>
#include <xsec/dsig/DSIGReference.hpp>
#include <xsec/dsig/DSIGTransformList.hpp>
#include <xsec/framework/XSECEnv.hpp>
#include <xsec/transformers/TXFMChain.hpp>
#include <xsec/transformers/TXFMBase.hpp>
#include "../utils/XSECDOMUtils.hpp"
#include "../xenc/impl/XENCEncryptedKeyImpl.hpp"
#include <xercesc/util/Janitor.hpp>
XERCES_CPP_NAMESPACE_USE
DSIGKeyInfoList::DSIGKeyInfoList(const XSECEnv * env) :
mp_env(env),
mp_keyInfoNode(NULL) {}
DSIGKeyInfoList::~DSIGKeyInfoList() {
empty();
}
// Actions
void DSIGKeyInfoList::addKeyInfo(DSIGKeyInfo * ref) {
m_keyInfoList.push_back(ref);
}
DSIGKeyInfo * DSIGKeyInfoList::removeKeyInfo(size_type index) {
if (index < m_keyInfoList.size())
return m_keyInfoList[index];
return NULL;
}
size_t DSIGKeyInfoList::getSize() const {
return m_keyInfoList.size();
}
DSIGKeyInfo * DSIGKeyInfoList::item(size_type index) {
if (index < m_keyInfoList.size())
return m_keyInfoList[index];
return NULL;
}
const DSIGKeyInfo * DSIGKeyInfoList::item(size_type index) const {
if (index < m_keyInfoList.size())
return m_keyInfoList[index];
return NULL;
}
void DSIGKeyInfoList::empty() {
size_type i, s;
s = getSize();
for (i = 0; i < s; ++i)
delete m_keyInfoList[i];
m_keyInfoList.clear();
}
bool DSIGKeyInfoList::isEmpty() const {
return (m_keyInfoList.size() == 0);
}
// --------------------------------------------------------------------------------
// Add a KeyInfo based on XML DomNode source
// --------------------------------------------------------------------------------
bool DSIGKeyInfoList::addXMLKeyInfo(DOMNode *ki) {
// return true if successful - does not throw if the node type is unknown
if (ki == 0)
return false;
DSIGKeyInfo * k;
if (strEquals(getDSIGLocalName(ki), "X509Data")) {
// Have a certificate!
XSECnew(k, DSIGKeyInfoX509(mp_env, ki));
}
else if (strEquals(getDSIGLocalName(ki), "KeyName")) {
XSECnew(k, DSIGKeyInfoName(mp_env, ki));
}
else if (strEquals(getDSIGLocalName(ki), "KeyValue")) {
XSECnew(k, DSIGKeyInfoValue(mp_env, ki));
}
else if (strEquals(getDSIGLocalName(ki), "PGPData")) {
XSECnew(k, DSIGKeyInfoPGPData(mp_env, ki));
}
else if (strEquals(getDSIGLocalName(ki), "SPKIData")) {
XSECnew(k, DSIGKeyInfoSPKIData(mp_env, ki));
}
else if (strEquals(getDSIGLocalName(ki), "MgmtData")) {
XSECnew(k, DSIGKeyInfoMgmtData(mp_env, ki));
}
else if (strEquals(getDSIG11LocalName(ki), "DEREncodedKeyValue")) {
XSECnew(k, DSIGKeyInfoDEREncoded(mp_env, ki));
}
else if (strEquals(getXENCLocalName(ki), "EncryptedKey")) {
XSECnew(k, XENCEncryptedKeyImpl(mp_env, (DOMElement *) ki));
}
else {
XSECnew(k, DSIGKeyInfoExt(mp_env, ki));
}
// Now we know what the element type is - do the load and save
try {
k->load();
}
catch (...) {
delete k;
throw;
}
// Add
this->addKeyInfo(k);
return true;
}
// --------------------------------------------------------------------------------
// Retrieve a complete KeyInfo list
// --------------------------------------------------------------------------------
bool DSIGKeyInfoList::loadListFromXML(DOMNode * node) {
if (node == NULL || !strEquals(getDSIGLocalName(node), "KeyInfo")) {
throw XSECException(XSECException::ExpectedDSIGChildNotFound,
"DSIGKeyInfoList::loadListFromXML - expected KeyInfo node");
}
DOMNode *tmpKI = findFirstChildOfType(node, DOMNode::ELEMENT_NODE);
while (tmpKI != 0) {
// Find out what kind of KeyInfo child it is
if (tmpKI != 0 && strEquals(getDSIGLocalName(tmpKI), "RetrievalMethod")) {
// A reference to key information held elsewhere
const XMLCh * URI = NULL;
TXFMBase * currentTxfm;
bool isRawX509 = false;
DOMNamedNodeMap *atts = tmpKI->getAttributes();
const XMLCh * name;
XMLSize_t size;
if (atts == 0 || (size = atts->getLength()) == 0)
return true;
for (XMLSize_t i = 0; i < size; ++i) {
name = atts->item(i)->getNodeName();
if (strEquals(name, "URI")) {
URI = atts->item(i)->getNodeValue();
}
else if (strEquals(name, "Type")) {
// Check if this is a raw X509 cert
if (strEquals(atts->item(i)->getNodeValue(), DSIGConstants::s_unicodeStrURIRawX509)) {
isRawX509 = true;
}
}
else if (strEquals(name, "Id")) {
// For now ignore
}
else {
safeBuffer tmp, error;
error << (*mp_env->getSBFormatter() << name);
tmp.sbStrcpyIn("Unknown attribute in <RetrievalMethod> Element : ");
tmp.sbStrcatIn(error);
throw XSECException(XSECException::UnknownDSIGAttribute, tmp.rawCharBuffer());
}
}
if (isRawX509 == true) {
if (URI == NULL) {
throw XSECException(XSECException::ExpectedDSIGChildNotFound,
"Expected to find a URI attribute in a rawX509RetrievalMethod KeyInfo");
}
DSIGKeyInfoX509 * x509;
XSECnew(x509, DSIGKeyInfoX509(mp_env));
x509->setRawRetrievalURI(URI);
addKeyInfo(x509);
}
else {
// Find base transform using the base URI
currentTxfm = DSIGReference::getURIBaseTXFM(mp_env->getParentDocument(), URI, mp_env);
TXFMChain * chain;
XSECnew(chain, TXFMChain(currentTxfm));
Janitor<TXFMChain> j_chain(chain);
// Now check for transforms
DOMNode * tmpTran = tmpKI->getFirstChild();
while (tmpTran != 0 && (tmpTran->getNodeType() != DOMNode::ELEMENT_NODE))
// Skip text and comments
tmpTran = tmpTran->getNextSibling();
if (tmpTran != 0 && strEquals(getDSIGLocalName(tmpTran), "Transforms")) {
// Process the transforms using the static function.
// For the moment we don't really support remote KeyInfos, so
// Just built the transform list, process it and then destroy it.
DSIGTransformList * l = DSIGReference::loadTransforms(
tmpTran,
mp_env->getSBFormatter(),
mp_env);
DSIGTransformList::TransformListVectorType::size_type size, i;
size = l->getSize();
for (i = 0; i < size; ++ i) {
try {
l->item(i)->appendTransformer(chain);
}
catch (...) {
delete l;
throw;
}
}
delete l;
}
// Find out the type of the final transform and process accordingly
TXFMBase::nodeType type = chain->getLastTxfm()->getNodeType();
XSECXPathNodeList lst;
const DOMNode * element;
switch (type) {
case TXFMBase::DOM_NODE_DOCUMENT :
break;
case TXFMBase::DOM_NODE_DOCUMENT_FRAGMENT :
element = chain->getLastTxfm()->getFragmentNode();
if (element != NULL)
addXMLKeyInfo((DOMNode *) element);
break;
case TXFMBase::DOM_NODE_XPATH_NODESET :
lst = chain->getLastTxfm()->getXPathNodeList();
element = lst.getFirstNode();
while (element != NULL) {
// Try to add each element - just call KeyInfoList add as it will
// do the check to see if it is a valid KeyInfo
addXMLKeyInfo((DOMNode *) element);
element = lst.getNextNode();
}
break;
default :
throw XSECException(XSECException::XPathError);
}
// Delete the transform chain
chain->getLastTxfm()->deleteExpandedNameSpaces();
// Janitor will clean up chain
}
} /* if getNodeName == Retrieval Method */
// Now just run through each node type in turn to process "local" KeyInfos
else {
// This used to check the return value, and throw if the child was unknown.
// Now, should handle all cases.
addXMLKeyInfo(tmpKI);
}
if (tmpKI != NULL)
tmpKI = tmpKI->getNextSibling();
while (tmpKI != NULL && (tmpKI->getNodeType() != DOMNode::ELEMENT_NODE))
tmpKI = tmpKI->getNextSibling();
}
return true;
}
// --------------------------------------------------------------------------------
// Create new KeyInfo elements
// --------------------------------------------------------------------------------
DOMElement * DSIGKeyInfoList::createKeyInfo(void) {
// Assume that someone else has looked after the DOM
empty();
safeBuffer str;
DOMDocument * doc = mp_env->getParentDocument();
makeQName(str, mp_env->getDSIGNSPrefix(), "KeyInfo");
DOMElement * ret = doc->createElementNS(DSIGConstants::s_unicodeStrURIDSIG, str.rawXMLChBuffer());
mp_keyInfoNode = ret;
mp_env->doPrettyPrint(mp_keyInfoNode);
return ret;
}
DSIGKeyInfoValue * DSIGKeyInfoList::appendDSAKeyValue(const XMLCh * P,
const XMLCh * Q,
const XMLCh * G,
const XMLCh * Y) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create DSAKeyValue before creating KeyInfo");
}
// Create the new element
DSIGKeyInfoValue * v;
XSECnew(v, DSIGKeyInfoValue(mp_env));
mp_keyInfoNode->appendChild(v->createBlankDSAKeyValue(P, Q, G, Y));
mp_env->doPrettyPrint(mp_keyInfoNode);
// Add to the list
addKeyInfo(v);
return v;
}
DSIGKeyInfoValue * DSIGKeyInfoList::appendRSAKeyValue(const XMLCh * modulus,
const XMLCh * exponent) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create RSAKeyValue before creating KeyInfo");
}
// Create the new element
DSIGKeyInfoValue * v;
XSECnew(v, DSIGKeyInfoValue(mp_env));
mp_keyInfoNode->appendChild(v->createBlankRSAKeyValue(modulus, exponent));
mp_env->doPrettyPrint(mp_keyInfoNode);
// Add to the list
addKeyInfo(v);
return v;
}
DSIGKeyInfoX509 * DSIGKeyInfoList::appendX509Data(void) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create X509Data before creating KeyInfo");
}
DSIGKeyInfoX509 * x;
XSECnew(x, DSIGKeyInfoX509(mp_env));
mp_keyInfoNode->appendChild(x->createBlankX509Data());
mp_env->doPrettyPrint(mp_keyInfoNode);
// Add to the list
addKeyInfo(x);
return x;
}
DSIGKeyInfoName * DSIGKeyInfoList::appendKeyName(const XMLCh * name, bool isDName) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create KeyName before creating KeyInfo");
}
DSIGKeyInfoName * n;
XSECnew(n, DSIGKeyInfoName(mp_env));
mp_keyInfoNode->appendChild(n->createBlankKeyName(name, isDName));
mp_env->doPrettyPrint(mp_keyInfoNode);
// Add to the list
addKeyInfo(n);
return n;
}
DSIGKeyInfoPGPData * DSIGKeyInfoList::appendPGPData(const XMLCh * id, const XMLCh * packet) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create PGPData before creating KeyInfo");
}
DSIGKeyInfoPGPData * p;
XSECnew(p, DSIGKeyInfoPGPData(mp_env));
mp_keyInfoNode->appendChild(p->createBlankPGPData(id, packet));
mp_env->doPrettyPrint(mp_keyInfoNode);
addKeyInfo(p);
return p;
}
DSIGKeyInfoSPKIData * DSIGKeyInfoList::appendSPKIData(const XMLCh * sexp) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create SPKIData before creating KeyInfo");
}
DSIGKeyInfoSPKIData * s;
XSECnew(s, DSIGKeyInfoSPKIData(mp_env));
mp_keyInfoNode->appendChild(s->createBlankSPKIData(sexp));
mp_env->doPrettyPrint(mp_keyInfoNode);
addKeyInfo(s);
return s;
}
DSIGKeyInfoMgmtData * DSIGKeyInfoList::appendMgmtData(const XMLCh * data) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create MgmtData before creating KeyInfo");
}
DSIGKeyInfoMgmtData * m;
XSECnew(m, DSIGKeyInfoMgmtData(mp_env));
mp_keyInfoNode->appendChild(m->createBlankMgmtData(data));
mp_env->doPrettyPrint(mp_keyInfoNode);
addKeyInfo(m);
return m;
}
DSIGKeyInfoDEREncoded * DSIGKeyInfoList::appendDEREncoded(const XMLCh * data) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create DEREncodedKeyValue before creating KeyInfo");
}
DSIGKeyInfoDEREncoded * d;
XSECnew(d, DSIGKeyInfoDEREncoded(mp_env));
mp_keyInfoNode->appendChild(d->createBlankDEREncoded(data));
mp_env->doPrettyPrint(mp_keyInfoNode);
addKeyInfo(d);
return d;
}
// --------------------------------------------------------------------------------
// Some helper functions
// --------------------------------------------------------------------------------
void DSIGKeyInfoList::addAndInsertKeyInfo(DSIGKeyInfo * ref) {
if (mp_keyInfoNode == NULL) {
throw XSECException(XSECException::KeyInfoError,
"KeyInfoList - Attempt to create child before creating KeyInfo");
}
mp_keyInfoNode->appendChild(ref->getKeyInfoDOMNode());
mp_env->doPrettyPrint(mp_keyInfoNode);
addKeyInfo(ref);
}