/* * 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 #include #include #include #include #include #include #include #include using std::unique_ptr; namespace keymaster { PureSoftKeymasterContext::PureSoftKeymasterContext(keymaster_security_level_t security_level) : rsa_factory_(new RsaKeyFactory(this)), ec_factory_(new EcKeyFactory(this)), aes_factory_(new AesKeyFactory(this, this)), tdes_factory_(new TripleDesKeyFactory(this, this)), hmac_factory_(new HmacKeyFactory(this, this)), os_version_(0), os_patchlevel_(0), soft_keymaster_enforcement_(64, 64), security_level_(security_level) {} PureSoftKeymasterContext::~PureSoftKeymasterContext() {} keymaster_error_t PureSoftKeymasterContext::SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel) { os_version_ = os_version; os_patchlevel_ = os_patchlevel; return KM_ERROR_OK; } void PureSoftKeymasterContext::GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const { *os_version = os_version_; *os_patchlevel = os_patchlevel_; } KeyFactory* PureSoftKeymasterContext::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* PureSoftKeymasterContext::GetSupportedAlgorithms(size_t* algorithms_count) const { *algorithms_count = array_length(supported_algorithms); return supported_algorithms; } OperationFactory* PureSoftKeymasterContext::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); } keymaster_error_t PureSoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& key_description, const keymaster_key_origin_t origin, const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const { if (key_description.GetTagValue(TAG_ROLLBACK_RESISTANCE)) { return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE; } if (GetSecurityLevel() != KM_SECURITY_LEVEL_SOFTWARE) { // We're pretending to be some sort of secure hardware. Put relevant tags in hw_enforced. for (auto& entry : key_description) { switch (entry.tag) { case KM_TAG_PURPOSE: case KM_TAG_ALGORITHM: case KM_TAG_KEY_SIZE: case KM_TAG_RSA_PUBLIC_EXPONENT: case KM_TAG_BLOB_USAGE_REQUIREMENTS: case KM_TAG_DIGEST: case KM_TAG_PADDING: case KM_TAG_BLOCK_MODE: case KM_TAG_MIN_SECONDS_BETWEEN_OPS: case KM_TAG_MAX_USES_PER_BOOT: case KM_TAG_USER_SECURE_ID: case KM_TAG_NO_AUTH_REQUIRED: case KM_TAG_AUTH_TIMEOUT: case KM_TAG_CALLER_NONCE: case KM_TAG_MIN_MAC_LENGTH: case KM_TAG_KDF: case KM_TAG_EC_CURVE: case KM_TAG_ECIES_SINGLE_HASH_MODE: case KM_TAG_USER_AUTH_TYPE: case KM_TAG_ORIGIN: case KM_TAG_OS_VERSION: case KM_TAG_OS_PATCHLEVEL: case KM_TAG_EARLY_BOOT_ONLY: case KM_TAG_UNLOCKED_DEVICE_REQUIRED: hw_enforced->push_back(entry); break; default: break; } } } keymaster_error_t error = SetKeyBlobAuthorizations(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, softwareRootOfTrust); if (error != KM_ERROR_OK) return error; return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob); } keymaster_error_t PureSoftKeymasterContext::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; return UpgradeSoftKeyBlob(key, os_version_, os_patchlevel_, upgrade_params, upgraded_key); } keymaster_error_t PureSoftKeymasterContext::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. // // 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; 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); }; AuthorizationSet hidden; error = BuildHiddenAuthorizations(additional_params, &hidden, softwareRootOfTrust); 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 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 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); return constructKey(); } keymaster_error_t PureSoftKeymasterContext::DeleteKey(const KeymasterKeyBlob& /* blob */) const { // Nothing to do for software-only contexts. return KM_ERROR_OK; } keymaster_error_t PureSoftKeymasterContext::DeleteAllKeys() const { return KM_ERROR_OK; } keymaster_error_t PureSoftKeymasterContext::AddRngEntropy(const uint8_t* buf, size_t length) const { // XXX TODO according to boringssl openssl/rand.h RAND_add is deprecated and does // nothing RAND_add(buf, length, 0 /* Don't assume any entropy is added to the pool. */); return KM_ERROR_OK; } keymaster_error_t PureSoftKeymasterContext::GenerateAttestation(const Key& key, const AuthorizationSet& attest_params, CertChainPtr* cert_chain) const { keymaster_error_t error = KM_ERROR_OK; keymaster_algorithm_t key_algorithm; if (!key.authorizations().GetTagValue(TAG_ALGORITHM, &key_algorithm)) { return KM_ERROR_UNKNOWN_ERROR; } if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) return KM_ERROR_INCOMPATIBLE_ALGORITHM; // 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); auto attestation_chain = getAttestationChain(key_algorithm, &error); if (error != KM_ERROR_OK) return error; auto attestation_key = getAttestationKey(key_algorithm, &error); if (error != KM_ERROR_OK) return error; return generate_attestation(asymmetric_key, attest_params, *attestation_chain, *attestation_key, *this, cert_chain); } 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; } keymaster_error_t PureSoftKeymasterContext::UnwrapKey( const KeymasterKeyBlob& wrapped_key_blob, const KeymasterKeyBlob& wrapping_key_blob, const AuthorizationSet& /* wrapping_key_params */, const KeymasterKeyBlob& masking_key, AuthorizationSet* wrapped_key_params, keymaster_key_format_t* wrapped_key_format, KeymasterKeyBlob* wrapped_key_material) const { keymaster_error_t error = KM_ERROR_OK; if (!wrapped_key_material) return KM_ERROR_UNEXPECTED_NULL_POINTER; // Parse wrapped key data KeymasterBlob iv; KeymasterKeyBlob transit_key; KeymasterKeyBlob secure_key; KeymasterBlob tag; KeymasterBlob wrapped_key_description; error = parse_wrapped_key(wrapped_key_blob, &iv, &transit_key, &secure_key, &tag, wrapped_key_params, wrapped_key_format, &wrapped_key_description); if (error != KM_ERROR_OK) return error; UniquePtr key; auto wrapping_key_params = AuthorizationSetBuilder() .RsaEncryptionKey(2048, 65537) .Digest(KM_DIGEST_SHA_2_256) .Padding(KM_PAD_RSA_OAEP) .Authorization(TAG_PURPOSE, KM_PURPOSE_WRAP) .build(); error = ParseKeyBlob(wrapping_key_blob, wrapping_key_params, &key); if (error != KM_ERROR_OK) return error; // Ensure the wrapping key has the right purpose if (!key->hw_enforced().Contains(TAG_PURPOSE, KM_PURPOSE_WRAP) && !key->sw_enforced().Contains(TAG_PURPOSE, KM_PURPOSE_WRAP)) { return KM_ERROR_INCOMPATIBLE_PURPOSE; } auto operation_factory = GetOperationFactory(KM_ALGORITHM_RSA, KM_PURPOSE_DECRYPT); if (!operation_factory) return KM_ERROR_UNKNOWN_ERROR; AuthorizationSet out_params; OperationPtr operation( operation_factory->CreateOperation(move(*key), wrapping_key_params, &error)); if (!operation.get()) return error; error = operation->Begin(wrapping_key_params, &out_params); if (error != KM_ERROR_OK) return error; Buffer input; Buffer output; if (!input.Reinitialize(transit_key.key_material, transit_key.key_material_size)) { return KM_ERROR_MEMORY_ALLOCATION_FAILED; } error = operation->Finish(wrapping_key_params, input, Buffer() /* signature */, &out_params, &output); if (error != KM_ERROR_OK) return error; // decrypt the encrypted key material with the transit key KeymasterKeyBlob key_material = {output.peek_read(), output.available_read()}; // XOR the transit key with the masking key if (key_material.key_material_size != masking_key.key_material_size) { return KM_ERROR_INVALID_ARGUMENT; } for (size_t i = 0; i < key_material.key_material_size; i++) { key_material.writable_data()[i] ^= masking_key.key_material[i]; } auto transit_key_authorizations = AuthorizationSetBuilder() .AesEncryptionKey(256) .Padding(KM_PAD_NONE) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) .Authorization(TAG_NONCE, iv) .Authorization(TAG_MIN_MAC_LENGTH, 128) .build(); if (transit_key_authorizations.is_valid() != AuthorizationSet::Error::OK) { return TranslateAuthorizationSetError(transit_key_authorizations.is_valid()); } auto gcm_params = AuthorizationSetBuilder() .Padding(KM_PAD_NONE) .Authorization(TAG_BLOCK_MODE, KM_MODE_GCM) .Authorization(TAG_NONCE, iv) .Authorization(TAG_MAC_LENGTH, 128) .build(); if (gcm_params.is_valid() != AuthorizationSet::Error::OK) { return TranslateAuthorizationSetError(transit_key_authorizations.is_valid()); } auto aes_factory = GetKeyFactory(KM_ALGORITHM_AES); if (!aes_factory) return KM_ERROR_UNKNOWN_ERROR; UniquePtr aes_key; error = aes_factory->LoadKey(move(key_material), gcm_params, move(transit_key_authorizations), AuthorizationSet(), &aes_key); if (error != KM_ERROR_OK) return error; auto aes_operation_factory = GetOperationFactory(KM_ALGORITHM_AES, KM_PURPOSE_DECRYPT); if (!aes_operation_factory) return KM_ERROR_UNKNOWN_ERROR; OperationPtr aes_operation( aes_operation_factory->CreateOperation(move(*aes_key), gcm_params, &error)); if (!aes_operation.get()) return error; error = aes_operation->Begin(gcm_params, &out_params); if (error != KM_ERROR_OK) return error; size_t consumed = 0; Buffer encrypted_key, plaintext; if (!plaintext.Reinitialize(secure_key.key_material_size + tag.data_length)) { return KM_ERROR_MEMORY_ALLOCATION_FAILED; } if (!encrypted_key.Reinitialize(secure_key.key_material_size + tag.data_length)) { return KM_ERROR_MEMORY_ALLOCATION_FAILED; } if (!encrypted_key.write(secure_key.key_material, secure_key.key_material_size)) { return KM_ERROR_UNKNOWN_ERROR; } if (!encrypted_key.write(tag.data, tag.data_length)) { return KM_ERROR_UNKNOWN_ERROR; } AuthorizationSet update_outparams; auto update_params = AuthorizationSetBuilder() .Authorization(TAG_ASSOCIATED_DATA, wrapped_key_description.data, wrapped_key_description.data_length) .build(); if (update_params.is_valid() != AuthorizationSet::Error::OK) { return TranslateAuthorizationSetError(transit_key_authorizations.is_valid()); } error = aes_operation->Update(update_params, encrypted_key, &update_outparams, &plaintext, &consumed); if (error != KM_ERROR_OK) return error; AuthorizationSet finish_params, finish_out_params; Buffer finish_input; error = aes_operation->Finish(finish_params, finish_input, Buffer() /* signature */, &finish_out_params, &plaintext); if (error != KM_ERROR_OK) return error; *wrapped_key_material = {plaintext.peek_read(), plaintext.available_read()}; if (!wrapped_key_material->key_material && plaintext.peek_read()) { return KM_ERROR_MEMORY_ALLOCATION_FAILED; } return error; } keymaster_error_t PureSoftKeymasterContext::GetVerifiedBootParams( keymaster_blob_t* verified_boot_key, keymaster_blob_t* verified_boot_hash, keymaster_verified_boot_t* verified_boot_state, bool* device_locked) const { // TODO(swillden): See if there might be some sort of vbmeta data in goldfish/cuttlefish. static std::string fake_vb_key(32, 0); *verified_boot_key = {reinterpret_cast(fake_vb_key.data()), fake_vb_key.size()}; *verified_boot_hash = {reinterpret_cast(fake_vb_key.data()), fake_vb_key.size()}; *verified_boot_state = KM_VERIFIED_BOOT_UNVERIFIED; *device_locked = false; return KM_ERROR_OK; } } // namespace keymaster