Search code examples
proguardjava.security

How to fix Proguard removes java.security code


I am using java.security.PublicKey in my project

However, when I enable proguard, I get the following error:

java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String java.security.PublicKey.getAlgorithm()' on a null object reference

After some investigation I found that it falls on

val entry = KeyStore.PrivateKeyEntry(keyPair.private, arrayOf(certificate)) <--- this line
keyStore.setEntry(alias, entry, keyProtection)

How do I make it work?

adding this to the proguard file does not work:

-keep class java.security.** { *; }
-keepclassmembers class java.security.** { *; }
-keep public interface java.security.Key {*;}
-keep public interface java.security.PublicKey {*;}
-keepclassmembers class * implements java.security.PublicKey {
    public <methods>;
}

After even more investigations I found that a more specific line in the constructor of KeyStore.PrivateEntry() is causing the issue

And it is

Certificate[] clonedChain = chain.clone();
clonedChain[0].publicKey is left null

How do I make it clone the public key as well?


Solution

  • The issue was deprecated code.

    I was using deprecated spongycastle code to generate a self signed certificate. The public key in said certificate turned to be null, when on proguard.

    I changed to the following:

    api 'com.madgag.spongycastle:core:1.58.0.0'
    api 'com.madgag.spongycastle:prov:1.58.0.0'
    api 'com.madgag.spongycastle:bcpkix-jdk15on:1.58.0.0'
    api 'com.madgag.spongycastle:bcpg-jdk15on:1.58.0.0'
    

    And then:

    fun KeyPair.toSelfSignedCertificate(principal: String, signatureAlgorithm: String, validity: Int): X509Certificate? {
        val x500Name =  X500Name("CN=$principal")
        val today = Calendar.getInstance()
        val notBefore = today.timeInMillis
        today.add(Calendar.YEAR, validity)
        val notAfter = today.timeInMillis
        val sigGen: ContentSigner = JcaContentSignerBuilder(signatureAlgorithm).build(private)
        val publicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(public.encoded))
        val certGen = X509v3CertificateBuilder(x500Name,
                RSAKeyGenParameterSpec.F4,
                Date(notBefore),
                Date(notAfter),
                x500Name,
                publicKeyInfo)
        val certHolder: X509CertificateHolder = certGen.build(sigGen)
        return JcaX509CertificateConverter().getCertificate(certHolder)
    }
    

    And it worked well.