diff options
author | Shawn Willden <swillden@google.com> | 2015-05-18 08:35:28 -0600 |
---|---|---|
committer | Shawn Willden <swillden@google.com> | 2015-05-20 12:55:18 -0600 |
commit | 8ba2a043f0d44ad3f58d4af518f9391c03eca9c3 (patch) | |
tree | ff76cdef7952c9bfe52f7b2608373622b83a4238 /rsa_key.cpp | |
parent | f923963fda888eac9e7997b71d5525ea2f82a091 (diff) | |
download | android_system_keymaster-8ba2a043f0d44ad3f58d4af518f9391c03eca9c3.tar.gz android_system_keymaster-8ba2a043f0d44ad3f58d4af518f9391c03eca9c3.tar.bz2 android_system_keymaster-8ba2a043f0d44ad3f58d4af518f9391c03eca9c3.zip |
Large refactor to move context out of AndroidKeymaster.
AndroidKeymaster made a number of assumptions about its context that are
really only valid for TEE-based usage. In addition, KeyFactory made
some similarly TEE-focused assumptions about key blob creation and
parsing.
Both concerns have been moved to a new KeymasterContext class, which is
responsible for building and parsing key blobs in a manner appropriate
for the context in which AndroidKeymaster is running, as well as
providing other context-specific services, such as random number
generation.
In addition, the refactor reduces the need for the KeyBlob and
UnencryptedKeyBlob classes, which encode too many assumptions about blob
formatting and encryption, to the point that they can be removed and
replaced by a handful of utility functions which are much cleaner and
more flexible.
How to review this CL:
I looked hard at breaking this up into smaller CLs, but it's mostly not
feasible. However, it's probably easier to approach it by starting with
the fundamental changes, and then looking at the cascade effects.
1. Look at keymaster_context.h. The core of the change was pulling this
set of features out of AndroidKeymaster. Note that the revised approach
to key blob creation does not involve the KeyBlob and UnencryptedKeyBlob
classes, but instead goes directly from raw key material plus ancillary
data (e.g. auth sets) to a serialized buffer ready to return to
keystore. The same is true in reverse direction for parsing key blobs.
2. Look at key.h. The revised KeyFactory GenerateKey, ImportKey and
LoadKey methods are essential. GenerateKey and ImportKey no longer
produce a Key object, because all that's needed is a returnable blob.
LoadKey produces a Key object, but it starts with raw key material,
rather than an UnencryptedKeyBlob. Also note the change to the Key
class; because Key objects are only created by LoadKey, when there's a
need to use a key, there's only one constructor.
3. Look at asymmetric_key.h, rsa_key.h and rsa_key.cpp. rsa_key.cpp
provides a good example of how the new structure works. GenerateKey and
ImportKey do all of the work necessary to produce an OpenSSL RSA key and
extract the internal representation (using EvpToKeyMaterial; defined in
asymmetric_key.h because it's the same for EC keys). Then, with the raw
key data in hand, they call KeymasterContext::CreateKeyBlob to wrap the
key data in a key blob that can be returned to the caller -- whatever
that wrapping means in the current context. There's a subtlety not
apparent here which is crucial to the rationale for the refactoring:
RsaKeyFactory uses KeymasterContext::get_instance to retrieve the
context, but key factories which depend on operating in a particular
context can use a different way to get their context object, which may
have a larger interface. RsaKeymaster0KeyFactory will do this.
4. Look at soft_keymaster_context. In
particular, SoftKeymasterContext::CreateKeyBlob and ParseKeyBlob.
CreateKeyBlob allocates authorization tags from key_description to
hw_enforced and sw_enforced, then encrypts the key material and
serializes it to a blob. This approach is compatible with the keys
softkeymaster has been producing, but I'm going to change it (post M),
because there's no reason to bother encrypting SW keys with a SW key.
ParseKeyBlob reverses the process to recover the unencrypted key
material and the auth lists. One debatable point was the decision to
implement BuildHiddenAuthorizations and SetAuthorizations here, since
all contexts will need something similar, and they really should all do
it the same. I may refactor later to pull that functionality up to
KeymasterContext; it will depend on what I learn implementing
TrustyKeymasterContext and HybridKeymasterContext (used for the
keymaster0 adapter).
5. Look at ocb_utils and auth_encrypted_key_blob. These contain the key
encryption and key blob serialization code which was formerly split
between AndroidKeymaster::SerializeKeyBlob, UnencryptedKeyBlob and
KeyBlob, now divided into separate encryption and serialization
utilities. Note the refactored key_blob_test.cpp, updated to use the
new utilities rather than UnencryptedKeyBlob.
6. Look at soft_keymaster_device.cpp. Since KeyBlob no longer exists to
provide a nice way to peer into a blob to extract the algorithm, for use
in determining how to parse the keymaster0 signing key params (which
come in as a void*, yuck), we now have to use get_key_characteristics to
recover the params. This was the right way all along; the device layer
should not depend on being able to parse key blobs.
7. The rest.
Bug: 20912868, 19799085
Change-Id: Ieb74b8da39974f674eb8baa959bde75011fdd2e8
Diffstat (limited to 'rsa_key.cpp')
-rw-r--r-- | rsa_key.cpp | 127 |
1 files changed, 59 insertions, 68 deletions
diff --git a/rsa_key.cpp b/rsa_key.cpp index 5150588..293d51e 100644 --- a/rsa_key.cpp +++ b/rsa_key.cpp @@ -16,10 +16,10 @@ #include "rsa_key.h" +#include <keymaster/keymaster_context.h> + #include "openssl_err.h" #include "openssl_utils.h" -#include "rsa_operation.h" -#include "unencrypted_key_blob.h" #if defined(OPENSSL_IS_BORINGSSL) typedef size_t openssl_size_t; @@ -29,66 +29,67 @@ typedef int openssl_size_t; namespace keymaster { -Key* RsaKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) { - return new RsaKey(blob, error); -} - -Key* RsaKeyFactory::GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) { - if (!error) - return NULL; +keymaster_error_t RsaKeyFactory::GenerateKey(const AuthorizationSet& key_description, + KeymasterKeyBlob* key_blob, + AuthorizationSet* hw_enforced, + AuthorizationSet* sw_enforced) { + if (!key_blob || !hw_enforced || !sw_enforced) + return KM_ERROR_OUTPUT_PARAMETER_NULL; AuthorizationSet authorizations(key_description); uint64_t public_exponent; if (!authorizations.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &public_exponent)) { LOG_E("%s", "No public exponent specified for RSA key generation"); - *error = KM_ERROR_INVALID_ARGUMENT; - return NULL; + return KM_ERROR_INVALID_ARGUMENT; } uint32_t key_size; if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) { LOG_E("%s", "No key size specified for RSA key generation"); - *error = KM_ERROR_UNSUPPORTED_KEY_SIZE; - return NULL; + return KM_ERROR_UNSUPPORTED_KEY_SIZE; } UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new()); UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(RSA_new()); UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new()); - if (exponent.get() == NULL || rsa_key.get() == NULL || pkey.get() == NULL) { - *error = KM_ERROR_MEMORY_ALLOCATION_FAILED; - return NULL; - } + if (exponent.get() == NULL || rsa_key.get() == NULL || pkey.get() == NULL) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; if (!BN_set_word(exponent.get(), public_exponent) || - !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */)) { - *error = TranslateLastOpenSslError(); - return NULL; - } + !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */)) + return TranslateLastOpenSslError(); - RsaKey* new_key = new RsaKey(rsa_key.release(), authorizations); - *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED; - return new_key; -} + if (EVP_PKEY_set1_RSA(pkey.get(), rsa_key.get()) != 1) + return TranslateLastOpenSslError(); -Key* RsaKeyFactory::ImportKey(const AuthorizationSet& key_description, - keymaster_key_format_t key_format, const uint8_t* key_data, - size_t key_data_length, keymaster_error_t* error) { - if (!error) - return NULL; + KeymasterKeyBlob key_material; + keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material); + if (error != KM_ERROR_OK) + return error; - UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey( - ExtractEvpKey(key_format, KM_ALGORITHM_RSA, key_data, key_data_length, error)); - if (*error != KM_ERROR_OK) - return NULL; - assert(pkey.get()); + return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob, + hw_enforced, sw_enforced); +} + +keymaster_error_t RsaKeyFactory::ImportKey(const AuthorizationSet& key_description, + keymaster_key_format_t input_key_material_format, + const KeymasterKeyBlob& input_key_material, + KeymasterKeyBlob* output_key_blob, + AuthorizationSet* hw_enforced, + AuthorizationSet* sw_enforced) { + if (!output_key_blob || !hw_enforced || !sw_enforced) + return KM_ERROR_OUTPUT_PARAMETER_NULL; + + UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey; + keymaster_error_t error = + KeyMaterialToEvpKey(input_key_material_format, input_key_material, &pkey); + if (error != KM_ERROR_OK) + return error; UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(EVP_PKEY_get1_RSA(pkey.get())); - if (!rsa_key.get()) { - *error = TranslateLastOpenSslError(); - return NULL; - } + if (!rsa_key.get()) + return TranslateLastOpenSslError(); AuthorizationSet authorizations(key_description); @@ -97,28 +98,22 @@ Key* RsaKeyFactory::ImportKey(const AuthorizationSet& key_description, // public_exponent specified, make sure it matches the key UniquePtr<BIGNUM, BIGNUM_Delete> public_exponent_bn(BN_new()); if (!BN_set_word(public_exponent_bn.get(), public_exponent)) - return NULL; - if (BN_cmp(public_exponent_bn.get(), rsa_key->e) != 0) { - *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH; - return NULL; - } + return KM_ERROR_UNKNOWN_ERROR; + if (BN_cmp(public_exponent_bn.get(), rsa_key->e) != 0) + return KM_ERROR_IMPORT_PARAMETER_MISMATCH; } else { // public_exponent not specified, use the one from the key. public_exponent = BN_get_word(rsa_key->e); - if (public_exponent == 0xffffffffL) { - *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH; - return NULL; - } + if (public_exponent == 0xffffffffL) + return KM_ERROR_IMPORT_PARAMETER_MISMATCH; authorizations.push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent); } uint32_t key_size; if (authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) { // key_size specified, make sure it matches the key. - if (RSA_size(rsa_key.get()) * 8 != (openssl_size_t)key_size) { - *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH; - return NULL; - } + if (RSA_size(rsa_key.get()) * 8 != (openssl_size_t)key_size) + return KM_ERROR_IMPORT_PARAMETER_MISMATCH; } else { key_size = RSA_size(rsa_key.get()) * 8; authorizations.push_back(TAG_KEY_SIZE, key_size); @@ -126,28 +121,24 @@ Key* RsaKeyFactory::ImportKey(const AuthorizationSet& key_description, keymaster_algorithm_t algorithm; if (authorizations.GetTagValue(TAG_ALGORITHM, &algorithm)) { - if (algorithm != KM_ALGORITHM_RSA) { - *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH; - return NULL; - } + if (algorithm != KM_ALGORITHM_RSA) + return KM_ERROR_IMPORT_PARAMETER_MISMATCH; } else { authorizations.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA); } - // Don't bother with the other parameters. If the necessary padding, digest, purpose, etc. are - // missing, the error will be diagnosed when the key is used (when auth checking is - // implemented). - *error = KM_ERROR_OK; - return new RsaKey(rsa_key.release(), authorizations); -} - -RsaKey::RsaKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : AsymmetricKey(blob) { - if (error) - *error = LoadKey(blob); + return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material, + output_key_blob, hw_enforced, sw_enforced); } -RSA* RsaKey::key() const { - return rsa_key_.get(); +keymaster_error_t RsaKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced, + const AuthorizationSet& sw_enforced, + UniquePtr<AsymmetricKey>* key) { + keymaster_error_t error; + key->reset(new RsaKey(hw_enforced, sw_enforced, &error)); + if (!key->get()) + error = KM_ERROR_MEMORY_ALLOCATION_FAILED; + return error; } bool RsaKey::EvpToInternal(const EVP_PKEY* pkey) { |