Merge changes I28f673b6,I146f7cfd into main am: 39b7af2fcd
Original change: https://android-review.googlesource.com/c/platform/system/security/+/2821841 Change-Id: I1f1ce6604d72d9d3f6109526ac8499bd959167cd Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
37744f6cfd
5 changed files with 436 additions and 35 deletions
|
@ -15,3 +15,11 @@ flag {
|
|||
bug: "307460850"
|
||||
is_fixed_read_only: true
|
||||
}
|
||||
|
||||
flag {
|
||||
name: "import_previously_emulated_keys"
|
||||
namespace: "hardware_backed_security"
|
||||
description: "Include support for importing keys that were previously software-emulated into KeyMint"
|
||||
bug: "283077822"
|
||||
is_fixed_read_only: true
|
||||
}
|
|
@ -37,6 +37,11 @@ use keystore2_crypto::{hmac_sha256, HMAC_SHA256_LEN};
|
|||
/// final zero byte indicates that the blob is not software emulated.)
|
||||
pub const KEYMASTER_BLOB_HW_PREFIX: &[u8] = b"pKMblob\x00";
|
||||
|
||||
/// Magic prefix used by the km_compat C++ code to mark a key that is owned by an
|
||||
/// software emulation device that has been wrapped by km_compat. (The final one
|
||||
/// byte indicates that the blob is software emulated.)
|
||||
pub const KEYMASTER_BLOB_SW_PREFIX: &[u8] = b"pKMblob\x01";
|
||||
|
||||
/// Key data associated with key generation/import.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum KeyImportData<'a> {
|
||||
|
@ -94,7 +99,7 @@ fn wrap_keyblob(keyblob: &[u8]) -> anyhow::Result<Vec<u8>> {
|
|||
|
||||
/// Return an unwrapped version of the provided `keyblob`, which may or may
|
||||
/// not be associated with the software emulation.
|
||||
fn unwrap_keyblob(keyblob: &[u8]) -> KeyBlob {
|
||||
pub fn unwrap_keyblob(keyblob: &[u8]) -> KeyBlob {
|
||||
if !keyblob.starts_with(KEYBLOB_PREFIX) {
|
||||
return KeyBlob::Raw(keyblob);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ use crate::super_key::{KeyBlob, SuperKeyManager};
|
|||
use crate::utils::{
|
||||
check_device_attestation_permissions, check_key_permission,
|
||||
check_unique_id_attestation_permissions, is_device_id_attestation_tag,
|
||||
key_characteristics_to_internal, uid_to_android_user, watchdog as wd,
|
||||
key_characteristics_to_internal, uid_to_android_user, watchdog as wd, UNDEFINED_NOT_AFTER,
|
||||
};
|
||||
use crate::{
|
||||
database::{
|
||||
|
@ -81,10 +81,6 @@ pub struct KeystoreSecurityLevel {
|
|||
// Blob of 32 zeroes used as empty masking key.
|
||||
static ZERO_BLOB_32: &[u8] = &[0; 32];
|
||||
|
||||
// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to GeneralizedTime
|
||||
// 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
|
||||
const UNDEFINED_NOT_AFTER: i64 = 253402300799000i64;
|
||||
|
||||
impl KeystoreSecurityLevel {
|
||||
/// Creates a new security level instance wrapped in a
|
||||
/// BnKeystoreSecurityLevel proxy object. It also enables
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
//! Code for parsing software-backed keyblobs, as emitted by the C++ reference implementation of
|
||||
//! KeyMint.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::ks_err;
|
||||
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
|
||||
|
@ -73,9 +71,135 @@ pub fn export_key(
|
|||
| KeyParameterValue::Algorithm(Algorithm::EC) => KeyFormat::PKCS8,
|
||||
_ => return Err(bloberr!("Unexpected algorithm {:?}", algo_val)),
|
||||
};
|
||||
|
||||
let key_material = match (format, algo_val) {
|
||||
(KeyFormat::PKCS8, KeyParameterValue::Algorithm(Algorithm::EC)) => {
|
||||
// Key material format depends on the curve.
|
||||
let curve = get_tag_value(&combined, Tag::EC_CURVE)
|
||||
.ok_or_else(|| bloberr!("Failed to determine curve for EC key!"))?;
|
||||
match curve {
|
||||
KeyParameterValue::EcCurve(EcCurve::CURVE_25519) => key_material,
|
||||
KeyParameterValue::EcCurve(EcCurve::P_224) => {
|
||||
pkcs8_wrap_nist_key(&key_material, EcCurve::P_224)?
|
||||
}
|
||||
KeyParameterValue::EcCurve(EcCurve::P_256) => {
|
||||
pkcs8_wrap_nist_key(&key_material, EcCurve::P_256)?
|
||||
}
|
||||
KeyParameterValue::EcCurve(EcCurve::P_384) => {
|
||||
pkcs8_wrap_nist_key(&key_material, EcCurve::P_384)?
|
||||
}
|
||||
KeyParameterValue::EcCurve(EcCurve::P_521) => {
|
||||
pkcs8_wrap_nist_key(&key_material, EcCurve::P_521)?
|
||||
}
|
||||
_ => {
|
||||
return Err(bloberr!("Unexpected EC curve {curve:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
(KeyFormat::RAW, _) => key_material,
|
||||
(format, algo) => {
|
||||
return Err(bloberr!(
|
||||
"Unsupported combination of {format:?} format for {algo:?} algorithm"
|
||||
));
|
||||
}
|
||||
};
|
||||
Ok((format, key_material, combined))
|
||||
}
|
||||
|
||||
/// DER-encoded `AlgorithmIdentifier` for a P-224 key.
|
||||
const DER_ALGORITHM_ID_P224: &[u8] = &[
|
||||
0x30, 0x10, // SEQUENCE (AlgorithmIdentifier) {
|
||||
0x06, 0x07, // OBJECT IDENTIFIER (algorithm)
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // 1.2.840.10045.2.1 (ecPublicKey)
|
||||
0x06, 0x05, // OBJECT IDENTIFIER (param)
|
||||
0x2b, 0x81, 0x04, 0x00, 0x21, // 1.3.132.0.33 (secp224r1) }
|
||||
];
|
||||
|
||||
/// DER-encoded `AlgorithmIdentifier` for a P-256 key.
|
||||
const DER_ALGORITHM_ID_P256: &[u8] = &[
|
||||
0x30, 0x13, // SEQUENCE (AlgorithmIdentifier) {
|
||||
0x06, 0x07, // OBJECT IDENTIFIER (algorithm)
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // 1.2.840.10045.2.1 (ecPublicKey)
|
||||
0x06, 0x08, // OBJECT IDENTIFIER (param)
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, // 1.2.840.10045.3.1.7 (secp256r1) }
|
||||
];
|
||||
|
||||
/// DER-encoded `AlgorithmIdentifier` for a P-384 key.
|
||||
const DER_ALGORITHM_ID_P384: &[u8] = &[
|
||||
0x30, 0x10, // SEQUENCE (AlgorithmIdentifier) {
|
||||
0x06, 0x07, // OBJECT IDENTIFIER (algorithm)
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // 1.2.840.10045.2.1 (ecPublicKey)
|
||||
0x06, 0x05, // OBJECT IDENTIFIER (param)
|
||||
0x2b, 0x81, 0x04, 0x00, 0x22, // 1.3.132.0.34 (secp384r1) }
|
||||
];
|
||||
|
||||
/// DER-encoded `AlgorithmIdentifier` for a P-384 key.
|
||||
const DER_ALGORITHM_ID_P521: &[u8] = &[
|
||||
0x30, 0x10, // SEQUENCE (AlgorithmIdentifier) {
|
||||
0x06, 0x07, // OBJECT IDENTIFIER (algorithm)
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, // 1.2.840.10045.2.1 (ecPublicKey)
|
||||
0x06, 0x05, // OBJECT IDENTIFIER (param)
|
||||
0x2b, 0x81, 0x04, 0x00, 0x23, // 1.3.132.0.35 (secp521r1) }
|
||||
];
|
||||
|
||||
/// DER-encoded integer value zero.
|
||||
const DER_VERSION_0: &[u8] = &[
|
||||
0x02, // INTEGER
|
||||
0x01, // len
|
||||
0x00, // value 0
|
||||
];
|
||||
|
||||
/// Given a NIST curve EC key in the form of a DER-encoded `ECPrivateKey`
|
||||
/// (RFC 5915 s3), wrap it in a DER-encoded PKCS#8 format (RFC 5208 s5).
|
||||
fn pkcs8_wrap_nist_key(nist_key: &[u8], curve: EcCurve) -> Result<Vec<u8>> {
|
||||
let der_alg_id = match curve {
|
||||
EcCurve::P_224 => DER_ALGORITHM_ID_P224,
|
||||
EcCurve::P_256 => DER_ALGORITHM_ID_P256,
|
||||
EcCurve::P_384 => DER_ALGORITHM_ID_P384,
|
||||
EcCurve::P_521 => DER_ALGORITHM_ID_P521,
|
||||
_ => return Err(bloberr!("unknown curve {curve:?}")),
|
||||
};
|
||||
|
||||
// Output format is:
|
||||
//
|
||||
// PrivateKeyInfo ::= SEQUENCE {
|
||||
// version INTEGER,
|
||||
// privateKeyAlgorithm AlgorithmIdentifier,
|
||||
// privateKey OCTET STRING,
|
||||
// }
|
||||
//
|
||||
// Start by building the OCTET STRING so we know its length.
|
||||
let mut nist_key_octet_string = Vec::new();
|
||||
nist_key_octet_string.push(0x04); // OCTET STRING
|
||||
add_der_len(&mut nist_key_octet_string, nist_key.len())?;
|
||||
nist_key_octet_string.extend_from_slice(nist_key);
|
||||
|
||||
let mut buf = Vec::new();
|
||||
buf.push(0x30); // SEQUENCE
|
||||
add_der_len(&mut buf, DER_VERSION_0.len() + der_alg_id.len() + nist_key_octet_string.len())?;
|
||||
buf.extend_from_slice(DER_VERSION_0);
|
||||
buf.extend_from_slice(der_alg_id);
|
||||
buf.extend_from_slice(&nist_key_octet_string);
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Append a DER-encoded length value to the given buffer.
|
||||
fn add_der_len(buf: &mut Vec<u8>, len: usize) -> Result<()> {
|
||||
if len <= 0x7f {
|
||||
buf.push(len as u8)
|
||||
} else if len <= 0xff {
|
||||
buf.push(0x81); // One length octet to come
|
||||
buf.push(len as u8);
|
||||
} else if len <= 0xffff {
|
||||
buf.push(0x82); // Two length octets to come
|
||||
buf.push((len >> 8) as u8);
|
||||
buf.push((len & 0xff) as u8);
|
||||
} else {
|
||||
return Err(bloberr!("Unsupported DER length {len}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Plaintext key blob, with key characteristics.
|
||||
#[derive(PartialEq, Eq)]
|
||||
struct KeyBlob {
|
||||
|
@ -809,4 +933,104 @@ mod tests {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_der_len() {
|
||||
let tests = [
|
||||
(0, "00"),
|
||||
(1, "01"),
|
||||
(126, "7e"),
|
||||
(127, "7f"),
|
||||
(128, "8180"),
|
||||
(129, "8181"),
|
||||
(255, "81ff"),
|
||||
(256, "820100"),
|
||||
(257, "820101"),
|
||||
(65535, "82ffff"),
|
||||
];
|
||||
for (input, want) in tests {
|
||||
let mut got = Vec::new();
|
||||
add_der_len(&mut got, input).unwrap();
|
||||
assert_eq!(hex::encode(got), want, " for input length {input}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pkcs8_wrap_key_p256() {
|
||||
// Key material taken from `ec_256_key` in
|
||||
// hardware/interfaces/security/keymint/aidl/vts/function/KeyMintTest.cpp
|
||||
let input = hex::decode(concat!(
|
||||
"3025", // SEQUENCE (ECPrivateKey)
|
||||
"020101", // INTEGER length 1 value 1 (version)
|
||||
"0420", // OCTET STRING (privateKey)
|
||||
"737c2ecd7b8d1940bf2930aa9b4ed3ff",
|
||||
"941eed09366bc03299986481f3a4d859",
|
||||
))
|
||||
.unwrap();
|
||||
let want = hex::decode(concat!(
|
||||
// RFC 5208 s5
|
||||
"3041", // SEQUENCE (PrivateKeyInfo) {
|
||||
"020100", // INTEGER length 1 value 0 (version)
|
||||
"3013", // SEQUENCE length 0x13 (AlgorithmIdentifier) {
|
||||
"0607", // OBJECT IDENTIFIER length 7 (algorithm)
|
||||
"2a8648ce3d0201", // 1.2.840.10045.2.1 (ecPublicKey)
|
||||
"0608", // OBJECT IDENTIFIER length 8 (param)
|
||||
"2a8648ce3d030107", // 1.2.840.10045.3.1.7 (secp256r1)
|
||||
// } end SEQUENCE (AlgorithmIdentifier)
|
||||
"0427", // OCTET STRING (privateKey) holding...
|
||||
"3025", // SEQUENCE (ECPrivateKey)
|
||||
"020101", // INTEGER length 1 value 1 (version)
|
||||
"0420", // OCTET STRING length 0x20 (privateKey)
|
||||
"737c2ecd7b8d1940bf2930aa9b4ed3ff",
|
||||
"941eed09366bc03299986481f3a4d859",
|
||||
// } end SEQUENCE (ECPrivateKey)
|
||||
// } end SEQUENCE (PrivateKeyInfo)
|
||||
))
|
||||
.unwrap();
|
||||
let got = pkcs8_wrap_nist_key(&input, EcCurve::P_256).unwrap();
|
||||
assert_eq!(hex::encode(got), hex::encode(want), " for input {}", hex::encode(input));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pkcs8_wrap_key_p521() {
|
||||
// Key material taken from `ec_521_key` in
|
||||
// hardware/interfaces/security/keymint/aidl/vts/function/KeyMintTest.cpp
|
||||
let input = hex::decode(concat!(
|
||||
"3047", // SEQUENCE length 0xd3 (ECPrivateKey)
|
||||
"020101", // INTEGER length 1 value 1 (version)
|
||||
"0442", // OCTET STRING length 0x42 (privateKey)
|
||||
"0011458c586db5daa92afab03f4fe46a",
|
||||
"a9d9c3ce9a9b7a006a8384bec4c78e8e",
|
||||
"9d18d7d08b5bcfa0e53c75b064ad51c4",
|
||||
"49bae0258d54b94b1e885ded08ed4fb2",
|
||||
"5ce9",
|
||||
// } end SEQUENCE (ECPrivateKey)
|
||||
))
|
||||
.unwrap();
|
||||
let want = hex::decode(concat!(
|
||||
// RFC 5208 s5
|
||||
"3060", // SEQUENCE (PrivateKeyInfo) {
|
||||
"020100", // INTEGER length 1 value 0 (version)
|
||||
"3010", // SEQUENCE length 0x10 (AlgorithmIdentifier) {
|
||||
"0607", // OBJECT IDENTIFIER length 7 (algorithm)
|
||||
"2a8648ce3d0201", // 1.2.840.10045.2.1 (ecPublicKey)
|
||||
"0605", // OBJECT IDENTIFIER length 5 (param)
|
||||
"2b81040023", // 1.3.132.0.35 (secp521r1)
|
||||
// } end SEQUENCE (AlgorithmIdentifier)
|
||||
"0449", // OCTET STRING (privateKey) holding...
|
||||
"3047", // SEQUENCE (ECPrivateKey)
|
||||
"020101", // INTEGER length 1 value 1 (version)
|
||||
"0442", // OCTET STRING length 0x42 (privateKey)
|
||||
"0011458c586db5daa92afab03f4fe46a",
|
||||
"a9d9c3ce9a9b7a006a8384bec4c78e8e",
|
||||
"9d18d7d08b5bcfa0e53c75b064ad51c4",
|
||||
"49bae0258d54b94b1e885ded08ed4fb2",
|
||||
"5ce9",
|
||||
// } end SEQUENCE (ECPrivateKey)
|
||||
// } end SEQUENCE (PrivateKeyInfo)
|
||||
))
|
||||
.unwrap();
|
||||
let got = pkcs8_wrap_nist_key(&input, EcCurve::P_521).unwrap();
|
||||
assert_eq!(hex::encode(got), hex::encode(want), " for input {}", hex::encode(input));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ use crate::{
|
|||
raw_device::KeyMintDevice,
|
||||
};
|
||||
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
|
||||
IKeyMintDevice::IKeyMintDevice, KeyCharacteristics::KeyCharacteristics,
|
||||
KeyParameter::KeyParameter as KmKeyParameter, Tag::Tag,
|
||||
Algorithm::Algorithm, IKeyMintDevice::IKeyMintDevice, KeyCharacteristics::KeyCharacteristics,
|
||||
KeyParameter::KeyParameter as KmKeyParameter, KeyParameterValue::KeyParameterValue, Tag::Tag,
|
||||
};
|
||||
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
|
||||
use android_security_apc::aidl::android::security::apc::{
|
||||
|
@ -49,6 +49,10 @@ use keystore2_apc_compat::{
|
|||
use keystore2_crypto::{aes_gcm_decrypt, aes_gcm_encrypt, ZVec};
|
||||
use std::iter::IntoIterator;
|
||||
|
||||
/// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to GeneralizedTime
|
||||
/// 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
|
||||
pub const UNDEFINED_NOT_AFTER: i64 = 253402300799000i64;
|
||||
|
||||
/// This function uses its namesake in the permission module and in
|
||||
/// combination with with_calling_sid from the binder crate to check
|
||||
/// if the caller has the given keystore permission.
|
||||
|
@ -166,6 +170,119 @@ pub fn key_characteristics_to_internal(
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Import a keyblob that is of the format used by the software C++ KeyMint implementation. After
|
||||
/// successful import, invoke both the `new_blob_handler` and `km_op` closures. On success a tuple
|
||||
/// of the `km_op`s result and the optional upgraded blob is returned.
|
||||
fn import_keyblob_and_perform_op<T, KmOp, NewBlobHandler>(
|
||||
km_dev: &dyn IKeyMintDevice,
|
||||
inner_keyblob: &[u8],
|
||||
upgrade_params: &[KmKeyParameter],
|
||||
km_op: KmOp,
|
||||
new_blob_handler: NewBlobHandler,
|
||||
) -> Result<(T, Option<Vec<u8>>)>
|
||||
where
|
||||
KmOp: Fn(&[u8]) -> Result<T, Error>,
|
||||
NewBlobHandler: FnOnce(&[u8]) -> Result<()>,
|
||||
{
|
||||
let (format, key_material, mut chars) =
|
||||
crate::sw_keyblob::export_key(inner_keyblob, upgrade_params)?;
|
||||
log::debug!(
|
||||
"importing {:?} key material (len={}) with original chars={:?}",
|
||||
format,
|
||||
key_material.len(),
|
||||
chars
|
||||
);
|
||||
let asymmetric = chars.iter().any(|kp| {
|
||||
kp.tag == Tag::ALGORITHM
|
||||
&& (kp.value == KeyParameterValue::Algorithm(Algorithm::RSA)
|
||||
|| (kp.value == KeyParameterValue::Algorithm(Algorithm::EC)))
|
||||
});
|
||||
|
||||
// Combine the characteristics of the previous keyblob with the upgrade parameters (which might
|
||||
// include special things like APPLICATION_ID / APPLICATION_DATA).
|
||||
chars.extend_from_slice(upgrade_params);
|
||||
|
||||
// Now filter out values from the existing keyblob that shouldn't be set on import, either
|
||||
// because they are per-operation parameter or because they are auto-added by KeyMint itself.
|
||||
let mut import_params: Vec<KmKeyParameter> = chars
|
||||
.into_iter()
|
||||
.filter(|kp| {
|
||||
!matches!(
|
||||
kp.tag,
|
||||
Tag::ORIGIN
|
||||
| Tag::ROOT_OF_TRUST
|
||||
| Tag::OS_VERSION
|
||||
| Tag::OS_PATCHLEVEL
|
||||
| Tag::UNIQUE_ID
|
||||
| Tag::ATTESTATION_CHALLENGE
|
||||
| Tag::ATTESTATION_APPLICATION_ID
|
||||
| Tag::ATTESTATION_ID_BRAND
|
||||
| Tag::ATTESTATION_ID_DEVICE
|
||||
| Tag::ATTESTATION_ID_PRODUCT
|
||||
| Tag::ATTESTATION_ID_SERIAL
|
||||
| Tag::ATTESTATION_ID_IMEI
|
||||
| Tag::ATTESTATION_ID_MEID
|
||||
| Tag::ATTESTATION_ID_MANUFACTURER
|
||||
| Tag::ATTESTATION_ID_MODEL
|
||||
| Tag::VENDOR_PATCHLEVEL
|
||||
| Tag::BOOT_PATCHLEVEL
|
||||
| Tag::DEVICE_UNIQUE_ATTESTATION
|
||||
| Tag::ATTESTATION_ID_SECOND_IMEI
|
||||
| Tag::NONCE
|
||||
| Tag::MAC_LENGTH
|
||||
| Tag::CERTIFICATE_SERIAL
|
||||
| Tag::CERTIFICATE_SUBJECT
|
||||
| Tag::CERTIFICATE_NOT_BEFORE
|
||||
| Tag::CERTIFICATE_NOT_AFTER
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Now that any previous values have been removed, add any additional parameters that needed for
|
||||
// import. In particular, if we are generating/importing an asymmetric key, we need to make sure
|
||||
// that NOT_BEFORE and NOT_AFTER are present.
|
||||
if asymmetric {
|
||||
import_params.push(KmKeyParameter {
|
||||
tag: Tag::CERTIFICATE_NOT_BEFORE,
|
||||
value: KeyParameterValue::DateTime(0),
|
||||
});
|
||||
import_params.push(KmKeyParameter {
|
||||
tag: Tag::CERTIFICATE_NOT_AFTER,
|
||||
value: KeyParameterValue::DateTime(UNDEFINED_NOT_AFTER),
|
||||
});
|
||||
}
|
||||
log::debug!("import parameters={import_params:?}");
|
||||
|
||||
let creation_result = {
|
||||
let _wp = watchdog::watch_millis(
|
||||
"In utils::import_keyblob_and_perform_op: calling importKey.",
|
||||
500,
|
||||
);
|
||||
map_km_error(km_dev.importKey(&import_params, format, &key_material, None))
|
||||
}
|
||||
.context(ks_err!("Upgrade failed."))?;
|
||||
|
||||
// Note that the importKey operation will produce key characteristics that may be different
|
||||
// than are already stored in Keystore's SQL database. In particular, the KeyMint
|
||||
// implementation will now mark the key as `Origin::IMPORTED` not `Origin::GENERATED`, and
|
||||
// the security level for characteristics will now be `TRUSTED_ENVIRONMENT` not `SOFTWARE`.
|
||||
//
|
||||
// However, the DB metadata still accurately reflects the original origin of the key, and
|
||||
// so we leave the values as-is (and so any `KeyInfo` retrieved in the Java layer will get the
|
||||
// same results before and after import).
|
||||
//
|
||||
// Note that this also applies to the `USAGE_COUNT_LIMIT` parameter -- if the key has already
|
||||
// been used, then the DB version of the parameter will be (and will continue to be) lower
|
||||
// than the original count bound to the keyblob. This means that Keystore's policing of
|
||||
// usage counts will continue where it left off.
|
||||
|
||||
new_blob_handler(&creation_result.keyBlob).context(ks_err!("calling new_blob_handler."))?;
|
||||
|
||||
km_op(&creation_result.keyBlob)
|
||||
.map(|v| (v, Some(creation_result.keyBlob)))
|
||||
.context(ks_err!("Calling km_op after upgrade."))
|
||||
}
|
||||
|
||||
/// Upgrade a keyblob then invoke both the `new_blob_handler` and the `km_op` closures. On success
|
||||
/// a tuple of the `km_op`s result and the optional upgraded blob is returned.
|
||||
fn upgrade_keyblob_and_perform_op<T, KmOp, NewBlobHandler>(
|
||||
|
@ -221,33 +338,84 @@ where
|
|||
km_op,
|
||||
new_blob_handler,
|
||||
),
|
||||
// Some devices have been known to upgrade their Keymaster device to be a KeyMint
|
||||
// device with a new release of Android. If this is the case, then any pre-upgrade
|
||||
// keyblobs will have the km_compat prefix attached to them.
|
||||
//
|
||||
// This prefix gets stripped by the km_compat layer when used pre-upgrade, but after
|
||||
// the upgrade the keyblob will be passed as-is to the KeyMint device, which probably
|
||||
// won't expect to see the km_compat prefix.
|
||||
//
|
||||
// So if a keyblob:
|
||||
// a) gets rejected with INVALID_KEY_BLOB
|
||||
// b) when sent to a KeyMint (not km_compat) device
|
||||
// c) and has the km_compat magic prefix
|
||||
// d) and was not a software-emulated key pre-upgrade
|
||||
// then strip the prefix and attempt a key upgrade.
|
||||
Err(Error::Km(ErrorCode::INVALID_KEY_BLOB))
|
||||
if km_dev_version >= KeyMintDevice::KEY_MINT_V1
|
||||
&& key_blob.starts_with(km_compat::KEYMASTER_BLOB_HW_PREFIX) =>
|
||||
if km_dev_version >= KeyMintDevice::KEY_MINT_V1 =>
|
||||
{
|
||||
log::info!("found apparent km_compat(Keymaster) blob, attempt strip-and-upgrade");
|
||||
let inner_keyblob = &key_blob[km_compat::KEYMASTER_BLOB_HW_PREFIX.len()..];
|
||||
upgrade_keyblob_and_perform_op(
|
||||
km_dev,
|
||||
inner_keyblob,
|
||||
upgrade_params,
|
||||
km_op,
|
||||
new_blob_handler,
|
||||
)
|
||||
// A KeyMint (not Keymaster via km_compat) device says that this is an invalid keyblob.
|
||||
//
|
||||
// This may be because the keyblob was created before an Android upgrade, and as part of
|
||||
// the device upgrade the underlying Keymaster/KeyMint implementation has been upgraded.
|
||||
//
|
||||
// If that's the case, there are three possible scenarios:
|
||||
if key_blob.starts_with(km_compat::KEYMASTER_BLOB_HW_PREFIX) {
|
||||
// 1) The keyblob was created in hardware by the km_compat C++ code, using a prior
|
||||
// Keymaster implementation, and wrapped.
|
||||
//
|
||||
// In this case, the keyblob will have the km_compat magic prefix, including the
|
||||
// marker that indicates that this was a hardware-backed key.
|
||||
//
|
||||
// The inner keyblob should still be recognized by the hardware implementation, so
|
||||
// strip the prefix and attempt a key upgrade.
|
||||
log::info!(
|
||||
"found apparent km_compat(Keymaster) HW blob, attempt strip-and-upgrade"
|
||||
);
|
||||
let inner_keyblob = &key_blob[km_compat::KEYMASTER_BLOB_HW_PREFIX.len()..];
|
||||
upgrade_keyblob_and_perform_op(
|
||||
km_dev,
|
||||
inner_keyblob,
|
||||
upgrade_params,
|
||||
km_op,
|
||||
new_blob_handler,
|
||||
)
|
||||
} else if keystore2_flags::import_previously_emulated_keys()
|
||||
&& key_blob.starts_with(km_compat::KEYMASTER_BLOB_SW_PREFIX)
|
||||
{
|
||||
// 2) The keyblob was created in software by the km_compat C++ code because a prior
|
||||
// Keymaster implementation did not support ECDH (which was only added in KeyMint).
|
||||
//
|
||||
// In this case, the keyblob with have the km_compat magic prefix, but with the
|
||||
// marker that indicates that this was a software-emulated key.
|
||||
//
|
||||
// The inner keyblob should be in the format produced by the C++ reference
|
||||
// implementation of KeyMint. Extract the key material and import it into the
|
||||
// current KeyMint device.
|
||||
log::info!("found apparent km_compat(Keymaster) SW blob, attempt strip-and-import");
|
||||
let inner_keyblob = &key_blob[km_compat::KEYMASTER_BLOB_SW_PREFIX.len()..];
|
||||
import_keyblob_and_perform_op(
|
||||
km_dev,
|
||||
inner_keyblob,
|
||||
upgrade_params,
|
||||
km_op,
|
||||
new_blob_handler,
|
||||
)
|
||||
} else if let (true, km_compat::KeyBlob::Wrapped(inner_keyblob)) = (
|
||||
keystore2_flags::import_previously_emulated_keys(),
|
||||
km_compat::unwrap_keyblob(key_blob),
|
||||
) {
|
||||
// 3) The keyblob was created in software by km_compat.rs because a prior KeyMint
|
||||
// implementation did not support a feature present in the current KeyMint spec.
|
||||
// (For example, a curve 25519 key created when the device only supported KeyMint
|
||||
// v1).
|
||||
//
|
||||
// In this case, the keyblob with have the km_compat.rs wrapper around it to
|
||||
// indicate that this was a software-emulated key.
|
||||
//
|
||||
// The inner keyblob should be in the format produced by the C++ reference
|
||||
// implementation of KeyMint. Extract the key material and import it into the
|
||||
// current KeyMint device.
|
||||
log::info!(
|
||||
"found apparent km_compat.rs(KeyMint) SW blob, attempt strip-and-import"
|
||||
);
|
||||
import_keyblob_and_perform_op(
|
||||
km_dev,
|
||||
inner_keyblob,
|
||||
upgrade_params,
|
||||
km_op,
|
||||
new_blob_handler,
|
||||
)
|
||||
} else {
|
||||
Err(Error::Km(ErrorCode::INVALID_KEY_BLOB)).context(ks_err!("Calling km_op"))
|
||||
}
|
||||
}
|
||||
r => r.map(|v| (v, None)).context(ks_err!("Calling km_op.")),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue