fix(certgen): omit attestation extension when no challenge provided
AOSP KeyMint only includes the attestation extension (OID 1.3.6.1.4.1.11129.2.1.17) when ATTESTATION_CHALLENGE is present. Without a challenge, generateKey produces a plain self-signed cert. Our code unconditionally added the extension, which behavioral probes detect by generating a key without a challenge and checking for the OID. Fixes both the Rust native-certgen and BouncyCastle paths. Also skips AAID computation when no challenge is provided, matching keystore2 security_level.rs:457 behavior.
This commit is contained in:
+3
-2
@@ -708,7 +708,8 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
|
|
||||||
val attestVersion = AndroidDeviceUtils.getAttestVersion(securityLevel)
|
val attestVersion = AndroidDeviceUtils.getAttestVersion(securityLevel)
|
||||||
val keymasterVersion = AndroidDeviceUtils.getKeymasterVersion(securityLevel)
|
val keymasterVersion = AndroidDeviceUtils.getKeymasterVersion(securityLevel)
|
||||||
val appId = AttestationBuilder.createApplicationId(callingUid)
|
val hasChallenge = params.attestationChallenge != null
|
||||||
|
val appId = if (hasChallenge) AttestationBuilder.createApplicationId(callingUid) else null
|
||||||
|
|
||||||
val config = CertGenConfig(
|
val config = CertGenConfig(
|
||||||
algorithm = params.algorithm,
|
algorithm = params.algorithm,
|
||||||
@@ -734,7 +735,7 @@ class KeyMintSecurityLevelInterceptor(
|
|||||||
bootKey = AndroidDeviceUtils.bootKey,
|
bootKey = AndroidDeviceUtils.bootKey,
|
||||||
bootHash = AndroidDeviceUtils.bootHash,
|
bootHash = AndroidDeviceUtils.bootHash,
|
||||||
creationDatetime = System.currentTimeMillis(),
|
creationDatetime = System.currentTimeMillis(),
|
||||||
attestationApplicationId = appId.octets,
|
attestationApplicationId = appId?.octets ?: ByteArray(0),
|
||||||
moduleHash = if (attestVersion >= 400) AndroidDeviceUtils.moduleHash else null,
|
moduleHash = if (attestVersion >= 400) AndroidDeviceUtils.moduleHash else null,
|
||||||
idBrand = params.brand,
|
idBrand = params.brand,
|
||||||
idDevice = params.device,
|
idDevice = params.device,
|
||||||
|
|||||||
@@ -238,10 +238,11 @@ object CertificateGenerator {
|
|||||||
if (keyUsageBits != 0) {
|
if (keyUsageBits != 0) {
|
||||||
builder.addExtension(Extension.keyUsage, true, KeyUsage(keyUsageBits))
|
builder.addExtension(Extension.keyUsage, true, KeyUsage(keyUsageBits))
|
||||||
}
|
}
|
||||||
// Add our custom, simulated attestation extension.
|
if (params.attestationChallenge != null) {
|
||||||
builder.addExtension(
|
builder.addExtension(
|
||||||
AttestationBuilder.buildAttestationExtension(params, uid, securityLevel)
|
AttestationBuilder.buildAttestationExtension(params, uid, securityLevel)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val signerAlgorithm =
|
val signerAlgorithm =
|
||||||
when (signingKeyPair.private.algorithm) {
|
when (signingKeyPair.private.algorithm) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const OID_KEY_USAGE: &[u64] = &[2, 5, 29, 15];
|
|||||||
|
|
||||||
pub fn build_certificate_chain(
|
pub fn build_certificate_chain(
|
||||||
key_pair: &GeneratedKeyPair,
|
key_pair: &GeneratedKeyPair,
|
||||||
attestation_ext_der: &[u8],
|
attestation_ext_der: Option<&[u8]>,
|
||||||
keybox: &ParsedKeybox,
|
keybox: &ParsedKeybox,
|
||||||
params: &CertGenParams,
|
params: &CertGenParams,
|
||||||
) -> Result<Vec<Vec<u8>>> {
|
) -> Result<Vec<Vec<u8>>> {
|
||||||
@@ -33,7 +33,7 @@ pub fn build_certificate_chain(
|
|||||||
|
|
||||||
fn build_leaf_cert(
|
fn build_leaf_cert(
|
||||||
key_pair: &GeneratedKeyPair,
|
key_pair: &GeneratedKeyPair,
|
||||||
attestation_ext_der: &[u8],
|
attestation_ext_der: Option<&[u8]>,
|
||||||
keybox: &ParsedKeybox,
|
keybox: &ParsedKeybox,
|
||||||
params: &CertGenParams,
|
params: &CertGenParams,
|
||||||
) -> Result<Vec<u8>> {
|
) -> Result<Vec<u8>> {
|
||||||
@@ -63,7 +63,6 @@ fn build_leaf_cert(
|
|||||||
timestamp_to_datetime(params.cert_not_after)?
|
timestamp_to_datetime(params.cert_not_after)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extensions
|
|
||||||
let extensions_der = build_extensions(attestation_ext_der, ¶ms.purposes)?;
|
let extensions_der = build_extensions(attestation_ext_der, ¶ms.purposes)?;
|
||||||
|
|
||||||
// TBS Certificate
|
// TBS Certificate
|
||||||
@@ -256,19 +255,19 @@ fn extract_rsa_spki(pkcs8_der: &[u8]) -> Result<Vec<u8>> {
|
|||||||
Ok(encode_der_sequence(&[&alg_id, &pub_key_bits]))
|
Ok(encode_der_sequence(&[&alg_id, &pub_key_bits]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_extensions(attestation_ext_der: &[u8], purposes: &[i32]) -> Result<Vec<u8>> {
|
fn build_extensions(attestation_ext_der: Option<&[u8]>, purposes: &[i32]) -> Result<Vec<u8>> {
|
||||||
let mut extensions: Vec<Vec<u8>> = Vec::new();
|
let mut extensions: Vec<Vec<u8>> = Vec::new();
|
||||||
|
|
||||||
// KeyUsage extension (critical)
|
|
||||||
let ku_byte = map_key_usage_byte(purposes);
|
let ku_byte = map_key_usage_byte(purposes);
|
||||||
if ku_byte != 0 {
|
if ku_byte != 0 {
|
||||||
let ku_ext = build_key_usage_extension(ku_byte);
|
let ku_ext = build_key_usage_extension(ku_byte);
|
||||||
extensions.push(ku_ext);
|
extensions.push(ku_ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attestation extension (non-critical)
|
if let Some(attest_der) = attestation_ext_der {
|
||||||
let attest_ext = build_extension(&encode_der_oid(ATTESTATION_OID), false, attestation_ext_der);
|
let attest_ext = build_extension(&encode_der_oid(ATTESTATION_OID), false, attest_der);
|
||||||
extensions.push(attest_ext);
|
extensions.push(attest_ext);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(encode_der_sequence_of(&extensions))
|
Ok(encode_der_sequence_of(&extensions))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,11 +62,14 @@ fn generate_attested_inner(env: &mut JNIEnv, config: &JObject) -> Result<jbyteAr
|
|||||||
|
|
||||||
let keybox = keybox::parse_keybox(¶ms.keybox_cert_chain, ¶ms.keybox_private_key)?;
|
let keybox = keybox::parse_keybox(¶ms.keybox_cert_chain, ¶ms.keybox_private_key)?;
|
||||||
|
|
||||||
let attest_ext = attestation::build_attestation_extension(¶ms)?;
|
let attest_ext = match params.attestation_challenge {
|
||||||
|
Some(_) => Some(attestation::build_attestation_extension(¶ms)?),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
let cert_chain = certbuilder::build_certificate_chain(
|
let cert_chain = certbuilder::build_certificate_chain(
|
||||||
&key_pair,
|
&key_pair,
|
||||||
&attest_ext,
|
attest_ext.as_deref(),
|
||||||
&keybox,
|
&keybox,
|
||||||
¶ms,
|
¶ms,
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user