blob: ad5405df199ce26437f5ac1ee95a00b8dafe1365 [file]
// Copyright 2022, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Static information about tag behaviour.
use crate::{km_err, Error};
use kmr_wire::keymint::{Tag, TagType};
#[cfg(test)]
mod tests;
/// Indicate the allowed use of the tag as a key characteristic.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Characteristic {
/// Tag is a key characteristic that is enforced by KeyMint (at whatever security
/// level the KeyMint implementation is running at), and is visible to KeyMint
/// users (e.g. via GetKeyCharacteristics).
KeyMintEnforced,
/// Tag is a key characteristic that is enforced by KeyMint (at whatever security
/// level the KeyMint implementation is running at), but is not exposed to KeyMint
/// users. If a key has this tag associated with it, all operations on the key
/// must have this tag provided as an operation parameter.
KeyMintHidden,
/// Tag is a key characteristic that is enforced by Keystore.
KeystoreEnforced,
/// Tag is enforced by both KeyMint and Keystore, in different ways.
BothEnforced,
/// Tag is not a key characteristic, either because it only acts as an operation
/// parameter or because it never appears on the API.
NotKeyCharacteristic,
}
/// The set of characteristics that are necessarily enforced by Keystore.
pub const KEYSTORE_ENFORCED_CHARACTERISTICS: &[Tag] = &[
Tag::ActiveDatetime,
Tag::OriginationExpireDatetime,
Tag::UsageExpireDatetime,
Tag::UserId,
Tag::AllowWhileOnBody,
Tag::CreationDatetime,
Tag::MaxBootLevel,
Tag::UnlockedDeviceRequired,
];
/// The set of characteristics that are enforced by KeyMint.
pub const KEYMINT_ENFORCED_CHARACTERISTICS: &[Tag] = &[
Tag::UserSecureId,
Tag::Algorithm,
Tag::EcCurve,
Tag::UserAuthType,
Tag::Origin,
Tag::Purpose,
Tag::BlockMode,
Tag::Digest,
Tag::Padding,
Tag::RsaOaepMgfDigest,
Tag::KeySize,
Tag::MinMacLength,
Tag::MaxUsesPerBoot,
Tag::AuthTimeout,
Tag::OsVersion,
Tag::OsPatchlevel,
Tag::VendorPatchlevel,
Tag::BootPatchlevel,
Tag::RsaPublicExponent,
Tag::CallerNonce,
Tag::BootloaderOnly,
Tag::RollbackResistance,
Tag::EarlyBootOnly,
Tag::NoAuthRequired,
Tag::TrustedUserPresenceRequired,
Tag::TrustedConfirmationRequired,
Tag::StorageKey,
];
/// The set of characteristics that are automatically added by KeyMint on key generation.
pub const AUTO_ADDED_CHARACTERISTICS: &[Tag] =
&[Tag::Origin, Tag::OsVersion, Tag::OsPatchlevel, Tag::VendorPatchlevel, Tag::BootPatchlevel];
/// Indicate the allowed use of the tag as a parameter for an operation.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperationParam {
/// Tag acts as an operation parameter for key generation/import operations.
KeyGenImport,
/// Tag is provided as an explicit argument for a cipher operation, and must
/// match one of the values for this tag in the key characteristics.
CipherExplicitArgOneOf,
/// Tag is provided as a parameter for a cipher operation, and must
/// match one of the values for this tag in the key characteristics.
CipherParamOneOf,
/// Tag is provided as a parameter for a cipher operation, and must
/// exactly match the (single) value for this tag in the key characteristics.
CipherParamExactMatch,
/// Tag is provided as a parameter for a cipher operation, and is not a key
/// characteristic.
CipherParam,
/// Tag is not an operation parameter; this *normally* means that it only acts
/// as a key characteristic (exception: ROOT_OF_TRUST is neither an operation
/// parameter nor a key characteristic).
NotOperationParam,
}
/// Indicate whether the KeyMint user is allowed to specify this tag.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct UserSpecifiable(pub bool);
/// Indicate whether the KeyMint implementation auto-adds this tag as a characteristic to generated
/// or imported keys.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AutoAddedCharacteristic(pub bool);
/// Indicate the lifetime of the value associated with the tag.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueLifetime {
/// Indicates that the value of the tag is communicated to KeyMint from the bootloader, and
/// fixed thereafter.
FixedAtBoot,
/// Indicates that the value of the tag is communicated to KeyMint from the HAL service, and
/// fixed thereafter.
FixedAtStartup,
/// Indicates that the value of the tag varies from key to key, or operation to operation.
Variable,
}
/// Indicate whether a tag provided as an asymmetric key generation/import parameter is
/// required for the production of a certificate or attestation extension.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CertGenParam {
/// Tag not required as a parameter for certificate or extension generation (although its value
/// may appear in the extension as a key characteristic).
///
/// Example: `Tag::KeySize` doesn't affect cert generation (but does appear in any attestation
/// extension).
NotRequired,
/// Tag must be specified as a parameter on key generation in order to get certificate
/// generation.
///
/// Example: `Tag::CertificateNotBefore` must be specified to get a cert.
Required,
/// Tag must be specified as a parameter on key generation in order to get an attestation
/// extension in a generated certificate.
///
/// Example: `Tag::AttestationChallenge` must be specified to get a cert with an attestation
/// extension.
RequiredForAttestation,
/// Tag need not be specified as a parameter on key generation, but if specified it does affect
/// the contents of the generated certificate (not extension).
///
/// Example: `Tag::CertificateSerial` can be omitted, but if supplied it alters the cert.
Optional,
/// Tag need not be specified as a parameter on key generation, but if specified it does affect
/// the contents of the attestation extension.
///
/// Example: `Tag::ResetSinceIdRotation` can be omitted, but if supplied (along with
/// `Tag::IncludeUniqueId`) then the attestation extension contents are altered.
OptionalForAttestation,
/// Special cases; see individual tags for information.
Special,
}
/// Information about a tag's behaviour.
#[derive(Debug, Clone)]
pub struct Info {
/// Tag name as a string for debug purposes.
pub name: &'static str,
/// Indication of the type of the corresponding value.
pub tt: TagType,
/// Indicates whether the tag value appears in an attestation extension, and as what ASN.1
/// type.
pub ext_asn1_type: Option<&'static str>,
/// Indicates whether the KeyMint user can specify this tag.
pub user_can_specify: UserSpecifiable,
/// Indicates how this tag acts as a key characteristic.
pub characteristic: Characteristic,
/// Indicates how this tag acts as an operation parameter.
pub op_param: OperationParam,
/// Indicates whether KeyMint automatically adds this tag to keys as a key characteristic.
pub keymint_auto_adds: AutoAddedCharacteristic,
/// Indicates the lifetime of the value associated with this tag.
pub lifetime: ValueLifetime,
/// Indicates the role this tag plays in certificate generation for asymmetric keys.
pub cert_gen: CertGenParam,
/// Unique bit index for tracking this tag.
bit_index: usize,
}
/// Global "map" of tags to information about their behaviour.
/// Encoded as an array to avoid allocation; lookup should only be slightly slower
/// for this few entries.
const INFO: [(Tag, Info); 61] = [
(
Tag::Purpose,
Info {
name: "PURPOSE",
tt: TagType::EnumRep,
ext_asn1_type: Some("SET OF INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::CipherExplicitArgOneOf,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 0,
},
),
(
Tag::Algorithm,
Info {
name: "ALGORITHM",
tt: TagType::Enum,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 1,
},
),
(
Tag::KeySize,
Info {
name: "KEY_SIZE",
tt: TagType::Uint,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 2,
},
),
(
Tag::BlockMode,
Info {
name: "BLOCK_MODE",
tt: TagType::EnumRep,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::CipherParamOneOf,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 3,
},
),
(
Tag::Digest,
Info {
name: "DIGEST",
tt: TagType::EnumRep,
ext_asn1_type: Some("SET OF INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::CipherParamOneOf,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 4,
},
),
(
Tag::Padding,
Info {
name: "PADDING",
tt: TagType::EnumRep,
ext_asn1_type: Some("SET OF INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::CipherParamOneOf,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 5,
},
),
(
Tag::CallerNonce,
Info {
name: "CALLER_NONCE",
tt: TagType::Bool,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 6,
},
),
(
Tag::MinMacLength,
Info {
name: "MIN_MAC_LENGTH",
tt: TagType::Uint,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 7,
},
),
(
Tag::EcCurve,
Info {
name: "EC_CURVE",
tt: TagType::Enum,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 8,
},
),
(
Tag::RsaPublicExponent,
Info {
name: "RSA_PUBLIC_EXPONENT",
tt: TagType::Ulong,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 9,
},
),
(
Tag::IncludeUniqueId,
Info {
name: "INCLUDE_UNIQUE_ID",
tt: TagType::Bool,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 10,
},
),
(
Tag::RsaOaepMgfDigest,
Info {
name: "RSA_OAEP_MGF_DIGEST",
tt: TagType::EnumRep,
ext_asn1_type: Some("SET OF INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::CipherParamOneOf,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 11,
},
),
(
Tag::BootloaderOnly,
Info {
name: "BOOTLOADER_ONLY",
tt: TagType::Bool,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(false),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 12,
},
),
(
Tag::RollbackResistance,
Info {
name: "ROLLBACK_RESISTANCE",
tt: TagType::Bool,
ext_asn1_type: Some("NULL"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 13,
},
),
(
Tag::EarlyBootOnly,
Info {
name: "EARLY_BOOT_ONLY",
tt: TagType::Bool,
ext_asn1_type: Some("NULL"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 14,
},
),
(
Tag::ActiveDatetime,
Info {
name: "ACTIVE_DATETIME",
tt: TagType::Date,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeystoreEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 15,
},
),
(
Tag::OriginationExpireDatetime,
Info {
name: "ORIGINATION_EXPIRE_DATETIME",
tt: TagType::Date,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeystoreEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 16,
},
),
(
Tag::UsageExpireDatetime,
Info {
name: "USAGE_EXPIRE_DATETIME",
tt: TagType::Date,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeystoreEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 17,
},
),
(
Tag::MaxUsesPerBoot,
Info {
name: "MAX_USES_PER_BOOT",
tt: TagType::Uint,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 18,
},
),
(
Tag::UsageCountLimit,
Info {
name: "USAGE_COUNT_LIMIT",
tt: TagType::Uint,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::BothEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 19,
},
),
(
Tag::UserId,
Info {
name: "USER_ID",
tt: TagType::Uint,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeystoreEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 20,
},
),
// Value must match userID or secureId in authToken param
(
Tag::UserSecureId,
Info {
name: "USER_SECURE_ID",
tt: TagType::UlongRep,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::CipherExplicitArgOneOf,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 21,
},
),
(
Tag::NoAuthRequired,
Info {
name: "NO_AUTH_REQUIRED",
tt: TagType::Bool,
ext_asn1_type: Some("NULL"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 22,
},
),
(
Tag::UserAuthType,
Info {
name: "USER_AUTH_TYPE",
tt: TagType::Enum,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::CipherParamOneOf,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 23,
},
),
(
Tag::AuthTimeout,
Info {
name: "AUTH_TIMEOUT",
tt: TagType::Uint,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 24,
},
),
(
Tag::AllowWhileOnBody,
Info {
name: "ALLOW_WHILE_ON_BODY",
tt: TagType::Bool,
ext_asn1_type: Some("NULL"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeystoreEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 25,
},
),
(
Tag::TrustedUserPresenceRequired,
Info {
name: "TRUSTED_USER_PRESENCE_REQUIRED",
tt: TagType::Bool,
ext_asn1_type: Some("NULL"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 26,
},
),
(
Tag::TrustedConfirmationRequired,
Info {
name: "TRUSTED_CONFIRMATION_REQUIRED",
tt: TagType::Bool,
ext_asn1_type: Some("NULL"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 27,
},
),
(
Tag::UnlockedDeviceRequired,
Info {
name: "UNLOCKED_DEVICE_REQUIRED",
tt: TagType::Bool,
ext_asn1_type: Some("NULL"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeystoreEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 28,
},
),
(
Tag::ApplicationId,
Info {
name: "APPLICATION_ID",
tt: TagType::Bytes,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintHidden,
op_param: OperationParam::CipherParamExactMatch,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 29,
},
),
(
Tag::ApplicationData,
Info {
name: "APPLICATION_DATA",
tt: TagType::Bytes,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintHidden,
op_param: OperationParam::CipherParamExactMatch,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 30,
},
),
(
Tag::CreationDatetime,
Info {
name: "CREATION_DATETIME",
tt: TagType::Date,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeystoreEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
// If `Tag::IncludeUniqueId` is specified for attestation extension
// generation, then a value for `Tag::CreationDatetime` is needed for
// the calculation of the unique ID value.
cert_gen: CertGenParam::Special,
bit_index: 31,
},
),
(
Tag::Origin,
Info {
name: "ORIGIN",
tt: TagType::Enum,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(false),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(true),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 32,
},
),
(
Tag::RootOfTrust,
Info {
name: "ROOT_OF_TRUST",
tt: TagType::Bytes,
ext_asn1_type: Some("RootOfTrust SEQUENCE"),
user_can_specify: UserSpecifiable(false),
// The root of trust is neither a key characteristic nor an operation parameter.
// The tag exists only to reserve a numeric value that can be used in the
// attestation extension record.
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::NotRequired,
bit_index: 33,
},
),
(
Tag::OsVersion,
Info {
name: "OS_VERSION",
tt: TagType::Uint,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(false),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(true),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::NotRequired,
bit_index: 34,
},
),
(
Tag::OsPatchlevel,
Info {
name: "OS_PATCHLEVEL",
tt: TagType::Uint,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(false),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(true),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::NotRequired,
bit_index: 35,
},
),
(
Tag::UniqueId,
Info {
name: "UNIQUE_ID",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(false),
// The unique ID is neither a key characteristic nor an operation parameter.
//
// The docs claim that tag exists only to reserve a numeric value that can be used in
// the attestation extension record created on key generation.
//
// However, the unique ID gets a field of its own in the top-level KeyDescription
// SEQUENCE; it does not appear in the AuthorizationList SEQUENCE, so this tag value
// should never be seen anywhere.
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::Special,
bit_index: 36,
},
),
(
Tag::AttestationChallenge,
Info {
name: "ATTESTATION_CHALLENGE",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::RequiredForAttestation,
bit_index: 37,
},
),
(
Tag::AttestationApplicationId,
Info {
name: "ATTESTATION_APPLICATION_ID",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::RequiredForAttestation,
bit_index: 38,
},
),
(
Tag::AttestationIdBrand,
Info {
name: "ATTESTATION_ID_BRAND",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 39,
},
),
(
Tag::AttestationIdDevice,
Info {
name: "ATTESTATION_ID_DEVICE",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 40,
},
),
(
Tag::AttestationIdProduct,
Info {
name: "ATTESTATION_ID_PRODUCT",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 41,
},
),
(
Tag::AttestationIdSerial,
Info {
name: "ATTESTATION_ID_SERIAL",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 42,
},
),
(
Tag::AttestationIdImei,
Info {
name: "ATTESTATION_ID_IMEI",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 43,
},
),
(
Tag::AttestationIdSecondImei,
Info {
name: "ATTESTATION_ID_SECOND_IMEI",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 44,
},
),
(
Tag::AttestationIdMeid,
Info {
name: "ATTESTATION_ID_MEID",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 45,
},
),
(
Tag::AttestationIdManufacturer,
Info {
name: "ATTESTATION_ID_MANUFACTURER",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 46,
},
),
(
Tag::AttestationIdModel,
Info {
name: "ATTESTATION_ID_MODEL",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 47,
},
),
(
Tag::VendorPatchlevel,
Info {
name: "VENDOR_PATCHLEVEL",
tt: TagType::Uint,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(false),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(true),
lifetime: ValueLifetime::FixedAtStartup,
cert_gen: CertGenParam::NotRequired,
bit_index: 48,
},
),
(
Tag::BootPatchlevel,
Info {
name: "BOOT_PATCHLEVEL",
tt: TagType::Uint,
ext_asn1_type: Some("INTEGER"),
user_can_specify: UserSpecifiable(false),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(true),
lifetime: ValueLifetime::FixedAtBoot,
cert_gen: CertGenParam::NotRequired,
bit_index: 49,
},
),
(
Tag::DeviceUniqueAttestation,
Info {
name: "DEVICE_UNIQUE_ATTESTATION",
tt: TagType::Bool,
ext_asn1_type: Some("NULL"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
// Device unique attestation does not affect the contents of the `tbsCertificate`,
// but it does change the chain used to sign the resulting certificate.
cert_gen: CertGenParam::Special,
bit_index: 50,
},
),
// A key marked as a storage key cannot be used via most of the KeyMint API. Instead, it
// can be passed to `convertStorageKeyToEphemeral` to convert it to an ephemeral key.
(
Tag::StorageKey,
Info {
name: "STORAGE_KEY",
tt: TagType::Bool,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeyMintEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 51,
},
),
// Can only be user-specified if CALLER_NONCE set in key characteristics.
(
Tag::Nonce,
Info {
name: "NONCE",
tt: TagType::Bytes,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::CipherParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 52,
},
),
(
Tag::MacLength,
Info {
name: "MAC_LENGTH",
tt: TagType::Uint,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::CipherParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 53,
},
),
(
Tag::ResetSinceIdRotation,
Info {
name: "RESET_SINCE_ID_ROTATION",
tt: TagType::Bool,
ext_asn1_type: Some("part of UniqueID"),
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::OptionalForAttestation,
bit_index: 54,
},
),
// Default to 1 if not present
(
Tag::CertificateSerial,
Info {
name: "CERTIFICATE_SERIAL",
tt: TagType::Bignum,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::Optional,
bit_index: 55,
},
),
// Default to "CN=Android Keystore Key" if not present
(
Tag::CertificateSubject,
Info {
name: "CERTIFICATE_SUBJECT",
tt: TagType::Bytes,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::Optional,
bit_index: 56,
},
),
(
Tag::CertificateNotBefore,
Info {
name: "CERTIFICATE_NOT_BEFORE",
tt: TagType::Date,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::Required,
bit_index: 57,
},
),
(
Tag::CertificateNotAfter,
Info {
name: "CERTIFICATE_NOT_AFTER",
tt: TagType::Date,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::KeyGenImport,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::Required,
bit_index: 58,
},
),
(
Tag::MaxBootLevel,
Info {
name: "MAX_BOOT_LEVEL",
tt: TagType::Uint,
ext_asn1_type: None,
user_can_specify: UserSpecifiable(true),
characteristic: Characteristic::KeystoreEnforced,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::Variable,
cert_gen: CertGenParam::NotRequired,
bit_index: 59,
},
),
(
Tag::ModuleHash,
Info {
name: "MODULE_HASH",
tt: TagType::Bytes,
ext_asn1_type: Some("OCTET STRING"),
user_can_specify: UserSpecifiable(false),
// The module hash is neither a key characteristic nor an operation parameter.
// The tag exists only to reserve a numeric value that can be used in the
// attestation extension record.
characteristic: Characteristic::NotKeyCharacteristic,
op_param: OperationParam::NotOperationParam,
keymint_auto_adds: AutoAddedCharacteristic(false),
lifetime: ValueLifetime::FixedAtStartup,
cert_gen: CertGenParam::NotRequired,
bit_index: 60,
},
),
];
/// Return behaviour information about the specified tag.
pub fn info(tag: Tag) -> Result<&'static Info, Error> {
for (t, info) in &INFO {
if tag == *t {
return Ok(info);
}
}
Err(km_err!(InvalidTag, "unknown tag {:?}", tag))
}
/// Indicate whether a tag is allowed to have multiple values.
#[inline]
pub fn multivalued(tag: Tag) -> bool {
matches!(
kmr_wire::keymint::tag_type(tag),
TagType::EnumRep | TagType::UintRep | TagType::UlongRep
)
}
/// Tracker for observed tag values.
#[derive(Default)]
pub struct DuplicateTagChecker(u64);
impl DuplicateTagChecker {
/// Add the given tag to the set of seen tags, failing if the tag
/// has already been observed (and is not multivalued).
pub fn add(&mut self, tag: Tag) -> Result<(), Error> {
let bit_idx = info(tag)?.bit_index;
let bit_mask = 0x01u64 << bit_idx;
if !multivalued(tag) && (self.0 & bit_mask) != 0 {
return Err(km_err!(InvalidKeyBlob, "duplicate value for {:?}", tag));
}
self.0 |= bit_mask;
Ok(())
}
}