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 <string>
18 #include <vector>
19 
20 #include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
21 #include <android/binder_manager.h>
22 #include <cppbor.h>
23 #include <gflags/gflags.h>
24 #include <keymaster/cppcose/cppcose.h>
25 #include <remote_prov/remote_prov_utils.h>
26 #include <sys/random.h>
27 
28 using aidl::android::hardware::security::keymint::DeviceInfo;
29 using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
30 using aidl::android::hardware::security::keymint::MacedPublicKey;
31 using aidl::android::hardware::security::keymint::ProtectedData;
32 using aidl::android::hardware::security::keymint::remote_prov::generateEekChain;
33 using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
34 using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
35 
36 using namespace cppbor;
37 using namespace cppcose;
38 
39 DEFINE_bool(test_mode, false, "If enabled, a fake EEK key/cert are used.");
40 
41 DEFINE_string(output_format, "csr", "How to format the output. Defaults to 'csr'.");
42 
43 namespace {
44 
45 // Various supported --output_format values.
46 constexpr std::string_view kBinaryCsrOutput = "csr";     // Just the raw csr as binary
47 constexpr std::string_view kBuildPlusCsr = "build+csr";  // Text-encoded (JSON) build
48                                                          // fingerprint plus CSR.
49 
50 constexpr size_t kChallengeSize = 16;
51 
generateChallenge()52 std::vector<uint8_t> generateChallenge() {
53     std::vector<uint8_t> challenge(kChallengeSize);
54 
55     ssize_t bytesRemaining = static_cast<ssize_t>(challenge.size());
56     uint8_t* writePtr = challenge.data();
57     while (bytesRemaining > 0) {
58         int bytesRead = getrandom(writePtr, bytesRemaining, /*flags=*/0);
59         if (bytesRead < 0 && errno != EINTR) {
60             std::cerr << errno << ": " << strerror(errno) << std::endl;
61             exit(-1);
62         }
63         bytesRemaining -= bytesRead;
64         writePtr += bytesRead;
65     }
66 
67     return challenge;
68 }
69 
composeCertificateRequest(const ProtectedData & protectedData,const DeviceInfo & verifiedDeviceInfo,const std::vector<uint8_t> & challenge,const std::vector<uint8_t> & keysToSignMac)70 Array composeCertificateRequest(const ProtectedData& protectedData,
71                                 const DeviceInfo& verifiedDeviceInfo,
72                                 const std::vector<uint8_t>& challenge,
73                                 const std::vector<uint8_t>& keysToSignMac) {
74     Array macedKeysToSign = Array()
75                                 .add(std::vector<uint8_t>(0))  // empty protected headers as bstr
76                                 .add(Map())                    // empty unprotected headers
77                                 .add(Null())                   // nil for the payload
78                                 .add(keysToSignMac);           // MAC as returned from the HAL
79 
80     Array deviceInfo =
81         Array().add(EncodedItem(verifiedDeviceInfo.deviceInfo)).add(Map());  // Empty device info
82 
83     Array certificateRequest = Array()
84                                    .add(std::move(deviceInfo))
85                                    .add(challenge)
86                                    .add(EncodedItem(protectedData.protectedData))
87                                    .add(std::move(macedKeysToSign));
88     return certificateRequest;
89 }
90 
getEekChain()91 std::vector<uint8_t> getEekChain() {
92     if (FLAGS_test_mode) {
93         const std::vector<uint8_t> kFakeEekId = {'f', 'a', 'k', 'e', 0};
94         auto eekOrErr = generateEekChain(3 /* chainlength */, kFakeEekId);
95         if (!eekOrErr) {
96             std::cerr << "Failed to generate test EEK somehow: " << eekOrErr.message() << std::endl;
97             exit(-1);
98         }
99         auto [eek, ignored_pubkey, ignored_privkey] = eekOrErr.moveValue();
100         return eek;
101     }
102 
103     return getProdEekChain();
104 }
105 
writeOutput(const Array & csr)106 void writeOutput(const Array& csr) {
107     if (FLAGS_output_format == kBinaryCsrOutput) {
108         auto bytes = csr.encode();
109         std::copy(bytes.begin(), bytes.end(), std::ostream_iterator<char>(std::cout));
110     } else if (FLAGS_output_format == kBuildPlusCsr) {
111         auto [json, error] = jsonEncodeCsrWithBuild(csr);
112         if (!error.empty()) {
113             std::cerr << "Error JSON encoding the output: " << error;
114             exit(1);
115         }
116         std::cout << json << std::endl;
117     } else {
118         std::cerr << "Unexpected output_format '" << FLAGS_output_format << "'" << std::endl;
119         std::cerr << "Valid formats:" << std::endl;
120         std::cerr << "  " << kBinaryCsrOutput << std::endl;
121         std::cerr << "  " << kBuildPlusCsr << std::endl;
122         exit(1);
123     }
124 }
125 
126 // Callback for AServiceManager_forEachDeclaredInstance that writes out a CSR
127 // for every IRemotelyProvisionedComponent.
getCsrForInstance(const char * name,void *)128 void getCsrForInstance(const char* name, void* /*context*/) {
129     const std::vector<uint8_t> challenge = generateChallenge();
130 
131     auto fullName = std::string(IRemotelyProvisionedComponent::descriptor) + "/" + name;
132     AIBinder* rkpAiBinder = AServiceManager_getService(fullName.c_str());
133     ::ndk::SpAIBinder rkp_binder(rkpAiBinder);
134     auto rkp_service = IRemotelyProvisionedComponent::fromBinder(rkp_binder);
135     if (!rkp_service) {
136         std::cerr << "Unable to get binder object for '" << fullName << "', skipping.";
137         return;
138     }
139 
140     std::vector<uint8_t> keysToSignMac;
141     std::vector<MacedPublicKey> emptyKeys;
142     DeviceInfo verifiedDeviceInfo;
143     ProtectedData protectedData;
144     ::ndk::ScopedAStatus status = rkp_service->generateCertificateRequest(
145         FLAGS_test_mode, emptyKeys, getEekChain(), challenge, &verifiedDeviceInfo, &protectedData,
146         &keysToSignMac);
147     if (!status.isOk()) {
148         std::cerr << "Bundle extraction failed for '" << fullName
149                   << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
150         exit(-1);
151     }
152     auto request =
153         composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac);
154     writeOutput(request);
155 }
156 
157 }  // namespace
158 
main(int argc,char ** argv)159 int main(int argc, char** argv) {
160     gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags=*/true);
161 
162     AServiceManager_forEachDeclaredInstance(IRemotelyProvisionedComponent::descriptor,
163                                             /*context=*/nullptr, getCsrForInstance);
164 
165     return 0;
166 }
167