blob: 5878d2278035b4838d5d5b8a2845d99390003e08 [file] [log] [blame]
Max Biresf60987e2021-04-16 13:35:20 -07001/*
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>
Seth Moore01688562021-06-22 12:59:32 -070023#include <gflags/gflags.h>
Max Biresf60987e2021-04-16 13:35:20 -070024#include <keymaster/cppcose/cppcose.h>
Seth Moore6dfb02a2021-06-18 15:43:09 -070025#include <remote_prov/remote_prov_utils.h>
Seth Moore5a40fa72021-06-22 13:48:59 -070026#include <sys/random.h>
Max Biresf60987e2021-04-16 13:35:20 -070027
28using aidl::android::hardware::security::keymint::DeviceInfo;
29using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
30using aidl::android::hardware::security::keymint::MacedPublicKey;
31using aidl::android::hardware::security::keymint::ProtectedData;
Seth Moore6dfb02a2021-06-18 15:43:09 -070032using aidl::android::hardware::security::keymint::remote_prov::generateEekChain;
Seth Moore01688562021-06-22 12:59:32 -070033using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
Seth Mooree44aad22021-06-25 17:38:24 -070034using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
Max Biresf60987e2021-04-16 13:35:20 -070035
Max Biresf60987e2021-04-16 13:35:20 -070036using namespace cppbor;
37using namespace cppcose;
38
Seth Moore01688562021-06-22 12:59:32 -070039DEFINE_bool(test_mode, false, "If enabled, a fake EEK key/cert are used.");
40
Seth Mooree44aad22021-06-25 17:38:24 -070041DEFINE_string(output_format, "csr", "How to format the output. Defaults to 'csr'.");
42
Max Biresf60987e2021-04-16 13:35:20 -070043namespace {
44
Seth Mooree44aad22021-06-25 17:38:24 -070045// Various supported --output_format values.
46constexpr std::string_view kBinaryCsrOutput = "csr"; // Just the raw csr as binary
47constexpr std::string_view kBuildPlusCsr = "build+csr"; // Text-encoded (JSON) build
48 // fingerprint plus CSR.
49
Seth Moore5a40fa72021-06-22 13:48:59 -070050constexpr size_t kChallengeSize = 16;
51
52std::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);
Seth Moore59146252021-07-02 08:59:23 -070059 if (bytesRead < 0 && errno != EINTR) {
60 std::cerr << errno << ": " << strerror(errno) << std::endl;
61 exit(-1);
Seth Moore5a40fa72021-06-22 13:48:59 -070062 }
63 bytesRemaining -= bytesRead;
64 writePtr += bytesRead;
65 }
66
67 return challenge;
Max Biresf60987e2021-04-16 13:35:20 -070068}
69
Seth Mooree44aad22021-06-25 17:38:24 -070070Array composeCertificateRequest(ProtectedData&& protectedData, DeviceInfo&& deviceInfo,
71 const std::vector<uint8_t>& challenge) {
Max Biresf60987e2021-04-16 13:35:20 -070072 Array emptyMacedKeysToSign;
73 emptyMacedKeysToSign
74 .add(std::vector<uint8_t>(0)) // empty protected headers as bstr
75 .add(Map()) // empty unprotected headers
76 .add(Null()) // nil for the payload
77 .add(std::vector<uint8_t>(0)); // empty tag as bstr
78 Array certificateRequest;
79 certificateRequest.add(EncodedItem(std::move(deviceInfo.deviceInfo)))
Seth Moore5a40fa72021-06-22 13:48:59 -070080 .add(challenge)
Max Biresf60987e2021-04-16 13:35:20 -070081 .add(EncodedItem(std::move(protectedData.protectedData)))
82 .add(std::move(emptyMacedKeysToSign));
Seth Mooree44aad22021-06-25 17:38:24 -070083 return certificateRequest;
Max Biresf60987e2021-04-16 13:35:20 -070084}
85
Seth Moore01688562021-06-22 12:59:32 -070086std::vector<uint8_t> getEekChain() {
87 if (FLAGS_test_mode) {
88 const std::vector<uint8_t> kFakeEekId = {'f', 'a', 'k', 'e', 0};
89 auto eekOrErr = generateEekChain(3 /* chainlength */, kFakeEekId);
Seth Moore59146252021-07-02 08:59:23 -070090 if (!eekOrErr) {
91 std::cerr << "Failed to generate test EEK somehow: " << eekOrErr.message() << std::endl;
92 exit(-1);
93 }
Seth Moore01688562021-06-22 12:59:32 -070094 auto [eek, ignored_pubkey, ignored_privkey] = eekOrErr.moveValue();
95 return eek;
96 }
97
98 return getProdEekChain();
99}
100
Seth Mooree44aad22021-06-25 17:38:24 -0700101void writeOutput(const Array& csr) {
102 if (FLAGS_output_format == kBinaryCsrOutput) {
103 auto bytes = csr.encode();
104 std::copy(bytes.begin(), bytes.end(), std::ostream_iterator<char>(std::cout));
105 } else if (FLAGS_output_format == kBuildPlusCsr) {
106 auto [json, error] = jsonEncodeCsrWithBuild(csr);
107 if (!error.empty()) {
108 std::cerr << "Error JSON encoding the output: " << error;
109 exit(1);
110 }
111 std::cout << json << std::endl;
112 } else {
113 std::cerr << "Unexpected output_format '" << FLAGS_output_format << "'" << std::endl;
114 std::cerr << "Valid formats:" << std::endl;
115 std::cerr << " " << kBinaryCsrOutput << std::endl;
116 std::cerr << " " << kBuildPlusCsr << std::endl;
117 exit(1);
118 }
119}
120
Seth Moore59146252021-07-02 08:59:23 -0700121// Callback for AServiceManager_forEachDeclaredInstance that writes out a CSR
122// for every IRemotelyProvisionedComponent.
123void getCsrForInstance(const char* name, void* /*context*/) {
124 const std::vector<uint8_t> challenge = generateChallenge();
125
126 auto fullName = std::string(IRemotelyProvisionedComponent::descriptor) + "/" + name;
127 AIBinder* rkpAiBinder = AServiceManager_getService(fullName.c_str());
128 ::ndk::SpAIBinder rkp_binder(rkpAiBinder);
129 auto rkp_service = IRemotelyProvisionedComponent::fromBinder(rkp_binder);
130 if (!rkp_service) {
131 std::cerr << "Unable to get binder object for '" << fullName << "', skipping.";
132 return;
133 }
134
135 std::vector<uint8_t> keysToSignMac;
136 std::vector<MacedPublicKey> emptyKeys;
137 DeviceInfo deviceInfo;
138 ProtectedData protectedData;
139 ::ndk::ScopedAStatus status = rkp_service->generateCertificateRequest(
140 FLAGS_test_mode, emptyKeys, getEekChain(), challenge, &deviceInfo, &protectedData,
141 &keysToSignMac);
142 if (!status.isOk()) {
143 std::cerr << "Bundle extraction failed for '" << fullName
144 << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
145 exit(-1);
146 }
147 writeOutput(
148 composeCertificateRequest(std::move(protectedData), std::move(deviceInfo), challenge));
149}
150
Max Biresf60987e2021-04-16 13:35:20 -0700151} // namespace
152
Seth Moore01688562021-06-22 12:59:32 -0700153int main(int argc, char** argv) {
154 gflags::ParseCommandLineFlags(&argc, &argv, /*remove_flags=*/true);
155
Seth Moore59146252021-07-02 08:59:23 -0700156 AServiceManager_forEachDeclaredInstance(IRemotelyProvisionedComponent::descriptor,
157 /*context=*/nullptr, getCsrForInstance);
Seth Moore01688562021-06-22 12:59:32 -0700158
Seth Moore59146252021-07-02 08:59:23 -0700159 return 0;
Max Biresf60987e2021-04-16 13:35:20 -0700160}