package com.opentrust.spi.cms.helpers;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CRL;
import java.security.cert.CRLException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509CRL;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTCTime;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.asn1.cms.Time;
import org.bouncycastle.asn1.esf.CommitmentTypeIndication;
import org.bouncycastle.asn1.esf.OtherHashAlgAndValue;
import org.bouncycastle.asn1.esf.SignaturePolicyId;
import org.bouncycastle.asn1.esf.SignaturePolicyIdentifier;
import org.bouncycastle.asn1.esf.SignerAttribute;
import org.bouncycastle.asn1.esf.SignerLocation;
import org.bouncycastle.asn1.ess.ContentHints;
import org.bouncycastle.asn1.ess.ContentIdentifier;
import org.bouncycastle.asn1.ess.ESSCertID;
import org.bouncycastle.asn1.ess.ESSCertIDv2;
import org.bouncycastle.asn1.ess.SigningCertificate;
import org.bouncycastle.asn1.ess.SigningCertificateV2;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.AttributeCertificate;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.tsp.TSPException;
import com.opentrust.spi.crypto.CRLHelper;
import com.opentrust.spi.logger.Channel;
import com.opentrust.spi.logger.SPILogger;
/*
import com.opentrust.spi.crypto.CRLHelper;
import com.opentrust.spi.ocsp.OCSPResponse;
import com.opentrust.spi.ocsp.OCSPResponseFactory;
import com.opentrust.spi.tsp.TimestampToken;
import com.opentrust.spi.tsp.TimestampTokenManagerFactory;
*/
import com.opentrust.spi.tsp.TimestampToken;
import com.opentrust.spi.tsp.impl.BCTimeStampToken;
public class SignedAttributesHelper {
private static SPILogger log = SPILogger.getLogger("CMS");
public static final ASN1ObjectIdentifier ID_ADBE_REVOCATION = new ASN1ObjectIdentifier("1.2.840.113583.1.1.8");
/****** SETTERS *******/
public static void addMessageDigestAttribute(Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable, byte[] digest) {
if(digest==null) return;
Attribute messageDigestAttribute = new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(digest)));
signedAttributesHashtable.put(CMSAttributes.messageDigest, messageDigestAttribute);
}
public static void addSigningTimeAttribute(Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable, Date signingTime) {
if(signingTime==null) return;
Attribute signingTimeAttribute = new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(signingTime)));
signedAttributesHashtable.put(CMSAttributes.signingTime, signingTimeAttribute);
}
public static void addSigningCertificateAttribute(
Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable, Certificate cert)
throws CertificateEncodingException, NoSuchAlgorithmException {
if (cert == null)
return;
ESSCertID essCertid = new ESSCertID(MessageDigest.getInstance("SHA-1").digest(cert.getEncoded()));
Attribute signingCertificateAttribute = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificate,
new DERSet(new SigningCertificate(essCertid)));
signedAttributesHashtable.put(PKCSObjectIdentifiers.id_aa_signingCertificate, signingCertificateAttribute);
}
public static void addSigningCertificateV2Attribute(
Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable,
AlgorithmIdentifier hashAlgo, Certificate cert)
throws CertificateEncodingException, NoSuchAlgorithmException, NoSuchProviderException {
if (cert == null || hashAlgo == null)
return;
ESSCertIDv2 essCertid = new ESSCertIDv2(hashAlgo, MessageDigest.getInstance(hashAlgo.getAlgorithm().getId(),
BouncyCastleProvider.PROVIDER_NAME).digest(cert.getEncoded()));
Attribute signingCertificateV2Attribute = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2,
new DERSet(new SigningCertificateV2(new ESSCertIDv2[] { essCertid })));
signedAttributesHashtable.put(PKCSObjectIdentifiers.id_aa_signingCertificateV2, signingCertificateV2Attribute);
}
public static void addRevocationValuesAttribute(Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable, Collection<CRL> crls, Collection<OCSPResponse> ocspResponses) throws IOException, CRLException {
if (((crls == null) || (crls.size() == 0)) && ((ocspResponses == null) || (ocspResponses.size() == 0)))
return;
ASN1EncodableVector revocationValues = new ASN1EncodableVector();
if ((crls != null) && (crls.size() > 0)) {
ASN1EncodableVector v2 = new ASN1EncodableVector();
for (CRL crl:crls) {
ASN1InputStream t = new ASN1InputStream(new ByteArrayInputStream(((X509CRL) crl).getEncoded()));
v2.add(t.readObject());
}
// 0->CRL
revocationValues.add(new DERTaggedObject(true, 0, new DERSequence(
v2)));
}
if ((ocspResponses != null) && (ocspResponses.size() > 0)) {
ASN1EncodableVector v2 = new ASN1EncodableVector();
for (OCSPResponse ocspResponse : ocspResponses) {
ASN1InputStream t = new ASN1InputStream(
new ByteArrayInputStream(ocspResponse.getEncoded()));
v2.add(t.readObject());
}
// 1->OCSP
revocationValues.add(new DERTaggedObject(true, 1, new DERSequence(
v2)));
}
Attribute revocationAttr = new Attribute(ID_ADBE_REVOCATION,
new DERSet(new DERSequence(revocationValues)));
signedAttributesHashtable.put(ID_ADBE_REVOCATION, revocationAttr);
}
public static void addSignaturePolicyIdentifier(Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable, DERObjectIdentifier signaturePolicyOID, ASN1OctetString signaturePolicyHashValue, AlgorithmIdentifier signaturePolicyHashAlgorithm) throws CertificateEncodingException, NoSuchAlgorithmException, NoSuchProviderException {
//FIXME : validate input
SignaturePolicyIdentifier signaturePolicyIdentifier = new SignaturePolicyIdentifier(new SignaturePolicyId(signaturePolicyOID, new OtherHashAlgAndValue(signaturePolicyHashAlgorithm, signaturePolicyHashValue)));
Attribute signaturePolicyIdentifierAttr = new Attribute(PKCSObjectIdentifiers.id_aa_ets_sigPolicyId, new DERSet(signaturePolicyIdentifier));
signedAttributesHashtable.put(PKCSObjectIdentifiers.id_aa_ets_sigPolicyId, signaturePolicyIdentifierAttr);
}
public static void addImpliedSignaturePolicy(Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable) {
SignaturePolicyIdentifier signaturePolicyIdentifier = new SignaturePolicyIdentifier();
Attribute signaturePolicyIdentifierAttr = new Attribute(PKCSObjectIdentifiers.id_aa_ets_sigPolicyId, new DERSet(signaturePolicyIdentifier));
signedAttributesHashtable.put(PKCSObjectIdentifiers.id_aa_ets_sigPolicyId, signaturePolicyIdentifierAttr);
}
public static void addSignerAttributes(Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable, String claimedAttributesOID, List<String> claimedAttributes, byte[] certifiedAttributes) throws IOException {
SignerAttribute signerAttribute = null;
if(claimedAttributes!=null && !claimedAttributes.isEmpty()) {
DERUTF8String[] claimedRoles = new DERUTF8String[claimedAttributes.size()];
int i = 0;
for(String claimedRole : claimedAttributes) {
claimedRoles[i++] = new DERUTF8String(claimedRole);
}
ASN1Set claimedRolesList = new DERSet(claimedRoles);
Attribute claimedRolesAttr = new Attribute(new ASN1ObjectIdentifier(claimedAttributesOID), claimedRolesList);
signerAttribute = new SignerAttribute(new DERSequence(claimedRolesAttr));
} else if(certifiedAttributes!=null) {
ByteArrayInputStream bIn = new ByteArrayInputStream(certifiedAttributes);
ASN1InputStream aIn = new ASN1InputStream(bIn);
ASN1Sequence seq = (ASN1Sequence) aIn.readObject();
signerAttribute = new SignerAttribute(new AttributeCertificate(seq));
}
//TODO : else, when both are empty, throw exception
Attribute signerAttributesAttr = new Attribute(PKCSObjectIdentifiers.id_aa_ets_signerAttr, new DERSet(signerAttribute));
signedAttributesHashtable.put(PKCSObjectIdentifiers.id_aa_ets_signerAttr, signerAttributesAttr);
}
public static void addContentTimestampAttribute(Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable, byte[] timeStampTokenBytes) throws IOException {
if(timeStampTokenBytes==null) return;
DERObject derObj = new ASN1InputStream(new ByteArrayInputStream(timeStampTokenBytes)).readObject();
DERSet derSet = new DERSet(derObj);
Attribute contentTimestampAtt = new Attribute(PKCSObjectIdentifiers.id_aa_ets_contentTimestamp, derSet);
signedAttributesHashtable.put(PKCSObjectIdentifiers.id_aa_ets_contentTimestamp, contentTimestampAtt);
}
public static void addCommitmentTypeIndicationAttribute(Hashtable<DERObjectIdentifier, Attribute> signedAttributesHashtable, String commitmentTypeId) throws IOException {
CommitmentTypeIndication indic = new CommitmentTypeIndication(new ASN1ObjectIdentifier(commitmentTypeId));
Attribute commitmentTypeIndicationAttr = new Attribute(PKCSObjectIdentifiers.id_aa_ets_commitmentType, new DERSet(indic));
signedAttributesHashtable.put(PKCSObjectIdentifiers.id_aa_ets_commitmentType, commitmentTypeIndicationAttr);
}
/****** GETTERS *******/
public static Set<OCSPResponse> getSignedOCSPResponses(AttributeTable table) {
Set<OCSPResponse> ocspResponses = new HashSet<OCSPResponse>();
// OCSP responses found as signed ID_ADBE_REVOCATION attribute
if(table!=null) {
Attribute hash = table.get(ID_ADBE_REVOCATION);
if(hash!=null) {
ASN1Set attrValues = hash.getAttrValues();
if(attrValues!=null) {
DERSequence seq = (DERSequence) attrValues.getObjectAt(0);
if(seq!=null) {
Enumeration enumer0 = seq.getObjects();
if(enumer0!=null) {
while(enumer0.hasMoreElements()) {
DEREncodable derenc = (DEREncodable)enumer0.nextElement();
DERTaggedObject dertag = (DERTaggedObject) derenc;
if (dertag.getTagNo()==1) { // 1->OCSP
// Extracts signed OCSPs
DERSequence seq3 = (DERSequence) dertag.getObject();
for (int i=0; i < seq3.size(); ++i) {
DERSequence seq4 = ((DERSequence)seq3.getObjectAt(i));
OCSPResponse ocspResponse = null;
try {
byte[] ocspResponseEncoded = seq4.getDEREncoded();
ocspResponse = OCSPResponse.parseResponse(ocspResponseEncoded);
} catch (Exception e1) {
log.error(Channel.TECH, "Problem with ocspResponse retrieving : " + e1);
}
if (ocspResponse != null) {
log.debug(Channel.TECH, "Successfully parsed OCSP response");
ocspResponses.add(ocspResponse);
} else
log.info(Channel.TECH, "OCSP response extracted from pdf signature is null !");
}
}
}
}
}
}
}
}
return ocspResponses;
}
public static Collection<CRL> getSignedCRLs(AttributeTable table) throws CRLException, CertificateException, IOException, NoSuchProviderException {
Collection<CRL> x509CrlsCollection = new HashSet<CRL>();
if(table!=null) {
Attribute hash = table.get(ID_ADBE_REVOCATION);
if(hash!=null) {
ASN1Set attrValues = hash.getAttrValues();
if(attrValues!=null) {
DERSequence seq = (DERSequence) attrValues.getObjectAt(0);
if(seq!=null) {
Enumeration enumer0 = seq.getObjects();
if(enumer0!=null) {
while(enumer0.hasMoreElements()) {
DEREncodable derenc = (DEREncodable)enumer0.nextElement();
if(derenc!=null) {
DERTaggedObject dertag = (DERTaggedObject) derenc;
if (dertag.getTagNo()==0) { // 0->CRL
// Extracts signed CRLs
DERSequence seq3 = (DERSequence) dertag.getObject();
for (int i=0; i < seq3.size(); ++i) {
DERSequence seq4 = ((DERSequence)seq3.getObjectAt(i));
CRL crl = CRLHelper.getCRL(seq4.getDEREncoded());
x509CrlsCollection.add(crl);
}
}
}
}
}
}
}
}
}
return x509CrlsCollection;
}
public static Date getSigningTime(AttributeTable atab) {
Date result = null;
if (atab != null) {
Attribute attr = atab.get(CMSAttributes.signingTime);
if (attr != null) {
Time t = Time.getInstance(attr.getAttrValues().getObjectAt(0).getDERObject());
result = t.getDate();
}
}
return result;
}
public static byte[] getDigestAttribute(AttributeTable atab) {
byte[] result = null;
if (atab != null) {
Attribute attr = atab.get(CMSAttributes.messageDigest);
if (attr != null) {
result = ASN1OctetString.getInstance(attr.getAttrValues().getObjectAt(0)).getOctets();
}
}
return result;
}
public static ASN1ObjectIdentifier getContentTypeAttribute(AttributeTable atab) {
ASN1ObjectIdentifier result = null;
if (atab != null) {
Attribute attr = atab.get(CMSAttributes.contentType);
if (attr != null) {
result = (ASN1ObjectIdentifier)attr.getAttrValues().getObjectAt(0);
}
}
return result;
}
public static ESSCertID getSigningCertificateAttribute(AttributeTable atab) {
ESSCertID result = null;
if (atab != null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_signingCertificate);
if (attr != null) {
ESSCertID[] signingCerts = SigningCertificate.getInstance(attr.getAttrValues().getObjectAt(0)).getCerts();
if(signingCerts!=null && signingCerts.length>0) {
result = signingCerts[0];
}
//TODO : what should we do with the other certs ?
}
}
return result;
}
public static ESSCertIDv2 getSigningCertificateV2Attribute(AttributeTable atab) {
ESSCertIDv2 result = null;
if (atab != null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2);
if (attr != null) {
ESSCertIDv2[] signingCerts = SigningCertificateV2.getInstance(attr.getAttrValues().getObjectAt(0)).getCerts();
if(signingCerts!=null && signingCerts.length>0) {
result = signingCerts[0];
}
//TODO : what should we do with the other certs ?
}
}
return result;
}
public static SignaturePolicyIdentifier getSignaturePolicyIdentifierAttribute(AttributeTable atab) {
SignaturePolicyIdentifier result = null;
if (atab != null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_ets_sigPolicyId);
if (attr != null) {
result = SignaturePolicyIdentifier.getInstance(attr.getAttrValues().getObjectAt(0));
}
}
return result;
}
public static DEREncodable getContentReferenceAttribute(AttributeTable atab) {
DEREncodable result = null;
if (atab != null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_contentReference);
if (attr != null) {
result = attr.getAttrValues().getObjectAt(0);
}
}
return result;
}
public static ContentIdentifier getContentIdentifierAttribute(AttributeTable atab) {
ContentIdentifier result = null;
if (atab != null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_contentIdentifier);
if (attr != null) {
result = ContentIdentifier.getInstance(attr.getAttrValues().getObjectAt(0));
}
}
return result;
}
public static ContentHints getContentHintsAttribute(AttributeTable atab) {
ContentHints result = null;
if (atab != null) {
Attribute attr = atab.get(CMSAttributes.contentHint);
if (attr != null) {
result = ContentHints.getInstance(attr.getAttrValues().getObjectAt(0));
}
}
return result;
}
public static CommitmentTypeIndication getCommitmentTypeIndicationAttribute(AttributeTable atab) {
CommitmentTypeIndication result = null;
if (atab != null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_ets_commitmentType);
if (attr != null) {
result = CommitmentTypeIndication.getInstance(attr.getAttrValues().getObjectAt(0));
}
}
return result;
}
public static SignerLocation getSignerLocationAttribute(AttributeTable atab) {
SignerLocation result = null;
if (atab != null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_ets_signerLocation);
if (attr != null) {
result = SignerLocation.getInstance(attr.getAttrValues().getObjectAt(0));
}
}
return result;
}
public static SignerAttribute getSignerAttributesAttribute(AttributeTable atab) {
SignerAttribute result = null;
if (atab != null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_ets_signerAttr);
if (attr != null) {
// Does not work for certifiedAttributes !? (AttributeCertificate.getInstance(dertaggedobject) tries to ASN1Sequence.getInstance(dertaggedobject) -> fails)
//FIXME : use this simple line when bug is fixed by BC
//result = SignerAttribute.getInstance(attr.getAttrValues().getObjectAt(0));
// Copied from SignerAttribute getInstance & constructor :
Object obj = attr.getAttrValues().getObjectAt(0);
if(obj == null || (obj instanceof SignerAttribute))
return (SignerAttribute)obj;
if(obj instanceof ASN1Sequence) {
ASN1Sequence asn1sequence = (ASN1Sequence)obj;
DERTaggedObject dertaggedobject = (DERTaggedObject)asn1sequence.getObjectAt(0);
if(dertaggedobject.getTagNo() == 0)
result = new SignerAttribute(ASN1Sequence.getInstance(dertaggedobject, true));
else if(dertaggedobject.getTagNo() == 1) {
return new SignerAttribute(new AttributeCertificate(ASN1Sequence.getInstance(dertaggedobject, true)));
} else
throw new IllegalArgumentException("illegal tag.");
} else
throw new IllegalArgumentException((new StringBuilder()).append("unknown object in 'SignerAttribute' factory: ").append(obj.getClass().getName()).append(".").toString());
}
}
return result;
}
public static TimestampToken getContentTimestamp(AttributeTable atab) throws IOException, CMSException, TSPException {
TimestampToken result = null;
if(atab!=null) {
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_ets_contentTimestamp);
if (attr != null) {
DEREncodable dob = attr.getAttrValues().getObjectAt(0);
if(dob!=null) {
byte[] encodedTsp = dob.getDERObject().getEncoded();
if(encodedTsp!=null) {
result = new BCTimeStampToken(encodedTsp);
}
}
}
}
return result;
}
}