public Certificate getSignerCertificate() { try { Collection certificateCollection = cmsSignedData.getCertificates().getMatches(firstSignerInfo.getSID()); Iterator iterator = certificateCollection.iterator(); X509CertificateHolder certHolder = (X509CertificateHolder) iterator.next(); return CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME) .generateCertificate(new ByteArrayInputStream(certHolder.getEncoded())); } catch (Exception e) { log.error(Channel.TECH, "Could not extract signer certificate from CMS signature : %1$s", e); } return null; }
public class CMSSignedDataWrapper { private static SPILogger log = SPILogger.getLogger("CMS"); static { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); } protected CMSSignedData cmsSignedData = null; protected SignerInformation firstSignerInfo = null; protected List<TimestampToken> signatureTimeStamps = null; protected boolean hasMultipleSignerInfos = false; public CMSSignedDataWrapper(InputStream inputStream) throws SignatureException, CMSException { this(new CMSSignedData(inputStream)); } public CMSSignedDataWrapper(byte[] data) throws SignatureException, CMSException { this(new CMSSignedData(data)); } public CMSSignedDataWrapper(CMSSignedData cmsSignedData) { try { this.cmsSignedData = cmsSignedData; parseCms(); } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } } private void parseCms() { Collection signers = cmsSignedData.getSignerInfos().getSigners(); if (signers.size() != 1) hasMultipleSignerInfos = true; Iterator iterator = signers.iterator(); firstSignerInfo = (SignerInformation) iterator.next(); } public boolean hasMultipleSignerInfos() { return hasMultipleSignerInfos; } public ASN1ObjectIdentifier getContentType() { ContentInfo ci = cmsSignedData.getContentInfo(); if (ci == null) return null; return ci.getContentType(); } public int getVersion() { return cmsSignedData.getVersion(); } public int getSignerVersion() { return firstSignerInfo.getVersion(); } public void appendSignatureTimeStamp(byte[] timeStampTokenBytes) { try { AttributeTable at = firstSignerInfo.getUnsignedAttributes(); firstSignerInfo = SignerInformation.replaceUnsignedAttributes( firstSignerInfo, appendTimestampAttribute(timeStampTokenBytes, at)); Collection<SignerInformation> signers = new ArrayList<SignerInformation>(1); signers.add(firstSignerInfo); SignerInformationStore sis = new SignerInformationStore(signers); cmsSignedData = CMSSignedData.replaceSigners(cmsSignedData, sis); } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } } protected static AttributeTable appendTimestampAttribute( byte[] timeStampTokenBytes, AttributeTable attributeTable) { Hashtable unsignedAttributesHT; if (attributeTable == null) { unsignedAttributesHT = new Hashtable(); } else { unsignedAttributesHT = attributeTable.toHashtable(); } try { UnsignedAttributesHelper.addTimestampAttribute(unsignedAttributesHT, timeStampTokenBytes); } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } attributeTable = new AttributeTable(unsignedAttributesHT); return attributeTable; } // adds unsigned certs & revocation infos (CRL or OCSP) to existing certs & revocation info list // ('certificates' and 'crls' CMS fields) public void appendValidationValues(Collection certificateValues, Collection revocationValues) { try { Store certStore = cmsSignedData.getCertificates(); Store crlStore = cmsSignedData.getCRLs(); if (certificateValues != null && !certificateValues.isEmpty()) { Collection<Certificate> existingCerts = getSignatureCertificateInfo(); Set<Certificate> newCerts = new HashSet<Certificate>(existingCerts); // 'Set' to avoid duplicates newCerts.addAll(certificateValues); certStore = new JcaCertStore(newCerts); } if (revocationValues != null && !revocationValues.isEmpty()) { Collection<CRL> existingCrls = getUnsignedCRLs(); Set<CRL> newCrls = new HashSet<CRL>(existingCrls); // 'Set' to avoid duplicates // FIXME : also add OCSP info (use OtherRevocationInfoFormat of RevocationInfoChoices, see // RFC 3852) for (Object o : revocationValues) { if (o instanceof CRL) newCrls.add((CRL) o); } crlStore = new JcaCRLStore(newCrls); } cmsSignedData = CMSSignedData.replaceCertificatesAndCRLs( cmsSignedData, certStore, cmsSignedData.getAttributeCertificates(), crlStore); } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } } public byte[] getEncoded() { try { return cmsSignedData.getEncoded(); } catch (IOException e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } public String getSignatureAlgorithm() { return SignatureHelper.getSignatureAlgoFromDigestAndKeyAlgo( getDataDigestAlgorithm(), getEncryptionAlgorithm()); } public String getDataDigestAlgorithm() { return firstSignerInfo.getDigestAlgOID(); } public String getEncryptionAlgorithm() { return firstSignerInfo.getEncryptionAlgOID(); } public List<Certificate> getSignatureCertificateInfo() { try { Store certificateStore = cmsSignedData.getCertificates(); Collection<X509CertificateHolder> certificateCollection = certificateStore.getMatches(null); List<Certificate> x509CertsCollection = new ArrayList<Certificate>(certificateCollection.size()); for (X509CertificateHolder certHolder : certificateCollection) { x509CertsCollection.add( CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME) .generateCertificate(new ByteArrayInputStream(certHolder.getEncoded()))); } return x509CertsCollection; } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } public Collection<CRL> getCRLs() { Collection<CRL> crls = new HashSet<CRL>(); try { crls.addAll(getUnsignedCRLs()); crls.addAll(getSignedCRLs()); return crls; } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return crls; } // unsigned CRLs at the root of CMS structure (outside signerInfos) public Collection<CRL> getUnsignedCRLs() { try { Collection<CertificateList> crlCollection = cmsSignedData.getCRLs().getMatches(null); // Then we need to "cast" from bouncycastle.CertificateList to java.CRL Collection<CRL> x509CrlsCollection = new HashSet<CRL>(crlCollection.size()); for (CertificateList certList : crlCollection) { x509CrlsCollection.add( CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME) .generateCRL(new ByteArrayInputStream(certList.getEncoded()))); } return x509CrlsCollection; } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } // CRLS found as signed ID_ADBE_REVOCATION attribute public Collection<CRL> getSignedCRLs() { try { AttributeTable table = firstSignerInfo.getSignedAttributes(); return SignedAttributesHelper.getSignedCRLs(table); } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } public CertStore getSignatureCRLStore() { try { CertStore crlStore = CertStore.getInstance( "Collection", new CollectionCertStoreParameters(getCRLs()), BouncyCastleProvider.PROVIDER_NAME); return crlStore; } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } public Set<OCSPResponse> getOCSPResponses() { try { Set<OCSPResponse> ocspResponses = getUnsignedOCSPResponses(); ocspResponses.addAll(getSignedOCSPResponses()); return ocspResponses; } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } // OCSP responses found as signed ID_ADBE_REVOCATION attribute public Set<OCSPResponse> getSignedOCSPResponses() { try { AttributeTable table = firstSignerInfo.getSignedAttributes(); return SignedAttributesHelper.getSignedOCSPResponses(table); } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } // unsigned OCSPs at the root of CMS structure (outside signerInfos) public Set<OCSPResponse> getUnsignedOCSPResponses() { try { // FIXME : really fetch those values ! Set<OCSPResponse> ocspResponses = new HashSet<OCSPResponse>(); return ocspResponses; } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } public List<TimestampToken> getSignatureTimestamps() { if (signatureTimeStamps == null) { try { signatureTimeStamps = UnsignedAttributesHelper.getSignatureTimestamps( firstSignerInfo.getUnsignedAttributes()); } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } } return signatureTimeStamps; } public TimestampToken getContentTimestamp() { try { return SignedAttributesHelper.getContentTimestamp(firstSignerInfo.getSignedAttributes()); } catch (Exception e) { ExceptionHandlerTyped.<SPISignatureException>handle(SPISignatureException.class, e); } return null; } public byte[] getSignatureValue() { return firstSignerInfo.getSignature(); } public Certificate getSignerCertificate() { try { Collection certificateCollection = cmsSignedData.getCertificates().getMatches(firstSignerInfo.getSID()); Iterator iterator = certificateCollection.iterator(); X509CertificateHolder certHolder = (X509CertificateHolder) iterator.next(); return CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME) .generateCertificate(new ByteArrayInputStream(certHolder.getEncoded())); } catch (Exception e) { log.error(Channel.TECH, "Could not extract signer certificate from CMS signature : %1$s", e); } return null; } public Date getSigningTime() { return SignedAttributesHelper.getSigningTime(firstSignerInfo.getSignedAttributes()); } public byte[] getDigestAttribute() { return SignedAttributesHelper.getDigestAttribute(firstSignerInfo.getSignedAttributes()); } public ASN1ObjectIdentifier getContentTypeAttribute() { return SignedAttributesHelper.getContentTypeAttribute(firstSignerInfo.getSignedAttributes()); } public ESSCertID getSigningCertificateAttribute() { return SignedAttributesHelper.getSigningCertificateAttribute( firstSignerInfo.getSignedAttributes()); } public ESSCertIDv2 getSigningCertificateV2Attribute() { return SignedAttributesHelper.getSigningCertificateV2Attribute( firstSignerInfo.getSignedAttributes()); } public SignaturePolicyIdentifier getSignaturePolicyIdentifierAttribute() { return SignedAttributesHelper.getSignaturePolicyIdentifierAttribute( firstSignerInfo.getSignedAttributes()); } public DEREncodable getContentReferenceAttribute() { return SignedAttributesHelper.getContentReferenceAttribute( firstSignerInfo.getSignedAttributes()); } public ContentIdentifier getContentIdentifierAttribute() { return SignedAttributesHelper.getContentIdentifierAttribute( firstSignerInfo.getSignedAttributes()); } public ContentHints getContentHintsAttribute() { return SignedAttributesHelper.getContentHintsAttribute(firstSignerInfo.getSignedAttributes()); } public CommitmentTypeIndication getCommitmentTypeIndicationAttribute() { return SignedAttributesHelper.getCommitmentTypeIndicationAttribute( firstSignerInfo.getSignedAttributes()); } public SignerLocation getSignerLocationAttribute() { return SignedAttributesHelper.getSignerLocationAttribute(firstSignerInfo.getSignedAttributes()); } public SignerAttribute getSignerAttributesAttribute() { return SignedAttributesHelper.getSignerAttributesAttribute( firstSignerInfo.getSignedAttributes()); } public SignerInformationStore getCounterSignatures() { return firstSignerInfo.getCounterSignatures(); } // For external signatures, inputStream parameter is the data being signed (external eContent) public boolean verifyExternalWithContent(InputStream inputStream) throws CMSException, IOException, NoSuchAlgorithmException, NoSuchProviderException, CertStoreException, OperatorCreationException, CertificateException { CMSSignedDataParser sp = new CMSSignedDataParser(new CMSTypedStream(inputStream), cmsSignedData.getEncoded()); sp.getSignedContent() .drain(); // here digests are computed and passed to newly created SignerInformation objects Collection signers = sp.getSignerInfos().getSigners(); if (signers.size() != 1) hasMultipleSignerInfos = true; Iterator iterator = signers.iterator(); firstSignerInfo = (SignerInformation) iterator.next(); return CMSVerifier.verify(firstSignerInfo, cmsSignedData.getCertificates()); } // For encapsulated signatures, data being signed is inside the CMS structure, under the // EncapsulatedContentInfo field public boolean verifyEncapsulated() throws InvalidKeyException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException, IOException, CertStoreException, OperatorCreationException, CMSException { return CMSVerifier.verify(firstSignerInfo, cmsSignedData.getCertificates()); } // For external signatures, digest parameter is the digest of the data being signed (external // eContent pre-digested with digestAlgo specified in signerInfo) public boolean verifyExternalWithReference(byte[] digest) throws InvalidKeyException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException, IOException { return CMSVerifier.verifyReference(digest, firstSignerInfo, cmsSignedData.getCertificates()); } public byte[] getEncodedSignedAttrs() throws IOException { return firstSignerInfo.getEncodedSignedAttributes(); } public byte[] getEncodedEncapsulatedData() throws IOException { CMSProcessable content = cmsSignedData.getSignedContent(); if (content == null) return null; return (byte[]) content.getContent(); } }