1 //
2 // Copyright (C) 2020 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 #include "host/commands/secure_env/primary_key_builder.h"
17
18 #include <android-base/logging.h>
19 #include <tss2/tss2_mu.h>
20 #include <tss2/tss2_rc.h>
21
PrimaryKeyBuilder()22 PrimaryKeyBuilder::PrimaryKeyBuilder() : public_area_({}) {
23 public_area_.nameAlg = TPM2_ALG_SHA256;
24 };
25
SigningKey()26 void PrimaryKeyBuilder::SigningKey() {
27 public_area_.type = TPM2_ALG_KEYEDHASH;
28 public_area_.objectAttributes |= TPMA_OBJECT_SIGN_ENCRYPT;
29 public_area_.objectAttributes |= TPMA_OBJECT_USERWITHAUTH;
30 public_area_.objectAttributes |= TPMA_OBJECT_SENSITIVEDATAORIGIN;
31 public_area_.parameters.keyedHashDetail.scheme = (TPMT_KEYEDHASH_SCHEME) {
32 .scheme = TPM2_ALG_HMAC,
33 .details.hmac.hashAlg = TPM2_ALG_SHA256,
34 };
35 }
36
ParentKey()37 void PrimaryKeyBuilder::ParentKey() {
38 public_area_.type = TPM2_ALG_SYMCIPHER;
39 public_area_.objectAttributes |= TPMA_OBJECT_USERWITHAUTH;
40 public_area_.objectAttributes |= TPMA_OBJECT_RESTRICTED;
41 public_area_.objectAttributes |= TPMA_OBJECT_DECRYPT;
42 public_area_.objectAttributes |= TPMA_OBJECT_FIXEDTPM;
43 public_area_.objectAttributes |= TPMA_OBJECT_FIXEDPARENT;
44 public_area_.objectAttributes |= TPMA_OBJECT_SENSITIVEDATAORIGIN;
45 public_area_.parameters.symDetail.sym = (TPMT_SYM_DEF_OBJECT) {
46 .algorithm = TPM2_ALG_AES,
47 .keyBits.aes = 128, // The default maximum AES key size in the simulator.
48 .mode.aes = TPM2_ALG_CFB,
49 };
50 }
51
UniqueData(const std::string & data)52 void PrimaryKeyBuilder::UniqueData(const std::string& data) {
53 if (data.size() > TPM2_SHA256_DIGEST_SIZE) {
54 LOG(FATAL) << "Unique data size was too large";
55 }
56 /* The unique field normally has a precise size to go with the type of the
57 * object. During primary key creation the unique field accepts any short byte
58 * string to let the user introduce variability into the primary key creation
59 * process which is otherwise determinstic relative to secret TPM state. */
60 public_area_.unique.sym.size = data.size();
61 memcpy(&public_area_.unique.sym.buffer, data.data(), data.size());
62 }
63
CreateKey(TpmResourceManager & resource_manager)64 TpmObjectSlot PrimaryKeyBuilder::CreateKey(
65 TpmResourceManager& resource_manager) {
66 TPM2B_AUTH authValue = {};
67 auto rc =
68 Esys_TR_SetAuth(resource_manager.Esys(), ESYS_TR_RH_OWNER, &authValue);
69 if (rc != TSS2_RC_SUCCESS) {
70 LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
71 << " (" << Tss2_RC_Decode(rc) << ")";
72 return {};
73 }
74
75 TPM2B_TEMPLATE public_template = {};
76 size_t offset = 0;
77 rc = Tss2_MU_TPMT_PUBLIC_Marshal(&public_area_, &public_template.buffer[0],
78 sizeof(public_template.buffer), &offset);
79 if (rc != TSS2_RC_SUCCESS) {
80 LOG(ERROR) << "Tss2_MU_TPMT_PUBLIC_Marshal failed with return code " << rc
81 << " (" << Tss2_RC_Decode(rc) << ")";
82 return {};
83 }
84 public_template.size = offset;
85
86 TPM2B_SENSITIVE_CREATE in_sensitive = {};
87
88 auto key_slot = resource_manager.ReserveSlot();
89 if (!key_slot) {
90 LOG(ERROR) << "No slots available";
91 return {};
92 }
93 ESYS_TR raw_handle;
94 // TODO(b/154956668): Define better ACLs on these keys.
95 // Since this is a primary key, it's generated deterministically. It would
96 // also be possible to generate this once and hold it in storage.
97 rc = Esys_CreateLoaded(
98 /* esysContext */ resource_manager.Esys(),
99 /* primaryHandle */ ESYS_TR_RH_OWNER,
100 /* shandle1 */ ESYS_TR_PASSWORD,
101 /* shandle2 */ ESYS_TR_NONE,
102 /* shandle3 */ ESYS_TR_NONE,
103 /* inSensitive */ &in_sensitive,
104 /* inPublic */ &public_template,
105 /* objectHandle */ &raw_handle,
106 /* outPrivate */ nullptr,
107 /* outPublic */ nullptr);
108 if (rc != TSS2_RC_SUCCESS) {
109 LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc
110 << " (" << Tss2_RC_Decode(rc) << ")";
111 return {};
112 }
113 key_slot->set(raw_handle);
114 return key_slot;
115 }
116
117 std::function<TpmObjectSlot(TpmResourceManager&)>
SigningKeyCreator(const std::string & unique)118 SigningKeyCreator(const std::string& unique) {
119 return [unique](TpmResourceManager& resource_manager) {
120 PrimaryKeyBuilder key_builder;
121 key_builder.SigningKey();
122 key_builder.UniqueData(unique);
123 return key_builder.CreateKey(resource_manager);
124 };
125 }
126
127 std::function<TpmObjectSlot(TpmResourceManager&)>
ParentKeyCreator(const std::string & unique)128 ParentKeyCreator(const std::string& unique) {
129 return [unique](TpmResourceManager& resource_manager) {
130 PrimaryKeyBuilder key_builder;
131 key_builder.ParentKey();
132 key_builder.UniqueData(unique);
133 return key_builder.CreateKey(resource_manager);
134 };
135 }
136