From 47785792837382c2ab1c3d8f4f64266b2ac9ca4b Mon Sep 17 00:00:00 2001 From: Stephen Crane Date: Fri, 12 Feb 2021 12:50:46 -0800 Subject: [PATCH] Trusty: Add BoringSSL modulewrapper for ACVP In order to validate the BoringSSL implementation in Trusty using ACVP, we need a modulewrapper tool that forwards requests to Trusty and back to the ACVP tool. Adds this tool, which interfaces with the Trusty ACVP testing service. Test: make trusty_acvp_modulewrapper Test: adb shell "acvptool -wrapper trusty_acvp_modulewrapper -json vectors/ACVP-AES-CBC" Bug: 173805789 Change-Id: I3028e44c00f8e315dfd94ea34c004bbd25fab788 --- trusty/utils/acvp/Android.bp | 36 ++++ trusty/utils/acvp/acvp_ipc.h | 77 +++++++ trusty/utils/acvp/trusty_modulewrapper.cpp | 235 +++++++++++++++++++++ 3 files changed, 348 insertions(+) create mode 100644 trusty/utils/acvp/Android.bp create mode 100644 trusty/utils/acvp/acvp_ipc.h create mode 100644 trusty/utils/acvp/trusty_modulewrapper.cpp diff --git a/trusty/utils/acvp/Android.bp b/trusty/utils/acvp/Android.bp new file mode 100644 index 000000000..6fe193e5f --- /dev/null +++ b/trusty/utils/acvp/Android.bp @@ -0,0 +1,36 @@ +// 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. + +cc_binary { + name: "trusty_acvp_modulewrapper", + vendor: true, + + srcs: [ + "trusty_modulewrapper.cpp", + ], + static_libs: [ + "libacvp_modulewrapper", + ], + shared_libs: [ + "libbase", + "libc", + "libdmabufheap", + "liblog", + "libtrusty", + "libssl", + ], + cflags: [ + "-Wall", + "-Werror", + ], +} diff --git a/trusty/utils/acvp/acvp_ipc.h b/trusty/utils/acvp/acvp_ipc.h new file mode 100644 index 000000000..8b48ae3cd --- /dev/null +++ b/trusty/utils/acvp/acvp_ipc.h @@ -0,0 +1,77 @@ +/* + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#define ACVP_PORT "com.android.trusty.acvp" + +/* + * Maximum number of arguments + */ +#define ACVP_MAX_NUM_ARGUMENTS 8 + +/* + * Maximum length of an algorithm name + */ +#define ACVP_MAX_NAME_LENGTH 30 + +/* + * Maximum length of an ACVP request message + */ +#define ACVP_MAX_MESSAGE_LENGTH sizeof(struct acvp_req) + +/* + * Minimum length of the shared memory buffer + * + * This must be at least as long as the longest reply from the ACVP service + * (currently the reply from getConfig()). + */ +#define ACVP_MIN_SHARED_MEMORY 16384 + +/** + * acvp_req - Request for the Trusty ACVP app + * @num_args: Number of acvp_arg structures following this struct + * @buffer_size: Total size of shared memory buffer + * @lengths: Length of each argument in the shared memory buffer + * + * @num_args copies of the acvp_arg struct follow this structure. + */ +struct acvp_req { + uint32_t num_args; + uint32_t buffer_size; + uint32_t lengths[ACVP_MAX_NUM_ARGUMENTS]; +}; + +/** + * acvp_resp - Response to a ACVP request + * + * @num_spans: Number of response sections + * @lengths: Length of each response section + */ +struct acvp_resp { + uint32_t num_spans; + uint32_t lengths[ACVP_MAX_NUM_ARGUMENTS]; +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/trusty/utils/acvp/trusty_modulewrapper.cpp b/trusty/utils/acvp/trusty_modulewrapper.cpp new file mode 100644 index 000000000..70ffb52ec --- /dev/null +++ b/trusty/utils/acvp/trusty_modulewrapper.cpp @@ -0,0 +1,235 @@ +/* + * 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 LOG_TAG "TrustyAcvpModulewrapper" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acvp_ipc.h" + +constexpr const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0"; + +using android::base::ErrnoError; +using android::base::Error; +using android::base::Result; +using android::base::unique_fd; +using android::base::WriteFully; + +static inline size_t AlignUpToPage(size_t size) { + return (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); +} + +namespace { + +class ModuleWrapper { + private: + static const char* kAcvpPort_; + static const char* kTrustyDeviceName_; + + public: + ModuleWrapper(); + ~ModuleWrapper(); + + Result SendMessage(bssl::Span>); + + Result ForwardResponse(); + + private: + // Connection to the Trusty ACVP service + int tipc_fd_ = -1; + + // Shared memory DMA buf + unique_fd dmabuf_fd_; + + // Size of shared memory mapping + size_t shm_size_ = 0; + + // Shared memory mapping + uint8_t* shm_buffer_ = nullptr; +}; + +} // namespace + +const char* ModuleWrapper::kAcvpPort_ = ACVP_PORT; +const char* ModuleWrapper::kTrustyDeviceName_ = kTrustyDeviceName; + +ModuleWrapper::ModuleWrapper() { + tipc_fd_ = tipc_connect(kTrustyDeviceName_, kAcvpPort_); + if (tipc_fd_ < 0) { + fprintf(stderr, "Failed to connect to Trusty ACVP test app: %s\n", strerror(-tipc_fd_)); + } +} + +ModuleWrapper::~ModuleWrapper() { + if (tipc_fd_ >= 0) { + tipc_close(tipc_fd_); + } + + if (shm_buffer_) { + munmap(shm_buffer_, shm_size_); + } +} + +Result ModuleWrapper::SendMessage(bssl::Span> args) { + assert(args.size() < ACVP_MAX_NUM_ARGUMENTS); + assert(args[0].size() < ACVP_MAX_NAME_LENGTH); + + struct acvp_req request; + request.num_args = args.size(); + + size_t total_args_size = 0; + for (auto arg : args) { + total_args_size += arg.size(); + } + + shm_size_ = ACVP_MIN_SHARED_MEMORY; + if (total_args_size > shm_size_) { + shm_size_ = AlignUpToPage(total_args_size); + } + request.buffer_size = shm_size_; + + struct iovec iov = { + .iov_base = &request, + .iov_len = sizeof(struct acvp_req), + }; + + BufferAllocator alloc; + dmabuf_fd_.reset(alloc.Alloc(kDmabufSystemHeapName, shm_size_)); + if (!dmabuf_fd_.ok()) { + return ErrnoError() << "Error creating dmabuf"; + } + + shm_buffer_ = (uint8_t*)mmap(0, shm_size_, PROT_READ | PROT_WRITE, MAP_SHARED, dmabuf_fd_, 0); + if (shm_buffer_ == MAP_FAILED) { + return ErrnoError() << "Failed to map shared memory dmabuf"; + } + + size_t cur_offset = 0; + for (int i = 0; i < args.size(); ++i) { + request.lengths[i] = args[i].size(); + memcpy(shm_buffer_ + cur_offset, args[i].data(), args[i].size()); + cur_offset += args[i].size(); + } + + struct trusty_shm shm = { + .fd = dmabuf_fd_.get(), + .transfer = TRUSTY_SHARE, + }; + + int rc = tipc_send(tipc_fd_, &iov, 1, &shm, 1); + if (rc != sizeof(struct acvp_req)) { + return ErrnoError() << "Failed to send request to Trusty ACVP service"; + } + + return {}; +} + +Result ModuleWrapper::ForwardResponse() { + struct acvp_resp resp; + int bytes_read = read(tipc_fd_, &resp, sizeof(struct acvp_resp)); + if (bytes_read < 0) { + return ErrnoError() << "Failed to read response from Trusty ACVP service"; + } + + if (bytes_read != sizeof(struct acvp_resp)) { + return Error() << "Trusty ACVP response overflowed expected size"; + } + + size_t total_args_size = 0; + for (size_t i = 0; i < resp.num_spans; i++) { + total_args_size += resp.lengths[i]; + } + + iovec iovs[2]; + iovs[0].iov_base = &resp; + iovs[0].iov_len = sizeof(uint32_t) * (1 + resp.num_spans); + + iovs[1].iov_base = shm_buffer_; + iovs[1].iov_len = total_args_size; + + size_t iov_done = 0; + while (iov_done < 2) { + ssize_t r; + do { + r = writev(STDOUT_FILENO, &iovs[iov_done], 2 - iov_done); + } while (r == -1 && errno == EINTR); + + if (r <= 0) { + return Error() << "Failed to write ACVP response to standard out"; + } + + size_t written = r; + for (size_t i = iov_done; i < 2 && written > 0; i++) { + iovec& iov = iovs[i]; + + size_t done = written; + if (done > iov.iov_len) { + done = iov.iov_len; + } + + iov.iov_base = reinterpret_cast(iov.iov_base) + done; + iov.iov_len -= done; + written -= done; + + if (iov.iov_len == 0) { + iov_done++; + } + } + + assert(written == 0); + } + + return {}; +} + +int main() { + for (;;) { + auto buffer = bssl::acvp::RequestBuffer::New(); + auto args = bssl::acvp::ParseArgsFromFd(STDIN_FILENO, buffer.get()); + if (args.empty()) { + ALOGE("Could not parse arguments\n"); + return EXIT_FAILURE; + } + + ModuleWrapper wrapper; + auto res = wrapper.SendMessage(args); + if (!res.ok()) { + std::cerr << res.error() << std::endl; + return EXIT_FAILURE; + } + + res = wrapper.ForwardResponse(); + if (!res.ok()) { + std::cerr << res.error() << std::endl; + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; +};