/* * Copyright 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using std::unique_ptr; namespace keymaster { namespace { KeymasterBlob string2Blob(const std::string& str) { return KeymasterBlob(reinterpret_cast(str.data()), str.size()); } } // anonymous namespace SoftKeymasterContext::SoftKeymasterContext(KmVersion version, const std::string& root_of_trust) : SoftAttestationContext(version), // rsa_factory_(new RsaKeyFactory(*this /* blob_maker */, *this /* context */)), ec_factory_(new EcKeyFactory(*this /* blob_maker */, *this /* context */)), aes_factory_(new AesKeyFactory(*this /* blob_maker */, *this /* random_source */)), tdes_factory_(new TripleDesKeyFactory(*this /* blob_maker */, *this /* random_source */)), hmac_factory_(new HmacKeyFactory(*this /* blob_maker */, *this /* random_source */)), km1_dev_(nullptr), root_of_trust_(string2Blob(root_of_trust)), os_version_(0), os_patchlevel_(0) {} SoftKeymasterContext::~SoftKeymasterContext() {} keymaster_error_t SoftKeymasterContext::SetHardwareDevice(keymaster1_device_t* keymaster1_device) { if (!keymaster1_device) return KM_ERROR_UNEXPECTED_NULL_POINTER; km1_dev_ = keymaster1_device; km1_engine_.reset(new Keymaster1Engine(keymaster1_device)); rsa_factory_.reset(new RsaKeymaster1KeyFactory( *this /* blob_maker */, *this /* attestation_context */, km1_engine_.get())); ec_factory_.reset(new EcdsaKeymaster1KeyFactory( *this /* blob_maker */, *this /* attestation_context */, km1_engine_.get())); // Use default HMAC and AES key factories. Higher layers will pass HMAC/AES keys/ops that are // supported by the hardware to it and other ones to the software-only factory. return KM_ERROR_OK; } keymaster_error_t SoftKeymasterContext::SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel) { os_version_ = os_version; os_patchlevel_ = os_patchlevel; return KM_ERROR_OK; } void SoftKeymasterContext::GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const { *os_version = os_version_; *os_patchlevel = os_patchlevel_; } KeyFactory* SoftKeymasterContext::GetKeyFactory(keymaster_algorithm_t algorithm) const { switch (algorithm) { case KM_ALGORITHM_RSA: return rsa_factory_.get(); case KM_ALGORITHM_EC: return ec_factory_.get(); case KM_ALGORITHM_AES: return aes_factory_.get(); case KM_ALGORITHM_TRIPLE_DES: return tdes_factory_.get(); case KM_ALGORITHM_HMAC: return hmac_factory_.get(); default: return nullptr; } } static keymaster_algorithm_t supported_algorithms[] = {KM_ALGORITHM_RSA, KM_ALGORITHM_EC, KM_ALGORITHM_AES, KM_ALGORITHM_HMAC}; keymaster_algorithm_t* SoftKeymasterContext::GetSupportedAlgorithms(size_t* algorithms_count) const { *algorithms_count = array_length(supported_algorithms); return supported_algorithms; } OperationFactory* SoftKeymasterContext::GetOperationFactory(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose) const { KeyFactory* key_factory = GetKeyFactory(algorithm); if (!key_factory) return nullptr; return key_factory->GetOperationFactory(purpose); } static keymaster_error_t TranslateAuthorizationSetError(AuthorizationSet::Error err) { switch (err) { case AuthorizationSet::OK: return KM_ERROR_OK; case AuthorizationSet::ALLOCATION_FAILURE: return KM_ERROR_MEMORY_ALLOCATION_FAILED; case AuthorizationSet::MALFORMED_DATA: return KM_ERROR_UNKNOWN_ERROR; } return KM_ERROR_OK; } static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description, keymaster_key_origin_t origin, uint32_t os_version, uint32_t os_patchlevel, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) { sw_enforced->Clear(); 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: LOG_E("Root of trust and origin tags may not be specified", 0); return KM_ERROR_INVALID_TAG; // These don't work. case KM_TAG_ROLLBACK_RESISTANT: LOG_E("KM_TAG_ROLLBACK_RESISTANT not supported", 0); return KM_ERROR_UNSUPPORTED_TAG; // These are hidden. case KM_TAG_APPLICATION_ID: case KM_TAG_APPLICATION_DATA: break; // 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: if (hw_enforced->GetTagCount(entry.tag) == 0) sw_enforced->push_back(entry); break; } } sw_enforced->push_back(TAG_CREATION_DATETIME, java_time(time(nullptr))); sw_enforced->push_back(TAG_ORIGIN, origin); sw_enforced->push_back(TAG_OS_VERSION, os_version); sw_enforced->push_back(TAG_OS_PATCHLEVEL, os_patchlevel); return TranslateAuthorizationSetError(sw_enforced->is_valid()); } keymaster_error_t SoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& key_description, const keymaster_key_origin_t origin, const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const { keymaster_error_t error = SetAuthorizations(key_description, origin, os_version_, os_patchlevel_, hw_enforced, sw_enforced); if (error != KM_ERROR_OK) return error; AuthorizationSet hidden; error = BuildHiddenAuthorizations(key_description, &hidden, root_of_trust_); if (error != KM_ERROR_OK) return error; return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob); } keymaster_error_t SoftKeymasterContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade, const AuthorizationSet& upgrade_params, KeymasterKeyBlob* upgraded_key) const { UniquePtr key; keymaster_error_t error = ParseKeyBlob(key_to_upgrade, upgrade_params, &key); if (error != KM_ERROR_OK) return error; // Three cases here: // // 1. Software key blob. Version info, if present, is in sw_enforced. If not present, we // should add it. // // 2. Keymaster0 hardware key blob. Version info, if present, is in sw_enforced. If not // present we should add it. // // 3. Keymaster1 hardware key blob. Version info is not present and we shouldn't have been // asked to upgrade. // Handle case 3. if (km1_dev_ && key->hw_enforced().Contains(TAG_PURPOSE) && !key->hw_enforced().Contains(TAG_OS_PATCHLEVEL)) return KM_ERROR_INVALID_ARGUMENT; // Handle case 1 and 2 return UpgradeSoftKeyBlob(key, os_version_, os_patchlevel_, upgrade_params, upgraded_key); } keymaster_error_t SoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params, UniquePtr* key) const { // 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. Keymaster1 hardware key blobs. These are raw hardware key blobs. They contain auth // sets, which we retrieve from the hardware module. // // 6. 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 hw_enforced; AuthorizationSet sw_enforced; KeymasterKeyBlob key_material; AuthorizationSet hidden; keymaster_error_t error; auto constructKey = [&, this]() mutable -> keymaster_error_t { // GetKeyFactory if (error != KM_ERROR_OK) return error; keymaster_algorithm_t algorithm; if (!hw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm) && !sw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) { return KM_ERROR_INVALID_ARGUMENT; } auto factory = GetKeyFactory(algorithm); return factory->LoadKey(move(key_material), additional_params, move(hw_enforced), move(sw_enforced), key); }; error = BuildHiddenAuthorizations(additional_params, &hidden, root_of_trust_); if (error != KM_ERROR_OK) return error; // 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 constructKey(); // Wasn't an integrity-assured blob. Maybe it's an Auth-encrypted blob. error = ParseAuthEncryptedBlob(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 constructKey(); // 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 constructKey(); if (km1_dev_) { error = ParseKeymaster1HwBlob(blob, additional_params, &key_material, &hw_enforced, &sw_enforced); } else { return KM_ERROR_INVALID_KEY_BLOB; } return constructKey(); } keymaster_error_t SoftKeymasterContext::DeleteKey(const KeymasterKeyBlob& blob) const { if (km1_engine_) { // HACK. Due to a bug with Qualcomm's Keymaster implementation, which causes the device to // reboot if we pass it a key blob it doesn't understand, we need to check for software // keys. If it looks like a software key there's nothing to do so we just return. KeymasterKeyBlob key_material; AuthorizationSet hw_enforced, sw_enforced; keymaster_error_t error = DeserializeIntegrityAssuredBlob_NoHmacCheck( blob, &key_material, &hw_enforced, &sw_enforced); if (error == KM_ERROR_OK) { return KM_ERROR_OK; } return km1_engine_->DeleteKey(blob); } // Nothing to do for software-only contexts. return KM_ERROR_OK; } keymaster_error_t SoftKeymasterContext::DeleteAllKeys() const { if (km1_engine_) return km1_engine_->DeleteAllKeys(); return KM_ERROR_OK; } keymaster_error_t SoftKeymasterContext::AddRngEntropy(const uint8_t* buf, size_t length) const { RAND_add(buf, length, 0 /* Don't assume any entropy is added to the pool. */); return KM_ERROR_OK; } keymaster_error_t SoftKeymasterContext::ParseKeymaster1HwBlob( const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params, KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const { assert(km1_dev_); keymaster_blob_t client_id = {nullptr, 0}; keymaster_blob_t app_data = {nullptr, 0}; keymaster_blob_t* client_id_ptr = nullptr; keymaster_blob_t* app_data_ptr = nullptr; if (additional_params.GetTagValue(TAG_APPLICATION_ID, &client_id)) client_id_ptr = &client_id; if (additional_params.GetTagValue(TAG_APPLICATION_DATA, &app_data)) app_data_ptr = &app_data; // Get key characteristics, which incidentally verifies that the HW recognizes the key. keymaster_key_characteristics_t* characteristics; keymaster_error_t error = km1_dev_->get_key_characteristics(km1_dev_, &blob, client_id_ptr, app_data_ptr, &characteristics); if (error != KM_ERROR_OK) return error; unique_ptr characteristics_deleter( characteristics); LOG_D("Module \"%s\" accepted key", km1_dev_->common.module->name); hw_enforced->Reinitialize(characteristics->hw_enforced); sw_enforced->Reinitialize(characteristics->sw_enforced); *key_material = blob; return KM_ERROR_OK; } CertificateChain SoftKeymasterContext::GenerateAttestation(const Key& key, // const AuthorizationSet& attest_params, UniquePtr /* attest_key */, const KeymasterBlob& /* issuer_subject */, // keymaster_error_t* error) const { keymaster_algorithm_t key_algorithm; if (!key.authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) { *error = KM_ERROR_UNKNOWN_ERROR; return {}; } if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) { *error = KM_ERROR_INCOMPATIBLE_ALGORITHM; return {}; } // We have established that the given key has the correct algorithm, and because this is the // SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast. const AsymmetricKey& asymmetric_key = static_cast(key); return generate_attestation(asymmetric_key, attest_params, {} /* attest_key */, *this, error); } CertificateChain SoftKeymasterContext::GenerateSelfSignedCertificate( const Key& key, const AuthorizationSet& cert_params, bool fake_signature, keymaster_error_t* error) const { keymaster_algorithm_t key_algorithm; if (!key.authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) { *error = KM_ERROR_UNKNOWN_ERROR; return {}; } if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) { *error = KM_ERROR_INCOMPATIBLE_ALGORITHM; return {}; } // We have established that the given key has the correct algorithm, and because this is the // SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast. const AsymmetricKey& asymmetric_key = static_cast(key); return generate_self_signed_cert(asymmetric_key, cert_params, fake_signature, error); } keymaster_error_t SoftKeymasterContext::UnwrapKey(const KeymasterKeyBlob&, const KeymasterKeyBlob&, const AuthorizationSet&, const KeymasterKeyBlob&, AuthorizationSet*, keymaster_key_format_t*, KeymasterKeyBlob*) const { return KM_ERROR_UNIMPLEMENTED; } } // namespace keymaster