/* * Copyright 2002-2005 The Apache Software Foundation. * * Licensed 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: DSIGKeyInfoList.cpp 464121 2006-10-15 05:15:59Z blautenb $ * */ // XSEC Includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../xenc/impl/XENCEncryptedKeyImpl.hpp" #include 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() { return m_keyInfoList.size(); } DSIGKeyInfo * DSIGKeyInfoList::item(size_type index) { 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() { 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(getXENCLocalName(ki), "EncryptedKey")) { XSECnew(k, XENCEncryptedKeyImpl(mp_env, (DOMElement *) ki)); } else { return false; } // 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 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 j_chain(chain); // Now check for transforms tmpKI = tmpKI->getFirstChild(); while (tmpKI != 0 && (tmpKI->getNodeType() != DOMNode::ELEMENT_NODE)) // Skip text and comments tmpKI = tmpKI->getNextSibling(); if (tmpKI != 0 && strEquals(getDSIGLocalName(tmpKI), "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( tmpKI, 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 valud 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 if (!addXMLKeyInfo(tmpKI)) { throw XSECException(XSECException::KeyInfoError, "Unknown KeyInfo element found"); } 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; } // -------------------------------------------------------------------------------- // Some helper functions // -------------------------------------------------------------------------------- void DSIGKeyInfoList::addAndInsertKeyInfo(DSIGKeyInfo * ref) { if (mp_keyInfoNode == NULL) { throw XSECException(XSECException::KeyInfoError, "KeyInfoList - Attempt to create MgmtData before creating KeyInfo"); } mp_keyInfoNode->appendChild(ref->getKeyInfoDOMNode()); mp_env->doPrettyPrint(mp_keyInfoNode); addKeyInfo(ref); }