/* * Created on 19 janv. 2005 * */ package com.opentrust.spi.tsp.impl; import java.io.IOException; import java.math.BigInteger; import java.security.DigestException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.Security; import java.security.SignatureException; import java.security.cert.CertPathBuilder; import java.security.cert.CertStore; import java.security.cert.Certificate; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.PKIXBuilderParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Vector; import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.tsp.Accuracy; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.tsp.TSPAlgorithms; import org.bouncycastle.tsp.TSPException; import org.bouncycastle.tsp.TimeStampToken; import org.bouncycastle.util.encoders.Base64; import com.keynectis.sequoia.ca.crypto.utils.OIDUtils; import com.opentrust.spi.tsp.TimestampToken; /** * Implémentation d'un jeton d'hotodatage à base du provider Bouncy Castle * @author mehdi.bouallagui */ public class BCTimeStampToken implements TimestampToken { TimeStampToken timeStampToken; public BCTimeStampToken(byte [] b) throws CMSException, TSPException, IOException { CMSSignedData cms = new CMSSignedData(b); timeStampToken = new TimeStampToken(cms); } /** * Constructeur prenant en paramêtre une instance concrete de jeton d'horodatage à base de BC * @param timeStampToken */ public BCTimeStampToken(TimeStampToken timeStampToken) { if (timeStampToken == null) { throw new NullPointerException("timeStampToken argument is null"); } this.timeStampToken = timeStampToken; } /** * @see com.kotio.commons.tsa.TimestampToken#getDateTime() */ public Date getDateTime() throws NoSuchFieldException { try { return timeStampToken.getTimeStampInfo().getGenTime(); } catch (Exception e) { NoSuchFieldException ex = new NoSuchFieldException("Can extract generation time in timestamp info"); ex.initCause(e); throw ex; } } /** * @see com.kotio.commons.tsa.TimestampToken#getAccuracy() */ public String getAccuracy() throws NoSuchFieldException { try { Accuracy accuracy = timeStampToken.getTimeStampInfo().getAccuracy(); DERInteger seconds = accuracy.getSeconds(); DERInteger millis = accuracy.getMillis(); DERInteger micros = accuracy.getMicros(); StringBuffer accuracyStringBuffer = new StringBuffer(); if (seconds != null) { accuracyStringBuffer.append(seconds.getValue()); accuracyStringBuffer.append(" sec "); } if (millis != null) { accuracyStringBuffer.append(millis.getValue()); accuracyStringBuffer.append(" millis "); } if (micros != null) { accuracyStringBuffer.append(micros.getValue()); accuracyStringBuffer.append(" micors "); } if (accuracyStringBuffer.length() == 0) throw new NullPointerException(); return accuracyStringBuffer.toString(); } catch (Exception e) { NoSuchFieldException ex = new NoSuchFieldException("Can extract accuracy in timestamp info"); ex.initCause(e); throw ex; } } /** * @see com.kotio.commons.timestamp.opentsa.TimestampToken#getPolicy(java.lang.Object) */ public String getPolicy() { return timeStampToken.getTimeStampInfo().getPolicy(); } /** * @see com.kotio.commons.tsa.TimestampToken#getNonce() */ public BigInteger getNonce() throws NoSuchFieldException { try { return timeStampToken.getTimeStampInfo().getNonce(); } catch (Exception e) { NoSuchFieldException ex = new NoSuchFieldException("Can extract Nonce in timestamp info"); ex.initCause(e); throw ex; } } /** * @see com.kotio.commons.tsa.TimestampToken#getSignerCertificate() */ public Certificate getSignerCertificate() throws NoSuchFieldException { try { // Force bouncy castle provider Collection collection = timeStampToken.getCertificatesAndCRLs( "Collection", BouncyCastleProvider.PROVIDER_NAME) .getCertificates(timeStampToken.getSID()); if (collection != null && collection.size() != 0) { return (Certificate) (collection.toArray())[0]; } else { throw new NoSuchFieldException("Signer certificate"); } } catch (Exception e) { NoSuchFieldException ex = new NoSuchFieldException("Cannot extract signer certificate from timestamp info"); ex.initCause(e); throw ex; } } public CertStore getCertificatesAndCRLs() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchFieldException { try { // Force bouncy castle provider return timeStampToken.getCertificatesAndCRLs("Collection", BouncyCastleProvider.PROVIDER_NAME); } catch (CMSException e) { NoSuchFieldException ex = new NoSuchFieldException("Cannot extract CertificatesAndCRLs from timestamp info"); ex.initCause(e); throw ex; } } /** * @throws SignatureException * @see com.kotio.commons.tsa.TimestampToken#verifySignature() */ public boolean verifySignature() throws SignatureException { try { timeStampToken.validate(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build((X509Certificate) getSignerCertificate())); } catch (Exception e) { throw new SignatureException(e); } return true; } /** * @throws DigestException * @see com.kotio.commons.tsa.TimestampToken#verifyImprint(byte[]) */ public boolean verifyImprint(byte[] dataImprint) throws DigestException { byte[] timestampImprint = null; try { timestampImprint=timeStampToken.getTimeStampInfo().getMessageImprintDigest(); if (Arrays.equals(timestampImprint, dataImprint)) return true; } catch (Exception e) { StringBuffer message = new StringBuffer( "Timestamp imprint mismatch: " + "Expecting " + new String(Base64.encode(dataImprint))); if (timestampImprint != null) { message.append("; found " + new String(Base64.encode(timestampImprint))); } throw new DigestException(message.toString(), e); } return false; } /** * Cette implémentation ne retourne que les bytes correspondant au token.(pas ceux de response) * * @see com.kotio.commons.tsa.TimestampToken#getEncoded() */ public byte[] getEncoded() throws IOException { return timeStampToken.getEncoded(); } /** * Aucune vérification de la révocation n'est effectuée. L'implémentation se base sur * Java Certification Path API. * @see com.kotio.commons.tsa.TimestampToken#verifyCertPath(java.security.cert.Certificate[]) */ public boolean verifyCertPath(Certificate[] trustedCertificates) { Certificate targetCertificate; try { targetCertificate = getSignerCertificate(); } catch (NoSuchFieldException e1) { return false; } Vector certificateCollection = new Vector(); certificateCollection.add(targetCertificate); HashSet trustedAnchors = new HashSet(); for (int i = 0; i < trustedCertificates.length; i++) { try { X509Certificate certificate = (X509Certificate) trustedCertificates[i]; trustedAnchors.add(new TrustAnchor(certificate, null)); } catch (Exception e) { } } X509CertSelector targetConstraints = new X509CertSelector(); targetConstraints.setCertificate((X509Certificate) targetCertificate); CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters( certificateCollection); CertStore store = null; try { store = CertStore.getInstance("Collection", ccsp); } catch (Exception e) { return false; } PKIXBuilderParameters params = null; try { params = new PKIXBuilderParameters(trustedAnchors, targetConstraints); } catch (Exception e) { return false; } params.setRevocationEnabled(false); params.addCertStore(store); try { params.setDate(getDateTime()); } catch (NoSuchFieldException e1) { return false; } CertPathBuilder builder; try { builder = CertPathBuilder.getInstance("PKIX"); } catch (NoSuchAlgorithmException e) { return false; } try { builder.build(params); } catch (Exception e) { return false; } return true; } public String getMessageImprintAlgName() { return getTSPAlgorithmNameFromOID(timeStampToken.getTimeStampInfo().getMessageImprintAlgOID()); } private String getTSPAlgorithmNameFromOID(String oid) { String algo = OIDUtils.getName(new DERObjectIdentifier(oid)); if (algo == null) throw new IllegalArgumentException ("No TSP digest algorithm corresponds to OID:"+oid); return algo; } }