libdigidocpp
SignatureBES.cpp
Go to the documentation of this file.
1 /*
2  * libdigidocpp
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  */
19 
20 #include "SignatureBES.h"
21 
22 #include "log.h"
23 #include "Conf.h"
24 #include "Document.h"
25 #include "crypto/Digest.h"
26 #include "crypto/OpenSSLHelpers.h"
28 #include "crypto/crypt/RSACrypt.h"
29 #include "crypto/ocsp/OCSP.h"
30 #include "util/DateTime.h"
31 #include "util/File.h"
32 
33 #include <xercesc/dom/DOM.hpp>
34 #include <xsec/canon/XSECC14n20010315.hpp>
35 #include <xsec/utils/XSECPlatformUtils.hpp>
36 
37 #include <iostream>
38 #include <list>
39 
43 const std::string digidoc::SignatureBES::MEDIA_TYPE = "signature/bdoc-1.0/BES";
44 
48 digidoc::SignatureBES::SignatureBES(unsigned int id, const BDoc &bdoc)
49  : Signature(id)
50  , bdoc(bdoc)
51 {
52 }
53 
59 digidoc::SignatureBES::SignatureBES(const std::string& path, const BDoc &bdoc) throw(SignatureException)
60  : Signature(path)
61  , bdoc(bdoc)
62 {
63  // Base class has verified the signature to be valid according to XML-DSig.
64  // Now perform additional checks here and throw if this signature is
65  // ill-formed according to BDoc.
66 
67  Signature::getSignedSignatureProperties(); // assumed to throw in case this block doesn't exist
68 
69  Signature::getSigningX509CertificateType(); // assumed to throw in case this block doesn't exist
70 
71  const dsig::SignatureType::IdOptional &idOptional = signature->id();
72  if ( !idOptional.present() )
73  THROW_SIGNATUREEXCEPTION("Signature element mandatory attribute 'Id' is missing");
74  if ( idOptional.get().empty() )
75  THROW_SIGNATUREEXCEPTION("Signature element mandatory attribute 'Id' is empty");
76 
77  // TODO: implement more checks?
78 }
79 
81 
86 {
87  return MEDIA_TYPE;
88 }
89 
99 {
100  // A "master" exception containing all problems (causes) with this signature.
101  // It'll be only thrown in case we have a reason (cause).
102  SignatureException resultException(__FILE__, __LINE__, "Signature is invalid");
103 
104 
105  try
106  {
107  checkQualifyingProperties();
108  }
109  catch (digidoc::Exception& e)
110  {
111  resultException.addCause(e); // remember and proceed
112  }
113 
114  try
115  {
116  checkSignature();
117  }
118  catch (digidoc::Exception& e)
119  {
120  resultException.addCause(e); // remember and proceed
121  }
122 
123  try
124  {
125  checkSigningCertificate();
126  }
127  catch (digidoc::Exception& e)
128  {
129  resultException.addCause(e); // remember and proceed
130  }
131 
132  // now check if we've gathered some problems with this signature
133  if ( resultException.hasCause() )
134  {
135  throw resultException;
136  }
137  // else: this signature is fine
138 }
139 
146 {
147  // FIXME: Add exception handling.
148 
149  // Get signing signature.
150  X509Cert cert = getSigningCertificate();
151 
152  // Get issuer certificate.
153  X509* issuerCert = X509CertStore::getInstance()->getCert(cert.getIssuerNameAsn1());
154  X509_scope issuerCertScope(&issuerCert);
155  if(issuerCert == NULL)
156  {
157  THROW_SIGNATUREEXCEPTION("Failed to load issuer certificate.");
158  }
159 
160  Conf* conf = Conf::getInstance();
161 
162  // Get OCSP responder certificate.
163  // FIXME: throws IOException, handle it
164  Conf::OCSPConf ocspConf = conf->getOCSP(cert.getIssuerName());
165  if(ocspConf.issuer.empty())
166  {
167  SignatureException e(__FILE__, __LINE__, "Failed to find ocsp responder.");
169  throw e;
170  }
171  STACK_OF(X509)* ocspCerts = X509CertStore::getInstance()->findCerts( "CN", ocspConf.cert );
172  X509Stack_scope ocspCertsScope(&ocspCerts);
173 
174  // Check the certificate validity from OCSP server.
175  try
176  {
177  OCSP ocsp;
178  ocsp.setSkew(120);//XXX: load from conf
179  ocsp.setOCSPCerts(ocspCerts);
180  ocsp.setUrl(ocspConf.url);
181  std::auto_ptr<Digest> calc(new Digest());
182  calc->update(getSignatureValue());
183  return CertStatus(ocsp.checkCert(cert.getX509(), issuerCert, calc->getDigest()));
184  }
185  catch(const IOException&)
186  {
187  THROW_SIGNATUREEXCEPTION("Failed to check the certificate validity from OCSP server.");
188  }
189  catch(const OCSPException&)
190  {
191  THROW_SIGNATUREEXCEPTION("Failed to check the certificate validity from OCSP server.");
192  }
193  return GOOD;
194 }
195 
201 std::vector<std::string> digidoc::SignatureBES::referenceDigestMethods() const
202 {
203  std::vector<std::string> result;
204  const dsig::SignedInfoType::ReferenceSequence &refSeq = signature->signedInfo().reference();
205  for(dsig::SignedInfoType::ReferenceSequence::const_iterator i = refSeq.begin();
206  i != refSeq.end(); ++i)
207  result.push_back(i->digestMethod().algorithm());
208  return result;
209 }
210 
218 {
219  // Calculate digests for the documents and add these to the signature reference.
220  for(unsigned int i = 0; i < bdoc.documentCount(); ++i)
221  {
222  digidoc::Document doc = bdoc.getDocument(i);
223  try
224  {
225  DEBUG("Adding document '%s', '%s' to the signature references.", doc.getFileName().c_str(), doc.getMediaType().c_str());
226  // URIs must encode non-ASCII characters in the format %HH where HH is the hex representation of the character
227  std::string uri = std::string("/") + digidoc::util::File::toUri(doc.getFileName());
228  std::auto_ptr<Digest> calc(new Digest());
229  std::vector<unsigned char> digest = doc.calcDigest(calc.get());
230  DEBUGMEM("digest", &digest[0], digest.size());
231  addReference(uri, calc->getUri(), digest);
232  }
233  catch(const Exception& e)
234  {
235  delete signature;
236  THROW_SIGNEXCEPTION_CAUSE(e, "Failed to calculate digests for document '%s'.", doc.getFileName().c_str());
237  }
238  }
239 
240  // Set required signature fields.
241  try
242  {
243  setSigningCertificate(signer->getCert());
244  setSignatureProductionPlace(signer->getSignatureProductionPlace());
245  setSignerRole(signer->getSignerRole());
246  setSigningTime(util::date::currentTime());
247  }
248  catch( const IOException &e )
249  {
250  THROW_SIGNEXCEPTION_CAUSE( e, "Failed to sign document" );
251  }
252 
253  xml_schema::Uri uri(URI_ID_RSA_SHA1);
254  switch(signer->type())
255  {
256  case NID_sha224: uri = xml_schema::Uri(URI_ID_RSA_SHA224); break;
257  case NID_sha256: uri = xml_schema::Uri(URI_ID_RSA_SHA256); break;
258  case NID_sha384: uri = xml_schema::Uri(URI_ID_RSA_SHA384); break;
259  case NID_sha512: uri = xml_schema::Uri(URI_ID_RSA_SHA512); break;
260  default: break;
261  }
262  signature->signedInfo().signatureMethod(dsig::SignatureMethodType(uri));
263 
264  // Calculate digest of the Signature->Object->SignedProperties node.
265  std::auto_ptr<Digest> calc(new Digest());
266  std::vector<unsigned char> digest = calcDigestOnNode(calc.get(), XADES_NAMESPACE, "SignedProperties");
267  addReference("#" + getId() +"-SignedProperties", calc->getUri(), digest, "http://uri.etsi.org/01903#SignedProperties");
268 
269  // Calculate SHA digest of the Signature->SignedInfo node.
270  calc.reset(new Digest(signer->type()));
271  return calcDigestOnNode(calc.get(), URI_ID_DSIG, "SignedInfo");
272 }
273 
283 {
284  std::vector<unsigned char> sha = prepareSignedInfo(signer);
285  Signer::Digest sigDigestSha = { signer->type(), &sha[0], (unsigned int)sha.size() };
286 
287  // Sign the calculated SHA digest and add the signature value (SHA-RSA) to the signature.
288  int size = 128;
289  try
290  {
291  size = X509Cert(signer->getCert()).getPaddingSize();
292  }
293  catch( const IOException &e )
294  {
295  THROW_SIGNEXCEPTION_CAUSE( e, "Failed to sign document" );
296  }
297 
298  std::vector<unsigned char> buf(size);
299  Signer::Signature signatureShaRsa = { &buf[0], (unsigned int)buf.size() };
300  signer->sign(sigDigestSha, signatureShaRsa);
301  setSignatureValue(signatureShaRsa);
303 }
304 
309 {
310  checkSignedInfo();
311  checkKeyInfo();
312  checkSignatureValue();
313 }
314 
319 {
320  checkSignatureMethod();
321  checkReferences();
322 }
323 
328 {
329  std::string algorithmType = getSignatureMethod();
330  if ( algorithmType != URI_ID_RSA_SHA1 &&
331  algorithmType != URI_ID_RSA_SHA224 &&
332  algorithmType != URI_ID_RSA_SHA256 &&
333  algorithmType != URI_ID_RSA_SHA384 &&
334  algorithmType != URI_ID_RSA_SHA512 )//FIXME: const or dynamic
335  {
336  THROW_SIGNATUREEXCEPTION("Unsupported SignedInfo signature method \"%s\"", algorithmType.c_str());
337  }
338 }
339 
344 {
345  dsig::SignedInfoType& signedInfo = signature->signedInfo();
346  dsig::SignedInfoType::ReferenceSequence& refSeq = signedInfo.reference();
347 
348  if ( refSeq.size() != (bdoc.documentCount() + 1) )
349  {
350  // we require exactly one ref to every document, plus one ref to the SignedProperties
351  THROW_SIGNATUREEXCEPTION("Number of references in SignedInfo is invalid: found %d, expected %d"
352  , refSeq.size(), bdoc.documentCount() + 1);
353 
354  }
355 
356  // check reference to SignedProperties
357  bool gotSignatureRef = false; // remember to ensure, it exists only once
358  for ( dsig::SignedInfoType::ReferenceSequence::const_iterator itRef = refSeq.begin()
359  ; itRef != refSeq.end()
360  ; itRef++
361  )
362  {
363  const dsig::ReferenceType& refType = (*itRef);
364 
365  if ( isReferenceToSigProps(refType) )
366  {
367  // the one and only reference to SignedProperties
368  if ( gotSignatureRef )
369  {
370  THROW_SIGNATUREEXCEPTION("SignedInfo element refers to more than one SignedProperties");
371  }
372  gotSignatureRef = true; // remember this, we don't expect any more of those
373 
374  checkReferenceToSigProps(refType);
375  } // else: skip, checked elsewhere
376  }
377 
378  if ( !gotSignatureRef )
379  {
380  THROW_SIGNATUREEXCEPTION("SignedInfo does not contain reference to SignedProperties");
381  }
382 
383  // check refs to documents
384  checkReferencesToDocs(refSeq);
385 
386 }
387 
388 
393 {
394  X509Cert x509 = getSigningCertificate();
395 
396  dsig::SignatureType::ObjectSequence const& objs = signature->object();
397  if ( objs.size() != 1 )
398  THROW_SIGNATUREEXCEPTION("Number of Objects is %d, must be 1", objs.size());
399 
400  dsig::ObjectType::QualifyingPropertiesSequence const& qProps = objs[0].qualifyingProperties();
401  if ( qProps.size() != 1 )
402  THROW_SIGNATUREEXCEPTION("Number of QualifyingProperties is %d, must be 1", qProps.size());
403 
404  xades::QualifyingPropertiesType::SignedPropertiesOptional const& sigProps = qProps[0].signedProperties();
405  if ( !sigProps.present() )
406  THROW_SIGNATUREEXCEPTION("SignedProperties not found");
407 
408  xades::SignedSignaturePropertiesType::SigningCertificateOptional const& sigCertOpt = sigProps->signedSignatureProperties().signingCertificate();
409  if ( !sigCertOpt.present() )
410  THROW_SIGNATUREEXCEPTION("SigningCertificate not found");
411 
412  xades::CertIDListType::CertSequence const& certs = sigCertOpt->cert();
413  if ( certs.size() != 1 )
414  THROW_SIGNATUREEXCEPTION("Number of SigningCertificates is %d, must be 1", certs.size());
415 
416  dsig::DigestMethodType::AlgorithmType const& certDigestMethodAlgorithm = certs[0].certDigest().digestMethod().algorithm();
417  if ( !Digest::isSupported(certDigestMethodAlgorithm) )
418  THROW_SIGNATUREEXCEPTION("Unsupported digest algorithm %s for signing certificate", certDigestMethodAlgorithm.c_str());
419 
420  dsig::X509IssuerSerialType::X509IssuerNameType certIssuerName = certs[0].issuerSerial().x509IssuerName();
421  dsig::X509IssuerSerialType::X509SerialNumberType certSerialNumber = certs[0].issuerSerial().x509SerialNumber();
422  try
423  {
424  if ( x509.compareIssuerToString(certIssuerName) != 0 || x509.getSerial() != certSerialNumber )
425  {
426  DEBUG("certIssuerName: \"%s\"", certIssuerName.c_str());
427  DEBUG("x509.getCertIssuerName() \"%s\"", x509.getIssuerName().c_str());
428  DEBUG("sertCerials = %s %s", x509.getSerial().c_str(), certSerialNumber.c_str());
429  THROW_SIGNATUREEXCEPTION("Signing certificate issuer information does not match");
430  }
431  }
432  catch( const IOException &e )
433  {
434  THROW_SIGNATUREEXCEPTION_CAUSE(e, "Signing certificate issuer information not valid");
435  }
436 
437  xades::DigestAlgAndValueType::DigestValueType const& certDigestValue = certs[0].certDigest().digestValue();
438 
439  std::auto_ptr<Digest> certDigestCalc(new Digest(certDigestMethodAlgorithm));
440 
441  // lets check digest with x509 that was in keyInfo
442  std::vector<unsigned char> derEncodedX509 = x509.encodeDER();
443  certDigestCalc->update(&derEncodedX509[0], (unsigned int)derEncodedX509.size());
444  std::vector<unsigned char> calcDigest = certDigestCalc->getDigest();
445 
446  if ( certDigestValue.size() != static_cast<size_t>( certDigestCalc->getSize() ) )
447  {
448  THROW_SIGNATUREEXCEPTION("Wrong length for signing certificate digest");
449  }
450 
451  for ( size_t i = 0; i < static_cast<size_t>( certDigestCalc->getSize() ); ++i )
452  {
453  if ( calcDigest[i] != static_cast<unsigned char>(certDigestValue.data()[i]) )
454  {
455  DEBUGMEM("Document cert digest", &(certDigestValue.data())[0], certDigestValue.size());
456  DEBUGMEM("Calculated cert digest", &calcDigest[0], calcDigest.size());
457  THROW_SIGNATUREEXCEPTION("Signing certificate digest does not match");
458  }
459  }
460 }
461 
466 {
467  dsig::ObjectType::QualifyingPropertiesSequence const& qProps = signature->object()[0].qualifyingProperties();
468  if ( qProps.size() != 1 )
469  THROW_SIGNATUREEXCEPTION("Number of QualifyingProperties is %d, must be 1", qProps.size());
470  if ( qProps[0].target() != "#" + signature->id().get() )
471  THROW_SIGNATUREEXCEPTION("QualifyingProperties target is not Signature");
472 
473  checkSignedSignatureProperties();
474 
475  if ( qProps[0].unsignedProperties().present() )
476  {
477  xades::QualifyingPropertiesType::UnsignedPropertiesType uProps = qProps[0].unsignedProperties().get();
478  if ( uProps.unsignedDataObjectProperties().present() )
479  THROW_SIGNATUREEXCEPTION("unexpected UnsignedDataObjectProperties in Signature");
480  if ( !uProps.unsignedSignatureProperties().present() )
481  THROW_SIGNATUREEXCEPTION("UnsignedProperties must contain UnsignedSignatureProperties");
482  }
483 }
484 
489 {
490  const xades::SignedSignaturePropertiesType& signedProps = getSignedSignatureProperties();
491  xades::SignedSignaturePropertiesType::SignaturePolicyIdentifierOptional policyOpt = signedProps.signaturePolicyIdentifier();
492  if ( policyOpt.present() )
493  {
494  THROW_SIGNATUREEXCEPTION("Signature policy is not valid");
495  }
496 
497 }
498 
502 {
503  try
504  {
505  X509Cert signingCert = getSigningCertificate();
506  std::vector<digidoc::X509Cert::KeyUsage> usage = signingCert.getKeyUsage();
507  if( find( usage.begin(), usage.end(), digidoc::X509Cert::NonRepudiation ) == usage.end() )
508  THROW_SIGNATUREEXCEPTION("Signing certificate does not contain NonRepudiation key usage flag");
509  if( !signingCert.verify() )
510  THROW_SIGNATUREEXCEPTION("Unable to verify signing certificate");
511  }
512  catch( const IOException &e )
513  {
514  THROW_SIGNATUREEXCEPTION_CAUSE( e, "Unable to verify signing certificate" );
515  }
516 }
517 
522 bool digidoc::SignatureBES::isReferenceToSigProps(const digidoc::dsig::ReferenceType& refType) const throw(SignatureException)
523 {
524  const dsig::ReferenceType::TypeOptional& typeOpt = refType.type();
525 
526  if ( typeOpt.present() )
527  {
528  std::string typeAttr = typeOpt.get();
529  //BDOC-1.0 spec says that value must be "http://uri.etsi.org/01903#SignedProperties",
530  //but Xades wants value in format http://uri.etsi.org/01903/vX.Y.Z/#SignedProperties,
531  //where X.Y.Z is Xades version
532  //Try to support all possible values
533 
534  if((typeAttr.find("http://uri.etsi.org/01903") == 0)
535  && (typeAttr.rfind("#SignedProperties") == (typeAttr.length() - std::string("#SignedProperties").length())))
536  {
537  return true;
538  }
539  }
540 
541  return false;
542 }
543 
547 void digidoc::SignatureBES::checkReferenceToSigProps(const digidoc::dsig::ReferenceType& refType)
548 const throw(SignatureException)
549 {
550  // check attribute URI (e.g. "#SigId-SignedProperties")
551  const dsig::ReferenceType::URIOptional& uriOpt = refType.uRI();
552 
553  if ( !uriOpt.present() )
554  {
555  THROW_SIGNATUREEXCEPTION("SignedInfo reference to SignedProperties does not have attribute 'URI'");
556  }
557 
558 /* This check is pointless. It might make sense to check the syntax of the
559  * URL, but this is better left for the resolvers to handle.
560  std::string foundUri = uriOpt.get();
561  std::string expectedUri =
562  std::string("#") + id() + "-SignedProperties";
563 
564  if ( foundUri != expectedUri )
565  {
566  THROW_SIGNATUREEXCEPTION("SignedInfo reference to SignedProperties attribute 'URI' is invalid");
567  }
568 */
569 
570  // check DigestMethod
571  const dsig::DigestMethodType& digestMethod = refType.digestMethod();
572  const dsig::DigestMethodType::AlgorithmType& algorithm = digestMethod.algorithm();
573 
574  if ( !Digest::isSupported( algorithm ) )
575  {
576  THROW_SIGNATUREEXCEPTION("reference to SignedProperties digest method algorithm '%s' is not supported", algorithm.c_str());
577  }
578 
579  // check DigestValue
580  const dsig::DigestValueType& digestValue = refType.digestValue();
581 
582 
583  // TODO: do it nicely.
584  //xml_schema::dom::auto_ptr<xercesc::DOMDocument> dom = createDom();
585  //xercesc::DOMNode* signedPropsNode = dom->getFirstChild()->getLastChild()->getFirstChild()->getFirstChild();
586 
587  // xercesc::DOMNode* idNode(NULL);
588 // FIXME: Äkki oleks parem kasutada olemasolevat signature puud, mitte Xercese oma?
589 // if (!signedPropsNode->hasAttributes()
590 // || (idNode = signedPropsNode->getAttributes()->getNamedItem(xercesc::XMLString::transcode("Id"))) == NULL )
591 // {
592 // THROW_SIGNATUREEXCEPTION("SignedProperties does not have attribute 'Id'");
593 // }
594 
595  std::auto_ptr<Digest> calc(new Digest(refType.digestMethod().algorithm()));
596  //std::vector<unsigned char> calculatedDigestValue = calcDigestOnNode(calc.get(), signedPropsNode);
597  std::vector<unsigned char> calculatedDigestValue = calcDigestOnNode(calc.get(), XADES_NAMESPACE, "SignedProperties");
598 
599  if ( digestValue.begin() + calculatedDigestValue.size() != digestValue.end() )
600  {
601  THROW_SIGNATUREEXCEPTION("SignedProperties digest lengths do not match");
602  }
603 
604  for ( size_t i = 0; i < calculatedDigestValue.size(); i++ )
605  {
606  const char* dv = digestValue.begin() + i;
607  if ( *dv != static_cast<char>(calculatedDigestValue[i]) )
608  {
609  DEBUGMEM("Document digest:", &digestValue.data()[0], digestValue.size());
610  DEBUGMEM("Calculated digest:", &calculatedDigestValue[0], calculatedDigestValue.size());
611  THROW_SIGNATUREEXCEPTION("SignedProperties digest values do not match");
612  }
613  }
614 }
615 
616 // FIXME: this method does not work.
621 void digidoc::SignatureBES::checkReferencesToDocs(dsig::SignedInfoType::ReferenceSequence& refSeq)
622 const throw(SignatureException)
623 {
624  // copy documents to a list for removal on every successful find
625  std::vector< size_t > docNumberList;
626  size_t docCount = bdoc.documentCount();
627  for ( size_t i = 0; i != docCount; i++ )
628  {
629  docNumberList.push_back( i );
630  }
631 
632  // loop over references
633  for ( dsig::SignedInfoType::ReferenceSequence::const_iterator itRef = refSeq.begin()
634  ; itRef != refSeq.end()
635  ; itRef++
636  )
637  {
638  const dsig::ReferenceType& refType = (*itRef);
639 
640  if ( !isReferenceToSigProps(refType) )
641  {
642 
643  // get document URI
644  const dsig::ReferenceType::URIOptional& uriOpt = refType.uRI();
645  if ( !uriOpt.present() )
646  {
647  THROW_SIGNATUREEXCEPTION("Document reference is missing attribute 'URI'");
648  }
649  std::string docRefUri(uriOpt.get());
650  // file names in manifest do not have '/' at front
651  if ( !docRefUri.empty() && docRefUri[0] == '/' )
652  {
653  docRefUri.erase( 0, 1 );
654  }
655 
656  // find the matching document from container
657  bool foundDoc = false;
658  for ( std::vector< size_t >::iterator itDocs = docNumberList.begin()
659  ; itDocs != docNumberList.end(); itDocs++ )
660  {
661  Document doc = bdoc.getDocument( (unsigned int)*itDocs );
663  {
664  foundDoc = true;
665  docNumberList.erase( itDocs ); // remove from list to detect duplicate refs
666  checkDocumentRefDigest( doc, doc.getFileName(), refType );
667  break; // we modified docNumberList so get out of here
668  }
669 
670  }
671 
672  if ( !foundDoc )
673  {
674  THROW_SIGNATUREEXCEPTION("Referenced Document '%s' not found in BDoc container", docRefUri.c_str());
675  }
676 
677  } // else: skip, checked elsewhere
678  }
679 
680  if ( !docNumberList.empty() )
681  {
682  // that's actually coder's bug - fix it
683  THROW_SIGNATUREEXCEPTION("BDoc document list does not match the references block in signature");
684  }
685 }
686 
690 void digidoc::SignatureBES::checkDocumentRefDigest(Document& doc, const std::string& documentFileName, const digidoc::dsig::ReferenceType& refType)
691 const throw(SignatureException)
692 {
693  // get digest of the referred document
694  const dsig::DigestMethodType& digestMethod = refType.digestMethod();
695  const dsig::DigestMethodType::AlgorithmType& algorithmType = digestMethod.algorithm();
696 
697  if ( !Digest::isSupported(algorithmType) )
698  {
699  THROW_SIGNATUREEXCEPTION("Document reference '%s' has an unsupported digest algorithm '%s'"
700  , documentFileName.c_str(), algorithmType.c_str());
701  }
702 
703  std::auto_ptr< Digest > docDigest; // only this scope
704  try
705  {
706  docDigest.reset(new Digest(algorithmType));
707  }
708  catch (IOException&)
709  {
710  // according to Digest contract:
711  THROW_SIGNATUREEXCEPTION("Document reference '%s' algorithm '%s' is not implemented"
712  , documentFileName.c_str(), algorithmType.c_str());
713  }
714 
715  std::vector<unsigned char> docDigestBuf = doc.calcDigest(docDigest.get());
716 
717  // get the claimed digest
718  const dsig::DigestValueType& digestValueType = refType.digestValue();
719  const unsigned char* refDigest = reinterpret_cast<const unsigned char* >(digestValueType.data());
720 
721 
722 
723  if ( docDigestBuf.size() != digestValueType.size()
724  || memcmp(&docDigestBuf[0], refDigest, docDigestBuf.size()) != 0 )
725  {
726  DEBUGMEM("Claimed digest", refDigest, digestValueType.size());
727  DEBUGMEM("Calculated digest", &docDigestBuf[0], docDigestBuf.size());
728 
729  THROW_SIGNATUREEXCEPTION("Document '%s' digest does not match with digest in signature"
730  , documentFileName.c_str());
731  }
732 
733 }
734 
741 {
742  DEBUG("SignatureBES::checkSignatureValue()");
743  try
744  {
745  // Initialize RSA crypter.
746  X509Cert cert = getSigningCertificate();
747  RSACrypt rsa(cert.handle());
748 
749  // Calculate SHA digest of the Signature->SignedInfo node.
750  std::auto_ptr<Digest> calc(new Digest(getSignatureMethod()));
751  std::vector<unsigned char> sha = calcDigestOnNode(calc.get(), URI_ID_DSIG, "SignedInfo");
752  DEBUGMEM("Digest", &sha[0], sha.size());
753 
754  // Get signature value.
755  std::vector<unsigned char> signatureShaRsa = getSignatureValue();
756 
757  // Verify signature value with public RSA key.
758  bool valid = rsa.verify(calc->getMethod(), sha, signatureShaRsa);
759 
760  // Check that signature matched.
761  if(!valid)
762  {
763  THROW_SIGNATUREEXCEPTION("Signature is not valid.");
764  }
765  }
766  catch(const IOException& e)
767  {
768  THROW_SIGNATUREEXCEPTION_CAUSE(e, "Failed to validate signature.");
769  }
770 }