1 /*
2 * Copyright (C) 2017 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 <android-base/logging.h>
18 #include <hidl/HidlTransportSupport.h>
19 #include <utils/StrongPointer.h>
20
21 #include <application.h>
22 #include <nos/AppClient.h>
23 #include <nos/CitadeldProxyClient.h>
24 #include <nos/debug.h>
25
26 #include <KeymasterDevice.h>
27 #include <Keymaster.client.h>
28
29 #ifdef ENABLE_QCOM_OTF_PROVISIONING
30 #include <KeymasterKeyProvision.h>
31 #endif
32 #include <nugget/app/keymaster/keymaster.pb.h>
33 #include "../proto_utils.h"
34
35 using ::android::OK;
36 using ::android::sp;
37 using ::android::status_t;
38 using ::android::hardware::configureRpcThreadpool;
39 using ::android::hardware::joinRpcThreadpool;
40
41 using ::android::hardware::keymaster::KeymasterDevice;
42 using ::android::hardware::keymaster::translate_error_code;
43
44 using ::nos::CitadeldProxyClient;
45 using ::nos::AppClient;
46 using ::nugget::app::keymaster::ProvisionPresharedSecretRequest;
47 using ::nugget::app::keymaster::ProvisionPresharedSecretResponse;
48 using ::nugget::app::keymaster::PresharedSecretStatus;
49 using ErrorCodeNos = ::nugget::app::keymaster::ErrorCode;
50 using ::android::hardware::keymaster::V4_0::ErrorCode;
51
52 using KeymasterClient = ::nugget::app::keymaster::Keymaster;
53
54 #ifdef ENABLE_QCOM_OTF_PROVISIONING
55 // TODO(ngm): move this code into the HAL implementation.
alreadyProvisioned(KeymasterClient * keymasterClient)56 static bool alreadyProvisioned(KeymasterClient *keymasterClient) {
57 ProvisionPresharedSecretRequest request;
58 ProvisionPresharedSecretResponse response;
59 request.set_get_status(true);
60
61 const uint32_t status = keymasterClient->ProvisionPresharedSecret(
62 request, &response);
63 if (status != APP_SUCCESS) {
64 LOG(ERROR) << "KM ProvisionPresharedSecret() failed with status: "
65 << ::nos::StatusCodeString(status);
66 return false;
67 }
68 const ErrorCode error_code = translate_error_code(response.error_code());
69 if (error_code != ErrorCode::OK) {
70 LOG(ERROR) << "ProvisionPresharedSecret() response error code: "
71 << toString(error_code);
72 return false;
73 }
74 if (response.status() == PresharedSecretStatus::ALREADY_SET) {
75 LOG(INFO) << "Preshared key previously established";
76 return true;
77 }
78
79 return false;
80 }
81
82 // TODO(ngm): move this code into the HAL implementation.
maybeProvision(KeymasterClient * keymasterClient)83 static bool maybeProvision(KeymasterClient *keymasterClient) {
84 if (alreadyProvisioned(keymasterClient)) {
85 return true;
86 }
87
88 // Attempt to provision the preshared-secret.
89 keymasterdevice::KeymasterKeyProvision qc_km_provisioning;
90 int result = qc_km_provisioning.KeyMasterProvisionInit();
91 if (result) {
92 LOG(ERROR) << "KeyMasterProvisionInit error: " << result;
93 return false;
94 }
95 std::vector<uint8_t> preshared_secret(32);
96 result = qc_km_provisioning.GetPreSharedSecret(
97 preshared_secret.data(), preshared_secret.size());
98 if (result != KM_ERROR_OK) {
99 LOG(ERROR) << "GetPreSharedSecret error: " << result;
100 return false;
101 }
102
103 ProvisionPresharedSecretRequest request;
104 ProvisionPresharedSecretResponse response;
105 request.set_get_status(false);
106 request.set_preshared_secret(preshared_secret.data(),
107 preshared_secret.size());
108 const uint32_t status = keymasterClient->ProvisionPresharedSecret(
109 request, &response);
110 if (status != APP_SUCCESS) {
111 LOG(ERROR) << "KM ProvisionPresharedSecret() failed with status: "
112 << ::nos::StatusCodeString(status);
113 return false;
114 }
115 if (response.error_code() != ErrorCodeNos::OK) {
116 LOG(ERROR) << "KM ProvisionPresharedSecret() failed with code: "
117 << response.error_code();
118 return false;
119 }
120
121 return true;
122 }
123 #else
maybeProvision(KeymasterClient *)124 static bool maybeProvision(KeymasterClient *) {
125 return true;
126 }
127 #endif
128
main()129 int main() {
130 LOG(INFO) << "Keymaster HAL service starting";
131
132 // Connect to citadeld
133 CitadeldProxyClient citadeldProxy;
134 citadeldProxy.Open();
135 if (!citadeldProxy.IsOpen()) {
136 LOG(FATAL) << "Failed to open citadeld client";
137 }
138
139 // This thread will become the only thread of the daemon
140 constexpr bool thisThreadWillJoinPool = true;
141 configureRpcThreadpool(1, thisThreadWillJoinPool);
142
143 // Start the HAL service
144 KeymasterClient keymasterClient{citadeldProxy};
145 sp<KeymasterDevice> keymaster = new KeymasterDevice{keymasterClient};
146
147 if (maybeProvision(&keymasterClient)) {
148 const status_t status = keymaster->registerAsService("strongbox");
149 if (status != OK) {
150 LOG(FATAL) << "Failed to register Keymaster as a service (status: "
151 << status << ")";
152 }
153 } else {
154 LOG(ERROR) << "Skipping Keymaster registration, as provisioning failed";
155 // Leave the service running to avoid being restarted.
156 }
157
158 joinRpcThreadpool();
159 return -1; // Should never be reached
160 }
161