bdoc::OCSP* bdoc::SignatureValidator::prepare() { _signingCert = _sig->getSigningCertificate(); std::string issuer = _signingCert.getIssuerName(); int pos = issuer.find("CN=", 0) + 3; std::string issure_cn = issuer.substr(pos, issuer.find(",", pos) - pos); if (!_conf->hasOCSPConf(issure_cn)) { THROW_STACK_EXCEPTION("Failed to find ocsp responder."); } OCSPConf ocspConf = _conf->getOCSPConf(issure_cn); _issuerX509 = _conf->getCertStore()-> getCert(*(_signingCert.getIssuerNameAsn1())); if (_issuerX509 == NULL) { THROW_STACK_EXCEPTION("Failed to load issuer certificate."); } _ocspCerts = X509Cert::loadX509Stack(ocspConf.cert); OCSP *ocsp = new OCSP(ocspConf.url); ocsp->setSkew(ocspConf.skew); ocsp->setMaxAge(ocspConf.maxAge); ocsp->setOCSPCerts(_ocspCerts); return ocsp; }
/** * * 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); }