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
35using ::android::OK;
36using ::android::sp;
37using ::android::status_t;
38using ::android::hardware::configureRpcThreadpool;
39using ::android::hardware::joinRpcThreadpool;
40
41using ::android::hardware::keymaster::KeymasterDevice;
42using ::android::hardware::keymaster::translate_error_code;
43
44using ::nos::CitadeldProxyClient;
45using ::nos::AppClient;
46using ::nugget::app::keymaster::ProvisionPresharedSecretRequest;
47using ::nugget::app::keymaster::ProvisionPresharedSecretResponse;
48using ::nugget::app::keymaster::PresharedSecretStatus;
49using ErrorCodeNos = ::nugget::app::keymaster::ErrorCode;
50using ::android::hardware::keymaster::V4_0::ErrorCode;
51
52using KeymasterClient = ::nugget::app::keymaster::Keymaster;
53
54#ifdef ENABLE_QCOM_OTF_PROVISIONING
55// TODO(ngm): move this code into the HAL implementation.
56static 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.
83static 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
124static bool maybeProvision(KeymasterClient *) {
125    return true;
126}
127#endif
128
129int 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