ee.sk.digidoc.factory.BouncyCastleTimestampFactory.java Source code

Java tutorial

Introduction

Here is the source code for ee.sk.digidoc.factory.BouncyCastleTimestampFactory.java

Source

/*
 * BouncyCastleTimestampFactory.java
 * PROJECT: JDigiDoc
 * DESCRIPTION: Digi Doc functions for 
 *   handling timestamps 
 *==================================================
 * Copyright (C) AS Sertifitseerimiskeskus
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * GNU Lesser General Public Licence is available at
 * http://www.gnu.org/copyleft/lesser.html
 *==================================================
 */
package ee.sk.digidoc.factory;

import ee.sk.digidoc.DigiDocException;
import ee.sk.digidoc.SignedDoc;
import ee.sk.utils.ConfigManager;
import ee.sk.digidoc.Base64Util;
import ee.sk.digidoc.Notary;
import ee.sk.digidoc.CertID;
import ee.sk.digidoc.Signature;
import ee.sk.digidoc.TimestampInfo;

import java.security.cert.X509Certificate;
import java.util.ArrayList;

import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.asn1.cmp.PKIStatus;
import org.bouncycastle.asn1.cmp.PKIFailureInfo;

import org.apache.log4j.Logger;
import java.util.Date;

/**
 * Implements the TimestampFactory by using
 * BouncyCastle JCE toolkit
 * @author  Veiko Sinivee
 * @version 1.0
 */
public class BouncyCastleTimestampFactory implements TimestampFactory {
    /** log4j logger object */
    private Logger m_logger = null;

    /** 
     * Creates new BouncyCastleTimestampFactory 
     */
    public BouncyCastleTimestampFactory() {
        m_logger = Logger.getLogger(BouncyCastleTimestampFactory.class);
    }

    /**
     * initializes the implementation class
     */
    public void init() throws DigiDocException {
    }

    /**
     * Verifies this one timestamp
     * @param ts TimestampInfo object
     * @param tsaCert TSA certificate
     * @returns result of verification
     */
    public boolean verifyTimestamp(TimestampInfo ts, X509Certificate tsaCert) throws DigiDocException {
        boolean bOk = false;

        if (m_logger.isDebugEnabled())
            m_logger.debug("Verifying TS: " + ts.getId() + " nr: " + ts.getSerialNumber());
        if (!SignedDoc.compareDigests(ts.getMessageImprint(), ts.getHash())) {
            m_logger.error("TS digest: " + Base64Util.encode(ts.getMessageImprint()) + " real digest: "
                    + Base64Util.encode(ts.getHash()));
            throw new DigiDocException(DigiDocException.ERR_TIMESTAMP_VERIFY,
                    "Bad digest for timestamp: " + ts.getId(), null);
        }
        TimeStampResponse resp = ts.getTimeStampResponse();
        if (resp != null) {
            if (m_logger.isDebugEnabled())
                m_logger.debug("TS status: " + resp.getStatus());
            if (resp.getStatus() == PKIStatus.GRANTED || resp.getStatus() == PKIStatus.GRANTED_WITH_MODS) {
                try {
                    resp.getTimeStampToken().validate(tsaCert, "BC");
                    bOk = true;
                } catch (Exception ex) {
                    bOk = false;
                    m_logger.error("Timestamp verification error: " + ex);
                    throw new DigiDocException(DigiDocException.ERR_TIMESTAMP_VERIFY,
                            "Invalid timestamp: " + ex.getMessage(), ex);
                }
            } else
                throw new DigiDocException(DigiDocException.ERR_TIMESTAMP_VERIFY,
                        "Invalid timestamp status: " + resp.getStatus(), null);
        }

        return bOk;
    }

    private int findTSAIndex(Signature sig, String cn) {
        int idx = 0;
        // hack - just look at first TSA
        if (m_logger.isDebugEnabled())
            m_logger.debug("Cearch index for: " + cn);
        int nTsas = ConfigManager.instance().getIntProperty("DIGIDOC_TSA_COUNT", 0);
        for (int i = 0; i < nTsas; i++) {
            String s1 = ConfigManager.instance().getProperty("DIGIDOC_TSA" + (i + 1) + "_CN");
            if (s1 != null && s1.equals(cn))
                return i + 1;
        }
        return idx;
    }

    private X509Certificate findTSACert(int idx) throws DigiDocException {
        return SignedDoc.readCertificate(ConfigManager.instance().getProperty("DIGIDOC_TSA" + idx + "_CERT"));
    }

    private X509Certificate findTSACACert(int idx) throws DigiDocException {
        String fname = ConfigManager.instance().getProperty("DIGIDOC_TSA" + idx + "_CA_CERT");
        if (m_logger.isDebugEnabled())
            m_logger.debug("Read ca cert: " + fname);
        return SignedDoc.readCertificate(fname);
    }

    /**
     * Verifies all timestamps in this signature and
     * return a list of errors.
     * @param sig signature to verify timestamps
     * @return list of errors. Empty if no errors.
     * @throws DigiDocException
     */
    public ArrayList verifySignaturesTimestamps(Signature sig)
    //   throws DigiDocException
    {
        Date d1 = null, d2 = null;
        ArrayList errs = new ArrayList();
        ArrayList tsaCerts = sig.findTSACerts();
        for (int t = 0; t < sig.countTimestampInfos(); t++) {
            TimestampInfo ts = sig.getTimestampInfo(t);
            if (ts.getType() == TimestampInfo.TIMESTAMP_TYPE_SIGNATURE)
                d1 = ts.getTime();
            if (ts.getType() == TimestampInfo.TIMESTAMP_TYPE_SIG_AND_REFS)
                d2 = ts.getTime();
            boolean bVerified = false;
            DigiDocException ex2 = null;
            for (int j = 0; j < tsaCerts.size(); j++) {
                X509Certificate tsaCert = (X509Certificate) tsaCerts.get(j);
                if (m_logger.isDebugEnabled())
                    m_logger.debug("Verifying TS: " + ts.getId() + " with: "
                            + SignedDoc.getCommonName(tsaCert.getSubjectDN().getName()));
                // try verifying with all possible TSA certs
                try {
                    if (verifyTimestamp(ts, tsaCert)) {
                        bVerified = true;
                        if (m_logger.isDebugEnabled())
                            m_logger.debug("TS: " + ts.getId() + " - OK");
                        break;
                    } else {
                        m_logger.error("TS: " + ts.getId() + " - NOK");
                    }
                } catch (DigiDocException ex) {
                    ex2 = ex;
                    m_logger.error("TS: " + ts.getId() + " - ERROR: " + ex);
                    //ex.printStackTrace(System.err);
                }
            }
            if (!bVerified) {
                errs.add(ex2);
            }
        }
        // now check that SignatureTimeStamp is before SigAndRefsTimeStamp
        if (d1 != null && d2 != null) {
            if (m_logger.isDebugEnabled())
                m_logger.debug("SignatureTimeStamp: " + d1 + " SigAndRefsTimeStamp: " + d2);
            if (d1.after(d2)) {
                DigiDocException ex = new DigiDocException(DigiDocException.ERR_TIMESTAMP_VERIFY,
                        "SignatureTimeStamp time must be before SigAndRefsTimeStamp time!", null);
                errs.add(ex);
            }
        }
        return errs;
    }

}