Mixe for Privacy and Anonymity in the Internet
CAMultiSignature.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000, The JAP-Team
00003 All rights reserved.
00004 Redistribution and use in source and binary forms, with or without modification,
00005 are permitted provided that the following conditions are met:
00006 
00007   - Redistributions of source code must retain the above copyright notice,
00008     this list of conditions and the following disclaimer.
00009 
00010   - Redistributions in binary form must reproduce the above copyright notice,
00011     this list of conditions and the following disclaimer in the documentation and/or
00012     other materials provided with the distribution.
00013 
00014   - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors
00015     may be used to endorse or promote products derived from this software without specific
00016     prior written permission.
00017 
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
00020 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
00021 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
00022 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00024 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00025 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00027 */
00028 /*
00029  * CAMultiSignature.cpp
00030  *
00031  *  Created on: 17.07.2008
00032  *      Author: zenoxx
00033  */
00034 #include "StdAfx.h"
00035 #include "CABase64.hpp"
00036 #include "CAUtil.hpp"
00037 #include "xml/DOM_Output.hpp"
00038 #include "CASignature.hpp"
00039 #include "CAMultiSignature.hpp"
00040 
00041 CAMultiSignature::CAMultiSignature()
00042 {
00043   m_signatures = NULL;
00044   m_sigCount = 0;
00045   m_xoredID = new UINT8[SHA_DIGEST_LENGTH];
00046   for(SINT32 i = 0; i<SHA_DIGEST_LENGTH; i++)
00047   {
00048     m_xoredID[i] = 0;
00049   }
00050 }
00051 
00052 CAMultiSignature::~CAMultiSignature()
00053 {
00054   SIGNATURE* tmp;
00055   while(m_signatures != NULL)
00056   {
00057     //delete Signer and CertStore
00058     delete m_signatures->pSig;
00059     delete m_signatures->pCerts;
00060     m_signatures->pCerts = NULL;
00061     m_signatures->pSig = NULL;
00062     delete[] m_signatures->pSKI;
00063     m_signatures->pSKI = NULL;
00064     //store current pointer
00065     tmp = m_signatures;
00066     //go to next signature
00067     m_signatures = m_signatures->next;
00068     //delete current signature
00069     delete tmp;
00070     tmp = NULL;
00071   }
00072 }
00073 
00074 
00075 SINT32 CAMultiSignature::findSKI(const UINT8* a_strSKI)
00076 {
00077   SIGNATURE* tmp = m_signatures;
00078   UINT8 tmpSKI[200];
00079   
00080   if (tmp == NULL)
00081   {
00082     return E_UNKNOWN;
00083   }
00084   
00085   while(tmp != NULL)
00086   {
00087     if (getSKI(tmpSKI, 200, tmp->pSKI) == E_SUCCESS &&
00088       strncmp((char*)a_strSKI, (char*)tmpSKI, strlen((char*)tmpSKI) ) == 0)
00089     {
00090       return E_SUCCESS;
00091     }
00092     tmp = tmp->next;
00093   }
00094   
00095   if (getSKI(tmpSKI, 200, m_xoredID) == E_SUCCESS &&
00096     strncmp((char*)a_strSKI, (char*)tmpSKI, strlen((char*)tmpSKI) ) == 0)
00097   {
00098     return E_SUCCESS;
00099   }
00100   
00101   return E_NOT_FOUND;
00102 }
00103 
00104 SINT32 CAMultiSignature::addSignature(CASignature* a_signature, CACertStore* a_certs, UINT8* a_ski, UINT32 a_skiLen)
00105 {
00106   if(a_signature == NULL || a_certs == NULL || a_ski == NULL || a_skiLen != SHA_DIGEST_LENGTH)
00107     return E_UNKNOWN;
00108   for(SINT32 i=0; i<SHA_DIGEST_LENGTH; i++)
00109   {
00110     m_xoredID[i] = m_xoredID[i] ^ a_ski[i];
00111   }
00112   SIGNATURE* newSignature = new SIGNATURE;
00113   newSignature->pSig = a_signature;
00114   newSignature->pCerts = a_certs;
00115   newSignature->pSKI = new UINT8[a_skiLen];
00116   memcpy(newSignature->pSKI, a_ski, a_skiLen);
00117   newSignature->next = m_signatures;
00118   m_signatures = newSignature;
00119   m_sigCount++;
00120   return E_SUCCESS;
00121 }
00122 
00123 SINT32 CAMultiSignature::signXML(UINT8* in,UINT32 inlen,UINT8* out,UINT32* outlen, bool appendCerts)
00124 {
00125   if(in == NULL || inlen < 1 || out == NULL || outlen == NULL)
00126     return E_UNKNOWN;
00127 
00128   XERCES_CPP_NAMESPACE::DOMDocument* doc = parseDOMDocument(in, inlen);
00129   if(doc == NULL)
00130     return E_UNKNOWN;
00131   DOMElement* root = doc->getDocumentElement();
00132   if(signXML(root, appendCerts) != E_SUCCESS)
00133     return E_UNKNOWN;
00134   return DOM_Output::dumpToMem(root,out,outlen);
00135 }
00136 
00137 SINT32 CAMultiSignature::signXML(DOMNode* node, bool appendCerts)
00138 {
00139   if(m_sigCount == 0)
00140   {
00141     CAMsg::printMsg(LOG_ERR, "Trying to sign a document with no signature-keys set!");
00142     return E_UNKNOWN;
00143   }
00144 
00145   //getting the Document an the Node to sign
00146   XERCES_CPP_NAMESPACE::DOMDocument* doc = NULL;
00147   DOMNode* elemRoot = NULL;
00148   if(node->getNodeType() == DOMNode::DOCUMENT_NODE)
00149   {
00150     doc = (XERCES_CPP_NAMESPACE::DOMDocument*)node;
00151     elemRoot = doc->getDocumentElement();
00152   }
00153   else
00154   {
00155     elemRoot = node;
00156     doc = node->getOwnerDocument();
00157   }
00158 
00159   //check if there are already Signatures and if so remove them first...
00160   DOMNode* tmpSignature = NULL;
00161   while(getDOMChildByName(elemRoot, "Signature", tmpSignature, false) == E_SUCCESS)
00162   {
00163     DOMNode* n = elemRoot->removeChild(tmpSignature);
00164     if (n != NULL)
00165     {
00166       n->release();
00167       n = NULL;
00168     }
00169   }
00170   //get SHA1-Digest
00171   UINT32 len = 0;
00172   UINT8* canonicalBuff = DOM_Output::makeCanonical(elemRoot, &len);
00173   if(canonicalBuff == NULL)
00174   {
00175     return E_UNKNOWN;
00176   }
00177   UINT8 dgst[SHA_DIGEST_LENGTH];
00178   SHA1(canonicalBuff, len, dgst);
00179   delete[] canonicalBuff;
00180   canonicalBuff = NULL;
00181 
00182   UINT8 digestValue[512];
00183   len = 512;
00184   if(CABase64::encode(dgst, SHA_DIGEST_LENGTH, digestValue, &len) != E_SUCCESS)
00185   {
00186     return E_UNKNOWN;
00187   }
00188 
00189   //append a signature for each SIGNATURE element we have
00190   SIGNATURE* currentSignature = m_signatures;
00191   UINT32 sigCount = 0;
00192   for(UINT32 i=0; i<m_sigCount; i++)
00193   {
00194     //Creating the Sig-InfoBlock....
00195     DOMElement* elemSignedInfo = createDOMElement(doc, "SignedInfo");
00196     DOMElement* elemCanonicalizationMethod = createDOMElement(doc, "CanonicalizationMethod");
00197     DOMElement* elemSignatureMethod = createDOMElement(doc, "SignatureMethod");
00198     DOMElement* elemReference = createDOMElement(doc, "Reference");
00199     elemReference->setAttribute(XMLString::transcode("URI"), XMLString::transcode(""));
00200     DOMElement* elemDigestMethod = createDOMElement(doc, "DigestMethod");
00201     if(currentSignature->pSig->isDSA()) //DSA-Signature
00202     {
00203       setDOMElementAttribute(elemSignatureMethod, "Algorithm", (UINT8*)DSA_SHA1_REFERENCE);
00204     }
00205     else if(currentSignature->pSig->isRSA())
00206     {
00207       setDOMElementAttribute(elemSignatureMethod, "Algorithm", (UINT8*)RSA_SHA1_REFERENCE);
00208     }
00209 #ifdef ECC
00210     else if(currentSignature->pSig->isECDSA())
00211     {
00212       setDOMElementAttribute(elemSignatureMethod, "Algorithm", (UINT8*)ECDSA_SHA1_REFERENCE);
00213     }
00214 #endif //ECC
00215     setDOMElementAttribute(elemDigestMethod, "Algorithm", (UINT8*)SHA1_REFERENCE);
00216     DOMElement* elemDigestValue = createDOMElement(doc, "DigestValue");
00217     setDOMElementValue(elemDigestValue, digestValue);
00218 
00219     elemSignedInfo->appendChild(elemCanonicalizationMethod);
00220     elemSignedInfo->appendChild(elemSignatureMethod);
00221     elemSignedInfo->appendChild(elemReference);
00222     elemReference->appendChild(elemDigestMethod);
00223     elemReference->appendChild(elemDigestValue);
00224 
00225     // Signing the SignInfo block....
00226     canonicalBuff = DOM_Output::makeCanonical(elemSignedInfo,&len);
00227     if(canonicalBuff==NULL)
00228     {
00229       return E_UNKNOWN;
00230     }
00231 
00232     UINT32 sigLen = currentSignature->pSig->getSignatureSize();
00233     UINT8* sigBuff=new UINT8[sigLen];
00234     SINT32 ret = currentSignature->pSig->sign(canonicalBuff, len, sigBuff, &sigLen);
00235     delete[] canonicalBuff;
00236     canonicalBuff = NULL;
00237     if(ret != E_SUCCESS)
00238     {
00239       currentSignature = currentSignature->next;
00240       delete[] sigBuff;
00241       continue;
00242     }
00243     UINT sigSize = 255;
00244     UINT8 sig[255];
00245     if(CABase64::encode(sigBuff, sigLen, sig, &sigSize) != E_SUCCESS)
00246     {
00247       currentSignature = currentSignature->next;
00248       delete[] sigBuff;
00249       continue;
00250     }
00251 
00252     //Makeing the whole Signature-Block....
00253     DOMElement* elemSignature = createDOMElement(doc,"Signature");
00254     DOMElement* elemSignatureValue = createDOMElement(doc,"SignatureValue");
00255     setDOMElementValue(elemSignatureValue,sig);
00256     elemSignature->appendChild(elemSignedInfo);
00257     elemSignature->appendChild(elemSignatureValue);
00258 
00259     //Append KeyInfo if neccassary
00260     if(appendCerts)
00261     {
00262       //Making KeyInfo-Block
00263       DOMElement* tmpElemCerts = NULL;
00264       if(currentSignature->pCerts->encode(tmpElemCerts, doc) == E_SUCCESS && tmpElemCerts != NULL)
00265       {
00266         DOMElement* elemKeyInfo = createDOMElement(doc, "KeyInfo");
00267         elemKeyInfo->appendChild(tmpElemCerts);
00268         elemSignature->appendChild(elemKeyInfo);
00269       }
00270     }
00271     elemRoot->appendChild(elemSignature);
00272     sigCount++;
00273 
00274     //goto next Signature
00275     currentSignature = currentSignature->next;
00276     delete[] sigBuff;
00277   }
00278   if(sigCount > 0)
00279   {
00280     //CAMsg::printMsg(LOG_DEBUG, "Appended %d Signature(s) to XML-Structure\n", sigCount);
00281     return E_SUCCESS;
00282   }
00283   return E_UNKNOWN;
00284 }
00285 
00286 SINT32 CAMultiSignature::verifyXML(const UINT8* const in,UINT32 inlen, CACertificate* a_cert)
00287 {
00288   XERCES_CPP_NAMESPACE::DOMDocument* doc = parseDOMDocument(in,inlen);
00289   if(doc == NULL)
00290   {
00291     return E_UNKNOWN;
00292   }
00293   DOMElement* root = doc->getDocumentElement();
00294   if(root == NULL)
00295   {
00296     return E_UNKNOWN;
00297   }
00298   return CAMultiSignature::verifyXML(root, a_cert);
00299 }
00300 
00301 SINT32 CAMultiSignature::verifyXML(DOMNode* root, CACertificate* a_cert)
00302 {
00303   CASignature* sigVerifier = new CASignature();
00304   if(sigVerifier->setVerifyKey(a_cert) != E_SUCCESS)
00305   {
00306     CAMsg::printMsg(LOG_ERR, "Failed to set verify Key!");
00307     return E_UNKNOWN;
00308   }
00309   UINT8* signatureMethod = sigVerifier->getSignatureMethod();
00310 
00311   UINT32 signatureElementsCount = MAX_SIGNATURE_ELEMENTS;
00312   DOMNode* signatureElements[MAX_SIGNATURE_ELEMENTS];
00313 
00314   getSignatureElements((DOMElement*)root, signatureElements, &signatureElementsCount);
00315   CAMsg::printMsg(LOG_DEBUG, "Found %d Signature(s) in XML-Structure\n", signatureElementsCount);
00316 
00317   UINT8 dgst[255];
00318   UINT32 dgstlen=255;
00319   UINT8* out = NULL;
00320   UINT32 outlen;
00321   bool verified = false;
00322   //go through all appended Signatures an try to verify them with the given cert
00323   for(UINT32 i=0; i<signatureElementsCount; i++)
00324   {
00325     dgstlen=255;
00326     CAMsg::printMsg(LOG_DEBUG, "Trying to verify signature %d of %d!\n", i+1, signatureElementsCount);
00327     DOMNode* elemSignature = signatureElements[i];
00328 
00329     if(elemSignature == NULL)
00330     {
00331       CAMsg::printMsg(LOG_DEBUG, "Error: signature element is NULL\n");
00332       continue;
00333     }
00334     DOMNode* elemSigInfo;
00335     getDOMChildByName(elemSignature, "SignedInfo", elemSigInfo);
00336     if(elemSigInfo == NULL)
00337     {
00338       CAMsg::printMsg(LOG_DEBUG, "Error: signed info is NULL\n");
00339       continue;
00340     }
00341     //check if SignatureMethod fits...
00342     DOMNode* elemSigMethod;
00343     getDOMChildByName(elemSigInfo, "SignatureMethod", elemSigMethod);
00344     UINT32 algLen = 255;
00345     UINT8 algorithm[255];
00346     getDOMElementAttribute(elemSigMethod, (const char*)"Algorithm", algorithm, &algLen);
00347     //if signatureMethod is set check if its equal
00348     if(signatureMethod != NULL &&
00349         strncmp((const char*)algorithm, (const char*)signatureMethod, algLen) != E_SUCCESS)
00350     {
00351       CAMsg::printMsg(LOG_DEBUG, "Did NOT find matching SignatureMethods: %s and %s!\n", signatureMethod, algorithm);
00352       continue;
00353     }
00354     DOMNode* elemSigValue;
00355     getDOMChildByName(elemSignature, "SignatureValue", elemSigValue);
00356     if(elemSigValue == NULL)
00357     {
00358       CAMsg::printMsg(LOG_DEBUG, "Error: signature value is NULL\n");
00359       continue;
00360     }
00361     DOMNode* elemReference;
00362     getDOMChildByName(elemSigInfo, "Reference", elemReference);
00363     if(elemReference == NULL)
00364     {
00365       CAMsg::printMsg(LOG_DEBUG, "Error: signature reference is NULL\n");
00366       continue;
00367     }
00368     DOMNode* elemDigestValue;
00369     getDOMChildByName(elemReference, "DigestValue", elemDigestValue);
00370     if(elemDigestValue == NULL)
00371     {
00372       CAMsg::printMsg(LOG_DEBUG, "Error: digest value is NULL\n");
00373       continue;
00374     }
00375     if(getDOMElementValue(elemDigestValue,dgst,&dgstlen)!=E_SUCCESS)
00376     {
00377       CAMsg::printMsg(LOG_DEBUG, "Error: could not get digest value from XML\n");
00378       continue;
00379     }
00380     if(CABase64::decode(dgst,dgstlen,dgst,&dgstlen)!=E_SUCCESS)
00381     {
00382       CAMsg::printMsg(LOG_DEBUG, "Error: could not decode digest value\n");
00383       continue;
00384     }
00385     if(dgstlen!=SHA_DIGEST_LENGTH)
00386     {
00387       CAMsg::printMsg(LOG_DEBUG, "Error: digest is %d long, should be %d\n", dgstlen, SHA_DIGEST_LENGTH);
00388       continue;
00389     }
00390     UINT32 tmpSiglen = 255;
00391     UINT8 tmpSig[255];
00392     if(getDOMElementValue(elemSigValue,tmpSig,&tmpSiglen)!=E_SUCCESS)
00393     {
00394       CAMsg::printMsg(LOG_DEBUG, "Error: could not get signature value from XML\n");
00395       continue;
00396     }
00397     if(CABase64::decode(tmpSig,tmpSiglen,tmpSig,&tmpSiglen)!=E_SUCCESS)
00398     {
00399       CAMsg::printMsg(LOG_DEBUG, "Error: could not decode signature value\n");
00400       continue;
00401     }
00402     outlen = 5000;
00403     out = new UINT8[outlen];
00404     if(DOM_Output::makeCanonical(elemSigInfo, out, &outlen) == E_SUCCESS)
00405     {
00406       if(sigVerifier->verify(out, outlen, tmpSig, tmpSiglen) == E_SUCCESS)
00407       {
00408         CAMsg::printMsg(LOG_DEBUG, "Signature verification successful!\n");
00409         verified = true;
00410         break;
00411       }
00412     }
00413     CAMsg::printMsg(LOG_WARNING, "Signature verification not successful!\n");
00414     delete[] out;
00415     out = NULL;
00416     continue;
00417   }
00418   if(verified)
00419   {
00420     //the signature could be verified, now check digestValue
00421     //first remove Signature-nodes from root and store them
00422     DOMNode* removedSignatures[MAX_SIGNATURE_ELEMENTS];
00423 
00424     for(UINT32 i=0; i<signatureElementsCount; i++)
00425     {
00426       removedSignatures[i] = root->removeChild(signatureElements[i]);
00427       if(removedSignatures[i] == NULL)
00428       {
00429         //TODO do what? Verification will most likely fail, so just log the error for the moment
00430         CAMsg::printMsg(LOG_ERR, "Error removing signature-element %d of %d from Root-Node\n", i+1, signatureElementsCount);
00431       }
00432     }
00433 
00434     outlen = 5000;
00435     DOM_Output::makeCanonical(root, out, &outlen);
00436 
00437     //append Signature-nodes again
00438     for(UINT32 i=0; i<signatureElementsCount; i++)
00439     {
00440       if(removedSignatures[i] != NULL)
00441       {
00442         root->appendChild(removedSignatures[i]);
00443       }
00444     }
00445 
00446     UINT8 newDgst[SHA_DIGEST_LENGTH];
00447     SHA1(out, outlen, newDgst);
00448     delete[] out;
00449     out = NULL;
00450     for(int i=0; i<SHA_DIGEST_LENGTH; i++)
00451     {
00452       if(newDgst[i] != dgst[i])
00453       {
00454         CAMsg::printMsg(LOG_ERR, "Error checking XML-Signature DigestValue!\n");
00455         return E_UNKNOWN;
00456       }
00457     }
00458     return E_SUCCESS;
00459   }
00460   CAMsg::printMsg(LOG_ERR, "XML-Signature could not be verified!\n");
00461   return E_UNKNOWN;
00462 }
00464 SINT32 CAMultiSignature::sign(UINT8* in,UINT32 inlen,UINT8* sig,UINT32* siglen)
00465 {
00466   if(m_sigCount < 1)
00467   {
00468     return E_UNKNOWN;
00469   }
00470   return m_signatures->pSig->sign(in, inlen, sig, siglen);
00471 }
00472 
00473 SINT32 CAMultiSignature::getSKI(UINT8* out, UINT32 outlen, const UINT8* a_ski)
00474 {
00475   UINT8* tmp = (UINT8*) hex_to_string((unsigned char*)a_ski, SHA_DIGEST_LENGTH);
00476   UINT32 len=outlen;
00477   if (CACertificate::removeColons(tmp, strlen((const char*)tmp), out, &len) != E_SUCCESS)
00478   {
00479     OPENSSL_free(tmp);
00480     return E_UNKNOWN;
00481   }
00482   OPENSSL_free(tmp);
00483   strtrim(out);
00484   return E_SUCCESS;
00485 }
00486 
00487 SINT32 CAMultiSignature::getXORofSKIs(UINT8* out, UINT32 outlen)
00488 {
00489   return getSKI(out, outlen, m_xoredID);
00490 }