Search code examples
jaropensslsignmanifest.mf

Sign JAR without JRE but with OpenSSL?


Our system has Java and C parts. On the C side, we are signing certain data using command-line scripts calling OpenSSL commands. Now we want to sign some JARs too. We already have established PKI (what is important for this case - private keys are accessible) "on the C side" and we try to avoid duplicating/extending that to the Java side.

What would be an easy way to get the JAR signed for someone who does not want to have JRE (but has OpenSSL)? I.e. I want to create the correct MANIFEST.MF, KEY.SF and KEY.?SA for my JAR. Their format is not complicated and this seems to be doable with some scripting. Has anyone done this before?


Solution

  • Answering own question.

    Format of MANIFEST.MF and KEY.SF is documented by Oracle. Surprisingly, exact content of the signature KEY.?SA (where "KEY" is the keystore alias of the signing key) is not detailed in the "Signature File" section.

    This KEY.RSA (for RSA signatures) can be created by OpenSSL command-line tools in exactly the way jarsigner creates it. Example for RSA signature and SHA256 digest:

    $ openssl smime -sign -noattr -in META-INF/TEST1.SF -outform der -out META-INF/TEST1.RSA -inkey privateKey.pem -signer cert.pem -md sha256
    

    Similarly the signature can be produced with OpenSSL C API. Snap of C code (no error checking):

      /* PKCS7_PARTIAL flag is needed to be able to change the digest from the default value */
      PKCS7 *signed_data = PKCS7_sign(NULL, NULL, NULL, data,
        PKCS7_NOATTR | PKCS7_DETACHED | PKCS7_PARTIAL
      );
    
      digest = EVP_get_digestbyname("sha256");
    
      PKCS7_sign_add_signer(signed_data, signcert, pkey, digest, flags);
    
      PKCS7_final(signed_data, NULL, 0);
    

    Signature created in this way is identical to what jarsigner would have produced.