• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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