Example usage for org.bouncycastle.asn1.ess SigningCertificate SigningCertificate

List of usage examples for org.bouncycastle.asn1.ess SigningCertificate SigningCertificate

Introduction

In this page you can find the example usage for org.bouncycastle.asn1.ess SigningCertificate SigningCertificate.

Prototype

public SigningCertificate(ESSCertID essCertID) 

Source Link

Usage

From source file:es.gob.afirma.envelopers.cades.CAdESUtils.java

License:Open Source License

/** Método que genera la parte que contiene la información del
 * Usuario. Se generan los atributos que se necesitan para generar la firma.
 * @param cert Certificado del firmante//  w ww . jav  a 2s.  com
 * @param datos Datos firmados
 * @param policy Política de firma
 * @param messageDigest
 * @return Los datos necesarios para generar la firma referente a los datos
 *         del usuario.
 * @throws java.security.NoSuchAlgorithmException
 * @throws java.io.IOException
 * @throws CertificateEncodingException */
static ASN1EncodableVector generateSignerInfo(final X509Certificate cert, final String digestAlgorithmName,
        final byte[] datos, final AdESPolicy policy, final byte[] messageDigest)
        throws NoSuchAlgorithmException, IOException, CertificateEncodingException {

    // ALGORITMO DE HUELLA DIGITAL
    final AlgorithmIdentifier digestAlgorithmOID = SigUtils
            .makeAlgId(AOAlgorithmID.getOID(digestAlgorithmName));

    // // ATRIBUTOS

    // authenticatedAttributes
    final ASN1EncodableVector contexExpecific = initContexExpecific(digestAlgorithmName, datos,
            PKCSObjectIdentifiers.data.getId(), messageDigest);

    // Serial Number
    // comentar lo de abajo para version del rfc 3852
    contexExpecific.add(new Attribute(RFC4519Style.serialNumber,
            new DERSet(new DERPrintableString(cert.getSerialNumber().toString()))));

    if (!"SHA1".equals(AOSignConstants.getDigestAlgorithmName(digestAlgorithmName))) { //$NON-NLS-1$

        //********************************************/
        //***** La Nueva operatividad esta comentada */
        //********************************************/
        // INICIO SINGING CERTIFICATE-V2

        /** IssuerSerial ::= SEQUENCE { issuer GeneralNames, serialNumber
         * CertificateSerialNumber */

        final TBSCertificateStructure tbs = TBSCertificateStructure
                .getInstance(ASN1Primitive.fromByteArray(cert.getTBSCertificate()));

        /** ESSCertIDv2 ::= SEQUENCE { hashAlgorithm AlgorithmIdentifier
         * DEFAULT {algorithm id-sha256}, certHash Hash, issuerSerial
         * IssuerSerial OPTIONAL }
         * Hash ::= OCTET STRING */

        final byte[] certHash = MessageDigest.getInstance(digestAlgorithmName).digest(cert.getEncoded());
        final ESSCertIDv2[] essCertIDv2 = { new ESSCertIDv2(digestAlgorithmOID, certHash,
                new IssuerSerial(new GeneralNames(new GeneralName(tbs.getIssuer())), tbs.getSerialNumber())) };

        /** PolicyInformation ::= SEQUENCE { policyIdentifier CertPolicyId,
         * policyQualifiers SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo
         * OPTIONAL }
         * CertPolicyId ::= OBJECT IDENTIFIER
         * PolicyQualifierInfo ::= SEQUENCE { policyQualifierId
         * PolicyQualifierId, qualifier ANY DEFINED BY policyQualifierId } */

        final SigningCertificateV2 scv2;
        if (policy.getPolicyIdentifier() != null) {

            /** SigningCertificateV2 ::= SEQUENCE { certs SEQUENCE OF
             * ESSCertIDv2, policies SEQUENCE OF PolicyInformation OPTIONAL
             * } */
            scv2 = new SigningCertificateV2(essCertIDv2, getPolicyInformation(policy)); // con
            // politica
        } else {
            scv2 = new SigningCertificateV2(essCertIDv2); // Sin politica
        }

        // Secuencia con singningCertificate
        contexExpecific.add(new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(scv2)));

        // FIN SINGING CERTIFICATE-V2

    } else {

        // INICIO SINGNING CERTIFICATE

        /** IssuerSerial ::= SEQUENCE { issuer GeneralNames, serialNumber
         * CertificateSerialNumber } */

        final TBSCertificateStructure tbs = TBSCertificateStructure
                .getInstance(ASN1Primitive.fromByteArray(cert.getTBSCertificate()));

        final IssuerSerial isuerSerial = new IssuerSerial(new GeneralNames(new GeneralName(tbs.getIssuer())),
                tbs.getSerialNumber());

        /** ESSCertID ::= SEQUENCE { certHash Hash, issuerSerial IssuerSerial
         * OPTIONAL }
         * Hash ::= OCTET STRING -- SHA1 hash of entire certificate */
        final ESSCertID essCertID = new ESSCertID(
                MessageDigest.getInstance(digestAlgorithmName).digest(cert.getEncoded()), isuerSerial);

        /** PolicyInformation ::= SEQUENCE { policyIdentifier CertPolicyId,
         * policyQualifiers SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo
         * OPTIONAL }
         * CertPolicyId ::= OBJECT IDENTIFIER
         * PolicyQualifierInfo ::= SEQUENCE { policyQualifierId
         * PolicyQualifierId, qualifier ANY DEFINED BY policyQualifierId } */

        final SigningCertificate scv;
        if (policy.getPolicyIdentifier() != null) {

            /** SigningCertificateV2 ::= SEQUENCE { certs SEQUENCE OF
             * ESSCertIDv2, policies SEQUENCE OF PolicyInformation OPTIONAL
             * } */
            /*
             * HAY QUE HACER UN SEQUENCE, YA QUE EL CONSTRUCTOR DE BOUNCY
             * CASTLE NO TIENE DICHO CONSTRUCTOR.
             */
            final ASN1EncodableVector v = new ASN1EncodableVector();
            v.add(new DERSequence(essCertID));
            v.add(new DERSequence(getPolicyInformation(policy)));
            scv = SigningCertificate.getInstance(new DERSequence(v)); // con politica
        } else {
            scv = new SigningCertificate(essCertID); // Sin politica
        }

        /** id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
         * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) smime(16)
         * id-aa(2) 12 } */
        // Secuencia con singningCertificate
        contexExpecific.add(new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificate, new DERSet(scv)));
    }

    // INICIO SIGPOLICYID ATTRIBUTE

    if (policy.getPolicyIdentifier() != null) {
        /*
         * SigPolicyId ::= OBJECT IDENTIFIER Politica de firma.
         */
        final ASN1ObjectIdentifier doiSigPolicyId = new ASN1ObjectIdentifier(
                policy.getPolicyIdentifier().toLowerCase().replace("urn:oid:", "")); //$NON-NLS-1$ //$NON-NLS-2$

        /*
         *   OtherHashAlgAndValue ::= SEQUENCE {
         *     hashAlgorithm    AlgorithmIdentifier,
         *     hashValue        OCTET STRING }
         *
         */

        // Algoritmo para el hash
        final AlgorithmIdentifier hashid;
        // si tenemos algoritmo de calculo de hash, lo ponemos
        if (policy.getPolicyIdentifierHashAlgorithm() != null) {
            hashid = SigUtils.makeAlgId(AOAlgorithmID
                    .getOID(AOSignConstants.getDigestAlgorithmName(policy.getPolicyIdentifierHashAlgorithm())));
        }
        // si no tenemos, ponemos el algoritmo de firma.
        else {
            hashid = digestAlgorithmOID;
        }
        // hash del documento, descifrado en b64
        final byte[] hashed;
        if (policy.getPolicyIdentifierHash() != null) {
            hashed = Base64.decode(policy.getPolicyIdentifierHash());
        } else {
            hashed = new byte[] { 0 };
        }

        final DigestInfo otherHashAlgAndValue = new DigestInfo(hashid, hashed);

        /*
         *   SigPolicyQualifierInfo ::= SEQUENCE {
         *       SigPolicyQualifierId  SigPolicyQualifierId,
         *       SigQualifier          ANY DEFINED BY policyQualifierId }
         */
        SigPolicyQualifierInfo spqInfo = null;
        if (policy.getPolicyQualifier() != null) {
            spqInfo = new SigPolicyQualifierInfo(policy.getPolicyQualifier().toString());
        }

        /*
         * SignaturePolicyId ::= SEQUENCE {
         *  sigPolicyId           SigPolicyId,
         *  sigPolicyHash         SigPolicyHash,
         *  sigPolicyQualifiers   SEQUENCE SIZE (1..MAX) OF
         *                          SigPolicyQualifierInfo OPTIONAL}
         *
         */
        final ASN1EncodableVector v = new ASN1EncodableVector();
        // sigPolicyId
        v.add(doiSigPolicyId);
        // sigPolicyHash
        v.add(otherHashAlgAndValue.toASN1Primitive()); // como sequence
        // sigPolicyQualifiers
        if (spqInfo != null) {
            v.add(spqInfo.toASN1Primitive());
        }

        final DERSequence ds = new DERSequence(v);

        // Secuencia con singningCertificate
        contexExpecific.add(
                new Attribute(PKCSObjectIdentifiers.id_aa_ets_sigPolicyId, new DERSet(ds.toASN1Primitive())));
        // FIN SIGPOLICYID ATTRIBUTE
    }

    return contexExpecific;
}

From source file:es.gob.afirma.signers.cades.CAdESUtils.java

License:Open Source License

/** Genera una estructura <i>SigningCertificateV2</i> seg&uacute;n RFC 5035:
 *
 * <pre>/* ww w  .j  a  v a 2  s.  com*/
 * id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
 *      member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
 *      smime(16) id-aa(2) 12
 * }
 *
 * SigningCertificate ::=  SEQUENCE {
 *      certs        SEQUENCE OF ESSCertID,
 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
 * }
 * </pre>
 *
 * @param cert Certificado del firmante
 * @param digestAlgorithmName Nombre del algoritmo de huella digital a usar
 * @param policy Pol&iacute;tica de firma
 * @return Estructura <i>SigningCertificate</i> seg&uacute;n RFC 5035
 * @throws CertificateEncodingException Si el certificado proporcionado no es v&aacute;lido
 * @throws NoSuchAlgorithmException Si no se soporta el algoritmo de huella indicado */
private static Attribute getSigningCertificateV1(final X509Certificate cert, final String digestAlgorithmName,
        final AdESPolicy policy) throws CertificateEncodingException, NoSuchAlgorithmException {

    // INICIO SINGNING CERTIFICATE

    /** IssuerSerial ::= SEQUENCE { issuer GeneralNames, serialNumber
     * CertificateSerialNumber } */

    final GeneralName gn = new GeneralName(X500Name.getInstance(cert.getIssuerX500Principal().getEncoded()));
    final GeneralNames gns = new GeneralNames(gn);

    final IssuerSerial isuerSerial = new IssuerSerial(gns, cert.getSerialNumber());

    /** ESSCertID ::= SEQUENCE { certHash Hash, issuerSerial IssuerSerial
     * OPTIONAL }
     * Hash ::= OCTET STRING -- SHA1 hash of entire certificate */
    final byte[] certHash = MessageDigest.getInstance(digestAlgorithmName).digest(cert.getEncoded());
    final ESSCertID essCertID = new ESSCertID(certHash, isuerSerial);

    /** PolicyInformation ::= SEQUENCE { policyIdentifier CertPolicyId,
     * policyQualifiers SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo
     * OPTIONAL }
     * CertPolicyId ::= OBJECT IDENTIFIER
     * PolicyQualifierInfo ::= SEQUENCE { policyQualifierId
     * PolicyQualifierId, qualifier ANY DEFINED BY policyQualifierId } */

    final SigningCertificate scv;
    if (policy != null && policy.getPolicyIdentifier() != null) {

        /** SigningCertificateV2 ::= SEQUENCE {
         *    certs SEQUENCE OF ESSCertIDv2,
         *    policies SEQUENCE OF PolicyInformation OPTIONAL
         *  } */

        /*
         * HAY QUE HACER UN SEQUENCE, YA QUE EL CONSTRUCTOR DE BOUNCY
         * CASTLE NO TIENE DICHO CONSTRUCTOR.
         */
        final ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(new DERSequence(essCertID));
        v.add(new DERSequence(getPolicyInformation(policy)));
        scv = SigningCertificate.getInstance(new DERSequence(v)); // con politica
    } else {
        scv = new SigningCertificate(essCertID); // Sin politica
    }

    /** id-aa-signingCertificate OBJECT IDENTIFIER ::= {
     *    iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) smime(16) id-aa(2) 12
     *  } */

    return new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificate, new DERSet(scv));
}

From source file:eu.europa.ec.markt.dss.signature.cades.CAdESLevelBaselineB.java

License:Open Source License

private void addSigningCertificateAttribute(final SignatureParameters parameters,
        final ASN1EncodableVector signedAttributes) throws DSSException {

    final DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm();
    final X509Certificate signingCertificate = parameters.getSigningCertificate();
    final byte[] encoded = DSSUtils.getEncoded(signingCertificate);
    final byte[] certHash = DSSUtils.digest(digestAlgorithm, encoded);
    if (LOG.isDebugEnabled()) {
        LOG.debug("Adding Certificate Hash {} with algorithm {}", DSSUtils.encodeHexString(certHash),
                digestAlgorithm.getName());
    }//from  www .j  ava  2 s.  c  o  m
    final IssuerSerial issuerSerial = DSSUtils.getIssuerSerial(signingCertificate);
    if (digestAlgorithm == DigestAlgorithm.SHA1) {

        final ESSCertID essCertId = new ESSCertID(certHash, issuerSerial);
        final SigningCertificate cadesSigningCertificate = new SigningCertificate(essCertId);
        final DERSet attrValues = new DERSet(cadesSigningCertificate);
        final Attribute attribute = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificate, attrValues);
        signedAttributes.add(attribute);
    } else {

        final ESSCertIDv2 essCertIDv2 = new ESSCertIDv2(digestAlgorithm.getAlgorithmIdentifier(), certHash,
                issuerSerial);
        final ESSCertIDv2[] essCertIDv2Array = new ESSCertIDv2[] { essCertIDv2 };
        final SigningCertificateV2 cadesSigningCertificateV2 = new SigningCertificateV2(essCertIDv2Array);
        final DERSet attrValues = new DERSet(cadesSigningCertificateV2);
        final Attribute attribute = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, attrValues);
        signedAttributes.add(attribute);
    }
}

From source file:eu.europa.ec.markt.dss.signature.cades.CAdESProfileBES.java

License:Open Source License

private Attribute makeSigningCertificateAttribute(SignatureParameters parameters) {
    try {// ww  w  .  ja v  a 2s . co m
        MessageDigest dig = MessageDigest.getInstance(parameters.getDigestAlgorithm().getName(),
                new BouncyCastleProvider());
        byte[] certHash = dig.digest(parameters.getSigningCertificate().getEncoded());

        if (parameters.getDigestAlgorithm() == DigestAlgorithm.SHA1) {
            SigningCertificate sc = new SigningCertificate(new ESSCertID(certHash));

            return new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificate, new DERSet(sc));

        } else {
            ESSCertIDv2 essCert = new ESSCertIDv2(
                    new AlgorithmIdentifier(parameters.getDigestAlgorithm().getOid()), certHash);
            SigningCertificateV2 scv2 = new SigningCertificateV2(new ESSCertIDv2[] { essCert });

            return new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(scv2));
        }
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    } catch (CertificateException e) {
        throw new RuntimeException(e);
    }

}

From source file:eu.europa.esig.dss.cades.signature.CAdESLevelBaselineB.java

License:Open Source License

private void addSigningCertificateAttribute(final CAdESSignatureParameters parameters,
        final ASN1EncodableVector signedAttributes) throws DSSException {
    final DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm();
    final byte[] encoded = parameters.getSigningCertificate().getEncoded();
    final byte[] certHash = DSSUtils.digest(digestAlgorithm, encoded);
    if (LOG.isDebugEnabled()) {
        LOG.debug("Adding Certificate Hash {} with algorithm {}", Hex.encodeHexString(certHash),
                digestAlgorithm.getName());
    }/* w  w w.ja va2 s  .  c o m*/
    final IssuerSerial issuerSerial = DSSASN1Utils.getIssuerSerial(parameters.getSigningCertificate());

    Attribute attribute = null;
    if (digestAlgorithm == DigestAlgorithm.SHA1) {
        final ESSCertID essCertID = new ESSCertID(certHash, issuerSerial);
        SigningCertificate signingCertificate = new SigningCertificate(essCertID);
        attribute = new Attribute(id_aa_signingCertificate, new DERSet(signingCertificate));
    } else {
        final ESSCertIDv2 essCertIdv2 = new ESSCertIDv2(DSSASN1Utils.getAlgorithmIdentifier(digestAlgorithm),
                certHash, issuerSerial);
        SigningCertificateV2 signingCertificateV2 = new SigningCertificateV2(essCertIdv2);
        attribute = new Attribute(id_aa_signingCertificateV2, new DERSet(signingCertificateV2));
    }
    signedAttributes.add(attribute);
}

From source file:org.dihedron.crypto.operations.sign.pkcs7.PKCS7AttributeTableGenerator.java

License:Open Source License

@SuppressWarnings({ "unchecked", "rawtypes" })
public AttributeTable getAttributes(Map parameters) throws CMSAttributeTableGenerationException {

    AttributeTable result = super.getAttributes(parameters);
    Hashtable table = result.toHashtable();

    try {/*from  w  ww  . j  a va 2  s. c  o  m*/

        if (!table.containsKey(SignedData.id_aa_signingCertificate)
                && !table.containsKey(SignedData.id_aa_signingCertificateV2)) {
            logger.debug("signed attributes table does not contain SigningCertificate[V2]: adding...");

            IssuerSerial issuerSerial = Certificates.makeIssuerSerial(x509certificate);

            Attribute attribute = null;
            // create the ESSCertId[V2] objects to embed as SigningCertificate[V2]
            switch (digestAlgorithm) {
            case SHA1:
                logger.info("adding signing certificate v1 to signed attributes");
                ESSCertID essCertId = Certificates.makeESSCertIdV1(x509certificate, issuerSerial,
                        digestAlgorithm);
                attribute = new Attribute(SignedData.id_aa_signingCertificate,
                        new DERSet(new SigningCertificate(essCertId)));
                break;
            case SHA256:
            case SHA384:
            case SHA512:
                logger.info("adding signing certificate v2 to signed attributes");
                ESSCertIDv2 essCertIdv2s[] = Certificates.makeESSCertIdV2(x509certificate, issuerSerial,
                        digestAlgorithm);
                attribute = new Attribute(SignedData.id_aa_signingCertificateV2,
                        new DERSet(new SigningCertificateV2(essCertIdv2s)));
                break;
            default:
                logger.info("unsupported digest algorithm: {}", digestAlgorithm);
            }
            table.put(attribute.getAttrType(), attribute);
        }

        return new AttributeTable(table);

    } catch (CertificateEncodingException e) {
        logger.error("error reading certificate encoding", e);
    } catch (NoSuchAlgorithmException e) {
        logger.error("unsupported digest algorithm: " + digestAlgorithm, e);
    } catch (IOException e) {
        logger.error("I/O error reading certificate structure", e);
    }
    return null;
}

From source file:org.signserver.module.tsa.MSAuthCodeTimeStampSigner.java

License:Open Source License

/**
 * The main method performing the actual timestamp operation.
 * Expects the signRequest to be a GenericSignRequest contining a
 * TimeStampRequest/*from   w w  w  .  j  av a  2  s . c om*/
 *
 * @param signRequest
 * @param requestContext
 * @return the sign response
 * @see org.signserver.server.IProcessable#processData(org.signserver.common.ProcessRequest, org.signserver.common.RequestContext)
 */
public ProcessResponse processData(final ProcessRequest signRequest, final RequestContext requestContext)
        throws IllegalRequestException, CryptoTokenOfflineException, SignServerException {

    // Log values
    final LogMap logMap = LogMap.getInstance(requestContext);

    try {
        final ISignRequest sReq = (ISignRequest) signRequest;
        final byte[] requestbytes = (byte[]) sReq.getRequestData();

        if (requestbytes == null || requestbytes.length == 0) {
            LOG.error("Request must contain data");
            throw new IllegalRequestException("Request must contain data");
        }

        // Check that the request contains a valid TimeStampRequest object.
        if (!(signRequest instanceof GenericSignRequest)) {
            final IllegalRequestException exception = new IllegalRequestException(
                    "Recieved request wasn't an expected GenericSignRequest. ");
            LOG.error("Received request wasn't an expected GenericSignRequest");
            throw exception;
        }

        if (!((sReq.getRequestData() instanceof TimeStampRequest)
                || (sReq.getRequestData() instanceof byte[]))) {
            final IllegalRequestException exception = new IllegalRequestException(
                    "Recieved request data wasn't an expected TimeStampRequest. ");
            LOG.error("Received request data wasn't an expected TimeStampRequest");
            throw exception;
        }

        if (!validChain) {
            LOG.error("Certificate chain not correctly configured");
            throw new CryptoTokenOfflineException("Certificate chain not correctly configured");
        }

        ASN1Primitive asn1obj = ASN1Primitive.fromByteArray(Base64.decode(requestbytes));
        ASN1Sequence asn1seq = ASN1Sequence.getInstance(asn1obj);

        if (asn1seq.size() != 2) {
            LOG.error("Wrong structure, should be an ASN1Sequence with 2 elements");
            throw new IllegalRequestException("Wrong structure, should be an ASN1Sequence with 2 elements");
        }

        ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(asn1seq.getObjectAt(0));
        ASN1Sequence asn1seq1 = ASN1Sequence.getInstance(asn1seq.getObjectAt(1));

        final ContentInfo ci = new ContentInfo(asn1seq1);

        if (!oid.getId().equals(msOID)) {
            LOG.error("Invalid OID in request: " + oid.getId());
            throw new IllegalRequestException("Invalid OID in request: " + oid.getId());
        }

        if (asn1seq1.size() != 2) {
            LOG.error(
                    "Wrong structure, should be an ASN1Sequence with 2 elements as the value of element 0 in the outer ASN1Sequence");
            throw new IllegalRequestException(
                    "Wrong structure, should be an ASN1Sequence with 2 elements as the value of element 0 in the outer ASN1Sequence");
        }

        oid = ASN1ObjectIdentifier.getInstance(asn1seq1.getObjectAt(0));

        if (!oid.getId().equals(dataOID)) {
            throw new IllegalRequestException("Wrong contentType OID: " + oid.getId());
        }

        ASN1TaggedObject tag = ASN1TaggedObject.getInstance(asn1seq1.getObjectAt(1));

        if (tag.getTagNo() != 0) {
            throw new IllegalRequestException("Wrong tag no (should be 0): " + tag.getTagNo());
        }

        ASN1OctetString octets = ASN1OctetString.getInstance(tag.getObject());
        byte[] content = octets.getOctets();

        final ITimeSource timeSrc;
        final Date date;
        byte[] der;
        ICryptoInstance crypto = null;
        try {
            crypto = acquireCryptoInstance(ICryptoToken.PURPOSE_SIGN, signRequest, requestContext);

            // get signing cert certificate chain and private key
            List<Certificate> certList = this.getSigningCertificateChain(crypto);
            if (certList == null) {
                throw new SignServerException("Null certificate chain. This signer needs a certificate.");
            }

            Certificate[] certs = (Certificate[]) certList.toArray(new Certificate[certList.size()]);

            // Sign
            X509Certificate x509cert = (X509Certificate) certs[0];

            timeSrc = getTimeSource();
            if (LOG.isDebugEnabled()) {
                LOG.debug("TimeSource: " + timeSrc.getClass().getName());
            }
            date = timeSrc.getGenTime();

            if (date == null) {
                throw new ServiceUnavailableException("Time source is not available");
            }

            ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
            signedAttributes.add(new Attribute(CMSAttributes.signingTime, new DERSet(new Time(date))));

            if (includeSigningCertificateAttribute) {
                try {
                    final DERInteger serial = new DERInteger(x509cert.getSerialNumber());
                    final X509CertificateHolder certHolder = new X509CertificateHolder(x509cert.getEncoded());
                    final X500Name issuer = certHolder.getIssuer();
                    final GeneralName name = new GeneralName(issuer);
                    final GeneralNames names = new GeneralNames(name);
                    final IssuerSerial is = new IssuerSerial(names, ASN1Integer.getInstance(serial));

                    final ESSCertID essCertid = new ESSCertID(
                            MessageDigest.getInstance("SHA-1").digest(x509cert.getEncoded()), is);
                    signedAttributes.add(new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificate,
                            new DERSet(new SigningCertificate(essCertid))));
                } catch (NoSuchAlgorithmException e) {
                    LOG.error("Can't find SHA-1 implementation: " + e.getMessage());
                    throw new SignServerException("Can't find SHA-1 implementation", e);
                }
            }

            AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
            DefaultSignedAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator(
                    signedAttributesTable);

            final String provider = cryptoToken.getProvider(ICryptoToken.PROVIDERUSAGE_SIGN);

            SignerInfoGeneratorBuilder signerInfoBuilder = new SignerInfoGeneratorBuilder(
                    new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());
            signerInfoBuilder.setSignedAttributeGenerator(signedAttributeGenerator);

            JcaContentSignerBuilder contentSigner = new JcaContentSignerBuilder(signatureAlgo);
            contentSigner.setProvider(provider);

            final SignerInfoGenerator sig = signerInfoBuilder.build(contentSigner.build(crypto.getPrivateKey()),
                    new X509CertificateHolder(x509cert.getEncoded()));

            JcaCertStore cs = new JcaCertStore(certList);

            CMSTypedData cmspba = new CMSProcessableByteArray(content);
            CMSSignedData cmssd = MSAuthCodeCMSUtils.generate(cmspba, true, Arrays.asList(sig),
                    MSAuthCodeCMSUtils.getCertificatesFromStore(cs), Collections.emptyList(), ci);

            der = ASN1Primitive.fromByteArray(cmssd.getEncoded()).getEncoded();
        } finally {
            releaseCryptoInstance(crypto, requestContext);
        }

        // Log values
        logMap.put(ITimeStampLogger.LOG_TSA_TIME, String.valueOf(date.getTime()));
        logMap.put(ITimeStampLogger.LOG_TSA_TIMESOURCE, timeSrc.getClass().getSimpleName());

        final String archiveId = createArchiveId(requestbytes,
                (String) requestContext.get(RequestContext.TRANSACTION_ID));

        final GenericSignResponse signResponse;
        byte[] signedbytes = Base64.encode(der, false);

        logMap.put(ITimeStampLogger.LOG_TSA_TIMESTAMPRESPONSE_ENCODED, new String(signedbytes));

        final Collection<? extends Archivable> archivables = Arrays.asList(
                new DefaultArchivable(Archivable.TYPE_REQUEST, REQUEST_CONTENT_TYPE, requestbytes, archiveId),
                new DefaultArchivable(Archivable.TYPE_RESPONSE, RESPONSE_CONTENT_TYPE, signedbytes, archiveId));

        if (signRequest instanceof GenericServletRequest) {
            signResponse = new GenericServletResponse(sReq.getRequestID(), signedbytes,
                    getSigningCertificate(signRequest, requestContext), archiveId, archivables,
                    RESPONSE_CONTENT_TYPE);
        } else {
            signResponse = new GenericSignResponse(sReq.getRequestID(), signedbytes,
                    getSigningCertificate(signRequest, requestContext), archiveId, archivables);
        }

        // The client can be charged for the request
        requestContext.setRequestFulfilledByWorker(true);

        return signResponse;

    } catch (IOException e) {
        final IllegalRequestException exception = new IllegalRequestException("IOException: " + e.getMessage(),
                e);
        LOG.error("IOException: ", e);
        logMap.put(ITimeStampLogger.LOG_TSA_EXCEPTION, exception.getMessage());
        throw exception;
    } catch (CMSException e) {
        final SignServerException exception = new SignServerException(e.getMessage(), e);
        LOG.error("CMSException: ", e);
        logMap.put(ITimeStampLogger.LOG_TSA_EXCEPTION, exception.getMessage());
        throw exception;
    } catch (OperatorCreationException e) {
        final SignServerException exception = new SignServerException(e.getMessage(), e);
        LOG.error("OperatorCreationException: ", e);
        logMap.put(ITimeStampLogger.LOG_TSA_EXCEPTION, exception.getMessage());
        throw exception;
    } catch (CertificateEncodingException e) {
        final SignServerException exception = new SignServerException(e.getMessage(), e);
        LOG.error("CertificateEncodingException: ", e);
        logMap.put(ITimeStampLogger.LOG_TSA_EXCEPTION, exception.getMessage());
        throw exception;
    } catch (ArrayIndexOutOfBoundsException e) {
        // the BC base64 decoder doesn't check the the base64 input length...
        final IllegalRequestException exception = new IllegalRequestException(
                "ArrayIndexOutOfBoundsException: " + e.getMessage(), e);
        LOG.error("ArrayIndexOutOfBoundsException: ", e);
        logMap.put(ITimeStampLogger.LOG_TSA_EXCEPTION, exception.getMessage());
        throw exception;
    }
}