summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android_keymaster_test.cpp20
-rw-r--r--android_keymaster_utils.cpp50
-rw-r--r--asymmetric_key.cpp34
-rw-r--r--attestation_record.cpp23
-rw-r--r--authorization_set.cpp7
-rw-r--r--ec_key_factory.cpp71
-rw-r--r--ec_keymaster0_key.cpp8
-rw-r--r--include/keymaster/android_keymaster_utils.h3
-rw-r--r--include/keymaster/authorization_set.h9
-rw-r--r--include/keymaster/ec_key_factory.h7
10 files changed, 207 insertions, 25 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/asymmetric_key.cpp b/asymmetric_key.cpp
index 4412618..c4e2da5 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"
@@ -257,12 +258,39 @@ keymaster_error_t AsymmetricKey::GenerateAttestation(const KeymasterContext& con
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 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