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