예제 #1
0
/**
 * 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.");
    }
}
예제 #2
0
/**
 * Check if document digest matches with what reference claims
 */
void digidoc::SignatureBES::checkDocumentRefDigest(Document& doc, const std::string& documentFileName, const digidoc::dsig::ReferenceType& refType)
const throw(SignatureException)
{
    // get digest of the referred document
    const dsig::DigestMethodType& digestMethod = refType.digestMethod();
    const dsig::DigestMethodType::AlgorithmType& algorithmType = digestMethod.algorithm();

    if ( !Digest::isSupported(algorithmType) )
    {
        THROW_SIGNATUREEXCEPTION("Document reference '%s' has an unsupported digest algorithm '%s'"
                                 , documentFileName.c_str(), algorithmType.c_str());
    }

    std::auto_ptr< Digest > docDigest; // only this scope
    try
    {
        docDigest = Digest::create(algorithmType);
    }
    catch (IOException&)
    {
        // according to Digest contract:
        THROW_SIGNATUREEXCEPTION("Document reference '%s' algorithm '%s' is not implemented"
                                 , documentFileName.c_str(), algorithmType.c_str());
    }

    std::vector<unsigned char> docDigestBuf = doc.calcDigest(docDigest.get());

    // get the claimed digest
    const dsig::DigestValueType& digestValueType = refType.digestValue();
    const unsigned char* refDigest = reinterpret_cast<const unsigned char* >(digestValueType.data());



    if ( docDigestBuf.size() != digestValueType.size()
            || memcmp(&docDigestBuf[0], refDigest, docDigestBuf.size()) != 0 )
    {
        DEBUGMEM("Claimed digest", refDigest, digestValueType.size());
        DEBUGMEM("Calculated digest", &docDigestBuf[0], docDigestBuf.size());

        THROW_SIGNATUREEXCEPTION("Document '%s' digest does not match with digest in signature"
                                 , documentFileName.c_str());
    }

}
예제 #3
0
/**
 * 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");
}
예제 #4
0
/**
 * 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-&gt;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");
    }

}
예제 #5
0
/**
 *
 * @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);
}
예제 #6
0
/// 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");
        }
    }
}
예제 #7
0
/// TODO: comment
///
/// @throws SignatureException on a problem in signature
void digidoc::SignatureBES::checkKeyInfo() const throw(SignatureException)
{
    X509Cert x509 = getSigningCertificate();

    dsig::SignatureType::ObjectSequence const& objs = signature->object();

    if ( objs.size() != 1 )
    {
        THROW_SIGNATUREEXCEPTION("Number of Objects is %d, must be 1", objs.size());
    }

    dsig::ObjectType::QualifyingPropertiesSequence const& qProps = objs[0].qualifyingProperties();

    if ( qProps.size() != 1 )
    {
        THROW_SIGNATUREEXCEPTION("Number of QualifyingProperties is %d, must be 1", qProps.size());
    }

    xades::QualifyingPropertiesType::SignedPropertiesOptional const& sigProps =  qProps[0].signedProperties();

    if ( !sigProps.present() )
    {
        THROW_SIGNATUREEXCEPTION("SignedProperties not found");
    }

    xades::SignedSignaturePropertiesType::SigningCertificateOptional const& sigCertOpt = sigProps->signedSignatureProperties().signingCertificate();

    if ( !sigCertOpt.present() )
    {
        THROW_SIGNATUREEXCEPTION("SigningCertificate not found");
    }

    xades::CertIDListType::CertSequence const& certs = sigCertOpt->cert();

    if ( certs.size() != 1 )
    {
        THROW_SIGNATUREEXCEPTION("Number of SigningCertificates is %d, must be 1", certs.size());
    }

    dsig::DigestMethodType::AlgorithmType const& certDigestMethodAlgorithm = certs[0].certDigest().digestMethod().algorithm();

    if ( !Digest::isSupported(certDigestMethodAlgorithm) )
    {
        THROW_SIGNATUREEXCEPTION("Unsupported digest algorithm  %s for signing certificate", certDigestMethodAlgorithm.c_str());
    }

    dsig::X509IssuerSerialType::X509IssuerNameType certIssuerName = certs[0].issuerSerial().x509IssuerName();
    dsig::X509IssuerSerialType::X509SerialNumberType certSerialNumber = certs[0].issuerSerial().x509SerialNumber();

    try
    {
        if ( x509.compareIssuerToString(certIssuerName) || x509.getSerial() != certSerialNumber )
        {
            DEBUG("certIssuerName: \"%s\"", certIssuerName.c_str());
            DEBUG("x509.getCertIssuerName() \"%s\"", x509.getIssuerName().c_str());
            DEBUG("sertCerials = %ld %ld", x509.getSerial(), (long)certSerialNumber);
            THROW_SIGNATUREEXCEPTION("Signing certificate issuer information does not match");
        }
    }
    catch( const IOException &e )
    {
        THROW_SIGNATUREEXCEPTION_CAUSE(e, "Signing certificate issuer information not valid");
    }

    xades::DigestAlgAndValueType::DigestValueType const& certDigestValue = certs[0].certDigest().digestValue();

    std::auto_ptr<Digest> certDigestCalc = Digest::create(certDigestMethodAlgorithm);

    // lets check digest with x509 that was in keyInfo
    std::vector<unsigned char> derEncodedX509 = x509.encodeDER();
    certDigestCalc->update(&derEncodedX509[0], derEncodedX509.size());
    std::vector<unsigned char> calcDigest = certDigestCalc->getDigest();

    if ( certDigestValue.size() != static_cast<size_t>( certDigestCalc->getSize() ) )
    {
        THROW_SIGNATUREEXCEPTION("Wrong length for signing certificate digest");
    }

    for ( size_t i = 0; i < static_cast<size_t>( certDigestCalc->getSize() ); ++i )
    {
        if ( calcDigest[i] != static_cast<unsigned char>(certDigestValue.data()[i]) )
        {
            DEBUGMEM("Document cert digest", &(certDigestValue.data())[0], certDigestValue.size());
            DEBUGMEM("Calculated cert digest", &calcDigest[0], calcDigest.size());
            THROW_SIGNATUREEXCEPTION("Signing certificate digest does not match");
        }
    }
}
예제 #8
0
파일: BDoc.cpp 프로젝트: tixsys/esteid
/**
 * Signs all documents in container.
 *
 * @param signer signer implementation.
 * @param profile signature profile (e.g. BES, TM).
 * @throws BDocException exception is throws if signing the BDCO container failed.
 */
void digidoc::BDoc::sign(Signer* signer, Signature::Type profile) throw(BDocException)
{
    if (signer == NULL)
    {
        THROW_BDOCEXCEPTION("Null pointer in digidoc::BDoc::sign");
    }

    DEBUG("sign(signer = 0x%X, profile=%d)", (unsigned int)signer, profile);

    // Create signature by type.
    Signature* signature = NULL;
    if(profile == Signature::BES)
    {
        signature = new SignatureBES(*this);
    }
    else if(profile == Signature::TM)
    {
        signature = new SignatureTM(*this);
    }
	else if(profile == Signature::MOBILE)
	{
		try {
			signature = new SignatureMobile( signer->signaturePath(), *this);
		} catch(const Exception& e) {
			THROW_BDOCEXCEPTION_CAUSE(e, "MobileSignature");
		}
		addSignature( signature );
		return;
	}
	else
    {
        THROW_BDOCEXCEPTION("Unknown signature profile: %d", profile);
    }

    // Calculate digests for the documents and add these to the signature reference.
    for(std::vector<Document>::iterator iter = documents.begin(); iter != documents.end(); iter++)
    {
        try
        {
            DEBUG("Adding document '%s', '%s' to the signature references.", iter->getPath().c_str(), iter->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::String::toUriFormat(digidoc::util::File::fileName(iter->getPath()));
            std::auto_ptr<Digest> calc = Digest::create();
            std::vector<unsigned char> digest = iter->calcDigest(calc.get());
            DEBUGMEM("digest", &digest[0], digest.size());
            signature->addReference(uri, calc->getUri(), digest);
        }
        catch(const Exception& e)
        {
            delete signature;
            THROW_BDOCEXCEPTION_CAUSE(e, "Failed to calculate digests for document '%s'.", iter->getPath().c_str());
        }
    }

    try
    {
        // Finalize the signature by calculating signature.
        signature->sign(signer);
    }
    catch(const SignatureException& e)
    {
        delete signature;
        THROW_BDOCEXCEPTION_CAUSE(e, "Failed to sign BDOC container.");
    }
    catch(const SignException& e)
    {
        delete signature;
        THROW_BDOCEXCEPTION_CAUSE(e, "Failed to sign BDOC container.");
    }

    // Add the created signature to the signatures list.
    addSignature(signature);
}