package eu.europa.esig.dss.cades; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Hashtable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.cms.Attribute; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; import org.bouncycastle.asn1.ocsp.OCSPResponse; import org.bouncycastle.cert.ocsp.BasicOCSPResp; import org.bouncycastle.cert.ocsp.OCSPException; import org.bouncycastle.cert.ocsp.OCSPResp; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.CMSProcessableByteArray; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignedDataGenerator; import org.bouncycastle.cms.CMSTypedData; import org.bouncycastle.cms.SignerInformation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.europa.esig.dss.DSSASN1Utils; import eu.europa.esig.dss.DSSException; public final class CMSUtils { private static final Logger logger = LoggerFactory.getLogger(CMSUtils.class); private CMSUtils() {} /** * Returns the ASN.1 encoded representation of {@code CMSSignedData}. * * @param data * @return * @throws DSSException */ public static byte[] getEncoded(final CMSSignedData data) throws DSSException { try { return data.getEncoded(); } catch (IOException e) { throw new DSSException(e); } } /** * This method generate {@code CMSSignedData} using the provided #{@code CMSSignedDataGenerator}, the content and the indication if the content should be encapsulated. * * @param generator * @param content * @param encapsulate * @return * @throws DSSException */ public static CMSSignedData generateCMSSignedData(final CMSSignedDataGenerator generator, final CMSProcessableByteArray content, final boolean encapsulate) throws DSSException { try { final CMSSignedData cmsSignedData = generator.generate(content, encapsulate); return cmsSignedData; } catch (CMSException e) { throw new DSSException(e); } } public static CMSSignedData generateDetachedCMSSignedData(final CMSSignedDataGenerator generator, final CMSProcessableByteArray content) throws DSSException { return generateCMSSignedData(generator, content, false); } /** * @param signerInformation {@code SignerInformation} * @return {@code DERTaggedObject} representing the signed attributes * @throws DSSException in case of a decoding problem */ public static DERTaggedObject getDERSignedAttributes(final SignerInformation signerInformation) throws DSSException { try { final byte[] encodedSignedAttributes = signerInformation.getEncodedSignedAttributes(); if (encodedSignedAttributes == null) { return null; } final ASN1Set asn1Set = DSSASN1Utils.toASN1Primitive(encodedSignedAttributes); return new DERTaggedObject(false, 0, asn1Set); } catch (IOException e) { throw new DSSException(e); } } /** * This method returns the signed content extracted from a CMSTypedData * @param cmsTypedData * {@code CMSTypedData} cannot be null * @return the signed content extracted from {@code CMSTypedData} */ public static byte[] getSignedContent(final CMSTypedData cmsTypedData) { try { final ByteArrayOutputStream originalDocumentData = new ByteArrayOutputStream(); cmsTypedData.write(originalDocumentData); return originalDocumentData.toByteArray(); } catch (Exception e) { throw new DSSException(e); } } /** * This method returns the existing unsigned attributes or a new empty attributes hashtable * * @param signerInformation * the signer information * @return the existing unsigned attributes or an empty attributes hashtable */ public static AttributeTable getUnsignedAttributes(final SignerInformation signerInformation) { final AttributeTable unsignedAttributes = signerInformation.getUnsignedAttributes(); if (unsignedAttributes == null) { return new AttributeTable(new Hashtable<ASN1ObjectIdentifier, Attribute>()); } else { return unsignedAttributes; } } /** * This method returns the existing signed attributes or a new empty attributes hashtable * * @param signerInformation * the signer information * @return the existing signed attributes or an empty attributes {@code Hashtable} */ public static AttributeTable getSignedAttributes(final SignerInformation signerInformation) { final AttributeTable signedAttributes = signerInformation.getSignedAttributes(); if (signedAttributes == null) { return new AttributeTable(new Hashtable<ASN1ObjectIdentifier, Attribute>()); } else { return signedAttributes; } } /** * This method allows to create a {@code BasicOCSPResp} from a {@code DERSequence}. * The value for response SHALL be the DER encoding of BasicOCSPResponse (RFC 2560). * * @param derSequence * {@code DERSequence} to convert to {@code BasicOCSPResp} * @return {@code BasicOCSPResp} */ public static BasicOCSPResp getBasicOcspResp(final DERSequence derSequence) { BasicOCSPResp basicOCSPResp = null; try { final BasicOCSPResponse basicOcspResponse = BasicOCSPResponse.getInstance(derSequence); basicOCSPResp = new BasicOCSPResp(basicOcspResponse); } catch (Exception e) { logger.error("Impossible to create BasicOCSPResp from DERSequence!", e); } return basicOCSPResp; } /** * This method allows to create a {@code OCSPResp} from a {@code DERSequence}. * * @param derSequence * {@code DERSequence} to convert to {@code OCSPResp} * @return {@code OCSPResp} */ public static OCSPResp getOcspResp(final DERSequence derSequence) { OCSPResp ocspResp = null; try { final OCSPResponse ocspResponse = OCSPResponse.getInstance(derSequence); ocspResp = new OCSPResp(ocspResponse); } catch (Exception e) { logger.error("Impossible to create OCSPResp from DERSequence!", e); } return ocspResp; } /** * This method returns the {@code BasicOCSPResp} from a {@code OCSPResp}. * * @param ocspResp * {@code OCSPResp} to analysed * @return */ public static BasicOCSPResp getBasicOCSPResp(final OCSPResp ocspResp) { BasicOCSPResp basicOCSPResp = null; try { final Object responseObject = ocspResp.getResponseObject(); if (responseObject instanceof BasicOCSPResp) { basicOCSPResp = (BasicOCSPResp) responseObject; } else { logger.warn("Unknown OCSP response type: {}", responseObject.getClass()); } } catch (OCSPException e) { logger.error("Impossible to process OCSPResp!", e); } return basicOCSPResp; } }