Merge branch 'goog/upstream-master' into bill-nos-release
am: 7aead66273
Change-Id: I008ab8363a446fe09f8d1041a51a60f5fed02da6
diff --git a/hals/keymaster/KeymasterDevice.cpp b/hals/keymaster/KeymasterDevice.cpp
index dc89fbb..ee5c7d4 100644
--- a/hals/keymaster/KeymasterDevice.cpp
+++ b/hals/keymaster/KeymasterDevice.cpp
@@ -27,14 +27,56 @@
#include <keymasterV4_0/key_param_output.h>
#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+#include <algorithm>
namespace android {
namespace hardware {
namespace keymaster {
+namespace {
+
+constexpr char PROPERTY_OS_VERSION[] = "ro.build.version.release";
+constexpr char PROPERTY_OS_PATCHLEVEL[] = "ro.build.version.security_patch";
+constexpr char PROPERTY_VENDOR_PATCHLEVEL[] = "ro.vendor.build.security_patch";
+
+std::string DigitsOnly(const std::string& code) {
+ // Keep digits only.
+ std::string filtered_code;
+ std::copy_if(code.begin(), code.end(), std::back_inserter(filtered_code),
+ isdigit);
+ return filtered_code;
+}
+
+uint32_t DateCodeToUint32(const std::string& code, bool include_day) {
+ // Keep digits only.
+ std::string filtered_code = DigitsOnly(code);
+
+ // Return 0 if the date string has an unexpected number of digits.
+ uint32_t return_value = 0;
+ if (filtered_code.size() == 8) {
+ return_value = std::stoi(filtered_code);
+ if (!include_day) {
+ return_value /= 100;
+ }
+ } else if (filtered_code.size() == 6) {
+ return_value = std::stoi(filtered_code);
+ if (include_day) {
+ return_value *= 100;
+ }
+ }
+ return return_value;
+}
+
+} // namespace
+
// std
using std::string;
+// base
+using ::android::base::GetProperty;
+
// libhidl
using ::android::hardware::Void;
@@ -84,6 +126,10 @@
using ::nugget::app::keymaster::ComputeSharedHmacResponse;
using ::nugget::app::keymaster::GetHmacSharingParametersRequest;
using ::nugget::app::keymaster::GetHmacSharingParametersResponse;
+using ::nugget::app::keymaster::SetSystemVersionInfoRequest;
+using ::nugget::app::keymaster::SetSystemVersionInfoResponse;
+using ::nugget::app::keymaster::GetBootInfoRequest;
+using ::nugget::app::keymaster::GetBootInfoResponse;
// KM 4.0 types
using ::nugget::app::keymaster::ImportWrappedKeyRequest;
@@ -148,6 +194,19 @@
// Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
+KeymasterDevice::KeymasterDevice(KeymasterClient& keymaster) :
+ _keymaster{keymaster} {
+ _os_version = std::stoi(DigitsOnly(GetProperty(PROPERTY_OS_VERSION, "")));
+ _os_patchlevel = DateCodeToUint32(GetProperty(PROPERTY_OS_PATCHLEVEL, ""),
+ false /* include_day */);
+ _vendor_patchlevel = DateCodeToUint32(
+ GetProperty(PROPERTY_VENDOR_PATCHLEVEL, ""),
+ true /* include_day */);
+
+ SendSystemVersionInfo();
+ GetBootInfo();
+}
+
Return<void> KeymasterDevice::getHardwareInfo(
getHardwareInfo_cb _hidl_cb)
{
@@ -739,6 +798,32 @@
return Void();
}
+// Private methods.
+Return<ErrorCode> KeymasterDevice::SendSystemVersionInfo() const {
+ SetSystemVersionInfoRequest request;
+ SetSystemVersionInfoResponse response;
+
+ request.set_system_version(_os_version);
+ request.set_system_security_level(_os_patchlevel);
+ request.set_vendor_security_level(_vendor_patchlevel);
+
+ KM_CALL(SetSystemVersionInfo);
+ return ErrorCode::OK;
+}
+
+Return<ErrorCode> KeymasterDevice::GetBootInfo() {
+ GetBootInfoRequest request;
+ GetBootInfoResponse response;
+
+ KM_CALL(GetBootInfo);
+
+ _is_unlocked = response.is_unlocked();
+ _boot_color = response.boot_color();
+ _boot_key.assign(response.boot_key().begin(), response.boot_key().end());
+ _boot_hash.assign(response.boot_hash().begin(), response.boot_hash().end());
+ return ErrorCode::OK;
+}
+
} // namespace keymaster
} // namespace hardware
} // namespace android
diff --git a/hals/keymaster/citadel/Android.bp b/hals/keymaster/citadel/Android.bp
deleted file mode 100644
index ee3d084..0000000
--- a/hals/keymaster/citadel/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_binary {
- name: "android.hardware.keymaster@4.0-service.citadel",
- init_rc: ["android.hardware.keymaster@4.0-service.citadel.rc"],
- required: ["citadeld"],
- srcs: [
- "service.cpp",
- ],
- defaults: ["nos_hal_service_defaults"],
- shared_libs: [
- "android.hardware.keymaster@4.0",
- "android.hardware.keymaster@4.0-impl.nos",
- "libnos_citadeld_proxy",
- "nos_app_keymaster",
- ],
-}
diff --git a/hals/keymaster/citadel/Android.mk b/hals/keymaster/citadel/Android.mk
new file mode 100644
index 0000000..8b09168
--- /dev/null
+++ b/hals/keymaster/citadel/Android.mk
@@ -0,0 +1,77 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := android.hardware.keymaster@4.0-service.citadel
+LOCAL_INIT_RC := android.hardware.keymaster@4.0-service.citadel.rc
+
+LOCAL_SRC_FILES := service.cpp
+
+LOCAL_REQUIRED_MODULES := citadeld
+LOCAL_HEADER_LIBRARIES := nos_headers
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libhidlbase \
+ libhidltransport \
+ libnos \
+ libnosprotos \
+ libutils \
+ libprotobuf-cpp-full \
+ android.hardware.keymaster@4.0 \
+ android.hardware.keymaster@4.0-impl.nos \
+ libnos_citadeld_proxy \
+ nos_app_keymaster \
+ libkeymasterprovision \
+ libkeymasterutils \
+ libkeymasterdeviceutils \
+ libQSEEComAPI
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+
+LOCAL_CFLAGS := -pedantic -Wall -Wextra -Werror -Wno-zero-length-array
+LOCAL_CONLYFLAGS := -std=c11
+LOCAL_CLANG := true
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_OWNER := google
+
+# TODO: sort out QC component dependency.
+# The QC libraries aren't available to all build targets so only build this
+# component which depends on them when they are available.
+# See vendor/qcom/sdm845/proprietary/prebuilt_grease/Android.mk
+ifeq ($(call is-board-platform,sdm845),true)
+ include $(BUILD_EXECUTABLE)
+endif
+
+#cc_binary {
+# name: "android.hardware.keymaster@4.0-service.citadel",
+# init_rc: ["android.hardware.keymaster@4.0-service.citadel.rc"],
+# required: ["citadeld"],
+# srcs: [
+# "service.cpp",
+# ],
+# defaults: ["nos_hal_service_defaults"],
+# shared_libs: [
+# "android.hardware.keymaster@4.0",
+# "android.hardware.keymaster@4.0-impl.nos",
+# "libnos_citadeld_proxy",
+# "nos_app_keymaster",
+# "libkeymasterprovision",
+# "libkeymasterutils",
+# "libkeymasterdeviceutils",
+# "libQSEEComAPI",
+# ],
+#}
diff --git a/hals/keymaster/citadel/android.hardware.keymaster@4.0-service.citadel.rc b/hals/keymaster/citadel/android.hardware.keymaster@4.0-service.citadel.rc
index e9dc3e5..f88c565 100644
--- a/hals/keymaster/citadel/android.hardware.keymaster@4.0-service.citadel.rc
+++ b/hals/keymaster/citadel/android.hardware.keymaster@4.0-service.citadel.rc
@@ -1,4 +1,4 @@
service vendor.keymaster-4-0-citadel /vendor/bin/hw/android.hardware.keymaster@4.0-service.citadel
class early_hal
user hsm
- group hsm
+ group hsm drmrpc
diff --git a/hals/keymaster/citadel/service.cpp b/hals/keymaster/citadel/service.cpp
index 619a57a..6f37096 100644
--- a/hals/keymaster/citadel/service.cpp
+++ b/hals/keymaster/citadel/service.cpp
@@ -21,10 +21,15 @@
#include <application.h>
#include <nos/AppClient.h>
#include <nos/CitadeldProxyClient.h>
+#include <nos/debug.h>
#include <KeymasterDevice.h>
#include <Keymaster.client.h>
+#include <KeymasterKeyProvision.h>
+#include <nugget/app/keymaster/keymaster.pb.h>
+#include "../proto_utils.h"
+
using ::android::OK;
using ::android::sp;
using ::android::status_t;
@@ -32,12 +37,87 @@
using ::android::hardware::joinRpcThreadpool;
using ::android::hardware::keymaster::KeymasterDevice;
+using ::android::hardware::keymaster::translate_error_code;
using ::nos::CitadeldProxyClient;
using ::nos::AppClient;
+using ::nugget::app::keymaster::ProvisionPresharedSecretRequest;
+using ::nugget::app::keymaster::ProvisionPresharedSecretResponse;
+using ::nugget::app::keymaster::PresharedSecretStatus;
+using ErrorCodeNos = ::nugget::app::keymaster::ErrorCode;
+using ::android::hardware::keymaster::V4_0::ErrorCode;
using KeymasterClient = ::nugget::app::keymaster::Keymaster;
+// TODO(ngm): move this code into the HAL implementation.
+static bool alreadyProvisioned(KeymasterClient *keymasterClient) {
+ ProvisionPresharedSecretRequest request;
+ ProvisionPresharedSecretResponse response;
+ request.set_get_status(true);
+
+ const uint32_t status = keymasterClient->ProvisionPresharedSecret(
+ request, &response);
+ if (status != APP_SUCCESS) {
+ LOG(ERROR) << "KM ProvisionPresharedSecret() failed with status: "
+ << ::nos::StatusCodeString(status);
+ return false;
+ }
+ const ErrorCode error_code = translate_error_code(response.error_code());
+ if (error_code != ErrorCode::OK) {
+ LOG(ERROR) << "ProvisionPresharedSecret() response error code: "
+ << toString(error_code);
+ return false;
+ }
+ if (response.status() == PresharedSecretStatus::ALREADY_SET) {
+ LOG(INFO) << "Preshared key previously established";
+ return true;
+ }
+
+ return false;
+}
+
+// TODO(ngm): move this code into the HAL implementation.
+static bool maybeProvision(KeymasterClient *keymasterClient) {
+ if (alreadyProvisioned(keymasterClient)) {
+ return true;
+ }
+
+ // Attempt to provision the preshared-secret.
+ keymasterdevice::KeymasterKeyProvision qc_km_provisioning;
+ int result = qc_km_provisioning.KeyMasterProvisionInit();
+ if (result) {
+ LOG(ERROR) << "KeyMasterProvisionInit error: " << result;
+ return false;
+ }
+ std::vector<uint8_t> preshared_secret(32);
+ result = qc_km_provisioning.GetPreSharedSecret(
+ preshared_secret.data(), preshared_secret.size());
+ if (result != KM_ERROR_OK) {
+ LOG(ERROR) << "GetPreSharedSecret error: " << result;
+ return false;
+ }
+
+ ProvisionPresharedSecretRequest request;
+ ProvisionPresharedSecretResponse response;
+ request.set_get_status(false);
+ request.set_preshared_secret(preshared_secret.data(),
+ preshared_secret.size());
+ const uint32_t status = keymasterClient->ProvisionPresharedSecret(
+ request, &response);
+ if (status != APP_SUCCESS) {
+ LOG(ERROR) << "KM ProvisionPresharedSecret() failed with status: "
+ << ::nos::StatusCodeString(status);
+ return false;
+ }
+ if (response.error_code() != ErrorCodeNos::OK) {
+ LOG(ERROR) << "KM ProvisionPresharedSecret() failed with code: "
+ << response.error_code();
+ return false;
+ }
+
+ return true;
+}
+
int main() {
LOG(INFO) << "Keymaster HAL service starting";
@@ -55,9 +135,16 @@
// Start the HAL service
KeymasterClient keymasterClient{citadeldProxy};
sp<KeymasterDevice> keymaster = new KeymasterDevice{keymasterClient};
- const status_t status = keymaster->registerAsService("strongbox");
- if (status != OK) {
- LOG(FATAL) << "Failed to register Keymaster as a service (status: " << status << ")";
+
+ if (maybeProvision(&keymasterClient)) {
+ const status_t status = keymaster->registerAsService("strongbox");
+ if (status != OK) {
+ LOG(FATAL) << "Failed to register Keymaster as a service (status: "
+ << status << ")";
+ }
+ } else {
+ LOG(ERROR) << "Skipping Keymaster registration, as provisioning failed";
+ // Leave the service running to avoid being restarted.
}
joinRpcThreadpool();
diff --git a/hals/keymaster/include/KeymasterDevice.h b/hals/keymaster/include/KeymasterDevice.h
index 5f33fe9..29c379c 100644
--- a/hals/keymaster/include/KeymasterDevice.h
+++ b/hals/keymaster/include/KeymasterDevice.h
@@ -21,6 +21,8 @@
#include <Keymaster.client.h>
+#include <vector>
+
namespace android {
namespace hardware {
namespace keymaster {
@@ -35,13 +37,14 @@
using ::android::hardware::keymaster::V4_0::VerificationToken;
using ::android::hardware::Return;
using ::android::hardware::hidl_vec;
+using ::nugget::app::keymaster::BootColor;
#define KM_MAX_PROTO_FIELD_SIZE 2048
using KeymasterClient = ::nugget::app::keymaster::IKeymaster;
struct KeymasterDevice : public IKeymasterDevice {
- KeymasterDevice(KeymasterClient& keymaster) : _keymaster{keymaster} {}
+ KeymasterDevice(KeymasterClient& keymaster);
~KeymasterDevice() override = default;
// Methods from ::android::hardware::keymaster::V4_0::IKeymasterDevice follow.
@@ -105,6 +108,19 @@
private:
KeymasterClient& _keymaster;
+ // These come from GetProperty.
+ uint32_t _os_version;
+ uint32_t _os_patchlevel;
+ uint32_t _vendor_patchlevel;
+
+ // These come from the bootloader through Citadel.
+ bool _is_unlocked;
+ BootColor _boot_color;
+ std::vector<uint8_t> _boot_key;
+ std::vector<uint8_t> _boot_hash;
+
+ Return<ErrorCode> SendSystemVersionInfo() const;
+ Return<ErrorCode> GetBootInfo();
};
} // namespace keymaster
diff --git a/hals/keymaster/proto_utils.cpp b/hals/keymaster/proto_utils.cpp
index b16e2da..d3cb753 100644
--- a/hals/keymaster/proto_utils.cpp
+++ b/hals/keymaster/proto_utils.cpp
@@ -603,6 +603,12 @@
case Tag::ATTESTATION_ID_MEID: // (TagType:BYTES | 715)
case Tag::ATTESTATION_ID_MANUFACTURER: // (TagType:BYTES | 716)
case Tag::ATTESTATION_ID_MODEL: // (TagType:BYTES | 717)
+ pb->set_blob(¶m.blob[0], param.blob.size());
+ break;
+ case Tag::VENDOR_PATCHLEVEL: // (TagType:UINT | 718)
+ case Tag::BOOT_PATCHLEVEL: // (TagType:UINT | 719)
+ pb->set_integer(param.f.integer);
+ break;
case Tag::ASSOCIATED_DATA: // (TagType:BYTES | 1000)
case Tag::NONCE: // (TagType:BYTES | 1001)
pb->set_blob(¶m.blob[0], param.blob.size());
@@ -765,6 +771,14 @@
case nosapp::Tag::ATTESTATION_ID_MEID: // (TagType:BYTES | 715)
case nosapp::Tag::ATTESTATION_ID_MANUFACTURER: // (TagType:BYTES | 716)
case nosapp::Tag::ATTESTATION_ID_MODEL: // (TagType:BYTES | 717)
+ kp->blob.setToExternal(
+ reinterpret_cast<uint8_t *>(
+ const_cast<char *>(param.blob().data())), param.blob().size());
+ break;
+ case nosapp::Tag::VENDOR_PATCHLEVEL: // (TagType:UINT | 718)
+ case nosapp::Tag::BOOT_PATCHLEVEL: // (TagType:UINT | 719)
+ kp->f.integer = param.integer();
+ break;
case nosapp::Tag::ASSOCIATED_DATA: // (TagType:BYTES | 1000)
case nosapp::Tag::NONCE: // (TagType:BYTES | 1001)
kp->blob.setToExternal(