Andrew Scull | 9fadf34 | 2021-06-03 08:38:47 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2021, The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "MicrodroidKeymasterContext.h" |
| 18 | |
| 19 | #include <android-base/logging.h> |
| 20 | #include <keymaster/key.h> |
| 21 | #include <keymaster/key_blob_utils/auth_encrypted_key_blob.h> |
| 22 | #include <keymaster/key_blob_utils/software_keyblobs.h> |
| 23 | |
| 24 | using namespace ::keymaster; |
| 25 | |
| 26 | // This value is used for the ROOT_OF_TRUST tag which is only used in |
| 27 | // attestation records which aren't supported in this implementation so a |
| 28 | // constant doesn't cause any hard. MicroDroid SoftWare root-of-trust. |
| 29 | static uint8_t SWROT[] = {'M', 'D', 'S', 'W'}; |
| 30 | static const KeymasterBlob microdroidSoftwareRootOfTrust(SWROT); |
| 31 | |
| 32 | keymaster_error_t MicrodroidKeymasterContext::CreateKeyBlob(const AuthorizationSet& key_description, |
| 33 | keymaster_key_origin_t origin, |
| 34 | const KeymasterKeyBlob& key_material, |
| 35 | KeymasterKeyBlob* blob, |
| 36 | AuthorizationSet* hw_enforced, |
| 37 | AuthorizationSet* sw_enforced) const { |
| 38 | keymaster_error_t error; |
| 39 | |
| 40 | if (key_description.GetTagValue(TAG_ROLLBACK_RESISTANCE)) { |
| 41 | return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE; |
| 42 | } |
| 43 | |
| 44 | error = SetKeyBlobAuthorizations(key_description, origin, os_version_, os_patchlevel_, |
| 45 | hw_enforced, sw_enforced); |
| 46 | if (error != KM_ERROR_OK) return error; |
| 47 | |
| 48 | AuthorizationSet hidden; |
| 49 | error = BuildHiddenAuthorizations(key_description, &hidden, microdroidSoftwareRootOfTrust); |
| 50 | if (error != KM_ERROR_OK) return error; |
| 51 | |
| 52 | CHECK(hw_enforced->empty()); |
| 53 | |
| 54 | // Note that the authorizations included in the blob are not encrypted. This |
| 55 | // doesn't pose a problem for the current applications but may be a |
| 56 | // candidate for hardening. |
| 57 | auto encrypted_key = EncryptKey(key_material, AES_GCM_WITH_SW_ENFORCED, *hw_enforced, |
| 58 | *sw_enforced, hidden, root_key_, random_, &error); |
| 59 | if (error != KM_ERROR_OK) return error; |
| 60 | |
| 61 | *blob = SerializeAuthEncryptedBlob(encrypted_key, *hw_enforced, *sw_enforced, &error); |
| 62 | return error; |
| 63 | } |
| 64 | |
| 65 | keymaster_error_t MicrodroidKeymasterContext::ParseKeyBlob( |
| 66 | const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params, |
| 67 | UniquePtr<Key>* key) const { |
| 68 | keymaster_error_t error; |
| 69 | |
| 70 | AuthorizationSet hidden; |
| 71 | error = BuildHiddenAuthorizations(additional_params, &hidden, microdroidSoftwareRootOfTrust); |
| 72 | if (error != KM_ERROR_OK) return error; |
| 73 | |
| 74 | auto deserialized_key = DeserializeAuthEncryptedBlob(blob, &error); |
| 75 | if (error != KM_ERROR_OK) return error; |
| 76 | |
| 77 | keymaster_algorithm_t algorithm; |
| 78 | if (!deserialized_key.sw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) { |
| 79 | return KM_ERROR_INVALID_ARGUMENT; |
| 80 | } |
| 81 | |
| 82 | auto key_material = DecryptKey(deserialized_key, hidden, root_key_, &error); |
| 83 | if (error != KM_ERROR_OK) return error; |
| 84 | |
| 85 | auto factory = GetKeyFactory(algorithm); |
| 86 | return factory->LoadKey(move(key_material), additional_params, |
| 87 | move(deserialized_key.hw_enforced), move(deserialized_key.sw_enforced), |
| 88 | key); |
| 89 | } |
| 90 | |
| 91 | static bool UpgradeIntegerTag(keymaster_tag_t tag, uint32_t value, AuthorizationSet* set) { |
| 92 | int index = set->find(tag); |
| 93 | if (index == -1) { |
| 94 | keymaster_key_param_t param; |
| 95 | param.tag = tag; |
| 96 | param.integer = value; |
| 97 | set->push_back(param); |
| 98 | return true; |
| 99 | } |
| 100 | |
| 101 | if (set->params[index].integer > value) return false; |
| 102 | |
| 103 | if (set->params[index].integer != value) { |
| 104 | set->params[index].integer = value; |
| 105 | } |
| 106 | return true; |
| 107 | } |
| 108 | |
| 109 | keymaster_error_t MicrodroidKeymasterContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade, |
| 110 | const AuthorizationSet& upgrade_params, |
| 111 | KeymasterKeyBlob* upgraded_key) const { |
| 112 | UniquePtr<Key> key; |
| 113 | keymaster_error_t error = ParseKeyBlob(key_to_upgrade, upgrade_params, &key); |
| 114 | if (error != KM_ERROR_OK) return error; |
| 115 | |
| 116 | if (os_version_ == 0) { |
| 117 | // We need to allow "upgrading" OS version to zero, to support upgrading from proper |
| 118 | // numbered releases to unnumbered development and preview releases. |
| 119 | |
| 120 | int key_os_version_pos = key->sw_enforced().find(TAG_OS_VERSION); |
| 121 | if (key_os_version_pos != -1) { |
| 122 | uint32_t key_os_version = key->sw_enforced()[key_os_version_pos].integer; |
| 123 | if (key_os_version != 0) { |
| 124 | key->sw_enforced()[key_os_version_pos].integer = os_version_; |
| 125 | } |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | if (!UpgradeIntegerTag(TAG_OS_VERSION, os_version_, &key->sw_enforced()) || |
| 130 | !UpgradeIntegerTag(TAG_OS_PATCHLEVEL, os_patchlevel_, &key->sw_enforced())) |
| 131 | // One of the version fields would have been a downgrade. Not allowed. |
| 132 | return KM_ERROR_INVALID_ARGUMENT; |
| 133 | |
| 134 | AuthorizationSet hidden; |
| 135 | error = BuildHiddenAuthorizations(upgrade_params, &hidden, microdroidSoftwareRootOfTrust); |
| 136 | if (error != KM_ERROR_OK) return error; |
| 137 | |
| 138 | auto encrypted_key = |
| 139 | EncryptKey(key->key_material(), AES_GCM_WITH_SW_ENFORCED, key->hw_enforced(), |
| 140 | key->sw_enforced(), hidden, root_key_, random_, &error); |
| 141 | if (error != KM_ERROR_OK) return error; |
| 142 | |
| 143 | *upgraded_key = SerializeAuthEncryptedBlob(encrypted_key, key->hw_enforced(), |
| 144 | key->sw_enforced(), &error); |
| 145 | return error; |
| 146 | } |