diff options
| author | Shawn Willden <swillden@google.com> | 2016-04-28 05:00:54 +0000 |
|---|---|---|
| committer | android-build-merger <android-build-merger@google.com> | 2016-04-28 05:00:54 +0000 |
| commit | 89a1084424544bf2430c504122037bea536fad40 (patch) | |
| tree | 413c9cab85bfc89ef6079b89555b171dc2a10b6d | |
| parent | 6ecb98114be631e756cdae59d84de7e5972f7359 (diff) | |
| parent | ec4c9efca70fd6077ac996f3e487c2c979793bdc (diff) | |
| download | android_system_keymaster-89a1084424544bf2430c504122037bea536fad40.tar.gz android_system_keymaster-89a1084424544bf2430c504122037bea536fad40.tar.bz2 android_system_keymaster-89a1084424544bf2430c504122037bea536fad40.zip | |
Merge changes I8705aac6,I27d98b71 into nyc-dev
am: ec4c9ef
* commit 'ec4c9efca70fd6077ac996f3e487c2c979793bdc':
Add EC curve tag to keymaster1 SoftKeymaster1 attestations.
Fix SoftKeymaster handling of EC curve specification.
Change-Id: Ib93d86a3c240c003aaf966caa7a44148a85b60d0
| -rw-r--r-- | android_keymaster_test.cpp | 20 | ||||
| -rw-r--r-- | android_keymaster_utils.cpp | 50 | ||||
| -rw-r--r-- | attestation_record.cpp | 23 | ||||
| -rw-r--r-- | authorization_set.cpp | 7 | ||||
| -rw-r--r-- | ec_key_factory.cpp | 71 | ||||
| -rw-r--r-- | ec_keymaster0_key.cpp | 8 | ||||
| -rw-r--r-- | include/keymaster/android_keymaster_utils.h | 3 | ||||
| -rw-r--r-- | include/keymaster/authorization_set.h | 9 | ||||
| -rw-r--r-- | include/keymaster/ec_key_factory.h | 7 |
9 files changed, 176 insertions, 22 deletions
diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp index 1ea0c34..325a4c8 100644 --- a/android_keymaster_test.cpp +++ b/android_keymaster_test.cpp @@ -334,17 +334,17 @@ TEST_P(NewKeyGeneration, EcdsaDefaultSize) { } 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) { 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 @@ int memcmp_s(const void* p1, const void* p2, size_t length) { 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/attestation_record.cpp b/attestation_record.cpp index 4edac3e..befb8e2 100644 --- a/attestation_record.cpp +++ b/attestation_record.cpp @@ -378,6 +378,27 @@ static keymaster_error_t build_auth_list(const AuthorizationSet& auth_list, KM_A } } + 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; } @@ -455,7 +476,7 @@ keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_p return KM_ERROR_INVALID_KEY_BLOB; } - keymaster_blob_t application_id = {}; + keymaster_blob_t application_id = {nullptr, 0}; sw_enforced.GetTagValue(TAG_APPLICATION_ID, &application_id); Buffer unique_id; diff --git a/authorization_set.cpp b/authorization_set.cpp index b241b78..9f6810d 100644 --- a/authorization_set.cpp +++ b/authorization_set.cpp @@ -630,4 +630,11 @@ bool AuthorizationSet::ContainsEnumValue(keymaster_tag_t tag, uint32_t value) co 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 @@ OperationFactory* EcKeyFactory::GetOperationFactory(keymaster_purpose_t purpose) } } +/* 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 @@ keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_descript 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 @@ keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_descript 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 @@ keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_descript 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 @@ keymaster_error_t EcKeyFactory::UpdateImportKeyDescription(const AuthorizationSe } /* 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 @@ EC_GROUP* EcKeyFactory::choose_group(size_t key_size_bits) { } } +/* 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 @@ keymaster_error_t EcdsaKeymaster0KeyFactory::GenerateKey(const AuthorizationSet& 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 @@ keymaster_error_t EcdsaKeymaster0KeyFactory::GenerateKey(const AuthorizationSet& // 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_utils.h b/include/keymaster/android_keymaster_utils.h index c190e04..17688a6 100644 --- a/include/keymaster/android_keymaster_utils.h +++ b/include/keymaster/android_keymaster_utils.h @@ -325,6 +325,9 @@ struct CertificateChainDelete { } }; +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 5be5d83..ec68de0 100644 --- a/include/keymaster/authorization_set.h +++ b/include/keymaster/authorization_set.h @@ -231,6 +231,14 @@ class AuthorizationSet : public Serializable, public keymaster_key_param_set_t { } /** + * 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. */ @@ -442,6 +450,7 @@ class AuthorizationSet : public Serializable, public keymaster_key_param_set_t { 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, respectively. This is to // avoid using the variables without the trailing underscore in the implementation. diff --git a/include/keymaster/ec_key_factory.h b/include/keymaster/ec_key_factory.h index 2715e79..91c491c 100644 --- a/include/keymaster/ec_key_factory.h +++ b/include/keymaster/ec_key_factory.h @@ -52,7 +52,12 @@ class EcKeyFactory : public AsymmetricKeyFactory { 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 |
