简体   繁体   中英

How to convert detached CAdES signature to enveloped using BC?

My java applet is able to generate a CMSSignedData using Bouncy Castle 1.4.9 of the type detached. The byte array sigData.getEncoded() is then stored in a table on the server (which has access to the content data not enclosed). Now I would like to create the enveloped CMSSignedData in the server in order for the user to download a .p7m file.

The function I need to develop has the byte array of the detached signature and the byte array of the content data and must return the byte array of a CaDES enveloped signature, which will be used to download the .p7m file.

The problem is that I was not able to convert the detached signatore to an enveloped one.

Here is some code I used in my applet: signCAdeS signs the document using a detached signature, then calls attach (just for testing) to convert the detached to enveloped but without success: Opening the created .p7m file with Dike it is not possible to view the content data.

private byte[] signCAdES(byte[] aDocument, PrivateKey aPrivateKey, Certificate[] certChain)
        throws GeneralSecurityException {
    byte[] digitalSignature = null;
    try {

        Security.addProvider(new BouncyCastleProvider());
        ArrayList<X509Certificate> certsin = new ArrayList<X509Certificate>();
        for (int i = 0; i < certChain.length; i++) {
            certsin.add((X509Certificate) certChain[i]);
        }
        X509Certificate cert = certsin.get(0);
        //Nel nuovo standard di firma digitale e' richiesto l'hash del certificato di sottoscrizione:
        String digestAlgorithm = "SHA-256";
        String digitalSignatureAlgorithmName = "SHA256withRSA";
        MessageDigest sha = MessageDigest.getInstance(digestAlgorithm);
        byte[] digestedCert = sha.digest(cert.getEncoded());

        //Viene ora create l'attributo ESSCertID versione 2 cosi come richiesto nel nuovo standard:
        AlgorithmIdentifier aiSha256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256);
        ESSCertIDv2 essCert1 = new ESSCertIDv2(aiSha256, digestedCert);
        ESSCertIDv2[] essCert1Arr = {essCert1};
        SigningCertificateV2 scv2 = new SigningCertificateV2(essCert1Arr);
        Attribute certHAttribute = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, new DERSet(scv2));

        //Aggiungiamo l'attributo al vettore degli attributi da firmare:
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(certHAttribute);
        AttributeTable at = new AttributeTable(v);
        CMSAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator(at);

        //Creaiamo l'oggetto che firma e crea l'involucro attraverso le librerie di Bouncy Castle:
        SignerInfoGeneratorBuilder genBuild = new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider());
        genBuild.setSignedAttributeGenerator(attrGen);

        //Si effettua la firma con l'algoritmo SHA256withRSA che crea l'hash e lo firma con l'algoritmo RSA:
        CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
        ContentSigner shaSigner = new JcaContentSignerBuilder("SHA256withRSA").build(aPrivateKey);
        SignerInfoGenerator sifGen = genBuild.build(shaSigner, new X509CertificateHolder(cert.getEncoded()));
        gen.addSignerInfoGenerator(sifGen);
        X509CollectionStoreParameters x509CollectionStoreParameters = new X509CollectionStoreParameters(certsin);
        JcaCertStore jcaCertStore = new JcaCertStore(certsin);
        gen.addCertificates(jcaCertStore);

        CMSTypedData msg = new CMSProcessableByteArray(aDocument);
        CMSSignedData sigData = gen.generate(msg, false); // false=detached

        byte[] encoded = sigData.getEncoded();

        FileOutputStream fos = new FileOutputStream("H:\\prova2.txt.p7m");
        fos.write(attach(aDocument, encoded));
        fos.flush();
        fos.close();
        digitalSignature = encoded;


    } catch (CMSException ex) {
        ex.printStackTrace();
    } catch (IOException ex) {
        ex.printStackTrace();
    } catch (OperatorCreationException ex) {
        ex.printStackTrace();
    }
    return digitalSignature;
}

Here is the attach function:

public static byte[] attach(byte[] originalData, byte[] detached) {
    try {
        ASN1InputStream in = new ASN1InputStream(detached);

        CMSSignedData sigData = new CMSSignedData(new CMSProcessableByteArray(originalData), in);

        return sigData.getEncoded();
    } catch (Exception e) {
        return null;
    }
}

This response comes a little late. Surely you will have found an alternative because it is not possible to convert a detached CAdES into enveloping

Take a look to the ASN.1 structure of SignedData node of a CAdES signature as defined in RFC 3852 -CMS

CMS 签名信息

SignedData includes encapContentInfo that contains the original data to sign for enveloping signatures but is not present in a detached signature. Since SignedData is signed, it is not possible to add the original data to convert a detached into enveloping

Note: The correct term is enveloping , because signature wraps the data. An enveloped signature would be embedded into the data

adapted from http://bouncy-castle.1462172.n4.nabble.com/Add-signed-content-to-detached-signatures-td1467150.html

    public static byte[] attach(byte[] originalData, byte[] detached) throws IOException {
        try (ASN1InputStream in = new ASN1InputStream(detached);) {
            BERSequence seqContentData = (BERSequence) in.readObject();

            ContentInfo contentInfo = ContentInfo.getInstance(seqContentData);
            SignedData sdDetached = new SignedData((ASN1Sequence) contentInfo.getContent());
            ContentInfo encapContentInfo = new ContentInfo(CMSObjectIdentifiers.data, new BEROctetString(originalData));

            SignedData sdAttached = new SignedData(
                    sdDetached.getVersion(),
                    sdDetached.getDigestAlgorithms(), 
                    encapContentInfo, 
                    sdDetached.getCertificates(), 
                    sdDetached.getCRLs(), 
                    sdDetached.getSignerInfos());
            ContentInfo contentInfoAttached = new ContentInfo(PKCSObjectIdentifiers.signedData, sdAttached);
            return contentInfoAttached.getEncoded();
        }
    } 

tested with BC 1.64

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM