| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 1 | /* | 
|  | 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> | 
| Seth Moore | 7fc83ab | 2023-02-24 16:25:07 -0800 | [diff] [blame] | 20 | #include <android-base/properties.h> | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 21 | #include <android/binder_manager.h> | 
|  | 22 | #include <cppbor.h> | 
| Seth Moore | b84a1fb | 2022-09-13 12:02:49 -0700 | [diff] [blame] | 23 | #include <cstddef> | 
|  | 24 | #include <cstdint> | 
|  | 25 | #include <cstring> | 
|  | 26 | #include <iterator> | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 27 | #include <keymaster/cppcose/cppcose.h> | 
|  | 28 | #include <openssl/base64.h> | 
|  | 29 | #include <remote_prov/remote_prov_utils.h> | 
|  | 30 | #include <sys/random.h> | 
|  | 31 |  | 
|  | 32 | #include <memory> | 
|  | 33 | #include <optional> | 
|  | 34 | #include <string> | 
|  | 35 | #include <string_view> | 
|  | 36 | #include <vector> | 
|  | 37 |  | 
|  | 38 | #include "cppbor_parse.h" | 
|  | 39 |  | 
|  | 40 | using aidl::android::hardware::security::keymint::DeviceInfo; | 
|  | 41 | using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent; | 
|  | 42 | using aidl::android::hardware::security::keymint::MacedPublicKey; | 
|  | 43 | using aidl::android::hardware::security::keymint::ProtectedData; | 
|  | 44 | using aidl::android::hardware::security::keymint::RpcHardwareInfo; | 
| Seth Moore | 0475678 | 2022-09-13 16:09:15 -0700 | [diff] [blame] | 45 | using aidl::android::hardware::security::keymint::remote_prov::EekChain; | 
|  | 46 | using aidl::android::hardware::security::keymint::remote_prov::generateEekChain; | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 47 | using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain; | 
|  | 48 | using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild; | 
| Seth Moore | 0475678 | 2022-09-13 16:09:15 -0700 | [diff] [blame] | 49 | using aidl::android::hardware::security::keymint::remote_prov::parseAndValidateFactoryDeviceInfo; | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 50 | using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryCsr; | 
| Seth Moore | 0475678 | 2022-09-13 16:09:15 -0700 | [diff] [blame] | 51 | using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryProtectedData; | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 52 |  | 
|  | 53 | using namespace cppbor; | 
|  | 54 | using namespace cppcose; | 
|  | 55 |  | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 56 | constexpr size_t kVersionWithoutSuperencryption = 3; | 
|  | 57 |  | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 58 | std::string toBase64(const std::vector<uint8_t>& buffer) { | 
|  | 59 | size_t base64Length; | 
|  | 60 | int rc = EVP_EncodedLength(&base64Length, buffer.size()); | 
|  | 61 | if (!rc) { | 
|  | 62 | std::cerr << "Error getting base64 length. Size overflow?" << std::endl; | 
|  | 63 | exit(-1); | 
|  | 64 | } | 
|  | 65 |  | 
|  | 66 | std::string base64(base64Length, ' '); | 
|  | 67 | rc = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64.data()), buffer.data(), buffer.size()); | 
|  | 68 | ++rc;  // Account for NUL, which BoringSSL does not for some reason. | 
|  | 69 | if (rc != base64Length) { | 
|  | 70 | std::cerr << "Error writing base64. Expected " << base64Length | 
|  | 71 | << " bytes to be written, but " << rc << " bytes were actually written." | 
|  | 72 | << std::endl; | 
|  | 73 | exit(-1); | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | // BoringSSL automatically adds a NUL -- remove it from the string data | 
|  | 77 | base64.pop_back(); | 
|  | 78 |  | 
|  | 79 | return base64; | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | std::vector<uint8_t> generateChallenge() { | 
|  | 83 | std::vector<uint8_t> challenge(kChallengeSize); | 
|  | 84 |  | 
|  | 85 | ssize_t bytesRemaining = static_cast<ssize_t>(challenge.size()); | 
|  | 86 | uint8_t* writePtr = challenge.data(); | 
|  | 87 | while (bytesRemaining > 0) { | 
|  | 88 | int bytesRead = getrandom(writePtr, bytesRemaining, /*flags=*/0); | 
|  | 89 | if (bytesRead < 0) { | 
|  | 90 | if (errno == EINTR) { | 
|  | 91 | continue; | 
|  | 92 | } else { | 
|  | 93 | std::cerr << errno << ": " << strerror(errno) << std::endl; | 
|  | 94 | exit(-1); | 
|  | 95 | } | 
|  | 96 | } | 
|  | 97 | bytesRemaining -= bytesRead; | 
|  | 98 | writePtr += bytesRead; | 
|  | 99 | } | 
|  | 100 |  | 
|  | 101 | return challenge; | 
|  | 102 | } | 
|  | 103 |  | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 104 | CborResult<Array> composeCertificateRequestV1(const ProtectedData& protectedData, | 
|  | 105 | const DeviceInfo& verifiedDeviceInfo, | 
|  | 106 | const std::vector<uint8_t>& challenge, | 
|  | 107 | const std::vector<uint8_t>& keysToSignMac, | 
|  | 108 | IRemotelyProvisionedComponent* provisionable) { | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 109 | Array macedKeysToSign = Array() | 
|  | 110 | .add(Map().add(1, 5).encode())  // alg: hmac-sha256 | 
|  | 111 | .add(Map())                     // empty unprotected headers | 
|  | 112 | .add(Null())                    // nil for the payload | 
|  | 113 | .add(keysToSignMac);            // MAC as returned from the HAL | 
|  | 114 |  | 
| Seth Moore | b84a1fb | 2022-09-13 12:02:49 -0700 | [diff] [blame] | 115 | ErrMsgOr<std::unique_ptr<Map>> parsedVerifiedDeviceInfo = | 
| Seth Moore | 0475678 | 2022-09-13 16:09:15 -0700 | [diff] [blame] | 116 | parseAndValidateFactoryDeviceInfo(verifiedDeviceInfo.deviceInfo, provisionable); | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 117 | if (!parsedVerifiedDeviceInfo) { | 
| Seth Moore | b84a1fb | 2022-09-13 12:02:49 -0700 | [diff] [blame] | 118 | return {nullptr, parsedVerifiedDeviceInfo.moveMessage()}; | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 119 | } | 
|  | 120 |  | 
| Seth Moore | b84a1fb | 2022-09-13 12:02:49 -0700 | [diff] [blame] | 121 | auto [parsedProtectedData, ignore2, errMsg] = parse(protectedData.protectedData); | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 122 | if (!parsedProtectedData) { | 
| Seth Moore | b84a1fb | 2022-09-13 12:02:49 -0700 | [diff] [blame] | 123 | std::cerr << "Error parsing protected data: '" << errMsg << "'" << std::endl; | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 124 | return {nullptr, errMsg}; | 
|  | 125 | } | 
|  | 126 |  | 
| Seth Moore | b84a1fb | 2022-09-13 12:02:49 -0700 | [diff] [blame] | 127 | Array deviceInfo = Array().add(parsedVerifiedDeviceInfo.moveValue()).add(Map()); | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 128 |  | 
|  | 129 | auto certificateRequest = std::make_unique<Array>(); | 
|  | 130 | (*certificateRequest) | 
|  | 131 | .add(std::move(deviceInfo)) | 
|  | 132 | .add(challenge) | 
|  | 133 | .add(std::move(parsedProtectedData)) | 
|  | 134 | .add(std::move(macedKeysToSign)); | 
| Seth Moore | b84a1fb | 2022-09-13 12:02:49 -0700 | [diff] [blame] | 135 | return {std::move(certificateRequest), ""}; | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 136 | } | 
|  | 137 |  | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 138 | CborResult<Array> getCsrV1(std::string_view componentName, IRemotelyProvisionedComponent* irpc) { | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 139 | std::vector<uint8_t> keysToSignMac; | 
|  | 140 | std::vector<MacedPublicKey> emptyKeys; | 
|  | 141 | DeviceInfo verifiedDeviceInfo; | 
|  | 142 | ProtectedData protectedData; | 
|  | 143 | RpcHardwareInfo hwInfo; | 
|  | 144 | ::ndk::ScopedAStatus status = irpc->getHardwareInfo(&hwInfo); | 
|  | 145 | if (!status.isOk()) { | 
|  | 146 | std::cerr << "Failed to get hardware info for '" << componentName | 
| Robert Shih | 6c3e15b | 2023-12-18 20:09:02 -0800 | [diff] [blame] | 147 | << "'. Description: " << status.getDescription() << "." << std::endl; | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 148 | exit(-1); | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | const std::vector<uint8_t> eek = getProdEekChain(hwInfo.supportedEekCurve); | 
|  | 152 | const std::vector<uint8_t> challenge = generateChallenge(); | 
|  | 153 | status = irpc->generateCertificateRequest( | 
|  | 154 | /*test_mode=*/false, emptyKeys, eek, challenge, &verifiedDeviceInfo, &protectedData, | 
|  | 155 | &keysToSignMac); | 
|  | 156 | if (!status.isOk()) { | 
|  | 157 | std::cerr << "Bundle extraction failed for '" << componentName | 
| Robert Shih | 6c3e15b | 2023-12-18 20:09:02 -0800 | [diff] [blame] | 158 | << "'. Description: " << status.getDescription() << "." << std::endl; | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 159 | exit(-1); | 
|  | 160 | } | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 161 | return composeCertificateRequestV1(protectedData, verifiedDeviceInfo, challenge, keysToSignMac, | 
|  | 162 | irpc); | 
| Seth Moore | 708da93 | 2022-08-18 14:38:05 -0700 | [diff] [blame] | 163 | } | 
| Seth Moore | 0475678 | 2022-09-13 16:09:15 -0700 | [diff] [blame] | 164 |  | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 165 | void selfTestGetCsrV1(std::string_view componentName, IRemotelyProvisionedComponent* irpc) { | 
| Seth Moore | 0475678 | 2022-09-13 16:09:15 -0700 | [diff] [blame] | 166 | std::vector<uint8_t> keysToSignMac; | 
|  | 167 | std::vector<MacedPublicKey> emptyKeys; | 
|  | 168 | DeviceInfo verifiedDeviceInfo; | 
|  | 169 | ProtectedData protectedData; | 
|  | 170 | RpcHardwareInfo hwInfo; | 
|  | 171 | ::ndk::ScopedAStatus status = irpc->getHardwareInfo(&hwInfo); | 
|  | 172 | if (!status.isOk()) { | 
|  | 173 | std::cerr << "Failed to get hardware info for '" << componentName | 
| Robert Shih | 6c3e15b | 2023-12-18 20:09:02 -0800 | [diff] [blame] | 174 | << "'. Description: " << status.getDescription() << "." << std::endl; | 
| Seth Moore | 0475678 | 2022-09-13 16:09:15 -0700 | [diff] [blame] | 175 | exit(-1); | 
|  | 176 | } | 
|  | 177 |  | 
|  | 178 | const std::vector<uint8_t> eekId = {0, 1, 2, 3, 4, 5, 6, 7}; | 
|  | 179 | ErrMsgOr<EekChain> eekChain = generateEekChain(hwInfo.supportedEekCurve, /*length=*/3, eekId); | 
|  | 180 | if (!eekChain) { | 
|  | 181 | std::cerr << "Error generating test EEK certificate chain: " << eekChain.message(); | 
|  | 182 | exit(-1); | 
|  | 183 | } | 
|  | 184 | const std::vector<uint8_t> challenge = generateChallenge(); | 
|  | 185 | status = irpc->generateCertificateRequest( | 
|  | 186 | /*test_mode=*/true, emptyKeys, eekChain->chain, challenge, &verifiedDeviceInfo, | 
|  | 187 | &protectedData, &keysToSignMac); | 
|  | 188 | if (!status.isOk()) { | 
|  | 189 | std::cerr << "Error generating test cert chain for '" << componentName | 
| Robert Shih | 6c3e15b | 2023-12-18 20:09:02 -0800 | [diff] [blame] | 190 | << "'. Description: " << status.getDescription() << "." << std::endl; | 
| Seth Moore | 0475678 | 2022-09-13 16:09:15 -0700 | [diff] [blame] | 191 | exit(-1); | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | auto result = verifyFactoryProtectedData(verifiedDeviceInfo, /*keysToSign=*/{}, keysToSignMac, | 
|  | 195 | protectedData, *eekChain, eekId, | 
|  | 196 | hwInfo.supportedEekCurve, irpc, challenge); | 
|  | 197 |  | 
| Seth Moore | dff09d0 | 2023-05-31 09:38:47 -0700 | [diff] [blame] | 198 | if (!result) { | 
|  | 199 | std::cerr << "Self test failed for IRemotelyProvisionedComponent '" << componentName | 
|  | 200 | << "'. Error message: '" << result.message() << "'." << std::endl; | 
|  | 201 | exit(-1); | 
|  | 202 | } | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 203 | } | 
|  | 204 |  | 
|  | 205 | CborResult<Array> composeCertificateRequestV3(const std::vector<uint8_t>& csr) { | 
| Seth Moore | 7fc83ab | 2023-02-24 16:25:07 -0800 | [diff] [blame] | 206 | const std::string kFingerprintProp = "ro.build.fingerprint"; | 
|  | 207 |  | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 208 | auto [parsedCsr, _, csrErrMsg] = cppbor::parse(csr); | 
|  | 209 | if (!parsedCsr) { | 
|  | 210 | return {nullptr, csrErrMsg}; | 
|  | 211 | } | 
|  | 212 | if (!parsedCsr->asArray()) { | 
|  | 213 | return {nullptr, "CSR is not a CBOR array."}; | 
|  | 214 | } | 
|  | 215 |  | 
| Seth Moore | 7fc83ab | 2023-02-24 16:25:07 -0800 | [diff] [blame] | 216 | if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) { | 
|  | 217 | return {nullptr, "Unable to read build fingerprint"}; | 
|  | 218 | } | 
|  | 219 |  | 
|  | 220 | Map unverifiedDeviceInfo = | 
|  | 221 | Map().add("fingerprint", ::android::base::GetProperty(kFingerprintProp, /*default=*/"")); | 
|  | 222 | parsedCsr->asArray()->add(std::move(unverifiedDeviceInfo)); | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 223 | return {std::unique_ptr<Array>(parsedCsr.release()->asArray()), ""}; | 
|  | 224 | } | 
|  | 225 |  | 
|  | 226 | CborResult<cppbor::Array> getCsrV3(std::string_view componentName, | 
| Seth Moore | dff09d0 | 2023-05-31 09:38:47 -0700 | [diff] [blame] | 227 | IRemotelyProvisionedComponent* irpc, bool selfTest) { | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 228 | std::vector<uint8_t> csr; | 
|  | 229 | std::vector<MacedPublicKey> emptyKeys; | 
|  | 230 | const std::vector<uint8_t> challenge = generateChallenge(); | 
|  | 231 |  | 
|  | 232 | auto status = irpc->generateCertificateRequestV2(emptyKeys, challenge, &csr); | 
|  | 233 | if (!status.isOk()) { | 
|  | 234 | std::cerr << "Bundle extraction failed for '" << componentName | 
| Robert Shih | 6c3e15b | 2023-12-18 20:09:02 -0800 | [diff] [blame] | 235 | << "'. Description: " << status.getDescription() << "." << std::endl; | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 236 | exit(-1); | 
|  | 237 | } | 
|  | 238 |  | 
| Seth Moore | dff09d0 | 2023-05-31 09:38:47 -0700 | [diff] [blame] | 239 | if (selfTest) { | 
|  | 240 | auto result = verifyFactoryCsr(/*keysToSign=*/cppbor::Array(), csr, irpc, challenge); | 
|  | 241 | if (!result) { | 
|  | 242 | std::cerr << "Self test failed for IRemotelyProvisionedComponent '" << componentName | 
|  | 243 | << "'. Error message: '" << result.message() << "'." << std::endl; | 
|  | 244 | exit(-1); | 
|  | 245 | } | 
|  | 246 | } | 
|  | 247 |  | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 248 | return composeCertificateRequestV3(csr); | 
|  | 249 | } | 
|  | 250 |  | 
| Seth Moore | dff09d0 | 2023-05-31 09:38:47 -0700 | [diff] [blame] | 251 | CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc, | 
|  | 252 | bool selfTest) { | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 253 | RpcHardwareInfo hwInfo; | 
|  | 254 | auto status = irpc->getHardwareInfo(&hwInfo); | 
|  | 255 | if (!status.isOk()) { | 
|  | 256 | std::cerr << "Failed to get hardware info for '" << componentName | 
| Robert Shih | 6c3e15b | 2023-12-18 20:09:02 -0800 | [diff] [blame] | 257 | << "'. Description: " << status.getDescription() << "." << std::endl; | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 258 | exit(-1); | 
|  | 259 | } | 
|  | 260 |  | 
|  | 261 | if (hwInfo.versionNumber < kVersionWithoutSuperencryption) { | 
| Seth Moore | dff09d0 | 2023-05-31 09:38:47 -0700 | [diff] [blame] | 262 | if (selfTest) { | 
|  | 263 | selfTestGetCsrV1(componentName, irpc); | 
|  | 264 | } | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 265 | return getCsrV1(componentName, irpc); | 
|  | 266 | } else { | 
| Seth Moore | dff09d0 | 2023-05-31 09:38:47 -0700 | [diff] [blame] | 267 | return getCsrV3(componentName, irpc, selfTest); | 
| Tri Vo | ee773a2 | 2022-10-26 16:07:52 -0700 | [diff] [blame] | 268 | } | 
|  | 269 | } |