diff options
author | Selene Huang <seleneh@google.com> | 2020-04-29 04:22:39 -0700 |
---|---|---|
committer | Selene Huang <seleneh@google.com> | 2020-11-17 01:11:42 -0800 |
commit | 31ab404a5e631d0d4cc2b37ce9513fc91d20b18d (patch) | |
tree | caf9125db92c85453b8a073ab96439963ae3bc97 | |
parent | 7bfe3131a61491c511a38f9d21029ff39d3db2c8 (diff) | |
download | platform_hardware_interfaces-31ab404a5e631d0d4cc2b37ce9513fc91d20b18d.tar.gz platform_hardware_interfaces-31ab404a5e631d0d4cc2b37ce9513fc91d20b18d.tar.bz2 platform_hardware_interfaces-31ab404a5e631d0d4cc2b37ce9513fc91d20b18d.zip |
Implement keymint V1 aidl interfaces, service module, and vts tests.
Bug: b/160968242
Test: atest VtsHalKeyMintV1_0TargetTest
Change-Id: I5f9d642f96e262dd567d88f4d582e621d168dceb
81 files changed, 11375 insertions, 12 deletions
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml index ea8d6ad34a..6c8cb580b3 100644 --- a/compatibility_matrices/compatibility_matrix.current.xml +++ b/compatibility_matrices/compatibility_matrix.current.xml @@ -299,6 +299,14 @@ </interface> </hal> <hal format="aidl" optional="true"> + <name>android.hardware.keymint</name> + <interface> + <name>IKeyMintDevice</name> + <instance>default</instance> + <instance>strongbox</instance> + </interface> + </hal> + <hal format="aidl" optional="true"> <name>android.hardware.light</name> <interface> <name>ILights</name> diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp index 52067214c2..56a3ca99e7 100644 --- a/keymaster/aidl/Android.bp +++ b/keymaster/aidl/Android.bp @@ -20,12 +20,3 @@ aidl_interface { "2", ], } - -// This is a reminder that the next version of keymaster should be frozen at -// version "5" to avoid confusion with other versions of this interface. -cc_library { - name: "android.hardware.keymaster-V3-java", -} -cc_library { - name: "android.hardware.keymaster-V4-java", -} diff --git a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl index f1297831c1..00578a4971 100644 --- a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl +++ b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Android Open Source Project + * Copyright (C) 2020 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. diff --git a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl index 4b2f108887..19ea9445a2 100644 --- a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl +++ b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl @@ -16,6 +16,14 @@ package android.hardware.keymaster; + +/** + * Time in milliseconds since some arbitrary point in time. Time must be monotonically increasing, + * and a secure environment's notion of "current time" must not repeat until the Android device + * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied + * by setting the clock to zero during each boot, and then counting time accurately). + */ + @VintfStability parcelable Timestamp { long milliSeconds; diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl index eff9ca6f0c..f0532543c2 100644 --- a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl +++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Android Open Source Project + * Copyright (C) 2020 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. @@ -18,7 +18,6 @@ package android.hardware.keymaster; import android.hardware.keymaster.SecurityLevel; import android.hardware.keymaster.Timestamp; -import android.hardware.keymaster.HardwareAuthenticatorType; /** * VerificationToken instances are used for secure environments to authenticate one another. @@ -40,6 +39,7 @@ parcelable VerificationToken { */ Timestamp timestamp; + /** * SecurityLevel of the secure environment that generated the token. */ diff --git a/keymint/aidl/Android.bp b/keymint/aidl/Android.bp new file mode 100644 index 0000000000..0dae527d40 --- /dev/null +++ b/keymint/aidl/Android.bp @@ -0,0 +1,21 @@ +aidl_interface { + name: "android.hardware.keymint", + vendor_available: true, + srcs: [ + "android/hardware/keymint/*.aidl", + ], + stability: "vintf", + backend: { + java: { + sdk_version: "module_current", + }, + ndk: { + vndk: { + enabled: true, + }, + }, + rust: { + enabled: true, + }, + }, +} diff --git a/keymint/aidl/OWNERS b/keymint/aidl/OWNERS new file mode 100644 index 0000000000..5c79db8eb9 --- /dev/null +++ b/keymint/aidl/OWNERS @@ -0,0 +1,3 @@ +jdanis@google.com +seleneh@google.com +swillden@google.com diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Algorithm.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Algorithm.aidl new file mode 100644 index 0000000000..f51a4128c8 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Algorithm.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum Algorithm { + RSA = 1, + EC = 3, + AES = 32, + TRIPLE_DES = 33, + HMAC = 128, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BeginResult.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BeginResult.aidl new file mode 100644 index 0000000000..2f56be6721 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BeginResult.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable BeginResult { + long challenge; + android.hardware.keymint.KeyParameter[] params; + android.hardware.keymint.IKeyMintOperation operation; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BlockMode.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BlockMode.aidl new file mode 100644 index 0000000000..94de930d6e --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BlockMode.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum BlockMode { + ECB = 1, + CBC = 2, + CTR = 3, + GCM = 32, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ByteArray.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ByteArray.aidl new file mode 100644 index 0000000000..2dc22a970d --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ByteArray.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable ByteArray { + byte[] data; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Certificate.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Certificate.aidl new file mode 100644 index 0000000000..ca55054d72 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Certificate.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable Certificate { + byte[] encodedCertificate; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Digest.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Digest.aidl new file mode 100644 index 0000000000..cc4d2fdffa --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Digest.aidl @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum Digest { + NONE = 0, + MD5 = 1, + SHA1 = 2, + SHA_2_224 = 3, + SHA_2_256 = 4, + SHA_2_384 = 5, + SHA_2_512 = 6, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/EcCurve.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/EcCurve.aidl new file mode 100644 index 0000000000..4e446ad275 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/EcCurve.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum EcCurve { + P_224 = 0, + P_256 = 1, + P_384 = 2, + P_521 = 3, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ErrorCode.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ErrorCode.aidl new file mode 100644 index 0000000000..2679243f34 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ErrorCode.aidl @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum ErrorCode { + OK = 0, + ROOT_OF_TRUST_ALREADY_SET = -1, + UNSUPPORTED_PURPOSE = -2, + INCOMPATIBLE_PURPOSE = -3, + UNSUPPORTED_ALGORITHM = -4, + INCOMPATIBLE_ALGORITHM = -5, + UNSUPPORTED_KEY_SIZE = -6, + UNSUPPORTED_BLOCK_MODE = -7, + INCOMPATIBLE_BLOCK_MODE = -8, + UNSUPPORTED_MAC_LENGTH = -9, + UNSUPPORTED_PADDING_MODE = -10, + INCOMPATIBLE_PADDING_MODE = -11, + UNSUPPORTED_DIGEST = -12, + INCOMPATIBLE_DIGEST = -13, + INVALID_EXPIRATION_TIME = -14, + INVALID_USER_ID = -15, + INVALID_AUTHORIZATION_TIMEOUT = -16, + UNSUPPORTED_KEY_FORMAT = -17, + INCOMPATIBLE_KEY_FORMAT = -18, + UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19, + UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20, + INVALID_INPUT_LENGTH = -21, + KEY_EXPORT_OPTIONS_INVALID = -22, + DELEGATION_NOT_ALLOWED = -23, + KEY_NOT_YET_VALID = -24, + KEY_EXPIRED = -25, + KEY_USER_NOT_AUTHENTICATED = -26, + OUTPUT_PARAMETER_NULL = -27, + INVALID_OPERATION_HANDLE = -28, + INSUFFICIENT_BUFFER_SPACE = -29, + VERIFICATION_FAILED = -30, + TOO_MANY_OPERATIONS = -31, + UNEXPECTED_NULL_POINTER = -32, + INVALID_KEY_BLOB = -33, + IMPORTED_KEY_NOT_ENCRYPTED = -34, + IMPORTED_KEY_DECRYPTION_FAILED = -35, + IMPORTED_KEY_NOT_SIGNED = -36, + IMPORTED_KEY_VERIFICATION_FAILED = -37, + INVALID_ARGUMENT = -38, + UNSUPPORTED_TAG = -39, + INVALID_TAG = -40, + MEMORY_ALLOCATION_FAILED = -41, + IMPORT_PARAMETER_MISMATCH = -44, + SECURE_HW_ACCESS_DENIED = -45, + OPERATION_CANCELLED = -46, + CONCURRENT_ACCESS_CONFLICT = -47, + SECURE_HW_BUSY = -48, + SECURE_HW_COMMUNICATION_FAILED = -49, + UNSUPPORTED_EC_FIELD = -50, + MISSING_NONCE = -51, + INVALID_NONCE = -52, + MISSING_MAC_LENGTH = -53, + KEY_RATE_LIMIT_EXCEEDED = -54, + CALLER_NONCE_PROHIBITED = -55, + KEY_MAX_OPS_EXCEEDED = -56, + INVALID_MAC_LENGTH = -57, + MISSING_MIN_MAC_LENGTH = -58, + UNSUPPORTED_MIN_MAC_LENGTH = -59, + UNSUPPORTED_KDF = -60, + UNSUPPORTED_EC_CURVE = -61, + KEY_REQUIRES_UPGRADE = -62, + ATTESTATION_CHALLENGE_MISSING = -63, + KEYMINT_NOT_CONFIGURED = -64, + ATTESTATION_APPLICATION_ID_MISSING = -65, + CANNOT_ATTEST_IDS = -66, + ROLLBACK_RESISTANCE_UNAVAILABLE = -67, + HARDWARE_TYPE_UNAVAILABLE = -68, + PROOF_OF_PRESENCE_REQUIRED = -69, + CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70, + NO_USER_CONFIRMATION = -71, + DEVICE_LOCKED = -72, + EARLY_BOOT_ENDED = -73, + ATTESTATION_KEYS_NOT_PROVISIONED = -74, + ATTESTATION_IDS_NOT_PROVISIONED = -75, + INVALID_OPERATION = -76, + STORAGE_KEY_UNSUPPORTED = -77, + UNIMPLEMENTED = -100, + VERSION_MISMATCH = -101, + UNKNOWN_ERROR = -1000, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthToken.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthToken.aidl new file mode 100644 index 0000000000..1f5f8e952e --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthToken.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable HardwareAuthToken { + long challenge; + long userId; + long authenticatorId; + android.hardware.keymint.HardwareAuthenticatorType authenticatorType; + android.hardware.keymint.Timestamp timestamp; + byte[] mac; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthenticatorType.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthenticatorType.aidl new file mode 100644 index 0000000000..95ec5c5b45 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthenticatorType.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum HardwareAuthenticatorType { + NONE = 0, + PASSWORD = 1, + FINGERPRINT = 2, + ANY = -1, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintDevice.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintDevice.aidl new file mode 100644 index 0000000000..1616622927 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintDevice.aidl @@ -0,0 +1,33 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +interface IKeyMintDevice { + android.hardware.keymint.KeyMintHardwareInfo getHardwareInfo(); + android.hardware.keymint.VerificationToken verifyAuthorization(in long challenge, in android.hardware.keymint.HardwareAuthToken token); + void addRngEntropy(in byte[] data); + void generateKey(in android.hardware.keymint.KeyParameter[] keyParams, out android.hardware.keymint.ByteArray generatedKeyBlob, out android.hardware.keymint.KeyCharacteristics generatedKeyCharacteristics, out android.hardware.keymint.Certificate[] outCertChain); + void importKey(in android.hardware.keymint.KeyParameter[] inKeyParams, in android.hardware.keymint.KeyFormat inKeyFormat, in byte[] inKeyData, out android.hardware.keymint.ByteArray outImportedKeyBlob, out android.hardware.keymint.KeyCharacteristics outImportedKeyCharacteristics, out android.hardware.keymint.Certificate[] outCertChain); + void importWrappedKey(in byte[] inWrappedKeyData, in byte[] inWrappingKeyBlob, in byte[] inMaskingKey, in android.hardware.keymint.KeyParameter[] inUnwrappingParams, in long inPasswordSid, in long inBiometricSid, out android.hardware.keymint.ByteArray outImportedKeyBlob, out android.hardware.keymint.KeyCharacteristics outImportedKeyCharacteristics); + byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in android.hardware.keymint.KeyParameter[] inUpgradeParams); + void deleteKey(in byte[] inKeyBlob); + void deleteAllKeys(); + void destroyAttestationIds(); + android.hardware.keymint.BeginResult begin(in android.hardware.keymint.KeyPurpose inPurpose, in byte[] inKeyBlob, in android.hardware.keymint.KeyParameter[] inParams, in android.hardware.keymint.HardwareAuthToken inAuthToken); + const int AUTH_TOKEN_MAC_LENGTH = 32; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintOperation.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintOperation.aidl new file mode 100644 index 0000000000..5327345596 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintOperation.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +interface IKeyMintOperation { + int update(in @nullable android.hardware.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable android.hardware.keymint.HardwareAuthToken inAuthToken, in @nullable android.hardware.keymint.VerificationToken inVerificationToken, out @nullable android.hardware.keymint.KeyParameterArray outParams, out @nullable android.hardware.keymint.ByteArray output); + byte[] finish(in @nullable android.hardware.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable byte[] inSignature, in @nullable android.hardware.keymint.HardwareAuthToken authToken, in @nullable android.hardware.keymint.VerificationToken inVerificationToken, out @nullable android.hardware.keymint.KeyParameterArray outParams); + void abort(); +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyCharacteristics.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyCharacteristics.aidl new file mode 100644 index 0000000000..4e73381ad7 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyCharacteristics.aidl @@ -0,0 +1,23 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable KeyCharacteristics { + android.hardware.keymint.KeyParameter[] softwareEnforced; + android.hardware.keymint.KeyParameter[] hardwareEnforced; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyDerivationFunction.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyDerivationFunction.aidl new file mode 100644 index 0000000000..8e2c7747bb --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyDerivationFunction.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum KeyDerivationFunction { + NONE = 0, + RFC5869_SHA256 = 1, + ISO18033_2_KDF1_SHA1 = 2, + ISO18033_2_KDF1_SHA256 = 3, + ISO18033_2_KDF2_SHA1 = 4, + ISO18033_2_KDF2_SHA256 = 5, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyFormat.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyFormat.aidl new file mode 100644 index 0000000000..cfa585d369 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyFormat.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum KeyFormat { + X509 = 0, + PKCS8 = 1, + RAW = 3, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyMintHardwareInfo.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyMintHardwareInfo.aidl new file mode 100644 index 0000000000..8263e6018a --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyMintHardwareInfo.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable KeyMintHardwareInfo { + int versionNumber; + android.hardware.keymint.SecurityLevel securityLevel; + @utf8InCpp String keyMintName; + @utf8InCpp String keyMintAuthorName; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyOrigin.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyOrigin.aidl new file mode 100644 index 0000000000..8d03d2b683 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyOrigin.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum KeyOrigin { + GENERATED = 0, + DERIVED = 1, + IMPORTED = 2, + RESERVED = 3, + SECURELY_IMPORTED = 4, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameter.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameter.aidl new file mode 100644 index 0000000000..923cc6808a --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameter.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable KeyParameter { + android.hardware.keymint.Tag tag; + boolean boolValue; + int integer; + long longInteger; + byte[] blob; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameterArray.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameterArray.aidl new file mode 100644 index 0000000000..b9b978241b --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameterArray.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable KeyParameterArray { + android.hardware.keymint.KeyParameter[] params; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyPurpose.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyPurpose.aidl new file mode 100644 index 0000000000..1aee56a14b --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyPurpose.aidl @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum KeyPurpose { + ENCRYPT = 0, + DECRYPT = 1, + SIGN = 2, + VERIFY = 3, + WRAP_KEY = 5, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/PaddingMode.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/PaddingMode.aidl new file mode 100644 index 0000000000..97f93db3cb --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/PaddingMode.aidl @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum PaddingMode { + NONE = 1, + RSA_OAEP = 2, + RSA_PSS = 3, + RSA_PKCS1_1_5_ENCRYPT = 4, + RSA_PKCS1_1_5_SIGN = 5, + PKCS7 = 64, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/SecurityLevel.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/SecurityLevel.aidl new file mode 100644 index 0000000000..1fb529ded4 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/SecurityLevel.aidl @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum SecurityLevel { + SOFTWARE = 0, + TRUSTED_ENVIRONMENT = 1, + STRONGBOX = 2, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl new file mode 100644 index 0000000000..fba58afa5a --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum Tag { + INVALID = 0, + PURPOSE = 536870913, + ALGORITHM = 268435458, + KEY_SIZE = 805306371, + BLOCK_MODE = 536870916, + DIGEST = 536870917, + PADDING = 536870918, + CALLER_NONCE = 1879048199, + MIN_MAC_LENGTH = 805306376, + EC_CURVE = 268435466, + RSA_PUBLIC_EXPONENT = 1342177480, + INCLUDE_UNIQUE_ID = 1879048394, + BLOB_USAGE_REQUIREMENTS = 268435757, + BOOTLOADER_ONLY = 1879048494, + ROLLBACK_RESISTANCE = 1879048495, + HARDWARE_TYPE = 268435760, + EARLY_BOOT_ONLY = 1879048497, + ACTIVE_DATETIME = 1610613136, + ORIGINATION_EXPIRE_DATETIME = 1610613137, + USAGE_EXPIRE_DATETIME = 1610613138, + MIN_SECONDS_BETWEEN_OPS = 805306771, + MAX_USES_PER_BOOT = 805306772, + USER_ID = 805306869, + USER_SECURE_ID = 1073742326, + NO_AUTH_REQUIRED = 1879048695, + USER_AUTH_TYPE = 268435960, + AUTH_TIMEOUT = 805306873, + ALLOW_WHILE_ON_BODY = 1879048698, + TRUSTED_USER_PRESENCE_REQUIRED = 1879048699, + TRUSTED_CONFIRMATION_REQUIRED = 1879048700, + UNLOCKED_DEVICE_REQUIRED = 1879048701, + APPLICATION_ID = -1879047591, + APPLICATION_DATA = -1879047492, + CREATION_DATETIME = 1610613437, + ORIGIN = 268436158, + ROOT_OF_TRUST = -1879047488, + OS_VERSION = 805307073, + OS_PATCHLEVEL = 805307074, + UNIQUE_ID = -1879047485, + ATTESTATION_CHALLENGE = -1879047484, + ATTESTATION_APPLICATION_ID = -1879047483, + ATTESTATION_ID_BRAND = -1879047482, + ATTESTATION_ID_DEVICE = -1879047481, + ATTESTATION_ID_PRODUCT = -1879047480, + ATTESTATION_ID_SERIAL = -1879047479, + ATTESTATION_ID_IMEI = -1879047478, + ATTESTATION_ID_MEID = -1879047477, + ATTESTATION_ID_MANUFACTURER = -1879047476, + ATTESTATION_ID_MODEL = -1879047475, + VENDOR_PATCHLEVEL = 805307086, + BOOT_PATCHLEVEL = 805307087, + DEVICE_UNIQUE_ATTESTATION = 1879048912, + IDENTITY_CREDENTIAL_KEY = 1879048913, + STORAGE_KEY = 1879048914, + ASSOCIATED_DATA = -1879047192, + NONCE = -1879047191, + MAC_LENGTH = 805307371, + RESET_SINCE_ID_ROTATION = 1879049196, + CONFIRMATION_TOKEN = -1879047187, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/TagType.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/TagType.aidl new file mode 100644 index 0000000000..82144539a7 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/TagType.aidl @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@Backing(type="int") @VintfStability +enum TagType { + INVALID = 0, + ENUM = 268435456, + ENUM_REP = 536870912, + UINT = 805306368, + UINT_REP = 1073741824, + ULONG = 1342177280, + DATE = 1610612736, + BOOL = 1879048192, + BIGNUM = -2147483648, + BYTES = -1879048192, + ULONG_REP = -1610612736, +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Timestamp.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Timestamp.aidl new file mode 100644 index 0000000000..f95d8db828 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Timestamp.aidl @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable Timestamp { + long milliSeconds; +} diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/VerificationToken.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/VerificationToken.aidl new file mode 100644 index 0000000000..7b4989a408 --- /dev/null +++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/VerificationToken.aidl @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL interface (or parcelable). Do not try to +// edit this file. It looks like you are doing that because you have modified +// an AIDL interface in a backward-incompatible way, e.g., deleting a function +// from an interface or a field from a parcelable and it broke the build. That +// breakage is intended. +// +// You must not make a backward incompatible changes to the AIDL files built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.keymint; +@VintfStability +parcelable VerificationToken { + long challenge; + android.hardware.keymint.Timestamp timestamp; + android.hardware.keymint.SecurityLevel securityLevel; + byte[] mac; +} diff --git a/keymint/aidl/android/hardware/keymint/Algorithm.aidl b/keymint/aidl/android/hardware/keymint/Algorithm.aidl new file mode 100644 index 0000000000..8c5d99cf35 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/Algorithm.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * Algorithms provided by IKeyMintDevice implementations. + */ +@VintfStability +@Backing(type="int") +enum Algorithm { + /** Asymmetric algorithms. */ + RSA = 1, + /** 2 removed, do not reuse. */ + EC = 3, + + /** Block cipher algorithms */ + AES = 32, + TRIPLE_DES = 33, + + /** MAC algorithms */ + HMAC = 128, +} diff --git a/keymint/aidl/android/hardware/keymint/BeginResult.aidl b/keymint/aidl/android/hardware/keymint/BeginResult.aidl new file mode 100644 index 0000000000..58eb024427 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/BeginResult.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +import android.hardware.keymint.IKeyMintOperation; +import android.hardware.keymint.KeyParameter; + + +/** + * This is all the results returned by the IKeyMintDevice begin() function. + */ +@VintfStability +parcelable BeginResult { + /* This is the challenge used in verifyAuthorization. It must be a nonce. */ + long challenge; + + /** + * begin() uses this field to return additional data from the operation + * initialization, notably to return the IV or nonce from operations + * that generate an IV or nonce. + */ + KeyParameter[] params; + IKeyMintOperation operation; +} diff --git a/keymint/aidl/android/hardware/keymint/BlockMode.aidl b/keymint/aidl/android/hardware/keymint/BlockMode.aidl new file mode 100644 index 0000000000..b6b36ccf2a --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/BlockMode.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * Symmetric block cipher modes provided by IKeyMintDevice implementations. + */ +@VintfStability +@Backing(type="int") +enum BlockMode { + /* + * Unauthenticated modes, usable only for encryption/decryption and not generally recommended + * except for compatibility with existing other protocols. + */ + ECB = 1, + CBC = 2, + CTR = 3, + + /* + * Authenticated modes, usable for encryption/decryption and signing/verification. Recommended + * over unauthenticated modes for all purposes. + */ + GCM = 32, +} diff --git a/keymint/aidl/android/hardware/keymint/ByteArray.aidl b/keymint/aidl/android/hardware/keymint/ByteArray.aidl new file mode 100644 index 0000000000..18d187e889 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/ByteArray.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * This is used to contain a byte[], to make out parameters of byte arrays + * more convenient for callers. + */ +@VintfStability +parcelable ByteArray { + byte[] data; +} diff --git a/keymint/aidl/android/hardware/keymint/Certificate.aidl b/keymint/aidl/android/hardware/keymint/Certificate.aidl new file mode 100644 index 0000000000..3a70970f30 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/Certificate.aidl @@ -0,0 +1,29 @@ +/* + * Copyright 2020 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. + */ + +package android.hardware.keymint; + +/** + * This encodes the IKeyMintDevice attestation generated certificate. + */ + +@VintfStability +parcelable Certificate { + /** + * EncodedCertificate contains the bytes of a DER-encoded X.509 certificate. + */ + byte[] encodedCertificate; +} diff --git a/keymint/aidl/android/hardware/keymint/Digest.aidl b/keymint/aidl/android/hardware/keymint/Digest.aidl new file mode 100644 index 0000000000..a92ac23209 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/Digest.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * Digests provided by keyMint implementations. + */ +@VintfStability +@Backing(type="int") +enum Digest { + NONE = 0, + MD5 = 1, + SHA1 = 2, + SHA_2_224 = 3, + SHA_2_256 = 4, + SHA_2_384 = 5, + SHA_2_512 = 6, +} diff --git a/keymint/aidl/android/hardware/keymint/EcCurve.aidl b/keymint/aidl/android/hardware/keymint/EcCurve.aidl new file mode 100644 index 0000000000..abd44b406d --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/EcCurve.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * Supported EC curves, used in ECDSA + */ +@VintfStability +@Backing(type="int") +enum EcCurve { + P_224 = 0, + P_256 = 1, + P_384 = 2, + P_521 = 3, +} diff --git a/keymint/aidl/android/hardware/keymint/ErrorCode.aidl b/keymint/aidl/android/hardware/keymint/ErrorCode.aidl new file mode 100644 index 0000000000..2a54954c74 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/ErrorCode.aidl @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * KeyMint error codes. Aidl will return these error codes as service specific + * errors in EX_SERVICE_SPECIFIC. + */ +@VintfStability +@Backing(type="int") +enum ErrorCode { + OK = 0, + ROOT_OF_TRUST_ALREADY_SET = -1, + UNSUPPORTED_PURPOSE = -2, + INCOMPATIBLE_PURPOSE = -3, + UNSUPPORTED_ALGORITHM = -4, + INCOMPATIBLE_ALGORITHM = -5, + UNSUPPORTED_KEY_SIZE = -6, + UNSUPPORTED_BLOCK_MODE = -7, + INCOMPATIBLE_BLOCK_MODE = -8, + UNSUPPORTED_MAC_LENGTH = -9, + UNSUPPORTED_PADDING_MODE = -10, + INCOMPATIBLE_PADDING_MODE = -11, + UNSUPPORTED_DIGEST = -12, + INCOMPATIBLE_DIGEST = -13, + INVALID_EXPIRATION_TIME = -14, + INVALID_USER_ID = -15, + INVALID_AUTHORIZATION_TIMEOUT = -16, + UNSUPPORTED_KEY_FORMAT = -17, + INCOMPATIBLE_KEY_FORMAT = -18, + UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19, /** For PKCS8 & PKCS12 */ + UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20, /** For PKCS8 & PKCS12 */ + INVALID_INPUT_LENGTH = -21, + KEY_EXPORT_OPTIONS_INVALID = -22, + DELEGATION_NOT_ALLOWED = -23, + KEY_NOT_YET_VALID = -24, + KEY_EXPIRED = -25, + KEY_USER_NOT_AUTHENTICATED = -26, + OUTPUT_PARAMETER_NULL = -27, + INVALID_OPERATION_HANDLE = -28, + INSUFFICIENT_BUFFER_SPACE = -29, + VERIFICATION_FAILED = -30, + TOO_MANY_OPERATIONS = -31, + UNEXPECTED_NULL_POINTER = -32, + INVALID_KEY_BLOB = -33, + IMPORTED_KEY_NOT_ENCRYPTED = -34, + IMPORTED_KEY_DECRYPTION_FAILED = -35, + IMPORTED_KEY_NOT_SIGNED = -36, + IMPORTED_KEY_VERIFICATION_FAILED = -37, + INVALID_ARGUMENT = -38, + UNSUPPORTED_TAG = -39, + INVALID_TAG = -40, + MEMORY_ALLOCATION_FAILED = -41, + IMPORT_PARAMETER_MISMATCH = -44, + SECURE_HW_ACCESS_DENIED = -45, + OPERATION_CANCELLED = -46, + CONCURRENT_ACCESS_CONFLICT = -47, + SECURE_HW_BUSY = -48, + SECURE_HW_COMMUNICATION_FAILED = -49, + UNSUPPORTED_EC_FIELD = -50, + MISSING_NONCE = -51, + INVALID_NONCE = -52, + MISSING_MAC_LENGTH = -53, + KEY_RATE_LIMIT_EXCEEDED = -54, + CALLER_NONCE_PROHIBITED = -55, + KEY_MAX_OPS_EXCEEDED = -56, + INVALID_MAC_LENGTH = -57, + MISSING_MIN_MAC_LENGTH = -58, + UNSUPPORTED_MIN_MAC_LENGTH = -59, + UNSUPPORTED_KDF = -60, + UNSUPPORTED_EC_CURVE = -61, + KEY_REQUIRES_UPGRADE = -62, + ATTESTATION_CHALLENGE_MISSING = -63, + KEYMINT_NOT_CONFIGURED = -64, + ATTESTATION_APPLICATION_ID_MISSING = -65, + CANNOT_ATTEST_IDS = -66, + ROLLBACK_RESISTANCE_UNAVAILABLE = -67, + HARDWARE_TYPE_UNAVAILABLE = -68, + PROOF_OF_PRESENCE_REQUIRED = -69, + CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70, + NO_USER_CONFIRMATION = -71, + DEVICE_LOCKED = -72, + EARLY_BOOT_ENDED = -73, + ATTESTATION_KEYS_NOT_PROVISIONED = -74, + ATTESTATION_IDS_NOT_PROVISIONED = -75, + INVALID_OPERATION = -76, + STORAGE_KEY_UNSUPPORTED = -77, + + UNIMPLEMENTED = -100, + VERSION_MISMATCH = -101, + + UNKNOWN_ERROR = -1000, + + // Implementer's namespace for error codes starts at -10000. +} diff --git a/keymint/aidl/android/hardware/keymint/HardwareAuthToken.aidl b/keymint/aidl/android/hardware/keymint/HardwareAuthToken.aidl new file mode 100644 index 0000000000..9b56a2e661 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/HardwareAuthToken.aidl @@ -0,0 +1,84 @@ +/* + * Copyright 2020 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. + */ + +package android.hardware.keymint; + +import android.hardware.keymint.Timestamp; +import android.hardware.keymint.HardwareAuthenticatorType; + +/** + * HardwareAuthToken is used to prove successful user authentication, to unlock the use of a key. + * + * HardwareAuthTokens are produced by other secure environment applications, notably GateKeeper and + * biometric authenticators, in response to successful user authentication events. These tokens are passed to + * begin(), update(), and finish() to prove that authentication occurred. See those methods for + * more details. It is up to the caller to determine which of the generated auth tokens is + * appropriate for a given key operation. + */ +@VintfStability +parcelable HardwareAuthToken { + + /** + * challenge is a value that's used to enable authentication tokens to authorize specific + * events. The primary use case for challenge is to authorize an IKeyMintDevice cryptographic + * operation, for keys that require authentication per operation. See begin() for details. + */ + long challenge; + + /** + * userId is the a "secure" user ID. It is not related to any Android user ID or UID, but is + * created in the Gatekeeper application in the secure environment. + */ + long userId; + + /** + * authenticatorId is the a "secure" user ID. It is not related to any Android user ID or UID, + * but is created in an authentication application in the secure environment, such as the + * Fingerprint application. + */ + long authenticatorId; + + /** + * authenticatorType describes the type of authentication that took place, e.g. password or + * fingerprint. + */ + HardwareAuthenticatorType authenticatorType; + + /** + * timestamp indicates when the user authentication took place, in milliseconds since some + * starting point (generally the most recent device boot) which all of the applications within + * one secure environment must agree upon. This timestamp is used to determine whether or not + * the authentication occurred recently enough to unlock a key (see Tag::AUTH_TIMEOUT). + */ + Timestamp timestamp; + + /** + * MACs are computed with a backward-compatible method, used by Keymaster 3.0, Gatekeeper 1.0 + * and Fingerprint 1.0, as well as pre-treble HALs. + * + * The MAC is Constants::AUTH_TOKEN_MAC_LENGTH bytes in length and is computed as follows: + * + * HMAC_SHA256( + * H, 0 || challenge || user_id || authenticator_id || authenticator_type || timestamp) + * + * where ``||'' represents concatenation, the leading zero is a single byte, and all integers + * are represented as unsigned values, the full width of the type. The challenge, userId and + * authenticatorId values are in machine order, but authenticatorType and timestamp are in + * network order (big-endian). This odd construction is compatible with the hw_auth_token_t + * structure. + */ + byte[] mac; +} diff --git a/keymint/aidl/android/hardware/keymint/HardwareAuthenticatorType.aidl b/keymint/aidl/android/hardware/keymint/HardwareAuthenticatorType.aidl new file mode 100644 index 0000000000..5c25e2f544 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/HardwareAuthenticatorType.aidl @@ -0,0 +1,32 @@ +/* + * Copyright 2020 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. + */ + +package android.hardware.keymint; + +/** + * Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to + * authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for + * authenticating to activate a key. + */ +@VintfStability +@Backing(type="int") +enum HardwareAuthenticatorType { + NONE = 0, + PASSWORD = 1 << 0, + FINGERPRINT = 1 << 1, + // Additional entries must be powers of 2. + ANY = 0xFFFFFFFF, +} diff --git a/keymint/aidl/android/hardware/keymint/IKeyMintDevice.aidl b/keymint/aidl/android/hardware/keymint/IKeyMintDevice.aidl new file mode 100644 index 0000000000..8fbab79600 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/IKeyMintDevice.aidl @@ -0,0 +1,790 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +import android.hardware.keymint.BeginResult; +import android.hardware.keymint.ByteArray; +import android.hardware.keymint.Certificate; +import android.hardware.keymint.HardwareAuthToken; +import android.hardware.keymint.IKeyMintOperation; +import android.hardware.keymint.KeyCharacteristics; +import android.hardware.keymint.KeyFormat; +import android.hardware.keymint.KeyParameter; +import android.hardware.keymint.KeyMintHardwareInfo; +import android.hardware.keymint.KeyPurpose; +import android.hardware.keymint.SecurityLevel; +import android.hardware.keymint.VerificationToken; + +/** + * KeyMint device definition. + * + * == Features == + * + * An IKeyMintDevice provides cryptographic services, including the following categories of + * operations: + * + * o Key generation + * o Import of asymmetric keys + * o Import of raw symmetric keys + * o Asymmetric decryption with appropriate padding modes + * o Asymmetric signing with digesting and appropriate padding modes + * o Symmetric encryption and decryption in appropriate modes, including an AEAD mode + * o Generation and verification of symmetric message authentication codes + * o Attestation to the presence and configuration of asymmetric keys. + * + * Protocol elements, such as purpose, mode and padding, as well as access control constraints, must + * be specified by the caller when keys are generated or imported and must be permanently bound to + * the key, ensuring that the key cannot be used in any other way. + * + * In addition to the list above, IKeyMintDevice implementations must provide one more service + * which is not exposed as an API but used internally: Random number generation. The random number + * generator must be high-quality and must be used for generation of keys, initialization vectors, + * random padding and other elements of secure protocols that require randomness. + * + * == Types of IKeyMintDevices == + * + * All of the operations and storage of key material must occur in a secure environment. Secure + * environments may be either: + * + * 1. Isolated execution environments, such as a separate virtual machine, hypervisor or + * purpose-built trusted execution environment like ARM TrustZone. The isolated environment + * must provide complete separation from the Android kernel and user space (collectively called + * the "non-secure world", or NSW) so that nothing running in the NSW can observe or manipulate + * the results of any computation in the isolated environment. Isolated execution environments + * are identified by the SecurityLevel TRUSTED_ENVIRONMENT. + * + * 2. Completely separate, purpose-built and certified secure CPUs, called "StrongBox" devices. + * Examples of StrongBox devices are embedded Secure Elements (eSE) or on-SoC secure processing + * units (iSE). StrongBox environments are identified by the SecurityLevel STRONGBOX. To + * qualify as a StrongBox, a device must meet the requirements specified in CDD 9.11.2. + * + * == Necessary Primitives == + * + * All IKeyMintDevice implementations must provide support for the following: + * + * o RSA + * + * - TRUSTED_ENVIRONMENT IKeyMintDevices must support 2048, 3072 and 4096-bit keys. + * STRONGBOX IKeyMintDevices must support 2048-bit keys. + * - Public exponent F4 (2^16+1) + * - Unpadded, RSASSA-PSS and RSASSA-PKCS1-v1_5 padding modes for RSA signing + * - TRUSTED_ENVIRONMENT IKeyMintDevices must support MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 + * 384 and SHA-2 512 digest modes for RSA signing. STRONGBOX IKeyMintDevices must support + * SHA-2 256. + * - Unpadded, RSAES-OAEP and RSAES-PKCS1-v1_5 padding modes for RSA encryption. + * + * o ECDSA + * + * - TRUSTED_ENVIRONMENT IKeyMintDevices must support NIST curves P-224, P-256, P-384 and + * P-521. STRONGBOX IKeyMintDevices must support NIST curve P-256. + * - TRUSTED_ENVIRONMENT IKeyMintDevices must support SHA1, SHA-2 224, SHA-2 256, SHA-2 + * 384 and SHA-2 512 digest modes. STRONGBOX IKeyMintDevices must support SHA-2 256. + * + * o AES + * + * - 128 and 256-bit keys + * - CBC, CTR, ECB and GCM modes. The GCM mode must not allow the use of tags smaller than 96 + * bits or nonce lengths other than 96 bits. + * - CBC and ECB modes must support unpadded and PKCS7 padding modes. With no padding CBC and + * ECB-mode operations must fail with ErrorCode::INVALID_INPUT_LENGTH if the input isn't a + * multiple of the AES block size. With PKCS7 padding, GCM and CTR operations must fail with + * ErrorCode::INCOMPATIBLE_PADDING_MODE. + * + * o 3DES + * + * - 168-bit keys. + * - CBC and ECB mode. + + * - CBC and ECB modes must support unpadded and PKCS7 padding modes. With no padding CBC and + * ECB-mode operations must fail with ErrorCode::INVALID_INPUT_LENGTH if the input isn't a + * multiple of the DES block size. + * + * o HMAC + * + * - Any key size that is between 64 and 512 bits (inclusive) and a multiple of 8 must be + * supported. STRONGBOX IKeyMintDevices must not support keys larger than 512 bits. + * - TRUSTED_ENVIRONMENT IKeyMintDevices must support MD-5, SHA1, SHA-2-224, SHA-2-256, + * SHA-2-384 and SHA-2-512. STRONGBOX IKeyMintDevices must support SHA-2-256. + * + * == Key Access Control == + * + * Hardware-based keys that can never be extracted from the device don't provide much security if an + * attacker can use them at will (though they're more secure than keys which can be + * exfiltrated). Therefore, IKeyMintDevice must enforce access controls. + * + * Access controls are defined as an "authorization list" of tag/value pairs. Authorization tags + * are 32-bit integers from the Tag enum, and the values are a variety of types, defined in the + * TagType enum. Some tags may be repeated to specify multiple values. Whether a tag may be + * repeated is specified in the documentation for the tag and in the TagType. When a key is + * created or imported, the caller specifies an authorization list. The IKeyMintDevice must divide + * the caller-provided authorizations into two lists, those it enforces in tee secure zone and + * those enforced in the strongBox hardware. These two lists are returned as the "teeEnforced" + * and "strongboxEnforced" elements of the KeyCharacteristics struct. Note that software enforced + * authorization list entries are not returned because they are not enforced by keymint. The + * IKeyMintDevice must also add the following authorizations to the appropriate list: + * + * o Tag::OS_VERSION + * o Tag::OS_PATCHLEVEL + * o Tag::VENDOR_PATCHLEVEL + * o Tag::BOOT_PATCHLEVEL + * o Tag::ORIGIN + * + * The IKeyMintDevice must ignore unknown tags. + * + * The caller must always provide the current date time in the keyParameter CREATION_DATETIME + * tags. + * + * All authorization tags and their values, both teeEnforced and strongboxEnforced, including + * unknown tags, must be cryptographically bound to the private/secret key material such that any + * modification of the portion of the key blob that contains the authorization list makes it + * impossible for the secure environment to obtain the private/secret key material. The + * recommended approach to meet this requirement is to use the full set of authorization tags + * associated with a key as input to a secure key derivation function used to derive a key that + * is used to encrypt the private/secret key material. + * + * IKeyMintDevice implementations ignore any tags they cannot enforce and do not return them + * in KeyCharacteristics. For example, Tag::ORIGINATION_EXPIRE_DATETIME provides the date and + * time after which a key may not be used to encrypt or sign new messages. Unless the + * IKeyMintDevice has access to a secure source of current date/time information, it is not + * possible for the IKeyMintDevice to enforce this tag. An IKeyMintDevice implementation will + * not rely on the non-secure world's notion of time, because it could be controlled by an + * attacker. Similarly, it cannot rely on GPSr time, even if it has exclusive control of the + * GPSr, because that might be spoofed by attacker RF signals. + * + * IKeyMintDevices do not use or enforce any tags they place in the softwareEnforced + * list. The IKeyMintDevice caller must enforce them, and it is unnecessary to enforce them + * twice. + * + * Some tags must be enforced by the IKeyMintDevice. See the detailed documentation on each Tag + * in Tag.aidl. + * + * == Root of Trust Binding == + * + * IKeyMintDevice keys must be bound to a root of trust, which is a bitstring that must be + * provided to the secure environment (by an unspecified, implementation-defined mechanism) during + * startup, preferably by the bootloader. This bitstring must be cryptographically bound to every + * key managed by the IKeyMintDevice. As above, the recommended mechanism for this cryptographic + * binding is to include the Root of Trust data in the input to the key derivation function used to + * derive a key that is used to encryp the private/secret key material. + * + * The root of trust consists of a bitstring that must be derived from the public key used by + * Verified Boot to verify the signature on the boot image and from the lock state of the + * device. If the public key is changed to allow a different system image to be used or if the + * lock state is changed, then all of the IKeyMintDevice-protected keys created by the previous + * system state must be unusable, unless the previous state is restored. The goal is to increase + * the value of the software-enforced key access controls by making it impossible for an attacker- + * installed operating system to use IKeyMintDevice keys. + * + * == Version Binding == + * + * All keys must also be bound to the operating system and patch level of the system image and the + * patch levels of the vendor image and boot image. This ensures that an attacker who discovers a + * weakness in an old version of the software cannot roll a device back to the vulnerable version + * and use keys created with the newer version. In addition, when a key with a given version and + * patch level is used on a device that has been upgraded to a newer version or patch level, the + * key must be upgraded (See IKeyMintDevice::upgradeKey()) before it can be used, and the previous + * version of the key must be invalidated. In this way, as the device is upgraded, the keys will + * "ratchet" forward along with the device, but any reversion of the device to a previous release + * will cause the keys to be unusable. + * + * This version information must be associated with every key as a set of tag/value pairs in the + * hardwareEnforced authorization list. Tag::OS_VERSION, Tag::OS_PATCHLEVEL, + * Tag::VENDOR_PATCHLEVEL, and Tag::BOOT_PATCHLEVEL must be cryptographically bound to every + * IKeyMintDevice key, as described in the Key Access Control section above. + */ +@VintfStability +interface IKeyMintDevice { + const int AUTH_TOKEN_MAC_LENGTH = 32; + + /** + * @return info which contains information about the underlying IKeyMintDevice hardware, such + * as version number, security level, keyMint name and author name. + */ + KeyMintHardwareInfo getHardwareInfo(); + + /** + * Verify authorizations for another IKeyMintDevice instance. + * + * On systems with both a StrongBox and a TEE IKeyMintDevice instance it is sometimes useful + * to ask the TEE KeyMintDevice to verify authorizations for a key hosted in StrongBox. + * + * For every StrongBox operation, Keystore is required to call this method on the TEE KeyMint, + * passing in the StrongBox key's hardwareEnforced authorization list and the challenge + * returned by StrongBox begin(). Keystore must then pass the VerificationToken to the + * subsequent invocations of StrongBox update() and finish(). + * + * StrongBox implementations must return ErrorCode::UNIMPLEMENTED. + * + * @param the challenge returned by StrongBox's keyMint's begin(). + * + * @param authToken A HardwareAuthToken if needed to authorize key usage. + * + * @return error ErrorCode::OK on success or ErrorCode::UNIMPLEMENTED if the KeyMintDevice is + * a StrongBox. If the IKeyMintDevice cannot verify one or more elements of + * parametersToVerify it must not return an error code, but just omit the unverified + * parameter from the VerificationToken. + * + * @return token the verification token. See VerificationToken in VerificationToken.aidl for + * details. + */ + VerificationToken verifyAuthorization(in long challenge, + in HardwareAuthToken token); + + /** + * Adds entropy to the RNG used by KeyMint. Entropy added through this method must not be the + * only source of entropy used, and a secure mixing function must be used to mix the entropy + * provided by this method with internally-generated entropy. The mixing function must be + * secure in the sense that if any one of the mixing function inputs is provided with any data + * the attacker cannot predict (or control), then the output of the seeded CRNG is + * indistinguishable from random. Thus, if the entropy from any source is good, the output + * must be good. + * + * TODO(seleneh) specify what mixing functions and cprng we allow. + * + * @param data Bytes to be mixed into the CRNG seed. The caller must not provide more than 2 + * KiB of data per invocation. + * + * @return error ErrorCode::OK on success; ErrorCode::INVALID_INPUT_LENGTH if the caller + * provides more than 2 KiB of data. + */ + void addRngEntropy(in byte[] data); + + /** + * Generates a new cryptographic key, specifying associated parameters, which must be + * cryptographically bound to the key. IKeyMintDevice implementations must disallow any use + * of a key in any way inconsistent with the authorizations specified at generation time. With + * respect to parameters that the secure environment cannot enforce, the secure envionment's + * obligation is limited to ensuring that the unenforceable parameters associated with the key + * cannot be modified. In addition, the characteristics returned by generateKey places + * parameters correctly in the tee-enforced and strongbox-enforced lists. + * + * In addition to the parameters provided, generateKey must add the following to the returned + * characteristics. + * + * o Tag::ORIGIN with the value KeyOrigin::GENERATED. + * + * o Tag::BLOB_USAGE_REQUIREMENTS with the appropriate value (see KeyBlobUsageRequirements in + * Tag.aidl). + * + * o Tag::OS_VERSION, Tag::OS_PATCHLEVEL, Tag::VENDOR_PATCHLEVEL and Tag::BOOT_PATCHLEVEL with + * appropriate values. + * + * The parameters provided to generateKey depend on the type of key being generated. This + * section summarizes the necessary and optional tags for each type of key. Tag::ALGORITHM is + * always necessary, to specify the type. + * + * == RSA Keys == + * + * The following parameters are required to generate an RSA key: + * + * o Tag::Key_SIZE specifies the size of the public modulus, in bits. If omitted, generateKey + * must return ErrorCode::UNSUPPORTED_KEY_SIZE. Required values for TEE IKeyMintDevice + * implementations are 1024, 2048, 3072 and 4096. StrongBox IKeyMintDevice implementations + * must support 2048. + * + * o Tag::RSA_PUBLIC_EXPONENT specifies the RSA public exponent value. If omitted, generateKey + * must return ErrorCode::INVALID_ARGUMENT. The values 3 and 65537 must be supported. It is + * recommended to support all prime values up to 2^64. If provided with a non-prime value, + * generateKey must return ErrorCode::INVALID_ARGUMENT. + * + * The following parameters are not necessary to generate a usable RSA key, but generateKey must + * not return an error if they are omitted: + * + * o Tag::PURPOSE specifies allowed purposes. All KeyPurpose values (see KeyPurpose.aidl) + * except AGREE_KEY must be supported for RSA keys. + * + * o Tag::DIGEST specifies digest algorithms that may be used with the new key. TEE + * IKeyMintDevice implementatiosn must support all Digest values (see digest.aidl) for RSA + * keys. StrongBox IKeyMintDevice implementations must support SHA_2_256. + * + * o Tag::PADDING specifies the padding modes that may be used with the new + * key. IKeyMintDevice implementations must support PaddingMode::NONE, + * PaddingMode::RSA_OAEP, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_ENCRYPT and + * PaddingMode::RSA_PKCS1_1_5_SIGN for RSA keys. + * + * == ECDSA Keys == + * + * Either Tag::KEY_SIZE or Tag::EC_CURVE must be provided to generate an ECDSA key. If neither + * is provided, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE. If Tag::KEY_SIZE is + * provided, the possible values are 224, 256, 384 and 521, and must be mapped to Tag::EC_CURVE + * values P_224, P_256, P_384 and P_521, respectively. TEE IKeyMintDevice implementations + * must support all curves. StrongBox implementations must support P_256. + * + * == AES Keys == + * + * Only Tag::KEY_SIZE is required to generate an AES key. If omitted, generateKey must return + * ErrorCode::UNSUPPORTED_KEY_SIZE. 128 and 256-bit key sizes must be supported. + * + * If Tag::BLOCK_MODE is specified with value BlockMode::GCM, then the caller must also provide + * Tag::MIN_MAC_LENGTH. If omitted, generateKey must return ErrorCode::MISSING_MIN_MAC_LENGTH. + * + * + * @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs, + * provided in params. See above for detailed specifications of which tags are required + * for which types of keys. + * + * @return generatedKeyBlob Opaque descriptor of the generated key. The recommended + * implementation strategy is to include an encrypted copy of the key material, wrapped + * in a key unavailable outside secure hardware. + * + * @return generatedKeyCharacteristics Description of the generated key, divided into two sets: + * hardware-enforced and software-enforced. The description here applies equally + * to the key characteristics lists returned by generateKey, importKey and + * importWrappedKey. The characteristics returned by this parameter completely + * describe the type and usage of the specified key. + * + * The rule that IKeyMintDevice implementations must use for deciding whether a + * given tag belongs in the hardware-enforced or software-enforced list is that if + * the meaning of the tag is fully assured by secure hardware, it is hardware + * enforced. Otherwise, it's software enforced. + * + * @return outCertChain If the key is an asymmetric key, and proper keyparameters for + * attestation (such as challenge) is provided, then this parameter will return the + * attestation certificate. If the signing of the attestation certificate is from a + * factory key, additional certificates back to the root attestation certificate will + * also be provided. Clients will need to check root certificate against a known-good + * value. The certificates must be DER-encoded. Caller needs to provide + * CREATION_DATETIME as one of the attestation parameters, otherwise the attestation + * certificate will not contain the creation datetime. The first certificate in the + * vector is the attestation for the generated key itself, the next certificate is + * the key that signs the first certificate, and so forth. The last certificate in + * the chain is the root certificate. If the key is a symmetric key, then no + * certificate will be returned and this variable will return empty. TODO: change + * certificate return to a single certificate and make it nullable b/163604282. + */ + void generateKey(in KeyParameter[] keyParams, out ByteArray generatedKeyBlob, + out KeyCharacteristics generatedKeyCharacteristics, + out Certificate[] outCertChain); + + /** + * Imports key material into an IKeyMintDevice. Key definition parameters and return values + * are the same as for generateKey, with the following exceptions: + * + * o Tag::KEY_SIZE is not necessary in the input parameters. If not provided, the + * IKeyMintDevice must deduce the value from the provided key material and add the tag and + * value to the key characteristics. If Tag::KEY_SIZE is provided, the IKeyMintDevice must + * validate it against the key material. In the event of a mismatch, importKey must return + * ErrorCode::IMPORT_PARAMETER_MISMATCH. + * + * o Tag::RSA_PUBLIC_EXPONENT (for RSA keys only) is not necessary in the input parameters. If + * not provided, the IKeyMintDevice must deduce the value from the provided key material and + * add the tag and value to the key characteristics. If Tag::RSA_PUBLIC_EXPONENT is provided, + * the IKeyMintDevice must validate it against the key material. In the event of a + * mismatch, importKey must return ErrorCode::IMPORT_PARAMETER_MISMATCH. + * + * o Tag::ORIGIN (returned in keyCharacteristics) must have the value KeyOrigin::IMPORTED. + * + * @param inKeyParams Key generation parameters are defined as KeyMintDevice tag/value pairs, + * provided in params. + * + * @param inKeyFormat The format of the key material to import. See KeyFormat in + * keyformat.aidl. + * + * @param inKeyData The key material to import, in the format specified in keyFormat. + * + * @return outImportedKeyBlob descriptor of the imported key. The format of the keyblob will + * be the google specified keyblob format. + * + * @return outImportedKeyCharacteristics Description of the generated key. See the + * keyCharacteristics description in generateKey. + * + * @return outCertChain If the key is an asymmetric key, and proper keyparameters for + * attestation (such as challenge) is provided, then this parameter will return the + * attestation certificate. If the signing of the attestation certificate is from a + * factory key, additional certificates back to the root attestation certificate will + * also be provided. Clients will need to check root certificate against a known-good + * value. The certificates must be DER-encoded. Caller needs to provide + * CREATION_DATETIME as one of the attestation parameters, otherwise the attestation + * certificate will not contain the creation datetime. The first certificate in the + * vector is the attestation for the generated key itself, the next certificate is + * the key that signs the first certificate, and so forth. The last certificate in + * the chain is the root certificate. If the key is a symmetric key, then no + * certificate will be returned and this variable will return empty. + */ + void importKey(in KeyParameter[] inKeyParams, in KeyFormat inKeyFormat, + in byte[] inKeyData, out ByteArray outImportedKeyBlob, + out KeyCharacteristics outImportedKeyCharacteristics, + out Certificate[] outCertChain); + + /** + * Securely imports a key, or key pair, returning a key blob and a description of the imported + * key. + * + * @param inWrappedKeyData The wrapped key material to import. + * TODO(seleneh) Decide if we want the wrapped key in DER-encoded ASN.1 format or CBOR + * format or both. And specify the standarized format. + * + * KeyDescription ::= SEQUENCE( + * keyFormat INTEGER, # Values from KeyFormat enum. + * keyParams AuthorizationList, + * ) + * + * SecureKeyWrapper ::= SEQUENCE( + * version INTEGER, # Contains value 0 + * encryptedTransportKey OCTET_STRING, + * initializationVector OCTET_STRING, + * keyDescription KeyDescription, + * encryptedKey OCTET_STRING, + * tag OCTET_STRING + * ) + * + * Where: + * + * o keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext + * key material. + * o keyParams is the characteristics of the key to be imported (as with generateKey or + * importKey). If the secure import is successful, these characteristics must be + * associated with the key exactly as if the key material had been insecurely imported + * with the IKeyMintDevice::importKey. See attestKey() for documentation of the + * AuthorizationList schema. + * o encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted + * with the wrapping key specified by wrappingKeyBlob. + * o keyDescription is a KeyDescription, above. + * o encryptedKey is the key material of the key to be imported, in format keyFormat, and + * encrypted with encryptedEphemeralKey in AES-GCM mode, with the DER-encoded + * representation of keyDescription provided as additional authenticated data. + * o tag is the tag produced by the AES-GCM encryption of encryptedKey. + * + * So, importWrappedKey does the following: + * + * 1. Get the private key material for wrappingKeyBlob, verifying that the wrapping key has + * purpose KEY_WRAP, padding mode RSA_OAEP, and digest SHA_2_256, returning the + * error INCOMPATIBLE_PURPOSE, INCOMPATIBLE_PADDING_MODE, or INCOMPATIBLE_DIGEST if any + * of those requirements fail. + * 2. Extract the encryptedTransportKey field from the SecureKeyWrapper, and decrypt + * it with the wrapping key. + * 3. XOR the result of step 2 with maskingKey. + * 4. Use the result of step 3 as an AES-GCM key to decrypt encryptedKey, using the encoded + * value of keyDescription as the additional authenticated data. Call the result + * "keyData" for the next step. + * 5. Perform the equivalent of calling importKey(keyParams, keyFormat, keyData), except + * that the origin tag should be set to SECURELY_IMPORTED. + * + * @param inWrappingKeyBlob The opaque key descriptor returned by generateKey() or importKey(). + * This key must have been created with Purpose::WRAP_KEY. + * + * @param inMaskingKey The 32-byte value XOR'd with the transport key in the SecureWrappedKey + * structure. + * + * @param inUnwrappingParams must contain any parameters needed to perform the unwrapping + * operation. For example, if the wrapping key is an AES key the block and padding + * modes must be specified in this argument. + * + * @param inPasswordSid specifies the password secure ID (SID) of the user that owns the key + * being installed. If the authorization list in wrappedKeyData contains a + * Tag::USER_SECURE_IDwith a value that has the HardwareAuthenticatorType::PASSWORD + * bit set, the constructed key must be bound to the SID value provided by this + * argument. If the wrappedKeyData does not contain such a tag and value, this argument + * must be ignored. + * + * @param inBiometricSid specifies the biometric secure ID (SID) of the user that owns the key + * being installed. If the authorization list in wrappedKeyData contains a + * Tag::USER_SECURE_ID with a value that has the HardwareAuthenticatorType::FINGERPRINT + * bit set, the constructed key must be bound to the SID value provided by this argument. + * If the wrappedKeyData does not contain such a tag and value, this argument must be + * ignored. + * + * @return outImportedKeyBlob Opaque descriptor of the imported key. It is recommended that + * the keyBlob contain a copy of the key material, wrapped in a key unavailable outside + * secure hardware. + * + * @return outImportedKeyCharacteristics Description of the generated key. See the description + * of keyCharacteristics parameter in generateKey. + */ + void importWrappedKey(in byte[] inWrappedKeyData, + in byte[] inWrappingKeyBlob, + in byte[] inMaskingKey, + in KeyParameter[] inUnwrappingParams, + in long inPasswordSid, + in long inBiometricSid, + out ByteArray outImportedKeyBlob, + out KeyCharacteristics outImportedKeyCharacteristics); + + /** + * Upgrades an old key blob. Keys can become "old" in two ways: IKeyMintDevice can be + * upgraded to a new version with an incompatible key blob format, or the system can be updated + * to invalidate the OS version (OS_VERSION tag), system patch level (OS_PATCHLEVEL tag), + * vendor patch level (VENDOR_PATCH_LEVEL tag), boot patch level (BOOT_PATCH_LEVEL tag) or + * other, implementation-defined patch level (keyMint implementers are encouraged to extend + * this HAL with a minor version extension to define validatable patch levels for other + * images; tags must be defined in the implementer's namespace, starting at 10000). In either + * case, attempts to use an old key blob with begin() must result in IKeyMintDevice returning + * ErrorCode::KEY_REQUIRES_UPGRADE. The caller must use this method to upgrade the key blob. + * + * The upgradeKey method must examine each version or patch level associated with the key. If + * any one of them is higher than the corresponding current device value upgradeKey() must + * return ErrorCode::INVALID_ARGUMENT. There is one exception: it is always permissible to + * "downgrade" from any OS_VERSION number to OS_VERSION 0. For example, if the key has + * OS_VERSION 080001, it is permisible to upgrade the key if the current system version is + * 080100, because the new version is larger, or if the current system version is 0, because + * upgrades to 0 are always allowed. If the system version were 080000, however, keyMint must + * return ErrorCode::INVALID_ARGUMENT because that value is smaller than 080001. Values other + * than OS_VERSION must never be downgraded. + * + * Note that Keymaster versions 2 and 3 required that the system and boot images have the same + * patch level and OS version. This requirement is relaxed for 4.0::IKeymasterDevice and + * IKeyMintDevice, and the OS version in the boot image footer is no longer used. + * + * @param inKeyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey(); + * + * @param inUpgradeParams A parameter list containing any parameters needed to complete the + * upgrade, including Tag::APPLICATION_ID and Tag::APPLICATION_DATA. + * + * @return A new key blob that references the same key as keyBlobToUpgrade, but is in the new + * format, or has the new version data. + */ + byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in KeyParameter[] inUpgradeParams); + + /** + * Deletes the key, or key pair, associated with the key blob. Calling this function on + * a key with Tag::ROLLBACK_RESISTANCE in its hardware-enforced authorization list must + * render the key permanently unusable. Keys without Tag::ROLLBACK_RESISTANCE may or + * may not be rendered unusable. + * + * @param inKeyBlob The opaque descriptor returned by generateKey() or importKey(); + */ + void deleteKey(in byte[] inKeyBlob); + + /** + * Deletes all keys in the hardware keystore. Used when keystore is reset completely. After + * this function is called all keys with Tag::ROLLBACK_RESISTANCE in their hardware-enforced + * authorization lists must be rendered permanently unusable. Keys without + * Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable. + * + * @return error See the ErrorCode enum. + */ + void deleteAllKeys(); + + /** + * Destroys knowledge of the device's ids. This prevents all device id attestation in the + * future. The destruction must be permanent so that not even a factory reset will restore the + * device ids. + * + * Device id attestation may be provided only if this method is fully implemented, allowing the + * user to permanently disable device id attestation. If this cannot be guaranteed, the device + * must never attest any device ids. + * + * This is a NOP if device id attestation is not supported. + */ + void destroyAttestationIds(); + + /** + * Begins a cryptographic operation using the specified key. If all is well, begin() must + * return ErrorCode::OK and create an operation handle which must be passed to subsequent calls + * to update(), finish() or abort(). + * + * It is critical that each call to begin() be paired with a subsequent call to finish() or + * abort(), to allow the IKeyMintDevice implementation to clean up any internal operation + * state. The caller's failure to do this may leak internal state space or other internal + * resources and may eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it + * runs out of space for operations. Any result other than ErrorCode::OK from begin(), update() + * or finish() implicitly aborts the operation, in which case abort() need not be called (and + * must return ErrorCode::INVALID_OPERATION_HANDLE if called). IKeyMintDevice implementations + * must support 32 concurrent operations. + * + * If Tag::APPLICATION_ID or Tag::APPLICATION_DATA were specified during key generation or + * import, calls to begin must include those tags with the originally-specified values in the + * inParams argument to this method. If not, begin() must return ErrorCode::INVALID_KEY_BLOB. + * + * == Authorization Enforcement == + * + * The following key authorization parameters must be enforced by the IKeyMintDevice secure + * environment if the tags were returned in the "hardwareEnforced" list in the + * KeyCharacteristics. Public key operations, meaning KeyPurpose::ENCRYPT and + * KeyPurpose::VERIFY must be allowed to succeed even if authorization requirements are not met. + * + * -- All Key Types -- + * + * The tags in this section apply to all key types. See below for additional key type-specific + * tags. + * + * o Tag::PURPOSE: The purpose specified in the begin() call must match one of the purposes in + * the key authorizations. If the specified purpose does not match, begin() must return + * ErrorCode::UNSUPPORTED_PURPOSE. + * + * o Tag::ACTIVE_DATETIME can only be enforced if a trusted UTC time source is available. If + * the current date and time is prior to the tag value, begin() must return + * ErrorCode::KEY_NOT_YET_VALID. + * + * o Tag::ORIGINATION_EXPIRE_DATETIME can only be enforced if a trusted UTC time source is + * available. If the current date and time is later than the tag value and the purpose is + * KeyPurpose::ENCRYPT or KeyPurpose::SIGN, begin() must return ErrorCode::KEY_EXPIRED. + * + * o Tag::USAGE_EXPIRE_DATETIME can only be enforced if a trusted UTC time source is + * available. If the current date and time is later than the tag value and the purpose is + * KeyPurpose::DECRYPT or KeyPurpose::VERIFY, begin() must return ErrorCode::KEY_EXPIRED. + * + * o Tag::MAX_USES_PER_BOOT must be compared against a secure counter that tracks the uses of + * the key since boot time. If the count of previous uses exceeds the tag value, begin() must + * return ErrorCode::KEY_MAX_OPS_EXCEEDED. + * + * o Tag::USER_SECURE_ID must be enforced by this method if and only if the key also has + * Tag::AUTH_TIMEOUT (if it does not have Tag::AUTH_TIMEOUT, the Tag::USER_SECURE_ID + * requirement must be enforced by update() and finish()). If the key has both, then this + * method must receive a non-empty HardwareAuthToken in the authToken argument. For the auth + * token to be valid, all of the following have to be true: + * + * o The HMAC field must validate correctly. + * + * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of + * the secure ID values in the token. + * + * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token. + * + * o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be less than + * the current secure timestamp (which is a monotonic timer counting milliseconds since + * boot.) + * + * If any of these conditions are not met, begin() must return + * ErrorCode::KEY_USER_NOT_AUTHENTICATED. + * + * o Tag::CALLER_NONCE allows the caller to specify a nonce or initialization vector (IV). If + * the key doesn't have this tag, but the caller provided Tag::NONCE to this method, + * ErrorCode::CALLER_NONCE_PROHIBITED must be returned. + * + * o Tag::BOOTLOADER_ONLY specifies that only the bootloader may use the key. If this method is + * called with a bootloader-only key after the bootloader has finished executing, it must + * return ErrorCode::INVALID_KEY_BLOB. The mechanism for notifying the IKeyMintDevice that + * the bootloader has finished executing is implementation-defined. + * + * -- RSA Keys -- + * + * All RSA key operations must specify exactly one padding mode in inParams. If unspecified or + * specified more than once, the begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE. + * + * RSA signing and verification operations need a digest, as do RSA encryption and decryption + * operations with OAEP padding mode. For those cases, the caller must specify exactly one + * digest in inParams. If unspecified or specified more than once, begin() must return + * ErrorCode::UNSUPPORTED_DIGEST. + * + * Private key operations (KeyPurpose::DECRYPT and KeyPurpose::SIGN) need authorization of + * digest and padding, which means that the key authorizations need to contain the specified + * values. If not, begin() must return ErrorCode::INCOMPATIBLE_DIGEST or + * ErrorCode::INCOMPATIBLE_PADDING, as appropriate. Public key operations (KeyPurpose::ENCRYPT + * and KeyPurpose::VERIFY) are permitted with unauthorized digest or padding modes. + * + * With the exception of PaddingMode::NONE, all RSA padding modes are applicable only to certain + * purposes. Specifically, PaddingMode::RSA_PKCS1_1_5_SIGN and PaddingMode::RSA_PSS only + * support signing and verification, while PaddingMode::RSA_PKCS1_1_5_ENCRYPT and + * PaddingMode::RSA_OAEP only support encryption and decryption. begin() must return + * ErrorCode::UNSUPPORTED_PADDING_MODE if the specified mode does not support the specified + * purpose. + * + * There are some important interactions between padding modes and digests: + * + * o PaddingMode::NONE indicates that a "raw" RSA operation is performed. If signing or + * verifying, Digest::NONE is specified for the digest. No digest is necessary for unpadded + * encryption or decryption. + * + * o PaddingMode::RSA_PKCS1_1_5_SIGN padding requires a digest. The digest may be Digest::NONE, + * in which case the KeyMint implementation cannot build a proper PKCS#1 v1.5 signature + * structure, because it cannot add the DigestInfo structure. Instead, the IKeyMintDevice + * must construct 0x00 || 0x01 || PS || 0x00 || M, where M is the provided message and PS is a + * random padding string at least eight bytes in length. The size of the RSA key has to be at + * least 11 bytes larger than the message, otherwise begin() must return + * ErrorCode::INVALID_INPUT_LENGTH. + * + * o PaddingMode::RSA_PKCS1_1_1_5_ENCRYPT padding does not require a digest. + * + * o PaddingMode::RSA_PSS padding requires a digest, which may not be Digest::NONE. If + * Digest::NONE is specified, the begin() must return ErrorCode::INCOMPATIBLE_DIGEST. In + * addition, the size of the RSA key must be at least 2 + D bytes larger than the output size + * of the digest, where D is the size of the digest, in bytes. Otherwise begin() must + * return ErrorCode::INCOMPATIBLE_DIGEST. The salt size must be D. + * + * o PaddingMode::RSA_OAEP padding requires a digest, which may not be Digest::NONE. If + * Digest::NONE is specified, begin() must return ErrorCode::INCOMPATIBLE_DIGEST. The OAEP + * mask generation function must be MGF1 and the MGF1 digest must be SHA1, regardless of the + * OAEP digest specified. + * + * -- EC Keys -- + * + * EC key operations must specify exactly one padding mode in inParams. If unspecified or + * specified more than once, begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE. + * + * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which + * means that the key authorizations must contain the specified values. If not, begin() must + * return ErrorCode::INCOMPATIBLE_DIGEST. Public key operations (KeyPurpose::VERIFY) are + * permitted with unauthorized digest or padding. + * + * -- AES Keys -- + * + * AES key operations must specify exactly one block mode (Tag::BLOCK_MODE) and one padding mode + * (Tag::PADDING) in inParams. If either value is unspecified or specified more than once, + * begin() must return ErrorCode::UNSUPPORTED_BLOCK_MODE or + * ErrorCode::UNSUPPORTED_PADDING_MODE. The specified modes must be authorized by the key, + * otherwise begin() must return ErrorCode::INCOMPATIBLE_BLOCK_MODE or + * ErrorCode::INCOMPATIBLE_PADDING_MODE. + * + * If the block mode is BlockMode::GCM, inParams must specify Tag::MAC_LENGTH, and the specified + * value must be a multiple of 8 that is not greater than 128 or less than the value of + * Tag::MIN_MAC_LENGTH in the key authorizations. For MAC lengths greater than 128 or + * non-multiples of 8, begin() must return ErrorCode::UNSUPPORTED_MAC_LENGTH. For values less + * than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH. + * + * If the block mode is BlockMode::GCM or BlockMode::CTR, the specified padding mode must be + * PaddingMode::NONE. For BlockMode::ECB or BlockMode::CBC, the mode may be PaddingMode::NONE + * or PaddingMode::PKCS7. If the padding mode doesn't meet these conditions, begin() must + * return ErrorCode::INCOMPATIBLE_PADDING_MODE. + * + * If the block mode is BlockMode::CBC, BlockMode::CTR, or BlockMode::GCM, an initialization + * vector or nonce is required. In most cases, callers shouldn't provide an IV or nonce and the + * IKeyMintDevice implementation must generate a random IV or nonce and return it via + * Tag::NONCE in outParams. CBC and CTR IVs are 16 bytes. GCM nonces are 12 bytes. If the key + * authorizations contain Tag::CALLER_NONCE, then the caller may provide an IV/nonce with + * Tag::NONCE in inParams. If a nonce is provided when Tag::CALLER_NONCE is not authorized, + * begin() must return ErrorCode::CALLER_NONCE_PROHIBITED. If a nonce is not provided when + * Tag::CALLER_NONCE is authorized, IKeyMintDevice msut generate a random IV/nonce. + * + * -- HMAC keys -- + * + * HMAC key operations must specify Tag::MAC_LENGTH in inParams. The specified value must be a + * multiple of 8 that is not greater than the digest length or less than the value of + * Tag::MIN_MAC_LENGTH in the key authorizations. For MAC lengths greater than the digest + * length or non-multiples of 8, begin() must return ErrorCode::UNSUPPORTED_MAC_LENGTH. For + * values less than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH. + * + * @param inPurpose The purpose of the operation, one of KeyPurpose::ENCRYPT, + * KeyPurpose::DECRYPT, KeyPurpose::SIGN or KeyPurpose::VERIFY. Note that for AEAD + * modes, encryption and decryption imply signing and verification, respectively, but + * must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT. + * + * @param inKeyBlob The opaque key descriptor returned by generateKey() or importKey(). The key + * must have a purpose compatible with purpose and all of its usage requirements must be + * satisfied, or begin() must return an appropriate error code (see above). + * + * @param inParams Additional parameters for the operation. If Tag::APPLICATION_ID or + * Tag::APPLICATION_DATA were provided during generation, they must be provided here, or + * the operation must fail with ErrorCode::INVALID_KEY_BLOB. For operations that require + * a nonce or IV, on keys that were generated with Tag::CALLER_NONCE, inParams may + * contain a tag Tag::NONCE. If Tag::NONCE is provided for a key without + * Tag:CALLER_NONCE, ErrorCode::CALLER_NONCE_PROHIBITED must be returned. + * + * @param inAuthToken Authentication token. Callers that provide no token must set all numeric + * fields to zero and the MAC must be an empty vector. TODO: make this field nullable. + * b/173483024. + * + * @return BeginResult as output, which contains the challenge, KeyParameters which haves + * additional data from the operation initialization, notably to return the IV or nonce + * from operations that generate an IV or nonce, and IKeyMintOperation object pointer + * which is used to perform update(), finish() or abort() operations. + */ + BeginResult begin(in KeyPurpose inPurpose, + in byte[] inKeyBlob, + in KeyParameter[] inParams, + in HardwareAuthToken inAuthToken); +} diff --git a/keymint/aidl/android/hardware/keymint/IKeyMintOperation.aidl b/keymint/aidl/android/hardware/keymint/IKeyMintOperation.aidl new file mode 100644 index 0000000000..1b792961f7 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/IKeyMintOperation.aidl @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +import android.hardware.keymint.ByteArray; +import android.hardware.keymint.HardwareAuthToken; +import android.hardware.keymint.KeyParameter; +import android.hardware.keymint.KeyParameterArray; +import android.hardware.keymint.VerificationToken; + +@VintfStability +interface IKeyMintOperation { + /** + * Provides data to, and possibly receives output from, an ongoing cryptographic operation begun + * with begin(). + * + * If operation is in an invalid state (was aborted or had an error) update() must return + * ErrorCode::INVALID_OPERATION_HANDLE. + * + * To provide more flexibility for buffer handling, implementations of this method have the + * option of consuming less data than was provided. The caller is responsible for looping to + * feed the rest of the data in subsequent calls. The amount of input consumed must be returned + * in the inputConsumed parameter. Implementations must always consume at least one byte, + * unless the operation cannot accept any more; if more than zero bytes are provided and zero + * bytes are consumed, callers must consider this an error and abort the operation. + * TODO(seleneh) update the code to always consume alll the input data. b/168665179. + * + * Implementations may also choose how much data to return, as a result of the update. This is + * only relevant for encryption and decryption operations, because signing and verification + * return no data until finish. It is recommended to return data as early as possible, rather + * than buffer it. + * + * If this method returns an error code other than ErrorCode::OK, the operation is aborted and + * the operation handle must be invalidated. Any future use of the handle, with this method, + * finish, or abort, must return ErrorCode::INVALID_OPERATION_HANDLE. + * + * == Authorization Enforcement == + * + * Key authorization enforcement is performed primarily in begin(). The one exception is the + * case where the key has: + * + * o One or more Tag::USER_SECURE_IDs, and + * + * o Does not have a Tag::AUTH_TIMEOUT + * + * In this case, the key requires an authorization per operation, and the update method must + * receive a non-empty and valid HardwareAuthToken. For the auth token to be valid, all of the + * following has to be true: + * + * o The HMAC field must validate correctly. + * + * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of + * the secure ID values in the token. + * + * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token. + * + * o The challenge field in the auth token must contain the operationHandle + * + * If any of these conditions are not met, update() must return + * ErrorCode::KEY_USER_NOT_AUTHENTICATED. + * + * The caller must provide the auth token on every call to update() and finish(). + * + * -- RSA keys -- + * + * For signing and verification operations with Digest::NONE, this method must accept the entire + * block to be signed or verified in a single update. It may not consume only a portion of the + * block in these cases. However, the caller may choose to provide the data in multiple + * updates, and update() must accept the data this way as well. If the caller provides more + * data to sign than can be used (length of data exceeds RSA key size), update() must return + * ErrorCode::INVALID_INPUT_LENGTH. + * + * -- ECDSA keys -- + * + * For signing and verification operations with Digest::NONE, this method must accept the entire + * block to be signed or verified in a single update. This method may not consume only a + * portion of the block. However, the caller may choose to provide the data in multiple updates + * and update() must accept the data this way as well. If the caller provides more data to sign + * than can be used, the data is silently truncated. (This differs from the handling of excess + * data provided in similar RSA operations. The reason for this is compatibility with legacy + * clients.) + * + * -- AES keys -- + * + * AES GCM mode supports "associated authentication data," provided via the Tag::ASSOCIATED_DATA + * tag in the inParams argument. The associated data may be provided in repeated calls + * (important if the data is too large to send in a single block) but must always precede data + * to be encrypted or decrypted. An update call may receive both associated data and data to + * encrypt/decrypt, but subsequent updates must not include associated data. If the caller + * provides associated data to an update call after a call that includes data to + * encrypt/decrypt, update() must return ErrorCode::INVALID_TAG. + * + * For GCM encryption, the AEAD tag must be appended to the ciphertext by finish(). During + * decryption, the last Tag::MAC_LENGTH bytes of the data provided to the last update call must + * be the AEAD tag. Since a given invocation of update cannot know if it's the last invocation, + * it must process all but the tag length and buffer the possible tag data for processing during + * finish(). + * + * TODO: update() needs to be refactored b/168665179. + * + * @param inParams Additional parameters for the operation. For AEAD modes, this is used to + * specify Tag::ADDITIONAL_DATA. Note that additional data may be provided in multiple + * calls to update(), but only until input data has been provided. + * + * @param input Data to be processed. Note that update() may or may not consume all of the data + * provided. See return value. + * + * @param verificationToken Verification token, used to prove that another IKeymasterDevice HAL + * has verified some parameters, and to deliver the other HAL's current timestamp, if + * needed. If not provided, all fields must be initialized to zero and vectors must be + * empty. + * + * @return error Returns ErrorCode encountered in keymint as service specific errors. See the + * ErrorCode enum in ErrorCode.aidl. + * + * @return int Amount of data that was consumed by update(). If this is less than the + * amount provided, the caller may provide the remainder in a subsequent call to + * update() or finish(). Every call to update must consume at least one byte, unless + * the input is empty, and implementations should consume as much data as reasonably + * possible for each call. + * + * @return outParams returns the updated key parameters from the blob, if needed. + * operation. + * + * @return out variable output The output data, if any. + */ + int update(in @nullable KeyParameterArray inParams, + in @nullable byte[] input, + in @nullable HardwareAuthToken inAuthToken, + in @nullable VerificationToken inVerificationToken, + out @nullable KeyParameterArray outParams, + out @nullable ByteArray output); + + /** + * Finalizes a cryptographic operation begun with begin() and invalidates operation. + * + * This method is the last one called in an operation, so all processed data must be returned. + * + * Whether it completes successfully or returns an error, this method finalizes the operation. + * Any future use of the operation, with finish(), update(), or abort(), must return + * ErrorCode::INVALID_OPERATION_HANDLE. + * + * Signing operations return the signature as the output. Verification operations accept the + * signature in the signature parameter, and return no output. + * + * == Authorization enforcement == + * + * Key authorization enforcement is performed primarily in begin(). The exceptions are + * authorization per operation keys and confirmation-required keys. + * + * Authorization per operation keys are the case where the key has one or more + * Tag::USER_SECURE_IDs, and does not have a Tag::AUTH_TIMEOUT. In this case, the key requires + * an authorization per operation, and the finish method must receive a non-empty and valid + * authToken. For the auth token to be valid, all of the following has to be true: + * + * o The HMAC field must validate correctly. + * + * o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of + * the secure ID values in the token. + * + * o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token. + * + * o The challenge field in the auth token must contain the operation challenge. + * + * If any of these conditions are not met, update() must return + * ErrorCode::KEY_USER_NOT_AUTHENTICATED. + * + * The caller must provide the auth token on every call to update() and finish(). + * + * Confirmation-required keys are keys that were generated with + * Tag::TRUSTED_CONFIRMATION_REQUIRED. For these keys, when doing a signing operation the + * caller must pass a KeyParameter Tag::CONFIRMATION_TOKEN to finish(). Implementations must + * check the confirmation token by computing the 32-byte HMAC-SHA256 over all of the + * to-be-signed data, prefixed with the 18-byte UTF-8 encoded string "confirmation token". If + * the computed value does not match the Tag::CONFIRMATION_TOKEN parameter, finish() must not + * produce a signature and must return ErrorCode::NO_USER_CONFIRMATION. + * + * -- RSA keys -- + * + * Some additional requirements, depending on the padding mode: + * + * o PaddingMode::NONE. For unpadded signing and encryption operations, if the provided data is + * shorter than the key, the data must be zero-padded on the left before + * signing/encryption. If the data is the same length as the key, but numerically larger, + * finish() must return ErrorCode::INVALID_ARGUMENT. For verification and decryption + * operations, the data must be exactly as long as the key. Otherwise, return + * ErrorCode::INVALID_INPUT_LENGTH. + * + * o PaddingMode::RSA_PSS. For PSS-padded signature operations, the PSS salt length must match + * the size of the PSS digest selected. The digest specified with Tag::DIGEST in inputParams + * on begin() must be used as the PSS digest algorithm, MGF1 must be used as the mask + * generation function and SHA1 must be used as the MGF1 digest algorithm. + * + * o PaddingMode::RSA_OAEP. The digest specified with Tag::DIGEST in inputParams on begin is + * used as the OAEP digest algorithm, MGF1 must be used as the mask generation function and + * and SHA1 must be used as the MGF1 digest algorithm. + * + * -- ECDSA keys -- + * + * If the data provided for unpadded signing or verification is too long, truncate it. + * + * -- AES keys -- + * + * Some additional conditions, depending on block mode: + * + * o BlockMode::ECB or BlockMode::CBC. If padding is PaddingMode::NONE and the data length is + * not a multiple of the AES block size, finish() must return + * ErrorCode::INVALID_INPUT_LENGTH. If padding is PaddingMode::PKCS7, pad the data per the + * PKCS#7 specification, including adding an additional padding block if the data is a multiple + * of the block length. + * + * o BlockMode::GCM. During encryption, after processing all plaintext, compute the tag + * (Tag::MAC_LENGTH bytes) and append it to the returned ciphertext. During decryption, + * process the last Tag::MAC_LENGTH bytes as the tag. If tag verification fails, finish() + * must return ErrorCode::VERIFICATION_FAILED. + * + * TODO: update() will need to be refactored into 2 function. b/168665179. + * + * @param inParams Additional parameters for the operation. For AEAD modes, this is used to + * specify Tag::ADDITIONAL_DATA, but only if no input data was provided to update(). + * + * @param input Data to be processed, per the parameters established in the call to begin(). + * finish() must consume all provided data or return ErrorCode::INVALID_INPUT_LENGTH. + * + * @param signature The signature to be verified if the purpose specified in the begin() call + * was KeyPurpose::VERIFY. + * + * @param authToken Authentication token. Can be nullable if not provided. + * + * @param verificationToken Verification token, used to prove that another IKeyMintDevice HAL + * has verified some parameters, and to deliver the other HAL's current timestamp, if + * needed. Can be nullable if not needed. + * + * @return outParams Any output parameters generated by finish(). + * + * @return The output data, if any. + */ + byte[] finish(in @nullable KeyParameterArray inParams, in @nullable byte[] input, + in @nullable byte[] inSignature, + in @nullable HardwareAuthToken authToken, + in @nullable VerificationToken inVerificationToken, + out @nullable KeyParameterArray outParams); + + /** + * Aborts a cryptographic operation begun with begin(), freeing all internal resources. If an + * operation was finalized, calling update, finish, or abort yields + * ErrorCode::INVALID_OPERATION_HANDLE. An operation is finalized if finish or abort was + * called on it, or if update returned an ErrorCode. + * + * @param operationHandle The operation handle returned by begin(). This handle must be + * invalid when abort() returns. + * + * @return error See the ErrorCode enum in ErrorCode.aidl. + */ + void abort(); +} diff --git a/keymint/aidl/android/hardware/keymint/KeyCharacteristics.aidl b/keymint/aidl/android/hardware/keymint/KeyCharacteristics.aidl new file mode 100644 index 0000000000..ac7c2b482f --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/KeyCharacteristics.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +import android.hardware.keymint.KeyParameter; + +/** + * KeyCharacteristics defines the attributes of a key, including cryptographic parameters, and usage + * restrictions. It consits of two vectors of KeyParameters, one for "softwareEnforced" attributes + * and one for "hardwareEnforced" attributes. + * + * KeyCharacteristics objects are returned by generateKey, importKey, importWrappedKey and + * getKeyCharacteristics. The IKeyMintDevice secure environment is responsible for allocating the + * parameters, all of which are Tags with associated values, to the correct vector. The + * hardwareEnforced vector must contain only those attributes which are enforced by secure hardware. + * All others should be in the softwareEnforced vector. See the definitions of individual Tag enums + * for specification of which must be hardware-enforced, which may be software-enforced and which + * must never appear in KeyCharacteristics. + */ +@VintfStability +parcelable KeyCharacteristics { + /* TODO(seleneh) get rid of the software enforced in keymint. replace hardware enforced with + * tee enforced and strongbox enforced. + */ + KeyParameter[] softwareEnforced; + KeyParameter[] hardwareEnforced; +} diff --git a/keymint/aidl/android/hardware/keymint/KeyDerivationFunction.aidl b/keymint/aidl/android/hardware/keymint/KeyDerivationFunction.aidl new file mode 100644 index 0000000000..1eba446770 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/KeyDerivationFunction.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +/** + * Key derivation functions, mostly used in ECIES. + */ +@VintfStability +@Backing(type="int") +enum KeyDerivationFunction { + /** Do not apply a key derivation function; use the raw agreed key */ + NONE = 0, + /** HKDF defined in RFC 5869 with SHA256 */ + RFC5869_SHA256 = 1, + /** KDF1 defined in ISO 18033-2 with SHA1 */ + ISO18033_2_KDF1_SHA1 = 2, + /** KDF1 defined in ISO 18033-2 with SHA256 */ + ISO18033_2_KDF1_SHA256 = 3, + /** KDF2 defined in ISO 18033-2 with SHA1 */ + ISO18033_2_KDF2_SHA1 = 4, + /** KDF2 defined in ISO 18033-2 with SHA256 */ + ISO18033_2_KDF2_SHA256 = 5, +} diff --git a/keymint/aidl/android/hardware/keymint/KeyFormat.aidl b/keymint/aidl/android/hardware/keymint/KeyFormat.aidl new file mode 100644 index 0000000000..13044dc5b1 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/KeyFormat.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * Formats for key import and export. + */ +@VintfStability +@Backing(type="int") +enum KeyFormat { + /** X.509 certificate format, for public key export. */ + X509 = 0, + /** PCKS#8 format, asymmetric key pair import. */ + PKCS8 = 1, + /** Raw bytes, for symmetric key import. */ + RAW = 3, +} diff --git a/keymint/aidl/android/hardware/keymint/KeyMintHardwareInfo.aidl b/keymint/aidl/android/hardware/keymint/KeyMintHardwareInfo.aidl new file mode 100644 index 0000000000..5815b10951 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/KeyMintHardwareInfo.aidl @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +import android.hardware.keymint.SecurityLevel; + + +/** + * KeyMintHardwareInfo is the hardware information returned by calling KeyMint getHardwareInfo() + */ + +@VintfStability +parcelable KeyMintHardwareInfo { + /** + * Implementation version of the keymint hardware. The version number is implementation + * defined, and not necessarily globally meaningful. The version is used to distinguish + * between different versions of a given implementation. + * TODO(seleneh) add the version related info to the code. + */ + int versionNumber; + + /* securityLevel is the security level of the IKeyMintDevice implementation accessed + * through this aidl package. */ + SecurityLevel securityLevel; + + /* keyMintName is the name of the IKeyMintDevice implementation. */ + @utf8InCpp String keyMintName; + + /* keyMintAuthorName is the name of the author of the IKeyMintDevice implementation + * (organization name, not individual). This name is implementation defined, + * so it can be used to distinguish between different implementations from the + * same author. + */ + @utf8InCpp String keyMintAuthorName; +} diff --git a/keymint/aidl/android/hardware/keymint/KeyOrigin.aidl b/keymint/aidl/android/hardware/keymint/KeyOrigin.aidl new file mode 100644 index 0000000000..70320d3998 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/KeyOrigin.aidl @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * The origin of a key (or pair), i.e. where it was generated. Note that ORIGIN can be found in + * either the hardware-enforced or software-enforced list for a key, indicating whether the key is + * hardware or software-based. Specifically, a key with GENERATED in the hardware-enforced list + * must be guaranteed never to have existed outide the secure hardware. + */ +@VintfStability +@Backing(type="int") +enum KeyOrigin { + /** Generated in keyMint. Should not exist outside the TEE. */ + GENERATED = 0, + + /** Derived inside keyMint. Likely exists off-device. */ + DERIVED = 1, + + /** Imported into keyMint. Existed as cleartext in Android. */ + IMPORTED = 2, + + /** Previously used for another purpose that is now obsolete. */ + RESERVED = 3, + + /** + * Securely imported into KeyMint. Was created elsewhere, and passed securely through Android + * to secure hardware. + */ + SECURELY_IMPORTED = 4, +} diff --git a/keymint/aidl/android/hardware/keymint/KeyParameter.aidl b/keymint/aidl/android/hardware/keymint/KeyParameter.aidl new file mode 100644 index 0000000000..d58e4aa1aa --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/KeyParameter.aidl @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +import android.hardware.keymint.Algorithm; +import android.hardware.keymint.BlockMode; +import android.hardware.keymint.Digest; +import android.hardware.keymint.EcCurve; +import android.hardware.keymint.HardwareAuthenticatorType; +import android.hardware.keymint.KeyDerivationFunction; +import android.hardware.keymint.KeyOrigin; +import android.hardware.keymint.KeyPurpose; +import android.hardware.keymint.PaddingMode; +import android.hardware.keymint.SecurityLevel; +import android.hardware.keymint.Tag; + + +/** + * Identifies the key authorization parameters to be used with keyMint. This is usually + * provided as an array of KeyParameters to IKeyMintDevice or Operation. + * + * TODO(seleneh): Union was not supported in aidl when this cl is first drafted. So we just had + * the Tags, and bool, int, long, int[], and we will cast to the appropate types base on the + * Tag value. We need to update this defination to distingish Algorithm, BlockMode, + * PaddingMode, KeyOrigin...etc later, as union support is recently added to aidl. + * b/173253030 + */ +@VintfStability +parcelable KeyParameter { + /** + * Identify what type of key parameter this parcelable actually holds, and based on the type + * of tag is int, long, bool, or byte[], one of the fields below will be referenced. + */ + Tag tag; + + boolean boolValue; + int integer; + long longInteger; + // TODO: change this to nullable. + byte[] blob; +} diff --git a/keymint/aidl/android/hardware/keymint/KeyParameterArray.aidl b/keymint/aidl/android/hardware/keymint/KeyParameterArray.aidl new file mode 100644 index 0000000000..cc9e37ad2a --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/KeyParameterArray.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +import android.hardware.keymint.KeyParameter; + +/** + * Identifies the key authorization parameters to be used with keyMint. This is usually + * provided as an array of KeyParameters to IKeyMintDevice or Operation. + */ +@VintfStability +parcelable KeyParameterArray { + /** + * Identify list of key parameters corresponding to a particular key blob. + */ + KeyParameter[] params; +} diff --git a/keymint/aidl/android/hardware/keymint/KeyPurpose.aidl b/keymint/aidl/android/hardware/keymint/KeyPurpose.aidl new file mode 100644 index 0000000000..bc029fdb39 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/KeyPurpose.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + + +/** + * Possible purposes of a key (or pair). + */ +@VintfStability +@Backing(type = "int") +enum KeyPurpose { + /* Usable with RSA, EC and AES keys. */ + ENCRYPT = 0, + + /* Usable with RSA, EC and AES keys. */ + DECRYPT = 1, + + /* Usable with RSA, EC and HMAC keys. */ + SIGN = 2, + + /* Usable with RSA, EC and HMAC keys. */ + VERIFY = 3, + + /* 4 is reserved */ + /* Usable with wrapping keys. */ + WRAP_KEY = 5, + + /* TODO(seleneh) add AGREE_KEY and ATTEST_KEY and their corresponding codes and tests later*/ +} diff --git a/keymint/aidl/android/hardware/keymint/PaddingMode.aidl b/keymint/aidl/android/hardware/keymint/PaddingMode.aidl new file mode 100644 index 0000000000..337ed912fc --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/PaddingMode.aidl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +/** + * TODO(seleneh) update the description. + * + * Padding modes that may be applied to plaintext for encryption operations. This list includes + * padding modes for both symmetric and asymmetric algorithms. Note that implementations should not + * provide all possible combinations of algorithm and padding, only the + * cryptographically-appropriate pairs. + */ +@VintfStability +@Backing(type="int") +enum PaddingMode { + NONE = 1, /* deprecated */ + RSA_OAEP = 2, + RSA_PSS = 3, + RSA_PKCS1_1_5_ENCRYPT = 4, + RSA_PKCS1_1_5_SIGN = 5, + PKCS7 = 64, +} diff --git a/keymint/aidl/android/hardware/keymint/SecurityLevel.aidl b/keymint/aidl/android/hardware/keymint/SecurityLevel.aidl new file mode 100644 index 0000000000..d8de024493 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/SecurityLevel.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +/** + * Device security levels. + */ +@VintfStability +@Backing(type="int") +enum SecurityLevel { + SOFTWARE = 0, + TRUSTED_ENVIRONMENT = 1, + /** + * STRONGBOX specifies that the secure hardware satisfies the requirements specified in CDD + * 9.11.2. + */ + STRONGBOX = 2, +} diff --git a/keymint/aidl/android/hardware/keymint/Tag.aidl b/keymint/aidl/android/hardware/keymint/Tag.aidl new file mode 100644 index 0000000000..e85a8f5fa7 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/Tag.aidl @@ -0,0 +1,892 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +import android.hardware.keymint.TagType; + +// TODO(seleneh) : note aidl currently does not support double nested enum definitions such as +// ROOT_OF_TRUST = TagType:BYTES | 704. So we are forced to write definations as +// ROOT_OF_TRUST = (9 << 28) for now. Will need to flip this back later when aidl support is added. + +/** + * Tag specifies various kinds of tags that can be set in KeyParameter to identify what kind of + * data are stored in KeyParameter. + */ +@VintfStability +@Backing(type = "int") +enum Tag { + /** + * Tag::INVALID should never be set. It means you hit an error. + */ + INVALID = (0 << 28) | 0, + + /** + * Tag::PURPOSE specifies the set of purposes for which the key may be used. Possible values + * are defined in the KeyPurpose enumeration. + * + * This tag is repeatable; keys may be generated with multiple values, although an operation has + * a single purpose. When begin() is called to start an operation, the purpose of the operation + * is specified. If the purpose specified for the operation is not authorized by the key (the + * key didn't have a corresponding Tag::PURPOSE provided during generation/import), the + * operation must fail with ErrorCode::INCOMPATIBLE_PURPOSE. + * + * Must be hardware-enforced. + */ + PURPOSE = (2 << 28) | 1, /* TagType:ENUM_REP */ + + /** + * Tag::ALGORITHM specifies the cryptographic algorithm with which the key is used. This tag + * must be provided to generateKey and importKey, and must be specified in the wrapped key + * provided to importWrappedKey. + * + * Must be hardware-enforced. + */ + ALGORITHM = (1 << 28) | 2, /* TagType:ENUM */ + + /** + * Tag::KEY_SIZE pecifies the size, in bits, of the key, measuring in the normal way for the + * key's algorithm. For example, for RSA keys, Tag::KEY_SIZE specifies the size of the public + * modulus. For AES keys it specifies the length of the secret key material. For 3DES keys it + * specifies the length of the key material, not counting parity bits (though parity bits must + * be provided for import, etc.). Since only three-key 3DES keys are supported, 3DES + * Tag::KEY_SIZE must be 168. + * + * Must be hardware-enforced. + */ + KEY_SIZE = (3 << 28) | 3, /* TagType:UINT */ + + /** + * Tag::BLOCK_MODE specifies the block cipher mode(s) with which the key may be used. This tag + * is only relevant to AES and 3DES keys. Possible values are defined by the BlockMode enum. + * + * This tag is repeatable for key generation/import. For AES and 3DES operations the caller + * must specify a Tag::BLOCK_MODE in the additionalParams argument of begin(). If the mode is + * missing or the specified mode is not in the modes specified for the key during + * generation/import, the operation must fail with ErrorCode::INCOMPATIBLE_BLOCK_MODE. + * + * Must be hardware-enforced. + */ + BLOCK_MODE = (2 << 28) | 4, + /* BlockMode. */ /* TagType:ENUM_REP */ + + /** + * Tag::DIGEST specifies the digest algorithms that may be used with the key to perform signing + * and verification operations. This tag is relevant to RSA, ECDSA and HMAC keys. Possible + * values are defined by the Digest enum. + * + * This tag is repeatable for key generation/import. For signing and verification operations, + * the caller must specify a digest in the additionalParams argument of begin(). If the digest + * is missing or the specified digest is not in the digests associated with the key, the + * operation must fail with ErrorCode::INCOMPATIBLE_DIGEST. + * + * Must be hardware-enforced. + */ + DIGEST = (2 << 28) | 5, /* TagType:ENUM_REP */ + + /** + * Tag::PADDING specifies the padding modes that may be used with the key. This tag is relevant + * to RSA, AES and 3DES keys. Possible values are defined by the PaddingMode enum. + * + * PaddingMode::RSA_OAEP and PaddingMode::RSA_PKCS1_1_5_ENCRYPT are used only for RSA + * encryption/decryption keys and specify RSA OAEP padding and RSA PKCS#1 v1.5 randomized + * padding, respectively. PaddingMode::RSA_PSS and PaddingMode::RSA_PKCS1_1_5_SIGN are used + * only for RSA signing/verification keys and specify RSA PSS padding and RSA PKCS#1 v1.5 + * deterministic padding, respectively. + * + * PaddingMode::NONE may be used with either RSA, AES or 3DES keys. For AES or 3DES keys, if + * PaddingMode::NONE is used with block mode ECB or CBC and the data to be encrypted or + * decrypted is not a multiple of the AES block size in length, the call to finish() must fail + * with ErrorCode::INVALID_INPUT_LENGTH. + * + * PaddingMode::PKCS7 may only be used with AES and 3DES keys, and only with ECB and CBC modes. + * + * In any case, if the caller specifies a padding mode that is not usable with the key's + * algorithm, the generation or import method must return ErrorCode::INCOMPATIBLE_PADDING_MODE. + * + * This tag is repeatable. A padding mode must be specified in the call to begin(). If the + * specified mode is not authorized for the key, the operation must fail with + * ErrorCode::INCOMPATIBLE_BLOCK_MODE. + * + * Must be hardware-enforced. + */ + PADDING = (2 << 28) | 6, /* TagType:ENUM_REP */ + + /** + * Tag::CALLER_NONCE specifies that the caller can provide a nonce for nonce-requiring + * operations. This tag is boolean, so the possible values are true (if the tag is present) and + * false (if the tag is not present). + * + * This tag is used only for AES and 3DES keys, and is only relevant for CBC, CTR and GCM block + * modes. If the tag is not present in a key's authorization list, implementations must reject + * any operation that provides Tag::NONCE to begin() with ErrorCode::CALLER_NONCE_PROHIBITED. + * + * Must be hardware-enforced. + */ + CALLER_NONCE = (7 << 28) | 7, /* TagType:BOOL */ + + /** + * Tag::MIN_MAC_LENGTH specifies the minimum length of MAC that can be requested or verified + * with this key for HMAC keys and AES keys that support GCM mode. + * + * This value is the minimum MAC length, in bits. It must be a multiple of 8 bits. For HMAC + * keys, the value must be least 64 and no more than 512. For GCM keys, the value must be at + * least 96 and no more than 128. If the provided value violates these requirements, + * generateKey() or importKey() must return ErrorCode::UNSUPPORTED_KEY_SIZE. + * + * Must be hardware-enforced. + */ + MIN_MAC_LENGTH = (3 << 28) | 8, /* TagType:UINT */ + + // Tag 9 reserved + + /** + * Tag::EC_CURVE specifies the elliptic curve. EC key generation requests may have + * Tag:EC_CURVE, Tag::KEY_SIZE, or both. If both are provided and the size and curve do not + * match, IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT. + * + * Must be hardware-enforced. + */ + EC_CURVE = (1 << 28) | 10, /* TagType:ENUM */ + + /** + * Tag::RSA_PUBLIC_EXPONENT specifies the value of the public exponent for an RSA key pair. + * This tag is relevant only to RSA keys, and is required for all RSA keys. + * + * The value is a 64-bit unsigned integer that satisfies the requirements of an RSA public + * exponent. This value must be a prime number. IKeyMintDevice implementations must support + * the value 2^16+1 and may support other reasonable values. If no exponent is specified or if + * the specified exponent is not supported, key generation must fail with + * ErrorCode::INVALID_ARGUMENT. + * + * Must be hardware-enforced. + */ + RSA_PUBLIC_EXPONENT = (5 << 28) | 200, /* TagType:ULONG */ + + // Tag 201 reserved + + /** + * Tag::INCLUDE_UNIQUE_ID is specified during key generation to indicate that an attestation + * certificate for the generated key should contain an application-scoped and time-bounded + * device-unique ID. See Tag::UNIQUE_ID. + * + * Must be hardware-enforced. + */ + INCLUDE_UNIQUE_ID = (7 << 28) | 202, /* TagType:BOOL */ + + /** + * TODO(seleneh) this tag needs to be deleted from all codes. + * + * Tag::BLOB_USAGE_REQUIREMENTS specifies the necessary system environment conditions for the + * generated key to be used. Possible values are defined by the KeyBlobUsageRequirements enum. + * + * This tag is specified by the caller during key generation or import to require that the key + * is usable in the specified condition. If the caller specifies Tag::BLOB_USAGE_REQUIREMENTS + * with value KeyBlobUsageRequirements::STANDALONE the IKeyMintDevice must return a key blob + * that can be used without file system support. This is critical for devices with encrypted + * disks, where the file system may not be available until after a KeyMint key is used to + * decrypt the disk. + * + * Must be hardware-enforced. + */ + BLOB_USAGE_REQUIREMENTS = (1 << 28) | 301, /* TagType:ENUM */ + + /** + * Tag::BOOTLOADER_ONLY specifies only the bootloader can use the key. + * + * Any attempt to use a key with Tag::BOOTLOADER_ONLY from the Android system must fail with + * ErrorCode::INVALID_KEY_BLOB. + * + * Must be hardware-enforced. + */ + BOOTLOADER_ONLY = (7 << 28) | 302, /* TagType:BOOL */ + + /** + * Tag::ROLLBACK_RESISTANCE specifies that the key has rollback resistance, meaning that when + * deleted with deleteKey() or deleteAllKeys(), the key is guaranteed to be permanently deleted + * and unusable. It's possible that keys without this tag could be deleted and then restored + * from backup. + * + * This tag is specified by the caller during key generation or import to require. If the + * IKeyMintDevice cannot guarantee rollback resistance for the specified key, it must return + * ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE. IKeyMintDevice implementations are not + * required to support rollback resistance. + * + * Must be hardwared-enforced. + */ + ROLLBACK_RESISTANCE = (7 << 28) | 303, /* TagType:BOOL */ + + // Reserved for future use. + HARDWARE_TYPE = (1 << 28) | 304, /* TagType:ENUM */ + + /** + * Keys tagged with EARLY_BOOT_ONLY may only be used, or created, during early boot, until + * IKeyMintDevice::earlyBootEnded() is called. + */ + EARLY_BOOT_ONLY = (7 << 28) | 305, /* TagType:BOOL */ + + /** + * Tag::ACTIVE_DATETIME specifies the date and time at which the key becomes active, in + * milliseconds since Jan 1, 1970. If a key with this tag is used prior to the specified date + * and time, IKeyMintDevice::begin() must return ErrorCode::KEY_NOT_YET_VALID; + * + * Need not be hardware-enforced. + */ + ACTIVE_DATETIME = (6 << 28) | 400, + /* Start of validity. */ /* TagType:DATE */ + + /** + * Tag::ORIGINATION_EXPIRE_DATETIME specifies the date and time at which the key expires for + * signing and encryption purposes. After this time, any attempt to use a key with + * KeyPurpose::SIGN or KeyPurpose::ENCRYPT provided to begin() must fail with + * ErrorCode::KEY_EXPIRED. + * + * The value is a 64-bit integer representing milliseconds since January 1, 1970. + * + * Need not be hardware-enforced. + */ + ORIGINATION_EXPIRE_DATETIME = (6 << 28) | 401, /* TagType:DATE */ + + /** + * Tag::USAGE_EXPIRE_DATETIME specifies the date and time at which the key expires for + * verification and decryption purposes. After this time, any attempt to use a key with + * KeyPurpose::VERIFY or KeyPurpose::DECRYPT provided to begin() must fail with + * ErrorCode::KEY_EXPIRED. + * + * The value is a 64-bit integer representing milliseconds since January 1, 1970. + * + * Need not be hardware-enforced. + */ + USAGE_EXPIRE_DATETIME = (6 << 28) | 402, /* TagType:DATE */ + + /** + * TODO(seleneh) this tag need to be deleted. + * + * TODO(seleneh) this tag need to be deleted. + * + * Tag::MIN_SECONDS_BETWEEN_OPS specifies the minimum amount of time that elapses between + * allowed operations using a key. This can be used to rate-limit uses of keys in contexts + * where unlimited use may enable brute force attacks. + * + * The value is a 32-bit integer representing seconds between allowed operations. + * + * When a key with this tag is used in an operation, the IKeyMintDevice must start a timer + * during the finish() or abort() call. Any call to begin() that is received before the timer + * indicates that the interval specified by Tag::MIN_SECONDS_BETWEEN_OPS has elapsed must fail + * with ErrorCode::KEY_RATE_LIMIT_EXCEEDED. This implies that the IKeyMintDevice must keep a + * table of use counters for keys with this tag. Because memory is often limited, this table + * may have a fixed maximum size and KeyMint may fail operations that attempt to use keys with + * this tag when the table is full. The table must acommodate at least 8 in-use keys and + * aggressively reuse table slots when key minimum-usage intervals expire. If an operation + * fails because the table is full, KeyMint returns ErrorCode::TOO_MANY_OPERATIONS. + * + * Must be hardware-enforced. + */ + MIN_SECONDS_BETWEEN_OPS = (3 << 28) | 403, /* TagType:UINT */ + + /** + * Tag::MAX_USES_PER_BOOT specifies the maximum number of times that a key may be used between + * system reboots. This is another mechanism to rate-limit key use. + * + * The value is a 32-bit integer representing uses per boot. + * + * When a key with this tag is used in an operation, a key-associated counter must be + * incremented during the begin() call. After the key counter has exceeded this value, all + * subsequent attempts to use the key must fail with ErrorCode::MAX_OPS_EXCEEDED, until the + * device is restarted. This implies that the IKeyMintDevice must keep a table of use + * counters for keys with this tag. Because KeyMint memory is often limited, this table can + * have a fixed maximum size and KeyMint can fail operations that attempt to use keys with + * this tag when the table is full. The table needs to acommodate at least 8 keys. If an + * operation fails because the table is full, IKeyMintDevice must + * ErrorCode::TOO_MANY_OPERATIONS. + * + * Must be hardware-enforced. + */ + MAX_USES_PER_BOOT = (3 << 28) | 404, /* TagType:UINT */ + + /** + * Tag::USER_ID specifies the ID of the Android user that is permitted to use the key. + * + * Must not be hardware-enforced. + */ + USER_ID = (3 << 28) | 501, /* TagType:UINT */ + + /** + * Tag::USER_SECURE_ID specifies that a key may only be used under a particular secure user + * authentication state. This tag is mutually exclusive with Tag::NO_AUTH_REQUIRED. + * + * The value is a 64-bit integer specifying the authentication policy state value which must be + * present in the userId or authenticatorId field of a HardwareAuthToken provided to begin(), + * update(), or finish(). If a key with Tag::USER_SECURE_ID is used without a HardwareAuthToken + * with the matching userId or authenticatorId, the IKeyMintDevice must return + * ErrorCode::KEY_USER_NOT_AUTHENTICATED. + * + * Tag::USER_SECURE_ID interacts with Tag::AUTH_TIMEOUT in a very important way. If + * Tag::AUTH_TIMEOUT is present in the key's characteristics then the key is a "timeout-based" + * key, and may only be used if the difference between the current time when begin() is called + * and the timestamp in the HardwareAuthToken is less than the value in Tag::AUTH_TIMEOUT * 1000 + * (the multiplier is because Tag::AUTH_TIMEOUT is in seconds, but the HardwareAuthToken + * timestamp is in milliseconds). Otherwise the IKeyMintDevice must returrn + * ErrorCode::KEY_USER_NOT_AUTHENTICATED. + * + * If Tag::AUTH_TIMEOUT is not present, then the key is an "auth-per-operation" key. In this + * case, begin() must not require a HardwareAuthToken with appropriate contents. Instead, + * update() and finish() must receive a HardwareAuthToken with Tag::USER_SECURE_ID value in + * userId or authenticatorId fields, and the current operation's operation handle in the + * challenge field. Otherwise the IKeyMintDevice must returrn + * ErrorCode::KEY_USER_NOT_AUTHENTICATED. + * + * This tag is repeatable. If repeated, and any one of the values matches the HardwareAuthToken + * as described above, the key is authorized for use. Otherwise the operation must fail with + * ErrorCode::KEY_USER_NOT_AUTHENTICATED. + * + * Must be hardware-enforced. + */ + USER_SECURE_ID = (4 << 28) | 502, /* TagType:UINT_REP */ + + /** + * Tag::NO_AUTH_REQUIRED specifies that no authentication is required to use this key. This tag + * is mutually exclusive with Tag::USER_SECURE_ID. + * + * Must be hardware-enforced. + */ + NO_AUTH_REQUIRED = (7 << 28) | 503, /* TagType:BOOL */ + + /** + * Tag::USER_AUTH_TYPE specifies the types of user authenticators that may be used to authorize + * this key. + * + * The value is one or more values from HardwareAuthenticatorType, ORed together. + * + * When IKeyMintDevice is requested to perform an operation with a key with this tag, it must + * receive a HardwareAuthToken and one or more bits must be set in both the HardwareAuthToken's + * authenticatorType field and the Tag::USER_AUTH_TYPE value. That is, it must be true that + * + * (token.authenticatorType & tag_user_auth_type) != 0 + * + * where token.authenticatorType is the authenticatorType field of the HardwareAuthToken and + * tag_user_auth_type is the value of Tag:USER_AUTH_TYPE. + * + * Must be hardware-enforced. + */ + USER_AUTH_TYPE = (1 << 28) | 504, /* TagType:ENUM */ + + /** + * Tag::AUTH_TIMEOUT specifies the time in seconds for which the key is authorized for use, + * after user authentication. If + * Tag::USER_SECURE_ID is present and this tag is not, then the key requies authentication for + * every usage (see begin() for the details of the authentication-per-operation flow). + * + * The value is a 32-bit integer specifying the time in seconds after a successful + * authentication of the user specified by Tag::USER_SECURE_ID with the authentication method + * specified by Tag::USER_AUTH_TYPE that the key can be used. + * + * Must be hardware-enforced. + */ + AUTH_TIMEOUT = (3 << 28) | 505, /* TagType:UINT */ + + /** + * Tag::ALLOW_WHILE_ON_BODY specifies that the key may be used after authentication timeout if + * device is still on-body (requires on-body sensor). + * + * Cannot be hardware-enforced. + */ + ALLOW_WHILE_ON_BODY = (7 << 28) | 506, /* TagType:BOOL */ + + /** + * TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be + * unusable except when the user has provided proof of physical presence. Proof of physical + * presence must be a signal that cannot be triggered by an attacker who doesn't have one of: + * + * a) Physical control of the device or + * + * b) Control of the secure environment that holds the key. + * + * For instance, proof of user identity may be considered proof of presence if it meets the + * requirements. However, proof of identity established in one security domain (e.g. TEE) does + * not constitute proof of presence in another security domain (e.g. StrongBox), and no + * mechanism analogous to the authentication token is defined for communicating proof of + * presence across security domains. + * + * Some examples: + * + * A hardware button hardwired to a pin on a StrongBox device in such a way that nothing + * other than a button press can trigger the signal constitutes proof of physical presence + * for StrongBox keys. + * + * Fingerprint authentication provides proof of presence (and identity) for TEE keys if the + * TEE has exclusive control of the fingerprint scanner and performs fingerprint matching. + * + * Password authentication does not provide proof of presence to either TEE or StrongBox, + * even if TEE or StrongBox does the password matching, because password input is handled by + * the non-secure world, which means an attacker who has compromised Android can spoof + * password authentication. + * + * Note that no mechanism is defined for delivering proof of presence to an IKeyMintDevice, + * except perhaps as implied by an auth token. This means that KeyMint must be able to check + * proof of presence some other way. Further, the proof of presence must be performed between + * begin() and the first call to update() or finish(). If the first update() or the finish() + * call is made without proof of presence, the keyMint method must return + * ErrorCode::PROOF_OF_PRESENCE_REQUIRED and abort the operation. The caller must delay the + * update() or finish() call until proof of presence has been provided, which means the caller + * must also have some mechanism for verifying that the proof has been provided. + * + * Only one operation requiring TUP may be in flight at a time. If begin() has already been + * called on one key with TRUSTED_USER_PRESENCE_REQUIRED, and another begin() comes in for that + * key or another with TRUSTED_USER_PRESENCE_REQUIRED, KeyMint must return + * ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED. + * + * Must be hardware-enforced. + */ + TRUSTED_USER_PRESENCE_REQUIRED = (7 << 28) | 507, /* TagType:BOOL */ + + /** Tag::TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and + * specifies that this key must not be usable unless the user provides confirmation of the data + * to be signed. Confirmation is proven to keyMint via an approval token. See + * CONFIRMATION_TOKEN, as well as the ConfirmatinUI HAL. + * + * If an attempt to use a key with this tag does not have a cryptographically valid + * CONFIRMATION_TOKEN provided to finish() or if the data provided to update()/finish() does not + * match the data described in the token, keyMint must return NO_USER_CONFIRMATION. + * + * Must be hardware-enforced. + */ + TRUSTED_CONFIRMATION_REQUIRED = (7 << 28) | 508, /* TagType:BOOL */ + + /** + * Tag::UNLOCKED_DEVICE_REQUIRED specifies that the key may only be used when the device is + * unlocked. + * + * Must be software-enforced. + */ + UNLOCKED_DEVICE_REQUIRED = (7 << 28) | 509, /* TagType:BOOL */ + + /** + * Tag::APPLICATION_ID. When provided to generateKey or importKey, this tag specifies data + * that is necessary during all uses of the key. In particular, calls to exportKey() and + * getKeyCharacteristics() must provide the same value to the clientId parameter, and calls to + * begin must provide this tag and the same associated data as part of the inParams set. If + * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB. + * + * The content of this tag must be bound to the key cryptographically, meaning it must not be + * possible for an adversary who has access to all of the secure world secrets but does not have + * access to the tag content to decrypt the key without brute-forcing the tag content, which + * applications can prevent by specifying sufficiently high-entropy content. + * + * Must never appear in KeyCharacteristics. + */ + APPLICATION_ID = (9 << 28) | 601, /* TagType:BYTES */ + + /* + * Semantically unenforceable tags, either because they have no specific meaning or because + * they're informational only. + */ + + /** + * Tag::APPLICATION_DATA. When provided to generateKey or importKey, this tag specifies data + * that is necessary during all uses of the key. In particular, calls to exportKey() and + * getKeyCharacteristics() must provide the same value to the appData parameter, and calls to + * begin must provide this tag and the same associated data as part of the inParams set. If + * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB. + * + * The content of this tag msut be bound to the key cryptographically, meaning it must not be + * possible for an adversary who has access to all of the secure world secrets but does not have + * access to the tag content to decrypt the key without brute-forcing the tag content, which + * applications can prevent by specifying sufficiently high-entropy content. + * + * Must never appear in KeyCharacteristics. + */ + APPLICATION_DATA = (9 << 28) | 700, /* TagType:BYTES */ + + /** + * Tag::CREATION_DATETIME specifies the date and time the key was created, in milliseconds since + * January 1, 1970. This tag is optional and informational only. + * + * Tag::CREATED is informational only, and not enforced by anything. Must be in the + * software-enforced list, if provided. + */ + CREATION_DATETIME = (6 << 28) | 701, /* TagType:DATE */ + + /** + * Tag::ORIGIN specifies where the key was created, if known. This tag must not be specified + * during key generation or import, and must be added to the key characteristics by the + * IKeyMintDevice. The possible values are defined in the KeyOrigin enum. + * + * Must be hardware-enforced. + */ + ORIGIN = (1 << 28) | 702, /* TagType:ENUM */ + + // 703 is unused. + + /** + * Tag::ROOT_OF_TRUST specifies the root of trust associated with the key used by verified boot + * to validate the system. It describes the boot key, verified boot state, boot hash, and + * whether device is locked. This tag is never provided to or returned from KeyMint in the + * key characteristics. It exists only to define the tag for use in the attestation record. + * + * Must never appear in KeyCharacteristics. + */ + ROOT_OF_TRUST = (9 << 28) | 704, /* TagType:BYTES */ + + /** + * Tag::OS_VERSION specifies the system OS version with which the key may be used. This tag is + * never sent to the IKeyMintDevice, but is added to the hardware-enforced authorization list + * by the TA. Any attempt to use a key with a Tag::OS_VERSION value different from the + * currently-running OS version must cause begin(), getKeyCharacteristics() or exportKey() to + * return ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details. + * + * The value of the tag is an integer of the form MMmmss, where MM is the major version number, + * mm is the minor version number, and ss is the sub-minor version number. For example, for a + * key generated on Android version 4.0.3, the value would be 040003. + * + * The IKeyMintDevice HAL must read the current OS version from the system property + * ro.build.version.release and deliver it to the secure environment when the HAL is first + * loaded (mechanism is implementation-defined). The secure environment must not accept another + * version until after the next boot. If the content of ro.build.version.release has additional + * version information after the sub-minor version number, it must not be included in + * Tag::OS_VERSION. If the content is non-numeric, the secure environment must use 0 as the + * system version. + * + * Must be hardware-enforced. + */ + OS_VERSION = (3 << 28) | 705, /* TagType:UINT */ + + /** + * Tag::OS_PATCHLEVEL specifies the system security patch level with which the key may be used. + * This tag is never sent to the keyMint TA, but is added to the hardware-enforced + * authorization list by the TA. Any attempt to use a key with a Tag::OS_PATCHLEVEL value + * different from the currently-running system patchlevel must cause begin(), + * getKeyCharacteristics() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See + * upgradeKey() for details. + * + * The value of the tag is an integer of the form YYYYMM, where YYYY is the four-digit year of + * the last update and MM is the two-digit month of the last update. For example, for a key + * generated on an Android device last updated in December 2015, the value would be 201512. + * + * The IKeyMintDevice HAL must read the current system patchlevel from the system property + * ro.build.version.security_patch and deliver it to the secure environment when the HAL is + * first loaded (mechanism is implementation-defined). The secure environment must not accept + * another patchlevel until after the next boot. + * + * Must be hardware-enforced. + */ + OS_PATCHLEVEL = (3 << 28) | 706, /* TagType:UINT */ + + /** + * Tag::UNIQUE_ID specifies a unique, time-based identifier. This tag is never provided to or + * returned from KeyMint in the key characteristics. It exists only to define the tag for use + * in the attestation record. + * + * When a key with Tag::INCLUDE_UNIQUE_ID is attested, the unique ID is added to the attestation + * record. The value is a 128-bit hash that is unique per device and per calling application, + * and changes monthly and on most password resets. It is computed with: + * + * HMAC_SHA256(T || C || R, HBK) + * + * Where: + * + * T is the "temporal counter value", computed by dividing the value of + * Tag::CREATION_DATETIME by 2592000000, dropping any remainder. T changes every 30 days + * (2592000000 = 30 * 24 * 60 * 60 * 1000). + * + * C is the value of Tag::ATTESTATION_APPLICATION_ID that is provided to attestKey(). + * + * R is 1 if Tag::RESET_SINCE_ID_ROTATION was provided to attestKey or 0 if the tag was not + * provided. + * + * HBK is a unique hardware-bound secret known to the secure environment and never revealed + * by it. The secret must contain at least 128 bits of entropy and be unique to the + * individual device (probabilistic uniqueness is acceptable). + * + * HMAC_SHA256 is the HMAC function, with SHA-2-256 as the hash. + * + * The output of the HMAC function must be truncated to 128 bits. + * + * Must be hardware-enforced. + */ + UNIQUE_ID = (9 << 28) | 707, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attestKey() method, + * which must place the value in the KeyDescription SEQUENCE of the attestation extension. See + * attestKey(). + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_CHALLENGE = (9 << 28) | 708, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_APPLICATION_ID identifies the set of applications which may use a key, used + * only with attestKey(). + * + * The content of Tag::ATTESTATION_APPLICATION_ID is a DER-encoded ASN.1 structure, with the + * following schema: + * + * AttestationApplicationId ::= SEQUENCE { + * packageInfoRecords SET OF PackageInfoRecord, + * signatureDigests SET OF OCTET_STRING, + * } + * + * PackageInfoRecord ::= SEQUENCE { + * packageName OCTET_STRING, + * version INTEGER, + * } + * + * See system/security/keystore/keystore_attestation_id.cpp for details of construction. + * IKeyMintDevice implementers do not need to create or parse the ASN.1 structure, but only + * copy the tag value into the attestation record. The DER-encoded string must not exceed 1 KiB + * in length. + * + * Cannot be hardware-enforced. + */ + ATTESTATION_APPLICATION_ID = (9 << 28) | 709, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_ID_BRAND provides the device's brand name, as returned by Build.BRAND in + * Android, to attestKey(). This field must be set only when requesting attestation of the + * device's identifiers. + * + * If the device does not support ID attestation (or destroyAttestationIds() was previously + * called and the device can no longer attest its IDs), any key attestation request that + * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS. + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_ID_BRAND = (9 << 28) | 710, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_ID_DEVICE provides the device's device name, as returned by Build.DEVICE in + * Android, to attestKey(). This field must be set only when requesting attestation of the + * device's identifiers. + * + * If the device does not support ID attestation (or destroyAttestationIds() was previously + * called and the device can no longer attest its IDs), any key attestation request that + * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS. + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_ID_DEVICE = (9 << 28) | 711, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_ID_PRODUCT provides the device's product name, as returned by Build.PRODUCT + * in Android, to attestKey(). This field must be set only when requesting attestation of the + * device's identifiers. + * + * If the device does not support ID attestation (or destroyAttestationIds() was previously + * called and the device can no longer attest its IDs), any key attestation request that + * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS. + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_ID_PRODUCT = (9 << 28) | 712, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_ID_SERIAL the device's serial number. This field must be set only when + * requesting attestation of the device's identifiers. + * + * If the device does not support ID attestation (or destroyAttestationIds() was previously + * called and the device can no longer attest its IDs), any key attestation request that + * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS. + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_ID_SERIAL = (9 << 28) | 713, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attestKey(). + * This field must be set only when requesting attestation of the device's identifiers. + * + * If the device does not support ID attestation (or destroyAttestationIds() was previously + * called and the device can no longer attest its IDs), any key attestation request that + * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS. + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_ID_IMEI = (9 << 28) | 714, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attestKey(). + * This field must be set only when requesting attestation of the device's identifiers. + * + * If the device does not support ID attestation (or destroyAttestationIds() was previously + * called and the device can no longer attest its IDs), any key attestation request that + * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS. + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_ID_MEID = (9 << 28) | 715, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_ID_MANUFACTURER provides the device's manufacturer name, as returned by + * Build.MANUFACTURER in Android, to attstKey(). This field must be set only when requesting + * attestation of the device's identifiers. + * + * If the device does not support ID attestation (or destroyAttestationIds() was previously + * called and the device can no longer attest its IDs), any key attestation request that + * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS. + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_ID_MANUFACTURER = (9 << 28) | 716, /* TagType:BYTES */ + + /** + * Tag::ATTESTATION_ID_MODEL provides the device's model name, as returned by Build.MODEL in + * Android, to attestKey(). This field must be set only when requesting attestation of the + * device's identifiers. + * + * If the device does not support ID attestation (or destroyAttestationIds() was previously + * called and the device can no longer attest its IDs), any key attestation request that + * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS. + * + * Must never appear in KeyCharacteristics. + */ + ATTESTATION_ID_MODEL = (9 << 28) | 717, /* TagType:BYTES */ + + /** + * Tag::VENDOR_PATCHLEVEL specifies the vendor image security patch level with which the key may + * be used. This tag is never sent to the keyMint TA, but is added to the hardware-enforced + * authorization list by the TA. Any attempt to use a key with a Tag::VENDOR_PATCHLEVEL value + * different from the currently-running system patchlevel must cause begin(), + * getKeyCharacteristics() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE. See + * upgradeKey() for details. + * + * The value of the tag is an integer of the form YYYYMMDD, where YYYY is the four-digit year of + * the last update, MM is the two-digit month and DD is the two-digit day of the last + * update. For example, for a key generated on an Android device last updated on June 5, 2018, + * the value would be 20180605. + * + * The IKeyMintDevice HAL must read the current vendor patchlevel from the system property + * ro.vendor.build.security_patch and deliver it to the secure environment when the HAL is first + * loaded (mechanism is implementation-defined). The secure environment must not accept another + * patchlevel until after the next boot. + * + * Must be hardware-enforced. + */ + VENDOR_PATCHLEVEL = (3 << 28) | 718, /* TagType:UINT */ + + /** + * Tag::BOOT_PATCHLEVEL specifies the boot image (kernel) security patch level with which the + * key may be used. This tag is never sent to the keyMint TA, but is added to the + * hardware-enforced authorization list by the TA. Any attempt to use a key with a + * Tag::BOOT_PATCHLEVEL value different from the currently-running system patchlevel must + * cause begin(), getKeyCharacteristics() or exportKey() to return + * ErrorCode::KEY_REQUIRES_UPGRADE. See upgradeKey() for details. + * + * The value of the tag is an integer of the form YYYYMMDD, where YYYY is the four-digit year of + * the last update, MM is the two-digit month and DD is the two-digit day of the last + * update. For example, for a key generated on an Android device last updated on June 5, 2018, + * the value would be 20180605. If the day is not known, 00 may be substituted. + * + * During each boot, the bootloader must provide the patch level of the boot image to the secure + * envirionment (mechanism is implementation-defined). + * + * Must be hardware-enforced. + */ + BOOT_PATCHLEVEL = (3 << 28) | 719, /* TagType:UINT */ + + /** + * DEVICE_UNIQUE_ATTESTATION is an argument to IKeyMintDevice::attestKey(). It indicates that + * attestation using a device-unique key is requested, rather than a batch key. When a + * device-unique key is used, only the attestation certificate is returned; no additional + * chained certificates are provided. It's up to the caller to recognize the device-unique + * signing key. Only SecurityLevel::STRONGBOX IKeyMintDevices may support device-unique + * attestations. SecurityLevel::TRUSTED_ENVIRONMENT IKeyMintDevices must return + * ErrorCode::INVALID_ARGUMENT if they receive DEVICE_UNIQUE_ATTESTATION. + * SecurityLevel::STRONGBOX IKeyMintDevices need not support DEVICE_UNIQUE_ATTESTATION, and + * return ErrorCode::CANNOT_ATTEST_IDS if they do not support it. + * + * IKeyMintDevice implementations that support device-unique attestation MUST add the + * DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations. + */ + DEVICE_UNIQUE_ATTESTATION = (7 << 28) | 720, /* TagType:BOOL */ + + /** + * IDENTITY_CREDENTIAL_KEY is never used by IKeyMintDevice, is not a valid argument to key + * generation or any operation, is never returned by any method and is never used in a key + * attestation. It is used in attestations produced by the IIdentityCredential HAL when that + * HAL attests to Credential Keys. IIdentityCredential produces KeyMint-style attestations. + */ + IDENTITY_CREDENTIAL_KEY = (7 << 28) | 721, /* TagType:BOOL */ + + /** + * To prevent keys from being compromised if an attacker acquires read access to system / kernel + * memory, some inline encryption hardware supports protecting storage encryption keys in + * hardware without software having access to or the ability to set the plaintext keys. + * Instead, software only sees wrapped version of these keys. + * + * STORAGE_KEY is used to denote that a key generated or imported is a key used for storage + * encryption. Keys of this type can either be generated or imported or secure imported using + * keyMint. exportKey() can be used to re-wrap storage key with a per-boot ephemeral key + * wrapped key once the key characteristics are enforced. + * + * Keys with this tag cannot be used for any operation within keyMint. + * ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to + * begin(). + */ + STORAGE_KEY = (7 << 28) | 722, /* TagType:BOOL */ + + /** + * Tag::ASSOCIATED_DATA Provides "associated data" for AES-GCM encryption or decryption. This + * tag is provided to update and specifies data that is not encrypted/decrypted, but is used in + * computing the GCM tag. + * + * Must never appear KeyCharacteristics. + */ + ASSOCIATED_DATA = (9 << 28) | 1000, /* TagType:BYTES */ + + /** + * Tag::NONCE is used to provide or return a nonce or Initialization Vector (IV) for AES-GCM, + * AES-CBC, AES-CTR, or 3DES-CBC encryption or decryption. This tag is provided to begin during + * encryption and decryption operations. It is only provided to begin if the key has + * Tag::CALLER_NONCE. If not provided, an appropriate nonce or IV must be randomly generated by + * KeyMint and returned from begin. + * + * The value is a blob, an arbitrary-length array of bytes. Allowed lengths depend on the mode: + * GCM nonces are 12 bytes in length; AES-CBC and AES-CTR IVs are 16 bytes in length, 3DES-CBC + * IVs are 8 bytes in length. + * + * Must never appear in KeyCharacteristics. + */ + NONCE = (9 << 28) | 1001, /* TagType:BYTES */ + + /** + * Tag::MAC_LENGTH provides the requested length of a MAC or GCM authentication tag, in bits. + * + * The value is the MAC length in bits. It must be a multiple of 8 and at least as large as the + * value of Tag::MIN_MAC_LENGTH associated with the key. Otherwise, begin() must return + * ErrorCode::INVALID_MAC_LENGTH. + * + * Must never appear in KeyCharacteristics. + */ + MAC_LENGTH = (3 << 28) | 1003, /* TagType:UINT */ + + /** + * Tag::RESET_SINCE_ID_ROTATION specifies whether the device has been factory reset since the + * last unique ID rotation. Used for key attestation. + * + * Must never appear in KeyCharacteristics. + */ + RESET_SINCE_ID_ROTATION = (7 << 28) | 1004, /* TagType:BOOL */ + + /** + * Tag::CONFIRMATION_TOKEN is used to deliver a cryptographic token proving that the user + * confirmed a signing request. The content is a full-length HMAC-SHA256 value. See the + * ConfirmationUI HAL for details of token computation. + * + * Must never appear in KeyCharacteristics. + */ + CONFIRMATION_TOKEN = (9 << 28) | 1005, /* TagType:BYTES */ +} diff --git a/keymint/aidl/android/hardware/keymint/TagType.aidl b/keymint/aidl/android/hardware/keymint/TagType.aidl new file mode 100644 index 0000000000..fb50b10d4a --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/TagType.aidl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +/** + * TagType classifies Tags in Tag.aidl into various groups of data. + */ +@VintfStability +@Backing(type="int") +enum TagType { + /** Invalid type, used to designate a tag as uninitialized. */ + INVALID = 0 << 28, + /** Enumeration value. */ + ENUM = 1 << 28, + /** Repeatable enumeration value. */ + ENUM_REP = 2 << 28, + /** 32-bit unsigned integer. */ + UINT = 3 << 28, + /** Repeatable 32-bit unsigned integer. */ + UINT_REP = 4 << 28, + /** 64-bit unsigned integer. */ + ULONG = 5 << 28, + /** 64-bit unsigned integer representing a date and time, in milliseconds since 1 Jan 1970. */ + DATE = 6 << 28, + /** Boolean. If a tag with this type is present, the value is "true". If absent, "false". */ + BOOL = 7 << 28, + /** Byte string containing an arbitrary-length integer, big-endian ordering. */ + BIGNUM = 8 << 28, + /** Byte string */ + BYTES = 9 << 28, + /** Repeatable 64-bit unsigned integer */ + ULONG_REP = 10 << 28, +} diff --git a/keymint/aidl/android/hardware/keymint/Timestamp.aidl b/keymint/aidl/android/hardware/keymint/Timestamp.aidl new file mode 100644 index 0000000000..7c882c6811 --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/Timestamp.aidl @@ -0,0 +1,28 @@ +/* + * Copyright 2020 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. + */ + +package android.hardware.keymint; + +/** + * Time in milliseconds since some arbitrary point in time. Time must be monotonically increasing, + * and a secure environment's notion of "current time" must not repeat until the Android device + * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied + * by setting the clock to zero during each boot, and then counting time accurately). + */ +@VintfStability +parcelable Timestamp { + long milliSeconds; +} diff --git a/keymint/aidl/android/hardware/keymint/VerificationToken.aidl b/keymint/aidl/android/hardware/keymint/VerificationToken.aidl new file mode 100644 index 0000000000..736c0e2f3e --- /dev/null +++ b/keymint/aidl/android/hardware/keymint/VerificationToken.aidl @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 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. + */ + +package android.hardware.keymint; + +import android.hardware.keymint.SecurityLevel; +import android.hardware.keymint.Timestamp; + +/** + * VerificationToken instances are used for secure environments to authenticate one another. + * + * This version of the parcelable currently don't use the parametersVerified field since it's not + * needed for time-based verification. This can be added in a later version, if needed. + */ +@VintfStability +parcelable VerificationToken { + /** + * The operation handle, used to ensure freshness. + */ + long challenge; + + /** + * The current time of the secure environment that generates the VerificationToken. This can be + * checked against auth tokens generated by the same secure environment, which avoids needing to + * synchronize clocks. + */ + Timestamp timestamp; + + /** + * SecurityLevel of the secure environment that generated the token. + */ + SecurityLevel securityLevel; + + /** + * 32-byte HMAC-SHA256 of the above values, computed as: + * + * HMAC(H, + * "Auth Verification" || challenge || timestamp || securityLevel || parametersVerified) + * + * where: + * + * ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeyMint). + * + * ``||'' represents concatenation + * + * The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian + * order. securityLevel is represented as a 32-bit unsigned integer in big-endian order. + * + * If parametersVerified is non-empty, the representation of parametersVerified is an ASN.1 DER + * encoded representation of the values. The ASN.1 schema used is the AuthorizationList schema + * from the Keystore attestation documentation. If parametersVerified is empty, it is simply + * omitted from the HMAC computation. + */ + byte[] mac; +} diff --git a/keymint/aidl/default/Android.bp b/keymint/aidl/default/Android.bp new file mode 100644 index 0000000000..539ca47511 --- /dev/null +++ b/keymint/aidl/default/Android.bp @@ -0,0 +1,26 @@ +cc_binary { + name: "android.hardware.keymint@1.0-service", + relative_install_path: "hw", + init_rc: ["android.hardware.keymint@1.0-service.rc"], + vintf_fragments: ["android.hardware.keymint@1.0-service.xml"], + vendor: true, + cflags: [ + "-Wall", + "-Wextra", + ], + shared_libs: [ + "android.hardware.keymint-ndk_platform", + "libbase", + "libbinder_ndk", + "libcppbor", + "libcrypto", + "liblog", + "libkeymaster_portable", + "libkeymint1", + "libpuresoftkeymasterdevice", + "libutils", + ], + srcs: [ + "service.cpp", + ], +} diff --git a/keymint/aidl/default/android.hardware.keymint@1.0-service.rc b/keymint/aidl/default/android.hardware.keymint@1.0-service.rc new file mode 100644 index 0000000000..92dce88449 --- /dev/null +++ b/keymint/aidl/default/android.hardware.keymint@1.0-service.rc @@ -0,0 +1,3 @@ +service vendor.keymint-default /vendor/bin/hw/android.hardware.keymint@1.0-service + class early_hal + user nobody diff --git a/keymint/aidl/default/android.hardware.keymint@1.0-service.xml b/keymint/aidl/default/android.hardware.keymint@1.0-service.xml new file mode 100644 index 0000000000..3935b5a0d4 --- /dev/null +++ b/keymint/aidl/default/android.hardware.keymint@1.0-service.xml @@ -0,0 +1,6 @@ +<manifest version="1.0" type="device"> + <hal format="aidl"> + <name>android.hardware.keymint</name> + <fqname>IKeyMintDevice/default</fqname> + </hal> +</manifest> diff --git a/keymint/aidl/default/service.cpp b/keymint/aidl/default/service.cpp new file mode 100644 index 0000000000..ca5555e633 --- /dev/null +++ b/keymint/aidl/default/service.cpp @@ -0,0 +1,45 @@ +/* + * Copyright 2020, 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. + */ + +#define LOG_TAG "android.hardware.keymint1-service" + +#include <android-base/logging.h> +#include <android/binder_manager.h> +#include <android/binder_process.h> + +#include <AndroidKeyMint1Device.h> +#include <keymaster/soft_keymaster_logger.h> + +using aidl::android::hardware::keymint::SecurityLevel; +using aidl::android::hardware::keymint::V1_0::AndroidKeyMint1Device; + +int main() { + // Zero threads seems like a useless pool, but below we'll join this thread to it, increasing + // the pool size to 1. + ABinderProcess_setThreadPoolMaxThreadCount(0); + std::shared_ptr<AndroidKeyMint1Device> km5 = + ndk::SharedRefBase::make<AndroidKeyMint1Device>(SecurityLevel::SOFTWARE); + + keymaster::SoftKeymasterLogger logger; + const auto instanceName = std::string(AndroidKeyMint1Device::descriptor) + "/default"; + LOG(INFO) << "instance: " << instanceName; + binder_status_t status = + AServiceManager_addService(km5->asBinder().get(), instanceName.c_str()); + CHECK(status == STATUS_OK); + + ABinderProcess_joinThreadPool(); + return EXIT_FAILURE; // should not reach +} diff --git a/keymint/aidl/vts/functional/Android.bp b/keymint/aidl/vts/functional/Android.bp new file mode 100644 index 0000000000..9ee8239455 --- /dev/null +++ b/keymint/aidl/vts/functional/Android.bp @@ -0,0 +1,66 @@ +// +// Copyright (C) 2020 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. +// + +cc_test { + name: "VtsAidlKeyMintV1_0TargetTest", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "keyMint1Test.cpp", + "VerificationTokenTest.cpp", + ], + shared_libs: [ + "libbinder", + "libcrypto", + "libkeymint1", + "libkeymintSupport", + ], + static_libs: [ + "android.hardware.keymint-cpp", + "libcppbor", + "libkeyMint1VtsTestUtil", + ], + test_suites: [ + "general-tests", + "vts", + ], +} + +cc_test_library { + name: "libkeyMint1VtsTestUtil", + defaults: [ + "VtsHalTargetTestDefaults", + "use_libaidlvintf_gtest_helper_static", + ], + srcs: [ + "KeyMintAidlTestBase.cpp", + ], + export_include_dirs: [ + ".", + ], + shared_libs: [ + "libbinder", + "libcrypto", + "libkeymint1", + "libkeymintSupport", + ], + static_libs: [ + "android.hardware.keymint-cpp", + "libcppbor", + ], +} diff --git a/keymint/aidl/vts/functional/AndroidTest.xml b/keymint/aidl/vts/functional/AndroidTest.xml new file mode 100644 index 0000000000..43e7a8a2e7 --- /dev/null +++ b/keymint/aidl/vts/functional/AndroidTest.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 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. +--> +<configuration description="Runs VtsAidlKeyMintV1_0TargetTest."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-native" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"> + </target_preparer> + + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="VtsAidlKeyMintV1_0TargetTest->/data/local/tmp/VtsAidlKeyMintV1_0TargetTest" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="VtsAidlKeyMintV1_0TargetTest" /> + <option name="native-test-timeout" value="900000"/> + </test> +</configuration> diff --git a/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp new file mode 100644 index 0000000000..05461492be --- /dev/null +++ b/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -0,0 +1,756 @@ +/* + * Copyright (C) 2020 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. + */ + +#include "KeyMintAidlTestBase.h" + +#include <chrono> +#include <vector> + +#include <android-base/logging.h> + +#include <keymintSupport/key_param_output.h> +#include <keymintSupport/keymint_utils.h> + +namespace android { +namespace hardware { +namespace keymint { + +using namespace std::literals::chrono_literals; +using std::endl; +using std::optional; + +::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) { + if (set.size() == 0) + os << "(Empty)" << ::std::endl; + else { + os << "\n"; + for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl; + } + return os; +} + +namespace test { + +ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(Status result) { + if (result.isOk()) return ErrorCode::OK; + + if (result.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) { + return static_cast<ErrorCode>(result.serviceSpecificErrorCode()); + } + + return ErrorCode::UNKNOWN_ERROR; +} + +void KeyMintAidlTestBase::InitializeKeyMint(sp<IKeyMintDevice> keyMint) { + ASSERT_NE(keyMint, nullptr); + keymint_ = keyMint; + + KeyMintHardwareInfo info; + ASSERT_TRUE(keymint_->getHardwareInfo(&info).isOk()); + + securityLevel_ = info.securityLevel; + name_.assign(info.keyMintName.begin(), info.keyMintName.end()); + author_.assign(info.keyMintAuthorName.begin(), info.keyMintAuthorName.end()); + + os_version_ = getOsVersion(); + os_patch_level_ = getOsPatchlevel(); +} + +void KeyMintAidlTestBase::SetUp() { + InitializeKeyMint( + android::waitForDeclaredService<IKeyMintDevice>(String16(GetParam().c_str()))); +} + +ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc, + vector<uint8_t>* keyBlob, KeyCharacteristics* keyChar) { + EXPECT_NE(keyBlob, nullptr) << "Key blob pointer must not be null. Test bug"; + EXPECT_NE(keyChar, nullptr) + << "Previous characteristics not deleted before generating key. Test bug."; + + // Aidl does not clear these output parameters if the function returns + // error. This is different from hal where output parameter is always + // cleared due to hal returning void. So now we need to do our own clearing + // of the output variables prior to calling keyMint aidl libraries. + keyBlob->clear(); + keyChar->softwareEnforced.clear(); + keyChar->hardwareEnforced.clear(); + certChain_.clear(); + + Status result; + ByteArray blob; + + result = keymint_->generateKey(key_desc.vector_data(), &blob, keyChar, &certChain_); + + // On result, blob & characteristics should be empty. + if (result.isOk()) { + if (SecLevel() != SecurityLevel::SOFTWARE) { + EXPECT_GT(keyChar->hardwareEnforced.size(), 0); + } + EXPECT_GT(keyChar->softwareEnforced.size(), 0); + // TODO(seleneh) in a later version where we return @nullable + // single Certificate, check non-null single certificate is always + // non-empty. + *keyBlob = blob.data; + } + + return GetReturnErrorCode(result); +} + +ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc) { + return GenerateKey(key_desc, &key_blob_, &key_characteristics_); +} + +ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format, + const string& key_material, vector<uint8_t>* key_blob, + KeyCharacteristics* key_characteristics) { + Status result; + + certChain_.clear(); + key_characteristics->softwareEnforced.clear(); + key_characteristics->hardwareEnforced.clear(); + key_blob->clear(); + + ByteArray blob; + result = keymint_->importKey(key_desc.vector_data(), format, + vector<uint8_t>(key_material.begin(), key_material.end()), &blob, + key_characteristics, &certChain_); + + if (result.isOk()) { + if (SecLevel() != SecurityLevel::SOFTWARE) { + EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0); + } + EXPECT_GT(key_characteristics->softwareEnforced.size(), 0); + *key_blob = blob.data; + } + + return GetReturnErrorCode(result); +} + +ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format, + const string& key_material) { + return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_); +} + +ErrorCode KeyMintAidlTestBase::ImportWrappedKey(string wrapped_key, string wrapping_key, + const AuthorizationSet& wrapping_key_desc, + string masking_key, + const AuthorizationSet& unwrapping_params) { + Status result; + EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key)); + + ByteArray outBlob; + key_characteristics_.softwareEnforced.clear(); + key_characteristics_.hardwareEnforced.clear(); + + result = keymint_->importWrappedKey(vector<uint8_t>(wrapped_key.begin(), wrapped_key.end()), + key_blob_, + vector<uint8_t>(masking_key.begin(), masking_key.end()), + unwrapping_params.vector_data(), 0 /* passwordSid */, + 0 /* biometricSid */, &outBlob, &key_characteristics_); + + if (result.isOk()) { + key_blob_ = outBlob.data; + if (SecLevel() != SecurityLevel::SOFTWARE) { + EXPECT_GT(key_characteristics_.hardwareEnforced.size(), 0); + } + EXPECT_GT(key_characteristics_.softwareEnforced.size(), 0); + } + + return GetReturnErrorCode(result); +} + +ErrorCode KeyMintAidlTestBase::DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) { + Status result = keymint_->deleteKey(*key_blob); + if (!keep_key_blob) { + *key_blob = vector<uint8_t>(); + } + + EXPECT_TRUE(result.isOk()) << result.serviceSpecificErrorCode() << endl; + return GetReturnErrorCode(result); +} + +ErrorCode KeyMintAidlTestBase::DeleteKey(bool keep_key_blob) { + return DeleteKey(&key_blob_, keep_key_blob); +} + +ErrorCode KeyMintAidlTestBase::DeleteAllKeys() { + Status result = keymint_->deleteAllKeys(); + EXPECT_TRUE(result.isOk()) << result.serviceSpecificErrorCode() << endl; + return GetReturnErrorCode(result); +} + +void KeyMintAidlTestBase::CheckedDeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) { + ErrorCode result = DeleteKey(key_blob, keep_key_blob); + EXPECT_TRUE(result == ErrorCode::OK || result == ErrorCode::UNIMPLEMENTED) << result << endl; +} + +void KeyMintAidlTestBase::CheckedDeleteKey() { + CheckedDeleteKey(&key_blob_); +} + +ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob, + const AuthorizationSet& in_params, + AuthorizationSet* out_params, sp<IKeyMintOperation>& op) { + SCOPED_TRACE("Begin"); + Status result; + BeginResult out; + result = keymint_->begin(purpose, key_blob, in_params.vector_data(), HardwareAuthToken(), &out); + + if (result.isOk()) { + *out_params = out.params; + challenge_ = out.challenge; + op = out.operation; + } + + return GetReturnErrorCode(result); +} + +ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob, + const AuthorizationSet& in_params, + AuthorizationSet* out_params) { + SCOPED_TRACE("Begin"); + Status result; + BeginResult out; + + result = keymint_->begin(purpose, key_blob, in_params.vector_data(), HardwareAuthToken(), &out); + + if (result.isOk()) { + *out_params = out.params; + challenge_ = out.challenge; + op_ = out.operation; + } + + return GetReturnErrorCode(result); +} + +ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const AuthorizationSet& in_params, + AuthorizationSet* out_params) { + SCOPED_TRACE("Begin"); + EXPECT_EQ(nullptr, op_); + return Begin(purpose, key_blob_, in_params, out_params); +} + +ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const AuthorizationSet& in_params) { + SCOPED_TRACE("Begin"); + AuthorizationSet out_params; + ErrorCode result = Begin(purpose, in_params, &out_params); + EXPECT_TRUE(out_params.empty()); + return result; +} + +ErrorCode KeyMintAidlTestBase::Update(const AuthorizationSet& in_params, const string& input, + AuthorizationSet* out_params, string* output, + int32_t* input_consumed) { + SCOPED_TRACE("Update"); + + Status result; + EXPECT_NE(op_, nullptr); + if (!op_) { + return ErrorCode::UNEXPECTED_NULL_POINTER; + } + + KeyParameterArray key_params; + key_params.params = in_params.vector_data(); + + KeyParameterArray in_keyParams; + in_keyParams.params = in_params.vector_data(); + + optional<KeyParameterArray> out_keyParams; + optional<ByteArray> o_put; + result = op_->update(in_keyParams, vector<uint8_t>(input.begin(), input.end()), {}, {}, + &out_keyParams, &o_put, input_consumed); + + if (result.isOk()) { + if (o_put) { + output->append(o_put->data.begin(), o_put->data.end()); + } + + if (out_keyParams) { + out_params->push_back(AuthorizationSet(out_keyParams->params)); + } + } + + return GetReturnErrorCode(result); +} + +ErrorCode KeyMintAidlTestBase::Update(const string& input, string* out, int32_t* input_consumed) { + SCOPED_TRACE("Update"); + AuthorizationSet out_params; + ErrorCode result = + Update(AuthorizationSet() /* in_params */, input, &out_params, out, input_consumed); + EXPECT_TRUE(out_params.empty()); + return result; +} + +ErrorCode KeyMintAidlTestBase::Finish(const AuthorizationSet& in_params, const string& input, + const string& signature, AuthorizationSet* out_params, + string* output) { + SCOPED_TRACE("Finish"); + Status result; + + EXPECT_NE(op_, nullptr); + if (!op_) { + return ErrorCode::UNEXPECTED_NULL_POINTER; + } + + KeyParameterArray key_params; + key_params.params = in_params.vector_data(); + + KeyParameterArray in_keyParams; + in_keyParams.params = in_params.vector_data(); + + optional<KeyParameterArray> out_keyParams; + optional<vector<uint8_t>> o_put; + + vector<uint8_t> oPut; + result = op_->finish(in_keyParams, vector<uint8_t>(input.begin(), input.end()), + vector<uint8_t>(signature.begin(), signature.end()), {}, {}, + &out_keyParams, &oPut); + + if (result.isOk()) { + if (out_keyParams) { + out_params->push_back(AuthorizationSet(out_keyParams->params)); + } + + output->append(oPut.begin(), oPut.end()); + } + + op_.clear(); // So dtor doesn't Abort(). + return GetReturnErrorCode(result); +} + +ErrorCode KeyMintAidlTestBase::Finish(const string& message, string* output) { + SCOPED_TRACE("Finish"); + AuthorizationSet out_params; + string finish_output; + ErrorCode result = Finish(AuthorizationSet() /* in_params */, message, "" /* signature */, + &out_params, output); + if (result != ErrorCode::OK) { + return result; + } + EXPECT_EQ(0U, out_params.size()); + return result; +} + +ErrorCode KeyMintAidlTestBase::Finish(const string& message, const string& signature, + string* output) { + SCOPED_TRACE("Finish"); + AuthorizationSet out_params; + ErrorCode result = + Finish(AuthorizationSet() /* in_params */, message, signature, &out_params, output); + + if (result != ErrorCode::OK) { + return result; + } + + EXPECT_EQ(0U, out_params.size()); + return result; +} + +ErrorCode KeyMintAidlTestBase::Abort(const sp<IKeyMintOperation>& op) { + SCOPED_TRACE("Abort"); + + EXPECT_NE(op, nullptr); + if (!op) { + return ErrorCode::UNEXPECTED_NULL_POINTER; + } + + Status retval = op->abort(); + EXPECT_TRUE(retval.isOk()); + return static_cast<ErrorCode>(retval.serviceSpecificErrorCode()); +} + +ErrorCode KeyMintAidlTestBase::Abort() { + SCOPED_TRACE("Abort"); + + EXPECT_NE(op_, nullptr); + if (!op_) { + return ErrorCode::UNEXPECTED_NULL_POINTER; + } + + Status retval = op_->abort(); + return static_cast<ErrorCode>(retval.serviceSpecificErrorCode()); +} + +void KeyMintAidlTestBase::AbortIfNeeded() { + SCOPED_TRACE("AbortIfNeeded"); + if (op_) { + EXPECT_EQ(ErrorCode::OK, Abort()); + op_.clear(); + } +} + +string KeyMintAidlTestBase::ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation, + const string& message, const AuthorizationSet& in_params, + AuthorizationSet* out_params) { + SCOPED_TRACE("ProcessMessage"); + AuthorizationSet begin_out_params; + ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params); + EXPECT_EQ(ErrorCode::OK, result); + if (result != ErrorCode::OK) { + return ""; + } + + string output; + int32_t consumed = 0; + AuthorizationSet update_params; + AuthorizationSet update_out_params; + result = Update(update_params, message, &update_out_params, &output, &consumed); + EXPECT_EQ(ErrorCode::OK, result); + if (result != ErrorCode::OK) { + return ""; + } + + string unused; + AuthorizationSet finish_params; + AuthorizationSet finish_out_params; + EXPECT_EQ(ErrorCode::OK, + Finish(finish_params, message.substr(consumed), unused, &finish_out_params, &output)); + + out_params->push_back(begin_out_params); + out_params->push_back(finish_out_params); + return output; +} + +string KeyMintAidlTestBase::SignMessage(const vector<uint8_t>& key_blob, const string& message, + const AuthorizationSet& params) { + SCOPED_TRACE("SignMessage"); + AuthorizationSet out_params; + string signature = ProcessMessage(key_blob, KeyPurpose::SIGN, message, params, &out_params); + EXPECT_TRUE(out_params.empty()); + return signature; +} + +string KeyMintAidlTestBase::SignMessage(const string& message, const AuthorizationSet& params) { + SCOPED_TRACE("SignMessage"); + return SignMessage(key_blob_, message, params); +} + +string KeyMintAidlTestBase::MacMessage(const string& message, Digest digest, size_t mac_length) { + SCOPED_TRACE("MacMessage"); + return SignMessage( + key_blob_, message, + AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length)); +} + +void KeyMintAidlTestBase::CheckHmacTestVector(const string& key, const string& message, + Digest digest, const string& expected_mac) { + SCOPED_TRACE("CheckHmacTestVector"); + ASSERT_EQ(ErrorCode::OK, + ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .HmacKey(key.size() * 8) + .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8) + .Digest(digest), + KeyFormat::RAW, key)); + string signature = MacMessage(message, digest, expected_mac.size() * 8); + EXPECT_EQ(expected_mac, signature) + << "Test vector didn't match for key of size " << key.size() << " message of size " + << message.size() << " and digest " << digest; + CheckedDeleteKey(); +} + +void KeyMintAidlTestBase::CheckAesCtrTestVector(const string& key, const string& nonce, + const string& message, + const string& expected_ciphertext) { + SCOPED_TRACE("CheckAesCtrTestVector"); + ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(key.size() * 8) + .BlockMode(BlockMode::CTR) + .Authorization(TAG_CALLER_NONCE) + .Padding(PaddingMode::NONE), + KeyFormat::RAW, key)); + + auto params = AuthorizationSetBuilder() + .Authorization(TAG_NONCE, nonce.data(), nonce.size()) + .BlockMode(BlockMode::CTR) + .Padding(PaddingMode::NONE); + AuthorizationSet out_params; + string ciphertext = EncryptMessage(key_blob_, message, params, &out_params); + EXPECT_EQ(expected_ciphertext, ciphertext); +} + +void KeyMintAidlTestBase::CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode, + PaddingMode padding_mode, const string& key, + const string& iv, const string& input, + const string& expected_output) { + auto authset = AuthorizationSetBuilder() + .TripleDesEncryptionKey(key.size() * 7) + .BlockMode(block_mode) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(padding_mode); + if (iv.size()) authset.Authorization(TAG_CALLER_NONCE); + ASSERT_EQ(ErrorCode::OK, ImportKey(authset, KeyFormat::RAW, key)); + ASSERT_GT(key_blob_.size(), 0U); + + auto begin_params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding_mode); + if (iv.size()) begin_params.Authorization(TAG_NONCE, iv.data(), iv.size()); + AuthorizationSet output_params; + string output = ProcessMessage(key_blob_, purpose, input, begin_params, &output_params); + EXPECT_EQ(expected_output, output); +} + +void KeyMintAidlTestBase::VerifyMessage(const vector<uint8_t>& key_blob, const string& message, + const string& signature, const AuthorizationSet& params) { + SCOPED_TRACE("VerifyMessage"); + AuthorizationSet begin_out_params; + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::VERIFY, key_blob, params, &begin_out_params)); + + string output; + AuthorizationSet update_params; + AuthorizationSet update_out_params; + int32_t consumed; + ASSERT_EQ(ErrorCode::OK, + Update(update_params, message, &update_out_params, &output, &consumed)); + EXPECT_TRUE(output.empty()); + EXPECT_GT(consumed, 0U); + + string unused; + AuthorizationSet finish_params; + AuthorizationSet finish_out_params; + EXPECT_EQ(ErrorCode::OK, Finish(finish_params, message.substr(consumed), signature, + &finish_out_params, &output)); + op_.clear(); + EXPECT_TRUE(output.empty()); +} + +void KeyMintAidlTestBase::VerifyMessage(const string& message, const string& signature, + const AuthorizationSet& params) { + SCOPED_TRACE("VerifyMessage"); + VerifyMessage(key_blob_, message, signature, params); +} + +string KeyMintAidlTestBase::EncryptMessage(const vector<uint8_t>& key_blob, const string& message, + const AuthorizationSet& in_params, + AuthorizationSet* out_params) { + SCOPED_TRACE("EncryptMessage"); + return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params); +} + +string KeyMintAidlTestBase::EncryptMessage(const string& message, const AuthorizationSet& params, + AuthorizationSet* out_params) { + SCOPED_TRACE("EncryptMessage"); + return EncryptMessage(key_blob_, message, params, out_params); +} + +string KeyMintAidlTestBase::EncryptMessage(const string& message, const AuthorizationSet& params) { + SCOPED_TRACE("EncryptMessage"); + AuthorizationSet out_params; + string ciphertext = EncryptMessage(message, params, &out_params); + EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params; + return ciphertext; +} + +string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode, + PaddingMode padding) { + SCOPED_TRACE("EncryptMessage"); + auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding); + AuthorizationSet out_params; + string ciphertext = EncryptMessage(message, params, &out_params); + EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params; + return ciphertext; +} + +string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode, + PaddingMode padding, vector<uint8_t>* iv_out) { + SCOPED_TRACE("EncryptMessage"); + auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding); + AuthorizationSet out_params; + string ciphertext = EncryptMessage(message, params, &out_params); + EXPECT_EQ(1U, out_params.size()); + auto ivVal = out_params.GetTagValue(TAG_NONCE); + EXPECT_TRUE(ivVal.isOk()); + if (ivVal.isOk()) *iv_out = ivVal.value(); + return ciphertext; +} + +string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode, + PaddingMode padding, const vector<uint8_t>& iv_in) { + SCOPED_TRACE("EncryptMessage"); + auto params = AuthorizationSetBuilder() + .BlockMode(block_mode) + .Padding(padding) + .Authorization(TAG_NONCE, iv_in); + AuthorizationSet out_params; + string ciphertext = EncryptMessage(message, params, &out_params); + return ciphertext; +} + +string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode, + PaddingMode padding, uint8_t mac_length_bits, + const vector<uint8_t>& iv_in) { + SCOPED_TRACE("EncryptMessage"); + auto params = AuthorizationSetBuilder() + .BlockMode(block_mode) + .Padding(padding) + .Authorization(TAG_MAC_LENGTH, mac_length_bits) + .Authorization(TAG_NONCE, iv_in); + AuthorizationSet out_params; + string ciphertext = EncryptMessage(message, params, &out_params); + return ciphertext; +} + +string KeyMintAidlTestBase::DecryptMessage(const vector<uint8_t>& key_blob, + const string& ciphertext, + const AuthorizationSet& params) { + SCOPED_TRACE("DecryptMessage"); + AuthorizationSet out_params; + string plaintext = + ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params); + EXPECT_TRUE(out_params.empty()); + return plaintext; +} + +string KeyMintAidlTestBase::DecryptMessage(const string& ciphertext, + const AuthorizationSet& params) { + SCOPED_TRACE("DecryptMessage"); + return DecryptMessage(key_blob_, ciphertext, params); +} + +string KeyMintAidlTestBase::DecryptMessage(const string& ciphertext, BlockMode block_mode, + PaddingMode padding_mode, const vector<uint8_t>& iv) { + SCOPED_TRACE("DecryptMessage"); + auto params = AuthorizationSetBuilder() + .BlockMode(block_mode) + .Padding(padding_mode) + .Authorization(TAG_NONCE, iv); + return DecryptMessage(key_blob_, ciphertext, params); +} + +std::pair<ErrorCode, vector<uint8_t>> KeyMintAidlTestBase::UpgradeKey( + const vector<uint8_t>& key_blob) { + std::pair<ErrorCode, vector<uint8_t>> retval; + vector<uint8_t> outKeyBlob; + Status result = keymint_->upgradeKey(key_blob, vector<KeyParameter>(), &outKeyBlob); + ErrorCode errorcode = GetReturnErrorCode(result); + retval = std::tie(errorcode, outKeyBlob); + + return retval; +} +vector<uint32_t> KeyMintAidlTestBase::ValidKeySizes(Algorithm algorithm) { + switch (algorithm) { + case Algorithm::RSA: + switch (SecLevel()) { + case SecurityLevel::SOFTWARE: + case SecurityLevel::TRUSTED_ENVIRONMENT: + return {2048, 3072, 4096}; + case SecurityLevel::STRONGBOX: + return {2048}; + default: + ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel()); + break; + } + break; + case Algorithm::EC: + switch (SecLevel()) { + case SecurityLevel::SOFTWARE: + case SecurityLevel::TRUSTED_ENVIRONMENT: + return {224, 256, 384, 521}; + case SecurityLevel::STRONGBOX: + return {256}; + default: + ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel()); + break; + } + break; + case Algorithm::AES: + return {128, 256}; + case Algorithm::TRIPLE_DES: + return {168}; + case Algorithm::HMAC: { + vector<uint32_t> retval((512 - 64) / 8 + 1); + uint32_t size = 64 - 8; + std::generate(retval.begin(), retval.end(), [&]() { return (size += 8); }); + return retval; + } + default: + ADD_FAILURE() << "Invalid Algorithm: " << algorithm; + return {}; + } + ADD_FAILURE() << "Should be impossible to get here"; + return {}; +} + +vector<uint32_t> KeyMintAidlTestBase::InvalidKeySizes(Algorithm algorithm) { + if (SecLevel() == SecurityLevel::STRONGBOX) { + switch (algorithm) { + case Algorithm::RSA: + return {3072, 4096}; + case Algorithm::EC: + return {224, 384, 521}; + case Algorithm::AES: + return {192}; + default: + return {}; + } + } + return {}; +} + +vector<EcCurve> KeyMintAidlTestBase::ValidCurves() { + if (securityLevel_ == SecurityLevel::STRONGBOX) { + return {EcCurve::P_256}; + } else { + return {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}; + } +} + +vector<EcCurve> KeyMintAidlTestBase::InvalidCurves() { + if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {}; + CHECK(SecLevel() == SecurityLevel::STRONGBOX); + return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521}; +} + +vector<Digest> KeyMintAidlTestBase::ValidDigests(bool withNone, bool withMD5) { + switch (SecLevel()) { + case SecurityLevel::SOFTWARE: + case SecurityLevel::TRUSTED_ENVIRONMENT: + if (withNone) { + if (withMD5) + return {Digest::NONE, Digest::MD5, Digest::SHA1, + Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384, + Digest::SHA_2_512}; + else + return {Digest::NONE, Digest::SHA1, Digest::SHA_2_224, + Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512}; + } else { + if (withMD5) + return {Digest::MD5, Digest::SHA1, Digest::SHA_2_224, + Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512}; + else + return {Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384, + Digest::SHA_2_512}; + } + break; + case SecurityLevel::STRONGBOX: + if (withNone) + return {Digest::NONE, Digest::SHA_2_256}; + else + return {Digest::SHA_2_256}; + break; + default: + ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel()); + break; + } + ADD_FAILURE() << "Should be impossible to get here"; + return {}; +} + +} // namespace test +} // namespace keymint +} // namespace hardware +} // namespace android diff --git a/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/keymint/aidl/vts/functional/KeyMintAidlTestBase.h new file mode 100644 index 0000000000..2948c41eae --- /dev/null +++ b/keymint/aidl/vts/functional/KeyMintAidlTestBase.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2020 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. + */ + +#ifndef VTS_KEYMINT_AIDL_TEST_UTILS_H +#define VTS_KEYMINT_AIDL_TEST_UTILS_H + +#pragma once + +#include <aidl/Gtest.h> +#include <aidl/Vintf.h> +#include <android/hardware/keymint/ErrorCode.h> +#include <android/hardware/keymint/IKeyMintDevice.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <gtest/gtest.h> + +#include <keymintSupport/authorization_set.h> + +namespace android { +namespace hardware { +namespace keymint { +namespace test { + +using ::android::sp; +using binder::Status; +using ::std::shared_ptr; +using ::std::string; +using ::std::vector; + +constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF; + +::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set); + +class KeyMintAidlTestBase : public ::testing::TestWithParam<string> { + public: + void SetUp() override; + void TearDown() override { + if (key_blob_.size()) { + CheckedDeleteKey(); + } + AbortIfNeeded(); + } + + void InitializeKeyMint(sp<IKeyMintDevice> keyMint); + IKeyMintDevice& keyMint() { return *keymint_; } + uint32_t os_version() { return os_version_; } + uint32_t os_patch_level() { return os_patch_level_; } + + ErrorCode GetReturnErrorCode(Status result); + ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob, + KeyCharacteristics* key_characteristics); + + ErrorCode GenerateKey(const AuthorizationSet& key_desc); + + ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format, + const string& key_material, vector<uint8_t>* key_blob, + KeyCharacteristics* key_characteristics); + ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format, + const string& key_material); + + ErrorCode ImportWrappedKey(string wrapped_key, string wrapping_key, + const AuthorizationSet& wrapping_key_desc, string masking_key, + const AuthorizationSet& unwrapping_params); + + ErrorCode DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false); + ErrorCode DeleteKey(bool keep_key_blob = false); + + ErrorCode DeleteAllKeys(); + + void CheckedDeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false); + void CheckedDeleteKey(); + + ErrorCode Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob, + const AuthorizationSet& in_params, AuthorizationSet* out_params, + sp<IKeyMintOperation>& op); + ErrorCode Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob, + const AuthorizationSet& in_params, AuthorizationSet* out_params); + ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params, + AuthorizationSet* out_params); + ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params); + + ErrorCode Update(const AuthorizationSet& in_params, const string& input, + AuthorizationSet* out_params, string* output, int32_t* input_consumed); + ErrorCode Update(const string& input, string* out, int32_t* input_consumed); + + ErrorCode Finish(const AuthorizationSet& in_params, const string& input, + const string& signature, AuthorizationSet* out_params, string* output); + ErrorCode Finish(const string& message, string* output); + ErrorCode Finish(const string& message, const string& signature, string* output); + ErrorCode Finish(string* output) { return Finish(string(), output); } + + ErrorCode Abort(); + ErrorCode Abort(const sp<IKeyMintOperation>& op); + void AbortIfNeeded(); + + string ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation, + const string& message, const AuthorizationSet& in_params, + AuthorizationSet* out_params); + + string SignMessage(const vector<uint8_t>& key_blob, const string& message, + const AuthorizationSet& params); + string SignMessage(const string& message, const AuthorizationSet& params); + + string MacMessage(const string& message, Digest digest, size_t mac_length); + + void CheckHmacTestVector(const string& key, const string& message, Digest digest, + const string& expected_mac); + + void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message, + const string& expected_ciphertext); + + void CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode, + PaddingMode padding_mode, const string& key, const string& iv, + const string& input, const string& expected_output); + + void VerifyMessage(const vector<uint8_t>& key_blob, const string& message, + const string& signature, const AuthorizationSet& params); + void VerifyMessage(const string& message, const string& signature, + const AuthorizationSet& params); + + string EncryptMessage(const vector<uint8_t>& key_blob, const string& message, + const AuthorizationSet& in_params, AuthorizationSet* out_params); + string EncryptMessage(const string& message, const AuthorizationSet& params, + AuthorizationSet* out_params); + string EncryptMessage(const string& message, const AuthorizationSet& params); + string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding); + string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding, + vector<uint8_t>* iv_out); + string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding, + const vector<uint8_t>& iv_in); + string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding, + uint8_t mac_length_bits, const vector<uint8_t>& iv_in); + + string DecryptMessage(const vector<uint8_t>& key_blob, const string& ciphertext, + const AuthorizationSet& params); + string DecryptMessage(const string& ciphertext, const AuthorizationSet& params); + string DecryptMessage(const string& ciphertext, BlockMode block_mode, PaddingMode padding_mode, + const vector<uint8_t>& iv); + + std::pair<ErrorCode, vector<uint8_t>> UpgradeKey(const vector<uint8_t>& key_blob); + + bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; } + SecurityLevel SecLevel() { return securityLevel_; } + + vector<uint32_t> ValidKeySizes(Algorithm algorithm); + vector<uint32_t> InvalidKeySizes(Algorithm algorithm); + + vector<EcCurve> ValidCurves(); + vector<EcCurve> InvalidCurves(); + + vector<Digest> ValidDigests(bool withNone, bool withMD5); + + static vector<string> build_params() { + auto params = android::getAidlHalInstanceNames(IKeyMintDevice::descriptor); + return params; + } + + sp<IKeyMintOperation> op_; + vector<Certificate> certChain_; + vector<uint8_t> key_blob_; + KeyCharacteristics key_characteristics_; + + private: + sp<IKeyMintDevice> keymint_; + uint32_t os_version_; + uint32_t os_patch_level_; + + SecurityLevel securityLevel_; + string name_; + string author_; + long challenge_; +}; + +#define INSTANTIATE_KEYMINT_AIDL_TEST(name) \ + INSTANTIATE_TEST_SUITE_P(PerInstance, name, \ + testing::ValuesIn(KeyMintAidlTestBase::build_params()), \ + android::PrintInstanceNameToString) + +} // namespace test +} // namespace keymint +} // namespace hardware +} // namespace android + +#endif // VTS_KEYMINT_AIDL_TEST_UTILS_H diff --git a/keymint/aidl/vts/functional/VerificationTokenTest.cpp b/keymint/aidl/vts/functional/VerificationTokenTest.cpp new file mode 100644 index 0000000000..bd0942ba10 --- /dev/null +++ b/keymint/aidl/vts/functional/VerificationTokenTest.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2020 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. + */ + +#include "KeyMintAidlTestBase.h" + +namespace android { +namespace hardware { +namespace keymint { +namespace test { + +class VerificationTokenTest : public KeyMintAidlTestBase { + protected: + struct VerifyAuthorizationResult { + ErrorCode error; + VerificationToken token; + }; + + VerifyAuthorizationResult verifyAuthorization(uint64_t operationHandle, + const HardwareAuthToken& authToken) { + VerifyAuthorizationResult result; + + Status err; + err = keyMint().verifyAuthorization(operationHandle, // + authToken, // + &result.token); + + result.error = GetReturnErrorCode(err); + return result; + } + + uint64_t getTime() { + struct timespec timespec; + EXPECT_EQ(0, clock_gettime(CLOCK_BOOTTIME, ×pec)); + return timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000; + } + + int sleep_ms(uint32_t milliseconds) { + struct timespec sleep_time = {static_cast<time_t>(milliseconds / 1000), + static_cast<long>(milliseconds % 1000) * 1000000}; + while (sleep_time.tv_sec || sleep_time.tv_nsec) { + if (nanosleep(&sleep_time /* to wait */, + &sleep_time /* remaining (on interrruption) */) == 0) { + sleep_time = {}; + } else { + if (errno != EINTR) return errno; + } + } + return 0; + } +}; + +/* + * VerificationTokens exist to facilitate cross-KeyMint verification of requirements. As + * such, the precise capabilities required will vary depending on the specific vendor + * implementations. Essentially, VerificationTokens are a "hook" to enable vendor + * implementations to communicate, so the precise usage is defined by those vendors. The only + * thing we really can test is that tokens can be created by TEE keyMints, and that the + * timestamps increase as expected. + */ +TEST_P(VerificationTokenTest, TestCreation) { + auto result1 = verifyAuthorization(1 /* operation handle */, HardwareAuthToken()); + auto result1_time = getTime(); + + if (SecLevel() == SecurityLevel::STRONGBOX) { + // StrongBox should not implement verifyAuthorization. + EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error); + return; + } + + ASSERT_EQ(ErrorCode::OK, result1.error); + EXPECT_EQ(1U, result1.token.challenge); + EXPECT_EQ(SecLevel(), result1.token.securityLevel); + EXPECT_GT(result1.token.timestamp.milliSeconds, 0U); + + constexpr uint32_t time_to_sleep = 200; + sleep_ms(time_to_sleep); + + auto result2 = verifyAuthorization(2 /* operation handle */, HardwareAuthToken()); + + auto result2_time = getTime(); + ASSERT_EQ(ErrorCode::OK, result2.error); + EXPECT_EQ(2U, result2.token.challenge); + EXPECT_EQ(SecLevel(), result2.token.securityLevel); + + auto host_time_delta = result2_time - result1_time; + + EXPECT_GE(host_time_delta, time_to_sleep) + << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much"; + EXPECT_LE(host_time_delta, time_to_sleep + 20) + << "The verifyAuthorization call took " << (host_time_delta - time_to_sleep) + << " ms? That's awful!"; + + auto km_time_delta = + result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds; + + // If not too much else is going on on the system, the time delta should be quite close. Allow + // 2 ms of slop just to avoid test flakiness. + // + // TODO(swillden): see if we can output values so they can be gathered across many runs and + // report if times aren't nearly always <1ms apart. + EXPECT_LE(host_time_delta, km_time_delta + 2); + EXPECT_LE(km_time_delta, host_time_delta + 2); + ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size()); + ASSERT_NE(0, + memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size())); +} + +/* + * Test that the mac changes when the time stamp changes. This is does not guarantee that the time + * stamp is included in the mac but on failure we know that it is not. Other than in the test + * case above we call verifyAuthorization with the exact same set of parameters. + */ +TEST_P(VerificationTokenTest, MacChangesOnChangingTimestamp) { + auto result1 = verifyAuthorization(0 /* operation handle */, HardwareAuthToken()); + auto result1_time = getTime(); + + if (SecLevel() == SecurityLevel::STRONGBOX) { + // StrongBox should not implement verifyAuthorization. + EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error); + return; + } + + EXPECT_EQ(ErrorCode::OK, result1.error); + EXPECT_EQ(0U, result1.token.challenge); + EXPECT_EQ(SecLevel(), result1.token.securityLevel); + EXPECT_GT(result1.token.timestamp.milliSeconds, 0U); + + constexpr uint32_t time_to_sleep = 200; + sleep_ms(time_to_sleep); + + auto result2 = verifyAuthorization(0 /* operation handle */, HardwareAuthToken()); + // ASSERT_TRUE(result2.callSuccessful); + auto result2_time = getTime(); + EXPECT_EQ(ErrorCode::OK, result2.error); + EXPECT_EQ(0U, result2.token.challenge); + EXPECT_EQ(SecLevel(), result2.token.securityLevel); + + auto host_time_delta = result2_time - result1_time; + + EXPECT_GE(host_time_delta, time_to_sleep) + << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much"; + EXPECT_LE(host_time_delta, time_to_sleep + 20) + << "The verifyAuthorization call took " << (host_time_delta - time_to_sleep) + << " ms? That's awful!"; + + auto km_time_delta = + result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds; + + EXPECT_LE(host_time_delta, km_time_delta + 2); + EXPECT_LE(km_time_delta, host_time_delta + 2); + ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size()); + ASSERT_NE(0, + memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size())); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(VerificationTokenTest); + +} // namespace test +} // namespace keymint +} // namespace hardware +} // namespace android diff --git a/keymint/aidl/vts/functional/keyMint1Test.cpp b/keymint/aidl/vts/functional/keyMint1Test.cpp new file mode 100644 index 0000000000..c2fa2f8588 --- /dev/null +++ b/keymint/aidl/vts/functional/keyMint1Test.cpp @@ -0,0 +1,4069 @@ +/* + * Copyright (C) 2020 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. + */ + +#define LOG_TAG "keymint_5_test" +#include <cutils/log.h> + +#include <signal.h> +#include <iostream> + +#include <openssl/evp.h> +#include <openssl/mem.h> +#include <openssl/x509.h> + +#include <cutils/properties.h> + +#include <android/hardware/keymint/KeyFormat.h> + +#include <keymintSupport/attestation_record.h> +#include <keymintSupport/key_param_output.h> +#include <keymintSupport/openssl_utils.h> + +#include "KeyMintAidlTestBase.h" + +static bool arm_deleteAllKeys = false; +static bool dump_Attestations = false; + +using android::hardware::keymint::AuthorizationSet; +using android::hardware::keymint::KeyCharacteristics; +using android::hardware::keymint::KeyFormat; + +namespace android { +namespace hardware { + +namespace keymint { + +bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) { + return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); +} +} // namespace keymint +} // namespace hardware +} // namespace android + +namespace std { + +using namespace android::hardware::keymint; + +template <> +struct std::equal_to<KeyCharacteristics> { + bool operator()(const KeyCharacteristics& a, const KeyCharacteristics& b) const { + // This isn't very efficient. Oh, well. + AuthorizationSet a_sw(a.softwareEnforced); + AuthorizationSet b_sw(b.softwareEnforced); + AuthorizationSet a_tee(b.hardwareEnforced); + AuthorizationSet b_tee(b.hardwareEnforced); + + a_sw.Sort(); + b_sw.Sort(); + a_tee.Sort(); + b_tee.Sort(); + + return ((a_sw == b_sw) && (a_tee == b_tee)); + } +}; + +} // namespace std + +namespace android { +namespace hardware { +namespace keymint { +namespace test { +namespace { + +template <TagType tag_type, Tag tag, typename ValueT> +bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) { + auto it = std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) { + return param.tag == tag && accessTagValue(ttag, param) == expected_value; + }); + return (it != set.end()); +} + +template <TagType tag_type, Tag tag> +bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag>) { + auto it = std::find_if(set.begin(), set.end(), + [&](const KeyParameter& param) { return param.tag == tag; }); + return (it != set.end()); +} + +constexpr char hex_value[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +string hex2str(string a) { + string b; + size_t num = a.size() / 2; + b.resize(num); + for (size_t i = 0; i < num; i++) { + b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]); + } + return b; +} + +string rsa_key = + hex2str("30820275020100300d06092a864886f70d01010105000482025f3082025b" + "02010002818100c6095409047d8634812d5a218176e45c41d60a75b13901" + "f234226cffe776521c5a77b9e389417b71c0b6a44d13afe4e4a2805d46c9" + "da2935adb1ff0c1f24ea06e62b20d776430a4d435157233c6f916783c30e" + "310fcbd89b85c2d56771169785ac12bca244abda72bfb19fc44d27c81e1d" + "92de284f4061edfd99280745ea6d2502030100010281801be0f04d9cae37" + "18691f035338308e91564b55899ffb5084d2460e6630257e05b3ceab0297" + "2dfabcd6ce5f6ee2589eb67911ed0fac16e43a444b8c861e544a05933657" + "72f8baf6b22fc9e3c5f1024b063ac080a7b2234cf8aee8f6c47bbf4fd3ac" + "e7240290bef16c0b3f7f3cdd64ce3ab5912cf6e32f39ab188358afcccd80" + "81024100e4b49ef50f765d3b24dde01aceaaf130f2c76670a91a61ae08af" + "497b4a82be6dee8fcdd5e3f7ba1cfb1f0c926b88f88c92bfab137fba2285" + "227b83c342ff7c55024100ddabb5839c4c7f6bf3d4183231f005b31aa58a" + "ffdda5c79e4cce217f6bc930dbe563d480706c24e9ebfcab28a6cdefd324" + "b77e1bf7251b709092c24ff501fd91024023d4340eda3445d8cd26c14411" + "da6fdca63c1ccd4b80a98ad52b78cc8ad8beb2842c1d280405bc2f6c1bea" + "214a1d742ab996b35b63a82a5e470fa88dbf823cdd02401b7b57449ad30d" + "1518249a5f56bb98294d4b6ac12ffc86940497a5a5837a6cf946262b4945" + "26d328c11e1126380fde04c24f916dec250892db09a6d77cdba351024077" + "62cd8f4d050da56bd591adb515d24d7ccd32cca0d05f866d583514bd7324" + "d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3" + "3492d6"); + +string ec_256_key = + hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30" + "6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032" + "99986481f3a4d859a14403420004bf85d7720d07c25461683bc648b4778a" + "9a14dd8a024e3bdd8c7ddd9ab2b528bbc7aa1b51f14ebbbb0bd0ce21bcc4" + "1c6eb00083cf3376d11fd44949e0b2183bfe"); + +string ec_521_key = + hex2str("3081EE020100301006072A8648CE3D020106052B810400230481D63081D3" + "02010104420011458C586DB5DAA92AFAB03F4FE46AA9D9C3CE9A9B7A006A" + "8384BEC4C78E8E9D18D7D08B5BCFA0E53C75B064AD51C449BAE0258D54B9" + "4B1E885DED08ED4FB25CE9A1818903818600040149EC11C6DF0FA122C6A9" + "AFD9754A4FA9513A627CA329E349535A5629875A8ADFBE27DCB932C05198" + "6377108D054C28C6F39B6F2C9AF81802F9F326B842FF2E5F3C00AB7635CF" + "B36157FC0882D574A10D839C1A0C049DC5E0D775E2EE50671A208431BB45" + "E78E70BEFE930DB34818EE4D5C26259F5C6B8E28A652950F9F88D7B4B2C9" + "D9"); + +string ec_256_key_rfc5915 = + hex2str("308193020100301306072a8648ce3d020106082a8648ce3d030107047930" + "770201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3" + "8e8d21c9fa750c1da00a06082a8648ce3d030107a14403420004e2cc561e" + "e701da0ad0ef0d176bb0c919d42e79c393fdc1bd6c4010d85cf2cf8e68c9" + "05464666f98dad4f01573ba81078b3428570a439ba3229fbc026c550682f"); + +string ec_256_key_sec1 = + hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30" + "6b0201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3" + "8e8d21c9fa750c1da14403420004e2cc561ee701da0ad0ef0d176bb0c919" + "d42e79c393fdc1bd6c4010d85cf2cf8e68c905464666f98dad4f01573ba8" + "1078b3428570a439ba3229fbc026c550682f"); + +struct RSA_Delete { + void operator()(RSA* p) { RSA_free(p); } +}; + +/* TODO(seleneh) add attestation verification codes like verify_chain() and + * attestation tests after we decided on the keymint 1 attestation changes. + */ + +std::string make_string(const uint8_t* data, size_t length) { + return std::string(reinterpret_cast<const char*>(data), length); +} + +template <size_t N> +std::string make_string(const uint8_t (&a)[N]) { + return make_string(a, N); +} + +class AidlBuf : public vector<uint8_t> { + typedef vector<uint8_t> super; + + public: + AidlBuf() {} + AidlBuf(const super& other) : super(other) {} + AidlBuf(super&& other) : super(std::move(other)) {} + explicit AidlBuf(const std::string& other) : AidlBuf() { *this = other; } + + AidlBuf& operator=(const super& other) { + super::operator=(other); + return *this; + } + + AidlBuf& operator=(super&& other) { + super::operator=(std::move(other)); + return *this; + } + + AidlBuf& operator=(const string& other) { + resize(other.size()); + for (size_t i = 0; i < other.size(); ++i) { + (*this)[i] = static_cast<uint8_t>(other[i]); + } + return *this; + } + + string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); } +}; + +} // namespace + +class NewKeyGenerationTest : public KeyMintAidlTestBase { + protected: + void CheckBaseParams(const KeyCharacteristics& keyCharacteristics) { + // TODO(swillden): Distinguish which params should be in which auth list. + + AuthorizationSet auths(keyCharacteristics.hardwareEnforced); + auths.push_back(AuthorizationSet(keyCharacteristics.softwareEnforced)); + + EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED)); + EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN)); + EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY)); + + // Verify that App ID, App data and ROT are NOT included. + EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST)); + EXPECT_FALSE(auths.Contains(TAG_APPLICATION_ID)); + EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA)); + + // Check that some unexpected tags/values are NOT present. + EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT)); + EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT)); + EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301U)); + + // Now check that unspecified, defaulted tags are correct. + EXPECT_TRUE(auths.Contains(TAG_CREATION_DATETIME)); + + EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version())) + << "OS version is " << os_version() << " key reported " + << auths.GetTagValue(TAG_OS_VERSION); + EXPECT_TRUE(auths.Contains(TAG_OS_PATCHLEVEL, os_patch_level())) + << "OS patch level is " << os_patch_level() << " key reported " + << auths.GetTagValue(TAG_OS_PATCHLEVEL); + } +}; + +/* + * NewKeyGenerationTest.Rsa + * + * Verifies that keymint can generate all required RSA key sizes, and that the resulting keys + * have correct characteristics. + */ +TEST_P(NewKeyGenerationTest, Rsa) { + for (auto key_size : ValidKeySizes(Algorithm::RSA)) { + vector<uint8_t> key_blob; + KeyCharacteristics key_characteristics; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(key_size, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE), + &key_blob, &key_characteristics)); + + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params; + if (IsSecure()) { + crypto_params = key_characteristics.hardwareEnforced; + } else { + crypto_params = key_characteristics.softwareEnforced; + } + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U)); + + CheckedDeleteKey(&key_blob); + } +} + +/* + * NewKeyGenerationTest.NoInvalidRsaSizes + * + * Verifies that keymint cannot generate any RSA key sizes that are designated as invalid. + */ +TEST_P(NewKeyGenerationTest, NoInvalidRsaSizes) { + for (auto key_size : InvalidKeySizes(Algorithm::RSA)) { + vector<uint8_t> key_blob; + KeyCharacteristics key_characteristics; + ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(key_size, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE), + &key_blob, &key_characteristics)); + } +} + +/* + * NewKeyGenerationTest.RsaNoDefaultSize + * + * Verifies that failing to specify a key size for RSA key generation returns + * UNSUPPORTED_KEY_SIZE. + */ +TEST_P(NewKeyGenerationTest, RsaNoDefaultSize) { + ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, Algorithm::RSA) + .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3U) + .SigningKey())); +} + +/* + * NewKeyGenerationTest.Ecdsa + * + * Verifies that keymint can generate all required EC key sizes, and that the resulting keys + * have correct characteristics. + */ +TEST_P(NewKeyGenerationTest, Ecdsa) { + for (auto key_size : ValidKeySizes(Algorithm::EC)) { + vector<uint8_t> key_blob; + KeyCharacteristics key_characteristics; + ASSERT_EQ(ErrorCode::OK, + GenerateKey( + AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(Digest::NONE), + &key_blob, &key_characteristics)); + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet crypto_params; + if (IsSecure()) { + crypto_params = key_characteristics.hardwareEnforced; + } else { + crypto_params = key_characteristics.softwareEnforced; + } + + EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC)); + EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + + CheckedDeleteKey(&key_blob); + } +} + +/* + * NewKeyGenerationTest.EcdsaDefaultSize + * + * Verifies that failing to specify a key size for EC key generation returns + * UNSUPPORTED_KEY_SIZE. + */ +TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) { + ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, + GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_ALGORITHM, Algorithm::EC) + .SigningKey() + .Digest(Digest::NONE))); +} + +/* + * NewKeyGenerationTest.EcdsaInvalidSize + * + * Verifies that specifying an invalid key size for EC key generation returns + * UNSUPPORTED_KEY_SIZE. + */ +TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) { + for (auto key_size : InvalidKeySizes(Algorithm::EC)) { + vector<uint8_t> key_blob; + KeyCharacteristics key_characteristics; + ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, + GenerateKey( + AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(Digest::NONE), + &key_blob, &key_characteristics)); + } + + ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(Digest::NONE))); +} + +/* + * NewKeyGenerationTest.EcdsaMismatchKeySize + * + * Verifies that specifying mismatched key size and curve for EC key generation returns + * INVALID_ARGUMENT. + */ +TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::INVALID_ARGUMENT, + GenerateKey(AuthorizationSetBuilder() + .EcdsaSigningKey(224) + .Authorization(TAG_EC_CURVE, EcCurve::P_256) + .Digest(Digest::NONE))); +} + +/* + * NewKeyGenerationTest.EcdsaAllValidSizes + * + * Verifies that keymint supports all required EC key sizes. + */ +TEST_P(NewKeyGenerationTest, EcdsaAllValidSizes) { + auto valid_sizes = ValidKeySizes(Algorithm::EC); + for (size_t size : valid_sizes) { + EXPECT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(Digest::NONE))) + << "Failed to generate size: " << size; + CheckedDeleteKey(); + } +} + +/* + * NewKeyGenerationTest.EcdsaInvalidCurves + * + * Verifies that keymint does not support any curve designated as unsupported. + */ +TEST_P(NewKeyGenerationTest, EcdsaAllValidCurves) { + Digest digest; + if (SecLevel() == SecurityLevel::STRONGBOX) { + digest = Digest::SHA_2_256; + } else { + digest = Digest::SHA_2_512; + } + for (auto curve : ValidCurves()) { + EXPECT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(curve).Digest(digest))) + << "Failed to generate key on curve: " << curve; + CheckedDeleteKey(); + } +} + +/* + * NewKeyGenerationTest.Hmac + * + * Verifies that keymint supports all required digests, and that the resulting keys have correct + * characteristics. + */ +TEST_P(NewKeyGenerationTest, Hmac) { + for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) { + vector<uint8_t> key_blob; + KeyCharacteristics key_characteristics; + constexpr size_t key_size = 128; + ASSERT_EQ(ErrorCode::OK, + GenerateKey( + AuthorizationSetBuilder().HmacKey(key_size).Digest(digest).Authorization( + TAG_MIN_MAC_LENGTH, 128), + &key_blob, &key_characteristics)); + + ASSERT_GT(key_blob.size(), 0U); + CheckBaseParams(key_characteristics); + + AuthorizationSet hardwareEnforced = key_characteristics.hardwareEnforced; + AuthorizationSet softwareEnforced = key_characteristics.softwareEnforced; + if (IsSecure()) { + EXPECT_TRUE(hardwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC)); + EXPECT_TRUE(hardwareEnforced.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + } else { + EXPECT_TRUE(softwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC)); + EXPECT_TRUE(softwareEnforced.Contains(TAG_KEY_SIZE, key_size)) + << "Key size " << key_size << "missing"; + } + + CheckedDeleteKey(&key_blob); + } +} + +/* + * NewKeyGenerationTest.HmacCheckKeySizes + * + * Verifies that keymint supports all key sizes, and rejects all invalid key sizes. + */ +TEST_P(NewKeyGenerationTest, HmacCheckKeySizes) { + for (size_t key_size = 0; key_size <= 512; ++key_size) { + if (key_size < 64 || key_size % 8 != 0) { + // To keep this test from being very slow, we only test a random fraction of + // non-byte key sizes. We test only ~10% of such cases. Since there are 392 of + // them, we expect to run ~40 of them in each run. + if (key_size % 8 == 0 || random() % 10 == 0) { + EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(key_size) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))) + << "HMAC key size " << key_size << " invalid"; + } + } else { + EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .HmacKey(key_size) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))) + << "Failed to generate HMAC key of size " << key_size; + CheckedDeleteKey(); + } + } +} + +/* + * NewKeyGenerationTest.HmacCheckMinMacLengths + * + * Verifies that keymint supports all required MAC lengths and rejects all invalid lengths. This + * test is probabilistic in order to keep the runtime down, but any failure prints out the + * specific MAC length that failed, so reproducing a failed run will be easy. + */ +TEST_P(NewKeyGenerationTest, HmacCheckMinMacLengths) { + for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) { + if (min_mac_length < 64 || min_mac_length % 8 != 0) { + // To keep this test from being very long, we only test a random fraction of + // non-byte lengths. We test only ~10% of such cases. Since there are 172 of them, + // we expect to run ~17 of them in each run. + if (min_mac_length % 8 == 0 || random() % 10 == 0) { + EXPECT_EQ(ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length))) + << "HMAC min mac length " << min_mac_length << " invalid."; + } + } else { + EXPECT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length))) + << "Failed to generate HMAC key with min MAC length " << min_mac_length; + CheckedDeleteKey(); + } + } +} + +/* + * NewKeyGenerationTest.HmacMultipleDigests + * + * Verifies that keymint rejects HMAC key generation with multiple specified digest algorithms. + */ +TEST_P(NewKeyGenerationTest, HmacMultipleDigests) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(Digest::SHA1) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); +} + +/* + * NewKeyGenerationTest.HmacDigestNone + * + * Verifies that keymint rejects HMAC key generation with no digest or Digest::NONE + */ +TEST_P(NewKeyGenerationTest, HmacDigestNone) { + ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST, + GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH, + 128))); + + ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST, + GenerateKey(AuthorizationSetBuilder() + .HmacKey(128) + .Digest(Digest::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(NewKeyGenerationTest); + +typedef KeyMintAidlTestBase SigningOperationsTest; + +/* + * SigningOperationsTest.RsaSuccess + * + * Verifies that raw RSA signature operations succeed. + */ +TEST_P(SigningOperationsTest, RsaSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED))); + string message = "12345678901234567890123456789012"; + string signature = SignMessage( + message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)); +} + +/* + * SigningOperationsTest.RsaUseRequiresCorrectAppIdAppData + * + * Verifies that using an RSA key requires the correct app ID/data. + */ +TEST_P(SigningOperationsTest, RsaUseRequiresCorrectAppIdAppData) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_ID, "clientid") + .Authorization(TAG_APPLICATION_DATA, "appdata"))); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_ID, "clientid"))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_DATA, "appdata"))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_APPLICATION_DATA, "appdata") + .Authorization(TAG_APPLICATION_ID, "clientid"))); + AbortIfNeeded(); +} + +/* + * SigningOperationsTest.RsaPssSha256Success + * + * Verifies that RSA-PSS signature operations succeed. + */ +TEST_P(SigningOperationsTest, RsaPssSha256Success) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PSS) + .Authorization(TAG_NO_AUTH_REQUIRED))); + // Use large message, which won't work without digesting. + string message(1024, 'a'); + string signature = SignMessage( + message, + AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS)); +} + +/* + * SigningOperationsTest.RsaPaddingNoneDoesNotAllowOther + * + * Verifies that keymint rejects signature operations that specify a padding mode when the key + * supports only unpadded operations. + */ +TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + string message = "12345678901234567890123456789012"; + string signature; + + EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN))); +} + +/* + * SigningOperationsTest.NoUserConfirmation + * + * Verifies that keymint rejects signing operations for keys with + * TRUSTED_CONFIRMATION_REQUIRED and no valid confirmation token + * presented. + */ +TEST_P(SigningOperationsTest, NoUserConfirmation) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + ASSERT_EQ(ErrorCode::OK, + GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(1024, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED))); + + const string message = "12345678901234567890123456789012"; + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE))); + string signature; + EXPECT_EQ(ErrorCode::NO_USER_CONFIRMATION, Finish(message, &signature)); +} + +/* + * SigningOperationsTest.RsaPkcs1Sha256Success + * + * Verifies that digested RSA-PKCS1 signature operations succeed. + */ +TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN))); + string message(1024, 'a'); + string signature = SignMessage(message, AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)); +} + +/* + * SigningOperationsTest.RsaPkcs1NoDigestSuccess + * + * Verifies that undigested RSA-PKCS1 signature operations succeed. + */ +TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN))); + string message(53, 'a'); + string signature = SignMessage(message, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)); +} + +/* + * SigningOperationsTest.RsaPkcs1NoDigestTooLarge + * + * Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when + * given a too-long message. + */ +TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLong) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN))); + string message(257, 'a'); + + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN))); + string signature; + EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &signature)); +} + +/* + * SigningOperationsTest.RsaPssSha512TooSmallKey + * + * Verifies that undigested RSA-PSS signature operations fail with the correct error code when + * used with a key that is too small for the message. + * + * A PSS-padded message is of length salt_size + digest_size + 16 (sizes in bits), and the + * keymint specification requires that salt_size == digest_size, so the message will be + * digest_size * 2 + + * 16. Such a message can only be signed by a given key if the key is at least that size. This + * test uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large + * for a 1024-bit key. + */ +TEST_P(SigningOperationsTest, RsaPssSha512TooSmallKey) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(1024, 65537) + .Digest(Digest::SHA_2_512) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::RSA_PSS))); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::SHA_2_512) + .Padding(PaddingMode::RSA_PSS))); +} + +/* + * SigningOperationsTest.RsaNoPaddingTooLong + * + * Verifies that raw RSA signature operations fail with the correct error code when + * given a too-long message. + */ +TEST_P(SigningOperationsTest, RsaNoPaddingTooLong) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN))); + // One byte too long + string message(2048 / 8 + 1, 'a'); + ASSERT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN))); + string result; + ErrorCode finish_error_code = Finish(message, &result); + EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH || + finish_error_code == ErrorCode::INVALID_ARGUMENT); + + // Very large message that should exceed the transfer buffer size of any reasonable TEE. + message = string(128 * 1024, 'a'); + ASSERT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN))); + finish_error_code = Finish(message, &result); + EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH || + finish_error_code == ErrorCode::INVALID_ARGUMENT); +} + +/* + * SigningOperationsTest.RsaAbort + * + * Verifies that operations can be aborted correctly. Uses an RSA signing operation for the + * test, but the behavior should be algorithm and purpose-independent. + */ +TEST_P(SigningOperationsTest, RsaAbort) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + + ASSERT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE))); + EXPECT_EQ(ErrorCode::OK, Abort()); + + // Another abort should fail + EXPECT_EQ(ErrorCode::INVALID_OPERATION_HANDLE, Abort()); + + // Set to sentinel, so TearDown() doesn't try to abort again. + op_.clear(); +} + +/* + * SigningOperationsTest.RsaUnsupportedPadding + * + * Verifies that RSA operations fail with the correct error (but key gen succeeds) when used + * with a padding mode inappropriate for RSA. + */ +TEST_P(SigningOperationsTest, RsaUnsupportedPadding) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Digest(Digest::SHA_2_256 /* supported digest */) + .Padding(PaddingMode::PKCS7))); + ASSERT_EQ( + ErrorCode::UNSUPPORTED_PADDING_MODE, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::PKCS7))); +} + +/* + * SigningOperationsTest.RsaPssNoDigest + * + * Verifies that RSA PSS operations fail when no digest is used. PSS requires a digest. + */ +TEST_P(SigningOperationsTest, RsaNoDigest) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Digest(Digest::NONE) + .Padding(PaddingMode::RSA_PSS))); + ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PSS))); + + ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Padding(PaddingMode::RSA_PSS))); +} + +/* + * SigningOperationsTest.RsaPssNoDigest + * + * Verifies that RSA operations fail when no padding mode is specified. PaddingMode::NONE is + * supported in some cases (as validated in other tests), but a mode must be specified. + */ +TEST_P(SigningOperationsTest, RsaNoPadding) { + // Padding must be specified + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .RsaKey(2048, 65537) + .Authorization(TAG_NO_AUTH_REQUIRED) + .SigningKey() + .Digest(Digest::NONE))); + ASSERT_EQ(ErrorCode::UNSUPPORTED_PADDING_MODE, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE))); +} + +/* + * SigningOperationsTest.RsaShortMessage + * + * Verifies that raw RSA signatures succeed with a message shorter than the key size. + */ +TEST_P(SigningOperationsTest, RsaTooShortMessage) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE))); + + // Barely shorter + string message(2048 / 8 - 1, 'a'); + SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)); + + // Much shorter + message = "a"; + SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)); +} + +/* + * SigningOperationsTest.RsaSignWithEncryptionKey + * + * Verifies that RSA encryption keys cannot be used to sign. + */ +TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE))); + ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, + Begin(KeyPurpose::SIGN, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE))); +} + +/* + * SigningOperationsTest.RsaSignTooLargeMessage + * + * Verifies that attempting a raw signature of a message which is the same length as the key, + * but numerically larger than the public modulus, fails with the correct error. + */ +TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE))); + + // Largest possible message will always be larger than the public modulus. + string message(2048 / 8, static_cast<char>(0xff)); + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE))); + string signature; + ASSERT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &signature)); +} + +/* + * SigningOperationsTest.EcdsaAllSizesAndHashes + * + * Verifies that ECDSA operations succeed with all possible key sizes and hashes. + */ +TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) { + for (auto key_size : ValidKeySizes(Algorithm::EC)) { + for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) { + ErrorCode error = GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(key_size) + .Digest(digest)); + EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with size " << key_size + << " and digest " << digest; + if (error != ErrorCode::OK) continue; + + string message(1024, 'a'); + if (digest == Digest::NONE) message.resize(key_size / 8); + SignMessage(message, AuthorizationSetBuilder().Digest(digest)); + CheckedDeleteKey(); + } + } +} + +/* + * SigningOperationsTest.EcdsaAllCurves + * + * Verifies that ECDSA operations succeed with all possible curves. + */ +TEST_P(SigningOperationsTest, EcdsaAllCurves) { + for (auto curve : ValidCurves()) { + ErrorCode error = GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(curve) + .Digest(Digest::SHA_2_256)); + EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve; + if (error != ErrorCode::OK) continue; + + string message(1024, 'a'); + SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256)); + CheckedDeleteKey(); + } +} + +/* + * SigningOperationsTest.EcdsaNoDigestHugeData + * + * Verifies that ECDSA operations support very large messages, even without digesting. This + * should work because ECDSA actually only signs the leftmost L_n bits of the message, however + * large it may be. Not using digesting is a bad idea, but in some cases digesting is done by + * the framework. + */ +TEST_P(SigningOperationsTest, EcdsaNoDigestHugeData) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::NONE))); + string message(1 * 1024, 'a'); + SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE)); +} + +/* + * SigningOperationsTest.EcUseRequiresCorrectAppIdAppData + * + * Verifies that using an EC key requires the correct app ID/data. + */ +TEST_P(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_ID, "clientid") + .Authorization(TAG_APPLICATION_DATA, "appdata"))); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_ID, "clientid"))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_DATA, "appdata"))); + AbortIfNeeded(); + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::SIGN, AuthorizationSetBuilder() + .Digest(Digest::NONE) + .Authorization(TAG_APPLICATION_DATA, "appdata") + .Authorization(TAG_APPLICATION_ID, "clientid"))); + AbortIfNeeded(); +} + +/* + * SigningOperationsTest.AesEcbSign + * + * Verifies that attempts to use AES keys to sign fail in the correct way. + */ +TEST_P(SigningOperationsTest, AesEcbSign) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .SigningKey() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::ECB))); + + AuthorizationSet out_params; + EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, + Begin(KeyPurpose::SIGN, AuthorizationSet() /* in_params */, &out_params)); + EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, + Begin(KeyPurpose::VERIFY, AuthorizationSet() /* in_params */, &out_params)); +} + +/* + * SigningOperationsTest.HmacAllDigests + * + * Verifies that HMAC works with all digests. + */ +TEST_P(SigningOperationsTest, HmacAllDigests) { + for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .HmacKey(128) + .Digest(digest) + .Authorization(TAG_MIN_MAC_LENGTH, 160))) + << "Failed to create HMAC key with digest " << digest; + string message = "12345678901234567890123456789012"; + string signature = MacMessage(message, digest, 160); + EXPECT_EQ(160U / 8U, signature.size()) + << "Failed to sign with HMAC key with digest " << digest; + CheckedDeleteKey(); + } +} + +/* + * SigningOperationsTest.HmacSha256TooLargeMacLength + * + * Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the + * digest size. + */ +TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .HmacKey(128) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256))); + AuthorizationSet output_params; + EXPECT_EQ(ErrorCode::UNSUPPORTED_MAC_LENGTH, Begin(KeyPurpose::SIGN, key_blob_, + AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MAC_LENGTH, 264), + &output_params)); +} + +/* + * SigningOperationsTest.HmacSha256TooSmallMacLength + * + * Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the + * specified minimum MAC length. + */ +TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .HmacKey(128) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + AuthorizationSet output_params; + EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::SIGN, key_blob_, + AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MAC_LENGTH, 120), + &output_params)); +} + +/* + * SigningOperationsTest.HmacRfc4231TestCase3 + * + * Validates against the test vectors from RFC 4231 test case 3. + */ +TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) { + string key(20, 0xaa); + string message(50, 0xdd); + uint8_t sha_224_expected[] = { + 0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a, + 0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea, + }; + uint8_t sha_256_expected[] = { + 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, + 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, + 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe, + }; + uint8_t sha_384_expected[] = { + 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0, + 0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb, + 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d, + 0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27, + }; + uint8_t sha_512_expected[] = { + 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c, + 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8, + 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22, + 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37, + 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb, + }; + + CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected)); + if (SecLevel() != SecurityLevel::STRONGBOX) { + CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected)); + } +} + +/* + * SigningOperationsTest.HmacRfc4231TestCase5 + * + * Validates against the test vectors from RFC 4231 test case 5. + */ +TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) { + string key(20, 0x0c); + string message = "Test With Truncation"; + + uint8_t sha_224_expected[] = { + 0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37, + 0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8, + }; + uint8_t sha_256_expected[] = { + 0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0, + 0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b, + }; + uint8_t sha_384_expected[] = { + 0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23, + 0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97, + }; + uint8_t sha_512_expected[] = { + 0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53, + 0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6, + }; + + CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected)); + if (SecLevel() != SecurityLevel::STRONGBOX) { + CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected)); + CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected)); + CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected)); + } +} + +INSTANTIATE_KEYMINT_AIDL_TEST(SigningOperationsTest); + +typedef KeyMintAidlTestBase VerificationOperationsTest; + +/* + * VerificationOperationsTest.RsaSuccess + * + * Verifies that a simple RSA signature/verification sequence succeeds. + */ +TEST_P(VerificationOperationsTest, RsaSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE))); + string message = "12345678901234567890123456789012"; + string signature = SignMessage( + message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)); + VerifyMessage(message, signature, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)); +} + +/* + * VerificationOperationsTest.RsaSuccess + * + * Verifies RSA signature/verification for all padding modes and digests. + */ +TEST_P(VerificationOperationsTest, RsaAllPaddingsAndDigests) { + auto authorizations = AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(2048, 65537) + .Digest(ValidDigests(true /* withNone */, true /* withMD5 */)) + .Padding(PaddingMode::NONE) + .Padding(PaddingMode::RSA_PSS) + .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN); + + ASSERT_EQ(ErrorCode::OK, GenerateKey(authorizations)); + + string message(128, 'a'); + string corrupt_message(message); + ++corrupt_message[corrupt_message.size() / 2]; + + for (auto padding : + {PaddingMode::NONE, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN}) { + for (auto digest : ValidDigests(true /* withNone */, true /* withMD5 */)) { + if (padding == PaddingMode::NONE && digest != Digest::NONE) { + // Digesting only makes sense with padding. + continue; + } + + if (padding == PaddingMode::RSA_PSS && digest == Digest::NONE) { + // PSS requires digesting. + continue; + } + + string signature = + SignMessage(message, AuthorizationSetBuilder().Digest(digest).Padding(padding)); + VerifyMessage(message, signature, + AuthorizationSetBuilder().Digest(digest).Padding(padding)); + + /* TODO(seleneh) add exportkey tests back later when we have decided on + * the new api. + if (digest != Digest::NONE) { + // Verify with OpenSSL. + vector<uint8_t> pubkey; + ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey)); + + const uint8_t* p = pubkey.data(); + EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr, &p, pubkey.size())); + ASSERT_TRUE(pkey.get()); + + EVP_MD_CTX digest_ctx; + EVP_MD_CTX_init(&digest_ctx); + EVP_PKEY_CTX* pkey_ctx; + const EVP_MD* md = openssl_digest(digest); + ASSERT_NE(md, nullptr); + EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md, + nullptr, pkey.get())); + + switch (padding) { + case PaddingMode::RSA_PSS: + EXPECT_GT(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, + RSA_PKCS1_PSS_PADDING), 0); EXPECT_GT(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, + EVP_MD_size(md)), 0); break; case PaddingMode::RSA_PKCS1_1_5_SIGN: + // PKCS1 is the default; don't need to set anything. + break; + default: + FAIL(); + break; + } + + EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), + message.size())); EXPECT_EQ(1, EVP_DigestVerifyFinal(&digest_ctx, + reinterpret_cast<const + uint8_t*>(signature.data()), signature.size())); EVP_MD_CTX_cleanup(&digest_ctx); + } + */ + + // Corrupt signature shouldn't verify. + string corrupt_signature(signature); + ++corrupt_signature[corrupt_signature.size() / 2]; + + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::VERIFY, + AuthorizationSetBuilder().Digest(digest).Padding(padding))); + string result; + EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result)); + + // Corrupt message shouldn't verify + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::VERIFY, + AuthorizationSetBuilder().Digest(digest).Padding(padding))); + EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result)); + } + } +} + +/* + * VerificationOperationsTest.RsaSuccess + * + * Verifies ECDSA signature/verification for all digests and curves. + */ +TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndCurves) { + auto digests = ValidDigests(true /* withNone */, false /* withMD5 */); + + string message = "1234567890"; + string corrupt_message = "2234567890"; + for (auto curve : ValidCurves()) { + ErrorCode error = GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(curve) + .Digest(digests)); + EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate key for EC curve " << curve; + if (error != ErrorCode::OK) { + continue; + } + + for (auto digest : digests) { + string signature = SignMessage(message, AuthorizationSetBuilder().Digest(digest)); + VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(digest)); + + /* TODO(seleneh) add exportkey tests back later when we have decided on + * the new api. + + // Verify with OpenSSL + if (digest != Digest::NONE) { + vector<uint8_t> pubkey; + ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey)) + << curve << ' ' << digest; + + const uint8_t* p = pubkey.data(); + EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr, &p, pubkey.size())); + ASSERT_TRUE(pkey.get()); + + EVP_MD_CTX digest_ctx; + EVP_MD_CTX_init(&digest_ctx); + EVP_PKEY_CTX* pkey_ctx; + const EVP_MD* md = openssl_digest(digest); + + EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md, + nullptr, pkey.get())) + << curve << ' ' << digest; + + EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), + message.size())) + << curve << ' ' << digest; + + EXPECT_EQ(1, + EVP_DigestVerifyFinal(&digest_ctx, + reinterpret_cast<const + uint8_t*>(signature.data()), signature.size())) + << curve << ' ' << digest; + + EVP_MD_CTX_cleanup(&digest_ctx); + } + */ + // Corrupt signature shouldn't verify. + string corrupt_signature(signature); + ++corrupt_signature[corrupt_signature.size() / 2]; + + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest))) + << curve << ' ' << digest; + + string result; + EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result)) + << curve << ' ' << digest; + + // Corrupt message shouldn't verify + EXPECT_EQ(ErrorCode::OK, + Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest))) + << curve << ' ' << digest; + + EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result)) + << curve << ' ' << digest; + } + + auto rc = DeleteKey(); + ASSERT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED); + } +} + +/* + * VerificationOperationsTest.HmacSigningKeyCannotVerify + * + * Verifies HMAC signing and verification, but that a signing key cannot be used to verify. + */ +TEST_P(VerificationOperationsTest, HmacSigningKeyCannotVerify) { + string key_material = "HelloThisIsAKey"; + + vector<uint8_t> signing_key, verification_key; + KeyCharacteristics signing_key_chars, verification_key_chars; + EXPECT_EQ(ErrorCode::OK, + ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_ALGORITHM, Algorithm::HMAC) + .Authorization(TAG_PURPOSE, KeyPurpose::SIGN) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 160), + KeyFormat::RAW, key_material, &signing_key, &signing_key_chars)); + EXPECT_EQ(ErrorCode::OK, + ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_ALGORITHM, Algorithm::HMAC) + .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 160), + KeyFormat::RAW, key_material, &verification_key, &verification_key_chars)); + + string message = "This is a message."; + string signature = SignMessage( + signing_key, message, + AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 160)); + + // Signing key should not work. + AuthorizationSet out_params; + EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, + Begin(KeyPurpose::VERIFY, signing_key, + AuthorizationSetBuilder().Digest(Digest::SHA_2_256), &out_params)); + + // Verification key should work. + VerifyMessage(verification_key, message, signature, + AuthorizationSetBuilder().Digest(Digest::SHA_2_256)); + + CheckedDeleteKey(&signing_key); + CheckedDeleteKey(&verification_key); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(VerificationOperationsTest); + +typedef KeyMintAidlTestBase ExportKeyTest; + +/* + * ExportKeyTest.RsaUnsupportedKeyFormat + * + * Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error. + */ +// TODO(seleneh) add ExportKey to GenerateKey +// check result + +class ImportKeyTest : public KeyMintAidlTestBase { + public: + template <TagType tag_type, Tag tag, typename ValueT> + void CheckCryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) { + SCOPED_TRACE("CheckCryptoParam"); + if (IsSecure()) { + EXPECT_TRUE(contains(key_characteristics_.hardwareEnforced, ttag, expected)) + << "Tag " << tag << " with value " << expected << " not found"; + EXPECT_FALSE(contains(key_characteristics_.softwareEnforced, ttag)) + << "Tag " << tag << " found"; + } else { + EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, ttag, expected)) + << "Tag " << tag << " with value " << expected << " not found"; + EXPECT_FALSE(contains(key_characteristics_.hardwareEnforced, ttag)) + << "Tag " << tag << " found"; + } + } + + void CheckOrigin() { + SCOPED_TRACE("CheckOrigin"); + if (IsSecure()) { + EXPECT_TRUE(contains(key_characteristics_.hardwareEnforced, TAG_ORIGIN, + KeyOrigin::IMPORTED)); + } else { + EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, TAG_ORIGIN, + KeyOrigin::IMPORTED)); + } + } +}; + +/* + * ImportKeyTest.RsaSuccess + * + * Verifies that importing and using an RSA key pair works correctly. + */ +TEST_P(ImportKeyTest, RsaSuccess) { + ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(1024, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_PSS), + KeyFormat::PKCS8, rsa_key)); + + CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA); + CheckCryptoParam(TAG_KEY_SIZE, 1024U); + CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U); + CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256); + CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_PSS); + CheckOrigin(); + + string message(1024 / 8, 'a'); + auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS); + string signature = SignMessage(message, params); + VerifyMessage(message, signature, params); +} + +/* + * ImportKeyTest.RsaKeySizeMismatch + * + * Verifies that importing an RSA key pair with a size that doesn't match the key fails in the + * correct way. + */ +TEST_P(ImportKeyTest, RsaKeySizeMismatch) { + ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH, + ImportKey(AuthorizationSetBuilder() + .RsaSigningKey(2048 /* Doesn't match key */, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE), + KeyFormat::PKCS8, rsa_key)); +} + +/* + * ImportKeyTest.RsaPublicExponentMismatch + * + * Verifies that importing an RSA key pair with a public exponent that doesn't match the key + * fails in the correct way. + */ +TEST_P(ImportKeyTest, RsaPublicExponentMismatch) { + ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH, + ImportKey(AuthorizationSetBuilder() + .RsaSigningKey(1024, 3 /* Doesn't match key */) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE), + KeyFormat::PKCS8, rsa_key)); +} + +/* + * ImportKeyTest.EcdsaSuccess + * + * Verifies that importing and using an ECDSA P-256 key pair works correctly. + */ +TEST_P(ImportKeyTest, EcdsaSuccess) { + ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256), + KeyFormat::PKCS8, ec_256_key)); + + CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC); + CheckCryptoParam(TAG_KEY_SIZE, 256U); + CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256); + CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256); + + CheckOrigin(); + + string message(32, 'a'); + auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256); + string signature = SignMessage(message, params); + VerifyMessage(message, signature, params); +} + +/* + * ImportKeyTest.EcdsaP256RFC5915Success + * + * Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works + * correctly. + */ +TEST_P(ImportKeyTest, EcdsaP256RFC5915Success) { + ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256), + KeyFormat::PKCS8, ec_256_key_rfc5915)); + + CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC); + CheckCryptoParam(TAG_KEY_SIZE, 256U); + CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256); + CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256); + + CheckOrigin(); + + string message(32, 'a'); + auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256); + string signature = SignMessage(message, params); + VerifyMessage(message, signature, params); +} + +/* + * ImportKeyTest.EcdsaP256SEC1Success + * + * Verifies that importing and using an ECDSA P-256 key pair encoded using SEC1 works correctly. + */ +TEST_P(ImportKeyTest, EcdsaP256SEC1Success) { + ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::SHA_2_256), + KeyFormat::PKCS8, ec_256_key_sec1)); + + CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC); + CheckCryptoParam(TAG_KEY_SIZE, 256U); + CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256); + CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256); + + CheckOrigin(); + + string message(32, 'a'); + auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256); + string signature = SignMessage(message, params); + VerifyMessage(message, signature, params); +} + +/* + * ImportKeyTest.Ecdsa521Success + * + * Verifies that importing and using an ECDSA P-521 key pair works correctly. + */ +TEST_P(ImportKeyTest, Ecdsa521Success) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(521) + .Digest(Digest::SHA_2_256), + KeyFormat::PKCS8, ec_521_key)); + + CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC); + CheckCryptoParam(TAG_KEY_SIZE, 521U); + CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256); + CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_521); + CheckOrigin(); + + string message(32, 'a'); + auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256); + string signature = SignMessage(message, params); + VerifyMessage(message, signature, params); +} + +/* + * ImportKeyTest.EcdsaSizeMismatch + * + * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the + * correct way. + */ +TEST_P(ImportKeyTest, EcdsaSizeMismatch) { + ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH, + ImportKey(AuthorizationSetBuilder() + .EcdsaSigningKey(224 /* Doesn't match key */) + .Digest(Digest::NONE), + KeyFormat::PKCS8, ec_256_key)); +} + +/* + * ImportKeyTest.EcdsaCurveMismatch + * + * Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in + * the correct way. + */ +TEST_P(ImportKeyTest, EcdsaCurveMismatch) { + ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH, + ImportKey(AuthorizationSetBuilder() + .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */) + .Digest(Digest::NONE), + KeyFormat::PKCS8, ec_256_key)); +} + +/* + * ImportKeyTest.AesSuccess + * + * Verifies that importing and using an AES key works. + */ +TEST_P(ImportKeyTest, AesSuccess) { + string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(key.size() * 8) + .EcbMode() + .Padding(PaddingMode::PKCS7), + KeyFormat::RAW, key)); + + CheckCryptoParam(TAG_ALGORITHM, Algorithm::AES); + CheckCryptoParam(TAG_KEY_SIZE, 128U); + CheckCryptoParam(TAG_PADDING, PaddingMode::PKCS7); + CheckCryptoParam(TAG_BLOCK_MODE, BlockMode::ECB); + CheckOrigin(); + + string message = "Hello World!"; + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7); + string ciphertext = EncryptMessage(message, params); + string plaintext = DecryptMessage(ciphertext, params); + EXPECT_EQ(message, plaintext); +} + +/* + * ImportKeyTest.AesSuccess + * + * Verifies that importing and using an HMAC key works. + */ +TEST_P(ImportKeyTest, HmacKeySuccess) { + string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .HmacKey(key.size() * 8) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_MIN_MAC_LENGTH, 256), + KeyFormat::RAW, key)); + + CheckCryptoParam(TAG_ALGORITHM, Algorithm::HMAC); + CheckCryptoParam(TAG_KEY_SIZE, 128U); + CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256); + CheckOrigin(); + + string message = "Hello World!"; + string signature = MacMessage(message, Digest::SHA_2_256, 256); + VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256)); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest); + +auto wrapped_key = hex2str( + "3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac8" + "4b59b30b455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e0" + "97474febc981195b1d13a69086c0863f66a7b7fdb48792227b1ac5e2489febdf087ab5486483033a6f001c" + "a5d1ec1e27f5c30f4cec2642074a39ae68aee552e196627a8e3d867e67a8c01b11e75f13cca0a97ab668b5" + "0cda07a8ecb7cd8e3dd7009c9636534f6f239cffe1fc8daa466f78b676c7119efb96bce4e69ca2a25d0b34" + "ed9c3ff999b801597d5220e307eaa5bee507fb94d1fa69f9e519b2de315bac92c36f2ea1fa1df4478c0dde" + "deae8c70e0233cd098040cd796b02c370f1fa4cc0124f1302e0201033029a1083106020100020101a20302" + "0120a30402020100a4053103020101a6053103020140bf83770205000420ccd540855f833a5e1480bfd2d3" + "6faf3aeee15df5beabe2691bc82dde2a7aa910041064c9f689c60ff6223ab6e6999e0eb6e5"); + +auto wrapped_key_masked = hex2str( + "3082017902010004820100aad93ed5924f283b4bb5526fbe7a1412f9d9749ec30db9062b29e574a8546f33" + "c88732452f5b8e6a391ee76c39ed1712c61d8df6213dec1cffbc17a8c6d04c7b30893d8daa9b2015213e21" + "946821553207f8f9931c4caba23ed3bee28b36947e47f10e0a5c3dc51c988a628daad3e5e1f4005e79c2d5" + "a96c284b4b8d7e4948f331e5b85dd5a236f85579f3ea1d1b848487470bdb0ab4f81a12bee42c99fe0df4be" + "e3759453e69ad1d68a809ce06b949f7694a990429b2fe81e066ff43e56a21602db70757922a4bcc23ab89f" + "1e35da77586775f423e519c2ea394caf48a28d0c8020f1dcf6b3a68ec246f615ae96dae9a079b1f6eb9590" + "33c1af5c125fd94168040c6d9721d08589581ab49204a3302e0201033029a1083106020100020101a20302" + "0120a30402020100a4053103020101a6053103020140bf83770205000420a61c6e247e25b3e6e69aa78eb0" + "3c2d4ac20d1f99a9a024a76f35c8e2cab9b68d04102560c70109ae67c030f00b98b512a670"); + +auto wrapping_key = hex2str( + "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d" + "8900ce56b0067f7d70e1fc653f3f34d194c1fed50018fb43db937b06e673a837313d56b1c725150a3fef86" + "acbddc41bb759c2854eae32d35841efb5c18d82bc90a1cb5c1d55adf245b02911f0b7cda88c421ff0ebafe" + "7c0d23be312d7bd5921ffaea1347c157406fef718f682643e4e5d33c6703d61c0cf7ac0bf4645c11f5c137" + "4c3886427411c449796792e0bef75dec858a2123c36753e02a95a96d7c454b504de385a642e0dfc3e60ac3" + "a7ee4991d0d48b0172a95f9536f02ba13cecccb92b727db5c27e5b2f5cec09600b286af5cf14c42024c61d" + "dfe71c2a8d7458f185234cb00e01d282f10f8fc6721d2aed3f4833cca2bd8fa62821dd5502030100010282" + "0100431447b6251908112b1ee76f99f3711a52b6630960046c2de70de188d833f8b8b91e4d785caeeeaf4f" + "0f74414e2cda40641f7fe24f14c67a88959bdb27766df9e710b630a03adc683b5d2c43080e52bee71e9eae" + "b6de297a5fea1072070d181c822bccff087d63c940ba8a45f670feb29fb4484d1c95e6d2579ba02aae0a00" + "900c3ebf490e3d2cd7ee8d0e20c536e4dc5a5097272888cddd7e91f228b1c4d7474c55b8fcd618c4a957bb" + "ddd5ad7407cc312d8d98a5caf7e08f4a0d6b45bb41c652659d5a5ba05b663737a8696281865ba20fbdd7f8" + "51e6c56e8cbe0ddbbf24dc03b2d2cb4c3d540fb0af52e034a2d06698b128e5f101e3b51a34f8d8b4f86181" + "02818100de392e18d682c829266cc3454e1d6166242f32d9a1d10577753e904ea7d08bff841be5bac82a16" + "4c5970007047b8c517db8f8f84e37bd5988561bdf503d4dc2bdb38f885434ae42c355f725c9a60f91f0788" + "e1f1a97223b524b5357fdf72e2f696bab7d78e32bf92ba8e1864eab1229e91346130748a6e3c124f9149d7" + "1c743502818100c95387c0f9d35f137b57d0d65c397c5e21cc251e47008ed62a542409c8b6b6ac7f8967b3" + "863ca645fcce49582a9aa17349db6c4a95affdae0dae612e1afac99ed39a2d934c880440aed8832f984316" + "3a47f27f392199dc1202f9a0f9bd08308007cb1e4e7f58309366a7de25f7c3c9b880677c068e1be936e812" + "88815252a8a102818057ff8ca1895080b2cae486ef0adfd791fb0235c0b8b36cd6c136e52e4085f4ea5a06" + "3212a4f105a3764743e53281988aba073f6e0027298e1c4378556e0efca0e14ece1af76ad0b030f27af6f0" + "ab35fb73a060d8b1a0e142fa2647e93b32e36d8282ae0a4de50ab7afe85500a16f43a64719d6e2b9439823" + "719cd08bcd03178102818100ba73b0bb28e3f81e9bd1c568713b101241acc607976c4ddccc90e65b6556ca" + "31516058f92b6e09f3b160ff0e374ec40d78ae4d4979fde6ac06a1a400c61dd31254186af30b22c10582a8" + "a43e34fe949c5f3b9755bae7baa7b7b7a6bd03b38cef55c86885fc6c1978b9cee7ef33da507c9df6b9277c" + "ff1e6aaa5d57aca528466102818100c931617c77829dfb1270502be9195c8f2830885f57dba869536811e6" + "864236d0c4736a0008a145af36b8357a7c3d139966d04c4e00934ea1aede3bb6b8ec841dc95e3f579751e2" + "bfdfe27ae778983f959356210723287b0affcc9f727044d48c373f1babde0724fa17a4fd4da0902c7c9b9b" + "f27ba61be6ad02dfddda8f4e6822"); + +string zero_masking_key = + hex2str("0000000000000000000000000000000000000000000000000000000000000000"); +string masking_key = hex2str("D796B02C370F1FA4CC0124F14EC8CBEBE987E825246265050F399A51FD477DFC"); + +class ImportWrappedKeyTest : public KeyMintAidlTestBase {}; + +TEST_P(ImportWrappedKeyTest, Success) { + auto wrapping_key_desc = AuthorizationSetBuilder() + .RsaEncryptionKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP) + .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY); + + ASSERT_EQ(ErrorCode::OK, + ImportWrappedKey(wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key, + AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP))); + + string message = "Hello World!"; + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7); + string ciphertext = EncryptMessage(message, params); + string plaintext = DecryptMessage(ciphertext, params); + EXPECT_EQ(message, plaintext); +} + +TEST_P(ImportWrappedKeyTest, SuccessMasked) { + auto wrapping_key_desc = AuthorizationSetBuilder() + .RsaEncryptionKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP) + .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY); + + ASSERT_EQ(ErrorCode::OK, + ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, masking_key, + AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP))); +} + +TEST_P(ImportWrappedKeyTest, WrongMask) { + auto wrapping_key_desc = AuthorizationSetBuilder() + .RsaEncryptionKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP) + .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY); + + ASSERT_EQ( + ErrorCode::VERIFICATION_FAILED, + ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key, + AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP))); +} + +TEST_P(ImportWrappedKeyTest, WrongPurpose) { + auto wrapping_key_desc = AuthorizationSetBuilder() + .RsaEncryptionKey(2048, 65537) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP); + + ASSERT_EQ( + ErrorCode::INCOMPATIBLE_PURPOSE, + ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key, + AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP))); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(ImportWrappedKeyTest); + +typedef KeyMintAidlTestBase EncryptionOperationsTest; + +/* + * EncryptionOperationsTest.RsaNoPaddingSuccess + * + * Verifies that raw RSA encryption works. + */ +TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Padding(PaddingMode::NONE))); + + string message = string(2048 / 8, 'a'); + auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE); + string ciphertext1 = EncryptMessage(message, params); + EXPECT_EQ(2048U / 8, ciphertext1.size()); + + string ciphertext2 = EncryptMessage(message, params); + EXPECT_EQ(2048U / 8, ciphertext2.size()); + + // Unpadded RSA is deterministic + EXPECT_EQ(ciphertext1, ciphertext2); +} + +/* + * EncryptionOperationsTest.RsaNoPaddingShortMessage + * + * Verifies that raw RSA encryption of short messages works. + */ +TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Padding(PaddingMode::NONE))); + + string message = "1"; + auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE); + + string ciphertext = EncryptMessage(message, params); + EXPECT_EQ(2048U / 8, ciphertext.size()); + + string expected_plaintext = string(2048U / 8 - 1, 0) + message; + string plaintext = DecryptMessage(ciphertext, params); + + EXPECT_EQ(expected_plaintext, plaintext); + + // Degenerate case, encrypting a numeric 1 yields 0x00..01 as the ciphertext. + message = static_cast<char>(1); + ciphertext = EncryptMessage(message, params); + EXPECT_EQ(2048U / 8, ciphertext.size()); + EXPECT_EQ(ciphertext, string(2048U / 8 - 1, 0) + message); +} + +/* + * EncryptionOperationsTest.RsaNoPaddingTooLong + * + * Verifies that raw RSA encryption of too-long messages fails in the expected way. + */ +TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Padding(PaddingMode::NONE))); + + string message(2048 / 8 + 1, 'a'); + + auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE); + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params)); + + string result; + EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result)); +} + +/* + * EncryptionOperationsTest.RsaNoPaddingTooLarge + * + * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected + * way. + */ +// TODO(seleneh) add RsaNoPaddingTooLarge test back after decided and implemented new +// version of ExportKey inside generateKey + +/* + * EncryptionOperationsTest.RsaOaepSuccess + * + * Verifies that RSA-OAEP encryption operations work, with all digests. + */ +TEST_P(EncryptionOperationsTest, RsaOaepSuccess) { + auto digests = ValidDigests(false /* withNone */, true /* withMD5 */); + + size_t key_size = 2048; // Need largish key for SHA-512 test. + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(key_size, 65537) + .Padding(PaddingMode::RSA_OAEP) + .Digest(digests))); + + string message = "Hello"; + + for (auto digest : digests) { + auto params = AuthorizationSetBuilder().Digest(digest).Padding(PaddingMode::RSA_OAEP); + string ciphertext1 = EncryptMessage(message, params); + if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl; + EXPECT_EQ(key_size / 8, ciphertext1.size()); + + string ciphertext2 = EncryptMessage(message, params); + EXPECT_EQ(key_size / 8, ciphertext2.size()); + + // OAEP randomizes padding so every result should be different (with astronomically high + // probability). + EXPECT_NE(ciphertext1, ciphertext2); + + string plaintext1 = DecryptMessage(ciphertext1, params); + EXPECT_EQ(message, plaintext1) << "RSA-OAEP failed with digest " << digest; + string plaintext2 = DecryptMessage(ciphertext2, params); + EXPECT_EQ(message, plaintext2) << "RSA-OAEP failed with digest " << digest; + + // Decrypting corrupted ciphertext should fail. + size_t offset_to_corrupt = random() % ciphertext1.size(); + char corrupt_byte; + do { + corrupt_byte = static_cast<char>(random() % 256); + } while (corrupt_byte == ciphertext1[offset_to_corrupt]); + ciphertext1[offset_to_corrupt] = corrupt_byte; + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params)); + string result; + EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result)); + EXPECT_EQ(0U, result.size()); + } +} + +/* + * EncryptionOperationsTest.RsaOaepInvalidDigest + * + * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate + * without a digest. + */ +TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Padding(PaddingMode::RSA_OAEP) + .Digest(Digest::NONE))); + string message = "Hello World!"; + + auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::NONE); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, Begin(KeyPurpose::ENCRYPT, params)); +} + +/* + * EncryptionOperationsTest.RsaOaepInvalidDigest + * + * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt + * with a different digest than was used to encrypt. + */ +TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(1024, 65537) + .Padding(PaddingMode::RSA_OAEP) + .Digest(Digest::SHA_2_224, Digest::SHA_2_256))); + string message = "Hello World!"; + string ciphertext = EncryptMessage( + message, + AuthorizationSetBuilder().Digest(Digest::SHA_2_224).Padding(PaddingMode::RSA_OAEP)); + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::RSA_OAEP))); + string result; + EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result)); + EXPECT_EQ(0U, result.size()); +} + +/* + * EncryptionOperationsTest.RsaOaepTooLarge + * + * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a + * too-large message. + */ +TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Padding(PaddingMode::RSA_OAEP) + .Digest(Digest::SHA_2_256))); + constexpr size_t digest_size = 256 /* SHA_2_256 */ / 8; + constexpr size_t oaep_overhead = 2 * digest_size + 2; + string message(2048 / 8 - oaep_overhead + 1, 'a'); + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder() + .Padding(PaddingMode::RSA_OAEP) + .Digest(Digest::SHA_2_256))); + string result; + ErrorCode error = Finish(message, &result); + EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT); + EXPECT_EQ(0U, result.size()); +} + +/* + * EncryptionOperationsTest.RsaPkcs1Success + * + * Verifies that RSA PKCS encryption/decrypts works. + */ +TEST_P(EncryptionOperationsTest, RsaPkcs1Success) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT))); + + string message = "Hello World!"; + auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT); + string ciphertext1 = EncryptMessage(message, params); + EXPECT_EQ(2048U / 8, ciphertext1.size()); + + string ciphertext2 = EncryptMessage(message, params); + EXPECT_EQ(2048U / 8, ciphertext2.size()); + + // PKCS1 v1.5 randomizes padding so every result should be different. + EXPECT_NE(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, params); + EXPECT_EQ(message, plaintext); + + // Decrypting corrupted ciphertext should fail. + size_t offset_to_corrupt = random() % ciphertext1.size(); + char corrupt_byte; + do { + corrupt_byte = static_cast<char>(random() % 256); + } while (corrupt_byte == ciphertext1[offset_to_corrupt]); + ciphertext1[offset_to_corrupt] = corrupt_byte; + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params)); + string result; + EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result)); + EXPECT_EQ(0U, result.size()); +} + +/* + * EncryptionOperationsTest.RsaPkcs1TooLarge + * + * Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large. + */ +TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT))); + string message(2048 / 8 - 10, 'a'); + + auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT); + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params)); + string result; + ErrorCode error = Finish(message, &result); + EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT); + EXPECT_EQ(0U, result.size()); +} + +/* + * EncryptionOperationsTest.EcdsaEncrypt + * + * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way. + */ +TEST_P(EncryptionOperationsTest, EcdsaEncrypt) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(256) + .Digest(Digest::NONE))); + auto params = AuthorizationSetBuilder().Digest(Digest::NONE); + ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params)); + ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params)); +} + +/* + * EncryptionOperationsTest.HmacEncrypt + * + * Verifies that attempting to use HMAC keys to encrypt fails in the correct way. + */ +TEST_P(EncryptionOperationsTest, HmacEncrypt) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .HmacKey(128) + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + auto params = AuthorizationSetBuilder() + .Digest(Digest::SHA_2_256) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params)); + ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params)); +} + +/* + * EncryptionOperationsTest.AesEcbRoundTripSuccess + * + * Verifies that AES ECB mode works. + */ +TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::ECB) + .Padding(PaddingMode::NONE))); + + ASSERT_GT(key_blob_.size(), 0U); + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE); + + // Two-block message. + string message = "12345678901234567890123456789012"; + string ciphertext1 = EncryptMessage(message, params); + EXPECT_EQ(message.size(), ciphertext1.size()); + + string ciphertext2 = EncryptMessage(string(message), params); + EXPECT_EQ(message.size(), ciphertext2.size()); + + // ECB is deterministic. + EXPECT_EQ(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, params); + EXPECT_EQ(message, plaintext); +} + +/* + * EncryptionOperationsTest.AesEcbRoundTripSuccess + * + * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified. + */ +TEST_P(EncryptionOperationsTest, AesWrongMode) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::CBC) + .Padding(PaddingMode::NONE))); + + ASSERT_GT(key_blob_.size(), 0U); + + // Two-block message. + string message = "12345678901234567890123456789012"; + EXPECT_EQ( + ErrorCode::INCOMPATIBLE_BLOCK_MODE, + Begin(KeyPurpose::ENCRYPT, + AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE))); +} + +/* + * EncryptionOperationsTest.AesWrongPurpose + * + * Verifies that AES encryption fails in the correct way when an unauthorized purpose is + * specified. + */ +TEST_P(EncryptionOperationsTest, AesWrongPurpose) { + auto err = GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesKey(128) + .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT) + .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) + .Authorization(TAG_MIN_MAC_LENGTH, 128) + .Padding(PaddingMode::NONE)); + ASSERT_EQ(ErrorCode::OK, err) << "Got " << err; + ASSERT_GT(key_blob_.size(), 0U); + + err = Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128)); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err; + + CheckedDeleteKey(); + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesKey(128) + .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT) + .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) + .Authorization(TAG_MIN_MAC_LENGTH, 128) + .Padding(PaddingMode::NONE))); + + err = Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128)); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err; +} + +/* + * EncryptionOperationsTest.AesEcbNoPaddingWrongInputSize + * + * Verifies that AES encryption fails in the correct way when provided an input that is not a + * multiple of the block size and no padding is specified. + */ +TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::ECB) + .Padding(PaddingMode::NONE))); + // Message is slightly shorter than two blocks. + string message(16 * 2 - 1, 'a'); + + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE); + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params)); + string ciphertext; + EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &ciphertext)); + EXPECT_EQ(0U, ciphertext.size()); +} + +/* + * EncryptionOperationsTest.AesEcbPkcs7Padding + * + * Verifies that AES PKCS7 padding works for any message length. + */ +TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::ECB) + .Padding(PaddingMode::PKCS7))); + + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7); + + // Try various message lengths; all should work. + for (size_t i = 0; i < 32; ++i) { + string message(i, 'a'); + string ciphertext = EncryptMessage(message, params); + EXPECT_EQ(i + 16 - (i % 16), ciphertext.size()); + string plaintext = DecryptMessage(ciphertext, params); + EXPECT_EQ(message, plaintext); + } +} + +/* + * EncryptionOperationsTest.AesEcbWrongPadding + * + * Verifies that AES enryption fails in the correct way when an unauthorized padding mode is + * specified. + */ +TEST_P(EncryptionOperationsTest, AesEcbWrongPadding) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::ECB) + .Padding(PaddingMode::NONE))); + + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7); + + // Try various message lengths; all should fail + for (size_t i = 0; i < 32; ++i) { + string message(i, 'a'); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params)); + } +} + +/* + * EncryptionOperationsTest.AesEcbPkcs7PaddingCorrupted + * + * Verifies that AES decryption fails in the correct way when the padding is corrupted. + */ +TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::ECB) + .Padding(PaddingMode::PKCS7))); + + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7); + + string message = "a"; + string ciphertext = EncryptMessage(message, params); + EXPECT_EQ(16U, ciphertext.size()); + EXPECT_NE(ciphertext, message); + ++ciphertext[ciphertext.size() / 2]; + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params)); + string plaintext; + EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext)); +} + +vector<uint8_t> CopyIv(const AuthorizationSet& set) { + auto iv = set.GetTagValue(TAG_NONCE); + EXPECT_TRUE(iv.isOk()); + return iv.value(); +} + +/* + * EncryptionOperationsTest.AesCtrRoundTripSuccess + * + * Verifies that AES CTR mode works. + */ +TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::CTR) + .Padding(PaddingMode::NONE))); + + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE); + + string message = "123"; + AuthorizationSet out_params; + string ciphertext1 = EncryptMessage(message, params, &out_params); + vector<uint8_t> iv1 = CopyIv(out_params); + EXPECT_EQ(16U, iv1.size()); + + EXPECT_EQ(message.size(), ciphertext1.size()); + + out_params.Clear(); + string ciphertext2 = EncryptMessage(message, params, &out_params); + vector<uint8_t> iv2 = CopyIv(out_params); + EXPECT_EQ(16U, iv2.size()); + + // IVs should be random, so ciphertexts should differ. + EXPECT_NE(ciphertext1, ciphertext2); + + auto params_iv1 = + AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv1); + auto params_iv2 = + AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv2); + + string plaintext = DecryptMessage(ciphertext1, params_iv1); + EXPECT_EQ(message, plaintext); + plaintext = DecryptMessage(ciphertext2, params_iv2); + EXPECT_EQ(message, plaintext); + + // Using the wrong IV will result in a "valid" decryption, but the data will be garbage. + plaintext = DecryptMessage(ciphertext1, params_iv2); + EXPECT_NE(message, plaintext); + plaintext = DecryptMessage(ciphertext2, params_iv1); + EXPECT_NE(message, plaintext); +} + +/* + * EncryptionOperationsTest.AesIncremental + * + * Verifies that AES works, all modes, when provided data in various size increments. + */ +TEST_P(EncryptionOperationsTest, AesIncremental) { + auto block_modes = { + BlockMode::ECB, + BlockMode::CBC, + BlockMode::CTR, + BlockMode::GCM, + }; + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(block_modes) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + for (int increment = 1; increment <= 240; ++increment) { + for (auto block_mode : block_modes) { + string message(240, 'a'); + auto params = AuthorizationSetBuilder() + .BlockMode(block_mode) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */; + + AuthorizationSet output_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params)); + + string ciphertext; + int32_t input_consumed; + string to_send; + for (size_t i = 0; i < message.size(); i += increment) { + to_send.append(message.substr(i, increment)); + EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed)); + EXPECT_EQ(to_send.length(), input_consumed); + to_send = to_send.substr(input_consumed); + EXPECT_EQ(0U, to_send.length()); + + switch (block_mode) { + case BlockMode::ECB: + case BlockMode::CBC: + // Implementations must take as many blocks as possible, leaving less + // than a block. + EXPECT_LE(to_send.length(), 16U); + break; + case BlockMode::GCM: + case BlockMode::CTR: + // Implementations must always take all the data. + EXPECT_EQ(0U, to_send.length()); + break; + } + } + EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send; + + switch (block_mode) { + case BlockMode::GCM: + EXPECT_EQ(message.size() + 16, ciphertext.size()); + break; + case BlockMode::CTR: + EXPECT_EQ(message.size(), ciphertext.size()); + break; + case BlockMode::CBC: + case BlockMode::ECB: + EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size()); + break; + } + + auto iv = output_params.GetTagValue(TAG_NONCE); + switch (block_mode) { + case BlockMode::CBC: + case BlockMode::GCM: + case BlockMode::CTR: + ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode; + EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size()); + params.push_back(TAG_NONCE, iv.value()); + break; + + case BlockMode::ECB: + EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV"; + break; + } + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params)) + << "Decrypt begin() failed for block mode " << block_mode; + + string plaintext; + for (size_t i = 0; i < ciphertext.size(); i += increment) { + to_send.append(ciphertext.substr(i, increment)); + EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed)); + to_send = to_send.substr(input_consumed); + } + ErrorCode error = Finish(to_send, &plaintext); + ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode + << " and increment " << increment; + if (error == ErrorCode::OK) { + ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode " + << block_mode << " and increment " << increment; + } + } + } +} + +struct AesCtrSp80038aTestVector { + const char* key; + const char* nonce; + const char* plaintext; + const char* ciphertext; +}; + +// These test vectors are taken from +// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5. +static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = { + // AES-128 + { + "2b7e151628aed2a6abf7158809cf4f3c", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", + "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff" + "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee", + }, + // AES-192 + { + "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", + "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94" + "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050", + }, + // AES-256 + { + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710", + "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5" + "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6", + }, +}; + +/* + * EncryptionOperationsTest.AesCtrSp80038aTestVector + * + * Verifies AES CTR implementation against SP800-38A test vectors. + */ +TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) { + std::vector<uint32_t> InvalidSizes = InvalidKeySizes(Algorithm::AES); + for (size_t i = 0; i < 3; i++) { + const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]); + const string key = hex2str(test.key); + if (std::find(InvalidSizes.begin(), InvalidSizes.end(), (key.size() * 8)) != + InvalidSizes.end()) + continue; + const string nonce = hex2str(test.nonce); + const string plaintext = hex2str(test.plaintext); + const string ciphertext = hex2str(test.ciphertext); + CheckAesCtrTestVector(key, nonce, plaintext, ciphertext); + } +} + +/* + * EncryptionOperationsTest.AesCtrIncompatiblePaddingMode + * + * Verifies that keymint rejects use of CTR mode with PKCS7 padding in the correct way. + */ +TEST_P(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::CTR) + .Padding(PaddingMode::PKCS7))); + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params)); +} + +/* + * EncryptionOperationsTest.AesCtrInvalidCallerNonce + * + * Verifies that keymint fails correctly when the user supplies an incorrect-size nonce. + */ +TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::CTR) + .Authorization(TAG_CALLER_NONCE) + .Padding(PaddingMode::NONE))); + + auto params = AuthorizationSetBuilder() + .BlockMode(BlockMode::CTR) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NONCE, AidlBuf(string(1, 'a'))); + EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params)); + + params = AuthorizationSetBuilder() + .BlockMode(BlockMode::CTR) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NONCE, AidlBuf(string(15, 'a'))); + EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params)); + + params = AuthorizationSetBuilder() + .BlockMode(BlockMode::CTR) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NONCE, AidlBuf(string(17, 'a'))); + EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params)); +} + +/* + * EncryptionOperationsTest.AesCtrInvalidCallerNonce + * + * Verifies that keymint fails correctly when the user supplies an incorrect-size nonce. + */ +TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::CBC) + .Padding(PaddingMode::NONE))); + // Two-block message. + string message = "12345678901234567890123456789012"; + auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE); + AuthorizationSet out_params; + string ciphertext1 = EncryptMessage(message, params, &out_params); + vector<uint8_t> iv1 = CopyIv(out_params); + EXPECT_EQ(message.size(), ciphertext1.size()); + + out_params.Clear(); + + string ciphertext2 = EncryptMessage(message, params, &out_params); + vector<uint8_t> iv2 = CopyIv(out_params); + EXPECT_EQ(message.size(), ciphertext2.size()); + + // IVs should be random, so ciphertexts should differ. + EXPECT_NE(ciphertext1, ciphertext2); + + params.push_back(TAG_NONCE, iv1); + string plaintext = DecryptMessage(ciphertext1, params); + EXPECT_EQ(message, plaintext); +} + +/* + * EncryptionOperationsTest.AesCallerNonce + * + * Verifies that AES caller-provided nonces work correctly. + */ +TEST_P(EncryptionOperationsTest, AesCallerNonce) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::CBC) + .Authorization(TAG_CALLER_NONCE) + .Padding(PaddingMode::NONE))); + + string message = "12345678901234567890123456789012"; + + // Don't specify nonce, should get a random one. + AuthorizationSetBuilder params = + AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE); + AuthorizationSet out_params; + string ciphertext = EncryptMessage(message, params, &out_params); + EXPECT_EQ(message.size(), ciphertext.size()); + EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size()); + + params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value()); + string plaintext = DecryptMessage(ciphertext, params); + EXPECT_EQ(message, plaintext); + + // Now specify a nonce, should also work. + params = AuthorizationSetBuilder() + .BlockMode(BlockMode::CBC) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NONCE, AidlBuf("abcdefghijklmnop")); + out_params.Clear(); + ciphertext = EncryptMessage(message, params, &out_params); + + // Decrypt with correct nonce. + plaintext = DecryptMessage(ciphertext, params); + EXPECT_EQ(message, plaintext); + + // Try with wrong nonce. + params = AuthorizationSetBuilder() + .BlockMode(BlockMode::CBC) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NONCE, AidlBuf("aaaaaaaaaaaaaaaa")); + plaintext = DecryptMessage(ciphertext, params); + EXPECT_NE(message, plaintext); +} + +/* + * EncryptionOperationsTest.AesCallerNonceProhibited + * + * Verifies that caller-provided nonces are not permitted when not specified in the key + * authorizations. + */ +TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::CBC) + .Padding(PaddingMode::NONE))); + + string message = "12345678901234567890123456789012"; + + // Don't specify nonce, should get a random one. + AuthorizationSetBuilder params = + AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE); + AuthorizationSet out_params; + string ciphertext = EncryptMessage(message, params, &out_params); + EXPECT_EQ(message.size(), ciphertext.size()); + EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size()); + + params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value()); + string plaintext = DecryptMessage(ciphertext, params); + EXPECT_EQ(message, plaintext); + + // Now specify a nonce, should fail + params = AuthorizationSetBuilder() + .BlockMode(BlockMode::CBC) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NONCE, AidlBuf("abcdefghijklmnop")); + out_params.Clear(); + EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED, Begin(KeyPurpose::ENCRYPT, params, &out_params)); +} + +/* + * EncryptionOperationsTest.AesGcmRoundTripSuccess + * + * Verifies that AES GCM mode works. + */ +TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + + auto begin_params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + + auto update_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params)) + << "Begin encrypt"; + string ciphertext; + AuthorizationSet update_out_params; + ASSERT_EQ(ErrorCode::OK, Finish(update_params, message, "", &update_out_params, &ciphertext)); + + ASSERT_EQ(ciphertext.length(), message.length() + 16); + + // Grab nonce + begin_params.push_back(begin_out_params); + + // Decrypt. + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt"; + string plaintext; + int32_t input_consumed; + ASSERT_EQ(ErrorCode::OK, + Update(update_params, ciphertext, &update_out_params, &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext)); + EXPECT_EQ(message.length(), plaintext.length()); + EXPECT_EQ(message, plaintext); +} + +/* + * EncryptionOperationsTest.AesGcmRoundTripWithDelaySuccess + * + * Verifies that AES GCM mode works, even when there's a long delay + * between operations. + */ +TEST_P(EncryptionOperationsTest, AesGcmRoundTripWithDelaySuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + + auto begin_params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + + auto update_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params)) + << "Begin encrypt"; + string ciphertext; + AuthorizationSet update_out_params; + sleep(5); + ASSERT_EQ(ErrorCode::OK, Finish(update_params, message, "", &update_out_params, &ciphertext)); + + ASSERT_EQ(ciphertext.length(), message.length() + 16); + + // Grab nonce + begin_params.push_back(begin_out_params); + + // Decrypt. + ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt"; + string plaintext; + int32_t input_consumed; + sleep(5); + ASSERT_EQ(ErrorCode::OK, + Update(update_params, ciphertext, &update_out_params, &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + sleep(5); + EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext)); + EXPECT_EQ(message.length(), plaintext.length()); + EXPECT_EQ(message, plaintext); +} + +/* + * EncryptionOperationsTest.AesGcmDifferentNonces + * + * Verifies that encrypting the same data with different nonces produces different outputs. + */ +TEST_P(EncryptionOperationsTest, AesGcmDifferentNonces) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128) + .Authorization(TAG_CALLER_NONCE))); + + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + string nonce1 = "000000000000"; + string nonce2 = "111111111111"; + string nonce3 = "222222222222"; + + string ciphertext1 = + EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce1)); + string ciphertext2 = + EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce2)); + string ciphertext3 = + EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce3)); + + ASSERT_NE(ciphertext1, ciphertext2); + ASSERT_NE(ciphertext1, ciphertext3); + ASSERT_NE(ciphertext2, ciphertext3); +} + +/* + * EncryptionOperationsTest.AesGcmTooShortTag + * + * Verifies that AES GCM mode fails correctly when a too-short tag length is specified. + */ +TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string message = "123456789012345678901234567890123456"; + auto params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 96); + + EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::ENCRYPT, params)); +} + +/* + * EncryptionOperationsTest.AesGcmTooShortTagOnDecrypt + * + * Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption. + */ +TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + string aad = "foobar"; + string message = "123456789012345678901234567890123456"; + auto params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + + auto finish_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params)); + EXPECT_EQ(1U, begin_out_params.size()); + ASSERT_TRUE(begin_out_params.GetTagValue(TAG_NONCE).isOk()); + + AuthorizationSet finish_out_params; + string ciphertext; + EXPECT_EQ(ErrorCode::OK, + Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext)); + + params = AuthorizationSetBuilder() + .Authorizations(begin_out_params) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 96); + + // Decrypt. + EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::DECRYPT, params)); +} + +/* + * EncryptionOperationsTest.AesGcmCorruptKey + * + * Verifies that AES GCM mode fails correctly when the decryption key is incorrect. + */ +TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) { + const uint8_t nonce_bytes[] = { + 0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f, + }; + string nonce = make_string(nonce_bytes); + const uint8_t ciphertext_bytes[] = { + 0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc, + 0xd2, 0xcb, 0x16, 0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78, + 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a, 0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d, + 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76, 0x76, 0x5e, 0xfb, + 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd, + 0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0, + }; + string ciphertext = make_string(ciphertext_bytes); + + auto params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128) + .Authorization(TAG_NONCE, nonce.data(), nonce.size()); + + auto import_params = AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_CALLER_NONCE) + .Authorization(TAG_MIN_MAC_LENGTH, 128); + + // Import correct key and decrypt + const uint8_t key_bytes[] = { + 0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d, + 0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb, + }; + string key = make_string(key_bytes); + ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key)); + string plaintext = DecryptMessage(ciphertext, params); + CheckedDeleteKey(); + + // Corrupt key and attempt to decrypt + key[0] = 0; + ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key)); + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params)); + EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext)); + CheckedDeleteKey(); +} + +/* + * EncryptionOperationsTest.AesGcmAadNoData + * + * Verifies that AES GCM mode works when provided additional authenticated data, but no data to + * encrypt. + */ +TEST_P(EncryptionOperationsTest, AesGcmAadNoData) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + string aad = "1234567890123456"; + auto params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + + auto finish_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params)); + string ciphertext; + AuthorizationSet finish_out_params; + EXPECT_EQ(ErrorCode::OK, Finish(finish_params, "" /* input */, "" /* signature */, + &finish_out_params, &ciphertext)); + EXPECT_TRUE(finish_out_params.empty()); + + // Grab nonce + params.push_back(begin_out_params); + + // Decrypt. + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params)); + string plaintext; + EXPECT_EQ(ErrorCode::OK, Finish(finish_params, ciphertext, "" /* signature */, + &finish_out_params, &plaintext)); + + EXPECT_TRUE(finish_out_params.empty()); + + EXPECT_EQ("", plaintext); +} + +/* + * EncryptionOperationsTest.AesGcmMultiPartAad + * + * Verifies that AES GCM mode works when provided additional authenticated data in multiple + * chunks. + */ +TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) { + const size_t tag_bits = 128; + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + string message = "123456789012345678901234567890123456"; + auto begin_params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, tag_bits); + AuthorizationSet begin_out_params; + + auto update_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3); + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params)); + + // No data, AAD only. + string ciphertext; + int32_t input_consumed; + AuthorizationSet update_out_params; + EXPECT_EQ(ErrorCode::OK, Update(update_params, "" /* input */, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(0U, input_consumed); + EXPECT_EQ(0U, ciphertext.size()); + EXPECT_TRUE(update_out_params.empty()); + + // AAD and data. + EXPECT_EQ(ErrorCode::OK, + Update(update_params, message, &update_out_params, &ciphertext, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_TRUE(update_out_params.empty()); + + EXPECT_EQ(ErrorCode::OK, Finish("" /* input */, &ciphertext)); + // Expect 128-bit (16-byte) tag appended to ciphertext. + EXPECT_EQ(message.size() + (tag_bits >> 3), ciphertext.size()); + + // Grab nonce. + begin_params.push_back(begin_out_params); + + // Decrypt + update_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foofoo", (size_t)6); + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)); + string plaintext; + EXPECT_EQ(ErrorCode::OK, Finish(update_params, ciphertext, "" /* signature */, + &update_out_params, &plaintext)); + EXPECT_TRUE(update_out_params.empty()); + EXPECT_EQ(message, plaintext); +} + +/* + * EncryptionOperationsTest.AesGcmAadOutOfOrder + * + * Verifies that AES GCM mode fails correctly when given AAD after data to encipher. + */ +TEST_P(EncryptionOperationsTest, AesGcmAadOutOfOrder) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + string message = "123456789012345678901234567890123456"; + auto begin_params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + AuthorizationSet begin_out_params; + + auto update_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3); + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params)); + + // No data, AAD only. + string ciphertext; + int32_t input_consumed; + AuthorizationSet update_out_params; + EXPECT_EQ(ErrorCode::OK, Update(update_params, "" /* input */, &update_out_params, &ciphertext, + &input_consumed)); + EXPECT_EQ(0U, input_consumed); + EXPECT_EQ(0U, ciphertext.size()); + EXPECT_TRUE(update_out_params.empty()); + + // AAD and data. + EXPECT_EQ(ErrorCode::OK, + Update(update_params, message, &update_out_params, &ciphertext, &input_consumed)); + EXPECT_EQ(message.size(), input_consumed); + EXPECT_TRUE(update_out_params.empty()); + + // More AAD + EXPECT_EQ(ErrorCode::INVALID_TAG, + Update(update_params, "", &update_out_params, &ciphertext, &input_consumed)); + + op_.clear(); +} + +/* + * EncryptionOperationsTest.AesGcmBadAad + * + * Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong. + */ +TEST_P(EncryptionOperationsTest, AesGcmBadAad) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + string message = "12345678901234567890123456789012"; + auto begin_params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + + auto finish_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params)); + string ciphertext; + AuthorizationSet finish_out_params; + EXPECT_EQ(ErrorCode::OK, + Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext)); + + // Grab nonce + begin_params.push_back(begin_out_params); + + finish_params = AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, + "barfoo" /* Wrong AAD */, (size_t)6); + + // Decrypt. + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params)); + string plaintext; + EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */, + &finish_out_params, &plaintext)); +} + +/* + * EncryptionOperationsTest.AesGcmWrongNonce + * + * Verifies that AES GCM decryption fails correctly when the nonce is incorrect. + */ +TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + string message = "12345678901234567890123456789012"; + auto begin_params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + + auto finish_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params)); + string ciphertext; + AuthorizationSet finish_out_params; + EXPECT_EQ(ErrorCode::OK, + Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext)); + + // Wrong nonce + begin_params.push_back(TAG_NONCE, AidlBuf("123456789012")); + + // Decrypt. + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params)); + string plaintext; + EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */, + &finish_out_params, &plaintext)); + + // With wrong nonce, should have gotten garbage plaintext (or none). + EXPECT_NE(message, plaintext); +} + +/* + * EncryptionOperationsTest.AesGcmCorruptTag + * + * Verifies that AES GCM decryption fails correctly when the tag is wrong. + */ +TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, 128))); + + string aad = "1234567890123456"; + string message = "123456789012345678901234567890123456"; + + auto params = AuthorizationSetBuilder() + .BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, 128); + + auto finish_params = + AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size()); + + // Encrypt + AuthorizationSet begin_out_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params)); + string ciphertext; + AuthorizationSet finish_out_params; + EXPECT_EQ(ErrorCode::OK, + Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext)); + EXPECT_TRUE(finish_out_params.empty()); + + // Corrupt tag + ++(*ciphertext.rbegin()); + + // Grab nonce + params.push_back(begin_out_params); + + // Decrypt. + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params)); + string plaintext; + EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */, + &finish_out_params, &plaintext)); + EXPECT_TRUE(finish_out_params.empty()); +} + +/* + * EncryptionOperationsTest.TripleDesEcbRoundTripSuccess + * + * Verifies that 3DES is basically functional. + */ +TEST_P(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) { + auto auths = AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::ECB) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE); + + ASSERT_EQ(ErrorCode::OK, GenerateKey(auths)); + // Two-block message. + string message = "1234567890123456"; + auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE); + string ciphertext1 = EncryptMessage(message, inParams); + EXPECT_EQ(message.size(), ciphertext1.size()); + + string ciphertext2 = EncryptMessage(string(message), inParams); + EXPECT_EQ(message.size(), ciphertext2.size()); + + // ECB is deterministic. + EXPECT_EQ(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, inParams); + EXPECT_EQ(message, plaintext); +} + +/* + * EncryptionOperationsTest.TripleDesEcbNotAuthorized + * + * Verifies that CBC keys reject ECB usage. + */ +TEST_P(EncryptionOperationsTest, TripleDesEcbNotAuthorized) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + + auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, inParams)); +} + +/* + * EncryptionOperationsTest.TripleDesEcbPkcs7Padding + * + * Tests ECB mode with PKCS#7 padding, various message sizes. + */ +TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::ECB) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::PKCS7))); + + for (size_t i = 0; i < 32; ++i) { + string message(i, 'a'); + auto inParams = + AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7); + string ciphertext = EncryptMessage(message, inParams); + EXPECT_EQ(i + 8 - (i % 8), ciphertext.size()); + string plaintext = DecryptMessage(ciphertext, inParams); + EXPECT_EQ(message, plaintext); + } +} + +/* + * EncryptionOperationsTest.TripleDesEcbNoPaddingKeyWithPkcs7Padding + * + * Verifies that keys configured for no padding reject PKCS7 padding + */ +TEST_P(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::ECB) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + for (size_t i = 0; i < 32; ++i) { + auto inParams = + AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, inParams)); + } +} + +/* + * EncryptionOperationsTest.TripleDesEcbPkcs7PaddingCorrupted + * + * Verifies that corrupted padding is detected. + */ +TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::ECB) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::PKCS7))); + + string message = "a"; + string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7); + EXPECT_EQ(8U, ciphertext.size()); + EXPECT_NE(ciphertext, message); + ++ciphertext[ciphertext.size() / 2]; + + AuthorizationSetBuilder begin_params; + begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB); + begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7); + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)); + string plaintext; + int32_t input_consumed; + EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext)); +} + +struct TripleDesTestVector { + const char* name; + const KeyPurpose purpose; + const BlockMode block_mode; + const PaddingMode padding_mode; + const char* key; + const char* iv; + const char* input; + const char* output; +}; + +// These test vectors are from NIST CAVP, plus a few custom variants to test padding, since all +// of the NIST vectors are multiples of the block size. +static const TripleDesTestVector kTripleDesTestVectors[] = { + { + "TECBMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE, + "a2b5bc67da13dc92cd9d344aa238544a0e1fa79ef76810cd", // key + "", // IV + "329d86bdf1bc5af4", // input + "d946c2756d78633f", // output + }, + { + "TECBMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE, + "49e692290d2a5e46bace79b9648a4c5d491004c262dc9d49", // key + "", // IV + "6b1540781b01ce1997adae102dbf3c5b", // input + "4d0dc182d6e481ac4a3dc6ab6976ccae", // output + }, + { + "TECBMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE, + "52daec2ac7dc1958377392682f37860b2cc1ea2304bab0e9", // key + "", // IV + "6daad94ce08acfe7", // input + "660e7d32dcc90e79", // output + }, + { + "TECBMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE, + "7f8fe3d3f4a48394fb682c2919926d6ddfce8932529229ce", // key + "", // IV + "e9653a0a1f05d31b9acd12d73aa9879d", // input + "9b2ae9d998efe62f1b592e7e1df8ff38", // output + }, + { + "TCBCMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE, + "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37", // key + "43f791134c5647ba", // IV + "dcc153cef81d6f24", // input + "92538bd8af18d3ba", // output + }, + { + "TCBCMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE, + "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key + "c2e999cb6249023c", // IV + "c689aee38a301bb316da75db36f110b5", // input + "e9afaba5ec75ea1bbe65506655bb4ecb", // output + }, + { + "TCBCMMT3 Encrypt 1 PKCS7 variant", KeyPurpose::ENCRYPT, BlockMode::CBC, + PaddingMode::PKCS7, + "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key + "c2e999cb6249023c", // IV + "c689aee38a301bb316da75db36f110b500", // input + "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156", // output + }, + { + "TCBCMMT3 Encrypt 1 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::CBC, + PaddingMode::PKCS7, + "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358", // key + "c2e999cb6249023c", // IV + "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156", // input + "c689aee38a301bb316da75db36f110b500", // output + }, + { + "TCBCMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE, + "5eb6040d46082c7aa7d06dfd08dfeac8c18364c1548c3ba1", // key + "41746c7e442d3681", // IV + "c53a7b0ec40600fe", // input + "d4f00eb455de1034", // output + }, + { + "TCBCMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE, + "5b1cce7c0dc1ec49130dfb4af45785ab9179e567f2c7d549", // key + "3982bc02c3727d45", // IV + "6006f10adef52991fcc777a1238bbb65", // input + "edae09288e9e3bc05746d872b48e3b29", // output + }, +}; + +/* + * EncryptionOperationsTest.TripleDesTestVector + * + * Verifies that NIST (plus a few extra) test vectors produce the correct results. + */ +TEST_P(EncryptionOperationsTest, TripleDesTestVector) { + constexpr size_t num_tests = sizeof(kTripleDesTestVectors) / sizeof(TripleDesTestVector); + for (auto* test = kTripleDesTestVectors; test < kTripleDesTestVectors + num_tests; ++test) { + SCOPED_TRACE(test->name); + CheckTripleDesTestVector(test->purpose, test->block_mode, test->padding_mode, + hex2str(test->key), hex2str(test->iv), hex2str(test->input), + hex2str(test->output)); + } +} + +/* + * EncryptionOperationsTest.TripleDesCbcRoundTripSuccess + * + * Validates CBC mode functionality. + */ +TEST_P(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + + ASSERT_GT(key_blob_.size(), 0U); + + // Two-block message. + string message = "1234567890123456"; + vector<uint8_t> iv1; + string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv1); + EXPECT_EQ(message.size(), ciphertext1.size()); + + vector<uint8_t> iv2; + string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv2); + EXPECT_EQ(message.size(), ciphertext2.size()); + + // IVs should be random, so ciphertexts should differ. + EXPECT_NE(iv1, iv2); + EXPECT_NE(ciphertext1, ciphertext2); + + string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv1); + EXPECT_EQ(message, plaintext); +} + +/* + * EncryptionOperationsTest.TripleDesCallerIv + * + * Validates that 3DES keys can allow caller-specified IVs, and use them correctly. + */ +TEST_P(EncryptionOperationsTest, TripleDesCallerIv) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_CALLER_NONCE) + .Padding(PaddingMode::NONE))); + string message = "1234567890123456"; + vector<uint8_t> iv; + // Don't specify IV, should get a random one. + string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv); + EXPECT_EQ(message.size(), ciphertext1.size()); + EXPECT_EQ(8U, iv.size()); + + string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv); + EXPECT_EQ(message, plaintext); + + // Now specify an IV, should also work. + iv = AidlBuf("abcdefgh"); + string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, iv); + + // Decrypt with correct IV. + plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, iv); + EXPECT_EQ(message, plaintext); + + // Now try with wrong IV. + plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, AidlBuf("aaaaaaaa")); + EXPECT_NE(message, plaintext); +} + +/* + * EncryptionOperationsTest, TripleDesCallerNonceProhibited. + * + * Verifies that 3DES keys without TAG_CALLER_NONCE do not allow caller-specified IVS. + */ +TEST_P(EncryptionOperationsTest, TripleDesCallerNonceProhibited) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + + string message = "12345678901234567890123456789012"; + vector<uint8_t> iv; + // Don't specify nonce, should get a random one. + string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv); + EXPECT_EQ(message.size(), ciphertext1.size()); + EXPECT_EQ(8U, iv.size()); + + string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv); + EXPECT_EQ(message, plaintext); + + // Now specify a nonce, should fail. + auto input_params = AuthorizationSetBuilder() + .Authorization(TAG_NONCE, AidlBuf("abcdefgh")) + .BlockMode(BlockMode::CBC) + .Padding(PaddingMode::NONE); + AuthorizationSet output_params; + EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED, + Begin(KeyPurpose::ENCRYPT, input_params, &output_params)); +} + +/* + * EncryptionOperationsTest.TripleDesCbcNotAuthorized + * + * Verifies that 3DES ECB-only keys do not allow CBC usage. + */ +TEST_P(EncryptionOperationsTest, TripleDesCbcNotAuthorized) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::ECB) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + // Two-block message. + string message = "1234567890123456"; + auto begin_params = + AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, begin_params)); +} + +/* + * EncryptionOperationsTest.TripleDesCbcNoPaddingWrongInputSize + * + * Verifies that unpadded CBC operations reject inputs that are not a multiple of block size. + */ +TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + // Message is slightly shorter than two blocks. + string message = "123456789012345"; + + auto begin_params = + AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE); + AuthorizationSet output_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params)); + string ciphertext; + EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext)); +} + +/* + * EncryptionOperationsTest, TripleDesCbcPkcs7Padding. + * + * Verifies that PKCS7 padding works correctly in CBC mode. + */ +TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::PKCS7))); + + // Try various message lengths; all should work. + for (size_t i = 0; i < 32; ++i) { + string message(i, 'a'); + vector<uint8_t> iv; + string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv); + EXPECT_EQ(i + 8 - (i % 8), ciphertext.size()); + string plaintext = DecryptMessage(ciphertext, BlockMode::CBC, PaddingMode::PKCS7, iv); + EXPECT_EQ(message, plaintext); + } +} + +/* + * EncryptionOperationsTest.TripleDesCbcNoPaddingKeyWithPkcs7Padding + * + * Verifies that a key that requires PKCS7 padding cannot be used in unpadded mode. + */ +TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + + // Try various message lengths; all should fail. + for (size_t i = 0; i < 32; ++i) { + auto begin_params = + AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::PKCS7); + EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, begin_params)); + } +} + +/* + * EncryptionOperationsTest.TripleDesCbcPkcs7PaddingCorrupted + * + * Verifies that corrupted PKCS7 padding is rejected during decryption. + */ +TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::PKCS7))); + + string message = "a"; + vector<uint8_t> iv; + string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv); + EXPECT_EQ(8U, ciphertext.size()); + EXPECT_NE(ciphertext, message); + ++ciphertext[ciphertext.size() / 2]; + + auto begin_params = AuthorizationSetBuilder() + .BlockMode(BlockMode::CBC) + .Padding(PaddingMode::PKCS7) + .Authorization(TAG_NONCE, iv); + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)); + string plaintext; + int32_t input_consumed; + EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed)); + EXPECT_EQ(ciphertext.size(), input_consumed); + EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext)); +} + +/* + * EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding. + * + * Verifies that 3DES CBC works with many different input sizes. + */ +TEST_P(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .TripleDesEncryptionKey(168) + .BlockMode(BlockMode::CBC) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Padding(PaddingMode::NONE))); + + int increment = 7; + string message(240, 'a'); + AuthorizationSet input_params = + AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE); + AuthorizationSet output_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params)); + + string ciphertext; + int32_t input_consumed; + for (size_t i = 0; i < message.size(); i += increment) + EXPECT_EQ(ErrorCode::OK, + Update(message.substr(i, increment), &ciphertext, &input_consumed)); + EXPECT_EQ(ErrorCode::OK, Finish(&ciphertext)); + EXPECT_EQ(message.size(), ciphertext.size()); + + // Move TAG_NONCE into input_params + input_params = output_params; + input_params.push_back(TAG_BLOCK_MODE, BlockMode::CBC); + input_params.push_back(TAG_PADDING, PaddingMode::NONE); + output_params.Clear(); + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params)); + string plaintext; + for (size_t i = 0; i < ciphertext.size(); i += increment) + EXPECT_EQ(ErrorCode::OK, + Update(ciphertext.substr(i, increment), &plaintext, &input_consumed)); + EXPECT_EQ(ErrorCode::OK, Finish(&plaintext)); + EXPECT_EQ(ciphertext.size(), plaintext.size()); + EXPECT_EQ(message, plaintext); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(EncryptionOperationsTest); + +typedef KeyMintAidlTestBase MaxOperationsTest; + +/* + * MaxOperationsTest.TestLimitAes + * + * Verifies that the max uses per boot tag works correctly with AES keys. + */ +TEST_P(MaxOperationsTest, TestLimitAes) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .EcbMode() + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAX_USES_PER_BOOT, 3))); + + string message = "1234567890123456"; + + auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE); + + EncryptMessage(message, params); + EncryptMessage(message, params); + EncryptMessage(message, params); + + // Fourth time should fail. + EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::ENCRYPT, params)); +} + +/* + * MaxOperationsTest.TestLimitAes + * + * Verifies that the max uses per boot tag works correctly with RSA keys. + */ +TEST_P(MaxOperationsTest, TestLimitRsa) { + if (SecLevel() == SecurityLevel::STRONGBOX) return; + + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaSigningKey(1024, 65537) + .NoDigestOrPadding() + .Authorization(TAG_MAX_USES_PER_BOOT, 3))); + + string message = "1234567890123456"; + + auto params = AuthorizationSetBuilder().NoDigestOrPadding(); + + SignMessage(message, params); + SignMessage(message, params); + SignMessage(message, params); + + // Fourth time should fail. + EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params)); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(MaxOperationsTest); + +typedef KeyMintAidlTestBase AddEntropyTest; + +/* + * AddEntropyTest.AddEntropy + * + * Verifies that the addRngEntropy method doesn't blow up. There's no way to test that entropy + * is actually added. + */ +TEST_P(AddEntropyTest, AddEntropy) { + string data = "foo"; + EXPECT_TRUE(keyMint().addRngEntropy(vector<uint8_t>(data.begin(), data.end())).isOk()); +} + +/* + * AddEntropyTest.AddEmptyEntropy + * + * Verifies that the addRngEntropy method doesn't blow up when given an empty buffer. + */ +TEST_P(AddEntropyTest, AddEmptyEntropy) { + EXPECT_TRUE(keyMint().addRngEntropy(AidlBuf()).isOk()); +} + +/* + * AddEntropyTest.AddLargeEntropy + * + * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data. + */ +TEST_P(AddEntropyTest, AddLargeEntropy) { + EXPECT_TRUE(keyMint().addRngEntropy(AidlBuf(string(2 * 1024, 'a'))).isOk()); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(AddEntropyTest); + +typedef KeyMintAidlTestBase AttestationTest; + +/* + * AttestationTest.RsaAttestation + * + * Verifies that attesting to RSA keys works and generates the expected output. + */ +// TODO(seleneh) add attestation tests back after decided on the new attestation +// behavior under generateKey and importKey + +typedef KeyMintAidlTestBase KeyDeletionTest; + +/** + * KeyDeletionTest.DeleteKey + * + * This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly + * valid key blob. + */ +TEST_P(KeyDeletionTest, DeleteKey) { + auto error = GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_ROLLBACK_RESISTANCE)); + ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK); + + // Delete must work if rollback protection is implemented + if (error == ErrorCode::OK) { + AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced); + ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE)); + + ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */)); + + string message = "12345678901234567890123456789012"; + AuthorizationSet begin_out_params; + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, key_blob_, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE), + &begin_out_params)); + AbortIfNeeded(); + key_blob_ = AidlBuf(); + } +} + +/** + * KeyDeletionTest.DeleteInvalidKey + * + * This test checks that the HAL excepts invalid key blobs.. + */ +TEST_P(KeyDeletionTest, DeleteInvalidKey) { + // Generate key just to check if rollback protection is implemented + auto error = GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_ROLLBACK_RESISTANCE)); + ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK); + + // Delete must work if rollback protection is implemented + if (error == ErrorCode::OK) { + AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced); + ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE)); + + // Delete the key we don't care about the result at this point. + DeleteKey(); + + // Now create an invalid key blob and delete it. + key_blob_ = AidlBuf("just some garbage data which is not a valid key blob"); + + ASSERT_EQ(ErrorCode::OK, DeleteKey()); + } +} + +/** + * KeyDeletionTest.DeleteAllKeys + * + * This test is disarmed by default. To arm it use --arm_deleteAllKeys. + * + * BEWARE: This test has serious side effects. All user keys will be lost! This includes + * FBE/FDE encryption keys, which means that the device will not even boot until after the + * device has been wiped manually (e.g., fastboot flashall -w), and new FBE/FDE keys have + * been provisioned. Use this test only on dedicated testing devices that have no valuable + * credentials stored in Keystore/Keymint. + */ +TEST_P(KeyDeletionTest, DeleteAllKeys) { + if (!arm_deleteAllKeys) return; + auto error = GenerateKey(AuthorizationSetBuilder() + .RsaSigningKey(2048, 65537) + .Digest(Digest::NONE) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_ROLLBACK_RESISTANCE)); + ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK); + + // Delete must work if rollback protection is implemented + if (error == ErrorCode::OK) { + AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced); + ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE)); + + ASSERT_EQ(ErrorCode::OK, DeleteAllKeys()); + + string message = "12345678901234567890123456789012"; + AuthorizationSet begin_out_params; + + EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, + Begin(KeyPurpose::SIGN, key_blob_, + AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE), + &begin_out_params)); + AbortIfNeeded(); + key_blob_ = AidlBuf(); + } +} + +INSTANTIATE_KEYMINT_AIDL_TEST(KeyDeletionTest); + +using UpgradeKeyTest = KeyMintAidlTestBase; + +/* + * UpgradeKeyTest.UpgradeKey + * + * Verifies that calling upgrade key on an up-to-date key works (i.e. does nothing). + */ +TEST_P(UpgradeKeyTest, UpgradeKey) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Padding(PaddingMode::NONE) + .Authorization(TAG_NO_AUTH_REQUIRED))); + + auto result = UpgradeKey(key_blob_); + + // Key doesn't need upgrading. Should get okay, but no new key blob. + EXPECT_EQ(result, std::make_pair(ErrorCode::OK, vector<uint8_t>())); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(UpgradeKeyTest); + +using ClearOperationsTest = KeyMintAidlTestBase; + +/* + * ClearSlotsTest.TooManyOperations + * + * Verifies that TOO_MANY_OPERATIONS is returned after the max number of + * operations are started without being finished or aborted. Also verifies + * that aborting the operations clears the operations. + * + */ +TEST_P(ClearOperationsTest, TooManyOperations) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .RsaEncryptionKey(2048, 65537) + .Padding(PaddingMode::NONE))); + + auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE); + constexpr size_t max_operations = 100; // set to arbituary large number + sp<IKeyMintOperation> op_handles[max_operations]; + AuthorizationSet out_params; + ErrorCode result; + size_t i; + + for (i = 0; i < max_operations; i++) { + result = Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, op_handles[i]); + if (ErrorCode::OK != result) { + break; + } + } + EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS, result); + // Try again just in case there's a weird overflow bug + EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS, + Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params)); + for (size_t j = 0; j < i; j++) { + EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j])) + << "Aboort failed for i = " << j << std::endl; + } + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params)); + AbortIfNeeded(); +} + +INSTANTIATE_KEYMINT_AIDL_TEST(ClearOperationsTest); + +typedef KeyMintAidlTestBase TransportLimitTest; + +/* + * TransportLimitTest.FinishInput + * + * Verifies that passing input data to finish succeeds as expected. + */ +TEST_P(TransportLimitTest, LargeFinishInput) { + ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .AesEncryptionKey(128) + .BlockMode(BlockMode::ECB) + .Padding(PaddingMode::NONE))); + + for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) { + auto cipher_params = + AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE); + + AuthorizationSet out_params; + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params)); + + string plain_message = std::string(1 << msg_size, 'x'); + string encrypted_message; + auto rc = Finish(plain_message, &encrypted_message); + + EXPECT_EQ(ErrorCode::OK, rc); + EXPECT_EQ(plain_message.size(), encrypted_message.size()) + << "Encrypt finish returned OK, but did not consume all of the given input"; + cipher_params.push_back(out_params); + + EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params)); + + string decrypted_message; + rc = Finish(encrypted_message, &decrypted_message); + EXPECT_EQ(ErrorCode::OK, rc); + EXPECT_EQ(plain_message.size(), decrypted_message.size()) + << "Decrypt finish returned OK, did not consume all of the given input"; + } +} + +INSTANTIATE_KEYMINT_AIDL_TEST(TransportLimitTest); + +} // namespace test +} // namespace keymint +} // namespace hardware +} // namespace android + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + for (int i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (std::string(argv[i]) == "--arm_deleteAllKeys") { + arm_deleteAllKeys = true; + } + if (std::string(argv[i]) == "--dump_attestations") { + dump_Attestations = true; + } + } + } + int status = RUN_ALL_TESTS(); + ALOGI("Test result = %d", status); + return status; +} diff --git a/keymint/support/Android.bp b/keymint/support/Android.bp new file mode 100644 index 0000000000..432416e006 --- /dev/null +++ b/keymint/support/Android.bp @@ -0,0 +1,39 @@ +// +// Copyright (C) 2020 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. +// + +cc_library { + name: "libkeymintSupport", + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + ], + srcs: [ + "attestation_record.cpp", + "authorization_set.cpp", + "keymint_utils.cpp", + "key_param_output.cpp", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "android.hardware.keymint-cpp", + "libbase", + "libcrypto", + "libutils", + ], +} diff --git a/keymint/support/OWNERS b/keymint/support/OWNERS new file mode 100644 index 0000000000..a93b171b00 --- /dev/null +++ b/keymint/support/OWNERS @@ -0,0 +1,4 @@ +jbires@google.com +jdanis@google.com +seleneh@google.com +swillden@google.com diff --git a/keymint/support/attestation_record.cpp b/keymint/support/attestation_record.cpp new file mode 100644 index 0000000000..e5659746fe --- /dev/null +++ b/keymint/support/attestation_record.cpp @@ -0,0 +1,387 @@ +/* + * Copyright 2020 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. + */ + +#include <keymintSupport/attestation_record.h> + +#include <android/hardware/keymint/Tag.h> +#include <android/hardware/keymint/TagType.h> + +#include <android-base/logging.h> +#include <assert.h> + +#include <openssl/asn1t.h> +#include <openssl/bn.h> +#include <openssl/evp.h> +#include <openssl/x509.h> + +#include <keymintSupport/authorization_set.h> +#include <keymintSupport/openssl_utils.h> + +#define AT __FILE__ ":" << __LINE__ + +namespace android { +namespace hardware { +namespace keymint { + +struct stack_st_ASN1_TYPE_Delete { + void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); } +}; + +struct ASN1_STRING_Delete { + void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); } +}; + +struct ASN1_TYPE_Delete { + void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); } +}; + +#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER) + +typedef struct km_root_of_trust { + ASN1_OCTET_STRING* verified_boot_key; + ASN1_BOOLEAN device_locked; + ASN1_ENUMERATED* verified_boot_state; + ASN1_OCTET_STRING* verified_boot_hash; +} KM_ROOT_OF_TRUST; + +ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = { + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING), +} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST); +IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST); + +typedef struct km_auth_list { + ASN1_INTEGER_SET* purpose; + ASN1_INTEGER* algorithm; + ASN1_INTEGER* key_size; + ASN1_INTEGER_SET* digest; + ASN1_INTEGER_SET* padding; + ASN1_INTEGER* ec_curve; + ASN1_INTEGER* rsa_public_exponent; + ASN1_INTEGER* active_date_time; + ASN1_INTEGER* origination_expire_date_time; + ASN1_INTEGER* usage_expire_date_time; + ASN1_NULL* no_auth_required; + ASN1_INTEGER* user_auth_type; + ASN1_INTEGER* auth_timeout; + ASN1_NULL* allow_while_on_body; + ASN1_NULL* all_applications; + ASN1_OCTET_STRING* application_id; + ASN1_INTEGER* creation_date_time; + ASN1_INTEGER* origin; + ASN1_NULL* rollback_resistance; + KM_ROOT_OF_TRUST* root_of_trust; + ASN1_INTEGER* os_version; + ASN1_INTEGER* os_patchlevel; + ASN1_OCTET_STRING* attestation_application_id; + ASN1_NULL* trusted_user_presence_required; + ASN1_NULL* trusted_confirmation_required; + ASN1_NULL* unlocked_device_required; + ASN1_INTEGER* vendor_patchlevel; + ASN1_INTEGER* boot_patchlevel; + ASN1_NULL* early_boot_only; + ASN1_NULL* device_unique_attestation; + ASN1_NULL* storage_key; + ASN1_NULL* identity_credential; +} KM_AUTH_LIST; + +ASN1_SEQUENCE(KM_AUTH_LIST) = { + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()), + ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER, + TAG_RSA_PUBLIC_EXPONENT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL, + TAG_ROLLBACK_RESISTANCE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER, + TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER, + TAG_USAGE_EXPIRE_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, + TAG_ALLOW_WHILE_ON_BODY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL, + TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL, + TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL, + TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, + TAG_CREATION_DATETIME.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER, + TAG_VENDOR_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING, + TAG_ATTESTATION_APPLICATION_ID.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL, + TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, storage_key, ASN1_NULL, TAG_STORAGE_KEY.maskedTag()), + ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL, + TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()), + +} ASN1_SEQUENCE_END(KM_AUTH_LIST); +IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST); + +typedef struct km_key_description { + ASN1_INTEGER* attestation_version; + ASN1_ENUMERATED* attestation_security_level; + ASN1_INTEGER* keymint_version; + ASN1_ENUMERATED* keymint_security_level; + ASN1_OCTET_STRING* attestation_challenge; + KM_AUTH_LIST* software_enforced; + KM_AUTH_LIST* tee_enforced; + ASN1_INTEGER* unique_id; +} KM_KEY_DESCRIPTION; + +ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = { + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymint_version, ASN1_INTEGER), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymint_security_level, ASN1_ENUMERATED), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST), + ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST), +} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION); +IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION); + +template <Tag tag> +void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag, + AuthorizationSet* auth_list) { + typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT; + for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) { + auth_list->push_back( + ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i)))); + } +} + +template <Tag tag> +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag, + AuthorizationSet* auth_list) { + typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT; + if (!asn1_int) return; + auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int))); +} + +template <Tag tag> +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int)); +} + +BIGNUM* construct_uint_max() { + BIGNUM* value = BN_new(); + BIGNUM_Ptr one(BN_new()); + BN_one(one.get()); + BN_lshift(value, one.get(), 32); + return value; +} + +uint64_t BignumToUint64(BIGNUM* num) { + static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)), + "This implementation only supports 32 and 64-bit BN_ULONG"); + if (sizeof(BN_ULONG) == sizeof(uint32_t)) { + BIGNUM_Ptr uint_max(construct_uint_max()); + BIGNUM_Ptr hi(BN_new()), lo(BN_new()); + BN_CTX_Ptr ctx(BN_CTX_new()); + BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get()); + return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get()); + } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) { + return BN_get_word(num); + } else { + return 0; + } +} + +template <Tag tag> +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr)); + auth_list->push_back(ttag, BignumToUint64(num.get())); +} + +template <Tag tag> +void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_int) return; + BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr)); + auth_list->push_back(ttag, BignumToUint64(num.get())); +} + +template <Tag tag> +void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_null) return; + auth_list->push_back(ttag); +} + +template <Tag tag> +void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag, + AuthorizationSet* auth_list) { + if (!asn1_string) return; + vector<uint8_t> buf(asn1_string->data, asn1_string->data + asn1_string->length); + auth_list->push_back(ttag, buf); +} + +// Extract the values from the specified ASN.1 record and place them in auth_list. +static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) { + if (!record) return ErrorCode::OK; + + copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list); + copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list); + copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list); + copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list); + copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list); + copyAuthTag(record->digest, TAG_DIGEST, auth_list); + copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list); + copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list); + copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list); + copyAuthTag(record->origin, TAG_ORIGIN, auth_list); + copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list); + copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list); + copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list); + copyAuthTag(record->padding, TAG_PADDING, auth_list); + copyAuthTag(record->purpose, TAG_PURPOSE, auth_list); + copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list); + copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list); + copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list); + copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list); + copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list); + copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list); + copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list); + copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED, + auth_list); + copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED, + auth_list); + copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list); + copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list); + copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list); + copyAuthTag(record->storage_key, TAG_STORAGE_KEY, auth_list); + copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list); + + return ErrorCode::OK; +} + +MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION) + +// Parse the DER-encoded attestation record, placing the results in keymint_version, +// attestation_challenge, software_enforced, tee_enforced and unique_id. +ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + uint32_t* attestation_version, // + SecurityLevel* attestation_security_level, + uint32_t* keymint_version, SecurityLevel* keymint_security_level, + vector<uint8_t>* attestation_challenge, + AuthorizationSet* software_enforced, + AuthorizationSet* tee_enforced, // + vector<uint8_t>* unique_id) { + const uint8_t* p = asn1_key_desc; + KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len)); + if (!record.get()) return ErrorCode::UNKNOWN_ERROR; + + *attestation_version = ASN1_INTEGER_get(record->attestation_version); + *attestation_security_level = + static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level)); + *keymint_version = ASN1_INTEGER_get(record->keymint_version); + *keymint_security_level = + static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymint_security_level)); + + auto& chall = record->attestation_challenge; + attestation_challenge->resize(chall->length); + memcpy(attestation_challenge->data(), chall->data, chall->length); + auto& uid = record->unique_id; + unique_id->resize(uid->length); + memcpy(unique_id->data(), uid->data, uid->length); + + ErrorCode error = extract_auth_list(record->software_enforced, software_enforced); + if (error != ErrorCode::OK) return error; + + return extract_auth_list(record->tee_enforced, tee_enforced); +} + +ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + vector<uint8_t>* verified_boot_key, + keymint_verified_boot_t* verified_boot_state, bool* device_locked, + vector<uint8_t>* verified_boot_hash) { + if (!verified_boot_key || !verified_boot_state || !device_locked || !verified_boot_hash) { + LOG(ERROR) << AT << "null pointer input(s)"; + return ErrorCode::INVALID_ARGUMENT; + } + const uint8_t* p = asn1_key_desc; + KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len)); + if (!record.get()) { + LOG(ERROR) << AT << "Failed record parsing"; + return ErrorCode::UNKNOWN_ERROR; + } + + KM_ROOT_OF_TRUST* root_of_trust = nullptr; + if (record->tee_enforced && record->tee_enforced->root_of_trust) { + root_of_trust = record->tee_enforced->root_of_trust; + } else if (record->software_enforced && record->software_enforced->root_of_trust) { + root_of_trust = record->software_enforced->root_of_trust; + } else { + LOG(ERROR) << AT << " Failed root of trust parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + if (!root_of_trust->verified_boot_key) { + LOG(ERROR) << AT << " Failed verified boot key parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + + auto& vb_key = root_of_trust->verified_boot_key; + verified_boot_key->resize(vb_key->length); + memcpy(verified_boot_key->data(), vb_key->data, vb_key->length); + + *verified_boot_state = static_cast<keymint_verified_boot_t>( + ASN1_ENUMERATED_get(root_of_trust->verified_boot_state)); + if (!verified_boot_state) { + LOG(ERROR) << AT << " Failed verified boot state parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + + *device_locked = root_of_trust->device_locked; + if (!device_locked) { + LOG(ERROR) << AT << " Failed device locked parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + + auto& vb_hash = root_of_trust->verified_boot_hash; + if (!vb_hash) { + LOG(ERROR) << AT << " Failed verified boot hash parsing"; + return ErrorCode::INVALID_ARGUMENT; + } + verified_boot_hash->resize(vb_hash->length); + memcpy(verified_boot_hash->data(), vb_hash->data, vb_hash->length); + return ErrorCode::OK; // KM_ERROR_OK; +} + +} // namespace keymint +} // namespace hardware +} // namespace android diff --git a/keymint/support/authorization_set.cpp b/keymint/support/authorization_set.cpp new file mode 100644 index 0000000000..9fc4e13727 --- /dev/null +++ b/keymint/support/authorization_set.cpp @@ -0,0 +1,529 @@ +/* + * Copyright 2020 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. + */ + +#include <keymintSupport/authorization_set.h> + +#include <assert.h> + +#include <android-base/logging.h> +#include <sstream> + +#include <android/hardware/keymint/Algorithm.h> +#include <android/hardware/keymint/BlockMode.h> +#include <android/hardware/keymint/Digest.h> +#include <android/hardware/keymint/KeyParameter.h> +#include <android/hardware/keymint/KeyPurpose.h> +#include <android/hardware/keymint/TagType.h> + +namespace android { +namespace hardware { +namespace keymint { + +void AuthorizationSet::Sort() { + std::sort(data_.begin(), data_.end()); +} + +void AuthorizationSet::Deduplicate() { + if (data_.empty()) return; + + Sort(); + std::vector<KeyParameter> result; + + auto curr = data_.begin(); + auto prev = curr++; + for (; curr != data_.end(); ++prev, ++curr) { + if (prev->tag == Tag::INVALID) continue; + + if (*prev != *curr) { + result.push_back(std::move(*prev)); + } + } + result.push_back(std::move(*prev)); + + std::swap(data_, result); +} + +void AuthorizationSet::Union(const AuthorizationSet& other) { + data_.insert(data_.end(), other.data_.begin(), other.data_.end()); + Deduplicate(); +} + +void AuthorizationSet::Subtract(const AuthorizationSet& other) { + Deduplicate(); + + auto i = other.begin(); + while (i != other.end()) { + int pos = -1; + do { + pos = find(i->tag, pos); + if (pos != -1 && (*i == data_[pos])) { + data_.erase(data_.begin() + pos); + break; + } + } while (pos != -1); + ++i; + } +} + +void AuthorizationSet::Filter(std::function<bool(const KeyParameter&)> doKeep) { + std::vector<KeyParameter> result; + for (auto& param : data_) { + if (doKeep(param)) { + result.push_back(std::move(param)); + } + } + std::swap(data_, result); +} + +KeyParameter& AuthorizationSet::operator[](int at) { + return data_[at]; +} + +const KeyParameter& AuthorizationSet::operator[](int at) const { + return data_[at]; +} + +void AuthorizationSet::Clear() { + data_.clear(); +} + +size_t AuthorizationSet::GetTagCount(Tag tag) const { + size_t count = 0; + for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count; + return count; +} + +int AuthorizationSet::find(Tag tag, int begin) const { + auto iter = data_.begin() + (1 + begin); + + while (iter != data_.end() && iter->tag != tag) ++iter; + + if (iter != data_.end()) return iter - data_.begin(); + return -1; +} + +bool AuthorizationSet::erase(int index) { + auto pos = data_.begin() + index; + if (pos != data_.end()) { + data_.erase(pos); + return true; + } + return false; +} + +NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const { + int pos = find(tag); + if (pos == -1) return {}; + return data_[pos]; +} + +/** + * Persistent format is: + * | 32 bit indirect_size | + * -------------------------------- + * | indirect_size bytes of data | this is where the blob data is stored + * -------------------------------- + * | 32 bit element_count | number of entries + * | 32 bit elements_size | total bytes used by entries (entries have variable length) + * -------------------------------- + * | elementes_size bytes of data | where the elements are stored + */ + +/** + * Persistent format of blobs and bignums: + * | 32 bit tag | + * | 32 bit blob_length | + * | 32 bit indirect_offset | + */ + +struct OutStreams { + std::ostream& indirect; + std::ostream& elements; + size_t skipped; +}; + +OutStreams& serializeParamValue(OutStreams& out, const vector<uint8_t>& blob) { + uint32_t buffer; + + // write blob_length + auto blob_length = blob.size(); + if (blob_length > std::numeric_limits<uint32_t>::max()) { + out.elements.setstate(std::ios_base::badbit); + return out; + } + buffer = blob_length; + out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t)); + + // write indirect_offset + auto offset = out.indirect.tellp(); + if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() || + uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check + out.elements.setstate(std::ios_base::badbit); + return out; + } + buffer = offset; + out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t)); + + // write blob to indirect stream + if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length); + + return out; +} + +template <typename T> +OutStreams& serializeParamValue(OutStreams& out, const T& value) { + out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T)); + return out; +} + +OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) { + // skip invalid entries. + ++out.skipped; + return out; +} +template <typename T> +OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) { + out.elements.write(reinterpret_cast<const char*>(¶m.tag), sizeof(int32_t)); + return serializeParamValue(out, accessTagValue(ttag, param)); +} + +template <typename... T> +struct choose_serializer; +template <typename... Tags> +struct choose_serializer<MetaList<Tags...>> { + static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + return choose_serializer<Tags...>::serialize(out, param); + } +}; + +template <> +struct choose_serializer<> { + static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + LOG(WARNING) << "Trying to serialize unknown tag " << unsigned(param.tag) + << ". Did you forget to add it to all_tags_t?"; + ++out.skipped; + return out; + } +}; + +template <TagType tag_type, Tag tag, typename... Tail> +struct choose_serializer<android::hardware::keymint::TypedTag<tag_type, tag>, Tail...> { + static OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + if (param.tag == tag) { + return android::hardware::keymint::serialize(TypedTag<tag_type, tag>(), out, param); + } else { + return choose_serializer<Tail...>::serialize(out, param); + } + } +}; + +OutStreams& serialize(OutStreams& out, const KeyParameter& param) { + return choose_serializer<all_tags_t>::serialize(out, param); +} + +std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) { + std::stringstream indirect; + std::stringstream elements; + OutStreams streams = {indirect, elements, 0}; + for (const auto& param : params) { + serialize(streams, param); + } + if (indirect.bad() || elements.bad()) { + out.setstate(std::ios_base::badbit); + return out; + } + auto pos = indirect.tellp(); + if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) { + out.setstate(std::ios_base::badbit); + return out; + } + uint32_t indirect_size = pos; + pos = elements.tellp(); + if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) { + out.setstate(std::ios_base::badbit); + return out; + } + uint32_t elements_size = pos; + uint32_t element_count = params.size() - streams.skipped; + + out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t)); + + pos = out.tellp(); + if (indirect_size) out << indirect.rdbuf(); + assert(out.tellp() - pos == indirect_size); + + out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t)); + out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t)); + + pos = out.tellp(); + if (elements_size) out << elements.rdbuf(); + assert(out.tellp() - pos == elements_size); + + return out; +} + +struct InStreams { + std::istream& indirect; + std::istream& elements; + size_t invalids; +}; + +InStreams& deserializeParamValue(InStreams& in, vector<uint8_t>* blob) { + uint32_t blob_length = 0; + uint32_t offset = 0; + in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t)); + blob->resize(blob_length); + in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t)); + in.indirect.seekg(offset); + in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size()); + return in; +} + +template <typename T> +InStreams& deserializeParamValue(InStreams& in, T* value) { + in.elements.read(reinterpret_cast<char*>(value), sizeof(T)); + return in; +} + +InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) { + // there should be no invalid KeyParameters but if handle them as zero sized. + ++in.invalids; + return in; +} + +template <typename T> +InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) { + return deserializeParamValue(in, &accessTagValue(ttag, *param)); +} + +template <typename... T> +struct choose_deserializer; +template <typename... Tags> +struct choose_deserializer<MetaList<Tags...>> { + static InStreams& deserialize(InStreams& in, KeyParameter* param) { + return choose_deserializer<Tags...>::deserialize(in, param); + } +}; +template <> +struct choose_deserializer<> { + static InStreams& deserialize(InStreams& in, KeyParameter*) { + // encountered an unknown tag -> fail parsing + in.elements.setstate(std::ios_base::badbit); + return in; + } +}; +template <TagType tag_type, Tag tag, typename... Tail> +struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> { + static InStreams& deserialize(InStreams& in, KeyParameter* param) { + if (param->tag == tag) { + return android::hardware::keymint::deserialize(TypedTag<tag_type, tag>(), in, param); + } else { + return choose_deserializer<Tail...>::deserialize(in, param); + } + } +}; + +InStreams& deserialize(InStreams& in, KeyParameter* param) { + in.elements.read(reinterpret_cast<char*>(¶m->tag), sizeof(Tag)); + return choose_deserializer<all_tags_t>::deserialize(in, param); +} + +std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) { + uint32_t indirect_size = 0; + in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t)); + std::string indirect_buffer(indirect_size, '\0'); + if (indirect_buffer.size() != indirect_size) { + in.setstate(std::ios_base::badbit); + return in; + } + in.read(&indirect_buffer[0], indirect_buffer.size()); + + uint32_t element_count = 0; + in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t)); + uint32_t elements_size = 0; + in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t)); + + std::string elements_buffer(elements_size, '\0'); + if (elements_buffer.size() != elements_size) { + in.setstate(std::ios_base::badbit); + return in; + } + in.read(&elements_buffer[0], elements_buffer.size()); + + if (in.bad()) return in; + + // TODO write one-shot stream buffer to avoid copying here + std::stringstream indirect(indirect_buffer); + std::stringstream elements(elements_buffer); + InStreams streams = {indirect, elements, 0}; + + params->resize(element_count); + + for (uint32_t i = 0; i < element_count; ++i) { + deserialize(streams, &(*params)[i]); + } + + /* + * There are legacy blobs which have invalid tags in them due to a bug during serialization. + * This makes sure that invalid tags are filtered from the result before it is returned. + */ + if (streams.invalids > 0) { + std::vector<KeyParameter> filtered(element_count - streams.invalids); + auto ifiltered = filtered.begin(); + for (auto& p : *params) { + if (p.tag != Tag::INVALID) { + *ifiltered++ = std::move(p); + } + } + *params = std::move(filtered); + } + return in; +} + +void AuthorizationSet::Serialize(std::ostream* out) const { + serialize(*out, data_); +} + +void AuthorizationSet::Deserialize(std::istream* in) { + deserialize(*in, &data_); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size, + uint64_t public_exponent) { + Authorization(TAG_ALGORITHM, Algorithm::RSA); + Authorization(TAG_KEY_SIZE, key_size); + Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent); + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::EC); + Authorization(TAG_KEY_SIZE, key_size); + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(EcCurve curve) { + Authorization(TAG_ALGORITHM, Algorithm::EC); + Authorization(TAG_EC_CURVE, curve); + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::AES); + return Authorization(TAG_KEY_SIZE, key_size); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::TRIPLE_DES); + return Authorization(TAG_KEY_SIZE, key_size); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) { + Authorization(TAG_ALGORITHM, Algorithm::HMAC); + Authorization(TAG_KEY_SIZE, key_size); + return SigningKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size, + uint64_t public_exponent) { + RsaKey(key_size, public_exponent); + return SigningKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, + uint64_t public_exponent) { + RsaKey(key_size, public_exponent); + return EncryptionKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) { + EcdsaKey(key_size); + return SigningKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(EcCurve curve) { + EcdsaKey(curve); + return SigningKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) { + AesKey(key_size); + return EncryptionKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) { + TripleDesKey(key_size); + return EncryptionKey(); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() { + Authorization(TAG_PURPOSE, KeyPurpose::SIGN); + return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() { + Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT); + return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() { + Authorization(TAG_DIGEST, Digest::NONE); + return Authorization(TAG_PADDING, PaddingMode::NONE); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() { + return Authorization(TAG_BLOCK_MODE, BlockMode::ECB); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMinMacLen(uint32_t minMacLength) { + return BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MIN_MAC_LENGTH, minMacLength); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMacLen(uint32_t macLength) { + return BlockMode(BlockMode::GCM) + .Padding(PaddingMode::NONE) + .Authorization(TAG_MAC_LENGTH, macLength); +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::BlockMode( + std::initializer_list<android::hardware::keymint::BlockMode> blockModes) { + for (auto mode : blockModes) { + push_back(TAG_BLOCK_MODE, mode); + } + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::Digest( + std::vector<android::hardware::keymint::Digest> digests) { + for (auto digest : digests) { + push_back(TAG_DIGEST, digest); + } + return *this; +} + +AuthorizationSetBuilder& AuthorizationSetBuilder::Padding( + std::initializer_list<PaddingMode> paddingModes) { + for (auto paddingMode : paddingModes) { + push_back(TAG_PADDING, paddingMode); + } + return *this; +} + +} // namespace keymint +} // namespace hardware +} // namespace android diff --git a/keymint/support/include/keymintSupport/attestation_record.h b/keymint/support/include/keymintSupport/attestation_record.h new file mode 100644 index 0000000000..7a69789423 --- /dev/null +++ b/keymint/support/include/keymintSupport/attestation_record.h @@ -0,0 +1,95 @@ +/* + * Copyright 2020 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. + */ + +#pragma once + +#include <android/hardware/keymint/ErrorCode.h> +#include <android/hardware/keymint/IKeyMintDevice.h> + +#include <keymintSupport/attestation_record.h> +#include <keymintSupport/authorization_set.h> +#include <keymintSupport/openssl_utils.h> + +namespace android { +namespace hardware { +namespace keymint { + +using android::hardware::keymint::KeyParameter; +using android::hardware::keymint::Tag; +using android::hardware::keymint::TAG_ALGORITHM; + +class AuthorizationSet; + +/** + * The OID for Android attestation records. For the curious, it breaks down as follows: + * + * 1 = ISO + * 3 = org + * 6 = DoD (Huh? OIDs are weird.) + * 1 = IANA + * 4 = Private + * 1 = Enterprises + * 11129 = Google + * 2 = Google security + * 1 = certificate extension + * 17 = Android attestation extension. + */ +static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17"; + +enum keymint_verified_boot_t { + KM_VERIFIED_BOOT_VERIFIED = 0, + KM_VERIFIED_BOOT_SELF_SIGNED = 1, + KM_VERIFIED_BOOT_UNVERIFIED = 2, + KM_VERIFIED_BOOT_FAILED = 3, +}; + +struct RootOfTrust { + SecurityLevel security_level; + vector<uint8_t> verified_boot_key; + vector<uint8_t> verified_boot_hash; + keymint_verified_boot_t verified_boot_state; + bool device_locked; +}; + +struct AttestationRecord { + RootOfTrust root_of_trust; + uint32_t attestation_version; + SecurityLevel attestation_security_level; + uint32_t keymint_version; + SecurityLevel keymint_security_level; + std::vector<uint8_t> attestation_challenge; + AuthorizationSet software_enforced; + AuthorizationSet hardware_enforced; + std::vector<uint8_t> unique_id; +}; + +ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + uint32_t* attestation_version, // + SecurityLevel* attestation_security_level, + uint32_t* keymint_version, SecurityLevel* keymint_security_level, + std::vector<uint8_t>* attestation_challenge, + AuthorizationSet* software_enforced, + AuthorizationSet* tee_enforced, // + std::vector<uint8_t>* unique_id); + +ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len, + std::vector<uint8_t>* verified_boot_key, + keymint_verified_boot_t* verified_boot_state, bool* device_locked, + std::vector<uint8_t>* verified_boot_hash); + +} // namespace keymint +} // namespace hardware +} // namespace android diff --git a/keymint/support/include/keymintSupport/authorization_set.h b/keymint/support/include/keymintSupport/authorization_set.h new file mode 100644 index 0000000000..141426a7a2 --- /dev/null +++ b/keymint/support/include/keymintSupport/authorization_set.h @@ -0,0 +1,329 @@ +/* + * Copyright 2020 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. + */ + +#ifndef SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_ +#define SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_ + +#include <vector> + +#include <android/hardware/keymint/BlockMode.h> +#include <android/hardware/keymint/Digest.h> +#include <android/hardware/keymint/EcCurve.h> +#include <android/hardware/keymint/PaddingMode.h> + +#include <keymintSupport/keymint_tags.h> + +namespace android { +namespace hardware { +namespace keymint { + +using android::hardware::keymint::BlockMode; +using android::hardware::keymint::Digest; +using android::hardware::keymint::EcCurve; +using android::hardware::keymint::PaddingMode; + +using std::vector; + +class AuthorizationSetBuilder; + +/** + * An ordered collection of KeyParameters. It provides memory ownership and some convenient + * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters. + * For serialization, wrap the backing store of this structure in a vector<KeyParameter>. + */ +class AuthorizationSet { + public: + typedef KeyParameter value_type; + + /** + * Construct an empty, dynamically-allocated, growable AuthorizationSet. + */ + AuthorizationSet(){}; + + // Copy constructor. + AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {} + + // Move constructor. + AuthorizationSet(AuthorizationSet&& other) noexcept : data_(std::move(other.data_)) {} + + // Constructor from vector<KeyParameter> + AuthorizationSet(const vector<KeyParameter>& other) { *this = other; } + + // Copy assignment. + AuthorizationSet& operator=(const AuthorizationSet& other) { + data_ = other.data_; + return *this; + } + + // Move assignment. + AuthorizationSet& operator=(AuthorizationSet&& other) noexcept { + data_ = std::move(other.data_); + return *this; + } + + AuthorizationSet& operator=(const vector<KeyParameter>& other) { + if (other.size() > 0) { + data_.resize(other.size()); + for (size_t i = 0; i < data_.size(); ++i) { + /* This makes a deep copy even of embedded blobs. + * See assignment operator/copy constructor of vector.*/ + data_[i] = other[i]; + } + } + return *this; + } + + /** + * Clear existing authorization set data + */ + void Clear(); + + ~AuthorizationSet() = default; + + /** + * Returns the size of the set. + */ + size_t size() const { return data_.size(); } + + /** + * Returns true if the set is empty. + */ + bool empty() const { return size() == 0; } + + /** + * Returns the data in the set, directly. Be careful with this. + */ + const KeyParameter* data() const { return data_.data(); } + + /** + * Sorts the set + */ + void Sort(); + + /** + * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the + * AuthorizationSetBuilder). + */ + void Deduplicate(); + + /** + * Adds all elements from \p set that are not already present in this AuthorizationSet. As a + * side-effect, if \p set is not null this AuthorizationSet will end up sorted. + */ + void Union(const AuthorizationSet& set); + + /** + * Removes all elements in \p set from this AuthorizationSet. + */ + void Subtract(const AuthorizationSet& set); + + /** + * Returns the offset of the next entry that matches \p tag, starting from the element after \p + * begin. If not found, returns -1. + */ + int find(Tag tag, int begin = -1) const; + + /** + * Removes the entry at the specified index. Returns true if successful, false if the index was + * out of bounds. + */ + bool erase(int index); + + /** + * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration + */ + std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); } + + /** + * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration + */ + std::vector<KeyParameter>::const_iterator end() const { return data_.end(); } + + /** + * Modifies this Authorization set such that it only keeps the entries for which doKeep + * returns true. + */ + void Filter(std::function<bool(const KeyParameter&)> doKeep); + /** + * Returns the nth element of the set. + * Like for std::vector::operator[] there is no range check performed. Use of out of range + * indices is undefined. + */ + KeyParameter& operator[](int n); + + /** + * Returns the nth element of the set. + * Like for std::vector::operator[] there is no range check performed. Use of out of range + * indices is undefined. + */ + const KeyParameter& operator[](int n) const; + + /** + * Returns true if the set contains at least one instance of \p tag + */ + bool Contains(Tag tag) const { return find(tag) != -1; } + + template <TagType tag_type, Tag tag, typename ValueT> + bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const { + for (const auto& param : data_) { + auto entry = authorizationValue(ttag, param); + if (entry.isOk() && static_cast<ValueT>(entry.value()) == value) return true; + } + return false; + } + /** + * Returns the number of \p tag entries. + */ + size_t GetTagCount(Tag tag) const; + + template <typename T> + inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const { + auto entry = GetEntry(tag); + if (entry.isOk()) return authorizationValue(tag, entry.value()); + return {}; + } + + void push_back(const KeyParameter& param) { data_.push_back(param); } + void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); } + void push_back(const AuthorizationSet& set) { + for (auto& entry : set) { + push_back(entry); + } + } + void push_back(AuthorizationSet&& set) { + std::move(set.begin(), set.end(), std::back_inserter(*this)); + } + + /** + * Append the tag and enumerated value to the set. + * "val" may be exactly one parameter unless a boolean parameter is added. + * In this case "val" is omitted. This condition is checked at compile time by Authorization() + */ + template <typename TypedTagT, typename... Value> + void push_back(TypedTagT tag, Value&&... val) { + push_back(Authorization(tag, std::forward<Value>(val)...)); + } + + template <typename Iterator> + void append(Iterator begin, Iterator end) { + while (begin != end) { + push_back(*begin); + ++begin; + } + } + + vector<KeyParameter> vector_data() const { + vector<KeyParameter> result(begin(), end()); + return result; + } + + void Serialize(std::ostream* out) const; + void Deserialize(std::istream* in); + + private: + NullOr<const KeyParameter&> GetEntry(Tag tag) const; + + std::vector<KeyParameter> data_; +}; + +class AuthorizationSetBuilder : public AuthorizationSet { + public: + template <typename TagType, typename... ValueType> + AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) { + push_back(ttag, std::forward<ValueType>(value)...); + return *this; + } + + template <Tag tag> + AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data, + size_t data_length) { + vector<uint8_t> new_blob(data, data + data_length); + push_back(ttag, new_blob); + return *this; + } + + template <Tag tag> + AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data, + size_t data_length) { + return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length); + } + + template <Tag tag> + AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, char* data, + size_t data_length) { + return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length); + } + + template <Tag tag, size_t size> + AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, + const char (&data)[size]) { + return Authorization(ttag, reinterpret_cast<const uint8_t*>(&data[0]), + size - 1); // drop the terminating '\0' + } + + AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) { + for (const auto& entry : set) { + push_back(entry); + } + return *this; + } + + AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& EcdsaKey(uint32_t key_size); + AuthorizationSetBuilder& EcdsaKey(EcCurve curve); + AuthorizationSetBuilder& AesKey(uint32_t key_size); + AuthorizationSetBuilder& TripleDesKey(uint32_t key_size); + AuthorizationSetBuilder& HmacKey(uint32_t key_size); + + AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent); + AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size); + AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve); + AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size); + AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size); + + AuthorizationSetBuilder& SigningKey(); + AuthorizationSetBuilder& EncryptionKey(); + + AuthorizationSetBuilder& NoDigestOrPadding(); + + AuthorizationSetBuilder& EcbMode(); + AuthorizationSetBuilder& GcmModeMinMacLen(uint32_t minMacLength); + AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength); + + AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes); + AuthorizationSetBuilder& Digest(std::vector<Digest> digests); + AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings); + + template <typename... T> + AuthorizationSetBuilder& BlockMode(T&&... a) { + return BlockMode({std::forward<T>(a)...}); + } + template <typename... T> + AuthorizationSetBuilder& Digest(T&&... a) { + return Digest({std::forward<T>(a)...}); + } + template <typename... T> + AuthorizationSetBuilder& Padding(T&&... a) { + return Padding({std::forward<T>(a)...}); + } +}; + +} // namespace keymint +} // namespace hardware +} // namespace android + +#endif // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_ diff --git a/keymint/support/include/keymintSupport/key_param_output.h b/keymint/support/include/keymintSupport/key_param_output.h new file mode 100644 index 0000000000..a35a9816a9 --- /dev/null +++ b/keymint/support/include/keymintSupport/key_param_output.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_ +#define HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_ + +#include <iostream> +#include <vector> + +#include "keymint_tags.h" + +#include <android/hardware/keymint/Algorithm.h> +#include <android/hardware/keymint/BlockMode.h> +#include <android/hardware/keymint/Digest.h> +#include <android/hardware/keymint/EcCurve.h> +#include <android/hardware/keymint/ErrorCode.h> +#include <android/hardware/keymint/HardwareAuthenticatorType.h> +#include <android/hardware/keymint/KeyCharacteristics.h> +#include <android/hardware/keymint/KeyOrigin.h> +#include <android/hardware/keymint/KeyParameter.h> +#include <android/hardware/keymint/KeyPurpose.h> +#include <android/hardware/keymint/PaddingMode.h> +#include <android/hardware/keymint/SecurityLevel.h> +#include <android/hardware/keymint/Tag.h> +#include <android/hardware/keymint/TagType.h> + +namespace android { +namespace hardware { +namespace keymint { + +using namespace ::android::hardware::keymint; + +inline ::std::ostream& operator<<(::std::ostream& os, Algorithm value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, BlockMode value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, Digest value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, EcCurve value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, ErrorCode value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, PaddingMode value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, SecurityLevel value) { + return os << toString(value); +} + +template <typename ValueT> +::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) { + if (!value.isOk()) { + os << "(value not present)"; + } else { + os << value.value(); + } + return os; +} + +::std::ostream& operator<<(::std::ostream& os, const ::std::vector<KeyParameter>& set); +::std::ostream& operator<<(::std::ostream& os, const KeyParameter& param); + +inline ::std::ostream& operator<<(::std::ostream& os, const KeyCharacteristics& value) { + return os << "SW: " << value.softwareEnforced << ::std::endl + << "HW: " << value.hardwareEnforced << ::std::endl; +} + +inline ::std::ostream& operator<<(::std::ostream& os, KeyPurpose value) { + return os << toString(value); +} + +inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) { + return os << toString(tag); +} + +} // namespace keymint +} // namespace hardware +} // namespace android + +#endif // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_ diff --git a/keymint/support/include/keymintSupport/keymint_tags.h b/keymint/support/include/keymintSupport/keymint_tags.h new file mode 100644 index 0000000000..f1060a9e16 --- /dev/null +++ b/keymint/support/include/keymintSupport/keymint_tags.h @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_ +#define HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_ + +#include <android/hardware/keymint/Algorithm.h> +#include <android/hardware/keymint/BlockMode.h> +#include <android/hardware/keymint/Digest.h> +#include <android/hardware/keymint/EcCurve.h> +#include <android/hardware/keymint/HardwareAuthenticatorType.h> +#include <android/hardware/keymint/KeyOrigin.h> +#include <android/hardware/keymint/KeyParameter.h> +#include <android/hardware/keymint/KeyPurpose.h> +#include <android/hardware/keymint/PaddingMode.h> +#include <android/hardware/keymint/SecurityLevel.h> +#include <android/hardware/keymint/Tag.h> +#include <android/hardware/keymint/TagType.h> + +namespace android::hardware::keymint { + +using android::hardware::keymint::KeyParameter; +using android::hardware::keymint::Tag; +using android::hardware::keymint::TagType; + +// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We +// need these old values to be able to support old keys that use them. +// TODO(seleneh) we should delete this code when we stop supporting keymaster1 +// and deletes it. +static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5; +static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7; + +constexpr TagType typeFromTag(Tag tag) { + return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000)); +} + +/** + * TypedTag is a templatized version of Tag, which provides compile-time checking of + * keymint tag types. Instances are convertible to Tag, so they can be used wherever + * Tag is expected, and because they encode the tag type it's possible to create + * function overloads that only operate on tags with a particular type. + */ +template <TagType tag_type, Tag tag> +struct TypedTag { + inline TypedTag() { + // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type + // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile + // error (no match for template specialization StaticAssert<false>), with no run-time cost. + static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type"); + } + operator Tag() const { return tag; } + int32_t maskedTag() { return static_cast<uint32_t>(tag) & 0x0FFFFFFF; } +}; + +template <Tag tag> +struct Tag2TypedTag { + typedef TypedTag<typeFromTag(tag), tag> type; +}; + +#define DECLARE_TYPED_TAG(name) \ + typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \ + static TAG_##name##_t TAG_##name; + +DECLARE_TYPED_TAG(ACTIVE_DATETIME); +DECLARE_TYPED_TAG(ALGORITHM); +DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY); +DECLARE_TYPED_TAG(APPLICATION_DATA); +DECLARE_TYPED_TAG(APPLICATION_ID); +DECLARE_TYPED_TAG(ASSOCIATED_DATA); +DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID); +DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE); +DECLARE_TYPED_TAG(ATTESTATION_ID_BRAND); +DECLARE_TYPED_TAG(ATTESTATION_ID_DEVICE); +DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT); +DECLARE_TYPED_TAG(ATTESTATION_ID_MANUFACTURER); +DECLARE_TYPED_TAG(ATTESTATION_ID_MODEL); +DECLARE_TYPED_TAG(AUTH_TIMEOUT); +DECLARE_TYPED_TAG(BLOCK_MODE); +DECLARE_TYPED_TAG(BOOTLOADER_ONLY); +DECLARE_TYPED_TAG(BOOT_PATCHLEVEL); +DECLARE_TYPED_TAG(CALLER_NONCE); +DECLARE_TYPED_TAG(CONFIRMATION_TOKEN); +DECLARE_TYPED_TAG(CREATION_DATETIME); +DECLARE_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION); +DECLARE_TYPED_TAG(DIGEST); +DECLARE_TYPED_TAG(EARLY_BOOT_ONLY); +DECLARE_TYPED_TAG(EC_CURVE); +DECLARE_TYPED_TAG(HARDWARE_TYPE); +DECLARE_TYPED_TAG(IDENTITY_CREDENTIAL_KEY); +DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID); +DECLARE_TYPED_TAG(INVALID); +DECLARE_TYPED_TAG(KEY_SIZE); +DECLARE_TYPED_TAG(MAC_LENGTH); +DECLARE_TYPED_TAG(MAX_USES_PER_BOOT); +DECLARE_TYPED_TAG(MIN_MAC_LENGTH); +DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS); +DECLARE_TYPED_TAG(NONCE); +DECLARE_TYPED_TAG(NO_AUTH_REQUIRED); +DECLARE_TYPED_TAG(ORIGIN); +DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME); +DECLARE_TYPED_TAG(OS_PATCHLEVEL); +DECLARE_TYPED_TAG(OS_VERSION); +DECLARE_TYPED_TAG(PADDING); +DECLARE_TYPED_TAG(PURPOSE); +DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION); +DECLARE_TYPED_TAG(ROLLBACK_RESISTANCE); +DECLARE_TYPED_TAG(ROOT_OF_TRUST); +DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT); +DECLARE_TYPED_TAG(STORAGE_KEY); +DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED); +DECLARE_TYPED_TAG(TRUSTED_USER_PRESENCE_REQUIRED); +DECLARE_TYPED_TAG(UNIQUE_ID); +DECLARE_TYPED_TAG(UNLOCKED_DEVICE_REQUIRED); +DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME); +DECLARE_TYPED_TAG(USER_AUTH_TYPE); +DECLARE_TYPED_TAG(USER_ID); +DECLARE_TYPED_TAG(USER_SECURE_ID); +DECLARE_TYPED_TAG(VENDOR_PATCHLEVEL); + +template <typename... Elems> +struct MetaList {}; + +using all_tags_t = MetaList< + TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t, + TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t, + TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, + TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_USER_ID_t, TAG_USER_SECURE_ID_t, + TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t, + TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, + TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_HARDWARE_TYPE_t, + TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t, + TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t, + TAG_ATTESTATION_APPLICATION_ID_t, TAG_ATTESTATION_ID_BRAND_t, TAG_ATTESTATION_ID_DEVICE_t, + TAG_ATTESTATION_ID_PRODUCT_t, TAG_ATTESTATION_ID_MANUFACTURER_t, TAG_ATTESTATION_ID_MODEL_t, + TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, + TAG_DIGEST_t, TAG_PADDING_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t, + TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t, TAG_TRUSTED_CONFIRMATION_REQUIRED_t, + TAG_TRUSTED_USER_PRESENCE_REQUIRED_t>; + +template <typename TypedTagType> +struct TypedTag2ValueType; + +#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \ + template <Tag tag> \ + struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \ + typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \ + }; \ + template <Tag tag> \ + inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \ + ->const decltype(param.field_name)& { \ + return param.field_name; \ + } \ + template <Tag tag> \ + inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) \ + ->decltype(param.field_name)& { \ + return param.field_name; \ + } + +MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, longInteger) +MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, longInteger) +MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, longInteger) +MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, integer) +MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, integer) +MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, boolValue) +MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob) +MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob) + +// TODO(seleneh) change these MAKE_TAG_ENUM_VALUE_ACCESSOR back to the 2 parameter +// version when aidl supports union +#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name, field_type) \ + template <> \ + struct TypedTag2ValueType<decltype(typed_tag)> { \ + typedef field_type type; \ + }; \ + inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \ + ->const field_type& { \ + return *reinterpret_cast<const field_type*>(¶m.field_name); \ + } \ + inline auto accessTagValue(decltype(typed_tag), KeyParameter& param)->field_type& { \ + return *reinterpret_cast<field_type*>(¶m.field_name); \ + } + +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, integer, Algorithm) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, integer, BlockMode) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, integer, Digest) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, integer, EcCurve) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, integer, KeyOrigin) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, integer, PaddingMode) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, integer, KeyPurpose) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, integer, HardwareAuthenticatorType) +MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, integer, SecurityLevel) + +template <TagType tag_type, Tag tag, typename ValueT> +inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) { + KeyParameter param; + param.tag = tag; + param.longInteger = 0; + accessTagValue(ttag, param) = std::forward<ValueT>(value); + return param; +} + +// the boolean case +template <Tag tag> +inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) { + KeyParameter param; + param.tag = tag; + param.boolValue = true; + return param; +} + +template <typename... Pack> +struct FirstOrNoneHelper; +template <typename First> +struct FirstOrNoneHelper<First> { + typedef First type; +}; +template <> +struct FirstOrNoneHelper<> { + struct type {}; +}; + +template <typename... Pack> +using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type; + +template <TagType tag_type, Tag tag, typename... Args> +inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) { + static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0), + "TagType::BOOL Authorizations do not take parameters. Presence is truth."); + static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1), + "Authorization other then TagType::BOOL take exactly one parameter."); + static_assert( + tag_type == TagType::BOOL || + std::is_convertible< + std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>, + typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value, + "Invalid argument type for given tag."); + + return makeKeyParameter(ttag, std::forward<Args>(args)...); +} + +/** + * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out + * of band. Note that if the wrapped value is a reference it is unsafe to access the value if + * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the + * wrapped value. In this case the pointer will be NULL though, and the value will be default + * constructed. + * + * TODO(seleneh) replace this with std::optional. + */ +template <typename ValueT> +class NullOr { + using internal_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, + std::remove_reference_t<ValueT>*, ValueT>; + + struct pointer_initializer { + static std::nullptr_t init() { return nullptr; } + }; + struct value_initializer { + static ValueT init() { return ValueT(); } + }; + struct value_pointer_deref_t { + static ValueT& deref(ValueT& v) { return v; } + }; + struct reference_deref_t { + static auto& deref(internal_t v) { return *v; } + }; + using initializer_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value || + std::is_pointer<ValueT>::value, + pointer_initializer, value_initializer>; + using deref_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, reference_deref_t, + value_pointer_deref_t>; + + public: + NullOr() : value_(initializer_t::init()), null_(true) {} + template <typename T> + NullOr(T&& value, typename std::enable_if< + !std::is_lvalue_reference<ValueT>::value && + std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value, + int>::type = 0) + : value_(std::forward<ValueT>(value)), null_(false) {} + template <typename T> + NullOr(T& value, typename std::enable_if< + std::is_lvalue_reference<ValueT>::value && + std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value, + int>::type = 0) + : value_(&value), null_(false) {} + + bool isOk() const { return !null_; } + + const ValueT& value() const& { return deref_t::deref(value_); } + ValueT& value() & { return deref_t::deref(value_); } + ValueT&& value() && { return std::move(deref_t::deref(value_)); } + + private: + internal_t value_; + bool null_; +}; + +template <typename T> +std::remove_reference_t<T> NullOrOr(T&& v) { + if (v.isOk()) return v; + return {}; +} + +template <typename Head, typename... Tail> +std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) { + if (head.isOk()) return head; + return NullOrOr(std::forward<Tail>(tail)...); +} + +template <typename Default, typename Wrapped> +std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) { + static_assert(std::is_convertible<std::remove_reference_t<Default>, + std::remove_reference_t<Wrapped>>::value, + "Type of default value must match the type wrapped by NullOr"); + if (optional.isOk()) return optional.value(); + return def; +} + +template <TagType tag_type, Tag tag> +inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue( + TypedTag<tag_type, tag> ttag, const KeyParameter& param) { + if (tag != param.tag) return {}; + return accessTagValue(ttag, param); +} + +} // namespace android::hardware::keymint + +namespace std { + +using namespace android::hardware::keymint; + +// Aidl generates KeyParameter operator<, >, ==, != for cpp translation but not ndk +// translations. So we cannot straight forward overload these operators. +// However we need our custom comparison for KeyParameters. So we will +// overload std::less, equal_to instead. +template <> +struct std::less<KeyParameter> { + bool operator()(const KeyParameter& a, const KeyParameter& b) const { + if (a.tag != b.tag) return a.tag < b.tag; + int retval; + switch (typeFromTag(a.tag)) { + case TagType::INVALID: + case TagType::BOOL: + return false; + case TagType::ENUM: + case TagType::ENUM_REP: + case TagType::UINT: + case TagType::UINT_REP: + return a.integer < b.integer; + case TagType::ULONG: + case TagType::ULONG_REP: + case TagType::DATE: + return a.longInteger < b.longInteger; + case TagType::BIGNUM: + case TagType::BYTES: + // Handle the empty cases. + if (a.blob.size() == 0) return b.blob.size() != 0; + if (b.blob.size() == 0) return false; + retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size())); + // if one is the prefix of the other the longer wins + if (retval == 0) return a.blob.size() < b.blob.size(); + // Otherwise a is less if a is less. + else + return retval < 0; + } + return false; + } +}; + +template <> +struct std::equal_to<KeyParameter> { + bool operator()(const KeyParameter& a, const KeyParameter& b) const { + if (a.tag != b.tag) { + return false; + } + switch (typeFromTag(a.tag)) { + case TagType::INVALID: + case TagType::BOOL: + return true; + case TagType::ENUM: + case TagType::ENUM_REP: + case TagType::UINT: + case TagType::UINT_REP: + return a.integer == b.integer; + case TagType::ULONG: + case TagType::ULONG_REP: + case TagType::DATE: + return a.longInteger == b.longInteger; + case TagType::BIGNUM: + case TagType::BYTES: + if (a.blob.size() != b.blob.size()) return false; + return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0; + } + return false; + } +}; + +} // namespace std + +#endif // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_ diff --git a/keymint/support/include/keymintSupport/keymint_utils.h b/keymint/support/include/keymintSupport/keymint_utils.h new file mode 100644 index 0000000000..aa1e93b3c5 --- /dev/null +++ b/keymint/support/include/keymintSupport/keymint_utils.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#ifndef HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_ +#define HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_ + +#include <android/hardware/keymint/HardwareAuthToken.h> + +namespace android { +namespace hardware { +namespace keymint { + +using std::vector; + +inline static std::vector<uint8_t> blob2vector(const uint8_t* data, const size_t length) { + std::vector<uint8_t> result(data, data + length); + return result; +} + +inline static std::vector<uint8_t> blob2vector(const std::string& value) { + vector<uint8_t> result(reinterpret_cast<const uint8_t*>(value.data()), + reinterpret_cast<const uint8_t*>(value.data()) + value.size()); + return result; +} + +HardwareAuthToken vector2AuthToken(const vector<uint8_t>& buffer); +vector<uint8_t> authToken2vector(const HardwareAuthToken& token); + +uint32_t getOsVersion(); +uint32_t getOsPatchlevel(); + +} // namespace keymint +} // namespace hardware +} // namespace android + +#endif // HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_ diff --git a/keymint/support/include/keymintSupport/openssl_utils.h b/keymint/support/include/keymintSupport/openssl_utils.h new file mode 100644 index 0000000000..39633edaaa --- /dev/null +++ b/keymint/support/include/keymintSupport/openssl_utils.h @@ -0,0 +1,63 @@ +/* + * Copyright 2017 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. + */ + +#ifndef HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_ +#define HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_ + +#include <android/hardware/keymint/Digest.h> + +#include <openssl/evp.h> +#include <openssl/x509.h> + +template <typename T, void (*F)(T*)> +struct UniquePtrDeleter { + void operator()(T* p) const { F(p); } +}; + +typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete; + +#define MAKE_OPENSSL_PTR_TYPE(type) \ + typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr; + +MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT) +MAKE_OPENSSL_PTR_TYPE(EVP_PKEY) +MAKE_OPENSSL_PTR_TYPE(RSA) +MAKE_OPENSSL_PTR_TYPE(X509) +MAKE_OPENSSL_PTR_TYPE(BN_CTX) + +typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr; + +inline const EVP_MD* openssl_digest(android::hardware::keymint::Digest digest) { + switch (digest) { + case android::hardware::keymint::Digest::NONE: + return nullptr; + case android::hardware::keymint::Digest::MD5: + return EVP_md5(); + case android::hardware::keymint::Digest::SHA1: + return EVP_sha1(); + case android::hardware::keymint::Digest::SHA_2_224: + return EVP_sha224(); + case android::hardware::keymint::Digest::SHA_2_256: + return EVP_sha256(); + case android::hardware::keymint::Digest::SHA_2_384: + return EVP_sha384(); + case android::hardware::keymint::Digest::SHA_2_512: + return EVP_sha512(); + } + return nullptr; +} + +#endif // HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_ diff --git a/keymint/support/key_param_output.cpp b/keymint/support/key_param_output.cpp new file mode 100644 index 0000000000..6e33558d58 --- /dev/null +++ b/keymint/support/key_param_output.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017 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. + */ + +#include <keymintSupport/key_param_output.h> + +#include <keymintSupport/keymint_tags.h> + +#include <iomanip> + +namespace android { +namespace hardware { +namespace keymint { + +using ::std::endl; +using ::std::ostream; + +ostream& operator<<(ostream& os, const ::std::vector<KeyParameter>& set) { + if (set.size() == 0) { + os << "(Empty)" << endl; + } else { + os << "\n"; + for (const auto& elem : set) os << elem << endl; + } + return os; +} + +// TODO(seleneh) update this to a parsing that looks at each tags individually +// such as ALGORITHM BLOCK_MODE when aidl union support is added. +ostream& operator<<(ostream& os, const KeyParameter& param) { + os << param.tag << ": "; + switch (typeFromTag(param.tag)) { + case TagType::INVALID: + return os << " Invalid"; + case TagType::ENUM_REP: + case TagType::ENUM: + case TagType::UINT_REP: + case TagType::UINT: + return os << param.integer; + case TagType::ULONG_REP: + case TagType::ULONG: + case TagType::DATE: + return os << param.longInteger; + case TagType::BOOL: + return os << "true"; + case TagType::BIGNUM: + os << " Bignum: "; + for (size_t i = 0; i < param.blob.size(); ++i) { + os << std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec; + } + return os; + case TagType::BYTES: + os << " Bytes: "; + for (size_t i = 0; i < param.blob.size(); ++i) { + os << ::std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec; + } + return os; + } + return os << "UNKNOWN TAG TYPE!"; +} + +} // namespace keymint +} // namespace hardware +} // namespace android diff --git a/keymint/support/keymint_utils.cpp b/keymint/support/keymint_utils.cpp new file mode 100644 index 0000000000..fd57cf5af9 --- /dev/null +++ b/keymint/support/keymint_utils.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 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. + */ + +#include <regex.h> + +#include <android-base/properties.h> +#include <hardware/hw_auth_token.h> +#include <keymintSupport/keymint_utils.h> + +#include <arpa/inet.h> + +namespace android::hardware::keymint { + +namespace { + +constexpr char kPlatformVersionProp[] = "ro.build.version.release"; +constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?"; +constexpr size_t kMajorVersionMatch = 1; +constexpr size_t kMinorVersionMatch = 3; +constexpr size_t kSubminorVersionMatch = 5; +constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1; + +constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch"; +constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$"; +constexpr size_t kYearMatch = 1; +constexpr size_t kMonthMatch = 2; +constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1; + +uint32_t match_to_uint32(const char* expression, const regmatch_t& match) { + if (match.rm_so == -1) return 0; + + size_t len = match.rm_eo - match.rm_so; + std::string s(expression + match.rm_so, len); + return std::stoul(s); +} + +std::string wait_and_get_property(const char* prop) { + std::string prop_value; + while (!::android::base::WaitForPropertyCreation(prop)) + ; + prop_value = ::android::base::GetProperty(prop, "" /* default */); + return prop_value; +} + +} // anonymous namespace + +uint32_t getOsVersion(const char* version_str) { + regex_t regex; + if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) { + return 0; + } + + regmatch_t matches[kPlatformVersionMatchCount]; + int not_match = + regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */); + regfree(®ex); + if (not_match) { + return 0; + } + + uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]); + uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]); + uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]); + + return (major * 100 + minor) * 100 + subminor; +} + +uint32_t getOsVersion() { + std::string version = wait_and_get_property(kPlatformVersionProp); + return getOsVersion(version.c_str()); +} + +uint32_t getOsPatchlevel(const char* patchlevel_str) { + regex_t regex; + if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) { + return 0; + } + + regmatch_t matches[kPlatformPatchlevelMatchCount]; + int not_match = + regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */); + regfree(®ex); + if (not_match) { + return 0; + } + + uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]); + uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]); + + if (month < 1 || month > 12) { + return 0; + } + return year * 100 + month; +} + +uint32_t getOsPatchlevel() { + std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp); + return getOsPatchlevel(patchlevel.c_str()); +} + +} // namespace android::hardware::keymint |