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   std::vector<uint8_t> result(num_bytes);
47   auto hbk = TpmHmacWithContext(
48       resource_manager_, "HardwareBoundKey",
49       reinterpret_cast<const uint8_t*>(context.data()), context.size());
50   if (!hbk) {
51     LOG(ERROR) << "Error calculating HMAC";
52     return result;
53   }
54 
55   if (!HKDF(result.data(), num_bytes,              //
56             EVP_sha256(),                          //
57             hbk->buffer, hbk->size,                //
58             nullptr /* salt */, 0 /* salt len */,  //
59             reinterpret_cast<const uint8_t*>(context.data()), context.size())) {
60     // Should never fail. Even if it could the API has no way of reporting the
61     // error.
62     LOG(ERROR) << "Error calculating HKDF: " << ERR_peek_last_error();
63   }
64 
65   return result;
66 }
67 
CreateDeviceInfo(uint32_t csrVersion) const68 std::unique_ptr<cppbor::Map> TpmRemoteProvisioningContext::CreateDeviceInfo(
69     uint32_t csrVersion) const {
70   auto result = std::make_unique<cppbor::Map>();
71   result->add(cppbor::Tstr("brand"), cppbor::Tstr("Google"));
72   result->add(cppbor::Tstr("manufacturer"), cppbor::Tstr("Google"));
73   result->add(cppbor::Tstr("product"),
74               cppbor::Tstr("Cuttlefish Virtual Device"));
75   result->add(cppbor::Tstr("model"), cppbor::Tstr("Virtual Device"));
76   result->add(cppbor::Tstr("device"), cppbor::Tstr("Virtual Device"));
77   if (bootloader_state_) {
78     result->add(cppbor::Tstr("bootloader_state"),
79                 cppbor::Tstr(*bootloader_state_));
80   }
81   if (verified_boot_state_) {
82     result->add(cppbor::Tstr("vb_state"), cppbor::Tstr(*verified_boot_state_));
83   }
84   if (vbmeta_digest_) {
85     result->add(cppbor::Tstr("vbmeta_digest"), cppbor::Bstr(*vbmeta_digest_));
86   }
87   if (os_version_) {
88     result->add(cppbor::Tstr("os_version"),
89                 cppbor::Tstr(std::to_string(*os_version_)));
90   }
91   if (os_patchlevel_) {
92     result->add(cppbor::Tstr("system_patch_level"),
93                 cppbor::Uint(*os_patchlevel_));
94   }
95   if (boot_patchlevel_) {
96     result->add(cppbor::Tstr("boot_patch_level"),
97                 cppbor::Uint(*boot_patchlevel_));
98   }
99   if (vendor_patchlevel_) {
100     result->add(cppbor::Tstr("vendor_patch_level"),
101                 cppbor::Uint(*vendor_patchlevel_));
102   }
103   // "version" field was removed from DeviceInfo in CSR v3.
104   if (csrVersion < 3) {
105     result->add(cppbor::Tstr("version"), cppbor::Uint(csrVersion));
106   }
107   result->add(cppbor::Tstr("fused"), cppbor::Uint(0));
108   result->add(cppbor::Tstr("security_level"), cppbor::Tstr("tee"));
109   result->canonicalize();
110   return result;
111 }
112 
113 std::pair<std::vector<uint8_t> /* privKey */, cppbor::Array /* BCC */>
GenerateBcc(bool testMode) const114 TpmRemoteProvisioningContext::GenerateBcc(bool testMode) const {
115   std::vector<uint8_t> privKey(ED25519_PRIVATE_KEY_LEN);
116   std::vector<uint8_t> pubKey(ED25519_PUBLIC_KEY_LEN);
117 
118   std::vector<uint8_t> seed;
119   if (testMode) {
120     // Length is hard-coded in the BoringCrypto API without a constant
121     seed.resize(32);
122     RAND_bytes(seed.data(), seed.size());
123   } else {
124     // TODO: Switch to P256 signing keys that are TPM-bound.
125     seed = DeriveBytesFromHbk("BccKey", 32);
126   }
127   ED25519_keypair_from_seed(pubKey.data(), privKey.data(), seed.data());
128 
129   const auto issuer_and_subject = "Cuttlefish secure env";
130   auto coseKey = cppbor::Map()
131                      .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
132                      .add(CoseKey::ALGORITHM, EDDSA)
133                      .add(CoseKey::CURVE, ED25519)
134                      .add(CoseKey::PUBKEY_X, pubKey)
135                      .canonicalize();
136   auto sign1Payload =
137       cppbor::Map()
138           .add(1 /* Issuer */, issuer_and_subject)
139           .add(2 /* Subject */, issuer_and_subject)
140           .add(-4670552 /* Subject Pub Key */, coseKey.encode())
141           .add(-4670553 /* Key Usage (little-endian order) */,
142                std::vector<uint8_t>{0x20} /* keyCertSign = 1<<5 */)
143           .canonicalize()
144           .encode();
145   auto coseSign1 = constructCoseSign1(privKey,       /* signing key */
146                                       cppbor::Map(), /* extra protected */
147                                       sign1Payload, {} /* AAD */);
148   assert(coseSign1);
149 
150   return {privKey,
151           cppbor::Array().add(std::move(coseKey)).add(coseSign1.moveValue())};
152 }
153 
SetSystemVersion(uint32_t os_version,uint32_t os_patchlevel)154 void TpmRemoteProvisioningContext::SetSystemVersion(uint32_t os_version,
155                                                     uint32_t os_patchlevel) {
156   os_version_ = os_version;
157   os_patchlevel_ = os_patchlevel;
158 }
159 
SetVendorPatchlevel(uint32_t vendor_patchlevel)160 void TpmRemoteProvisioningContext::SetVendorPatchlevel(
161     uint32_t vendor_patchlevel) {
162   vendor_patchlevel_ = vendor_patchlevel;
163 }
164 
SetBootPatchlevel(uint32_t boot_patchlevel)165 void TpmRemoteProvisioningContext::SetBootPatchlevel(uint32_t boot_patchlevel) {
166   boot_patchlevel_ = boot_patchlevel;
167 }
168 
SetVerifiedBootInfo(std::string_view boot_state,std::string_view bootloader_state,const std::vector<uint8_t> & vbmeta_digest)169 void TpmRemoteProvisioningContext::SetVerifiedBootInfo(
170     std::string_view boot_state, std::string_view bootloader_state,
171     const std::vector<uint8_t>& vbmeta_digest) {
172   verified_boot_state_ = boot_state;
173   bootloader_state_ = bootloader_state;
174   vbmeta_digest_ = vbmeta_digest;
175 }
176 
177 ErrMsgOr<std::vector<uint8_t>>
BuildProtectedDataPayload(bool isTestMode,const std::vector<uint8_t> & macKey,const std::vector<uint8_t> & aad) const178 TpmRemoteProvisioningContext::BuildProtectedDataPayload(
179     bool isTestMode,                     //
180     const std::vector<uint8_t>& macKey,  //
181     const std::vector<uint8_t>& aad) const {
182   std::vector<uint8_t> devicePrivKey;
183   cppbor::Array bcc;
184   if (isTestMode) {
185     std::tie(devicePrivKey, bcc) = GenerateBcc(/*testMode=*/true);
186   } else {
187     devicePrivKey = devicePrivKey_;
188     auto clone = bcc_.clone();
189     if (!clone->asArray()) {
190       return "The BCC is not an array";
191     }
192     bcc = std::move(*clone->asArray());
193   }
194   auto sign1 = constructCoseSign1(devicePrivKey, macKey, aad);
195   if (!sign1) {
196     return sign1.moveMessage();
197   }
198   return cppbor::Array().add(sign1.moveValue()).add(std::move(bcc)).encode();
199 }
200 
201 std::optional<cppcose::HmacSha256>
GenerateHmacSha256(const cppcose::bytevec & input) const202 TpmRemoteProvisioningContext::GenerateHmacSha256(
203     const cppcose::bytevec& input) const {
204   auto tpm_digest =
205       TpmHmacWithContext(resource_manager_, "Public Key Authentication Key",
206                          input.data(), input.size());
207   if (!tpm_digest) {
208     LOG(ERROR) << "Could not calculate hmac";
209     return std::nullopt;
210   }
211 
212   cppcose::HmacSha256 hmac;
213   if (tpm_digest->size != hmac.size()) {
214     LOG(ERROR) << "TPM-generated digest was too short. Actual size: "
215                << tpm_digest->size << " expected " << hmac.size() << " bytes";
216     return std::nullopt;
217   }
218 
219   std::copy(tpm_digest->buffer, tpm_digest->buffer + tpm_digest->size,
220             hmac.begin());
221   return hmac;
222 }
223 
GetHwInfo(keymaster::GetHwInfoResponse * hwInfo) const224 void TpmRemoteProvisioningContext::GetHwInfo(
225     keymaster::GetHwInfoResponse* hwInfo) const {
226   hwInfo->version = 3;
227   hwInfo->rpcAuthorName = "Google";
228   hwInfo->supportedEekCurve = 0 /* CURVE_NONE */;
229   hwInfo->uniqueId = "remote keymint";
230   hwInfo->supportedNumKeysInCsr = 20;
231 }
232 
BuildCsr(const std::vector<uint8_t> & challenge,cppbor::Array keysToSign) const233 cppcose::ErrMsgOr<cppbor::Array> TpmRemoteProvisioningContext::BuildCsr(
234     const std::vector<uint8_t>& challenge, cppbor::Array keysToSign) const {
235   uint32_t csrVersion = 3;
236   auto deviceInfo = std::move(*CreateDeviceInfo(csrVersion));
237   auto csrPayload = cppbor::Array()
238                         .add(csrVersion)
239                         .add("keymint" /* CertificateType */)
240                         .add(std::move(deviceInfo))
241                         .add(std::move(keysToSign));
242   auto signedDataPayload =
243       cppbor::Array().add(challenge).add(cppbor::Bstr(csrPayload.encode()));
244   auto signedData = constructCoseSign1(
245       devicePrivKey_, signedDataPayload.encode(), {} /* aad */);
246 
247   return cppbor::Array()
248       .add(1 /* version */)
249       .add(cppbor::Map() /* UdsCerts */)
250       .add(std::move(*bcc_.clone()->asArray()) /* DiceCertChain */)
251       .add(std::move(*signedData) /* SignedData */);
252 }
253 
254 }  // namespace cuttlefish
255