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 <algorithm>
18 #include <cassert>
19 #include <optional>
20
21 #include <android-base/logging.h>
22 #include <keymaster/cppcose/cppcose.h>
23 #include <openssl/bn.h>
24 #include <openssl/ec.h>
25 #include <openssl/err.h>
26 #include <openssl/hkdf.h>
27 #include <openssl/rand.h>
28
29 #include "host/commands/secure_env/primary_key_builder.h"
30 #include "host/commands/secure_env/tpm_hmac.h"
31 #include "tpm_remote_provisioning_context.h"
32 #include "tpm_resource_manager.h"
33
34 using namespace cppcose;
35
36 namespace cuttlefish {
37
TpmRemoteProvisioningContext(TpmResourceManager & resource_manager)38 TpmRemoteProvisioningContext::TpmRemoteProvisioningContext(
39 TpmResourceManager& resource_manager)
40 : resource_manager_(resource_manager) {
41 std::tie(devicePrivKey_, bcc_) = GenerateBcc(/*testMode=*/false);
42 }
43
DeriveBytesFromHbk(const std::string & context,size_t num_bytes) const44 std::vector<uint8_t> TpmRemoteProvisioningContext::DeriveBytesFromHbk(
45 const std::string& context, size_t num_bytes) const {
46 PrimaryKeyBuilder key_builder;
47 key_builder.SigningKey();
48 key_builder.UniqueData("HardwareBoundKey");
49 TpmObjectSlot key = key_builder.CreateKey(resource_manager_);
50
51 auto hbk =
52 TpmHmac(resource_manager_, key->get(), TpmAuth(ESYS_TR_PASSWORD),
53 reinterpret_cast<const uint8_t*>(context.data()), context.size());
54
55 std::vector<uint8_t> result(num_bytes);
56 if (!HKDF(result.data(), num_bytes, //
57 EVP_sha256(), //
58 hbk->buffer, hbk->size, //
59 nullptr /* salt */, 0 /* salt len */, //
60 reinterpret_cast<const uint8_t*>(context.data()), context.size())) {
61 // Should never fail. Even if it could the API has no way of reporting the
62 // error.
63 LOG(ERROR) << "Error calculating HMAC: " << ERR_peek_last_error();
64 }
65
66 return result;
67 }
68
CreateDeviceInfo() const69 std::unique_ptr<cppbor::Map> TpmRemoteProvisioningContext::CreateDeviceInfo()
70 const {
71 auto result = std::make_unique<cppbor::Map>();
72 result->add(cppbor::Tstr("brand"), cppbor::Tstr("Google"));
73 result->add(cppbor::Tstr("manufacturer"), cppbor::Tstr("Google"));
74 result->add(cppbor::Tstr("product"),
75 cppbor::Tstr("Cuttlefish Virtual Device"));
76 result->add(cppbor::Tstr("model"), cppbor::Tstr("Virtual Device"));
77 result->add(cppbor::Tstr("device"), cppbor::Tstr("Virtual Device"));
78 if (bootloader_state_) {
79 result->add(cppbor::Tstr("bootloader_state"),
80 cppbor::Tstr(*bootloader_state_));
81 }
82 if (verified_boot_state_) {
83 result->add(cppbor::Tstr("vb_state"), cppbor::Tstr(*verified_boot_state_));
84 }
85 if (vbmeta_digest_) {
86 result->add(cppbor::Tstr("vbmeta_digest"), cppbor::Bstr(*vbmeta_digest_));
87 }
88 if (os_version_) {
89 result->add(cppbor::Tstr("os_version"),
90 cppbor::Tstr(std::to_string(*os_version_)));
91 }
92 if (os_patchlevel_) {
93 result->add(cppbor::Tstr("system_patch_level"),
94 cppbor::Uint(*os_patchlevel_));
95 }
96 if (boot_patchlevel_) {
97 result->add(cppbor::Tstr("boot_patch_level"),
98 cppbor::Uint(*boot_patchlevel_));
99 }
100 if (vendor_patchlevel_) {
101 result->add(cppbor::Tstr("vendor_patch_level"),
102 cppbor::Uint(*vendor_patchlevel_));
103 }
104 result->add(cppbor::Tstr("version"), cppbor::Uint(2));
105 result->add(cppbor::Tstr("fused"), cppbor::Uint(0));
106 result->add(cppbor::Tstr("security_level"), cppbor::Tstr("tee"));
107 result->canonicalize();
108 return result;
109 }
110
111 std::pair<std::vector<uint8_t> /* privKey */, cppbor::Array /* BCC */>
GenerateBcc(bool testMode) const112 TpmRemoteProvisioningContext::GenerateBcc(bool testMode) const {
113 std::vector<uint8_t> privKey(ED25519_PRIVATE_KEY_LEN);
114 std::vector<uint8_t> pubKey(ED25519_PUBLIC_KEY_LEN);
115
116 std::vector<uint8_t> seed;
117 if (testMode) {
118 // Length is hard-coded in the BoringCrypto API without a constant
119 seed.resize(32);
120 RAND_bytes(seed.data(), seed.size());
121 } else {
122 // TODO: Switch to P256 signing keys that are TPM-bound.
123 seed = DeriveBytesFromHbk("BccKey", 32);
124 }
125 ED25519_keypair_from_seed(pubKey.data(), privKey.data(), seed.data());
126
127 auto coseKey = cppbor::Map()
128 .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
129 .add(CoseKey::ALGORITHM, EDDSA)
130 .add(CoseKey::CURVE, ED25519)
131 .add(CoseKey::KEY_OPS, VERIFY)
132 .add(CoseKey::PUBKEY_X, pubKey)
133 .canonicalize();
134 auto sign1Payload =
135 cppbor::Map()
136 .add(1 /* Issuer */, "Issuer")
137 .add(2 /* Subject */, "Subject")
138 .add(-4670552 /* Subject Pub Key */, coseKey.encode())
139 .add(-4670553 /* Key Usage (little-endian order) */,
140 std::vector<uint8_t>{0x20} /* keyCertSign = 1<<5 */)
141 .canonicalize()
142 .encode();
143 auto coseSign1 = constructCoseSign1(privKey, /* signing key */
144 cppbor::Map(), /* extra protected */
145 sign1Payload, {} /* AAD */);
146 assert(coseSign1);
147
148 return {privKey,
149 cppbor::Array().add(std::move(coseKey)).add(coseSign1.moveValue())};
150 }
151
SetSystemVersion(uint32_t os_version,uint32_t os_patchlevel)152 void TpmRemoteProvisioningContext::SetSystemVersion(uint32_t os_version,
153 uint32_t os_patchlevel) {
154 os_version_ = os_version;
155 os_patchlevel_ = os_patchlevel;
156 }
157
SetVendorPatchlevel(uint32_t vendor_patchlevel)158 void TpmRemoteProvisioningContext::SetVendorPatchlevel(
159 uint32_t vendor_patchlevel) {
160 vendor_patchlevel_ = vendor_patchlevel;
161 }
162
SetBootPatchlevel(uint32_t boot_patchlevel)163 void TpmRemoteProvisioningContext::SetBootPatchlevel(uint32_t boot_patchlevel) {
164 boot_patchlevel_ = boot_patchlevel;
165 }
166
SetVerifiedBootInfo(std::string_view boot_state,std::string_view bootloader_state,const std::vector<uint8_t> & vbmeta_digest)167 void TpmRemoteProvisioningContext::SetVerifiedBootInfo(
168 std::string_view boot_state, std::string_view bootloader_state,
169 const std::vector<uint8_t>& vbmeta_digest) {
170 verified_boot_state_ = boot_state;
171 bootloader_state_ = bootloader_state;
172 vbmeta_digest_ = vbmeta_digest;
173 }
174
175 ErrMsgOr<std::vector<uint8_t>>
BuildProtectedDataPayload(bool isTestMode,const std::vector<uint8_t> & macKey,const std::vector<uint8_t> & aad) const176 TpmRemoteProvisioningContext::BuildProtectedDataPayload(
177 bool isTestMode, //
178 const std::vector<uint8_t>& macKey, //
179 const std::vector<uint8_t>& aad) const {
180 std::vector<uint8_t> devicePrivKey;
181 cppbor::Array bcc;
182 if (isTestMode) {
183 std::tie(devicePrivKey, bcc) = GenerateBcc(/*testMode=*/true);
184 } else {
185 devicePrivKey = devicePrivKey_;
186 auto clone = bcc_.clone();
187 if (!clone->asArray()) {
188 return "The BCC is not an array";
189 }
190 bcc = std::move(*clone->asArray());
191 }
192 auto sign1 = constructCoseSign1(devicePrivKey, macKey, aad);
193 if (!sign1) {
194 return sign1.moveMessage();
195 }
196 return cppbor::Array().add(sign1.moveValue()).add(std::move(bcc)).encode();
197 }
198
199 std::optional<cppcose::HmacSha256>
GenerateHmacSha256(const cppcose::bytevec & input) const200 TpmRemoteProvisioningContext::GenerateHmacSha256(
201 const cppcose::bytevec& input) const {
202 auto signing_key_builder = PrimaryKeyBuilder();
203 signing_key_builder.SigningKey();
204 signing_key_builder.UniqueData("Public Key Authentication Key");
205 auto signing_key = signing_key_builder.CreateKey(resource_manager_);
206 if (!signing_key) {
207 LOG(ERROR) << "Could not make MAC key for authenticating the pubkey";
208 return std::nullopt;
209 }
210
211 auto tpm_digest =
212 TpmHmac(resource_manager_, signing_key->get(), TpmAuth(ESYS_TR_PASSWORD),
213 input.data(), input.size());
214
215 if (!tpm_digest) {
216 LOG(ERROR) << "Could not calculate hmac";
217 return std::nullopt;
218 }
219
220 cppcose::HmacSha256 hmac;
221 if (tpm_digest->size != hmac.size()) {
222 LOG(ERROR) << "TPM-generated digest was too short. Actual size: "
223 << tpm_digest->size << " expected " << hmac.size() << " bytes";
224 return std::nullopt;
225 }
226
227 std::copy(tpm_digest->buffer, tpm_digest->buffer + tpm_digest->size,
228 hmac.begin());
229 return hmac;
230 }
231
232 } // namespace cuttlefish
233