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