| // |
| // Copyright (C) 2020 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 "host/commands/secure_env/primary_key_builder.h" |
| |
| #include <android-base/logging.h> |
| #include <tss2/tss2_mu.h> |
| #include <tss2/tss2_rc.h> |
| |
| namespace cuttlefish { |
| |
| PrimaryKeyBuilder::PrimaryKeyBuilder() : public_area_({}) { |
| public_area_.nameAlg = TPM2_ALG_SHA256; |
| }; |
| |
| void PrimaryKeyBuilder::SigningKey() { |
| public_area_.type = TPM2_ALG_KEYEDHASH; |
| public_area_.objectAttributes |= TPMA_OBJECT_SIGN_ENCRYPT; |
| public_area_.objectAttributes |= TPMA_OBJECT_USERWITHAUTH; |
| public_area_.objectAttributes |= TPMA_OBJECT_SENSITIVEDATAORIGIN; |
| public_area_.parameters.keyedHashDetail.scheme = (TPMT_KEYEDHASH_SCHEME) { |
| .scheme = TPM2_ALG_HMAC, |
| .details.hmac.hashAlg = TPM2_ALG_SHA256, |
| }; |
| } |
| |
| void PrimaryKeyBuilder::ParentKey() { |
| public_area_.type = TPM2_ALG_SYMCIPHER; |
| public_area_.objectAttributes |= TPMA_OBJECT_USERWITHAUTH; |
| public_area_.objectAttributes |= TPMA_OBJECT_RESTRICTED; |
| public_area_.objectAttributes |= TPMA_OBJECT_DECRYPT; |
| public_area_.objectAttributes |= TPMA_OBJECT_FIXEDTPM; |
| public_area_.objectAttributes |= TPMA_OBJECT_FIXEDPARENT; |
| public_area_.objectAttributes |= TPMA_OBJECT_SENSITIVEDATAORIGIN; |
| public_area_.parameters.symDetail.sym = (TPMT_SYM_DEF_OBJECT) { |
| .algorithm = TPM2_ALG_AES, |
| .keyBits.aes = 128, // The default maximum AES key size in the simulator. |
| .mode.aes = TPM2_ALG_CFB, |
| }; |
| } |
| |
| void PrimaryKeyBuilder::UniqueData(const std::string& data) { |
| if (data.size() > TPM2_SHA256_DIGEST_SIZE) { |
| LOG(FATAL) << "Unique data size was too large"; |
| } |
| /* The unique field normally has a precise size to go with the type of the |
| * object. During primary key creation the unique field accepts any short byte |
| * string to let the user introduce variability into the primary key creation |
| * process which is otherwise determinstic relative to secret TPM state. */ |
| public_area_.unique.sym.size = data.size(); |
| memcpy(&public_area_.unique.sym.buffer, data.data(), data.size()); |
| } |
| |
| TpmObjectSlot PrimaryKeyBuilder::CreateKey( |
| TpmResourceManager& resource_manager) { |
| TPM2B_AUTH authValue = {}; |
| auto rc = |
| Esys_TR_SetAuth(resource_manager.Esys(), ESYS_TR_RH_OWNER, &authValue); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc |
| << " (" << Tss2_RC_Decode(rc) << ")"; |
| return {}; |
| } |
| |
| TPM2B_TEMPLATE public_template = {}; |
| size_t offset = 0; |
| rc = Tss2_MU_TPMT_PUBLIC_Marshal(&public_area_, &public_template.buffer[0], |
| sizeof(public_template.buffer), &offset); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG(ERROR) << "Tss2_MU_TPMT_PUBLIC_Marshal failed with return code " << rc |
| << " (" << Tss2_RC_Decode(rc) << ")"; |
| return {}; |
| } |
| public_template.size = offset; |
| |
| TPM2B_SENSITIVE_CREATE in_sensitive = {}; |
| |
| auto key_slot = resource_manager.ReserveSlot(); |
| if (!key_slot) { |
| LOG(ERROR) << "No slots available"; |
| return {}; |
| } |
| ESYS_TR raw_handle; |
| // TODO(b/154956668): Define better ACLs on these keys. |
| // Since this is a primary key, it's generated deterministically. It would |
| // also be possible to generate this once and hold it in storage. |
| rc = Esys_CreateLoaded( |
| /* esysContext */ resource_manager.Esys(), |
| /* primaryHandle */ ESYS_TR_RH_OWNER, |
| /* shandle1 */ ESYS_TR_PASSWORD, |
| /* shandle2 */ ESYS_TR_NONE, |
| /* shandle3 */ ESYS_TR_NONE, |
| /* inSensitive */ &in_sensitive, |
| /* inPublic */ &public_template, |
| /* objectHandle */ &raw_handle, |
| /* outPrivate */ nullptr, |
| /* outPublic */ nullptr); |
| if (rc != TSS2_RC_SUCCESS) { |
| LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc |
| << " (" << Tss2_RC_Decode(rc) << ")"; |
| return {}; |
| } |
| key_slot->set(raw_handle); |
| return key_slot; |
| } |
| |
| std::function<TpmObjectSlot(TpmResourceManager&)> |
| SigningKeyCreator(const std::string& unique) { |
| return [unique](TpmResourceManager& resource_manager) { |
| PrimaryKeyBuilder key_builder; |
| key_builder.SigningKey(); |
| key_builder.UniqueData(unique); |
| return key_builder.CreateKey(resource_manager); |
| }; |
| } |
| |
| std::function<TpmObjectSlot(TpmResourceManager&)> |
| ParentKeyCreator(const std::string& unique) { |
| return [unique](TpmResourceManager& resource_manager) { |
| PrimaryKeyBuilder key_builder; |
| key_builder.ParentKey(); |
| key_builder.UniqueData(unique); |
| return key_builder.CreateKey(resource_manager); |
| }; |
| } |
| |
| } // namespace cuttlefish |