/* * CAMultiSignature.cpp * * Created on: 17.07.2008 * Author: zenoxx */ #include "StdAfx.h" #include "CABase64.hpp" #include "CAUtil.hpp" #include "xml/DOM_Output.hpp" #include "CASignature.hpp" #include "CAMultiSignature.hpp" CAMultiSignature::CAMultiSignature() { m_signatures = NULL; m_sigCount = 0; m_xoredID = new UINT8[SHA_DIGEST_LENGTH]; for(SINT32 i = 0; ipSig; delete m_signatures->pCerts; m_signatures->pCerts = NULL; m_signatures->pSig = NULL; //store current pointer tmp = m_signatures; //go to next signature m_signatures = m_signatures->next; //delete currten signature delete tmp; tmp = NULL; } } SINT32 CAMultiSignature::addSignature(CASignature* a_signature, CACertStore* a_certs, UINT8* a_ski, UINT32 a_skiLen) { if(a_signature == NULL || a_certs == NULL || a_ski == NULL || a_skiLen != SHA_DIGEST_LENGTH) return E_UNKNOWN; for(SINT32 i=0; ipSig = a_signature; newSignature->pCerts = a_certs; newSignature->next = m_signatures; m_signatures = newSignature; m_sigCount++; return E_SUCCESS; } SINT32 CAMultiSignature::signXML(UINT8* in,UINT32 inlen,UINT8* out,UINT32* outlen, bool appendCerts) { if(in == NULL || inlen < 1 || out == NULL || outlen == NULL) return E_UNKNOWN; XERCES_CPP_NAMESPACE::DOMDocument* doc = parseDOMDocument(in, inlen); if(doc == NULL) return E_UNKNOWN; DOMElement* root = doc->getDocumentElement(); if(signXML(root, appendCerts) != E_SUCCESS) return E_UNKNOWN; return DOM_Output::dumpToMem(root,out,outlen); } SINT32 CAMultiSignature::signXML(DOMNode* node, bool appendCerts) { if(m_sigCount == 0) { CAMsg::printMsg(LOG_ERR, "Trying to sign a document with no signature-keys set!"); return E_UNKNOWN; } //getting the Document an the Node to sign XERCES_CPP_NAMESPACE::DOMDocument* doc = NULL; DOMNode* elemRoot = NULL; if(node->getNodeType() == DOMNode::DOCUMENT_NODE) { doc = (XERCES_CPP_NAMESPACE::DOMDocument*)node; elemRoot = doc->getDocumentElement(); } else { elemRoot = node; doc = node->getOwnerDocument(); } //check if there are already Signatures and if so remove them first... DOMNode* tmpSignature = NULL; while(getDOMChildByName(elemRoot, "Signature", tmpSignature, false) == E_SUCCESS) { DOMNode* n = elemRoot->removeChild(tmpSignature); if (n != NULL) { n->release(); n = NULL; } } //get SHA1-Digest UINT32 len = 0; UINT8* canonicalBuff = DOM_Output::makeCanonical(elemRoot, &len); if(canonicalBuff == NULL) { return E_UNKNOWN; } UINT8 dgst[SHA_DIGEST_LENGTH]; SHA1(canonicalBuff, len, dgst); delete[] canonicalBuff; canonicalBuff = NULL; UINT8 digestValue[512]; len = 512; if(CABase64::encode(dgst, SHA_DIGEST_LENGTH, digestValue, &len) != E_SUCCESS) { return E_UNKNOWN; } //append a signature for each SIGNATURE element we have SIGNATURE* currentSignature = m_signatures; UINT32 sigCount = 0; for(UINT32 i=0; isetAttribute(XMLString::transcode("URI"), XMLString::transcode("")); DOMElement* elemDigestMethod = createDOMElement(doc, "DigestMethod"); if(currentSignature->pSig->isDSA()) //DSA-Signature { setDOMElementAttribute(elemSignatureMethod, "Algorithm", (UINT8*)DSA_SHA1_REFERENCE); } else if(currentSignature->pSig->isRSA()) { setDOMElementAttribute(elemSignatureMethod, "Algorithm", (UINT8*)RSA_SHA1_REFERENCE); } #ifdef ECC else if(currentSignature->pSig->isECDSA()) { setDOMElementAttribute(elemSignatureMethod, "Algorithm", (UINT8*)ECDSA_SHA1_REFERENCE); } #endif //ECC setDOMElementAttribute(elemDigestMethod, "Algorithm", (UINT8*)SHA1_REFERENCE); DOMElement* elemDigestValue = createDOMElement(doc, "DigestValue"); setDOMElementValue(elemDigestValue, digestValue); elemSignedInfo->appendChild(elemCanonicalizationMethod); elemSignedInfo->appendChild(elemSignatureMethod); elemSignedInfo->appendChild(elemReference); elemReference->appendChild(elemDigestMethod); elemReference->appendChild(elemDigestValue); // Signing the SignInfo block.... canonicalBuff = DOM_Output::makeCanonical(elemSignedInfo,&len); if(canonicalBuff==NULL) { return E_UNKNOWN; } UINT32 sigLen = currentSignature->pSig->getSignatureSize(); UINT8 sigBuff[sigLen]; SINT32 ret = currentSignature->pSig->sign(canonicalBuff, len, sigBuff, &sigLen); delete[] canonicalBuff; canonicalBuff = NULL; if(ret != E_SUCCESS) { currentSignature = currentSignature->next; continue; } UINT sigSize = 255; UINT8 sig[255]; if(CABase64::encode(sigBuff, sigLen, sig, &sigSize) != E_SUCCESS) { currentSignature = currentSignature->next; continue; } //Makeing the whole Signature-Block.... DOMElement* elemSignature = createDOMElement(doc,"Signature"); DOMElement* elemSignatureValue = createDOMElement(doc,"SignatureValue"); setDOMElementValue(elemSignatureValue,sig); elemSignature->appendChild(elemSignedInfo); elemSignature->appendChild(elemSignatureValue); //Append KeyInfo if neccassary if(appendCerts) { //Making KeyInfo-Block DOMElement* tmpElemCerts = NULL; if(currentSignature->pCerts->encode(tmpElemCerts, doc) == E_SUCCESS && tmpElemCerts != NULL) { DOMElement* elemKeyInfo = createDOMElement(doc, "KeyInfo"); elemKeyInfo->appendChild(tmpElemCerts); elemSignature->appendChild(elemKeyInfo); } } elemRoot->appendChild(elemSignature); sigCount++; //goto next Signature currentSignature = currentSignature->next; } if(sigCount > 0) { CAMsg::printMsg(LOG_DEBUG, "Appended %d Signature(s) to XML-Structure\n", sigCount); return E_SUCCESS; } return E_UNKNOWN; } SINT32 CAMultiSignature::verifyXML(const UINT8* const in,UINT32 inlen, CACertificate* a_cert) { XERCES_CPP_NAMESPACE::DOMDocument* doc = parseDOMDocument(in,inlen); if(doc == NULL) { return E_UNKNOWN; } DOMElement* root = doc->getDocumentElement(); if(root == NULL) { return E_UNKNOWN; } return CAMultiSignature::verifyXML(root, a_cert); } SINT32 CAMultiSignature::verifyXML(DOMNode* root, CACertificate* a_cert) { CASignature* sigVerifier = new CASignature(); if(sigVerifier->setVerifyKey(a_cert) != E_SUCCESS) { CAMsg::printMsg(LOG_ERR, "Failed to set verify Key!"); return E_UNKNOWN; } UINT8* signatureMethod = sigVerifier->getSignatureMethod(); UINT32 signatureElementsCount = 10; DOMNode* signatureElements[signatureElementsCount]; getSignatureElements((DOMElement*)root, signatureElements, &signatureElementsCount); CAMsg::printMsg(LOG_DEBUG, "Found %d Signature(s) in XML-Structure\n", signatureElementsCount); UINT8 dgst[255]; UINT32 dgstlen=255; UINT8* out = NULL; UINT32 outlen; bool verified = false; //go through all appended Signatures an try to verify them with the given cert for(UINT32 i=0; iverify(out, outlen, tmpSig, tmpSiglen) == E_SUCCESS) { CAMsg::printMsg(LOG_DEBUG, "Signature Verification successful!\n"); verified = true; break; } } CAMsg::printMsg(LOG_WARNING, "Signature Verification not successful!\n"); delete[] out; out = NULL; continue; } if(verified) { //the signature could be verified, now check digestValue //first remove Signature-nodes from root and store them DOMNode* removedSignatures[signatureElementsCount]; for(UINT32 i=0; iremoveChild(signatureElements[i]); if(removedSignatures[i] == NULL) { //TODO do what? Verification will most likely fail, so just log the error for the moment CAMsg::printMsg(LOG_ERR, "Error removing signature-element %d of %d from Root-Node\n", i+1, signatureElementsCount); } } outlen = 5000; DOM_Output::makeCanonical(root, out, &outlen); //append Signature-nodes again for(UINT32 i=0; iappendChild(removedSignatures[i]); } } UINT8 newDgst[SHA_DIGEST_LENGTH]; SHA1(out, outlen, newDgst); delete[] out; out = NULL; for(int i=0; ipSig->sign(in, inlen, sig, siglen); } SINT32 CAMultiSignature::getXORofSKIs(UINT8* in, UINT32 inlen) { UINT8* tmp = (UINT8*) hex_to_string(m_xoredID, SHA_DIGEST_LENGTH); CACertificate::removeColons(tmp, strlen((const char*)tmp), in, &inlen); return E_SUCCESS; } SINT32 CAMultiSignature::getSignatureElements(DOMNode* parent, DOMNode** signatureNodes, UINT32* length) { if(parent == NULL) { return E_UNKNOWN; } DOMNode* child = parent->getFirstChild(); UINT32 count = 0; while(child != NULL) { if(XMLString::equals(child->getNodeName(), XMLString::transcode("Signature"))) { if(count < *length) { signatureNodes[count] = child; count++; } else { return E_UNKNOWN; } } child = child->getNextSibling(); } *length = count; return E_SUCCESS; }