| /* |
| * Copyright 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 "hwbcc-srv" |
| |
| #include <assert.h> |
| #include <interface/hwbcc/hwbcc.h> |
| #include <lib/hwbcc/srv/srv.h> |
| #include <lib/tipc/tipc.h> |
| #include <lib/tipc/tipc_srv.h> |
| #include <trusty_ipc.h> |
| #include <trusty_log.h> |
| #include <uapi/err.h> |
| |
| struct hwbcc_req { |
| struct hwbcc_req_hdr hdr; |
| struct hwbcc_req_sign_mac args; |
| uint8_t aad[HWBCC_MAX_AAD_SIZE]; |
| }; |
| STATIC_ASSERT(sizeof(struct hwbcc_req) == |
| sizeof(struct hwbcc_req_hdr) + sizeof(struct hwbcc_req_sign_mac) + |
| HWBCC_MAX_AAD_SIZE); |
| |
| struct hwbcc_resp { |
| struct hwbcc_resp_hdr hdr; |
| uint8_t payload[HWBCC_MAX_RESP_PAYLOAD_SIZE]; |
| }; |
| STATIC_ASSERT(sizeof(struct hwbcc_resp) == |
| sizeof(struct hwbcc_resp_hdr) + HWBCC_MAX_RESP_PAYLOAD_SIZE); |
| |
| /* UUID: {5f902ace-5e5c-4cd8-ae54-87b88c22ddaf} */ |
| static const struct uuid km_uuid = { |
| 0x5f902ace, |
| 0x5e5c, |
| 0x4cd8, |
| {0xae, 0x54, 0x87, 0xb8, 0x8c, 0x22, 0xdd, 0xaf}, |
| }; |
| |
| /* UUID: {0e109d31-8bbe-47d6-bb47-e1dd08910e16} */ |
| static const struct uuid hwbcc_test_uuid = { |
| 0x0e109d31, |
| 0x8bbe, |
| 0x47d6, |
| {0xbb, 0x47, 0xe1, 0xdd, 0x08, 0x91, 0x0e, 0x16}, |
| }; |
| |
| static const struct uuid* allowed_uuids[] = { |
| &km_uuid, |
| &hwbcc_test_uuid, |
| }; |
| |
| static struct tipc_port_acl acl = { |
| .flags = IPC_PORT_ALLOW_TA_CONNECT, |
| .uuids = allowed_uuids, |
| .uuid_num = countof(allowed_uuids), |
| }; |
| |
| static struct tipc_port port = { |
| .name = HWBCC_PORT, |
| .msg_max_size = sizeof(struct hwbcc_req), |
| .msg_queue_len = 1, |
| .acl = &acl, |
| }; |
| |
| static const struct hwbcc_ops* hwbcc_ops; |
| |
| static int hwbcc_check_ops(const struct hwbcc_ops* ops) { |
| if (!ops->init || !ops->close || !ops->sign_mac || !ops->get_bcc) { |
| TLOGE("NULL ops pointers\n"); |
| return ERR_INVALID_ARGS; |
| } |
| return NO_ERROR; |
| } |
| |
| static int on_connect(const struct tipc_port* port, |
| handle_t chan, |
| const struct uuid* peer, |
| void** ctx_p) { |
| assert(hwbcc_ops); |
| |
| hwbcc_session_t s; |
| int rc = hwbcc_ops->init(&s, peer); |
| if (rc != NO_ERROR) { |
| TLOGE("Failed to init HWBCC session: %d\n", rc); |
| return rc; |
| } |
| |
| *ctx_p = s; |
| return NO_ERROR; |
| } |
| |
| static void on_channel_cleanup(void* ctx) { |
| assert(hwbcc_ops); |
| |
| hwbcc_session_t s = ctx; |
| hwbcc_ops->close(s); |
| } |
| |
| static int handle_sign_mac(hwbcc_session_t s, |
| handle_t chan, |
| uint32_t test_mode, |
| struct hwbcc_req_sign_mac* args, |
| const uint8_t* aad) { |
| int rc; |
| struct hwbcc_resp resp = {0}; |
| size_t payload_size = 0; |
| |
| assert(hwbcc_ops); |
| |
| rc = hwbcc_ops->sign_mac(s, test_mode, args->algorithm, args->mac_key, aad, |
| args->aad_size, resp.payload, sizeof(resp.payload), |
| &payload_size); |
| if (rc != NO_ERROR) { |
| TLOGE("HWBCC_CMD_SIGN_MAC failure: %d\n", rc); |
| } |
| |
| resp.hdr.cmd = HWBCC_CMD_SIGN_MAC | HWBCC_CMD_RESP_BIT; |
| resp.hdr.status = rc; |
| resp.hdr.payload_size = payload_size; |
| rc = tipc_send1(chan, &resp, sizeof(resp.hdr) + payload_size); |
| if (rc < 0) { |
| return rc; |
| } |
| |
| if ((size_t)rc != sizeof(resp.hdr) + payload_size) { |
| return ERR_BAD_LEN; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| static int handle_get_bcc(hwbcc_session_t s, |
| handle_t chan, |
| uint32_t test_mode) { |
| int rc; |
| struct hwbcc_resp resp = {0}; |
| size_t payload_size = 0; |
| |
| assert(hwbcc_ops); |
| |
| rc = hwbcc_ops->get_bcc(s, test_mode, resp.payload, sizeof(resp.payload), |
| &payload_size); |
| if (rc != NO_ERROR) { |
| TLOGE("HWBCC_CMD_GET_BCC failure: %d\n", rc); |
| } |
| |
| resp.hdr.cmd = HWBCC_CMD_GET_BCC | HWBCC_CMD_RESP_BIT; |
| resp.hdr.status = rc; |
| resp.hdr.payload_size = payload_size; |
| rc = tipc_send1(chan, &resp, sizeof(resp.hdr) + payload_size); |
| if (rc < 0) { |
| return rc; |
| } |
| |
| if ((size_t)rc != sizeof(resp.hdr) + payload_size) { |
| return ERR_BAD_LEN; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| static int on_message(const struct tipc_port* port, handle_t chan, void* ctx) { |
| int rc; |
| struct hwbcc_req req; |
| hwbcc_session_t s = ctx; |
| |
| rc = tipc_recv1(chan, sizeof(req.hdr), &req, sizeof(req)); |
| if (rc < 0) { |
| TLOGE("Failed to read command %d\n", rc); |
| return rc; |
| } |
| |
| switch (req.hdr.cmd) { |
| case HWBCC_CMD_SIGN_MAC: { |
| if ((size_t)rc < sizeof(req.hdr) + sizeof(req.args)) { |
| return ERR_BAD_LEN; |
| } |
| |
| if (req.args.aad_size > HWBCC_MAX_AAD_SIZE) { |
| return ERR_BAD_LEN; |
| } |
| |
| if (rc - sizeof(req.hdr) - sizeof(req.args) != req.args.aad_size) { |
| return ERR_BAD_LEN; |
| } |
| |
| return handle_sign_mac(s, chan, req.hdr.test_mode, &req.args, req.aad); |
| } |
| |
| case HWBCC_CMD_GET_BCC: |
| if (rc != sizeof(req.hdr)) { |
| return ERR_BAD_LEN; |
| } |
| |
| return handle_get_bcc(s, chan, req.hdr.test_mode); |
| |
| default: |
| TLOGE("Received unknown command %x\n", req.hdr.cmd); |
| return ERR_CMD_UNKNOWN; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| static struct tipc_srv_ops tipc_ops = { |
| .on_connect = on_connect, |
| .on_message = on_message, |
| .on_channel_cleanup = on_channel_cleanup, |
| }; |
| |
| /* |
| * TODO: Currently we only support one instance of HWBCC service, i.e. this |
| * function can only be called once. |
| */ |
| int add_hwbcc_service(struct tipc_hset* hset, const struct hwbcc_ops* ops) { |
| int rc = hwbcc_check_ops(ops); |
| if (rc != NO_ERROR) { |
| return rc; |
| } |
| hwbcc_ops = ops; |
| |
| return tipc_add_service(hset, &port, 1, 1, &tipc_ops); |
| } |