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(&param.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(&param.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(