blob: d4842b1e21a3866b918cf8700653b241a09741c6 [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>
23#include <keymaster/cppcose/cppcose.h>
24#include <log/log.h>
25#include <vintf/VintfObject.h>
26
27using std::set;
28using std::string;
29using std::vector;
30
31using aidl::android::hardware::security::keymint::DeviceInfo;
32using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
33using aidl::android::hardware::security::keymint::MacedPublicKey;
34using aidl::android::hardware::security::keymint::ProtectedData;
35
36using android::vintf::HalManifest;
37using android::vintf::VintfObject;
38
39using namespace cppbor;
40using namespace cppcose;
41
42namespace {
43
44const string kPackage = "android.hardware.security.keymint";
45const string kInterface = "IRemotelyProvisionedComponent";
46const string kFormattedName = kPackage + "." + kInterface + "/";
47
48ErrMsgOr<vector<uint8_t>> generateEekChain(size_t length, const vector<uint8_t>& eekId) {
49 auto eekChain = cppbor::Array();
50
51 vector<uint8_t> prevPrivKey;
52 for (size_t i = 0; i < length - 1; ++i) {
53 vector<uint8_t> pubKey(ED25519_PUBLIC_KEY_LEN);
54 vector<uint8_t> privKey(ED25519_PRIVATE_KEY_LEN);
55
56 ED25519_keypair(pubKey.data(), privKey.data());
57
58 // The first signing key is self-signed.
59 if (prevPrivKey.empty()) prevPrivKey = privKey;
60
61 auto coseSign1 = constructCoseSign1(prevPrivKey,
62 cppbor::Map() /* payload CoseKey */
63 .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
64 .add(CoseKey::ALGORITHM, EDDSA)
65 .add(CoseKey::CURVE, ED25519)
66 .add(CoseKey::PUBKEY_X, pubKey)
67 .canonicalize()
68 .encode(),
69 {} /* AAD */);
70 if (!coseSign1) return coseSign1.moveMessage();
71 eekChain.add(coseSign1.moveValue());
72
73 prevPrivKey = privKey;
74 }
75
76 vector<uint8_t> pubKey(X25519_PUBLIC_VALUE_LEN);
77 vector<uint8_t> privKey(X25519_PRIVATE_KEY_LEN);
78 X25519_keypair(pubKey.data(), privKey.data());
79
80 auto coseSign1 = constructCoseSign1(prevPrivKey,
81 cppbor::Map() /* payload CoseKey */
82 .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
83 .add(CoseKey::KEY_ID, eekId)
84 .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256)
85 .add(CoseKey::CURVE, cppcose::X25519)
86 .add(CoseKey::PUBKEY_X, pubKey)
87 .canonicalize()
88 .encode(),
89 {} /* AAD */);
90 if (!coseSign1) return coseSign1.moveMessage();
91 eekChain.add(coseSign1.moveValue());
92
93 return eekChain.encode();
94}
95
96std::vector<uint8_t> getChallenge() {
97 return std::vector<uint8_t>(0);
98}
99
100std::vector<uint8_t> composeCertificateRequest(ProtectedData&& protectedData,
101 DeviceInfo&& deviceInfo) {
102 Array emptyMacedKeysToSign;
103 emptyMacedKeysToSign
104 .add(std::vector<uint8_t>(0)) // empty protected headers as bstr
105 .add(Map()) // empty unprotected headers
106 .add(Null()) // nil for the payload
107 .add(std::vector<uint8_t>(0)); // empty tag as bstr
108 Array certificateRequest;
109 certificateRequest.add(EncodedItem(std::move(deviceInfo.deviceInfo)))
110 .add(getChallenge()) // fake challenge
111 .add(EncodedItem(std::move(protectedData.protectedData)))
112 .add(std::move(emptyMacedKeysToSign));
113 return certificateRequest.encode();
114}
115
116int32_t errorMsg(string name) {
117 std::cerr << "Failed for rkp instance: " << name;
118 return -1;
119}
120
121} // namespace
122
123int main() {
124 std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest();
125 set<string> rkpNames = manifest->getAidlInstances(kPackage, kInterface);
126 for (auto name : rkpNames) {
127 string fullName = kFormattedName + name;
128 if (!AServiceManager_isDeclared(fullName.c_str())) {
129 ALOGE("Could not find the following instance declared in the manifest: %s\n",
130 fullName.c_str());
131 return errorMsg(name);
132 }
133 AIBinder* rkpAiBinder = AServiceManager_getService(fullName.c_str());
134 ::ndk::SpAIBinder rkp_binder(rkpAiBinder);
135 auto rkp_service = IRemotelyProvisionedComponent::fromBinder(rkp_binder);
136 std::vector<uint8_t> keysToSignMac;
137 std::vector<MacedPublicKey> emptyKeys;
138
139 // Replace this eek chain generation with the actual production GEEK
140 std::vector<uint8_t> eekId(10); // replace with real KID later (EEK fingerprint)
141 auto eekOrErr = generateEekChain(3 /* chainlength */, eekId);
142 if (!eekOrErr) {
143 ALOGE("Failed to generate test EEK somehow: %s", eekOrErr.message().c_str());
144 return errorMsg(name);
145 }
146
147 std::vector<uint8_t> eek = eekOrErr.moveValue();
148 DeviceInfo deviceInfo;
149 ProtectedData protectedData;
150 if (rkp_service) {
151 ALOGE("extracting bundle");
152 ::ndk::ScopedAStatus status = rkp_service->generateCertificateRequest(
153 true /* testMode */, emptyKeys, eek, getChallenge(), &deviceInfo, &protectedData,
154 &keysToSignMac);
155 if (!status.isOk()) {
156 ALOGE("Bundle extraction failed. Error code: %d", status.getServiceSpecificError());
157 return errorMsg(name);
158 }
159 std::cout << "\n";
160 std::vector<uint8_t> certificateRequest =
161 composeCertificateRequest(std::move(protectedData), std::move(deviceInfo));
162 std::copy(certificateRequest.begin(), certificateRequest.end(),
163 std::ostream_iterator<char>(std::cout));
164 }
165 }
166}