xsec/dsig/DSIGKeyInfoList.cpp (324 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 * * 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); }