summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Stokes <alanstokes@google.com>2024-01-12 15:55:45 +0000
committerAlan Stokes <alanstokes@google.com>2024-01-19 15:00:27 +0000
commit97f9dc99fefbdab4976d5521c2764a02a97fef74 (patch)
tree61b8d6d4eba1364f9fe941a38b528baf4dd59381
parentbc22e7583e3fd769befa6ca0a8ff2559062560b5 (diff)
downloadtrusty-simpleperf-release.tar.gz
Implement Secretkeeper bootloader client librarysimpleperf-releasemain-16k
The intention is that this will be used by the Android bootloader to populate pvmfw config data. Modify test-runner to exercise the API and validate that the response is in the expected form. (This is modeled on aosp/1866834 for hwbcc.) Bug: 291232226 Test: test-runner build-root/build-qemu-generic-arm64-test-debug/run --headless & --boot-test "com.android.ipc-unittest.ctrl" Change-Id: I9e5ced52e8f0283de7d1a68ac8e8cd4c289c3497
-rw-r--r--interface/include/interface/secretkeeper/secretkeeper.h64
-rw-r--r--ql-tipc/include/trusty/secretkeeper.h46
-rw-r--r--ql-tipc/secretkeeper.c131
-rw-r--r--test-runner/rules.mk1
-rw-r--r--test-runner/test-runner-sysdeps.c12
-rw-r--r--test-runner/test-runner.c52
6 files changed, 306 insertions, 0 deletions
diff --git a/interface/include/interface/secretkeeper/secretkeeper.h b/interface/include/interface/secretkeeper/secretkeeper.h
new file mode 100644
index 0000000..f8dd3d6
--- /dev/null
+++ b/interface/include/interface/secretkeeper/secretkeeper.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2024 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>
+#include <stdint.h>
+
+/* Note: The definitive source for the message interface here is is in
+ * trusty/user/app/secretkeeper/lib.rs (TIPC port details) and
+ * system/secretkeeper/core/src/ta/bootloader.rs (message format).
+ * This is a manual translation into C.
+ */
+
+#define SECRETKEEPER_BL_PORT "com.android.trusty.secretkeeper.bootloader"
+
+/**
+ * enum secretkeeper_cmd - Secretkeeper commands.
+ * @SECRETKEEPER_RESPONSE_MARKER: Bit indicating that this is a response.
+ * @SECRETKEEPER_CMD_GET_IDENTITY: Get the per-boot identity (public key) of
+ * Secretkeeper.
+ */
+enum secretkeeper_cmd {
+ SECRETKEEPER_RESPONSE_MARKER = 0x1 << 31,
+ SECRETKEEPER_CMD_GET_IDENTITY = 1,
+};
+
+/**
+ * struct secretkeeper_req_hdr - Generic header for all Secretkeeper requests.
+ * Note that all fields are stored in network byte order (big endian).
+ * @cmd: The command to be run. Commands are described in
+ * enum secretkeeper_cmd.
+ */
+struct secretkeeper_req_hdr {
+ uint32_t cmd;
+};
+STATIC_ASSERT(sizeof(struct secretkeeper_req_hdr) == 4);
+
+/**
+ * struct secretkeeper_resp_hdr - Generic header for all Secretkeeper responses.
+ * Note that all fields are stored in network byte order (big endian).
+ * Any response payload immediately follows this struct.
+ * @cmd: Command identifier - %SECRETKEEPER_RESPONSE_MARKER or'ed with
+ * the command identifier of the corresponding request.
+ * @error_code: 0 if the request succeeded, or an indication of how it failed.
+ */
+struct secretkeeper_resp_hdr {
+ uint32_t cmd;
+ uint32_t error_code;
+};
+STATIC_ASSERT(sizeof(struct secretkeeper_resp_hdr) == 8);
diff --git a/ql-tipc/include/trusty/secretkeeper.h b/ql-tipc/include/trusty/secretkeeper.h
new file mode 100644
index 0000000..47f0c0b
--- /dev/null
+++ b/ql-tipc/include/trusty/secretkeeper.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2024 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 <interface/secretkeeper/secretkeeper.h>
+#include <trusty/trusty_ipc.h>
+
+/*
+ * Initialize SECRETKEEPER TIPC client. Returns one of trusty_err.
+ *
+ * @dev: trusty_ipc_dev
+ */
+int secretkeeper_tipc_init(struct trusty_ipc_dev* dev);
+
+/*
+ * Shutdown SECRETKEEPER TIPC client.
+ */
+void secretkeeper_tipc_shutdown(void);
+
+/**
+ * Retrieves the identity (public key) of the Secretkeeper implementation.
+ * The key is represented as a CBOR-encoded COSE_key, as one of as a
+ * PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384. See
+ * https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
+ * @identity_buf_size: Size of the buffer pointed to by @identity_buf.
+ * @identity_buf: Pointer to a buffer to store the CBOR-encoded
+ * public key.
+ * @identity_size: On return the actual size of the public key.
+ */
+int secretkeeper_get_identity(size_t identity_buf_size,
+ uint8_t identity_buf[],
+ size_t* identity_size);
diff --git a/ql-tipc/secretkeeper.c b/ql-tipc/secretkeeper.c
new file mode 100644
index 0000000..a12d50f
--- /dev/null
+++ b/ql-tipc/secretkeeper.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#include <endian.h>
+#include <trusty/secretkeeper.h>
+#include <trusty/trusty_ipc.h>
+#include <trusty/util.h>
+
+static struct trusty_ipc_chan secretkeeper_chan;
+static bool initialized;
+
+int secretkeeper_tipc_init(struct trusty_ipc_dev* dev) {
+ trusty_assert(dev);
+ trusty_assert(!initialized);
+ trusty_ipc_chan_init(&secretkeeper_chan, dev);
+
+ trusty_debug(
+ "In secretkeeper_tipc_init: connecting to secretkeeper bootloader service.\n");
+ int rc = trusty_ipc_connect(&secretkeeper_chan, SECRETKEEPER_BL_PORT,
+ true /*wait*/);
+ if (rc < 0) {
+ trusty_error(
+ "In secretkeeper_tipc_init:: failed (%d) to connect to '%s'.\n",
+ rc, SECRETKEEPER_BL_PORT);
+ return rc;
+ }
+ initialized = true;
+ return TRUSTY_ERR_NONE;
+}
+
+void secretkeeper_tipc_shutdown(void) {
+ if (!initialized) {
+ return;
+ }
+ trusty_ipc_close(&secretkeeper_chan);
+ initialized = false;
+}
+
+static int send_header_only_request(struct secretkeeper_req_hdr* hdr,
+ size_t hdr_size) {
+ int num_iovec = 1;
+ struct trusty_ipc_iovec req_iov = {.base = hdr, .len = hdr_size};
+ return trusty_ipc_send(&secretkeeper_chan, &req_iov, num_iovec, true);
+}
+
+static int read_response_with_data(struct secretkeeper_req_hdr* hdr,
+ uint8_t* buf,
+ size_t buf_size,
+ size_t* out_size) {
+ struct secretkeeper_resp_hdr resp_hdr = {};
+
+ trusty_assert(buf);
+ trusty_assert(out_size);
+
+ int num_iovec = 2;
+ struct trusty_ipc_iovec resp_iovecs[2] = {
+ {.base = &resp_hdr, .len = sizeof(resp_hdr)},
+ {.base = buf, .len = buf_size},
+ };
+
+ int rc = trusty_ipc_recv(&secretkeeper_chan, resp_iovecs, num_iovec, true);
+ if (rc < 0) {
+ trusty_error("Secretkeeper: Failure on receiving response: %d\n", rc);
+ return rc;
+ }
+
+ size_t bytes = rc;
+ if (bytes < sizeof(resp_hdr)) {
+ trusty_error("Secretkeeper: Invalid response size (%d).\n", rc);
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ if (resp_hdr.cmd != (hdr->cmd | htonl(SECRETKEEPER_RESPONSE_MARKER))) {
+ trusty_error("Secretkeeper: Unknown response cmd: %x\n",
+ ntohl(resp_hdr.cmd));
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ if (resp_hdr.error_code != 0) {
+ trusty_error("Secretkeeper: Error code (%d) is not zero.\n",
+ ntohl(resp_hdr.error_code));
+ return TRUSTY_ERR_GENERIC;
+ }
+
+ *out_size = bytes - sizeof(resp_hdr);
+ return rc;
+}
+
+int secretkeeper_get_identity(size_t identity_buf_size,
+ uint8_t identity_buf[],
+ size_t* identity_size) {
+ trusty_assert(dice_artifacts);
+ trusty_assert(dice_artifacts_size);
+
+ struct secretkeeper_req_hdr hdr;
+ hdr.cmd = htonl(SECRETKEEPER_CMD_GET_IDENTITY);
+
+ int rc = send_header_only_request(&hdr, sizeof(hdr));
+
+ if (rc < 0) {
+ trusty_error(
+ "In secretkeeper_get_identity: failed (%d) to send request to Secretkeeper.",
+ rc);
+ return rc;
+ }
+
+ rc = read_response_with_data(&hdr, identity_buf, identity_buf_size,
+ identity_size);
+
+ if (rc < 0) {
+ trusty_error(
+ "In secretkeeper_get_identity: failed (%d) to read the response.",
+ rc);
+ return rc;
+ }
+
+ return TRUSTY_ERR_NONE;
+}
diff --git a/test-runner/rules.mk b/test-runner/rules.mk
index f81be68..82f82ce 100644
--- a/test-runner/rules.mk
+++ b/test-runner/rules.mk
@@ -64,6 +64,7 @@ MODULE_SRCS += \
$(QL_TIPC)/keymaster.c \
$(QL_TIPC)/keymaster_serializable.c \
$(QL_TIPC)/rpmb_proxy.c \
+ $(QL_TIPC)/secretkeeper.c \
$(QL_TIPC)/trusty_dev_common.c \
$(QL_TIPC)/util.c \
diff --git a/test-runner/test-runner-sysdeps.c b/test-runner/test-runner-sysdeps.c
index d99c5da..93466aa 100644
--- a/test-runner/test-runner-sysdeps.c
+++ b/test-runner/test-runner-sysdeps.c
@@ -56,6 +56,18 @@ void* memset(void* dest, int c, size_t count) {
return dest;
}
+int memcmp(const void* lhs, const void* rhs, size_t count) {
+ const uint8_t* l = lhs;
+ const uint8_t* r = rhs;
+ while (count--) {
+ if (*l != *r) {
+ return *l > *r ? +1 : -1;
+ }
+ ++l, ++r;
+ }
+ return 0;
+}
+
char* strcpy(char* dest, char const* src) {
char* ret = dest;
while ((*dest++ = *src++) != '\0') {
diff --git a/test-runner/test-runner.c b/test-runner/test-runner.c
index 25e6268..9ef66b8 100644
--- a/test-runner/test-runner.c
+++ b/test-runner/test-runner.c
@@ -31,6 +31,7 @@
#include <trusty/hwbcc.h>
#include <trusty/keymaster.h>
#include <trusty/rpmb.h>
+#include <trusty/secretkeeper.h>
#include <trusty/trusty_dev.h>
#include <trusty/trusty_ipc.h>
#include <utils.h>
@@ -59,6 +60,7 @@ bool starts_with(const char* str1, const char* str2, size_t str2_len) {
* Any return from this function indicates an internal error. The caller is
* responsible for reporting the error. It currently returns to the host with
* 2 as the exit code.
+ * No attempt is made to clean up before returning.
*/
void boot(int cpu) {
int ret;
@@ -222,6 +224,56 @@ void boot(int cpu) {
hwbcc_tipc_shutdown();
+ /**
+ * Check that Secretkeeper can be connected to.
+ */
+ ret = secretkeeper_tipc_init(ipc_dev);
+ if (ret != 0) {
+ log_msg("secretkeeper_tipc_init failed.\n");
+ return;
+ }
+
+ /**
+ * Check that we can retrieve the public key and that it has the expected
+ * form.
+ */
+ uint8_t sk_identity[100];
+ size_t sk_identity_size = 0;
+ ret = secretkeeper_get_identity(sizeof(sk_identity), sk_identity,
+ &sk_identity_size);
+ if (ret != 0) {
+ log_msg("secretkeeper_get_identity failed.\n");
+ return;
+ }
+
+ const size_t ed25519_key_size = 32;
+ const uint8_t expected_cbor_prefix[] = {
+ // Map with 4 entries (see PubKeyEd25519)
+ 0xa4,
+ // Key type: 1: 1
+ 0x01, 0x01,
+ // Algorithm: 3: -8
+ 0x03, 0x27,
+ // Curve: -1: 6
+ 0x20, 0x06,
+ // Public key: -2, 32 byte bstr (which follows)
+ 0x21, 0x58, 0x20};
+ const size_t expected_identity_size =
+ sizeof(expected_cbor_prefix) + ed25519_key_size;
+
+ if (sk_identity_size != expected_identity_size) {
+ log_msg("Unexpected sk_identity_size\n");
+ return;
+ }
+
+ if (memcmp(sk_identity, expected_cbor_prefix,
+ sizeof(expected_cbor_prefix))) {
+ log_msg("sk_identity does not start with expected prefix\n");
+ return;
+ }
+
+ secretkeeper_tipc_shutdown();
+
ret = arch_start_secondary_cpus();
if (ret) {
log_msg("Failed to start secondary CPUs\n");