• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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