10

I want to sign a file content with certificate in java.

With terminal and openssl, I can do this :

openssl smime -sign -in nosign.mobileconfig -out signed.mobileconfig -signer server.crt -inkey server.key -certfile cacert.crt -outform der -nodetach

server.crt and .key are the files to sign, and I think I understand the cacert.crt is embedded inside the out content.

finally, I have a file signed and trusted.

In Java, I can't use openssl (don't want to launch openssl command) so, I have to sign it with a lib.

To do that, I use Bouncy Castle (version 1.53)

here is my code :

    byte[] profile = ...; // I can have it also in String

    // the certificate in -certfile
    FileInputStream inputStream = new FileInputStream("src/main/resources/cacert.crt"); 

    byte[] caCertificate = ByteStreams.toByteArray(inputStream);

    // the certificate to sign : server.crt, embedded in p12
    X509Certificate serverCertificate = (X509Certificate) this.keyStore.getCertificate("1");

    // Private key is the server.key
    ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(this.privateKey);

    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
            new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha1Signer, serverCertificate));

    // the embedded certificate : cacert.crt, but  I don't know if it is good to do that this way
    X509CertificateHolder holder = new X509CertificateHolder(caCertificate);

    generator.addCertificate(holder);

    CMSProcessableByteArray bytes = new CMSProcessableByteArray(profile);
    CMSSignedData signedData = generator.generate(bytes, true);

    System.out.println("signedData : \n" + signedData.getEncoded());

Can you help me to have the good signed data please ? Thanks !

EDIT : I've got an error at

    X509CertificateHolder holder = new X509CertificateHolder(caCertificate);

java.io.IOException: unknown tag 13 encountered

zarghol
  • 478
  • 5
  • 19
  • Did you read this tutorial https://docs.oracle.com/javase/tutorial/security/apisign/step3.html – Mr_Thorynque Dec 09 '15 at 10:02
  • What is your problem/question? Are you getting any error messages or something? – JimmyB Dec 09 '15 at 10:02
  • I have a error at X509CertificateHolder holder = new X509CertificateHolder(caCertificate); java.io.IOException: unknown tag 13 encountered I check the cacert and it is well formed.. – zarghol Dec 09 '15 at 10:20

1 Answers1

8

The CA certificate file is obviously in PEM (ASCII) format. The constructor for X509CertificateHolder needs the BER/DER (binary) encoding of the certificate.

You can convert it by adding this:

PEMParser pemParser = new PEMParser(new FileReader("src/main/resources/cacert.crt"));
X509CertificateHolder caCertificate = (X509CertificateHolder) pemParser.readObject();

You should add the signing certificate to the CMS structure as well:

generator.addCertificate(new X509CertificateHolder(serverCertificate.getEncoded()));
Omikron
  • 4,072
  • 1
  • 27
  • 28
  • thanks ! it helps me to embed the cacert.crt, no longer error now. For the record, PEMReader no longer exist, but I can use PEMParser parser = new PEMParser(fileReader); parser.readObject(); My profile is generated, but it is still unrecognized as signed by my OS – zarghol Dec 09 '15 at 12:43
  • @zarghol I have updated my answer. Apart from not adding the signer certificate, your code looks perfectly fine. There are a lot of things you left out, however and there are often issues with p12 files if they are not generated with Java. If you are still running into problems, create a [MCVE](http://stackoverflow.com/help/mcve). – Omikron Dec 09 '15 at 15:27
  • I used generator.addCertificate((X509CertificateHolder) parser.readObject()); and it works, since my comment 3hours ago, but, it works now, it is recognized as signed ! I'll try some change, but it works globally. Thanks for your help ! – zarghol Dec 09 '15 at 16:00