blob: 77d032bdc8136e7fa79d613af96db546a867b234 [file] [log] [blame]
Seth Moore708da932022-08-18 14:38:05 -07001/*
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/binder_manager.h>
21#include <cppbor.h>
Seth Mooreb84a1fb2022-09-13 12:02:49 -070022#include <cstddef>
23#include <cstdint>
24#include <cstring>
25#include <iterator>
Seth Moore708da932022-08-18 14:38:05 -070026#include <keymaster/cppcose/cppcose.h>
27#include <openssl/base64.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 <vector>
36
37#include "cppbor_parse.h"
38
39using aidl::android::hardware::security::keymint::DeviceInfo;
40using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
41using aidl::android::hardware::security::keymint::MacedPublicKey;
42using aidl::android::hardware::security::keymint::ProtectedData;
43using aidl::android::hardware::security::keymint::RpcHardwareInfo;
Seth Moore04756782022-09-13 16:09:15 -070044using aidl::android::hardware::security::keymint::remote_prov::EekChain;
45using aidl::android::hardware::security::keymint::remote_prov::generateEekChain;
Seth Moore708da932022-08-18 14:38:05 -070046using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
47using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
Seth Moore04756782022-09-13 16:09:15 -070048using aidl::android::hardware::security::keymint::remote_prov::parseAndValidateFactoryDeviceInfo;
49using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryProtectedData;
Seth Moore708da932022-08-18 14:38:05 -070050
51using namespace cppbor;
52using namespace cppcose;
53
54std::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
72 // BoringSSL automatically adds a NUL -- remove it from the string data
73 base64.pop_back();
74
75 return base64;
76}
77
78std::vector<uint8_t> generateChallenge() {
79 std::vector<uint8_t> challenge(kChallengeSize);
80
81 ssize_t bytesRemaining = static_cast<ssize_t>(challenge.size());
82 uint8_t* writePtr = challenge.data();
83 while (bytesRemaining > 0) {
84 int bytesRead = getrandom(writePtr, bytesRemaining, /*flags=*/0);
85 if (bytesRead < 0) {
86 if (errno == EINTR) {
87 continue;
88 } else {
89 std::cerr << errno << ": " << strerror(errno) << std::endl;
90 exit(-1);
91 }
92 }
93 bytesRemaining -= bytesRead;
94 writePtr += bytesRead;
95 }
96
97 return challenge;
98}
99
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700100CborResult<Array> composeCertificateRequest(const ProtectedData& protectedData,
101 const DeviceInfo& verifiedDeviceInfo,
102 const std::vector<uint8_t>& challenge,
103 const std::vector<uint8_t>& keysToSignMac,
104 IRemotelyProvisionedComponent* provisionable) {
Seth Moore708da932022-08-18 14:38:05 -0700105 Array macedKeysToSign = Array()
106 .add(Map().add(1, 5).encode()) // alg: hmac-sha256
107 .add(Map()) // empty unprotected headers
108 .add(Null()) // nil for the payload
109 .add(keysToSignMac); // MAC as returned from the HAL
110
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700111 ErrMsgOr<std::unique_ptr<Map>> parsedVerifiedDeviceInfo =
Seth Moore04756782022-09-13 16:09:15 -0700112 parseAndValidateFactoryDeviceInfo(verifiedDeviceInfo.deviceInfo, provisionable);
Seth Moore708da932022-08-18 14:38:05 -0700113 if (!parsedVerifiedDeviceInfo) {
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700114 return {nullptr, parsedVerifiedDeviceInfo.moveMessage()};
Seth Moore708da932022-08-18 14:38:05 -0700115 }
116
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700117 auto [parsedProtectedData, ignore2, errMsg] = parse(protectedData.protectedData);
Seth Moore708da932022-08-18 14:38:05 -0700118 if (!parsedProtectedData) {
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700119 std::cerr << "Error parsing protected data: '" << errMsg << "'" << std::endl;
Seth Moore708da932022-08-18 14:38:05 -0700120 return {nullptr, errMsg};
121 }
122
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700123 Array deviceInfo = Array().add(parsedVerifiedDeviceInfo.moveValue()).add(Map());
Seth Moore708da932022-08-18 14:38:05 -0700124
125 auto certificateRequest = std::make_unique<Array>();
126 (*certificateRequest)
127 .add(std::move(deviceInfo))
128 .add(challenge)
129 .add(std::move(parsedProtectedData))
130 .add(std::move(macedKeysToSign));
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700131 return {std::move(certificateRequest), ""};
Seth Moore708da932022-08-18 14:38:05 -0700132}
133
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700134CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
Seth Moore708da932022-08-18 14:38:05 -0700135 std::vector<uint8_t> keysToSignMac;
136 std::vector<MacedPublicKey> emptyKeys;
137 DeviceInfo verifiedDeviceInfo;
138 ProtectedData protectedData;
139 RpcHardwareInfo hwInfo;
140 ::ndk::ScopedAStatus status = irpc->getHardwareInfo(&hwInfo);
141 if (!status.isOk()) {
142 std::cerr << "Failed to get hardware info for '" << componentName
143 << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
144 exit(-1);
145 }
146
147 const std::vector<uint8_t> eek = getProdEekChain(hwInfo.supportedEekCurve);
148 const std::vector<uint8_t> challenge = generateChallenge();
149 status = irpc->generateCertificateRequest(
150 /*test_mode=*/false, emptyKeys, eek, challenge, &verifiedDeviceInfo, &protectedData,
151 &keysToSignMac);
152 if (!status.isOk()) {
153 std::cerr << "Bundle extraction failed for '" << componentName
154 << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
155 exit(-1);
156 }
Seth Mooreb84a1fb2022-09-13 12:02:49 -0700157 return composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac,
158 irpc);
Seth Moore708da932022-08-18 14:38:05 -0700159}
Seth Moore04756782022-09-13 16:09:15 -0700160
161void selfTestGetCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
162 std::vector<uint8_t> keysToSignMac;
163 std::vector<MacedPublicKey> emptyKeys;
164 DeviceInfo verifiedDeviceInfo;
165 ProtectedData protectedData;
166 RpcHardwareInfo hwInfo;
167 ::ndk::ScopedAStatus status = irpc->getHardwareInfo(&hwInfo);
168 if (!status.isOk()) {
169 std::cerr << "Failed to get hardware info for '" << componentName
170 << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
171 exit(-1);
172 }
173
174 const std::vector<uint8_t> eekId = {0, 1, 2, 3, 4, 5, 6, 7};
175 ErrMsgOr<EekChain> eekChain = generateEekChain(hwInfo.supportedEekCurve, /*length=*/3, eekId);
176 if (!eekChain) {
177 std::cerr << "Error generating test EEK certificate chain: " << eekChain.message();
178 exit(-1);
179 }
180 const std::vector<uint8_t> challenge = generateChallenge();
181 status = irpc->generateCertificateRequest(
182 /*test_mode=*/true, emptyKeys, eekChain->chain, challenge, &verifiedDeviceInfo,
183 &protectedData, &keysToSignMac);
184 if (!status.isOk()) {
185 std::cerr << "Error generating test cert chain for '" << componentName
186 << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
187 exit(-1);
188 }
189
190 auto result = verifyFactoryProtectedData(verifiedDeviceInfo, /*keysToSign=*/{}, keysToSignMac,
191 protectedData, *eekChain, eekId,
192 hwInfo.supportedEekCurve, irpc, challenge);
193
194 std::cout << "Self test successful." << std::endl;
195}