/** * Sign the signature using BDOC-BES profile. Sets required fields, * calculates digests and finally signs the signature object using * the provided <code>signer</code> implementation. * * @param signer signer that signs the signature object. * @throws SignatureException exception is throws if signing failed. */ void digidoc::SignatureBES::sign(Signer* signer) throw(SignatureException, SignException) { // Set required signature fields. try { setSigningCertificate(signer->getCert()); setSignatureProductionPlace(signer->getSignatureProductionPlace()); setSignerRole(signer->getSignerRole()); setSigningTime(util::date::currentTime()); } catch( const IOException &e ) { THROW_SIGNEXCEPTION_CAUSE( e, "Failed to sign document" ); } // Calculate digest of the Signature->Object->SignedProperties node. std::auto_ptr<Digest> calc = Digest::create(); std::vector<unsigned char> digest = calcDigestOnNode(calc.get(), XADES_NAMESPACE, "SignedProperties"); addReference("#S0-SignedProperties", calc->getUri(), digest, "http://uri.etsi.org/01903#SignedProperties"); // Calculate SHA1 digest of the Signature->SignedInfo node. calc = Digest::create(NID_sha1); std::vector<unsigned char> sha1 = calcDigestOnNode(calc.get(), DSIG_NAMESPACE, "SignedInfo"); Signer::Digest sigDigestSha1 = { NID_sha1, &sha1[0], calc->getSize() }; // Sign the calculated SAH1 digest and add the signature value (SHA1-RSA) to the signature. std::vector<unsigned char> buf(128); Signer::Signature signatureSha1Rsa = { &buf[0], buf.size() }; signer->sign(sigDigestSha1, signatureSha1Rsa); setSignatureValue(signatureSha1Rsa); }
/** * Prepares SignedInfo * * @param signer signer that signs the signature object. * @throws SignatureException exception is throws if signing failed. */ std::vector<unsigned char> digidoc::SignatureBES::prepareSignedInfo(Signer* signer) throw(SignatureException, SignException) { // Calculate digests for the documents and add these to the signature reference. for(unsigned int i = 0; i < bdoc.documentCount(); ++i) { digidoc::Document doc = bdoc.getDocument(i); try { DEBUG("Adding document '%s', '%s' to the signature references.", doc.getFileName().c_str(), doc.getMediaType().c_str()); // URIs must encode non-ASCII characters in the format %HH where HH is the hex representation of the character std::string uri = std::string("/") + digidoc::util::File::toUri(doc.getFileName()); std::auto_ptr<Digest> calc(new Digest()); std::vector<unsigned char> digest = doc.calcDigest(calc.get()); DEBUGMEM("digest", &digest[0], digest.size()); addReference(uri, calc->getUri(), digest); } catch(const Exception& e) { delete signature; THROW_SIGNEXCEPTION_CAUSE(e, "Failed to calculate digests for document '%s'.", doc.getFileName().c_str()); } } // Set required signature fields. try { setSigningCertificate(signer->getCert()); setSignatureProductionPlace(signer->getSignatureProductionPlace()); setSignerRole(signer->getSignerRole()); setSigningTime(util::date::currentTime()); } catch( const IOException &e ) { THROW_SIGNEXCEPTION_CAUSE( e, "Failed to sign document" ); } xml_schema::Uri uri(URI_ID_RSA_SHA1); switch(signer->type()) { case NID_sha224: uri = xml_schema::Uri(URI_ID_RSA_SHA224); break; case NID_sha256: uri = xml_schema::Uri(URI_ID_RSA_SHA256); break; case NID_sha384: uri = xml_schema::Uri(URI_ID_RSA_SHA384); break; case NID_sha512: uri = xml_schema::Uri(URI_ID_RSA_SHA512); break; default: break; } signature->signedInfo().signatureMethod(dsig::SignatureMethodType(uri)); // Calculate digest of the Signature->Object->SignedProperties node. std::auto_ptr<Digest> calc(new Digest()); std::vector<unsigned char> digest = calcDigestOnNode(calc.get(), XADES_NAMESPACE, "SignedProperties"); addReference("#" + getId() +"-SignedProperties", calc->getUri(), digest, "http://uri.etsi.org/01903#SignedProperties"); // Calculate SHA digest of the Signature->SignedInfo node. calc.reset(new Digest(signer->type())); return calcDigestOnNode(calc.get(), URI_ID_DSIG, "SignedInfo"); }
/** * Validate signature value. * * @throws throws exception if signature value did not match. */ void digidoc::SignatureBES::checkSignatureValue() const throw(SignatureException) { DEBUG("SignatureBES::checkSignatureValue()"); try { // Initialize RSA crypter. X509* cert = getSigningCertificate().getX509(); X509_scope certScope(&cert); RSACrypt rsa(cert); // Calculate SHA1 digest of the Signature->SignedInfo node. std::auto_ptr<Digest> calc = Digest::create(NID_sha1); std::vector<unsigned char> sha1 = calcDigestOnNode(calc.get(), DSIG_NAMESPACE, "SignedInfo"); DEBUGMEM("Digest", &sha1[0], sha1.size()); // Get signature value. std::vector<unsigned char> signatureSha1Rsa = getSignatureValue(); // Verify signature value with public RSA key. bool valid = rsa.verify(calc->getMethod(), sha1, signatureSha1Rsa); // Check that signature matched. if(!valid) { THROW_SIGNATUREEXCEPTION("Signature is not valid."); } } catch(const IOException& e) { THROW_SIGNATUREEXCEPTION_CAUSE(e, "Failed to validate signature."); } }
void bdoc::Signature::checkSignatureValue() { X509Cert cert(getSigningCertificate()); const dsig::SignatureMethodType::AlgorithmType& algorithmType = getSignatureMethodAlgorithmType(); const char* algorithmUri = algorithmType.c_str(); // Get hash method URI from signature method URI. signatureMethod sm; hashMethod hm; safeBuffer hashMethodUri; if (!XSECmapURIToSignatureMethods(XMLString::transcode(algorithmUri), sm, hm) || !hashMethod2URI(hashMethodUri, hm)) { THROW_STACK_EXCEPTION("Couldn't extract hash method from " "signature method URI '%s'.", algorithmUri); } std::auto_ptr<Digest> calc = Digest::create(hashMethodUri.rawCharBuffer()); std::vector<unsigned char> digest = calcDigestOnNode(calc.get(), DSIG_NAMESPACE, "SignedInfo"); std::vector<unsigned char> signatureValue = getSignatureValue(); if (!cert.verifySignature(calc->getMethod(), calc->getSize(), digest, signatureValue)) { THROW_STACK_EXCEPTION("Signature is not valid."); } }
void bdoc::Signature::checkReferenceToSigProps( const bdoc::dsig::ReferenceType& refType) { const dsig::ReferenceType::URIOptional& uriOpt = refType.uRI(); if (!uriOpt.present()) { THROW_STACK_EXCEPTION( "SignedInfo reference to SignedProperties does not " "have attribute 'URI'"); } const dsig::DigestMethodType& digestMethod = refType.digestMethod(); const dsig::DigestMethodType::AlgorithmType& algorithm = digestMethod.algorithm(); if (!Digest::isSupported(algorithm)) { THROW_STACK_EXCEPTION( "reference to SignedProperties digest method " "algorithm '%s' is not supported", algorithm.c_str()); } const dsig::DigestValueType& digestValue = refType.digestValue(); std::auto_ptr<Digest> calc = Digest::create(refType.digestMethod().algorithm()); std::vector<unsigned char> calculatedDigestValue = calcDigestOnNode( calc.get(), xadesnamespace(), "SignedProperties"); if (digestValue.begin() + calculatedDigestValue.size() != digestValue.end()) { THROW_STACK_EXCEPTION( "SignedProperties digest lengths do not match"); } for (size_t i = 0; i < calculatedDigestValue.size(); i++) { const char* dv = digestValue.begin() + i; if (*dv != static_cast<char>(calculatedDigestValue[i])) { THROW_STACK_EXCEPTION( "SignedProperties digest values do not match"); } } }
/// TODO: comment /// /// @throws SignatureException on a problem in signature void digidoc::SignatureBES::checkReferenceToSigProps(const digidoc::dsig::ReferenceType& refType) const throw(SignatureException) { // check attribute URI (e.g. "#SigId-SignedProperties") const dsig::ReferenceType::URIOptional& uriOpt = refType.uRI(); if ( !uriOpt.present() ) { THROW_SIGNATUREEXCEPTION("SignedInfo reference to SignedProperties does not have attribute 'URI'"); } /* This check is pointless. It might make sense to check the syntax of the * URL, but this is better left for the resolvers to handle. std::string foundUri = uriOpt.get(); std::string expectedUri = std::string("#") + id() + "-SignedProperties"; if ( foundUri != expectedUri ) { THROW_SIGNATUREEXCEPTION("SignedInfo reference to SignedProperties attribute 'URI' is invalid"); } */ // check DigestMethod const dsig::DigestMethodType& digestMethod = refType.digestMethod(); const dsig::DigestMethodType::AlgorithmType& algorithm = digestMethod.algorithm(); if ( !Digest::isSupported( algorithm ) ) { THROW_SIGNATUREEXCEPTION("reference to SignedProperties digest method algorithm '%s' is not supported", algorithm.c_str()); } // check DigestValue const dsig::DigestValueType& digestValue = refType.digestValue(); // TODO: do it nicely. //xml_schema::dom::auto_ptr<xercesc::DOMDocument> dom = createDom(); //xercesc::DOMNode* signedPropsNode = dom->getFirstChild()->getLastChild()->getFirstChild()->getFirstChild(); // xercesc::DOMNode* idNode(NULL); // FIXME: Äkki oleks parem kasutada olemasolevat signature puud, mitte Xercese oma? // if (!signedPropsNode->hasAttributes() // || (idNode = signedPropsNode->getAttributes()->getNamedItem(xercesc::XMLString::transcode("Id"))) == NULL ) // { // THROW_SIGNATUREEXCEPTION("SignedProperties does not have attribute 'Id'"); // } std::auto_ptr<Digest> calc = Digest::create(refType.digestMethod().algorithm()); //std::vector<unsigned char> calculatedDigestValue = calcDigestOnNode(calc.get(), signedPropsNode); std::vector<unsigned char> calculatedDigestValue = calcDigestOnNode(calc.get(), XADES_NAMESPACE, "SignedProperties"); if ( digestValue.begin() + calculatedDigestValue.size() != digestValue.end() ) { THROW_SIGNATUREEXCEPTION("SignedProperties digest lengths do not match"); } for ( size_t i = 0; i < calculatedDigestValue.size(); i++ ) { const char* dv = digestValue.begin() + i; if ( *dv != static_cast<char>(calculatedDigestValue[i]) ) { DEBUGMEM("Document digest:", &digestValue.data()[0], digestValue.size()); DEBUGMEM("Calculated digest:", &calculatedDigestValue[0], calculatedDigestValue.size()); THROW_SIGNATUREEXCEPTION("SignedProperties digest values do not match"); } } }