| /* |
| * 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; |
| } |