1 /*
2 * Copyright 2022 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 "rkp_factory_extraction_lib.h"
18
19 #include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
20 #include <android-base/properties.h>
21 #include <android/binder_manager.h>
22 #include <cppbor.h>
23 #include <cstddef>
24 #include <cstdint>
25 #include <cstring>
26 #include <iterator>
27 #include <keymaster/cppcose/cppcose.h>
28 #include <openssl/base64.h>
29 #include <remote_prov/remote_prov_utils.h>
30 #include <sys/random.h>
31
32 #include <memory>
33 #include <optional>
34 #include <string>
35 #include <string_view>
36 #include <vector>
37
38 #include "cppbor_parse.h"
39
40 using aidl::android::hardware::security::keymint::DeviceInfo;
41 using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
42 using aidl::android::hardware::security::keymint::MacedPublicKey;
43 using aidl::android::hardware::security::keymint::ProtectedData;
44 using aidl::android::hardware::security::keymint::RpcHardwareInfo;
45 using aidl::android::hardware::security::keymint::remote_prov::EekChain;
46 using aidl::android::hardware::security::keymint::remote_prov::generateEekChain;
47 using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
48 using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
49 using aidl::android::hardware::security::keymint::remote_prov::parseAndValidateFactoryDeviceInfo;
50 using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryCsr;
51 using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryProtectedData;
52
53 using namespace cppbor;
54 using namespace cppcose;
55
56 constexpr size_t kVersionWithoutSuperencryption = 3;
57
toBase64(const std::vector<uint8_t> & buffer)58 std::string toBase64(const std::vector<uint8_t>& buffer) {
59 size_t base64Length;
60 int rc = EVP_EncodedLength(&base64Length, buffer.size());
61 if (!rc) {
62 std::cerr << "Error getting base64 length. Size overflow?" << std::endl;
63 exit(-1);
64 }
65
66 std::string base64(base64Length, ' ');
67 rc = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64.data()), buffer.data(), buffer.size());
68 ++rc; // Account for NUL, which BoringSSL does not for some reason.
69 if (rc != base64Length) {
70 std::cerr << "Error writing base64. Expected " << base64Length
71 << " bytes to be written, but " << rc << " bytes were actually written."
72 << std::endl;
73 exit(-1);
74 }
75
76 // BoringSSL automatically adds a NUL -- remove it from the string data
77 base64.pop_back();
78
79 return base64;
80 }
81
generateChallenge()82 std::vector<uint8_t> generateChallenge() {
83 std::vector<uint8_t> challenge(kChallengeSize);
84
85 ssize_t bytesRemaining = static_cast<ssize_t>(challenge.size());
86 uint8_t* writePtr = challenge.data();
87 while (bytesRemaining > 0) {
88 int bytesRead = getrandom(writePtr, bytesRemaining, /*flags=*/0);
89 if (bytesRead < 0) {
90 if (errno == EINTR) {
91 continue;
92 } else {
93 std::cerr << errno << ": " << strerror(errno) << std::endl;
94 exit(-1);
95 }
96 }
97 bytesRemaining -= bytesRead;
98 writePtr += bytesRead;
99 }
100
101 return challenge;
102 }
103
composeCertificateRequestV1(const ProtectedData & protectedData,const DeviceInfo & verifiedDeviceInfo,const std::vector<uint8_t> & challenge,const std::vector<uint8_t> & keysToSignMac,IRemotelyProvisionedComponent * provisionable)104 CborResult<Array> composeCertificateRequestV1(const ProtectedData& protectedData,
105 const DeviceInfo& verifiedDeviceInfo,
106 const std::vector<uint8_t>& challenge,
107 const std::vector<uint8_t>& keysToSignMac,
108 IRemotelyProvisionedComponent* provisionable) {
109 Array macedKeysToSign = Array()
110 .add(Map().add(1, 5).encode()) // alg: hmac-sha256
111 .add(Map()) // empty unprotected headers
112 .add(Null()) // nil for the payload
113 .add(keysToSignMac); // MAC as returned from the HAL
114
115 ErrMsgOr<std::unique_ptr<Map>> parsedVerifiedDeviceInfo =
116 parseAndValidateFactoryDeviceInfo(verifiedDeviceInfo.deviceInfo, provisionable);
117 if (!parsedVerifiedDeviceInfo) {
118 return {nullptr, parsedVerifiedDeviceInfo.moveMessage()};
119 }
120
121 auto [parsedProtectedData, ignore2, errMsg] = parse(protectedData.protectedData);
122 if (!parsedProtectedData) {
123 std::cerr << "Error parsing protected data: '" << errMsg << "'" << std::endl;
124 return {nullptr, errMsg};
125 }
126
127 Array deviceInfo = Array().add(parsedVerifiedDeviceInfo.moveValue()).add(Map());
128
129 auto certificateRequest = std::make_unique<Array>();
130 (*certificateRequest)
131 .add(std::move(deviceInfo))
132 .add(challenge)
133 .add(std::move(parsedProtectedData))
134 .add(std::move(macedKeysToSign));
135 return {std::move(certificateRequest), ""};
136 }
137
getCsrV1(std::string_view componentName,IRemotelyProvisionedComponent * irpc)138 CborResult<Array> getCsrV1(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
139 std::vector<uint8_t> keysToSignMac;
140 std::vector<MacedPublicKey> emptyKeys;
141 DeviceInfo verifiedDeviceInfo;
142 ProtectedData protectedData;
143 RpcHardwareInfo hwInfo;
144 ::ndk::ScopedAStatus status = irpc->getHardwareInfo(&hwInfo);
145 if (!status.isOk()) {
146 std::cerr << "Failed to get hardware info for '" << componentName
147 << "'. Description: " << status.getDescription() << "." << std::endl;
148 exit(-1);
149 }
150
151 const std::vector<uint8_t> eek = getProdEekChain(hwInfo.supportedEekCurve);
152 const std::vector<uint8_t> challenge = generateChallenge();
153 status = irpc->generateCertificateRequest(
154 /*test_mode=*/false, emptyKeys, eek, challenge, &verifiedDeviceInfo, &protectedData,
155 &keysToSignMac);
156 if (!status.isOk()) {
157 std::cerr << "Bundle extraction failed for '" << componentName
158 << "'. Description: " << status.getDescription() << "." << std::endl;
159 exit(-1);
160 }
161 return composeCertificateRequestV1(protectedData, verifiedDeviceInfo, challenge, keysToSignMac,
162 irpc);
163 }
164
selfTestGetCsrV1(std::string_view componentName,IRemotelyProvisionedComponent * irpc)165 void selfTestGetCsrV1(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
166 std::vector<uint8_t> keysToSignMac;
167 std::vector<MacedPublicKey> emptyKeys;
168 DeviceInfo verifiedDeviceInfo;
169 ProtectedData protectedData;
170 RpcHardwareInfo hwInfo;
171 ::ndk::ScopedAStatus status = irpc->getHardwareInfo(&hwInfo);
172 if (!status.isOk()) {
173 std::cerr << "Failed to get hardware info for '" << componentName
174 << "'. Description: " << status.getDescription() << "." << std::endl;
175 exit(-1);
176 }
177
178 const std::vector<uint8_t> eekId = {0, 1, 2, 3, 4, 5, 6, 7};
179 ErrMsgOr<EekChain> eekChain = generateEekChain(hwInfo.supportedEekCurve, /*length=*/3, eekId);
180 if (!eekChain) {
181 std::cerr << "Error generating test EEK certificate chain: " << eekChain.message();
182 exit(-1);
183 }
184 const std::vector<uint8_t> challenge = generateChallenge();
185 status = irpc->generateCertificateRequest(
186 /*test_mode=*/true, emptyKeys, eekChain->chain, challenge, &verifiedDeviceInfo,
187 &protectedData, &keysToSignMac);
188 if (!status.isOk()) {
189 std::cerr << "Error generating test cert chain for '" << componentName
190 << "'. Description: " << status.getDescription() << "." << std::endl;
191 exit(-1);
192 }
193
194 auto result = verifyFactoryProtectedData(verifiedDeviceInfo, /*keysToSign=*/{}, keysToSignMac,
195 protectedData, *eekChain, eekId,
196 hwInfo.supportedEekCurve, irpc, challenge);
197
198 if (!result) {
199 std::cerr << "Self test failed for IRemotelyProvisionedComponent '" << componentName
200 << "'. Error message: '" << result.message() << "'." << std::endl;
201 exit(-1);
202 }
203 }
204
composeCertificateRequestV3(const std::vector<uint8_t> & csr)205 CborResult<Array> composeCertificateRequestV3(const std::vector<uint8_t>& csr) {
206 const std::string kFingerprintProp = "ro.build.fingerprint";
207
208 auto [parsedCsr, _, csrErrMsg] = cppbor::parse(csr);
209 if (!parsedCsr) {
210 return {nullptr, csrErrMsg};
211 }
212 if (!parsedCsr->asArray()) {
213 return {nullptr, "CSR is not a CBOR array."};
214 }
215
216 if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
217 return {nullptr, "Unable to read build fingerprint"};
218 }
219
220 Map unverifiedDeviceInfo =
221 Map().add("fingerprint", ::android::base::GetProperty(kFingerprintProp, /*default=*/""));
222 parsedCsr->asArray()->add(std::move(unverifiedDeviceInfo));
223 return {std::unique_ptr<Array>(parsedCsr.release()->asArray()), ""};
224 }
225
getCsrV3(std::string_view componentName,IRemotelyProvisionedComponent * irpc,bool selfTest)226 CborResult<cppbor::Array> getCsrV3(std::string_view componentName,
227 IRemotelyProvisionedComponent* irpc, bool selfTest) {
228 std::vector<uint8_t> csr;
229 std::vector<MacedPublicKey> emptyKeys;
230 const std::vector<uint8_t> challenge = generateChallenge();
231
232 auto status = irpc->generateCertificateRequestV2(emptyKeys, challenge, &csr);
233 if (!status.isOk()) {
234 std::cerr << "Bundle extraction failed for '" << componentName
235 << "'. Description: " << status.getDescription() << "." << std::endl;
236 exit(-1);
237 }
238
239 if (selfTest) {
240 auto result = verifyFactoryCsr(/*keysToSign=*/cppbor::Array(), csr, irpc, challenge);
241 if (!result) {
242 std::cerr << "Self test failed for IRemotelyProvisionedComponent '" << componentName
243 << "'. Error message: '" << result.message() << "'." << std::endl;
244 exit(-1);
245 }
246 }
247
248 return composeCertificateRequestV3(csr);
249 }
250
getCsr(std::string_view componentName,IRemotelyProvisionedComponent * irpc,bool selfTest)251 CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc,
252 bool selfTest) {
253 RpcHardwareInfo hwInfo;
254 auto status = irpc->getHardwareInfo(&hwInfo);
255 if (!status.isOk()) {
256 std::cerr << "Failed to get hardware info for '" << componentName
257 << "'. Description: " << status.getDescription() << "." << std::endl;
258 exit(-1);
259 }
260
261 if (hwInfo.versionNumber < kVersionWithoutSuperencryption) {
262 if (selfTest) {
263 selfTestGetCsrV1(componentName, irpc);
264 }
265 return getCsrV1(componentName, irpc);
266 } else {
267 return getCsrV3(componentName, irpc, selfTest);
268 }
269 }
270
isRemoteProvisioningSupported(IRemotelyProvisionedComponent * irpc)271 bool isRemoteProvisioningSupported(IRemotelyProvisionedComponent* irpc) {
272 RpcHardwareInfo hwInfo;
273 auto status = irpc->getHardwareInfo(&hwInfo);
274 if (status.isOk()) {
275 return true;
276 }
277 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
278 return false;
279 }
280 std::cerr << "Unexpected error when getting hardware info. Description: "
281 << status.getDescription() << "." << std::endl;
282 exit(-1);
283 }
284