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