diff options
author | Shawn Willden <swillden@google.com> | 2015-05-20 16:36:24 -0600 |
---|---|---|
committer | Shawn Willden <swillden@google.com> | 2015-05-28 07:28:51 -0600 |
commit | 2beb628bfefae72fa6bb84a6235da7e3de532823 (patch) | |
tree | 53fdd19f54afc714b37505cbea0dc31e1ecadda9 /soft_keymaster_context.cpp | |
parent | de7e66c3692073eb967f01cc8281441709701e2d (diff) | |
download | keymaster-2beb628bfefae72fa6bb84a6235da7e3de532823.tar.gz |
Delegate RSA keys to keymaster0 in SoftKeymasterDevice.
Bug: 20912868
Change-Id: I515a125f1247357d2cd9b4633c3b223590848093
Diffstat (limited to 'soft_keymaster_context.cpp')
-rw-r--r-- | soft_keymaster_context.cpp | 230 |
1 files changed, 197 insertions, 33 deletions
diff --git a/soft_keymaster_context.cpp b/soft_keymaster_context.cpp index 0745a5e..8469925 100644 --- a/soft_keymaster_context.cpp +++ b/soft_keymaster_context.cpp @@ -16,6 +16,7 @@ #include <keymaster/soft_keymaster_context.h> +#include <memory> #include <time.h> #include <openssl/aes.h> @@ -29,9 +30,13 @@ #include "auth_encrypted_key_blob.h" #include "ec_key.h" #include "hmac_key.h" +#include "keymaster0_engine.h" #include "ocb_utils.h" #include "openssl_err.h" -#include "rsa_key.h" +#include "rsa_keymaster0_key.h" +#include "integrity_assured_key_blob.h" + +using std::unique_ptr; namespace keymaster { @@ -44,17 +49,19 @@ const KeymasterKeyBlob MASTER_KEY(master_key_bytes, array_length(master_key_byte class SoftKeymasterKeyRegistrations { public: - SoftKeymasterKeyRegistrations(const KeymasterContext* context) - : rsa_(context), ec_(context), hmac_(context), aes_(context) {} + SoftKeymasterKeyRegistrations(SoftKeymasterContext* context, Keymaster0Engine* engine) + : rsa_(context, engine), ec_(context), hmac_(context), aes_(context) {} - KeyFactoryRegistry::Registration<RsaKeyFactory> rsa_; + KeyFactoryRegistry::Registration<RsaKeymaster0KeyFactory> rsa_; KeyFactoryRegistry::Registration<EcdsaKeyFactory> ec_; KeyFactoryRegistry::Registration<HmacKeyFactory> hmac_; KeyFactoryRegistry::Registration<AesKeyFactory> aes_; }; -SoftKeymasterContext::SoftKeymasterContext() - : registrations_(new SoftKeymasterKeyRegistrations(this)) { +SoftKeymasterContext::SoftKeymasterContext(keymaster0_device_t* keymaster0_device) { + if (keymaster0_device && (keymaster0_device->flags & KEYMASTER_SOFTWARE_ONLY) == 0) + engine_.reset(new Keymaster0Engine(keymaster0_device)); + registrations_.reset(new SoftKeymasterKeyRegistrations(this, engine_.get())); } static keymaster_error_t TranslateAuthorizationSetError(AuthorizationSet::Error err) { @@ -90,10 +97,10 @@ static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_descripti keymaster_key_origin_t origin, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) { - hw_enforced->Clear(); sw_enforced->Clear(); - for (size_t i = 0; i < key_description.size(); ++i) { - switch (key_description[i].tag) { + + for (auto& entry : key_description) { + switch (entry.tag) { // These cannot be specified by the client. case KM_TAG_ROOT_OF_TRUST: case KM_TAG_ORIGIN: @@ -110,9 +117,11 @@ static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_descripti case KM_TAG_APPLICATION_DATA: break; - // Everything else we just copy into sw_enforced. + // Everything else we just copy into sw_enforced, unless the KeyFactory has placed it in + // hw_enforced, in which case we defer to its decision. default: - sw_enforced->push_back(key_description[i]); + if (hw_enforced->GetTagCount(entry.tag) == 0) + sw_enforced->push_back(entry); break; } } @@ -129,9 +138,7 @@ keymaster_error_t SoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& ke AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const { - keymaster_error_t error; - - error = SetAuthorizations(key_description, origin, hw_enforced, sw_enforced); + keymaster_error_t error = SetAuthorizations(key_description, origin, hw_enforced, sw_enforced); if (error != KM_ERROR_OK) return error; @@ -140,20 +147,129 @@ keymaster_error_t SoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& ke if (error != KM_ERROR_OK) return error; + return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob); +} + +static keymaster_error_t ParseOcbAuthEncryptedBlob(const KeymasterKeyBlob& blob, + const AuthorizationSet& hidden, + KeymasterKeyBlob* key_material, + AuthorizationSet* hw_enforced, + AuthorizationSet* sw_enforced) { Buffer nonce, tag; - if (!nonce.reserve(OCB_NONCE_LENGTH) || !tag.reserve(OCB_TAG_LENGTH)) + KeymasterKeyBlob encrypted_key_material; + keymaster_error_t error = DeserializeAuthEncryptedBlob(blob, &encrypted_key_material, + hw_enforced, sw_enforced, &nonce, &tag); + if (error != KM_ERROR_OK) + return error; + + if (nonce.available_read() != OCB_NONCE_LENGTH || tag.available_read() != OCB_TAG_LENGTH) + return KM_ERROR_INVALID_KEY_BLOB; + + return OcbDecryptKey(*hw_enforced, *sw_enforced, hidden, MASTER_KEY, encrypted_key_material, + nonce, tag, key_material); +} + +// Note: This parsing code in below is from system/security/softkeymaster/keymaster_openssl.cpp's +// unwrap_key function, modified for the preferred function signature and formatting. It does some +// odd things, but they have been left unchanged to avoid breaking compatibility. +static const uint8_t SOFT_KEY_MAGIC[] = {'P', 'K', '#', '8'}; +const uint64_t HUNDRED_YEARS = 1000LL * 60 * 60 * 24 * 365 * 100; +static keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob, + KeymasterKeyBlob* key_material, + AuthorizationSet* hw_enforced, + AuthorizationSet* sw_enforced) { + long publicLen = 0; + long privateLen = 0; + const uint8_t* p = blob.key_material; + const uint8_t* end = blob.key_material + blob.key_material_size; + + int type = 0; + ptrdiff_t min_size = + sizeof(SOFT_KEY_MAGIC) + sizeof(type) + sizeof(publicLen) + 1 + sizeof(privateLen) + 1; + if (end - p < min_size) { + LOG_W("key blob appears to be truncated (if an old SW key)", 0); + return KM_ERROR_INVALID_KEY_BLOB; + } + + if (memcmp(p, SOFT_KEY_MAGIC, sizeof(SOFT_KEY_MAGIC)) != 0) + return KM_ERROR_INVALID_KEY_BLOB; + p += sizeof(SOFT_KEY_MAGIC); + + for (size_t i = 0; i < sizeof(type); i++) + type = (type << 8) | *p++; + + for (size_t i = 0; i < sizeof(type); i++) + publicLen = (publicLen << 8) | *p++; + + if (p + publicLen > end) { + LOG_W("public key length encoding error: size=%ld, end=%td", publicLen, end - p); + return KM_ERROR_INVALID_KEY_BLOB; + } + p += publicLen; + + if (end - p < 2) { + LOG_W("key blob appears to be truncated (if an old SW key)", 0); + return KM_ERROR_INVALID_KEY_BLOB; + } + + for (size_t i = 0; i < sizeof(type); i++) + privateLen = (privateLen << 8) | *p++; + + if (p + privateLen > end) { + LOG_W("private key length encoding error: size=%ld, end=%td", privateLen, end - p); + return KM_ERROR_INVALID_KEY_BLOB; + } + + // Just to be sure, make sure that the ASN.1 structure parses correctly. We don't actually use + // the EVP_PKEY here. + unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new()); + if (pkey.get() == nullptr) return KM_ERROR_MEMORY_ALLOCATION_FAILED; - GenerateRandom(nonce.peek_write(), OCB_NONCE_LENGTH); - nonce.advance_write(OCB_NONCE_LENGTH); + EVP_PKEY* tmp = pkey.get(); + const uint8_t* key_start = p; + if (d2i_PrivateKey(type, &tmp, &p, privateLen) == NULL) { + LOG_W("Failed to parse PKCS#8 key material (if old SW key)", 0); + return KM_ERROR_INVALID_KEY_BLOB; + } - KeymasterKeyBlob encrypted_key; - error = OcbEncryptKey(*hw_enforced, *sw_enforced, hidden, MASTER_KEY, key_material, nonce, - &encrypted_key, &tag); - if (error != KM_ERROR_OK) - return error; + if (!key_material->Reset(privateLen)) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + memcpy(key_material->writable_data(), key_start, privateLen); + + hw_enforced->Clear(); + sw_enforced->Clear(); - return SerializeAuthEncryptedBlob(encrypted_key, *hw_enforced, *sw_enforced, nonce, tag, blob); + switch (type) { + case EVP_PKEY_RSA: + sw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA); + sw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE); + sw_enforced->push_back(TAG_PADDING, KM_PAD_NONE); + break; + + case EVP_PKEY_EC: + sw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA); + sw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE); + break; + + case EVP_PKEY_DSA: + return KM_ERROR_UNSUPPORTED_ALGORITHM; + + default: + return KM_ERROR_INVALID_KEY_BLOB; + } + + sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN); + sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY); + sw_enforced->push_back(TAG_ALL_USERS); + sw_enforced->push_back(TAG_NO_AUTH_REQUIRED); + uint64_t now = java_time(time(NULL)); + sw_enforced->push_back(TAG_CREATION_DATETIME, now); + sw_enforced->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, now + HUNDRED_YEARS); + sw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE); + sw_enforced->push_back(TAG_PADDING, KM_PAD_NONE); + + return KM_ERROR_OK; } keymaster_error_t SoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob, @@ -161,23 +277,71 @@ keymaster_error_t SoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blo KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const { - Buffer nonce, tag; - KeymasterKeyBlob encrypted_key_material; - keymaster_error_t error = DeserializeAuthEncryptedBlob(blob, &encrypted_key_material, - hw_enforced, sw_enforced, &nonce, &tag); - if (error != KM_ERROR_OK) - return error; + // This is a little bit complicated. + // + // The SoftKeymasterContext has to handle a lot of different kinds of key blobs. + // + // 1. New keymaster1 software key blobs. These are integrity-assured but not encrypted. The + // raw key material and auth sets should be extracted and returned. This is the kind + // produced by this context when the KeyFactory doesn't use keymaster0 to back the keys. + // + // 2. Old keymaster1 software key blobs. These are OCB-encrypted with an all-zero master key. + // They should be decrypted and the key material and auth sets extracted and returned. + // + // 3. Old keymaster0 software key blobs. These are raw key material with a small header tacked + // on the front. They don't have auth sets, so reasonable defaults are generated and + // returned along with the raw key material. + // + // 4. New keymaster0 hardware key blobs. These are integrity-assured but not encrypted (though + // they're protected by the keymaster0 hardware implementation). The keymaster0 key blob + // and auth sets should be extracted and returned. + // + // 5. Old keymaster0 hardware key blobs. These are raw hardware key blobs. They don't have + // auth sets so reasonable defaults are generated and returned along with the key blob. + // + // Determining what kind of blob has arrived is somewhat tricky. What helps is that + // integrity-assured and OCB-encrypted blobs are self-consistent and effectively impossible to + // parse as anything else. Old keymaster0 software key blobs have a header. It's reasonably + // unlikely that hardware keys would have the same header. So anything that is neither + // integrity-assured nor OCB-encrypted and lacks the old software key header is assumed to be + // keymaster0 hardware. AuthorizationSet hidden; - error = BuildHiddenAuthorizations(additional_params, &hidden); + keymaster_error_t error = BuildHiddenAuthorizations(additional_params, &hidden); if (error != KM_ERROR_OK) return error; - if (nonce.available_read() != OCB_NONCE_LENGTH || tag.available_read() != OCB_TAG_LENGTH) + // Assume it's an integrity-assured blob (new software-only blob, or new keymaster0-backed + // blob). + error = DeserializeIntegrityAssuredBlob(blob, hidden, key_material, hw_enforced, sw_enforced); + if (error != KM_ERROR_INVALID_KEY_BLOB) + return error; + + // Wasn't an integrity-assured blob. Maybe it's an OCB-encrypted blob. + error = ParseOcbAuthEncryptedBlob(blob, hidden, key_material, hw_enforced, sw_enforced); + if (error == KM_ERROR_OK) + LOG_D("Parsed an old keymaster1 software key", 0); + if (error != KM_ERROR_INVALID_KEY_BLOB) + return error; + + // Wasn't an OCB-encrypted blob. Maybe it's an old softkeymaster blob. + error = ParseOldSoftkeymasterBlob(blob, key_material, hw_enforced, sw_enforced); + if (error == KM_ERROR_OK) + LOG_D("Parsed an old sofkeymaster key", 0); + if (error != KM_ERROR_INVALID_KEY_BLOB) + return error; + + // Not an old softkeymaster blob, either. The only remaining option is old HW keymaster0. + if (!engine_) return KM_ERROR_INVALID_KEY_BLOB; - return OcbDecryptKey(*hw_enforced, *sw_enforced, hidden, MASTER_KEY, encrypted_key_material, - nonce, tag, key_material); + // See if the HW thinks it's valid. + unique_ptr<EVP_PKEY, EVP_PKEY_Delete> tmp_key(engine_->GetKeymaster0PublicKey(blob)); + if (!tmp_key) + return KM_ERROR_INVALID_KEY_BLOB; + + *key_material = blob; + return KM_ERROR_OK; } keymaster_error_t SoftKeymasterContext::AddRngEntropy(const uint8_t* buf, size_t length) const { |