TLDR: apksigner sign -key rsa_der.key -cert x509.cert app.apk
fails when directly using a certificate and key generated by openssl
which are not stored in a keystore.
I am wanting to get apksigner working for use on our CI server, however, I'd prefer not to generate a java keystore file on each build, or store one securely between builds.
The app is a cordova app, built with cordova build android --release
.
I did the following to create a certificate and key in the expected formats. I have tried a variety of ways of generating the certificate and key, the following is the most terse. (nb. passphrase.txt contains a large password, all commands executed on a Fedora 29 machine)
$ openssl req -x509 -days 9125 -newkey rsa:4096 -keyout rsa_pem.key -out x509.cert # generate certificate & key
$ openssl pkcs8 -topk8 -inform PEM -outform DER -in rsa_pem.key -out rsa_der.key -passout file:passphrase.txt # convert key over to DER formatted pkcs8, as required by apksigner
Attempting to use the certificate and key to sign an apk fails:
$ apksigner sign -key rsa_der.key --key-pass file:passphrase.txt -cert x509.cert app.apk
Failed to load signer "signer #1"
java.security.spec.InvalidKeySpecException: Failed to load PKCS #8 encoded private key from ./rsa_der.key
at com.android.apksigner.ApkSignerTool$SignerParams.loadPrivateKeyAndCertsFromFiles(ApkSignerTool.java:911)
at com.android.apksigner.ApkSignerTool$SignerParams.loadPrivateKeyAndCerts(ApkSignerTool.java:665)
at com.android.apksigner.ApkSignerTool$SignerParams.access$500(ApkSignerTool.java:615)
at com.android.apksigner.ApkSignerTool.sign(ApkSignerTool.java:269)
at com.android.apksigner.ApkSignerTool.main(ApkSignerTool.java:89)
Caused by: java.security.spec.InvalidKeySpecException: Not an RSA, EC, or DSA private key
at com.android.apksigner.ApkSignerTool$SignerParams.loadPkcs8EncodedPrivateKey(ApkSignerTool.java:968)
at com.android.apksigner.ApkSignerTool$SignerParams.loadPrivateKeyAndCertsFromFiles(ApkSignerTool.java:909)
... 4 more
As stated above, I'd prefer to not create and delete a keystore on every build, or need to store it between builds.
What am I doing wrong?
In this particular case, it ended up being the key length (I think), and using a file based passphrase.
The following worked for us:
openssl req -x509 -days 9125 -newkey rsa:1024 -nodes -keyout key.pem -out certificate_x509.pem
openssl pkcs8 -topk8 -outform DER -in key.pem -inform PEM -out key.pk8 -nocrypt
apksigner sign --key key.pk8 --cert certificate_x509.pem app.apk
As this lacks a passphrase on the private key it is somewhat less secure.