/** * 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."); } }
/** * * return * @throws SignatureException */ digidoc::OCSP::CertStatus digidoc::SignatureBES::validateOnline() const throw(SignatureException) { // FIXME: Add exception handling. // Get signing signature. X509Cert cert = getSigningCertificate(); // Get issuer certificate. X509* issuerCert = X509CertStore::getInstance()->getCert(*(cert.getIssuerNameAsn1())); X509_scope issuerCertScope(&issuerCert); if(issuerCert == NULL) { THROW_SIGNATUREEXCEPTION("Failed to load issuer certificate."); } Conf* conf = Conf::getInstance(); // Get OCSP responder certificate. // FIXME: throws IOException, handle it Conf::OCSPConf ocspConf = conf->getOCSP(cert.getIssuerName()); if(ocspConf.issuer.empty()) { SignatureException e(__FILE__, __LINE__, "Failed to find ocsp responder."); e.setCode( Exception::OCSPResponderMissing ); throw e; } STACK_OF(X509)* ocspCerts = X509Cert::loadX509Stack(ocspConf.cert); X509Stack_scope ocspCertsScope(&ocspCerts); // Check the certificate validity from OCSP server. try { OCSP ocsp; ocsp.setSkew(120);//XXX: load from conf ocsp.setOCSPCerts(ocspCerts); ocsp.setUrl(ocspConf.url); std::auto_ptr<Digest> calc = Digest::create(); calc->update(getSignatureValue()); return ocsp.checkCert(cert.getX509(), issuerCert, calc->getDigest()); } catch(const IOException& e) { THROW_SIGNATUREEXCEPTION("Failed to check the certificate validity from OCSP server."); } catch(const OCSPException& e) { THROW_SIGNATUREEXCEPTION("Failed to check the certificate validity from OCSP server."); } return digidoc::OCSP::GOOD; }
/** * Do TM offline validations. * <ul> * <li>Validate BES offline</li> * <li>Check OCSP response (RevocationValues) was signed by trusted OCSP server</li> * <li>Check that nonce field in OCSP response is same as CompleteRevocationRefs->DigestValue</li> * <li>Recalculate hash of signature and compare with nonce</li> * </ul> * @throws SignatureException if signature is not valid */ void digidoc::SignatureTM::validateOffline() const throw(SignatureException) { SignatureBES::validateOffline(); // 1. Check OCSP response (RevocationValues) was signed by OCSP server // 2. OCSP server certificate is trusted? // 3. Check that nonce field in OCSP response is same as CompleteRevocationRefs->DigestValue // 4. Recalculate hash of signature and compare with nonce #if 0 Conf* conf = Conf::getInstance(); Conf::OCSPConf ocspConf = conf->getOCSP(getSigningCertificate().getIssuerName()); if(ocspConf.issuer.empty()) { SignatureException e(__FILE__, __LINE__, "Failed to find ocsp responder."); e.setCode( Exception::OCSPResponderMissing ); throw e; } OCSP ocsp(ocspConf.url); STACK_OF(X509)* ocspCerts = 0; try { ocspCerts = X509Cert::loadX509Stack(ocspConf.cert); } catch( const Exception &e ) { SignatureException exception(__FILE__, __LINE__, "OCSP certificate loading failed", e); exception.setCode( Exception::OCSPCertMissing ); throw exception; } X509Stack_scope x509StackScope(&ocspCerts); ocsp.setOCSPCerts(ocspCerts); #else OCSP ocsp; ocsp.setCertStore(digidoc::X509CertStore::getInstance()->getCertStore()); ocsp.setOCSPCerts(digidoc::X509CertStore::getInstance()->getCerts()); #endif std::vector<unsigned char> respBuf; try { getOCSPResponseValue(respBuf); ocsp.verifyResponse(respBuf); } catch( const Exception &e ) { THROW_SIGNATUREEXCEPTION_CAUSE( e, "OCSP response verfiy failed" ); } DEBUG("OCSP response was signed by trusted OCSP responder"); std::vector<unsigned char> respNonce = ocsp.getNonce(respBuf); xml_schema::Uri method = unsignedSignatureProperties()->completeRevocationRefs()[0].oCSPRefs() ->oCSPRef()[0].digestAlgAndValue()->digestMethod().algorithm(); std::auto_ptr<Digest> calc = Digest::create(std::string(method)); calc->update(getSignatureValue()); std::vector<unsigned char> nonce = calc->getDigest(); if(nonce != respNonce) { DEBUGMEM("Calculated signature HASH", &nonce[0], nonce.size()); DEBUGMEM("Response nonce", &respNonce[0], respNonce.size()); THROW_SIGNATUREEXCEPTION("Calculated signature hash doesn't match to OCSP responder nonce field"); } std::vector<unsigned char> revocationOCSPRefValue(0); std::string ocspResponseHashUri; getRevocationOCSPRef(revocationOCSPRefValue, ocspResponseHashUri); std::auto_ptr<Digest> ocspResponseCalc = Digest::create(ocspResponseHashUri); DEBUG("Calculating digest on %d bytes", respBuf.size()); ocspResponseCalc->update(respBuf); std::vector<unsigned char> ocspResponseHash = ocspResponseCalc->getDigest(); if(ocspResponseHash != revocationOCSPRefValue) { DEBUGMEM("Document ocspResponse HASH:", &revocationOCSPRefValue[0], revocationOCSPRefValue.size()); DEBUGMEM("Calculated ocspResponse HASH:", &ocspResponseHash[0], ocspResponseHash.size()); THROW_SIGNATUREEXCEPTION("OCSPRef value doesn't match with hash of OCSP response"); } else { DEBUG("TM signature valid"); } }
/** * * @param signer * @throws SignatureException */ void digidoc::SignatureTM::sign(Signer* signer) throw(SignatureException, SignException) { DEBUG("SignatureTM::sign()"); // Sign with BES profile. SignatureBES::sign(signer); DEBUG("BES signature successful."); // Calculate NONCE value. std::auto_ptr<Digest> calc = Digest::create(); calc->update(getSignatureValue()); std::vector<unsigned char> nonce = calc->getDigest(); DEBUGMEM("Calculated signature HASH (nonce):", &nonce[0], nonce.size()); // Get issuer certificate from certificate store. X509* cert = signer->getCert(); X509Cert cert_(cert); X509* issuer = X509CertStore::getInstance()->getCert(*(cert_.getIssuerNameAsn1())); X509_scope issuerScope(&issuer); if(issuer == NULL) { THROW_SIGNATUREEXCEPTION("Could not find certificate '%s' issuer '%s' in certificate store.", cert_.getSubject().c_str(), cert_.getIssuerName().c_str()); } DEBUG("Signing with X.509 cert {serial=%ld, subject=%s, issuer=%s})", cert_.getSerial(), cert_.getSubject().c_str(), cert_.getIssuerName().c_str()); // Initialize OCSP. DEBUG("Making OCSP request."); Conf* conf = Conf::getInstance(); Conf::OCSPConf ocspConf = conf->getOCSP(cert_.getIssuerName()); if(ocspConf.issuer.empty()) { SignatureException e(__FILE__, __LINE__, "Failed to find ocsp responder."); e.setCode( Exception::OCSPResponderMissing ); throw e; } STACK_OF(X509)* ocspCerts = 0; try { ocspCerts = X509Cert::loadX509Stack(ocspConf.cert); } catch(const IOException& e) { THROW_SIGNATUREEXCEPTION_CAUSE(e, "Failed to load OCSP certificate"); } X509Stack_scope ocspCertsScope(&ocspCerts); OCSP::CertStatus status = OCSP::UNKNOWN; std::vector<unsigned char> ocspResponse; struct tm producedAt; try { OCSP ocsp; ocsp.setOCSPCerts(ocspCerts); ocsp.setUrl(ocspConf.url); ocsp.setMaxAge(2*60); // FIXME: remove or move to conf ocsp.setSkew(15*60); // FIXME: remove or move to conf status = ocsp.checkCert(cert, issuer, nonce, ocspResponse, producedAt); } catch(const IOException& e) { THROW_SIGNATUREEXCEPTION_CAUSE(e, "Failed to get OCSP response"); } catch(const OCSPException& e) { THROW_SIGNATUREEXCEPTION_CAUSE(e, "Failed to get OCSP response"); } switch(status) { case digidoc::OCSP::GOOD: DEBUG("OCSP status: GOOD"); break; case digidoc::OCSP::REVOKED: { DEBUG("OCSP status: REVOKED"); SignatureException e( __FILE__, __LINE__, "Certificate status: revoked" ); e.setCode( Exception::CertificateRevoked ); throw e; break; } case digidoc::OCSP::UNKNOWN: { DEBUG("OCSP status: UNKNOWN"); SignatureException e( __FILE__, __LINE__, "Certificate status: unknown" ); e.setCode( Exception::CertificateUnknown ); throw e; break; } } DEBUG("OCSP response size %d", ocspResponse.size()); // FIXME: get from ocsp instead // FIXME: This file can contain multiple certs. X509Cert class supports only one cert per file // loadX509Stack loads multiple certs from one file // X509* ocspCert = X509Cert::loadX509(Conf::getInstance()->getOCSPCertPath()); X509_scope ocspCertScope(&ocspCert); if(sk_X509_num(ocspCerts) > 1) { ERR("More than one OCSP cert in file."); } X509Cert ocspCert_(sk_X509_value(ocspCerts, 0)); std::auto_ptr<Digest> ocspResponseCalc = Digest::create(); ocspResponseCalc->update(ocspResponse); std::vector<unsigned char> ocspResponseHash = ocspResponseCalc->getDigest(); DEBUGMEM("Calculated ocspResponse HASH:", &ocspResponseHash[0], ocspResponseHash.size()); // Set TM profile signature parameters. createTMProperties(); setOCSPCertificate(ocspCert_); setCACertificate(X509Cert(issuer)); setCompleteRevocationRefs(ocspCert_.getIssuerName(), calc->getUri(), ocspResponseHash, producedAt); setOCSPResponseValue(ocspResponse); }