/* Copyright (c) 2000, The JAP-Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ /* * CAMultiSignature.cpp * * Created on: 17.07.2008 * Author: zenoxx */ #include "StdAfx.h" #if !defined ONLY_LOCAL_PROXY || defined INCLUDE_MIDDLE_MIX #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]; memset(m_xoredID,0,SHA_DIGEST_LENGTH); } CAMultiSignature::~CAMultiSignature() { SIGNATURE* tmp; while(m_signatures != NULL) { //delete Signer and CertStore delete m_signatures->pSig; delete m_signatures->pCerts; m_signatures->pCerts = NULL; m_signatures->pSig = NULL; delete[] m_signatures->pSKI; m_signatures->pSKI = NULL; //store current pointer tmp = m_signatures; //go to next signature m_signatures = m_signatures->next; //delete current signature delete tmp; tmp = NULL; } delete[] m_xoredID; } 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 HAVE_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=new UINT8[sigLen]; SINT32 ret = currentSignature->pSig->sign(canonicalBuff, len, sigBuff, &sigLen); delete[] canonicalBuff; canonicalBuff = NULL; if(ret != E_SUCCESS) { currentSignature = currentSignature->next; delete[] sigBuff; continue; } UINT sigSize = 255; UINT8 sig[255]; if(CABase64::encode(sigBuff, sigLen, sig, &sigSize) != E_SUCCESS) { currentSignature = currentSignature->next; delete[] sigBuff; 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; delete[] sigBuff; } 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!"); delete sigVerifier; return E_UNKNOWN; } UINT8* signatureMethod = sigVerifier->getSignatureMethod(); UINT32 signatureElementsCount = MAX_SIGNATURE_ELEMENTS; DOMNode* signatureElements[MAX_SIGNATURE_ELEMENTS]; 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; } delete sigVerifier; if(verified) { //the signature could be verified, now check digestValue //first remove Signature-nodes from root and store them DOMNode* removedSignatures[MAX_SIGNATURE_ELEMENTS]; 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::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->pSKI = new UINT8[a_skiLen]; memcpy(newSignature->pSKI, a_ski, a_skiLen); newSignature->next = m_signatures; m_signatures = newSignature; m_sigCount++; return E_SUCCESS; } SINT32 CAMultiSignature::getXORofSKIs(UINT8* out, UINT32 outlen) { return getSKI(out, outlen, m_xoredID); } SINT32 CAMultiSignature::getSKI(UINT8* out, UINT32 outlen, const UINT8* a_ski) { #if OPENSSL_VERSION_NUMBER < 0x10100000L UINT8* tmp = (UINT8*) hex_to_string((unsigned char*)a_ski, SHA_DIGEST_LENGTH); #else UINT8* tmp = (UINT8*) OPENSSL_buf2hexstr((unsigned char*)a_ski, SHA_DIGEST_LENGTH); #endif UINT32 len=outlen; if (CACertificate::removeColons(tmp, strlen((const char*)tmp), out, &len) != E_SUCCESS) { OPENSSL_free(tmp); return E_UNKNOWN; } OPENSSL_free(tmp); strtrim(out); return E_SUCCESS; } #endif #ifndef ONLY_LOCAL_PROXY SINT32 CAMultiSignature::findSKI(const UINT8* a_strSKI) { SIGNATURE* tmp = m_signatures; UINT8 tmpSKI[200]; if (tmp == NULL) { return E_UNKNOWN; } while(tmp != NULL) { if (getSKI(tmpSKI, 200, tmp->pSKI) == E_SUCCESS && strncmp((char*)a_strSKI, (char*)tmpSKI, strlen((char*)tmpSKI) ) == 0) { return E_SUCCESS; } tmp = tmp->next; } if (getSKI(tmpSKI, 200, m_xoredID) == E_SUCCESS && strncmp((char*)a_strSKI, (char*)tmpSKI, strlen((char*)tmpSKI) ) == 0) { return E_SUCCESS; } return E_NOT_FOUND; } #endif //ONLY_LOCAL_PROXY