package com.opentrust.spi.cms; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.SignatureException; import java.security.cert.CRL; import java.security.cert.CRLException; import java.security.cert.CertStoreException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.cms.CMSException; import org.bouncycastle.operator.OperatorCreationException; import com.keynectis.sequoia.ca.crypto.utils.OIDUtils; import com.opentrust.spi.cms.helpers.OCSPResponse; import com.opentrust.spi.cms.helpers.SignedAttributesHelper; // Generates CMS signatures suitable for PAdES v3 (or Enhanced = BES or EPES) compatibility public class CMSForPAdESEnhancedGenerator extends CMSForPAdESBasicGenerator { public static class PolicyIdentifierParams { private String signaturePolicyOID; private byte[] signaturePolicyHashValue; private String signaturePolicyHashAlgorithm; private boolean signaturePolicyImplied; public PolicyIdentifierParams(String signaturePolicyOID, byte[] signaturePolicyHashValue, String signaturePolicyHashAlgorithm) { this.signaturePolicyOID = signaturePolicyOID; this.signaturePolicyHashValue = signaturePolicyHashValue; this.signaturePolicyHashAlgorithm = signaturePolicyHashAlgorithm; this.signaturePolicyImplied = false; } protected PolicyIdentifierParams() { } public static PolicyIdentifierParams getPolicyImpliedParams() { PolicyIdentifierParams policyIdentifierParams = new PolicyIdentifierParams(); policyIdentifierParams.signaturePolicyImplied = true; return policyIdentifierParams; } public String getSignaturePolicyOID() { return signaturePolicyOID; } public byte[] getSignaturePolicyHashValue() { return signaturePolicyHashValue; } public String getSignaturePolicyHashAlgorithm() { return signaturePolicyHashAlgorithm; } public boolean isSignaturePolicyImplied() { return signaturePolicyImplied; } } public CMSForPAdESEnhancedGenerator(String provider, Certificate certificate, PrivateKey privateKey, Collection certStore, String digestAlgorithm, Collection<CRL> signedCrls, Collection<OCSPResponse> signedOcspResponses) throws NoSuchAlgorithmException { super(provider, certificate, privateKey, certStore, null, digestAlgorithm, signedCrls, signedOcspResponses); //null -> signingtime never set for PAdED enhanced } // Performs CMS signing on provided content // optionally, content can be encapsulated in CMS public static byte[] signContent(String provider, InputStream inputStream, Certificate certificate, PrivateKey privateKey, Collection certStore, String digestAlgorithm, Collection<CRL> signedCrls, Collection<OCSPResponse> signedOcspResponses, boolean encapsulate, PolicyIdentifierParams policyIdentifierParams) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, CertStoreException, CMSException, IOException, CRLException, OperatorCreationException, CertificateEncodingException, URISyntaxException, SignatureException { CMSForPAdESEnhancedGenerator cmsGenerator = new CMSForPAdESEnhancedGenerator(provider, certificate, privateKey, certStore, digestAlgorithm, signedCrls, signedOcspResponses); cmsGenerator.policyIdentifierParams = policyIdentifierParams; return cmsGenerator.signContent(inputStream, encapsulate); } // Performs CMS signing on pre-digested content public static byte[] signReference(String provider, byte[] digest, Certificate certificate, PrivateKey privateKey, Collection certStore, String digestAlgorithm, Collection<CRL> signedCrls, Collection<OCSPResponse> signedOcspResponses, PolicyIdentifierParams policyIdentifierParams) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException, CertStoreException, CMSException, IOException, CRLException, OperatorCreationException, CertificateEncodingException, URISyntaxException, SignatureException { CMSForPAdESEnhancedGenerator cmsGenerator = new CMSForPAdESEnhancedGenerator(provider, certificate, privateKey, certStore, digestAlgorithm, signedCrls, signedOcspResponses); cmsGenerator.policyIdentifierParams = policyIdentifierParams; return cmsGenerator.signReference(digest); } protected PolicyIdentifierParams policyIdentifierParams; public void setPolicyIdentifierParams(PolicyIdentifierParams policyIdentifierParams) { this.policyIdentifierParams = policyIdentifierParams; } protected List<String> claimedAttributes = new ArrayList<String>(); protected String claimedAttributesOID; public void addClaimedAttribute(String claimedAttribute) { if(certifiedAttributes==null) claimedAttributes.add(claimedAttribute); //TODO : else exception ? } public void setClaimedAttribute(String claimedAttributesOID, List<String> claimedAttributes) { if(certifiedAttributes==null) { this.claimedAttributesOID = claimedAttributesOID; this.claimedAttributes = claimedAttributes; } //TODO : else exception ? } protected byte[] certifiedAttributes; public void setCertifiedAttribute(byte[] certifiedAttribute) { if(claimedAttributes==null || claimedAttributes.isEmpty()) certifiedAttributes = certifiedAttribute; //TODO : else exception ? } protected byte[] contentTimeStamp; public void setContentTimeStamp(byte[] contentTimeStamp) { this.contentTimeStamp = contentTimeStamp; } protected String commitmentTypeId; public void setCommitmentTypeId(String commitmentTypeId) { this.commitmentTypeId = commitmentTypeId; } @Override protected void populateSignedAttributesHashtable() throws CRLException, IOException, CertificateEncodingException, NoSuchAlgorithmException, NoSuchProviderException { //AlgorithmID digestAlgo = digestAlg!=null?digestAlg:AlgorithmID.DIGEST_SHA256; String digestAlgo = digestAlg != null ? digestAlg : "Sha256"; //TODO : digestAlg being null means we should fetch digestAlgo elsewhere : by extracting it from contentSigner.getAlgorithm() ? //(for now this method is always called with digestAlg not being null...) //FIXME : deal with errors ! if(isSha1(digestAlgo)) SignedAttributesHelper.addSigningCertificateAttribute(signedAttributesHashtable, certificate); else { AlgorithmIdentifier algoIdentifier = getAlgorithmIdentifier(digestAlgo); SignedAttributesHelper.addSigningCertificateV2Attribute(signedAttributesHashtable, algoIdentifier, certificate); //SignedAttributesHelper.addSigningCertificateV2Attribute(signedAttributesHashtable, AlgorithmIdentifier.getInstance(digestAlgo.getOID()), certificate); } if(policyIdentifierParams!=null) { if(policyIdentifierParams.isSignaturePolicyImplied()) SignedAttributesHelper.addImpliedSignaturePolicy(signedAttributesHashtable); else SignedAttributesHelper.addSignaturePolicyIdentifier(signedAttributesHashtable, new DERObjectIdentifier(policyIdentifierParams.getSignaturePolicyOID()), new DEROctetString(policyIdentifierParams.getSignaturePolicyHashValue()), AlgorithmIdentifier.getInstance(policyIdentifierParams.getSignaturePolicyHashAlgorithm())); } if((claimedAttributes!=null && !claimedAttributes.isEmpty()) || certifiedAttributes!=null) SignedAttributesHelper.addSignerAttributes(signedAttributesHashtable, claimedAttributesOID, claimedAttributes, certifiedAttributes); if(contentTimeStamp!=null) SignedAttributesHelper.addContentTimestampAttribute(signedAttributesHashtable, contentTimeStamp); if(commitmentTypeId!=null) SignedAttributesHelper.addCommitmentTypeIndicationAttribute(signedAttributesHashtable, commitmentTypeId); } private boolean isSha1(String digestAlgo) { try { DERObjectIdentifier oid = new DERObjectIdentifier(digestAlgo); DERObjectIdentifier sha1Oid = OIDUtils.getOID("SHA-1"); return oid.equals(sha1Oid); }catch(Exception e) {} return digestAlgo.equalsIgnoreCase("SHA-1") || digestAlgo.equalsIgnoreCase("SHA1"); } public static AlgorithmIdentifier getAlgorithmIdentifier(String digestAlgo) { DERObjectIdentifier oid = OIDUtils.getOID(digestAlgo); return AlgorithmIdentifier.getInstance(oid.getId()); } }