Android KeyGenParameterSpec.Builder 当不在安全硬件中时忽略 setCertificateNotBefore 和 setCertificateNotAfter
Android KeyGenParameterSpec.Builder ignoring setCertificateNotBefore and setCertificateNotAfter when not in Secure Hadware
我创建了以下创建密钥对并记录证书详细信息的方法:
@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());
}
当我在带有安全硬件 (TEE) 的设备中执行时,它会按预期创建证书,但是当我在没有 TEE 的设备或模拟器中执行时,它会记录以下内容:
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
如您所见,Not Before 和 Not After 中的日期与预期不符。
有人知道可能是什么原因吗?
嗨,
我试过你是本地代码,结果和你已经说过的一样。我还尝试操纵开始和结束日期以获得:
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)
这只是告诉我们您的参数设置正确并且 Android OS 在非 TEE 设备上也能正确解释。
我还检查了 Android 文档,发现并非所有 Keystore 实现都可能关心 "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. "
这并没有回答你的问题是确定性的,而是告诉你并不是所有的环境都关心时间有效性,因为它不是 "secure"。因此,最好不要提供时间有效性,以表明它没有安全性,而不是提供没有真正帮助的模因验证时间。
请考虑 23:59:59 1969 等意味着 time_t notBefore(time_t)-1 而 1970 意味着 time_t notAfter=(time_t) 0。所以我相信他们禁用了有效性,但需要 notebefore < notAfter.
但这不是一个确定性的答案,仍在搜索详细解释此问题的文档:(.
我创建了以下创建密钥对并记录证书详细信息的方法:
@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());
}
当我在带有安全硬件 (TEE) 的设备中执行时,它会按预期创建证书,但是当我在没有 TEE 的设备或模拟器中执行时,它会记录以下内容:
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
如您所见,Not Before 和 Not After 中的日期与预期不符。
有人知道可能是什么原因吗?
嗨, 我试过你是本地代码,结果和你已经说过的一样。我还尝试操纵开始和结束日期以获得:
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)
这只是告诉我们您的参数设置正确并且 Android OS 在非 TEE 设备上也能正确解释。
我还检查了 Android 文档,发现并非所有 Keystore 实现都可能关心 "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. "
这并没有回答你的问题是确定性的,而是告诉你并不是所有的环境都关心时间有效性,因为它不是 "secure"。因此,最好不要提供时间有效性,以表明它没有安全性,而不是提供没有真正帮助的模因验证时间。
请考虑 23:59:59 1969 等意味着 time_t notBefore(time_t)-1 而 1970 意味着 time_t notAfter=(time_t) 0。所以我相信他们禁用了有效性,但需要 notebefore < notAfter.
但这不是一个确定性的答案,仍在搜索详细解释此问题的文档:(.