Fix clang-tidy performance warnings in keymaster.
am: 68ecd28e87
Change-Id: Id3789808369a9c71c92354d0f31889b8a61ad2d1
diff --git a/Android.mk b/Android.mk
index 233ed95..3e3a25b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,7 +90,7 @@
# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
# Currently, if enabled, these flags will cause an internal error in Clang.
LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
-# Ignore benigh warnings for now.
+# Ignore benign warnings for now.
LOCAL_CLANG_CFLAGS += -Wno-error=unused-private-field
LOCAL_MODULE_TAGS := optional
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
@@ -111,6 +111,7 @@
ecdsa_keymaster1_operation.cpp \
keymaster0_engine.cpp \
keymaster1_engine.cpp \
+ keymaster_configuration.cpp \
rsa_keymaster0_key.cpp \
rsa_keymaster1_key.cpp \
rsa_keymaster1_operation.cpp \
@@ -126,7 +127,7 @@
# TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
# Currently, if enabled, these flags will cause an internal error in Clang.
LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp
-LOCAL_SHARED_LIBRARIES := libkeymaster_messages libkeymaster1 liblog libcrypto
+LOCAL_SHARED_LIBRARIES := libkeymaster_messages libkeymaster1 liblog libcrypto libcutils
LOCAL_MODULE_TAGS := optional
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
diff --git a/Makefile b/Makefile
index fc8a540..656c4e5 100644
--- a/Makefile
+++ b/Makefile
@@ -49,11 +49,11 @@
endif
LDFLAGS += $(ARCH_FLAGS)
-CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP
+CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP $(ARCH_FLAGS) -DKEYMASTER_UNIT_TEST_BUILD -DHOST_BUILD
CXXFLAGS += -Wall -Werror -Wno-unused -Winit-self -Wpointer-arith -Wunused-parameter \
-Werror=sign-compare -Werror=return-type -fno-permissive \
-Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS $(ARCH_FLAGS)
-CFLAGS += $(ARCH_FLAGS)
+CFLAGS += $(ARCH_FLAGS) -DKEYMASTER_UNIT_TEST_BUILD -DHOST_BUILD
# Uncomment to enable debug logging.
# CXXFLAGS += -DDEBUG
@@ -94,13 +94,15 @@
integrity_assured_key_blob.cpp \
iso18033kdf.cpp \
kdf.cpp \
- kdf_test.cpp \
kdf1_test.cpp \
kdf2_test.cpp \
+ kdf_test.cpp \
key.cpp \
key_blob_test.cpp \
keymaster0_engine.cpp \
keymaster1_engine.cpp \
+ keymaster_configuration.cpp \
+ keymaster_configuration_test.cpp \
keymaster_enforcement.cpp \
keymaster_enforcement_test.cpp \
keymaster_tags.cpp \
@@ -137,10 +139,11 @@
ecies_kem_test \
hkdf_test \
hmac_test \
- kdf_test \
kdf1_test \
kdf2_test \
+ kdf_test \
key_blob_test \
+ keymaster_configuration_test \
keymaster_enforcement_test \
nist_curve_key_exchange_test
@@ -191,6 +194,13 @@
GTEST_OBJS = $(GTEST)/src/gtest-all.o gtest_main.o
+keymaster_configuration_test: keymaster_configuration_test.o \
+ authorization_set.o \
+ serializable.o \
+ logger.o \
+ keymaster_configuration.o \
+ $(GTEST_OBJS)
+
hmac_test: hmac_test.o \
android_keymaster_test_utils.o \
android_keymaster_utils.o \
@@ -361,6 +371,7 @@
attestation_record_test: attestation_record_test.o \
android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
attestation_record.o \
authorization_set.o \
keymaster_tags.o \
diff --git a/android_keymaster.cpp b/android_keymaster.cpp
index 3a53394..aeb4f4d 100644
--- a/android_keymaster.cpp
+++ b/android_keymaster.cpp
@@ -38,10 +38,33 @@
namespace keymaster {
+namespace {
+
const uint8_t MAJOR_VER = 1;
const uint8_t MINOR_VER = 1;
const uint8_t SUBMINOR_VER = 0;
+keymaster_error_t CheckVersionInfo(const AuthorizationSet& tee_enforced,
+ const AuthorizationSet& sw_enforced,
+ const KeymasterContext& context) {
+ uint32_t os_version;
+ uint32_t os_patchlevel;
+ context.GetSystemVersion(&os_version, &os_patchlevel);
+
+ uint32_t key_os_patchlevel;
+ if (tee_enforced.GetTagValue(TAG_OS_PATCHLEVEL, &key_os_patchlevel) ||
+ sw_enforced.GetTagValue(TAG_OS_PATCHLEVEL, &key_os_patchlevel)) {
+ if (key_os_patchlevel < os_patchlevel)
+ return KM_ERROR_KEY_REQUIRES_UPGRADE;
+ else if (key_os_patchlevel > os_patchlevel)
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ return KM_ERROR_OK;
+}
+
+} // anonymous namespace
+
AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size)
: context_(context), operation_table_(new OperationTable(operation_table_size)) {}
@@ -193,6 +216,8 @@
&key_material, &response->enforced, &response->unenforced);
if (response->error != KM_ERROR_OK)
return;
+
+ response->error = CheckVersionInfo(response->enforced, response->unenforced, *context_);
}
static KeyFactory* GetKeyFactory(const KeymasterContext& context,
@@ -381,6 +406,18 @@
sw_enforced, &response->certificate_chain);
}
+void AndroidKeymaster::UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response) {
+ if (!response)
+ return;
+
+ KeymasterKeyBlob upgraded_key;
+ response->error = context_->UpgradeKeyBlob(KeymasterKeyBlob(request.key_blob),
+ request.upgrade_params, &upgraded_key);
+ if (response->error != KM_ERROR_OK)
+ return;
+ response->upgraded_key = upgraded_key.release();
+}
+
void AndroidKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) {
if (response == NULL)
return;
@@ -429,6 +466,10 @@
if (error != KM_ERROR_OK)
return error;
+ error = CheckVersionInfo(*hw_enforced, *sw_enforced, *context_);
+ if (error != KM_ERROR_OK)
+ return error;
+
keymaster_algorithm_t algorithm;
*factory = GetKeyFactory(*context_, *hw_enforced, *sw_enforced, &algorithm, &error);
if (error != KM_ERROR_OK)
diff --git a/android_keymaster_messages.cpp b/android_keymaster_messages.cpp
index 1b8f36e..83a1785 100644
--- a/android_keymaster_messages.cpp
+++ b/android_keymaster_messages.cpp
@@ -523,4 +523,42 @@
return true;
}
+UpgradeKeyRequest::~UpgradeKeyRequest() {
+ delete[] key_blob.key_material;
+}
+
+void UpgradeKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
+ set_key_blob(&key_blob, key_material, length);
+}
+
+size_t UpgradeKeyRequest::SerializedSize() const {
+ return key_blob_size(key_blob) + upgrade_params.SerializedSize();
+}
+
+uint8_t* UpgradeKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const {
+ buf = serialize_key_blob(key_blob, buf, end);
+ return upgrade_params.Serialize(buf, end);
+}
+
+bool UpgradeKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ return deserialize_key_blob(&key_blob, buf_ptr, end) &&
+ upgrade_params.Deserialize(buf_ptr, end);
+}
+
+UpgradeKeyResponse::~UpgradeKeyResponse() {
+ delete[] upgraded_key.key_material;
+}
+
+size_t UpgradeKeyResponse::NonErrorSerializedSize() const {
+ return key_blob_size(upgraded_key);
+}
+
+uint8_t* UpgradeKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const {
+ return serialize_key_blob(upgraded_key, buf, end);
+}
+
+bool UpgradeKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ return deserialize_key_blob(&upgraded_key, buf_ptr, end);
+}
+
} // namespace keymaster
diff --git a/android_keymaster_messages_test.cpp b/android_keymaster_messages_test.cpp
index 1ec5894..9207df2 100644
--- a/android_keymaster_messages_test.cpp
+++ b/android_keymaster_messages_test.cpp
@@ -578,6 +578,34 @@
}
}
+TEST(RoundTrip, UpgradeKeyRequest) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ UpgradeKeyRequest msg(ver);
+ msg.SetKeyMaterial("foo", 3);
+ msg.upgrade_params.Reinitialize(params, array_length(params));
+
+ UniquePtr<UpgradeKeyRequest> deserialized(round_trip(ver, msg, 85));
+ EXPECT_EQ(3U, deserialized->key_blob.key_material_size);
+ EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3));
+ EXPECT_EQ(msg.upgrade_params, deserialized->upgrade_params);
+ }
+}
+
+TEST(RoundTrip, UpgradeKeyResponse) {
+ for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) {
+ UpgradeKeyResponse req(ver);
+ req.error = KM_ERROR_OK;
+ req.upgraded_key.key_material = dup_array(TEST_DATA);
+ req.upgraded_key.key_material_size = array_length(TEST_DATA);
+
+ UniquePtr<UpgradeKeyResponse> deserialized(round_trip(ver, req, 19));
+ EXPECT_EQ(KM_ERROR_OK, deserialized->error);
+ EXPECT_EQ(req.upgraded_key.key_material_size, deserialized->upgraded_key.key_material_size);
+ EXPECT_EQ(0, memcmp(req.upgraded_key.key_material, deserialized->upgraded_key.key_material,
+ req.upgraded_key.key_material_size));
+ }
+}
+
uint8_t msgbuf[] = {
220, 88, 183, 255, 71, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 173, 0, 0, 0, 228, 174, 98, 187, 191, 135, 253, 200, 51, 230, 114, 247, 151, 109,
@@ -672,6 +700,8 @@
GARBAGE_TEST(UpdateOperationResponse);
GARBAGE_TEST(AttestKeyRequest);
GARBAGE_TEST(AttestKeyResponse);
+GARBAGE_TEST(UpgradeKeyRequest);
+GARBAGE_TEST(UpgradeKeyResponse);
// The macro doesn't work on this one.
TEST(GarbageTest, SupportedResponse) {
diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp
index ddc9783..ce85316 100644
--- a/android_keymaster_test.cpp
+++ b/android_keymaster_test.cpp
@@ -50,6 +50,9 @@
namespace keymaster {
namespace test {
+const uint32_t kOsVersion = 060000;
+const uint32_t kOsPatchLevel = 201603;
+
StdoutLogger logger;
template <typename T> vector<T> make_vector(const T* array, size_t len) {
@@ -90,18 +93,28 @@
};
/**
- * Test instance creator that builds a pure software keymaster1 implementations.
+ * Test instance creator that builds a pure software keymaster2 implementation.
*/
class SoftKeymasterTestInstanceCreator : public Keymaster2TestInstanceCreator {
public:
keymaster2_device_t* CreateDevice() const override {
std::cerr << "Creating software-only device" << std::endl;
- SoftKeymasterDevice* device = new SoftKeymasterDevice(new TestKeymasterContext);
+ context_ = new TestKeymasterContext;
+ SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
+ AuthorizationSet version_info(AuthorizationSetBuilder()
+ .Authorization(TAG_OS_VERSION, kOsVersion)
+ .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
+ device->keymaster2_device()->configure(device->keymaster2_device(), &version_info);
return device->keymaster2_device();
}
bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
int keymaster0_calls() const override { return 0; }
+ bool is_keymaster1_hw() const override { return false; }
+ KeymasterContext* keymaster_context() const override { return context_; }
+
+ private:
+ mutable TestKeymasterContext* context_;
};
/**
@@ -130,8 +143,13 @@
counting_keymaster0_device_ = new Keymaster0CountingWrapper(keymaster0_device);
- SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(new TestKeymasterContext);
+ context_ = new TestKeymasterContext;
+ SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(context_);
keymaster->SetHardwareDevice(counting_keymaster0_device_);
+ AuthorizationSet version_info(AuthorizationSetBuilder()
+ .Authorization(TAG_OS_VERSION, kOsVersion)
+ .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
+ keymaster->keymaster2_device()->configure(keymaster->keymaster2_device(), &version_info);
return keymaster->keymaster2_device();
}
@@ -146,8 +164,11 @@
}
}
int keymaster0_calls() const override { return counting_keymaster0_device_->count(); }
+ bool is_keymaster1_hw() const override { return false; }
+ KeymasterContext* keymaster_context() const override { return context_; }
private:
+ mutable TestKeymasterContext* context_;
mutable Keymaster0CountingWrapper* counting_keymaster0_device_;
bool support_ec_;
};
@@ -156,7 +177,7 @@
* Test instance creator that builds a SoftKeymasterDevice which wraps a fake hardware keymaster1
* instance, with minimal digest support.
*/
-class Sha256OnlyKeymaster1TestInstanceCreator : public Keymaster2TestInstanceCreator {
+class Sha256OnlyKeymaster2TestInstanceCreator : public Keymaster2TestInstanceCreator {
keymaster2_device_t* CreateDevice() const {
std::cerr << "Creating keymaster1-backed device that supports only SHA256";
@@ -165,22 +186,32 @@
(new SoftKeymasterDevice(new TestKeymasterContext("PseudoHW")))->keymaster_device());
// device doesn't leak; it's cleaned up by device->keymaster_device()->common.close().
- SoftKeymasterDevice* device = new SoftKeymasterDevice(new TestKeymasterContext);
+ context_ = new TestKeymasterContext;
+ SoftKeymasterDevice* device = new SoftKeymasterDevice(context_);
device->SetHardwareDevice(fake_device);
+ AuthorizationSet version_info(AuthorizationSetBuilder()
+ .Authorization(TAG_OS_VERSION, kOsVersion)
+ .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel));
+ device->keymaster2_device()->configure(device->keymaster2_device(), &version_info);
return device->keymaster2_device();
}
bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; }
int keymaster0_calls() const override { return 0; }
int minimal_digest_set() const override { return true; }
+ bool is_keymaster1_hw() const override { return true; }
+ KeymasterContext* keymaster_context() const override { return context_; }
+
+ private:
+ mutable TestKeymasterContext* context_;
};
static auto test_params = testing::Values(
InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator),
InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)),
InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */)),
- InstanceCreatorPtr(new Sha256OnlyKeymaster1TestInstanceCreator));
+ InstanceCreatorPtr(new Sha256OnlyKeymaster2TestInstanceCreator));
class NewKeyGeneration : public Keymaster2Test {
protected:
@@ -206,6 +237,16 @@
// Now check that unspecified, defaulted tags are correct.
EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME));
+ if (GetParam()->is_keymaster1_hw()) {
+ // If the underlying (faked) HW is KM1, it will not have version info.
+ EXPECT_FALSE(auths.Contains(TAG_OS_VERSION));
+ EXPECT_FALSE(auths.Contains(TAG_OS_PATCHLEVEL));
+ } else {
+ // In all othe cases; SoftKeymasterDevice keys, or keymaster0 keys wrapped by
+ // SoftKeymasterDevice, version information will be present and up to date.
+ EXPECT_TRUE(contains(auths, TAG_OS_VERSION, kOsVersion));
+ EXPECT_TRUE(contains(auths, TAG_OS_PATCHLEVEL, kOsPatchLevel));
+ }
}
};
INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, NewKeyGeneration, test_params);
@@ -293,17 +334,17 @@
}
TEST_P(NewKeyGeneration, EcdsaInvalidSize) {
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- ASSERT_EQ(
- KM_ERROR_UNKNOWN_ERROR,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
- else
- ASSERT_EQ(
- KM_ERROR_UNSUPPORTED_KEY_SIZE,
- GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
+ ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_SIZE,
+ GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(KM_DIGEST_NONE)));
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
- if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
- EXPECT_EQ(1, GetParam()->keymaster0_calls());
+TEST_P(NewKeyGeneration, EcdsaMismatchKeySize) {
+ ASSERT_EQ(KM_ERROR_INVALID_ARGUMENT,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(224)
+ .Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256)
+ .Digest(KM_DIGEST_NONE)));
}
TEST_P(NewKeyGeneration, EcdsaAllValidSizes) {
@@ -413,7 +454,7 @@
TEST_P(SigningOperationsTest, RsaPssSha256Success) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
+ .RsaSigningKey(768, 3)
.Digest(KM_DIGEST_SHA_2_256)
.Padding(KM_PAD_RSA_PSS)));
// Use large message, which won't work without digesting.
@@ -1127,7 +1168,7 @@
TEST_P(VerificationOperationsTest, RsaPssSha256Success) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
+ .RsaSigningKey(768, 3)
.Digest(KM_DIGEST_SHA_2_256)
.Padding(KM_PAD_RSA_PSS)));
// Use large message, which won't work without digesting.
@@ -1178,7 +1219,7 @@
TEST_P(VerificationOperationsTest, RsaPssSha256CorruptSignature) {
GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
+ .RsaSigningKey(768, 3)
.Digest(KM_DIGEST_SHA_2_256)
.Padding(KM_PAD_RSA_PSS));
string message(1024, 'a');
@@ -1203,7 +1244,7 @@
TEST_P(VerificationOperationsTest, RsaPssSha256CorruptInput) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(512, 3)
+ .RsaSigningKey(768, 3)
.Digest(KM_DIGEST_SHA_2_256)
.Padding(KM_PAD_RSA_PSS)));
// Use large message, which won't work without digesting.
@@ -1395,7 +1436,7 @@
key_bits = digest_bits + 8 * (11 + 19);
break;
case KM_PAD_RSA_PSS:
- key_bits = digest_bits + 22 * 8;
+ key_bits = digest_bits * 2 + 2 * 8;
break;
default:
FAIL() << "Missing padding";
@@ -3500,8 +3541,11 @@
return attest_rec;
}
-static bool verify_attestation_record(AuthorizationSet expected_sw_enforced,
+static bool verify_attestation_record(const string& challenge,
+ AuthorizationSet expected_sw_enforced,
AuthorizationSet expected_tee_enforced,
+ uint32_t expected_keymaster_version,
+ keymaster_security_level_t expected_keymaster_security_level,
const keymaster_blob_t& attestation_cert) {
X509_Ptr cert(parse_cert_blob(attestation_cert));
@@ -3516,10 +3560,27 @@
AuthorizationSet att_sw_enforced;
AuthorizationSet att_tee_enforced;
- EXPECT_EQ(KM_ERROR_OK, parse_attestation_record(attest_rec->data, attest_rec->length,
- &att_sw_enforced, &att_tee_enforced));
+ uint32_t att_attestation_version;
+ uint32_t att_keymaster_version;
+ keymaster_security_level_t att_attestation_security_level;
+ keymaster_security_level_t att_keymaster_security_level;
+ keymaster_blob_t att_challenge = {};
+ keymaster_blob_t att_unique_id = {};
+ EXPECT_EQ(KM_ERROR_OK, parse_attestation_record(
+ attest_rec->data, attest_rec->length, &att_attestation_version,
+ &att_attestation_security_level, &att_keymaster_version,
+ &att_keymaster_security_level, &att_challenge, &att_sw_enforced,
+ &att_tee_enforced, &att_unique_id));
- // Add TAG_USER_ID to the attestation sw-enforced list, because user IDs are not included in
+ EXPECT_EQ(1U, att_attestation_version);
+ EXPECT_EQ(KM_SECURITY_LEVEL_SOFTWARE, att_attestation_security_level);
+ EXPECT_EQ(expected_keymaster_version, att_keymaster_version);
+ EXPECT_EQ(expected_keymaster_security_level, att_keymaster_security_level);
+
+ EXPECT_EQ(challenge.length(), att_challenge.data_length);
+ EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data, challenge.length()));
+
+ // Add TAG_USER_ID to the relevant attestation list, because user IDs are not included in
// attestations, since they're meaningless off-device.
uint32_t user_id;
if (expected_sw_enforced.GetTagValue(TAG_USER_ID, &user_id))
@@ -3527,6 +3588,13 @@
if (expected_tee_enforced.GetTagValue(TAG_USER_ID, &user_id))
att_tee_enforced.push_back(TAG_USER_ID, user_id);
+ // Add TAG_INCLUDE_UNIQUE_ID to the relevant attestation list, because that tag is not included
+ // in the attestation.
+ if (expected_sw_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID))
+ att_sw_enforced.push_back(TAG_INCLUDE_UNIQUE_ID);
+ if (expected_tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID))
+ att_tee_enforced.push_back(TAG_INCLUDE_UNIQUE_ID);
+
att_sw_enforced.Sort();
expected_sw_enforced.Sort();
EXPECT_EQ(expected_sw_enforced, att_sw_enforced);
@@ -3538,36 +3606,206 @@
return true;
}
-TEST_P(AttestationTest, RsaSignedWithRsa) {
+TEST_P(AttestationTest, RsaAttestation) {
ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
.RsaSigningKey(256, 3)
.Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
+ .Padding(KM_PAD_NONE)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)));
keymaster_cert_chain_t cert_chain;
- EXPECT_EQ(KM_ERROR_OK, AttestKey(KM_ALGORITHM_RSA, &cert_chain));
+ EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &cert_chain));
EXPECT_EQ(3U, cert_chain.entry_count);
EXPECT_TRUE(verify_chain(cert_chain));
- EXPECT_TRUE(verify_attestation_record(sw_enforced(), hw_enforced(), cert_chain.entries[0]));
+
+ uint32_t expected_keymaster_version;
+ keymaster_security_level_t expected_keymaster_security_level;
+ // TODO(swillden): Add a test KM1 that claims to be hardware.
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) {
+ expected_keymaster_version = 0;
+ expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ } else {
+ expected_keymaster_version = 2;
+ expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+ }
+
+ EXPECT_TRUE(verify_attestation_record(
+ "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version,
+ expected_keymaster_security_level, cert_chain.entries[0]));
keymaster_free_cert_chain(&cert_chain);
}
-TEST_P(AttestationTest, RsaSignedWithEc) {
- ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(256, 3)
- .Digest(KM_DIGEST_NONE)
- .Padding(KM_PAD_NONE)));
+TEST_P(AttestationTest, EcAttestation) {
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
+ KM_DIGEST_SHA_2_256)));
+
+ uint32_t expected_keymaster_version;
+ keymaster_security_level_t expected_keymaster_security_level;
+ // TODO(swillden): Add a test KM1 that claims to be hardware.
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) {
+ expected_keymaster_version = 0;
+ expected_keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ } else {
+ expected_keymaster_version = 2;
+ expected_keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+ }
keymaster_cert_chain_t cert_chain;
- EXPECT_EQ(KM_ERROR_OK, AttestKey(KM_ALGORITHM_EC, &cert_chain));
+ EXPECT_EQ(KM_ERROR_OK, AttestKey("challenge", &cert_chain));
EXPECT_EQ(3U, cert_chain.entry_count);
EXPECT_TRUE(verify_chain(cert_chain));
- EXPECT_TRUE(verify_attestation_record(sw_enforced(), hw_enforced(), cert_chain.entries[0]));
+ EXPECT_TRUE(verify_attestation_record(
+ "challenge", sw_enforced(), hw_enforced(), expected_keymaster_version,
+ expected_keymaster_security_level, cert_chain.entries[0]));
keymaster_free_cert_chain(&cert_chain);
}
+typedef Keymaster2Test KeyUpgradeTest;
+INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, KeyUpgradeTest, test_params);
+
+TEST_P(KeyUpgradeTest, AesVersionUpgrade) {
+ GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder()
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB)
+ .Padding(KM_PAD_NONE)));
+
+ // Key should operate fine.
+ string message = "1234567890123456";
+ string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+ EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE));
+
+ // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
+ GetParam()->keymaster_context()->SetSystemVersion(1, 2);
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB);
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ if (GetParam()->is_keymaster1_hw()) {
+ // Keymaster1 hardware can't support version binding. The key will work regardless
+ // of system version. Just abort the remainder of the test.
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ EXPECT_EQ(KM_ERROR_OK, AbortOperation());
+ return;
+ }
+ EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+ // Getting characteristics should also fail
+ EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
+
+ // Upgrade key.
+ EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
+
+ // Key should work again
+ ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE);
+ EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE));
+
+ // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
+ GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
+
+ // Upgrade should fail
+ EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
+
+ EXPECT_EQ(0, GetParam()->keymaster0_calls());
+}
+
+TEST_P(KeyUpgradeTest, RsaVersionUpgrade) {
+ GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+
+ ASSERT_EQ(KM_ERROR_OK,
+ GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(128, 3).Padding(KM_PAD_NONE)));
+
+ // Key should operate fine.
+ string message = "1234567890123456";
+ string ciphertext = EncryptMessage(message, KM_PAD_NONE);
+ EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE));
+
+ // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
+ GetParam()->keymaster_context()->SetSystemVersion(1, 2);
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_PADDING, KM_PAD_NONE);
+ if (GetParam()->is_keymaster1_hw()) {
+ // Keymaster1 hardware can't support version binding. The key will work regardless
+ // of system version. Just abort the remainder of the test.
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ EXPECT_EQ(KM_ERROR_OK, AbortOperation());
+ return;
+ }
+ EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+
+ // Getting characteristics should also fail
+ EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
+
+ // Upgrade key.
+ EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
+
+ // Key should work again
+ ciphertext = EncryptMessage(message, KM_PAD_NONE);
+ EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE));
+
+ // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
+ GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
+
+ // Upgrade should fail
+ EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA))
+ EXPECT_EQ(7, GetParam()->keymaster0_calls());
+}
+
+TEST_P(KeyUpgradeTest, EcVersionUpgrade) {
+ GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+
+ ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest(
+ KM_DIGEST_SHA_2_256)));
+
+ // Key should operate fine.
+ string message = "1234567890123456";
+ string signature;
+ SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
+ VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
+
+ // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE.
+ GetParam()->keymaster_context()->SetSystemVersion(1, 2);
+ AuthorizationSet begin_params(client_params());
+ begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256);
+ if (GetParam()->is_keymaster1_hw()) {
+ // Keymaster1 hardware can't support version binding. The key will work regardless
+ // of system version. Just abort the remainder of the test.
+ EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+ EXPECT_EQ(KM_ERROR_OK, AbortOperation());
+ return;
+ }
+ EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_SIGN, begin_params));
+
+ // Getting characteristics should also fail
+ EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics());
+
+ // Upgrade key.
+ EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params()));
+
+ // Key should work again
+ SignMessage(message, &signature, KM_DIGEST_SHA_2_256);
+ VerifyMessage(message, signature, KM_DIGEST_SHA_2_256);
+
+ // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB.
+ GetParam()->keymaster_context()->SetSystemVersion(1, 1);
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params));
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics());
+
+ // Upgrade should fail
+ EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params()));
+
+ if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC))
+ EXPECT_EQ(7, GetParam()->keymaster0_calls());
+}
+
TEST(SoftKeymasterWrapperTest, CheckKeymaster2Device) {
// Make a good fake device, and wrap it.
SoftKeymasterDevice* good_fake(new SoftKeymasterDevice(new TestKeymasterContext));
diff --git a/android_keymaster_test_utils.cpp b/android_keymaster_test_utils.cpp
index 346421a..ecaee62 100644
--- a/android_keymaster_test_utils.cpp
+++ b/android_keymaster_test_utils.cpp
@@ -328,15 +328,27 @@
return device()->abort(device(), op_handle_);
}
-keymaster_error_t Keymaster2Test::AttestKey(keymaster_algorithm_t algorithm,
+keymaster_error_t Keymaster2Test::AttestKey(const string& attest_challenge,
keymaster_cert_chain_t* cert_chain) {
- AuthorizationSet attest_params(
- AuthorizationSetBuilder().Authorization(TAG_ALGORITHM, algorithm));
+ AuthorizationSet attest_params;
attest_params.push_back(UserAuthParams());
attest_params.push_back(ClientParams());
+ attest_params.push_back(TAG_ATTESTATION_CHALLENGE, attest_challenge.data(),
+ attest_challenge.length());
return device()->attest_key(device(), &blob_, &attest_params, cert_chain);
}
+keymaster_error_t Keymaster2Test::UpgradeKey(const AuthorizationSet& upgrade_params) {
+ keymaster_key_blob_t upgraded_blob;
+ keymaster_error_t error =
+ device()->upgrade_key(device(), &blob_, &upgrade_params, &upgraded_blob);
+ if (error == KM_ERROR_OK) {
+ FreeKeyBlob();
+ blob_ = upgraded_blob;
+ }
+ return error;
+}
+
string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message) {
EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */));
diff --git a/android_keymaster_test_utils.h b/android_keymaster_test_utils.h
index 7a4d35e..25d4cf5 100644
--- a/android_keymaster_test_utils.h
+++ b/android_keymaster_test_utils.h
@@ -35,8 +35,10 @@
#include <hardware/keymaster1.h>
#include <hardware/keymaster2.h>
#include <hardware/keymaster_defs.h>
+
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/authorization_set.h>
+#include <keymaster/keymaster_context.h>
#include <keymaster/logger.h>
std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param);
@@ -162,6 +164,8 @@
virtual bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const = 0;
virtual int keymaster0_calls() const = 0;
virtual int minimal_digest_set() const { return false; }
+ virtual bool is_keymaster1_hw() const = 0;
+ virtual KeymasterContext* keymaster_context() const = 0;
};
// Use a shared_ptr because it's copyable.
@@ -208,7 +212,9 @@
keymaster_error_t AbortOperation();
- keymaster_error_t AttestKey(keymaster_algorithm_t algorithm, keymaster_cert_chain_t* chain);
+ keymaster_error_t AttestKey(const std::string& attest_challenge, keymaster_cert_chain_t* chain);
+
+ keymaster_error_t UpgradeKey(const AuthorizationSet& upgrade_params);
keymaster_error_t GetVersion(uint8_t* major, uint8_t* minor, uint8_t* subminor);
diff --git a/android_keymaster_utils.cpp b/android_keymaster_utils.cpp
index 053e72a..5e92745 100644
--- a/android_keymaster_utils.cpp
+++ b/android_keymaster_utils.cpp
@@ -42,4 +42,54 @@
return result == 0 ? 0 : 1;
}
+keymaster_error_t EcKeySizeToCurve(uint32_t key_size_bits, keymaster_ec_curve_t* curve) {
+ switch (key_size_bits) {
+ default:
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+ case 224:
+ *curve = KM_EC_CURVE_P_224;
+ break;
+
+ case 256:
+ *curve = KM_EC_CURVE_P_256;
+ break;
+
+ case 384:
+ *curve = KM_EC_CURVE_P_384;
+ break;
+
+ case 521:
+ *curve = KM_EC_CURVE_P_521;
+ break;
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t EcCurveToKeySize(keymaster_ec_curve_t curve, uint32_t* key_size_bits) {
+ switch (curve) {
+ default:
+ return KM_ERROR_UNSUPPORTED_EC_CURVE;
+
+ case KM_EC_CURVE_P_224:
+ *key_size_bits = 224;
+ break;
+
+ case KM_EC_CURVE_P_256:
+ *key_size_bits = 256;
+ break;
+
+ case KM_EC_CURVE_P_384:
+ *key_size_bits = 384;
+ break;
+
+ case KM_EC_CURVE_P_521:
+ *key_size_bits = 521;
+ break;
+ }
+
+ return KM_ERROR_OK;
+}
+
} // namespace keymaster
diff --git a/asymmetric_key.cpp b/asymmetric_key.cpp
index 02a7f15..782e87b 100644
--- a/asymmetric_key.cpp
+++ b/asymmetric_key.cpp
@@ -21,6 +21,7 @@
#include <openssl/asn1.h>
#include <openssl/stack.h>
#include <openssl/x509.h>
+#include <openssl/x509v3.h>
#include "attestation_record.h"
#include "openssl_err.h"
@@ -28,6 +29,88 @@
namespace keymaster {
+namespace {
+
+constexpr int kDigitalSignatureKeyUsageBit = 0;
+constexpr int kKeyEnciphermentKeyUsageBit = 2;
+constexpr int kDataEnciphermentKeyUsageBit = 3;
+constexpr int kMaxKeyUsageBit = 8;
+
+template <typename T> T min(T a, T b) {
+ return (a < b) ? a : b;
+}
+
+static keymaster_error_t add_key_usage_extension(const AuthorizationSet& tee_enforced,
+ const AuthorizationSet& sw_enforced,
+ X509* certificate) {
+ // Build BIT_STRING with correct contents.
+ ASN1_BIT_STRING_Ptr key_usage(ASN1_BIT_STRING_new());
+
+ for (size_t i = 0; i <= kMaxKeyUsageBit; ++i) {
+ if (!ASN1_BIT_STRING_set_bit(key_usage.get(), i, 0)) {
+ return TranslateLastOpenSslError();
+ }
+ }
+
+ if (tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN) ||
+ tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_VERIFY) ||
+ sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_SIGN) ||
+ sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_VERIFY)) {
+ if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kDigitalSignatureKeyUsageBit, 1)) {
+ return TranslateLastOpenSslError();
+ }
+ }
+
+ if (tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) ||
+ tee_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_DECRYPT) ||
+ sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_ENCRYPT) ||
+ sw_enforced.Contains(TAG_PURPOSE, KM_PURPOSE_DECRYPT)) {
+ if (!ASN1_BIT_STRING_set_bit(key_usage.get(), kKeyEnciphermentKeyUsageBit, 1) ||
+ !ASN1_BIT_STRING_set_bit(key_usage.get(), kDataEnciphermentKeyUsageBit, 1)) {
+ return TranslateLastOpenSslError();
+ }
+ }
+
+ // Convert to octets
+ int len = i2d_ASN1_BIT_STRING(key_usage.get(), nullptr);
+ if (len < 0) {
+ return TranslateLastOpenSslError();
+ }
+ UniquePtr<uint8_t[]> asn1_key_usage(new uint8_t[len]);
+ if (!asn1_key_usage.get()) {
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+ uint8_t* p = asn1_key_usage.get();
+ len = i2d_ASN1_BIT_STRING(key_usage.get(), &p);
+ if (len < 0) {
+ return TranslateLastOpenSslError();
+ }
+
+ // Build OCTET_STRING
+ ASN1_OCTET_STRING_Ptr key_usage_str(ASN1_OCTET_STRING_new());
+ if (!key_usage_str.get() ||
+ !ASN1_OCTET_STRING_set(key_usage_str.get(), asn1_key_usage.get(), len)) {
+ return TranslateLastOpenSslError();
+ }
+
+ X509_EXTENSION_Ptr key_usage_extension(X509_EXTENSION_create_by_NID(nullptr, //
+ NID_key_usage, //
+ false /* critical */,
+ key_usage_str.get()));
+ if (!key_usage_extension.get()) {
+ return TranslateLastOpenSslError();
+ }
+
+ if (!X509_add_ext(certificate, key_usage_extension.get() /* Don't release; copied */,
+ -1 /* insert at end */)) {
+ return TranslateLastOpenSslError();
+ }
+
+ return KM_ERROR_OK;
+}
+
+} // anonymous namespace
+
keymaster_error_t AsymmetricKey::formatted_key_material(keymaster_key_format_t format,
UniquePtr<uint8_t[]>* material,
size_t* size) const {
@@ -59,8 +142,10 @@
return KM_ERROR_OK;
}
-static keymaster_error_t build_attestation_extension(const AuthorizationSet& tee_enforced,
+static keymaster_error_t build_attestation_extension(const AuthorizationSet& attest_params,
+ const AuthorizationSet& tee_enforced,
const AuthorizationSet& sw_enforced,
+ const KeymasterContext& context,
X509_EXTENSION_Ptr* extension) {
ASN1_OBJECT_Ptr oid(
OBJ_txt2obj(kAttestionRecordOid, 1 /* accept numerical dotted string form only */));
@@ -69,8 +154,8 @@
UniquePtr<uint8_t[]> attest_bytes;
size_t attest_bytes_len;
- keymaster_error_t error =
- build_attestation_record(sw_enforced, tee_enforced, &attest_bytes, &attest_bytes_len);
+ keymaster_error_t error = build_attestation_record(attest_params, sw_enforced, tee_enforced,
+ context, &attest_bytes, &attest_bytes_len);
if (error != KM_ERROR_OK)
return error;
@@ -95,11 +180,14 @@
return true;
}
-static bool add_attestation_extension(const AuthorizationSet& tee_enforced,
- const AuthorizationSet& sw_enforced, X509* certificate,
+static bool add_attestation_extension(const AuthorizationSet& attest_params,
+ const AuthorizationSet& tee_enforced,
+ const AuthorizationSet& sw_enforced,
+ const KeymasterContext& context, X509* certificate,
keymaster_error_t* error) {
X509_EXTENSION_Ptr attest_extension;
- *error = build_attestation_extension(tee_enforced, sw_enforced, &attest_extension);
+ *error = build_attestation_extension(attest_params, tee_enforced, sw_enforced, context,
+ &attest_extension);
if (*error != KM_ERROR_OK)
return false;
@@ -162,7 +250,7 @@
return false;
chain->entries[0].data = nullptr; // Leave empty for the leaf certificate.
- chain->entries[0].data_length = 0;
+ chain->entries[1].data_length = 0;
for (size_t i = 0; i < attest_key_chain->entry_count; ++i) {
chain->entries[i + 1] = attest_key_chain->entries[i];
@@ -179,8 +267,11 @@
keymaster_cert_chain_t* cert_chain) const {
keymaster_algorithm_t sign_algorithm;
- if (!attest_params.GetTagValue(TAG_ALGORITHM, &sign_algorithm) ||
- (sign_algorithm != KM_ALGORITHM_RSA && sign_algorithm != KM_ALGORITHM_EC))
+ if ((!sw_enforced.GetTagValue(TAG_ALGORITHM, &sign_algorithm) &&
+ !tee_enforced.GetTagValue(TAG_ALGORITHM, &sign_algorithm)))
+ return KM_ERROR_UNKNOWN_ERROR;
+
+ if ((sign_algorithm != KM_ALGORITHM_RSA && sign_algorithm != KM_ALGORITHM_EC))
return KM_ERROR_INCOMPATIBLE_ALGORITHM;
EVP_PKEY_Ptr pkey(EVP_PKEY_new());
@@ -195,50 +286,91 @@
return TranslateLastOpenSslError();
ASN1_INTEGER_Ptr serialNumber(ASN1_INTEGER_new());
- if (!serialNumber.get() ||
- !ASN1_INTEGER_set(
- serialNumber.get(),
- 10000 /* TODO(swillden): Figure out what should go in serial number; probably a random
- * value */) ||
+ if (!serialNumber.get() || !ASN1_INTEGER_set(serialNumber.get(), 1) ||
!X509_set_serialNumber(certificate.get(), serialNumber.get() /* Don't release; copied */))
return TranslateLastOpenSslError();
// TODO(swillden): Find useful values (if possible) for issuerName and subjectName.
X509_NAME_Ptr issuerName(X509_NAME_new());
if (!issuerName.get() ||
- !X509_set_subject_name(certificate.get(), issuerName.get() /* Don't release; copied */))
+ !X509_NAME_add_entry_by_txt(issuerName.get(), "CN", MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>("Android Keymaster"),
+ -1 /* len */, -1 /* loc */, 0 /* set */) ||
+ !X509_set_issuer_name(certificate.get(), issuerName.get() /* Don't release; copied */))
return TranslateLastOpenSslError();
X509_NAME_Ptr subjectName(X509_NAME_new());
if (!subjectName.get() ||
+ !X509_NAME_add_entry_by_txt(subjectName.get(), "CN", MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>("A Keymaster Key"),
+ -1 /* len */, -1 /* loc */, 0 /* set */) ||
!X509_set_subject_name(certificate.get(), subjectName.get() /* Don't release; copied */))
return TranslateLastOpenSslError();
- // TODO(swillden): Use key activity and expiration dates for notBefore and notAfter.
ASN1_TIME_Ptr notBefore(ASN1_TIME_new());
- if (!notBefore.get() || !ASN1_TIME_set(notBefore.get(), 0) ||
+ uint64_t activeDateTime = 0;
+ authorizations().GetTagValue(TAG_ACTIVE_DATETIME, &activeDateTime);
+ if (!notBefore.get() || !ASN1_TIME_set(notBefore.get(), activeDateTime / 1000) ||
!X509_set_notBefore(certificate.get(), notBefore.get() /* Don't release; copied */))
return TranslateLastOpenSslError();
ASN1_TIME_Ptr notAfter(ASN1_TIME_new());
- if (!notAfter.get() || !ASN1_TIME_set(notAfter.get(), 10000) ||
+ uint64_t usageExpireDateTime = UINT64_MAX;
+ authorizations().GetTagValue(TAG_USAGE_EXPIRE_DATETIME, &usageExpireDateTime);
+ // TODO(swillden): When trusty can use the C++ standard library change the calculation of
+ // notAfterTime to use std::numeric_limits<time_t>::max(), rather than assuming that time_t is
+ // 32 bits.
+ time_t notAfterTime = min(static_cast<uint64_t>(UINT32_MAX), usageExpireDateTime / 1000);
+ if (!notAfter.get() || !ASN1_TIME_set(notAfter.get(), notAfterTime) ||
!X509_set_notAfter(certificate.get(), notAfter.get() /* Don't release; copied */))
return TranslateLastOpenSslError();
- keymaster_error_t error = KM_ERROR_OK;
+ keymaster_error_t error = add_key_usage_extension(tee_enforced, sw_enforced, certificate.get());
+ if (error != KM_ERROR_OK) {
+ return error;
+ }
+
EVP_PKEY_Ptr sign_key(context.AttestationKey(sign_algorithm, &error));
if (!sign_key.get() || //
!add_public_key(pkey.get(), certificate.get(), &error) ||
- !add_attestation_extension(tee_enforced, sw_enforced, certificate.get(), &error))
+ !add_attestation_extension(attest_params, tee_enforced, sw_enforced, context,
+ certificate.get(), &error))
return error;
- if (!X509_sign(certificate.get(), sign_key.get(), EVP_sha256()))
- return TranslateLastOpenSslError();
-
if (!copy_attestation_chain(context, sign_algorithm, cert_chain, &error))
return error;
+ // Copy subject key identifier from cert_chain->entries[1] as authority key_id.
+ if (cert_chain->entry_count < 2) {
+ // cert_chain must have at least two entries, one for the cert we're trying to create and
+ // one for the cert for the key that signs the new cert.
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+
+ const uint8_t* p = cert_chain->entries[1].data;
+ X509_Ptr signing_cert(d2i_X509(nullptr, &p, cert_chain->entries[1].data_length));
+ if (!signing_cert.get()) {
+ return TranslateLastOpenSslError();
+ }
+
+ UniquePtr<X509V3_CTX> x509v3_ctx(new X509V3_CTX);
+ *x509v3_ctx = {};
+ X509V3_set_ctx(x509v3_ctx.get(), signing_cert.get(), certificate.get(), nullptr /* req */,
+ nullptr /* crl */, 0 /* flags */);
+
+ X509_EXTENSION_Ptr auth_key_id(X509V3_EXT_nconf_nid(nullptr /* conf */, x509v3_ctx.get(),
+ NID_authority_key_identifier,
+ const_cast<char*>("keyid:always")));
+ if (!auth_key_id.get() ||
+ !X509_add_ext(certificate.get(), auth_key_id.get() /* Don't release; copied */,
+ -1 /* insert at end */)) {
+ return TranslateLastOpenSslError();
+ }
+
+ if (!X509_sign(certificate.get(), sign_key.get(), EVP_sha256()))
+ return TranslateLastOpenSslError();
+
return get_certificate_blob(certificate.get(), &cert_chain->entries[0]);
}
diff --git a/attestation_record.cpp b/attestation_record.cpp
index 809f7c8..8aed9ad 100644
--- a/attestation_record.cpp
+++ b/attestation_record.cpp
@@ -23,8 +23,33 @@
#include "openssl_err.h"
#include "openssl_utils.h"
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_context.h>
+
namespace keymaster {
+namespace {
+
+bool Uint64ToBignum(uint64_t value, BIGNUM* bn) {
+ static_assert(sizeof(unsigned long) == sizeof(uint64_t) ||
+ sizeof(unsigned long) == sizeof(uint32_t),
+ "Only 32 and 64-bit platforms supported");
+
+ if (sizeof(unsigned long) == sizeof(uint64_t)) {
+ return BN_set_word(bn, value);
+ } else if (sizeof(unsigned long) == sizeof(uint32_t)) {
+ uint32_t low_order = value & 0xFFFFFFFF;
+ uint32_t high_order = value >> 32;
+ return BN_set_word(bn, high_order) && //
+ BN_lshift(bn, bn, 32) && //
+ BN_add_word(bn, low_order);
+ } else {
+ return false;
+ }
+}
+
+} // anonymous namespace
+
struct stack_st_ASN1_TYPE_Delete {
void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
};
@@ -41,14 +66,14 @@
typedef struct km_root_of_trust {
ASN1_OCTET_STRING* verified_boot_key;
- ASN1_INTEGER* os_version;
- ASN1_INTEGER* os_patchlevel;
+ ASN1_BOOLEAN* device_locked;
+ ASN1_ENUMERATED* verified_boot_state;
} 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, os_version, ASN1_INTEGER),
- ASN1_SIMPLE(KM_ROOT_OF_TRUST, os_patchlevel, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+ ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
@@ -56,92 +81,78 @@
ASN1_INTEGER_SET* purpose;
ASN1_INTEGER* algorithm;
ASN1_INTEGER* key_size;
- ASN1_INTEGER_SET* block_mode;
ASN1_INTEGER_SET* digest;
ASN1_INTEGER_SET* padding;
- ASN1_NULL* caller_nonce;
- ASN1_INTEGER* min_mac_length;
ASN1_INTEGER_SET* kdf;
ASN1_INTEGER* ec_curve;
ASN1_INTEGER* rsa_public_exponent;
- ASN1_NULL* ecies_single_hash_mode;
- ASN1_NULL* include_unique_id;
- ASN1_INTEGER* blob_usage_requirement;
- ASN1_NULL* bootloader_only;
ASN1_INTEGER* active_date_time;
ASN1_INTEGER* origination_expire_date_time;
ASN1_INTEGER* usage_expire_date_time;
- ASN1_INTEGER* min_seconds_between_ops;
- ASN1_INTEGER* max_uses_per_boot;
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_OCTET_STRING* application_data;
ASN1_INTEGER* creation_date_time;
ASN1_INTEGER* origin;
ASN1_NULL* rollback_resistant;
KM_ROOT_OF_TRUST* root_of_trust;
ASN1_INTEGER* os_version;
ASN1_INTEGER* os_patchlevel;
- ASN1_OCTET_STRING* unique_id;
} KM_AUTH_LIST;
ASN1_SEQUENCE(KM_AUTH_LIST) = {
- ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
- ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, block_mode, ASN1_INTEGER, TAG_BLOCK_MODE.masked_tag()),
- ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
- ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, caller_nonce, ASN1_NULL, TAG_CALLER_NONCE.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, min_mac_length, ASN1_INTEGER, TAG_MIN_MAC_LENGTH.masked_tag()),
- ASN1_IMP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.masked_tag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.masked_tag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.masked_tag()),
+ ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, kdf, ASN1_INTEGER, TAG_KDF.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
TAG_RSA_PUBLIC_EXPONENT.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, ecies_single_hash_mode, ASN1_NULL,
- TAG_ECIES_SINGLE_HASH_MODE.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, include_unique_id, ASN1_NULL, TAG_INCLUDE_UNIQUE_ID.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, blob_usage_requirement, ASN1_INTEGER,
- TAG_BLOB_USAGE_REQUIREMENTS.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, bootloader_only, ASN1_NULL, TAG_BOOTLOADER_ONLY.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+ ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
TAG_ORIGINATION_EXPIRE_DATETIME.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+ ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
TAG_USAGE_EXPIRE_DATETIME.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, min_seconds_between_ops, ASN1_INTEGER,
- TAG_MIN_SECONDS_BETWEEN_OPS.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, max_uses_per_boot, ASN1_INTEGER, TAG_MAX_USES_PER_BOOT.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+ ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
TAG_ALLOW_WHILE_ON_BODY.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, application_data, ASN1_OCTET_STRING,
- TAG_APPLICATION_DATA.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+ ASN1_EXP_OPT(KM_AUTH_LIST, all_applications, ASN1_NULL, TAG_ALL_APPLICATIONS.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
TAG_CREATION_DATETIME.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
- ASN1_IMP_OPT(KM_AUTH_LIST, unique_id, ASN1_NULL, TAG_UNIQUE_ID.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANT.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.masked_tag()),
+ ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.masked_tag()),
} 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* keymaster_version;
+ ASN1_ENUMERATED* keymaster_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, keymaster_version, ASN1_INTEGER),
+ ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_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);
@@ -198,9 +209,11 @@
// Put the contents of the keymaster AuthorizationSet auth_list in to the ASN.1 record structure,
// record.
static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_AUTH_LIST* record) {
-
assert(record);
+ if (auth_list.empty())
+ return KM_ERROR_OK;
+
for (auto entry : auth_list) {
ASN1_INTEGER_SET** integer_set = nullptr;
@@ -221,6 +234,19 @@
case KM_TAG_USER_SECURE_ID:
case KM_TAG_EXPORTABLE:
case KM_TAG_RESET_SINCE_ID_ROTATION:
+ case KM_TAG_ATTESTATION_CHALLENGE:
+ case KM_TAG_BLOCK_MODE:
+ case KM_TAG_CALLER_NONCE:
+ case KM_TAG_MIN_MAC_LENGTH:
+ case KM_TAG_ECIES_SINGLE_HASH_MODE:
+ case KM_TAG_INCLUDE_UNIQUE_ID:
+ case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+ case KM_TAG_BOOTLOADER_ONLY:
+ case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+ case KM_TAG_MAX_USES_PER_BOOT:
+ case KM_TAG_APPLICATION_DATA:
+ case KM_TAG_UNIQUE_ID:
+ case KM_TAG_ROOT_OF_TRUST:
continue;
/* Non-repeating enumerations */
@@ -230,9 +256,6 @@
case KM_TAG_EC_CURVE:
integer_ptr = &record->ec_curve;
break;
- case KM_TAG_BLOB_USAGE_REQUIREMENTS:
- integer_ptr = &record->blob_usage_requirement;
- break;
case KM_TAG_USER_AUTH_TYPE:
integer_ptr = &record->user_auth_type;
break;
@@ -244,9 +267,6 @@
case KM_TAG_PURPOSE:
integer_set = &record->purpose;
break;
- case KM_TAG_BLOCK_MODE:
- integer_set = &record->block_mode;
- break;
case KM_TAG_PADDING:
integer_set = &record->padding;
break;
@@ -261,18 +281,15 @@
case KM_TAG_KEY_SIZE:
integer_ptr = &record->key_size;
break;
- case KM_TAG_MIN_MAC_LENGTH:
- integer_ptr = &record->min_mac_length;
- break;
- case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
- integer_ptr = &record->min_seconds_between_ops;
- break;
- case KM_TAG_MAX_USES_PER_BOOT:
- integer_ptr = &record->max_uses_per_boot;
- break;
case KM_TAG_AUTH_TIMEOUT:
integer_ptr = &record->auth_timeout;
break;
+ case KM_TAG_OS_VERSION:
+ integer_ptr = &record->os_version;
+ break;
+ case KM_TAG_OS_PATCHLEVEL:
+ integer_ptr = &record->os_patchlevel;
+ break;
/* Non-repeating long unsigned integers */
case KM_TAG_RSA_PUBLIC_EXPONENT:
@@ -294,15 +311,6 @@
break;
/* Booleans */
- case KM_TAG_CALLER_NONCE:
- bool_ptr = &record->caller_nonce;
- break;
- case KM_TAG_ECIES_SINGLE_HASH_MODE:
- bool_ptr = &record->ecies_single_hash_mode;
- break;
- case KM_TAG_BOOTLOADER_ONLY:
- bool_ptr = &record->bootloader_only;
- break;
case KM_TAG_NO_AUTH_REQUIRED:
bool_ptr = &record->no_auth_required;
break;
@@ -312,9 +320,6 @@
case KM_TAG_ROLLBACK_RESISTANT:
bool_ptr = &record->rollback_resistant;
break;
- case KM_TAG_INCLUDE_UNIQUE_ID:
- bool_ptr = &record->include_unique_id;
- break;
case KM_TAG_ALLOW_WHILE_ON_BODY:
bool_ptr = &record->allow_while_on_body;
break;
@@ -323,35 +328,6 @@
case KM_TAG_APPLICATION_ID:
string_ptr = &record->application_id;
break;
- case KM_TAG_APPLICATION_DATA:
- string_ptr = &record->application_data;
- break;
- case KM_TAG_UNIQUE_ID:
- string_ptr = &record->unique_id;
- break;
-
- /* Root of Trust components */
- case KM_TAG_OS_VERSION:
- case KM_TAG_OS_PATCHLEVEL:
- case KM_TAG_ROOT_OF_TRUST:
- if (!record->root_of_trust)
- record->root_of_trust = KM_ROOT_OF_TRUST_new();
- if (!record->root_of_trust)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- switch (entry.tag) {
- case KM_TAG_OS_VERSION:
- integer_ptr = &record->root_of_trust->os_version;
- break;
- case KM_TAG_OS_PATCHLEVEL:
- integer_ptr = &record->root_of_trust->os_patchlevel;
- break;
- case KM_TAG_ROOT_OF_TRUST:
- string_ptr = &record->root_of_trust->verified_boot_key;
- break;
- default:
- assert(false); // Can't get here.
- }
- break;
}
keymaster_tag_type_t type = keymaster_tag_get_type(entry.tag);
@@ -379,20 +355,22 @@
assert((keymaster_tag_repeatable(entry.tag) && integer_set) ||
(!keymaster_tag_repeatable(entry.tag) && integer_ptr));
- UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new());
- if (!exponent.get())
+ UniquePtr<BIGNUM, BIGNUM_Delete> bn_value(BN_new());
+ if (!bn_value.get())
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
if (type == KM_DATE) {
- if (!BN_set_word(exponent.get(), entry.date_time))
+ if (!Uint64ToBignum(entry.date_time, bn_value.get())) {
return TranslateLastOpenSslError();
+ }
} else {
- if (!BN_set_word(exponent.get(), entry.long_integer))
+ if (!Uint64ToBignum(entry.long_integer, bn_value.get())) {
return TranslateLastOpenSslError();
+ }
}
UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(
- BN_to_ASN1_INTEGER(exponent.get(), nullptr));
+ BN_to_ASN1_INTEGER(bn_value.get(), nullptr));
if (!value.get())
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -424,13 +402,36 @@
}
}
+ keymaster_ec_curve_t ec_curve;
+ uint32_t key_size;
+ if (auth_list.Contains(TAG_ALGORITHM, KM_ALGORITHM_EC) && //
+ !auth_list.Contains(TAG_EC_CURVE) && //
+ auth_list.GetTagValue(TAG_KEY_SIZE, &key_size)) {
+ // This must be a keymaster1 key. It's an EC key with no curve. Insert the curve.
+
+ keymaster_error_t error = EcKeySizeToCurve(key_size, &ec_curve);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> value(ASN1_INTEGER_new());
+ if (!value.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ if (!ASN1_INTEGER_set(value.get(), ec_curve))
+ return TranslateLastOpenSslError();
+
+ insert_integer(value.release(), &record->ec_curve, nullptr);
+ }
+
return KM_ERROR_OK;
}
// Construct an ASN1.1 DER-encoded attestation record containing the values from sw_enforced and
// tee_enforced.
-keymaster_error_t build_attestation_record(const AuthorizationSet& sw_enforced,
+keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
+ const AuthorizationSet& sw_enforced,
const AuthorizationSet& tee_enforced,
+ const KeymasterContext& context,
UniquePtr<uint8_t[]>* asn1_key_desc,
size_t* asn1_key_desc_len) {
assert(asn1_key_desc && asn1_key_desc_len);
@@ -439,15 +440,83 @@
if (!key_desc.get())
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- keymaster_error_t error;
+ keymaster_security_level_t keymaster_security_level;
+ uint32_t keymaster_version = UINT32_MAX;
+ if (tee_enforced.empty()) {
+ // Software key.
+ keymaster_security_level = KM_SECURITY_LEVEL_SOFTWARE;
+ keymaster_version = 2;
+ } else {
+ keymaster_security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
+ switch (context.GetSecurityLevel()) {
+ case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+ // We're running in a TEE, so the key is KM2.
+ keymaster_version = 2;
+ break;
- error = build_auth_list(sw_enforced, key_desc->software_enforced);
+ case KM_SECURITY_LEVEL_SOFTWARE:
+ // We're running in software, wrapping some KM hardware. Is it KM0 or KM1? KM1 keys
+ // have the purpose in the tee_enforced list. It's possible that a key could be created
+ // without a purpose, which would fool this test into reporting it's a KM0 key. That
+ // corner case doesn't matter much, because purpose-less keys are not usable anyway.
+ // Also, KM1 TEEs should disappear rapidly.
+ keymaster_version = tee_enforced.Contains(TAG_PURPOSE) ? 1 : 0;
+ break;
+ }
+
+ if (keymaster_version == UINT32_MAX)
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+
+ if (!ASN1_INTEGER_set(key_desc->attestation_version, 1) ||
+ !ASN1_ENUMERATED_set(key_desc->attestation_security_level, context.GetSecurityLevel()) ||
+ !ASN1_INTEGER_set(key_desc->keymaster_version, keymaster_version) ||
+ !ASN1_ENUMERATED_set(key_desc->keymaster_security_level, keymaster_security_level))
+ return TranslateLastOpenSslError();
+
+ keymaster_blob_t attestation_challenge = {nullptr, 0};
+ if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge))
+ return KM_ERROR_ATTESTATION_CHALLENGE_MISSING;
+ if (!ASN1_OCTET_STRING_set(key_desc->attestation_challenge, attestation_challenge.data,
+ attestation_challenge.data_length))
+ return TranslateLastOpenSslError();
+
+ keymaster_error_t error = build_auth_list(sw_enforced, key_desc->software_enforced);
if (error != KM_ERROR_OK)
return error;
+
error = build_auth_list(tee_enforced, key_desc->tee_enforced);
if (error != KM_ERROR_OK)
return error;
+ // Only check tee_enforced for TAG_INCLUDE_UNIQUE_ID. If we don't have hardware we can't
+ // generate unique IDs.
+ if (tee_enforced.GetTagValue(TAG_INCLUDE_UNIQUE_ID)) {
+ uint64_t creation_datetime;
+ // Only check sw_enforced for TAG_CREATION_DATETIME, since it shouldn't be in tee_enforced,
+ // since this implementation has no secure wall clock.
+ if (!sw_enforced.GetTagValue(TAG_CREATION_DATETIME, &creation_datetime)) {
+ LOG_E("Unique ID cannot be created without creation datetime", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ keymaster_blob_t application_id = {nullptr, 0};
+ sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id);
+
+ Buffer unique_id;
+ error = context.GenerateUniqueId(
+ creation_datetime, application_id,
+ attestation_params.GetTagValue(TAG_RESET_SINCE_ID_ROTATION), &unique_id);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ key_desc->unique_id = ASN1_OCTET_STRING_new();
+ if (!key_desc->unique_id ||
+ !ASN1_OCTET_STRING_set(key_desc->unique_id, unique_id.peek_read(),
+ unique_id.available_read()))
+ return TranslateLastOpenSslError();
+ }
+
int len = i2d_KM_KEY_DESCRIPTION(key_desc.get(), nullptr);
if (len < 0)
return TranslateLastOpenSslError();
@@ -499,6 +568,9 @@
// Extract the values from the specified ASN.1 record and place them in auth_list.
static keymaster_error_t extract_auth_list(const KM_AUTH_LIST* record,
AuthorizationSet* auth_list) {
+ if (!record)
+ return KM_ERROR_OK;
+
// Purpose
if (!get_repeated_enums(record->purpose, TAG_PURPOSE, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -511,10 +583,6 @@
if (record->key_size && !auth_list->push_back(TAG_KEY_SIZE, ASN1_INTEGER_get(record->key_size)))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // Block mode
- if (!get_repeated_enums(record->block_mode, TAG_BLOCK_MODE, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// Digest
if (!get_repeated_enums(record->digest, TAG_DIGEST, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -523,15 +591,6 @@
if (!get_repeated_enums(record->padding, TAG_PADDING, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // Caller NONCE
- if (record->caller_nonce && !auth_list->push_back(TAG_CALLER_NONCE))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Min MAC length
- if (record->min_mac_length &&
- !auth_list->push_back(TAG_MIN_MAC_LENGTH, ASN1_INTEGER_get(record->min_mac_length)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// EC curve
if (!get_enum(record->ec_curve, TAG_EC_CURVE, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -540,18 +599,6 @@
if (!get_ulong(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // ECIES single hash mode
- if (record->ecies_single_hash_mode && !auth_list->push_back(TAG_ECIES_SINGLE_HASH_MODE))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Blob usage requirement
- if (!get_enum(record->blob_usage_requirement, TAG_BLOB_USAGE_REQUIREMENTS, auth_list))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Bootloader only
- if (record->bootloader_only && !auth_list->push_back(TAG_BOOTLOADER_ONLY))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// Active date time
if (!get_ulong(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -565,17 +612,6 @@
if (!get_ulong(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // Min seconds between ops
- if (record->min_seconds_between_ops &&
- !auth_list->push_back(TAG_MIN_SECONDS_BETWEEN_OPS,
- ASN1_INTEGER_get(record->min_seconds_between_ops)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- // Max uses per boot
- if (record->max_uses_per_boot &&
- !auth_list->push_back(TAG_MAX_USES_PER_BOOT, ASN1_INTEGER_get(record->max_uses_per_boot)))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// No auth required
if (record->no_auth_required && !auth_list->push_back(TAG_NO_AUTH_REQUIRED))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -599,12 +635,6 @@
record->application_id->length))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- // Application data
- if (record->application_data &&
- !auth_list->push_back(TAG_APPLICATION_DATA, record->application_data->data,
- record->application_data->length))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
// Creation date time
if (!get_ulong(record->creation_date_time, TAG_CREATION_DATETIME, auth_list))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -620,30 +650,56 @@
// Root of trust
if (record->root_of_trust) {
KM_ROOT_OF_TRUST* rot = record->root_of_trust;
- if (!rot->verified_boot_key || !rot->os_version || !rot->os_patchlevel)
+ if (!rot->verified_boot_key)
return KM_ERROR_INVALID_KEY_BLOB;
- if (!auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(rot->os_version)) ||
- !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(rot->os_patchlevel)) ||
- !auth_list->push_back(TAG_ROOT_OF_TRUST, rot->verified_boot_key->data,
- rot->verified_boot_key->length))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ // Other root of trust fields are not mapped to auth set entries.
}
+ // OS Version
+ if (record->os_version &&
+ !auth_list->push_back(TAG_OS_VERSION, ASN1_INTEGER_get(record->os_version)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // OS Patch level
+ if (record->os_patchlevel &&
+ !auth_list->push_back(TAG_OS_PATCHLEVEL, ASN1_INTEGER_get(record->os_patchlevel)))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
return KM_ERROR_OK;
}
-// Parse the DER-encoded attestation record, placing the results in software_enforced and
-// tee_enforced.
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ uint32_t* attestation_version, //
+ keymaster_security_level_t* attestation_security_level,
+ uint32_t* keymaster_version,
+ keymaster_security_level_t* keymaster_security_level,
+ keymaster_blob_t* attestation_challenge,
AuthorizationSet* software_enforced,
- AuthorizationSet* tee_enforced) {
+ AuthorizationSet* tee_enforced,
+ keymaster_blob_t* unique_id) {
const uint8_t* p = asn1_key_desc;
UniquePtr<KM_KEY_DESCRIPTION, KM_KEY_DESCRIPTION_Delete> record(
d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
if (!record.get())
return TranslateLastOpenSslError();
+ *attestation_version = ASN1_INTEGER_get(record->attestation_version);
+ *attestation_security_level = static_cast<keymaster_security_level_t>(
+ ASN1_ENUMERATED_get(record->attestation_security_level));
+ *keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+ *keymaster_security_level = static_cast<keymaster_security_level_t>(
+ ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+ attestation_challenge->data =
+ dup_buffer(record->attestation_challenge->data, record->attestation_challenge->length);
+ attestation_challenge->data_length = record->attestation_challenge->length;
+
+ unique_id->data = dup_buffer(record->unique_id->data, record->unique_id->length);
+ unique_id->data_length = record->unique_id->length;
+
keymaster_error_t error = extract_auth_list(record->software_enforced, software_enforced);
if (error != KM_ERROR_OK)
return error;
diff --git a/attestation_record.h b/attestation_record.h
index 3cd5dde..64acabc 100644
--- a/attestation_record.h
+++ b/attestation_record.h
@@ -23,6 +23,8 @@
namespace keymaster {
+class KeymasterContext;
+
/**
* The OID for Android attestation records. For the curious, it breaks down as follows:
*
@@ -39,14 +41,22 @@
*/
static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
-keymaster_error_t build_attestation_record(const AuthorizationSet& software_enforced,
+keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_params,
+ const AuthorizationSet& software_enforced,
const AuthorizationSet& tee_enforced,
+ const KeymasterContext& context,
UniquePtr<uint8_t[]>* asn1_key_desc,
size_t* asn1_key_desc_len);
keymaster_error_t parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+ uint32_t* attestation_version, //
+ keymaster_security_level_t* attestation_security_level,
+ uint32_t* keymaster_version,
+ keymaster_security_level_t* keymaster_security_level,
+ keymaster_blob_t* attestation_challenge,
AuthorizationSet* software_enforced,
- AuthorizationSet* tee_enforced);
+ AuthorizationSet* tee_enforced,
+ keymaster_blob_t* unique_id);
}
#endif // SYSTEM_KEYMASTER_ATTESTATION_RECORD_H_
diff --git a/attestation_record_test.cpp b/attestation_record_test.cpp
index 21a7eee..1cf8630 100644
--- a/attestation_record_test.cpp
+++ b/attestation_record_test.cpp
@@ -18,18 +18,88 @@
#include <gtest/gtest.h>
+#include <keymaster/keymaster_context.h>
+
#include "android_keymaster_test_utils.h"
#include "attestation_record.h"
+#include <keymaster/keymaster_context.h>
+
namespace keymaster {
namespace test {
+class TestContext : public KeymasterContext {
+ public:
+ keymaster_security_level_t GetSecurityLevel() const override {
+ return KM_SECURITY_LEVEL_SOFTWARE;
+ }
+ keymaster_error_t SetSystemVersion(uint32_t /* os_version */,
+ uint32_t /* os_patchlevel */) override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const override {
+ *os_version = 0;
+ *os_patchlevel = 0;
+ }
+ KeyFactory* GetKeyFactory(keymaster_algorithm_t /* algorithm */) const override {
+ return nullptr;
+ }
+ OperationFactory* GetOperationFactory(keymaster_algorithm_t /* algorithm */,
+ keymaster_purpose_t /* purpose */) const override {
+ return nullptr;
+ }
+ keymaster_algorithm_t* GetSupportedAlgorithms(size_t* /* algorithms_count */) const override {
+ return nullptr;
+ }
+ keymaster_error_t CreateKeyBlob(const AuthorizationSet& /* key_description */,
+ keymaster_key_origin_t /* origin */,
+ const KeymasterKeyBlob& /* key_material */,
+ KeymasterKeyBlob* /* blob */,
+ AuthorizationSet* /* hw_enforced */,
+ AuthorizationSet* /* sw_enforced */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& /* key_to_upgrade */,
+ const AuthorizationSet& /* upgrade_params */,
+ KeymasterKeyBlob* /* upgraded_key */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& /* blob */,
+ const AuthorizationSet& /* additional_params */,
+ KeymasterKeyBlob* /* key_material */,
+ AuthorizationSet* /* hw_enforced */,
+ AuthorizationSet* /* sw_enforced */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ keymaster_error_t AddRngEntropy(const uint8_t* /* buf */, size_t /* length */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ keymaster_error_t GenerateRandom(uint8_t* /* buf */, size_t /* length */) const override {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ KeymasterEnforcement* enforcement_policy() { return nullptr; }
+ EVP_PKEY* AttestationKey(keymaster_algorithm_t /* algorithm */,
+ keymaster_error_t* /* error */) const override {
+ return nullptr;
+ }
+ keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t /* algorithm */,
+ keymaster_error_t* /* error */) const override {
+ return nullptr;
+ }
+ keymaster_error_t GenerateUniqueId(uint64_t /* creation_date_time */,
+ const keymaster_blob_t& /* application_id */,
+ bool /* reset_since_rotation */, Buffer* unique_id) const {
+ // Finally, the reason for defining this class:
+ unique_id->Reinitialize("foo", 3);
+ return KM_ERROR_OK;
+ }
+};
+
TEST(AttestTest, Simple) {
AuthorizationSet hw_set(AuthorizationSetBuilder()
.RsaSigningKey(512, 3)
.Digest(KM_DIGEST_SHA_2_256)
.Digest(KM_DIGEST_SHA_2_384)
- .Authorization(TAG_ROOT_OF_TRUST, "foo", 3)
.Authorization(TAG_OS_VERSION, 60000)
.Authorization(TAG_OS_PATCHLEVEL, 201512)
.Authorization(TAG_APPLICATION_ID, "bar", 3));
@@ -37,7 +107,10 @@
UniquePtr<uint8_t[]> asn1;
size_t asn1_len;
- EXPECT_EQ(KM_ERROR_OK, build_attestation_record(sw_set, hw_set, &asn1, &asn1_len));
+ AuthorizationSet attest_params(
+ AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE, "hello", 5));
+ EXPECT_EQ(KM_ERROR_OK, build_attestation_record(attest_params, sw_set, hw_set, TestContext(),
+ &asn1, &asn1_len));
EXPECT_GT(asn1_len, 0U);
std::ofstream output("attest.der",
@@ -48,8 +121,17 @@
AuthorizationSet parsed_hw_set;
AuthorizationSet parsed_sw_set;
+ uint32_t attestation_version;
+ uint32_t keymaster_version;
+ keymaster_security_level_t attestation_security_level;
+ keymaster_security_level_t keymaster_security_level;
+ keymaster_blob_t attestation_challenge = {};
+ keymaster_blob_t unique_id = {};
EXPECT_EQ(KM_ERROR_OK,
- parse_attestation_record(asn1.get(), asn1_len, &parsed_sw_set, &parsed_hw_set));
+ parse_attestation_record(asn1.get(), asn1_len, &attestation_version,
+ &attestation_security_level, &keymaster_version,
+ &keymaster_security_level, &attestation_challenge,
+ &parsed_sw_set, &parsed_hw_set, &unique_id));
hw_set.Sort();
sw_set.Sort();
diff --git a/authorization_set.cpp b/authorization_set.cpp
index 09093c9..9f6810d 100644
--- a/authorization_set.cpp
+++ b/authorization_set.cpp
@@ -103,6 +103,23 @@
return true;
}
+void AuthorizationSet::MoveFrom(AuthorizationSet& set) {
+ elems_ = set.elems_;
+ elems_size_ = set.elems_size_;
+ elems_capacity_ = set.elems_capacity_;
+ indirect_data_ = set.indirect_data_;
+ indirect_data_size_ = set.indirect_data_size_;
+ indirect_data_capacity_ = set.indirect_data_capacity_;
+ error_ = set.error_;
+ set.elems_ = nullptr;
+ set.elems_size_ = 0;
+ set.elems_capacity_ = 0;
+ set.indirect_data_ = nullptr;
+ set.indirect_data_size_ = 0;
+ set.indirect_data_capacity_ = 0;
+ set.error_ = OK;
+}
+
bool AuthorizationSet::Reinitialize(const keymaster_key_param_t* elems, const size_t count) {
FreeData();
@@ -196,8 +213,8 @@
return i;
}
-bool AuthorizationSet::erase(size_t index) {
- if (index >= size())
+bool AuthorizationSet::erase(int index) {
+ if (index < 0 || index >= static_cast<int>(size()))
return false;
--elems_size_;
@@ -206,21 +223,21 @@
return true;
}
-keymaster_key_param_t empty_set = {KM_TAG_INVALID, {}};
+keymaster_key_param_t empty_param = {KM_TAG_INVALID, {}};
keymaster_key_param_t& AuthorizationSet::operator[](int at) {
if (is_valid() == OK && at < (int)elems_size_) {
return elems_[at];
}
- empty_set = {KM_TAG_INVALID, {}};
- return empty_set;
+ empty_param = {KM_TAG_INVALID, {}};
+ return empty_param;
}
keymaster_key_param_t AuthorizationSet::operator[](int at) const {
if (is_valid() == OK && at < (int)elems_size_) {
return elems_[at];
}
- empty_set = {KM_TAG_INVALID, {}};
- return empty_set;
+ empty_param = {KM_TAG_INVALID, {}};
+ return empty_param;
}
bool AuthorizationSet::push_back(const keymaster_key_param_set_t& set) {
@@ -613,4 +630,11 @@
return false;
}
+bool AuthorizationSet::ContainsIntValue(keymaster_tag_t tag, uint32_t value) const {
+ for (auto& entry : *this)
+ if (entry.tag == tag && entry.integer == value)
+ return true;
+ return false;
+}
+
} // namespace keymaster
diff --git a/ec_key_factory.cpp b/ec_key_factory.cpp
index 14c8327..36ec433 100644
--- a/ec_key_factory.cpp
+++ b/ec_key_factory.cpp
@@ -40,6 +40,37 @@
}
}
+/* static */
+keymaster_error_t EcKeyFactory::GetCurveAndSize(const AuthorizationSet& key_description,
+ keymaster_ec_curve_t* curve,
+ uint32_t* key_size_bits) {
+ if (!key_description.GetTagValue(TAG_EC_CURVE, curve)) {
+ // Curve not specified. Fall back to deducing curve from key size.
+ if (!key_description.GetTagValue(TAG_KEY_SIZE, key_size_bits)) {
+ LOG_E("%s", "No curve or key size specified for EC key generation");
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ keymaster_error_t error = EcKeySizeToCurve(*key_size_bits, curve);
+ if (error != KM_ERROR_OK) {
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ }
+ } else {
+ keymaster_error_t error = EcCurveToKeySize(*curve, key_size_bits);
+ if (error != KM_ERROR_OK) {
+ return error;
+ }
+ uint32_t tag_key_size_bits;
+ if (key_description.GetTagValue(TAG_KEY_SIZE, &tag_key_size_bits) &&
+ *key_size_bits != tag_key_size_bits) {
+ LOG_E("Curve key size %d and specified key size %d don't match", key_size_bits,
+ tag_key_size_bits);
+ return KM_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ return KM_ERROR_OK;
+}
+
keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
KeymasterKeyBlob* key_blob,
AuthorizationSet* hw_enforced,
@@ -49,10 +80,15 @@
AuthorizationSet authorizations(key_description);
+ keymaster_ec_curve_t ec_curve;
uint32_t key_size;
- if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
- LOG_E("%s", "No key size specified for EC key generation");
- return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ keymaster_error_t error = GetCurveAndSize(authorizations, &ec_curve, &key_size);
+ if (error != KM_ERROR_OK) {
+ return error;
+ } else if (!authorizations.Contains(TAG_KEY_SIZE, key_size)) {
+ authorizations.push_back(TAG_KEY_SIZE, key_size);
+ } else if (!authorizations.Contains(TAG_EC_CURVE, ec_curve)) {
+ authorizations.push_back(TAG_EC_CURVE, ec_curve);
}
UniquePtr<EC_KEY, EC_KEY_Delete> ec_key(EC_KEY_new());
@@ -60,9 +96,9 @@
if (ec_key.get() == NULL || pkey.get() == NULL)
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- UniquePtr<EC_GROUP, EC_GROUP_Delete> group(choose_group(key_size));
+ UniquePtr<EC_GROUP, EC_GROUP_Delete> group(ChooseGroup(ec_curve));
if (group.get() == NULL) {
- LOG_E("Unable to get EC group for key of size %d", key_size);
+ LOG_E("Unable to get EC group for curve %d", ec_curve);
return KM_ERROR_UNSUPPORTED_KEY_SIZE;
}
@@ -80,7 +116,7 @@
return TranslateLastOpenSslError();
KeymasterKeyBlob key_material;
- keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
+ error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
if (error != KM_ERROR_OK)
return error;
@@ -149,7 +185,7 @@
}
/* static */
-EC_GROUP* EcKeyFactory::choose_group(size_t key_size_bits) {
+EC_GROUP* EcKeyFactory::ChooseGroup(size_t key_size_bits) {
switch (key_size_bits) {
case 224:
return EC_GROUP_new_by_curve_name(NID_secp224r1);
@@ -169,6 +205,27 @@
}
}
+/* static */
+EC_GROUP* EcKeyFactory::ChooseGroup(keymaster_ec_curve_t ec_curve) {
+ switch (ec_curve) {
+ case KM_EC_CURVE_P_224:
+ return EC_GROUP_new_by_curve_name(NID_secp224r1);
+ break;
+ case KM_EC_CURVE_P_256:
+ return EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ break;
+ case KM_EC_CURVE_P_384:
+ return EC_GROUP_new_by_curve_name(NID_secp384r1);
+ break;
+ case KM_EC_CURVE_P_521:
+ return EC_GROUP_new_by_curve_name(NID_secp521r1);
+ break;
+ default:
+ return nullptr;
+ break;
+ }
+}
+
keymaster_error_t EcKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
const AuthorizationSet& sw_enforced,
UniquePtr<AsymmetricKey>* key) const {
diff --git a/ec_keymaster0_key.cpp b/ec_keymaster0_key.cpp
index 705ee73..e11c887 100644
--- a/ec_keymaster0_key.cpp
+++ b/ec_keymaster0_key.cpp
@@ -43,10 +43,11 @@
if (!engine_ || !engine_->supports_ec())
return super::GenerateKey(key_description, key_blob, hw_enforced, sw_enforced);
+ keymaster_ec_curve_t ec_curve;
uint32_t key_size;
- if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size)) {
- LOG_E("%s", "No key size specified for EC key generation");
- return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ keymaster_error_t error = GetCurveAndSize(key_description, &ec_curve, &key_size);
+ if (error != KM_ERROR_OK) {
+ return error;
}
KeymasterKeyBlob key_material;
@@ -57,6 +58,7 @@
// context_->CreateKeyBlob doesn't put them in sw_enforced.
hw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
hw_enforced->push_back(TAG_KEY_SIZE, key_size);
+ hw_enforced->push_back(TAG_EC_CURVE, ec_curve);
hw_enforced->push_back(TAG_ORIGIN, KM_ORIGIN_UNKNOWN);
return context_->CreateKeyBlob(key_description, KM_ORIGIN_UNKNOWN, key_material, key_blob,
diff --git a/include/keymaster/android_keymaster.h b/include/keymaster/android_keymaster.h
index c7ecfad..301703b 100644
--- a/include/keymaster/android_keymaster.h
+++ b/include/keymaster/android_keymaster.h
@@ -71,6 +71,7 @@
void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+ void UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response);
void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response);
void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response);
diff --git a/include/keymaster/android_keymaster_messages.h b/include/keymaster/android_keymaster_messages.h
index 30d3fb7..3b8712f 100644
--- a/include/keymaster/android_keymaster_messages.h
+++ b/include/keymaster/android_keymaster_messages.h
@@ -45,6 +45,7 @@
GET_SUPPORTED_EXPORT_FORMATS = 14,
GET_KEY_CHARACTERISTICS = 15,
ATTEST_KEY = 16,
+ UPGRADE_KEY = 17,
};
/**
@@ -129,8 +130,7 @@
};
struct SupportedByAlgorithmRequest : public KeymasterMessage {
- explicit SupportedByAlgorithmRequest(int32_t ver = MAX_MESSAGE_VERSION)
- : KeymasterMessage(ver) {}
+ explicit SupportedByAlgorithmRequest(int32_t ver) : KeymasterMessage(ver) {}
size_t SerializedSize() const override { return sizeof(uint32_t); };
uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
@@ -187,7 +187,7 @@
};
template <typename T> struct SupportedResponse : public KeymasterResponse {
- explicit SupportedResponse(int32_t ver = MAX_MESSAGE_VERSION)
+ explicit SupportedResponse(int32_t ver)
: KeymasterResponse(ver), results(nullptr), results_length(0) {}
~SupportedResponse() { delete[] results; }
@@ -622,6 +622,38 @@
keymaster_cert_chain_t certificate_chain;
};
+struct UpgradeKeyRequest : public KeymasterMessage {
+ explicit UpgradeKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) {
+ key_blob = {nullptr, 0};
+ }
+ ~UpgradeKeyRequest();
+
+ void SetKeyMaterial(const void* key_material, size_t length);
+ void SetKeyMaterial(const keymaster_key_blob_t& blob) {
+ SetKeyMaterial(blob.key_material, blob.key_material_size);
+ }
+
+ size_t SerializedSize() const override;
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override;
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+ keymaster_key_blob_t key_blob;
+ AuthorizationSet upgrade_params;
+};
+
+struct UpgradeKeyResponse : public KeymasterResponse {
+ explicit UpgradeKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) {
+ upgraded_key = {nullptr, 0};
+ }
+ ~UpgradeKeyResponse();
+
+ size_t NonErrorSerializedSize() const override;
+ uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override;
+ bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override;
+
+ keymaster_key_blob_t upgraded_key;
+};
+
} // namespace keymaster
#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_
diff --git a/include/keymaster/android_keymaster_utils.h b/include/keymaster/android_keymaster_utils.h
index c190e04..a1cbf51 100644
--- a/include/keymaster/android_keymaster_utils.h
+++ b/include/keymaster/android_keymaster_utils.h
@@ -36,7 +36,7 @@
// The exact meaning of a time_t value is implementation-dependent. If this code is ported to a
// platform that doesn't define it as "seconds since Jan 1, 1970 UTC", this function will have
// to be revised.
- return time * 1000;
+ return static_cast<int64_t>(time) * 1000;
}
/*
@@ -325,6 +325,9 @@
}
};
+keymaster_error_t EcKeySizeToCurve(uint32_t key_size_bits, keymaster_ec_curve_t* curve);
+keymaster_error_t EcCurveToKeySize(keymaster_ec_curve_t curve, uint32_t* key_size_bits);
+
} // namespace keymaster
#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
diff --git a/include/keymaster/authorization_set.h b/include/keymaster/authorization_set.h
index 74daa8d..ec68de0 100644
--- a/include/keymaster/authorization_set.h
+++ b/include/keymaster/authorization_set.h
@@ -79,6 +79,26 @@
AuthorizationSet(const AuthorizationSet& set) : Serializable(), indirect_data_(nullptr) {
elems_ = nullptr;
Reinitialize(set.elems_, set.elems_size_);
+ error_ = set.error_;
+ }
+
+ // Move constructor.
+ AuthorizationSet(AuthorizationSet&& set) : Serializable() {
+ MoveFrom(set);
+ }
+
+ // Copy assignment.
+ AuthorizationSet& operator=(const AuthorizationSet& set) {
+ Reinitialize(set.elems_, set.elems_size_);
+ error_ = set.error_;
+ return *this;
+ }
+
+ // Move assignment.
+ AuthorizationSet& operator=(AuthorizationSet&& set) {
+ FreeData();
+ MoveFrom(set);
+ return *this;
}
/**
@@ -160,7 +180,7 @@
* Removes the entry at the specified index. Returns true if successful, false if the index was
* out of bounds.
*/
- bool erase(size_t index);
+ bool erase(int index);
/**
* Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
@@ -183,6 +203,13 @@
keymaster_key_param_t operator[](int n) const;
/**
+ * Returns true if the set contains at least one instance of \p tag
+ */
+ bool Contains(keymaster_tag_t tag) const {
+ return find(tag) != -1;
+ }
+
+ /**
* Returns the number of \p tag entries.
*/
size_t GetTagCount(keymaster_tag_t tag) const;
@@ -204,6 +231,14 @@
}
/**
+ * Returns true if the set contains the specified tag and value.
+ */
+ template <keymaster_tag_t Tag>
+ bool Contains(TypedTag<KM_UINT, Tag> tag, uint32_t val) const {
+ return ContainsIntValue(tag, val);
+ }
+
+ /**
* If the specified integer-typed \p tag exists, places its value in \p val and returns true.
* If \p tag is not present, leaves \p val unmodified and returns false.
*/
@@ -392,10 +427,9 @@
size_t SerializedSizeOfElements() const;
private:
- // Disallow assignment
- void operator=(const AuthorizationSet&);
-
void FreeData();
+ void MoveFrom(AuthorizationSet& set);
+
void set_invalid(Error err);
static size_t ComputeIndirectDataSize(const keymaster_key_param_t* elems, size_t count);
@@ -416,8 +450,9 @@
bool GetTagValueBool(keymaster_tag_t tag) const;
bool ContainsEnumValue(keymaster_tag_t tag, uint32_t val) const;
+ bool ContainsIntValue(keymaster_tag_t tag, uint32_t val) const;
- // Define elems_ and elems_size_ as aliases to params and length, respectivley. This is to
+ // Define elems_ and elems_size_ as aliases to params and length, respectively. This is to
// avoid using the variables without the trailing underscore in the implementation.
keymaster_key_param_t*& elems_ = keymaster_key_param_set_t::params;
size_t& elems_size_ = keymaster_key_param_set_t::length;
diff --git a/include/keymaster/ec_key_factory.h b/include/keymaster/ec_key_factory.h
index aaeb548..2bb9c8b 100644
--- a/include/keymaster/ec_key_factory.h
+++ b/include/keymaster/ec_key_factory.h
@@ -52,7 +52,12 @@
OperationFactory* GetOperationFactory(keymaster_purpose_t purpose) const override;
- static EC_GROUP* choose_group(size_t key_size_bits);
+ protected:
+ static EC_GROUP* ChooseGroup(size_t key_size_bits);
+ static EC_GROUP* ChooseGroup(keymaster_ec_curve_t ec_curve);
+
+ static keymaster_error_t GetCurveAndSize(const AuthorizationSet& key_description,
+ keymaster_ec_curve_t* curve, uint32_t* key_size_bits);
};
} // namespace keymaster
diff --git a/include/keymaster/keymaster_configuration.h b/include/keymaster/keymaster_configuration.h
new file mode 100644
index 0000000..97b7fa5
--- /dev/null
+++ b/include/keymaster/keymaster_configuration.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 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_KEYMASTER_KEYMASTER_CONFIGURATION_H_
+#define SYSTEM_KEYMASTER_KEYMASTER_CONFIGURATION_H_
+
+#include <string>
+
+#include <stdint.h>
+
+#include <hardware/keymaster2.h>
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+/**
+ * Retrieves OS version information from system build properties and configures the provided
+ * keymaster device.
+ */
+keymaster_error_t ConfigureDevice(keymaster2_device_t* dev);
+
+/**
+ * Parses OS version string, returning in integer form. For example, "6.1.2" will be returned as
+ * 60102. Ignores any non-numeric suffix, and allows short build numbers, e.g. "6" -> 60000 and
+ * "6.1" -> 60100. Returns 0 if the string doesn't contain a numeric version number.
+ */
+uint32_t GetOsVersion(const char* version_string);
+
+/**
+ * Parses OS patch level string, returning year and month in integer form. For example, "2016-03-25"
+ * will be returned as 201603. Returns 0 if the string doesn't contain a date in the form
+ * YYYY-MM-DD.
+ */
+uint32_t GetOsPatchlevel(const char* patchlevel_string);
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEYMASTER_CONFIGURATION_H_
diff --git a/include/keymaster/keymaster_context.h b/include/keymaster/keymaster_context.h
index c9802e4..104e874 100644
--- a/include/keymaster/keymaster_context.h
+++ b/include/keymaster/keymaster_context.h
@@ -65,6 +65,28 @@
KeymasterContext() {}
virtual ~KeymasterContext(){};
+ /**
+ * Returns the security level (SW or TEE) of this keymaster implementation.
+ */
+ virtual keymaster_security_level_t GetSecurityLevel() const = 0;
+
+ /**
+ * Sets the system version as reported by the system *itself*. This is used to verify that the
+ * system believes itself to be running the same version that is reported by the bootloader, in
+ * hardware implementations. For SoftKeymasterDevice, this sets the version information used.
+ *
+ * If the specified values don't match the bootloader-provided values, this method must return
+ * KM_ERROR_INVALID_ARGUMENT;
+ */
+ virtual keymaster_error_t SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel) = 0;
+
+ /**
+ * Returns the system version. For hardware-based implementations this will be the value
+ * reported by the bootloader. For SoftKeymasterDevice it will be the verion information set by
+ * SetSystemVersion above.
+ */
+ virtual void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const = 0;
+
virtual KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const = 0;
virtual OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
keymaster_purpose_t purpose) const = 0;
@@ -85,6 +107,14 @@
AuthorizationSet* sw_enforced) const = 0;
/**
+ * UpgradeKeyBlob takes an existing blob, parses out key material and constructs a new blob with
+ * the current format and OS version info.
+ */
+ virtual keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+ const AuthorizationSet& upgrade_params,
+ KeymasterKeyBlob* upgraded_key) const = 0;
+
+ /**
* ParseKeyBlob takes a blob and extracts authorization sets and key material, returning an
* error if the blob fails integrity checking or decryption. Note that the returned key
* material may itself be an opaque blob usable only by secure hardware (in the hybrid case).
@@ -131,18 +161,27 @@
/**
* Return the attestation signing key of the specified algorithm (KM_ALGORITHM_RSA or
- * KM_ALGORITHM_EC).
+ * KM_ALGORITHM_EC). Caller does not acquire ownership and should not delete.
*/
virtual EVP_PKEY* AttestationKey(keymaster_algorithm_t algorithm,
keymaster_error_t* error) const = 0;
/**
* Return the certificate chain of the attestation signing key of the specified algorithm
- * (KM_ALGORITHM_RSA or KM_ALGORITHM_EC).
+ * (KM_ALGORITHM_RSA or KM_ALGORITHM_EC). Caller does not acquire ownership and should not
+ * delete.
*/
virtual keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t algorithm,
keymaster_error_t* error) const = 0;
+ /**
+ * Generate the current unique ID.
+ */
+ virtual keymaster_error_t GenerateUniqueId(uint64_t creation_date_time,
+ const keymaster_blob_t& application_id,
+ bool reset_since_rotation,
+ Buffer* unique_id) const = 0;
+
private:
// Uncopyable.
KeymasterContext(const KeymasterContext&);
diff --git a/include/keymaster/keymaster_tags.h b/include/keymaster/keymaster_tags.h
index dcaf0da..2c7ac03 100644
--- a/include/keymaster/keymaster_tags.h
+++ b/include/keymaster/keymaster_tags.h
@@ -164,6 +164,8 @@
DECLARE_KEYMASTER_TAG(KM_UINT, TAG_OS_VERSION);
DECLARE_KEYMASTER_TAG(KM_UINT, TAG_OS_PATCHLEVEL);
DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_UNIQUE_ID);
+DECLARE_KEYMASTER_TAG(KM_BYTES, TAG_ATTESTATION_CHALLENGE);
+DECLARE_KEYMASTER_TAG(KM_BOOL, TAG_RESET_SINCE_ID_ROTATION);
// DECLARE_KEYMASTER_ENUM_TAG is used to declare TypedEnumTag instances for each enum keymaster tag.
#define DECLARE_KEYMASTER_ENUM_TAG(type, name, enumtype) \
diff --git a/include/keymaster/serializable.h b/include/keymaster/serializable.h
index 8748c55..58bfcca 100644
--- a/include/keymaster/serializable.h
+++ b/include/keymaster/serializable.h
@@ -62,6 +62,14 @@
*/
/**
+ * Convert a pointer into a value. This is used to make sure compiler won't optimize away pointer
+ * overflow checks. (See http://www.kb.cert.org/vuls/id/162289)
+ */
+template <typename T> inline uintptr_t __pval(const T *p) {
+ return reinterpret_cast<uintptr_t>(p);
+}
+
+/**
* Append a byte array to a buffer. Note that by itself this function isn't very useful, because it
* provides no indication in the serialized buffer of what the array size is. For writing arrays,
* see \p append_size_and_data_to_buf().
@@ -111,7 +119,8 @@
inline uint8_t* append_uint32_array_to_buf(uint8_t* buf, const uint8_t* end, const T* data,
size_t count) {
// Check for overflow
- if (count >= (UINT32_MAX / sizeof(uint32_t)) || buf + count * sizeof(uint32_t) < buf)
+ if (count >= (UINT32_MAX / sizeof(uint32_t)) ||
+ __pval(buf) + count * sizeof(uint32_t) < __pval(buf))
return buf;
buf = append_uint32_to_buf(buf, end, count);
for (size_t i = 0; i < count; ++i)
@@ -172,8 +181,9 @@
if (!copy_uint32_from_buf(buf_ptr, end, count))
return false;
- const uint8_t* array_end = *buf_ptr + *count * sizeof(uint32_t);
- if (*count >= UINT32_MAX / sizeof(uint32_t) || array_end < *buf_ptr || array_end > end)
+ uintptr_t array_end = __pval(*buf_ptr) + *count * sizeof(uint32_t);
+ if (*count >= UINT32_MAX / sizeof(uint32_t) ||
+ array_end < __pval(*buf_ptr) || array_end > __pval(end))
return false;
data->reset(new (std::nothrow) T[*count]);
diff --git a/include/keymaster/soft_keymaster_context.h b/include/keymaster/soft_keymaster_context.h
index 2091d6f..eb10f44 100644
--- a/include/keymaster/soft_keymaster_context.h
+++ b/include/keymaster/soft_keymaster_context.h
@@ -53,6 +53,13 @@
*/
keymaster_error_t SetHardwareDevice(keymaster1_device_t* keymaster1_device);
+ keymaster_security_level_t GetSecurityLevel() const override {
+ return KM_SECURITY_LEVEL_SOFTWARE;
+ }
+
+ keymaster_error_t SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel) override;
+ void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const override;
+
KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const override;
OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm,
keymaster_purpose_t purpose) const override;
@@ -61,7 +68,9 @@
const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob,
AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) const override;
-
+ keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+ const AuthorizationSet& upgrade_params,
+ KeymasterKeyBlob* upgraded_key) const override;
keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
const AuthorizationSet& additional_params,
KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
@@ -75,12 +84,17 @@
keymaster_error_t* error) const override;
keymaster_cert_chain_t* AttestationChain(keymaster_algorithm_t algorithm,
keymaster_error_t* error) const override;
+ keymaster_error_t GenerateUniqueId(uint64_t creation_date_time,
+ const keymaster_blob_t& application_id,
+ bool reset_since_rotation, Buffer* unique_id) const override;
KeymasterEnforcement* enforcement_policy() override {
// SoftKeymaster does no enforcement; it's all done by Keystore.
return nullptr;
}
+ void AddSystemVersionToSet(AuthorizationSet* auth_set) const;
+
private:
keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob,
KeymasterKeyBlob* key_material,
@@ -108,6 +122,8 @@
std::unique_ptr<KeyFactory> hmac_factory_;
keymaster1_device* km1_dev_;
const std::string root_of_trust_;
+ uint32_t os_version_;
+ uint32_t os_patchlevel_;
};
} // namespace keymaster
diff --git a/include/keymaster/soft_keymaster_device.h b/include/keymaster/soft_keymaster_device.h
index 4a734f1..a20454d 100644
--- a/include/keymaster/soft_keymaster_device.h
+++ b/include/keymaster/soft_keymaster_device.h
@@ -79,6 +79,8 @@
impl_->GetVersion(req, rsp);
}
+ bool configured() const { return configured_; }
+
typedef std::pair<keymaster_algorithm_t, keymaster_purpose_t> AlgPurposePair;
typedef std::map<AlgPurposePair, std::vector<keymaster_digest_t>> DigestMap;
@@ -177,6 +179,8 @@
keymaster_operation_handle_t operation_handle);
// Keymaster2 methods
+ static keymaster_error_t configure(const keymaster2_device_t* dev,
+ const keymaster_key_param_set_t* params);
static keymaster_error_t add_rng_entropy(const keymaster2_device_t* dev, const uint8_t* data,
size_t data_length);
static keymaster_error_t generate_key(const keymaster2_device_t* dev,
@@ -204,6 +208,10 @@
const keymaster_key_blob_t* key_to_attest,
const keymaster_key_param_set_t* attest_params,
keymaster_cert_chain_t* cert_chain);
+ static keymaster_error_t upgrade_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_to_upgrade,
+ const keymaster_key_param_set_t* upgrade_params,
+ keymaster_key_blob_t* upgraded_key);
static keymaster_error_t delete_key(const keymaster2_device_t* dev,
const keymaster_key_blob_t* key);
static keymaster_error_t delete_all_keys(const keymaster2_device_t* dev);
@@ -238,6 +246,7 @@
UniquePtr<AndroidKeymaster> impl_;
std::string module_name_;
hw_module_t updated_module_;
+ bool configured_;
};
} // namespace keymaster
diff --git a/keymaster_configuration.cpp b/keymaster_configuration.cpp
new file mode 100644
index 0000000..428197c
--- /dev/null
+++ b/keymaster_configuration.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 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 <keymaster/keymaster_configuration.h>
+
+#include <regex>
+#include <string>
+
+#include <regex.h>
+
+#define LOG_TAG "keymaster"
+#include <cutils/log.h>
+
+#ifndef KEYMASTER_UNIT_TEST_BUILD
+#include <cutils/properties.h>
+#else
+#define PROPERTY_VALUE_MAX 80 /* Value doesn't matter */
+void property_get(const char* /* prop_name */, char* /* prop */, const char* /* default */) {}
+#endif
+
+#include <keymaster/authorization_set.h>
+
+namespace keymaster {
+
+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);
+}
+
+} // anonymous namespace
+
+keymaster_error_t ConfigureDevice(keymaster2_device_t* dev, uint32_t os_version,
+ uint32_t os_patchlevel) {
+ AuthorizationSet config_params(AuthorizationSetBuilder()
+ .Authorization(keymaster::TAG_OS_VERSION, os_version)
+ .Authorization(keymaster::TAG_OS_PATCHLEVEL, os_patchlevel));
+ return dev->configure(dev, &config_params);
+}
+
+keymaster_error_t ConfigureDevice(keymaster2_device_t* dev) {
+ char version_str[PROPERTY_VALUE_MAX];
+ property_get(kPlatformVersionProp, version_str, "" /* default */);
+ uint32_t version = GetOsVersion(version_str);
+
+ char patchlevel_str[PROPERTY_VALUE_MAX];
+ property_get(kPlatformPatchlevelProp, patchlevel_str, "" /* default */);
+ uint32_t patchlevel = GetOsPatchlevel(patchlevel_str);
+
+ return ConfigureDevice(dev, version, patchlevel);
+}
+
+uint32_t GetOsVersion(const char* version_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) {
+ ALOGE("Failed to compile version regex! (%s)", kPlatformVersionRegex);
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformVersionMatchCount];
+ if (regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */)) {
+ ALOGI("Platform version string does not match expected format. Using version 0.");
+ 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 GetOsPatchlevel(const char* patchlevel_str) {
+ regex_t regex;
+ if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+ ALOGE("Failed to compile platform patchlevel regex! (%s)", kPlatformPatchlevelRegex);
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformPatchlevelMatchCount];
+ if (regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */)) {
+ ALOGI("Platform patchlevel string does not match expected format. Using patchlevel 0");
+ 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) {
+ ALOGE("Invalid patch month %d", month);
+ return 0;
+ }
+ return year * 100 + month;
+}
+
+} // namespace keymaster
diff --git a/keymaster_configuration_test.cpp b/keymaster_configuration_test.cpp
new file mode 100644
index 0000000..81e9598
--- /dev/null
+++ b/keymaster_configuration_test.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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 <gtest/gtest.h>
+
+#include <keymaster/keymaster_configuration.h>
+
+#ifdef HOST_BUILD
+extern "C" {
+int __android_log_print(int prio, const char* tag, const char* fmt);
+int __android_log_print(int prio, const char* tag, const char* fmt) {
+ (void)prio, (void)tag, (void)fmt;
+ std::cout << fmt << std::endl;
+ return 0;
+}
+} // extern "C"
+#endif // HOST_BUILD
+
+namespace keymaster {
+namespace test {
+
+TEST(VersionParsingTest, Full) {
+ EXPECT_EQ(612334U, GetOsVersion("61.23.34"));
+ EXPECT_EQ(680000U, GetOsVersion("681.23.24"));
+ EXPECT_EQ(682300U, GetOsVersion("68.231.24"));
+ EXPECT_EQ(682324U, GetOsVersion("68.23.241"));
+ EXPECT_EQ(60102U, GetOsVersion("6.1.2-extrajunk"));
+ EXPECT_EQ(0U, GetOsVersion("extra6.1.2"));
+}
+
+TEST(VersionParsingTest, FullWithExtraChars) {}
+
+TEST(VersionParsingTest, MajorOnly) {
+ EXPECT_EQ(60000U, GetOsVersion("6"));
+ EXPECT_EQ(680000U, GetOsVersion("68"));
+ EXPECT_EQ(680000U, GetOsVersion("681"));
+ EXPECT_EQ(60000U, GetOsVersion("6.junk"));
+}
+
+TEST(VersionParsingTest, MajorMinorOnly) {
+ EXPECT_EQ(60100U, GetOsVersion("6.1"));
+ EXPECT_EQ(60100U, GetOsVersion("6.1junk"));
+}
+
+TEST(PatchLevelParsingTest, Full) {
+ EXPECT_EQ(201603U, GetOsPatchlevel("2016-03-23"));
+ EXPECT_EQ(0U, GetOsPatchlevel("2016-13-23"));
+ EXPECT_EQ(0U, GetOsPatchlevel("2016-03"));
+ EXPECT_EQ(0U, GetOsPatchlevel("2016-3-23"));
+ EXPECT_EQ(0U, GetOsPatchlevel("2016-03-23r"));
+ EXPECT_EQ(0U, GetOsPatchlevel("r2016-03-23"));
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/keymaster_enforcement.cpp b/keymaster_enforcement.cpp
index 7696d89..3f2e4f4 100644
--- a/keymaster_enforcement.cpp
+++ b/keymaster_enforcement.cpp
@@ -285,6 +285,7 @@
case KM_TAG_AUTH_TOKEN:
case KM_TAG_ROOT_OF_TRUST:
case KM_TAG_APPLICATION_DATA:
+ case KM_TAG_ATTESTATION_CHALLENGE:
return KM_ERROR_INVALID_KEY_BLOB;
/* Tags used for cryptographic parameters in keygen. Nothing to enforce. */
diff --git a/keymaster_tags.cpp b/keymaster_tags.cpp
index ce7156f..238bc33 100644
--- a/keymaster_tags.cpp
+++ b/keymaster_tags.cpp
@@ -109,6 +109,8 @@
return "KM_TAG_RESET_SINCE_ID_ROTATION";
case KM_TAG_ALLOW_WHILE_ON_BODY:
return "KM_TAG_ALLOW_WHILE_ON_BODY";
+ case KM_TAG_ATTESTATION_CHALLENGE:
+ return "KM_TAG_ATTESTATION_CHALLENGE";
}
return "<Unknown>";
}
diff --git a/openssl_utils.h b/openssl_utils.h
index 034b129..9fa6ec1 100644
--- a/openssl_utils.h
+++ b/openssl_utils.h
@@ -49,18 +49,19 @@
typedef OpenSslObjectDeleter<name, name##_free> name##_Delete; \
typedef UniquePtr<name, name##_Delete> name##_Ptr;
+DEFINE_OPENSSL_OBJECT_POINTER(ASN1_BIT_STRING)
DEFINE_OPENSSL_OBJECT_POINTER(ASN1_INTEGER)
DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OBJECT)
DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OCTET_STRING)
DEFINE_OPENSSL_OBJECT_POINTER(ASN1_TIME)
-DEFINE_OPENSSL_OBJECT_POINTER(BN_CTX);
-DEFINE_OPENSSL_OBJECT_POINTER(EC_GROUP);
-DEFINE_OPENSSL_OBJECT_POINTER(EC_KEY);
-DEFINE_OPENSSL_OBJECT_POINTER(EC_POINT);
-DEFINE_OPENSSL_OBJECT_POINTER(ENGINE);
-DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY);
-DEFINE_OPENSSL_OBJECT_POINTER(PKCS8_PRIV_KEY_INFO);
-DEFINE_OPENSSL_OBJECT_POINTER(RSA);
+DEFINE_OPENSSL_OBJECT_POINTER(BN_CTX)
+DEFINE_OPENSSL_OBJECT_POINTER(EC_GROUP)
+DEFINE_OPENSSL_OBJECT_POINTER(EC_KEY)
+DEFINE_OPENSSL_OBJECT_POINTER(EC_POINT)
+DEFINE_OPENSSL_OBJECT_POINTER(ENGINE)
+DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY)
+DEFINE_OPENSSL_OBJECT_POINTER(PKCS8_PRIV_KEY_INFO)
+DEFINE_OPENSSL_OBJECT_POINTER(RSA)
DEFINE_OPENSSL_OBJECT_POINTER(X509)
DEFINE_OPENSSL_OBJECT_POINTER(X509_EXTENSION)
DEFINE_OPENSSL_OBJECT_POINTER(X509_NAME)
diff --git a/rsa_operation.cpp b/rsa_operation.cpp
index 2046a64..ce8d2f3 100644
--- a/rsa_operation.cpp
+++ b/rsa_operation.cpp
@@ -31,7 +31,6 @@
namespace keymaster {
const size_t kPssOverhead = 2;
-const size_t kMinPssSaltSize = 20;
// Overhead for PKCS#1 v1.5 signature padding of undigested messages. Digested messages have
// additional overhead, for the digest algorithmIdentifier required by PKCS#1.
@@ -173,7 +172,7 @@
return KM_ERROR_OK;
}
-keymaster_error_t RsaOperation::SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx) {
+keymaster_error_t RsaOperation::SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx, bool signing) {
keymaster_error_t error;
int openssl_padding = GetOpensslPadding(&error);
if (error != KM_ERROR_OK)
@@ -181,6 +180,15 @@
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, openssl_padding) <= 0)
return TranslateLastOpenSslError();
+
+ if (signing && openssl_padding == RSA_PKCS1_PSS_PADDING) {
+ // Also need to set the length of the salt used in the padding generation. We set it equal
+ // to the length of the selected digest.
+ assert(digest_algorithm_);
+ if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, EVP_MD_size(digest_algorithm_)) <= 0)
+ return TranslateLastOpenSslError();
+ }
+
return KM_ERROR_OK;
}
@@ -238,8 +246,7 @@
*error = KM_ERROR_INCOMPATIBLE_PADDING_MODE;
return -1;
}
- if (EVP_MD_size(digest_algorithm_) + kPssOverhead + kMinPssSaltSize >
- (size_t)EVP_PKEY_size(rsa_key_)) {
+ if (EVP_MD_size(digest_algorithm_) * 2 + kPssOverhead > (size_t)EVP_PKEY_size(rsa_key_)) {
LOG_E("Input too long: %d-byte digest cannot be used with %d-byte RSA key in PSS "
"padding mode",
EVP_MD_size(digest_algorithm_), EVP_PKEY_size(rsa_key_));
@@ -265,7 +272,7 @@
if (EVP_DigestSignInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, nullptr /* engine */,
rsa_key_) != 1)
return TranslateLastOpenSslError();
- return SetRsaPaddingInEvpContext(pkey_ctx);
+ return SetRsaPaddingInEvpContext(pkey_ctx, true /* signing */);
}
keymaster_error_t RsaSignOperation::Update(const AuthorizationSet& additional_params,
@@ -388,7 +395,7 @@
EVP_PKEY_CTX* pkey_ctx;
if (EVP_DigestVerifyInit(&digest_ctx_, &pkey_ctx, digest_algorithm_, NULL, rsa_key_) != 1)
return TranslateLastOpenSslError();
- return SetRsaPaddingInEvpContext(pkey_ctx);
+ return SetRsaPaddingInEvpContext(pkey_ctx, false /* signing */);
}
keymaster_error_t RsaVerifyOperation::Update(const AuthorizationSet& additional_params,
@@ -529,7 +536,7 @@
if (EVP_PKEY_encrypt_init(ctx.get()) <= 0)
return TranslateLastOpenSslError();
- error = SetRsaPaddingInEvpContext(ctx.get());
+ error = SetRsaPaddingInEvpContext(ctx.get(), false /* signing */);
if (error != KM_ERROR_OK)
return error;
error = SetOaepDigestIfRequired(ctx.get());
@@ -582,7 +589,7 @@
if (EVP_PKEY_decrypt_init(ctx.get()) <= 0)
return TranslateLastOpenSslError();
- error = SetRsaPaddingInEvpContext(ctx.get());
+ error = SetRsaPaddingInEvpContext(ctx.get(), false /* signing */);
if (error != KM_ERROR_OK)
return error;
error = SetOaepDigestIfRequired(ctx.get());
diff --git a/rsa_operation.h b/rsa_operation.h
index 8283f2e..669b21a 100644
--- a/rsa_operation.h
+++ b/rsa_operation.h
@@ -54,7 +54,7 @@
virtual bool require_digest() const = 0;
keymaster_error_t StoreData(const Buffer& input, size_t* input_consumed);
- keymaster_error_t SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx);
+ keymaster_error_t SetRsaPaddingInEvpContext(EVP_PKEY_CTX* pkey_ctx, bool signing);
keymaster_error_t InitDigest();
EVP_PKEY* rsa_key_;
diff --git a/serializable.cpp b/serializable.cpp
index 5db64f8..94b92d0 100644
--- a/serializable.cpp
+++ b/serializable.cpp
@@ -25,7 +25,7 @@
namespace keymaster {
uint8_t* append_to_buf(uint8_t* buf, const uint8_t* end, const void* data, size_t data_len) {
- if (buf + data_len < buf) // Pointer wrap check
+ if (__pval(buf) + data_len < __pval(buf)) // Pointer wrap check
return buf;
if (buf + data_len <= end) {
@@ -36,7 +36,7 @@
}
bool copy_from_buf(const uint8_t** buf_ptr, const uint8_t* end, void* dest, size_t size) {
- if (*buf_ptr + size < *buf_ptr) // Pointer wrap check
+ if (__pval(*buf_ptr) + size < __pval(*buf_ptr)) // Pointer wrap check
return false;
if (end < *buf_ptr + size)
@@ -51,7 +51,7 @@
if (!copy_uint32_from_buf(buf_ptr, end, size))
return false;
- if (*buf_ptr + *size < *buf_ptr) // Pointer wrap check
+ if (__pval(*buf_ptr) + *size < __pval(*buf_ptr)) // Pointer wrap check
return false;
if (*buf_ptr + *size > end)
@@ -96,7 +96,7 @@
bool Buffer::Reinitialize(const void* data, size_t data_len) {
Clear();
- if (static_cast<const uint8_t*>(data) + data_len < data) // Pointer wrap check
+ if (__pval(data) + data_len < __pval(data)) // Pointer wrap check
return false;
buffer_.reset(new (std::nothrow) uint8_t[data_len]);
if (!buffer_.get())
diff --git a/soft_keymaster_context.cpp b/soft_keymaster_context.cpp
index a143245..892fffa 100644
--- a/soft_keymaster_context.cpp
+++ b/soft_keymaster_context.cpp
@@ -20,6 +20,7 @@
#include <time.h>
#include <openssl/aes.h>
+#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
@@ -281,12 +282,34 @@
size_t kCertificateChainLength = 2;
+bool UpgradeIntegerTag(keymaster_tag_t tag, uint32_t value, AuthorizationSet* set,
+ bool* set_changed) {
+ int index = set->find(tag);
+ if (index == -1) {
+ keymaster_key_param_t param;
+ param.tag = tag;
+ param.integer = value;
+ set->push_back(param);
+ *set_changed = true;
+ return true;
+ }
+
+ if (set->params[index].integer > value)
+ return false;
+
+ if (set->params[index].integer != value) {
+ set->params[index].integer = value;
+ *set_changed = true;
+ }
+ return true;
+}
+
} // anonymous namespace
SoftKeymasterContext::SoftKeymasterContext(const std::string& root_of_trust)
: rsa_factory_(new RsaKeyFactory(this)), ec_factory_(new EcKeyFactory(this)),
aes_factory_(new AesKeyFactory(this)), hmac_factory_(new HmacKeyFactory(this)),
- km1_dev_(nullptr), root_of_trust_(root_of_trust) {}
+ km1_dev_(nullptr), root_of_trust_(root_of_trust), os_version_(0), os_patchlevel_(0) {}
SoftKeymasterContext::~SoftKeymasterContext() {}
@@ -326,6 +349,18 @@
return KM_ERROR_OK;
}
+keymaster_error_t SoftKeymasterContext::SetSystemVersion(uint32_t os_version,
+ uint32_t os_patchlevel) {
+ os_version_ = os_version;
+ os_patchlevel_ = os_patchlevel;
+ return KM_ERROR_OK;
+}
+
+void SoftKeymasterContext::GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const {
+ *os_version = os_version_;
+ *os_patchlevel = os_patchlevel_;
+}
+
KeyFactory* SoftKeymasterContext::GetKeyFactory(keymaster_algorithm_t algorithm) const {
switch (algorithm) {
case KM_ALGORITHM_RSA:
@@ -371,8 +406,8 @@
}
static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description,
- keymaster_key_origin_t origin,
- AuthorizationSet* hw_enforced,
+ keymaster_key_origin_t origin, uint32_t os_version,
+ uint32_t os_patchlevel, AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) {
sw_enforced->Clear();
@@ -405,6 +440,9 @@
sw_enforced->push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
sw_enforced->push_back(TAG_ORIGIN, origin);
+ sw_enforced->push_back(TAG_OS_VERSION, os_version);
+ sw_enforced->push_back(TAG_OS_PATCHLEVEL, os_patchlevel);
+
return TranslateAuthorizationSetError(sw_enforced->is_valid());
}
@@ -414,7 +452,8 @@
KeymasterKeyBlob* blob,
AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) const {
- keymaster_error_t error = SetAuthorizations(key_description, origin, hw_enforced, sw_enforced);
+ keymaster_error_t error = SetAuthorizations(key_description, origin, os_version_,
+ os_patchlevel_, hw_enforced, sw_enforced);
if (error != KM_ERROR_OK)
return error;
@@ -426,6 +465,51 @@
return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
}
+keymaster_error_t SoftKeymasterContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade,
+ const AuthorizationSet& upgrade_params,
+ KeymasterKeyBlob* upgraded_key) const {
+ KeymasterKeyBlob key_material;
+ AuthorizationSet tee_enforced;
+ AuthorizationSet sw_enforced;
+ keymaster_error_t error =
+ ParseKeyBlob(key_to_upgrade, upgrade_params, &key_material, &tee_enforced, &sw_enforced);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ // Three cases here:
+ //
+ // 1. Software key blob. Version info, if present, is in sw_enforced. If not present, we
+ // should add it.
+ //
+ // 2. Keymaster0 hardware key blob. Version info, if present, is in sw_enforced. If not
+ // present we should add it.
+ //
+ // 3. Keymaster1 hardware key blob. Version info is not present and we shouldn't have been
+ // asked to upgrade.
+
+ // Handle case 3.
+ if (km1_dev_ && tee_enforced.Contains(TAG_PURPOSE) && !tee_enforced.Contains(TAG_OS_PATCHLEVEL))
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ // Handle cases 1 & 2.
+ bool set_changed = false;
+ if (!UpgradeIntegerTag(TAG_OS_VERSION, os_version_, &sw_enforced, &set_changed) ||
+ !UpgradeIntegerTag(TAG_OS_PATCHLEVEL, os_patchlevel_, &sw_enforced, &set_changed))
+ // One of the version fields would have been a downgrade. Not allowed.
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ if (!set_changed)
+ // Dont' need an upgrade.
+ return KM_ERROR_OK;
+
+ AuthorizationSet hidden;
+ error = BuildHiddenAuthorizations(upgrade_params, &hidden);
+ if (error != KM_ERROR_OK)
+ return error;
+ return SerializeIntegrityAssuredBlob(key_material, hidden, tee_enforced, sw_enforced,
+ upgraded_key);
+}
+
static keymaster_error_t ParseOcbAuthEncryptedBlob(const KeymasterKeyBlob& blob,
const AuthorizationSet& hidden,
KeymasterKeyBlob* key_material,
@@ -653,6 +737,13 @@
return KM_ERROR_OK;
}
+void SoftKeymasterContext::AddSystemVersionToSet(AuthorizationSet* auth_set) const {
+ if (!auth_set->Contains(TAG_OS_VERSION))
+ auth_set->push_back(TAG_OS_VERSION, os_version_);
+ if (!auth_set->Contains(TAG_OS_PATCHLEVEL))
+ auth_set->push_back(TAG_OS_PATCHLEVEL, os_patchlevel_);
+}
+
EVP_PKEY* SoftKeymasterContext::AttestationKey(keymaster_algorithm_t algorithm,
keymaster_error_t* error) const {
@@ -742,6 +833,13 @@
return chain.release();
}
+keymaster_error_t SoftKeymasterContext::GenerateUniqueId(
+ uint64_t /* creation_date_time */, const keymaster_blob_t& /* application_id */,
+ bool /* reset_since_rotation */, Buffer* /* unique_id */) const {
+ // SoftKeymasterDevice cannot generate unique IDs.
+ return KM_ERROR_UNIMPLEMENTED;
+}
+
keymaster_error_t SoftKeymasterContext::ParseKeymaster1HwBlob(
const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp
index cbeaec7..eddbc5d 100644
--- a/soft_keymaster_device.cpp
+++ b/soft_keymaster_device.cpp
@@ -73,6 +73,7 @@
namespace keymaster {
+const size_t kMaximumAttestationChallengeLength = 128;
const size_t kOperationTableSize = 16;
template <typename T> std::vector<T> make_vector(const T* array, size_t len) {
@@ -126,7 +127,7 @@
SoftKeymasterDevice::SoftKeymasterDevice()
: wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr),
context_(new SoftKeymasterContext),
- impl_(new AndroidKeymaster(context_, kOperationTableSize)) {
+ impl_(new AndroidKeymaster(context_, kOperationTableSize)), configured_(false) {
LOG_I("Creating device", 0);
LOG_D("Device address: %p", this);
@@ -136,7 +137,7 @@
SoftKeymasterDevice::SoftKeymasterDevice(SoftKeymasterContext* context)
: wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr), context_(context),
- impl_(new AndroidKeymaster(context_, kOperationTableSize)) {
+ impl_(new AndroidKeymaster(context_, kOperationTableSize)), configured_(false) {
LOG_I("Creating test device", 0);
LOG_D("Device address: %p", this);
@@ -275,14 +276,14 @@
km2_device_.common.module = reinterpret_cast<hw_module_t*>(&soft_keymaster2_device_module);
km2_device_.common.close = &close_device;
+ km2_device_.configure = configure;
km2_device_.add_rng_entropy = add_rng_entropy;
km2_device_.generate_key = generate_key;
km2_device_.get_key_characteristics = get_key_characteristics;
km2_device_.import_key = import_key;
km2_device_.export_key = export_key;
- km2_device_.agree_key = nullptr; // TODO(swillden) Implement ECDH
km2_device_.attest_key = attest_key;
- km2_device_.upgrade_key = nullptr; // TODO(swillden) Implement upgrade
+ km2_device_.upgrade_key = upgrade_key;
km2_device_.delete_key = delete_key;
km2_device_.delete_all_keys = delete_all_keys;
km2_device_.begin = begin;
@@ -601,6 +602,25 @@
}
/* static */
+keymaster_error_t SoftKeymasterDevice::configure(const keymaster2_device_t* dev,
+ const keymaster_key_param_set_t* params) {
+ AuthorizationSet params_copy(*params);
+ uint32_t os_version;
+ uint32_t os_patchlevel;
+ if (!params_copy.GetTagValue(TAG_OS_VERSION, &os_version) ||
+ !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &os_patchlevel)) {
+ LOG_E("Configuration parameters must contain OS version and patch level", 0);
+ return KM_ERROR_INVALID_ARGUMENT;
+ }
+
+ keymaster_error_t error =
+ convert_device(dev)->context_->SetSystemVersion(os_version, os_patchlevel);
+ if (error == KM_ERROR_OK)
+ convert_device(dev)->configured_ = true;
+ return error;
+}
+
+/* static */
keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const keymaster1_device_t* dev,
const uint8_t* data, size_t data_length) {
if (!dev)
@@ -625,6 +645,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
SoftKeymasterDevice* sk_dev = convert_device(dev);
return add_rng_entropy(&sk_dev->km1_device_, data, data_length);
}
@@ -735,6 +758,12 @@
key_blob->key_material = tmp;
if (characteristics) {
+ // This is a keymaster1 method, and keymaster1 doesn't include version info, so remove it.
+ response.enforced.erase(response.enforced.find(TAG_OS_VERSION));
+ response.enforced.erase(response.enforced.find(TAG_OS_PATCHLEVEL));
+ response.unenforced.erase(response.unenforced.find(TAG_OS_VERSION));
+ response.unenforced.erase(response.unenforced.find(TAG_OS_PATCHLEVEL));
+
*characteristics = BuildCharacteristics(response.enforced, response.unenforced);
if (!*characteristics)
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -751,6 +780,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
if (!key_blob)
return KM_ERROR_OUTPUT_PARAMETER_NULL;
@@ -771,6 +803,7 @@
*characteristics = *chars_ptr;
free(chars_ptr);
}
+
return KM_ERROR_OK;
}
@@ -806,9 +839,10 @@
return KM_ERROR_OUTPUT_PARAMETER_NULL;
const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_;
- if (km1_dev)
+ if (km1_dev) {
return km1_dev->get_key_characteristics(km1_dev, key_blob, client_id, app_data,
characteristics);
+ }
GetKeyCharacteristicsRequest request;
request.SetKeyMaterial(*key_blob);
@@ -819,9 +853,16 @@
if (response.error != KM_ERROR_OK)
return response.error;
+ // This is a keymaster1 method, and keymaster1 doesn't include version info, so remove it.
+ response.enforced.erase(response.enforced.find(TAG_OS_VERSION));
+ response.enforced.erase(response.enforced.find(TAG_OS_PATCHLEVEL));
+ response.unenforced.erase(response.unenforced.find(TAG_OS_VERSION));
+ response.unenforced.erase(response.unenforced.find(TAG_OS_PATCHLEVEL));
+
*characteristics = BuildCharacteristics(response.enforced, response.unenforced);
if (!*characteristics)
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
return KM_ERROR_OK;
}
@@ -833,21 +874,39 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
if (!characteristics)
return KM_ERROR_OUTPUT_PARAMETER_NULL;
SoftKeymasterDevice* sk_dev = convert_device(dev);
- keymaster_error_t error;
- keymaster_key_characteristics_t* key_characteristics;
- error = get_key_characteristics(&sk_dev->km1_device_, key_blob, client_id, app_data,
- &key_characteristics);
- if (error != KM_ERROR_OK)
+ const keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_;
+ if (km1_dev) {
+ keymaster_key_characteristics_t* tmp_characteristics;
+ keymaster_error_t error = km1_dev->get_key_characteristics(km1_dev, key_blob, client_id,
+ app_data, &tmp_characteristics);
+ if (error == KM_ERROR_OK) {
+ *characteristics = *tmp_characteristics;
+ free(tmp_characteristics);
+ }
return error;
- *characteristics = *key_characteristics;
- free(key_characteristics);
+ }
- return error;
+ GetKeyCharacteristicsRequest request;
+ request.SetKeyMaterial(*key_blob);
+ AddClientAndAppData(client_id, app_data, &request);
+
+ GetKeyCharacteristicsResponse response;
+ sk_dev->impl_->GetKeyCharacteristics(request, &response);
+ if (response.error != KM_ERROR_OK)
+ return response.error;
+
+ response.enforced.CopyToParamSet(&characteristics->hw_enforced);
+ response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
+
+ return KM_ERROR_OK;
}
/* static */
@@ -871,7 +930,8 @@
return km1_dev->import_key(km1_dev, params, key_format, key_data, key_blob,
characteristics);
- *characteristics = nullptr;
+ if (characteristics)
+ *characteristics = nullptr;
request.key_format = key_format;
request.SetKeyMaterial(key_data->data, key_data->data_length);
@@ -904,6 +964,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
SoftKeymasterDevice* sk_dev = convert_device(dev);
keymaster_error_t error;
@@ -972,6 +1035,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
SoftKeymasterDevice* sk_dev = convert_device(dev);
return export_key(&sk_dev->km1_device_, export_format, key_to_export, client_id, app_data,
export_data);
@@ -985,6 +1051,9 @@
if (!dev || !key_to_attest || !attest_params || !cert_chain)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
cert_chain->entry_count = 0;
cert_chain->entries = nullptr;
@@ -992,6 +1061,14 @@
request.SetKeyMaterial(*key_to_attest);
request.attest_params.Reinitialize(*attest_params);
+ keymaster_blob_t attestation_challenge = {};
+ request.attest_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge);
+ if (attestation_challenge.data_length > kMaximumAttestationChallengeLength) {
+ LOG_E("%d-byte attestation challenge; only %d bytes allowed",
+ attestation_challenge.data_length, kMaximumAttestationChallengeLength);
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+
AttestKeyResponse response;
convert_device(dev)->impl_->AttestKey(request, &response);
if (response.error != KM_ERROR_OK)
@@ -1024,6 +1101,39 @@
}
/* static */
+keymaster_error_t SoftKeymasterDevice::upgrade_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_to_upgrade,
+ const keymaster_key_param_set_t* upgrade_params,
+ keymaster_key_blob_t* upgraded_key) {
+ if (!dev || !key_to_upgrade || !upgrade_params)
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+ if (!upgraded_key)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
+ UpgradeKeyRequest request;
+ request.SetKeyMaterial(*key_to_upgrade);
+ request.upgrade_params.Reinitialize(*upgrade_params);
+
+ UpgradeKeyResponse response;
+ convert_device(dev)->impl_->UpgradeKey(request, &response);
+ if (response.error != KM_ERROR_OK)
+ return response.error;
+
+ upgraded_key->key_material_size = response.upgraded_key.key_material_size;
+ uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(upgraded_key->key_material_size));
+ if (!tmp)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ memcpy(tmp, response.upgraded_key.key_material, response.upgraded_key.key_material_size);
+ upgraded_key->key_material = tmp;
+
+ return KM_ERROR_OK;
+}
+
+/* static */
keymaster_error_t SoftKeymasterDevice::delete_key(const keymaster1_device_t* dev,
const keymaster_key_blob_t* key) {
if (!dev || !key || !key->key_material)
@@ -1039,6 +1149,9 @@
if (!dev || !key || !key->key_material)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
KeymasterKeyBlob blob(*key);
return convert_device(dev)->context_->DeleteKey(blob);
}
@@ -1056,6 +1169,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
return convert_device(dev)->context_->DeleteAllKeys();
}
@@ -1125,6 +1241,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
SoftKeymasterDevice* sk_dev = convert_device(dev);
return begin(&sk_dev->km1_device_, purpose, key, in_params, out_params, operation_handle);
}
@@ -1203,6 +1322,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
SoftKeymasterDevice* sk_dev = convert_device(dev);
return update(&sk_dev->km1_device_, operation_handle, in_params, input, input_consumed,
out_params, output);
@@ -1275,6 +1397,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
if (input && input->data)
return KM_ERROR_UNIMPLEMENTED; // TODO(swillden): Implement this
@@ -1306,6 +1431,9 @@
if (!dev)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ if (!convert_device(dev)->configured())
+ return KM_ERROR_KEYMASTER_NOT_CONFIGURED;
+
SoftKeymasterDevice* sk_dev = convert_device(dev);
return abort(&sk_dev->km1_device_, operation_handle);
}