diff options
author | Alan Stokes <alanstokes@google.com> | 2024-02-16 04:32:25 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2024-02-16 04:32:25 +0000 |
commit | 462baaf2ed8920c1c767e817dfe3c806695dc760 (patch) | |
tree | 61b8d6d4eba1364f9fe941a38b528baf4dd59381 | |
parent | 5fd36c1c5500aebfae6df8c3cdfd038ab33255a0 (diff) | |
parent | 97f9dc99fefbdab4976d5521c2764a02a97fef74 (diff) | |
download | trusty-master.tar.gz |
Original change: https://android-review.googlesource.com/c/trusty/external/trusty/+/2919725
Change-Id: Ied7b26a3fe6243ee0d7412e8982903ac155ca24f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | interface/include/interface/secretkeeper/secretkeeper.h | 64 | ||||
-rw-r--r-- | ql-tipc/include/trusty/secretkeeper.h | 46 | ||||
-rw-r--r-- | ql-tipc/secretkeeper.c | 131 | ||||
-rw-r--r-- | test-runner/rules.mk | 1 | ||||
-rw-r--r-- | test-runner/test-runner-sysdeps.c | 12 | ||||
-rw-r--r-- | test-runner/test-runner.c | 52 |
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"); |