Android KeyGenParameterSpec.Builder ignoring setCertificateNotBefore and setCertificateNotAfter when not in Secure Hadware
Asked Answered
I

1

0

I've created the following method that creates a KeyPair and logs the Certificate details:

@RequiresApi(api = Build.VERSION_CODES.N)
public void createRSAKeyPairtWithChallenge(final String alias, final String attestationChallenge) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyStoreException, CertificateException, IOException {
    Calendar start = Calendar.getInstance();
    Calendar end = new GregorianCalendar(2025,03,24);
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
    keyPairGenerator.initialize(
            new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_DECRYPT)
                    .setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(1024, RSAKeyGenParameterSpec.F4))
                    .setCertificateNotBefore(start.getTime())
                    .setCertificateNotAfter(end.getTime())
                    .setAttestationChallenge(attestationChallenge.getBytes())
                    .build());
    keyPairGenerator.generateKeyPair();

    KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");

    keyStore.load(null);

    Certificate cert = keyStore.getCertificate(alias);
    Log.d(TAG,cert.toString());
}

When I execute in a device with a Secure Hardware (TEE) it creates the cert as expected, but when I execute in a device whithout TEE or in emulator it logs the following:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1 (0x1)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=Android Keymaster
        Validity
            Not Before: Jan  1 00:00:00 1970 GMT
            Not After : Dec 31 23:59:59 1969 GMT
        Subject: CN=A Keymaster Key
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1024 bit)
                Modulus:
                    00:8c:d1:bf:0e:22:ea:62:ad:e6:6d:9c:41:5c:d6:
                    f1:a1:17:6a:e4:e2:12:f7:45:21:70:ef:c0:c5:d7:
                    18:41:35:9c:42:c4:c6:11:48:0a:2d:97:a4:2a:54:
                    a0:7f:01:61:22:2e:2b:df:76:99:6c:e1:84:b9:ad:
                    f5:97:65:a7:f9:2b:bf:97:32:f8:b1:f2:06:3b:2b:
                    67:cb:ff:28:e4:1b:74:01:47:e9:91:0b:41:ec:17:
                    fe:4a:b4:3a:f5:0c:db:9b:fa:f3:c1:ef:e0:f5:bf:
                    e8:37:f9:b2:23:86:96:c4:50:5d:64:ba:b7:1b:61:
                    3f:65:54:2f:39:9b:d4:98:91
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: 
                Key Encipherment, Data Encipherment
            1.3.6.1.4.1.11129.2.1.17: 
                0b...
.....
....test-cert-challenge..0..=........+L0...1.................H........w.....>......?...
            X509v3 Authority Key Identifier: 
                keyid:D4:0C:10:1B:F8:CD:63:B9:F7:39:52:B5:0E:13:5C:A6:D7:99:93:86

    Signature Algorithm: sha256WithRSAEncryption
         40:79:42:eb:a2:22:e7:e5:95:8f:98:c8:de:35:80:b5:7b:fe:
         20:19:00:39:5b:59:3a:49:e0:10:06:c4:c4:a1:3e:52:69:7a:
         09:7b:39:67:28:3c:6a:94:96:9e:86:72:58:51:d9:96:0e:a8:
         1a:d9:d9:bf:24:6f:79:58:28:a5:1a:7d:14:ae:32:04:9c:e4:
         bf:1b:80:d3:4a:85:c2:e0:ab:b3:2c:b9:10:b2:ad:b2:36:00:
         68:eb:1b:52:85:b6:d0:0c:93:d5:bc:a5:35:1a:0c:02:a6:af:
         86:ee:2c:92:ef:25:5e:56:99:77:4f:72:8a:80:1a:54:33:1f:
         78:98 

As you can see the dates in Not Before and Not After are not as expected.

Does anybody know what could be the reason?

Inchoative answered 19/5, 2020 at 21:29 Comment(0)
H
1

Hy, I tried you're code locally and had the same results as you already told. I also tried to manipulate the start and end dates to get:

java.lang.IllegalArgumentException: certificateNotAfter < certificateNotBefore
        at android.security.keystore.KeyGenParameterSpec.<init>(KeyGenParameterSpec.java:328)
        at android.security.keystore.KeyGenParameterSpec$Builder.build(KeyGenParameterSpec.java:1340)
        at org.chickenhook.binderfuzzy.MainActivity.createRSAKeyPairtWithChallenge(MainActivity.kt:47)
        at org.chickenhook.binderfuzzy.MainActivity.onCreate(MainActivity.kt:28)
        at android.app.Activity.performCreate(Activity.java:7802)
        at android.app.Activity.performCreate(Activity.java:7791)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 

This just tells us that you're params are set correctly and correctly interpreted by the Android OS also on non TEE devices.

Also I checked the Android documentation and found out that not all Keystore implementations may care about start and end date in a "secure manner" (https://developer.android.com/training/articles/keystore).

"Temporal validity interval authorizations are unlikely to be enforced by the secure hardware because it normally doesn't have an independent secure real-time clock. "

This doesn't answer you're question deterministic but tells that not all environments care about time validity because it's just not "secure". So it's better to give no time validity in order to tell there is no security for it rather than to meme validation time that doesn't really help.

Please consider that 23:59:59 1969 etc. means time_t notBefore(time_t)-1 and the 1970 means time_t notAfter=(time_t)0. So I beleve they disabled the validity but it's required that notebefore < notAfter.

However this not a deterministic answer, still searching for documentation explaining this issue in detail :(.

Helminth answered 28/5, 2020 at 21:2 Comment(1)
Your answer confirms what I was suspecting it could be the reason. Thanks for your attention.Inchoative

© 2022 - 2024 — McMap. All rights reserved.