Add mock Keybox unwrapping service

Provides a mock implementation of the keybox unwrapping service for use
in the emulator to test keymaster provisioning of wrapped keyboxes.

This implementation provides NO SECURITY.

Bug: 152900279
Change-Id: I31bcf7b8125c1a4e0b7dfefd6a7054cd2d8188b8
diff --git a/hwcrypto/keybox/keybox.c b/hwcrypto/keybox/keybox.c
new file mode 100644
index 0000000..122dfc4
--- /dev/null
+++ b/hwcrypto/keybox/keybox.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define TLOG_TAG "keybox"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <lk/list.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <uapi/err.h>
+
+#include <trusty_log.h>
+
+#include "keybox.h"
+
+/*
+ * THIS DOES NOT PROVIDE ANY SECURITY
+ *
+ * This is not a useful wrapping system. This is just intended as enough to mock
+ * that:
+ * 1. The wrapped data and unwrapped data are not the same.
+ * 2. The wrapped data will fail to unwrap if it is trivially tampered with.
+ */
+enum keybox_status keybox_unwrap(const uint8_t* wrapped_keybox,
+                                 size_t wrapped_keybox_len,
+                                 uint8_t* keybox_plaintext,
+                                 size_t keybox_plaintext_buf_len,
+                                 size_t* keybox_plaintext_len) {
+    if (wrapped_keybox_len < 1) {
+        TLOGE("Wrapped keybox too short: %zu\n", wrapped_keybox_len);
+        return KEYBOX_STATUS_INVALID_REQUEST;
+    }
+
+    if (keybox_plaintext_buf_len < wrapped_keybox_len - 1) {
+        TLOGE("Unwrapped keybox buffer too short: %zu\n",
+              keybox_plaintext_buf_len);
+        return KEYBOX_STATUS_INVALID_REQUEST;
+    }
+
+    /* Validate checksum */
+    uint8_t checksum = 0;
+    for (size_t i = 0; i < wrapped_keybox_len - 1; i++) {
+        checksum ^= wrapped_keybox[i];
+    }
+
+    if (checksum != wrapped_keybox[wrapped_keybox_len - 1]) {
+        TLOGE("Invalid checksum\n");
+        return KEYBOX_STATUS_UNWRAP_FAIL;
+    }
+
+    /* Flip bits with masking byte */
+    for (size_t i = 0; i < wrapped_keybox_len - 1; i++) {
+        keybox_plaintext[i] = wrapped_keybox[i] ^ 0x42;
+    }
+
+    *keybox_plaintext_len = wrapped_keybox_len - 1;
+
+    return KEYBOX_STATUS_SUCCESS;
+}
diff --git a/hwcrypto/keybox/keybox.h b/hwcrypto/keybox/keybox.h
new file mode 100644
index 0000000..f629b21
--- /dev/null
+++ b/hwcrypto/keybox/keybox.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <lk/macros.h>
+
+#include <interface/keybox/keybox.h>
+
+enum keybox_status keybox_unwrap(const uint8_t* keybox_ciphertext,
+                                 size_t keybox_ciphertext_len,
+                                 uint8_t* keybox_plaintext,
+                                 size_t keybox_plaintext_buf_len,
+                                 size_t* keybox_plaintext_len);
diff --git a/hwcrypto/keybox/rules.mk b/hwcrypto/keybox/rules.mk
new file mode 100644
index 0000000..7d22842
--- /dev/null
+++ b/hwcrypto/keybox/rules.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2021 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.
+#
+
+MODULE_SRCS += \
+	$(LOCAL_DIR)/keybox/srv.c \
+	$(LOCAL_DIR)/keybox/keybox.c \
+
+MODULE_DEPS += \
+	trusty/user/base/lib/libc-trusty \
+	trusty/user/base/lib/tipc \
+	trusty/user/base/interface/keybox \
diff --git a/hwcrypto/keybox/srv.c b/hwcrypto/keybox/srv.c
new file mode 100644
index 0000000..79807ef
--- /dev/null
+++ b/hwcrypto/keybox/srv.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define TLOG_TAG "keybox"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <lk/list.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <uapi/err.h>
+
+#include <interface/keybox/keybox.h>
+
+#include <lib/tipc/tipc.h>
+#include <trusty_log.h>
+
+#include "keybox.h"
+#include "srv.h"
+
+struct keybox_chan_ctx {
+    struct tipc_event_handler evt_handler;
+    handle_t chan;
+};
+
+static void keybox_port_handler(const uevent_t* ev, void* priv);
+static void keybox_chan_handler(const uevent_t* ev, void* priv);
+
+static handle_t keybox_port = INVALID_IPC_HANDLE;
+
+static struct tipc_event_handler keybox_port_evt_handler = {
+        .proc = keybox_port_handler,
+};
+
+static void keybox_shutdown(struct keybox_chan_ctx* ctx) {
+    close(ctx->chan);
+    free(ctx);
+}
+
+struct full_keybox_unwrap_req {
+    struct keybox_unwrap_req unwrap_header;
+    uint8_t wrapped_keybox[KEYBOX_MAX_SIZE];
+};
+
+struct full_keybox_unwrap_resp {
+    struct keybox_resp header;
+    struct keybox_unwrap_resp unwrap_header;
+};
+
+static int keybox_handle_unwrap(handle_t chan,
+                                struct full_keybox_unwrap_req* req,
+                                size_t req_size) {
+    struct full_keybox_unwrap_resp rsp = {
+            .header.cmd = KEYBOX_CMD_UNWRAP | KEYBOX_CMD_RSP_BIT,
+    };
+
+    uint8_t output[KEYBOX_MAX_SIZE];
+    if (req_size < sizeof(req->unwrap_header)) {
+        rsp.header.status = KEYBOX_STATUS_INVALID_REQUEST;
+        goto out;
+    }
+
+    uint64_t computed_size;
+    if (__builtin_add_overflow(req->unwrap_header.wrapped_keybox_len,
+                               sizeof(req->unwrap_header), &computed_size)) {
+        rsp.header.status = KEYBOX_STATUS_INVALID_REQUEST;
+        goto out;
+    }
+    if (computed_size != req_size) {
+        rsp.header.status = KEYBOX_STATUS_INVALID_REQUEST;
+        goto out;
+    }
+
+    rsp.header.status = keybox_unwrap(
+            req->wrapped_keybox, req->unwrap_header.wrapped_keybox_len, output,
+            sizeof(output), (size_t*)&rsp.unwrap_header.unwrapped_keybox_len);
+    if (rsp.header.status != KEYBOX_STATUS_SUCCESS) {
+        goto out;
+    }
+
+    return tipc_send2(chan, &rsp, sizeof(rsp), output,
+                      rsp.unwrap_header.unwrapped_keybox_len);
+
+out:
+    return tipc_send1(chan, &rsp, sizeof(rsp.header));
+}
+
+struct full_keybox_req {
+    struct keybox_req header;
+    union {
+        struct full_keybox_unwrap_req unwrap;
+    } cmd_header;
+};
+
+static int keybox_handle_msg(struct keybox_chan_ctx* ctx) {
+    int rc;
+    struct full_keybox_req req;
+    enum keybox_status status = KEYBOX_STATUS_SUCCESS;
+    rc = tipc_recv1(ctx->chan, sizeof(req.header), &req, sizeof(req));
+    if (rc < 0) {
+        TLOGE("Failed (%d) to receive Keybox message\n", rc);
+        return KEYBOX_STATUS_INTERNAL_ERROR;
+    }
+
+    size_t cmd_specific_size = (size_t)rc - sizeof(req.header);
+    switch (req.header.cmd) {
+    case KEYBOX_CMD_UNWRAP:
+        rc = keybox_handle_unwrap(ctx->chan, &req.cmd_header.unwrap,
+                                  cmd_specific_size);
+        break;
+    default:
+        TLOGE("Invalid Keybox command: %d\n", req.header.cmd);
+        struct keybox_resp rsp;
+        rsp.cmd = req.header.cmd | KEYBOX_CMD_RSP_BIT;
+        rsp.status = KEYBOX_STATUS_INVALID_REQUEST;
+        rc = tipc_send1(ctx->chan, &rsp, sizeof(rsp));
+    }
+
+    if (rc < 0) {
+        status = KEYBOX_STATUS_INTERNAL_ERROR;
+    }
+
+    return status;
+}
+
+static void keybox_chan_handler(const uevent_t* ev, void* priv) {
+    struct keybox_chan_ctx* ctx = (struct keybox_chan_ctx*)priv;
+    assert(ctx);
+    assert(ev->handle == ctx->chan);
+
+    tipc_handle_chan_errors(ev);
+    int rc = 0;
+    if (ev->event & IPC_HANDLE_POLL_MSG) {
+        rc = keybox_handle_msg(ctx);
+    }
+    if (ev->event & IPC_HANDLE_POLL_HUP) {
+        keybox_shutdown(ctx);
+    }
+    if (rc) {
+        keybox_shutdown(ctx);
+    }
+}
+
+static void keybox_port_handler(const uevent_t* ev, void* priv) {
+    uuid_t peer_uuid;
+
+    tipc_handle_port_errors(ev);
+
+    if (ev->event & IPC_HANDLE_POLL_READY) {
+        handle_t chan;
+
+        /* incoming connection: accept it */
+        int rc = accept(ev->handle, &peer_uuid);
+        if (rc < 0) {
+            TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle);
+            return;
+        }
+        chan = (handle_t)rc;
+
+        struct keybox_chan_ctx* ctx = calloc(1, sizeof(struct keybox_chan_ctx));
+
+        if (!ctx) {
+            TLOGE("failed to alloc state for chan %d\n", chan);
+            close(chan);
+            return;
+        }
+
+        /* init channel state */
+        ctx->evt_handler.priv = ctx;
+        ctx->evt_handler.proc = keybox_chan_handler;
+        ctx->chan = chan;
+
+        /* attach channel handler */
+        rc = set_cookie(chan, &ctx->evt_handler);
+        if (rc) {
+            TLOGE("failed (%d) to set_cookie on chan %d\n", rc, chan);
+            free(ctx);
+            close(chan);
+            return;
+        }
+    }
+}
+
+/*
+ *  Initialize Keybox service
+ */
+int keybox_start_service(void) {
+    int rc;
+
+    TLOGI("Start Keybox service\n");
+
+    /* create Keybox port */
+    rc = port_create(KEYBOX_PORT, 1, sizeof(struct full_keybox_req),
+                     IPC_PORT_ALLOW_TA_CONNECT);
+    if (rc < 0) {
+        TLOGE("Failed (%d) to create port '%s'\n", rc, KEYBOX_PORT);
+        goto cleanup;
+    }
+
+    keybox_port = (handle_t)rc;
+    set_cookie(keybox_port, &keybox_port_evt_handler);
+
+    return NO_ERROR;
+
+cleanup:
+    close(keybox_port);
+    return rc;
+}
diff --git a/hwcrypto/keybox/srv.h b/hwcrypto/keybox/srv.h
new file mode 100644
index 0000000..74e2a2d
--- /dev/null
+++ b/hwcrypto/keybox/srv.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#include <lk/compiler.h>
+
+__BEGIN_CDECLS
+
+int keybox_start_service(void);
+
+__END_CDECLS
diff --git a/hwcrypto/main.c b/hwcrypto/main.c
index b48fd10..54170c2 100644
--- a/hwcrypto/main.c
+++ b/hwcrypto/main.c
@@ -29,6 +29,8 @@
 #include "hwkey_srv_priv.h"
 #include "hwrng_srv_priv.h"
 
+#include "keybox/srv.h"
+
 /*
  *  Dispatch event
  */
@@ -75,6 +77,12 @@
     }
     hwkey_init_srv_provider();
 
+    rc = keybox_start_service();
+    if (rc != NO_ERROR) {
+        TLOGE("Failed (%d) to initialize Keybox service\n", rc);
+        goto out;
+    }
+
     TLOGI("enter main event loop\n");
 
     /* enter main event loop */
diff --git a/hwcrypto/manifest.json b/hwcrypto/manifest.json
index 2795179..47c2cc2 100644
--- a/hwcrypto/manifest.json
+++ b/hwcrypto/manifest.json
@@ -1,5 +1,5 @@
 {
     "uuid": "GEN_HWCRYPTO_UUID",
     "min_heap": 24576,
-    "min_stack": 4096
+    "min_stack": 8192
 }
diff --git a/hwcrypto/rules.mk b/hwcrypto/rules.mk
index 00a4221..7eab702 100644
--- a/hwcrypto/rules.mk
+++ b/hwcrypto/rules.mk
@@ -42,4 +42,6 @@
 	trusty/user/base/lib/libc-trusty \
 	trusty/user/base/lib/tipc \
 
+include $(LOCAL_DIR)/keybox/rules.mk
+
 include make/module.mk