From d487dc9e95162f249048bd31d4191a0d50b77496 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Mon, 25 Apr 2016 08:58:31 -0600 Subject: Add key usage extension to attestation certificates. SoftKeymaster doesn't add the key usage extension to attestation certificates, as required by RFC 5280 and the attestation design doc. Bug: 28366730 Change-Id: Ic782a032c8b39754d60bca98126acff7b3179678 --- asymmetric_key.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++- openssl_utils.h | 17 +++++------ 2 files changed, 90 insertions(+), 9 deletions(-) diff --git a/asymmetric_key.cpp b/asymmetric_key.cpp index c4e2da5..782e87b 100644 --- a/asymmetric_key.cpp +++ b/asymmetric_key.cpp @@ -30,9 +30,85 @@ namespace keymaster { namespace { + +constexpr int kDigitalSignatureKeyUsageBit = 0; +constexpr int kKeyEnciphermentKeyUsageBit = 2; +constexpr int kDataEnciphermentKeyUsageBit = 3; +constexpr int kMaxKeyUsageBit = 8; + template 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 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, @@ -249,7 +325,11 @@ keymaster_error_t AsymmetricKey::GenerateAttestation(const KeymasterContext& con !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() || // diff --git a/openssl_utils.h b/openssl_utils.h index 016aea8..dd22bdf 100644 --- a/openssl_utils.h +++ b/openssl_utils.h @@ -49,18 +49,19 @@ template struct OpenSslObjectDeleter { typedef OpenSslObjectDeleter name##_Delete; \ typedef UniquePtr 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) -- cgit v1.2.3