summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Bentley <prb@google.com>2021-03-03 14:46:47 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-03-03 14:46:47 +0000
commit2de7559e47c141dcdb33fad468146c22a7c06228 (patch)
tree47a1e4993815ca9633235a86567a56a8fe8d74f2
parentc46dcead384cc4f628bd6d16c5f63f3bd159098e (diff)
parentff86bdb9ab7cfab0cc856e7cb9609fe8c778adfc (diff)
downloadboringssl-2de7559e47c141dcdb33fad468146c22a7c06228.tar.gz
Merge "external/boringssl: Cherry-pick bc0a4f1f0f7a2d56f944058da74b9c776ba38002" am: ff86bdb9ab
Original change: https://android-review.googlesource.com/c/platform/external/boringssl/+/1607475 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I9cddd09be819ecfc47538842254ca88f82922e77
-rw-r--r--Android.bp28
-rw-r--r--src/util/fipstools/acvp/modulewrapper/CMakeLists.txt1
-rw-r--r--src/util/fipstools/acvp/modulewrapper/main.cc49
-rw-r--r--src/util/fipstools/acvp/modulewrapper/modulewrapper.cc482
-rw-r--r--src/util/fipstools/acvp/modulewrapper/modulewrapper.h69
5 files changed, 390 insertions, 239 deletions
diff --git a/Android.bp b/Android.bp
index 0ea1c9a8..2353188f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -425,7 +425,7 @@ cc_binary {
name: "acvp_modulewrapper",
host_supported: true,
srcs: [
- "src/util/fipstools/acvp/modulewrapper/modulewrapper.cc",
+ "src/util/fipstools/acvp/modulewrapper/main.cc",
],
target: {
android: {
@@ -439,6 +439,32 @@ cc_binary {
},
},
+ static_libs: [
+ "libacvp_modulewrapper",
+ ],
+ shared_libs: [
+ "libcrypto",
+ ],
+
+ defaults: [
+ "boringssl_flags",
+ ],
+}
+
+// ACVP wrapper implementation shared between Android and Trusty
+cc_library_static {
+ name: "libacvp_modulewrapper",
+ host_supported: true,
+ vendor_available: true,
+ srcs: [
+ "src/util/fipstools/acvp/modulewrapper/modulewrapper.cc",
+ ],
+ target: {
+ android: {
+ compile_multilib: "both",
+ },
+ },
+ export_include_dirs: ["src/util/fipstools/acvp/modulewrapper/"],
shared_libs: [
"libcrypto",
],
diff --git a/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt b/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt
index 8bee5cd0..267f82c3 100644
--- a/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt
+++ b/src/util/fipstools/acvp/modulewrapper/CMakeLists.txt
@@ -4,6 +4,7 @@ if(FIPS)
add_executable(
modulewrapper
+ main.cc
modulewrapper.cc
)
diff --git a/src/util/fipstools/acvp/modulewrapper/main.cc b/src/util/fipstools/acvp/modulewrapper/main.cc
new file mode 100644
index 00000000..283c3406
--- /dev/null
+++ b/src/util/fipstools/acvp/modulewrapper/main.cc
@@ -0,0 +1,49 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <string>
+#include <unistd.h>
+
+#include <openssl/span.h>
+
+#include "modulewrapper.h"
+
+
+int main() {
+ std::unique_ptr<bssl::acvp::RequestBuffer> buffer =
+ bssl::acvp::RequestBuffer::New();
+ const bssl::acvp::ReplyCallback write_reply = std::bind(
+ bssl::acvp::WriteReplyToFd, STDOUT_FILENO, std::placeholders::_1);
+
+ for (;;) {
+ const bssl::Span<const bssl::Span<const uint8_t>> args =
+ ParseArgsFromFd(STDIN_FILENO, buffer.get());
+ if (args.empty()) {
+ return 1;
+ }
+
+ const bssl::acvp::Handler handler = bssl::acvp::FindHandler(args);
+ if (!handler) {
+ return 2;
+ }
+
+ if (!handler(args.subspan(1).data(), write_reply)) {
+ const std::string name(reinterpret_cast<const char *>(args[0].data()),
+ args[0].size());
+ fprintf(stderr, "\'%s\' operation failed.\n", name.c_str());
+ return 3;
+ }
+ }
+};
diff --git a/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc
index 06eac8b2..da01fd5e 100644
--- a/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc
+++ b/src/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -45,15 +45,35 @@
#include "../../../../crypto/fipsmodule/ec/internal.h"
#include "../../../../crypto/fipsmodule/rand/internal.h"
#include "../../../../crypto/fipsmodule/tls/internal.h"
+#include "modulewrapper.h"
-static constexpr size_t kMaxArgs = 8;
-static constexpr size_t kMaxArgLength = (1 << 20);
-static constexpr size_t kMaxNameLength = 30;
-static_assert((kMaxArgs - 1 * kMaxArgLength) + kMaxNameLength > (1 << 30),
- "Argument limits permit excessive messages");
+namespace bssl {
+namespace acvp {
-using namespace bssl;
+#if defined(OPENSSL_TRUSTY)
+#include <trusty_log.h>
+#define LOG_ERROR(...) TLOGE(__VA_ARGS__)
+#else
+#define LOG_ERROR(...) fprintf(stderr, __VA_ARGS__)
+#endif // OPENSSL_TRUSTY
+
+constexpr size_t kMaxArgLength = (1 << 20);
+
+RequestBuffer::~RequestBuffer() = default;
+
+class RequestBufferImpl : public RequestBuffer {
+ public:
+ ~RequestBufferImpl() = default;
+
+ std::vector<uint8_t> buf;
+ Span<const uint8_t> args[kMaxArgs];
+};
+
+// static
+std::unique_ptr<RequestBuffer> RequestBuffer::New() {
+ return std::unique_ptr<RequestBuffer>(new RequestBufferImpl);
+}
static bool ReadAll(int fd, void *in_data, size_t data_len) {
uint8_t *data = reinterpret_cast<uint8_t *>(in_data);
@@ -75,9 +95,74 @@ static bool ReadAll(int fd, void *in_data, size_t data_len) {
return true;
}
-template <typename... Args>
-static bool WriteReply(int fd, Args... args) {
- std::vector<Span<const uint8_t>> spans = {args...};
+Span<const Span<const uint8_t>> ParseArgsFromFd(int fd,
+ RequestBuffer *in_buffer) {
+ RequestBufferImpl *buffer = reinterpret_cast<RequestBufferImpl *>(in_buffer);
+ uint32_t nums[1 + kMaxArgs];
+ const Span<const Span<const uint8_t>> empty_span;
+
+ if (!ReadAll(fd, nums, sizeof(uint32_t) * 2)) {
+ return empty_span;
+ }
+
+ const size_t num_args = nums[0];
+ if (num_args == 0) {
+ LOG_ERROR("Invalid, zero-argument operation requested.\n");
+ return empty_span;
+ } else if (num_args > kMaxArgs) {
+ LOG_ERROR("Operation requested with %zu args, but %zu is the limit.\n",
+ num_args, kMaxArgs);
+ return empty_span;
+ }
+
+ if (num_args > 1 &&
+ !ReadAll(fd, &nums[2], sizeof(uint32_t) * (num_args - 1))) {
+ return empty_span;
+ }
+
+ size_t need = 0;
+ for (size_t i = 0; i < num_args; i++) {
+ const size_t arg_length = nums[i + 1];
+ if (i == 0 && arg_length > kMaxNameLength) {
+ LOG_ERROR("Operation with name of length %zu exceeded limit of %zu.\n",
+ arg_length, kMaxNameLength);
+ return empty_span;
+ } else if (arg_length > kMaxArgLength) {
+ LOG_ERROR(
+ "Operation with argument of length %zu exceeded limit of %zu.\n",
+ arg_length, kMaxArgLength);
+ return empty_span;
+ }
+
+ // This static_assert confirms that the following addition doesn't
+ // overflow.
+ static_assert((kMaxArgs - 1 * kMaxArgLength) + kMaxNameLength > (1 << 30),
+ "Argument limits permit excessive messages");
+ need += arg_length;
+ }
+
+ if (need > buffer->buf.size()) {
+ size_t alloced = need + (need >> 1);
+ if (alloced < need) {
+ abort();
+ }
+ buffer->buf.resize(alloced);
+ }
+
+ if (!ReadAll(fd, buffer->buf.data(), need)) {
+ return empty_span;
+ }
+
+ size_t offset = 0;
+ for (size_t i = 0; i < num_args; i++) {
+ buffer->args[i] = Span<const uint8_t>(&buffer->buf[offset], nums[i + 1]);
+ offset += nums[i + 1];
+ }
+
+ return Span<const Span<const uint8_t>>(buffer->args, num_args);
+}
+
+bool WriteReplyToFd(int fd, const std::vector<Span<const uint8_t>> &spans) {
if (spans.empty() || spans.size() > kMaxArgs) {
abort();
}
@@ -136,7 +221,7 @@ static bool WriteReply(int fd, Args... args) {
return true;
}
-static bool GetConfig(const Span<const uint8_t> args[]) {
+static bool GetConfig(const Span<const uint8_t> args[], ReplyCallback write_reply) {
static constexpr char kConfig[] =
R"([
{
@@ -740,35 +825,33 @@ static bool GetConfig(const Span<const uint8_t> args[]) {
]
}
])";
- return WriteReply(
- STDOUT_FILENO,
- Span<const uint8_t>(reinterpret_cast<const uint8_t *>(kConfig),
- sizeof(kConfig) - 1));
+ return write_reply({Span<const uint8_t>(
+ reinterpret_cast<const uint8_t *>(kConfig), sizeof(kConfig) - 1)});
}
template <uint8_t *(*OneShotHash)(const uint8_t *, size_t, uint8_t *),
size_t DigestLength>
-static bool Hash(const Span<const uint8_t> args[]) {
+static bool Hash(const Span<const uint8_t> args[], ReplyCallback write_reply) {
uint8_t digest[DigestLength];
OneShotHash(args[0].data(), args[0].size(), digest);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(digest));
+ return write_reply({Span<const uint8_t>(digest)});
}
static uint32_t GetIterations(const Span<const uint8_t> iterations_bytes) {
uint32_t iterations;
if (iterations_bytes.size() != sizeof(iterations)) {
- fprintf(stderr,
- "Expected %u-byte input for number of iterations, but found %u "
- "bytes.\n",
- static_cast<unsigned>(sizeof(iterations)),
- static_cast<unsigned>(iterations_bytes.size()));
+ LOG_ERROR(
+ "Expected %u-byte input for number of iterations, but found %u "
+ "bytes.\n",
+ static_cast<unsigned>(sizeof(iterations)),
+ static_cast<unsigned>(iterations_bytes.size()));
abort();
}
memcpy(&iterations, iterations_bytes.data(), sizeof(iterations));
if (iterations == 0 || iterations == UINT32_MAX) {
- fprintf(stderr, "Invalid number of iterations: %x.\n",
- static_cast<unsigned>(iterations));
+ LOG_ERROR("Invalid number of iterations: %x.\n",
+ static_cast<unsigned>(iterations));
abort();
}
@@ -777,7 +860,7 @@ static uint32_t GetIterations(const Span<const uint8_t> iterations_bytes) {
template <int (*SetKey)(const uint8_t *key, unsigned bits, AES_KEY *out),
void (*Block)(const uint8_t *in, uint8_t *out, const AES_KEY *key)>
-static bool AES(const Span<const uint8_t> args[]) {
+static bool AES(const Span<const uint8_t> args[], ReplyCallback write_reply) {
AES_KEY key;
if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) {
return false;
@@ -799,13 +882,13 @@ static bool AES(const Span<const uint8_t> args[]) {
}
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(result),
- Span<const uint8_t>(prev_result));
+ return write_reply(
+ {Span<const uint8_t>(result), Span<const uint8_t>(prev_result)});
}
template <int (*SetKey)(const uint8_t *key, unsigned bits, AES_KEY *out),
int Direction>
-static bool AES_CBC(const Span<const uint8_t> args[]) {
+static bool AES_CBC(const Span<const uint8_t> args[], ReplyCallback write_reply) {
AES_KEY key;
if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) {
return false;
@@ -848,15 +931,15 @@ static bool AES_CBC(const Span<const uint8_t> args[]) {
}
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(result),
- Span<const uint8_t>(prev_result));
+ return write_reply(
+ {Span<const uint8_t>(result), Span<const uint8_t>(prev_result)});
}
-static bool AES_CTR(const Span<const uint8_t> args[]) {
+static bool AES_CTR(const Span<const uint8_t> args[], ReplyCallback write_reply) {
static const uint32_t kOneIteration = 1;
if (args[3].size() != sizeof(kOneIteration) ||
memcmp(args[3].data(), &kOneIteration, sizeof(kOneIteration))) {
- fprintf(stderr, "Only a single iteration supported with AES-CTR\n");
+ LOG_ERROR("Only a single iteration supported with AES-CTR\n");
return false;
}
@@ -870,7 +953,7 @@ static bool AES_CTR(const Span<const uint8_t> args[]) {
uint8_t iv[AES_BLOCK_SIZE];
memcpy(iv, args[2].data(), AES_BLOCK_SIZE);
if (GetIterations(args[3]) != 1) {
- fprintf(stderr, "Multiple iterations of AES-CTR is not supported.\n");
+ LOG_ERROR("Multiple iterations of AES-CTR is not supported.\n");
return false;
}
@@ -880,15 +963,15 @@ static bool AES_CTR(const Span<const uint8_t> args[]) {
uint8_t ecount_buf[AES_BLOCK_SIZE];
AES_ctr128_encrypt(args[1].data(), out.data(), args[1].size(), &key, iv,
ecount_buf, &num);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
static bool AESGCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key) {
uint32_t tag_len_32;
if (tag_len_span.size() != sizeof(tag_len_32)) {
- fprintf(stderr, "Tag size value is %u bytes, not an uint32_t\n",
- static_cast<unsigned>(tag_len_span.size()));
+ LOG_ERROR("Tag size value is %u bytes, not an uint32_t\n",
+ static_cast<unsigned>(tag_len_span.size()));
return false;
}
memcpy(&tag_len_32, tag_len_span.data(), sizeof(tag_len_32));
@@ -905,15 +988,14 @@ static bool AESGCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
aead = EVP_aead_aes_256_gcm();
break;
default:
- fprintf(stderr, "Bad AES-GCM key length %u\n",
- static_cast<unsigned>(key.size()));
+ LOG_ERROR("Bad AES-GCM key length %u\n", static_cast<unsigned>(key.size()));
return false;
}
if (!EVP_AEAD_CTX_init(ctx, aead, key.data(), key.size(), tag_len_32,
nullptr)) {
- fprintf(stderr, "Failed to setup AES-GCM with tag length %u\n",
- static_cast<unsigned>(tag_len_32));
+ LOG_ERROR("Failed to setup AES-GCM with tag length %u\n",
+ static_cast<unsigned>(tag_len_32));
return false;
}
@@ -924,28 +1006,27 @@ static bool AESCCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key) {
uint32_t tag_len_32;
if (tag_len_span.size() != sizeof(tag_len_32)) {
- fprintf(stderr, "Tag size value is %u bytes, not an uint32_t\n",
- static_cast<unsigned>(tag_len_span.size()));
+ LOG_ERROR("Tag size value is %u bytes, not an uint32_t\n",
+ static_cast<unsigned>(tag_len_span.size()));
return false;
}
memcpy(&tag_len_32, tag_len_span.data(), sizeof(tag_len_32));
if (tag_len_32 != 4) {
- fprintf(stderr, "AES-CCM only supports 4-byte tags, but %u was requested\n",
- static_cast<unsigned>(tag_len_32));
+ LOG_ERROR("AES-CCM only supports 4-byte tags, but %u was requested\n",
+ static_cast<unsigned>(tag_len_32));
return false;
}
if (key.size() != 16) {
- fprintf(stderr,
- "AES-CCM only supports 128-bit keys, but %u bits were given\n",
- static_cast<unsigned>(key.size() * 8));
+ LOG_ERROR("AES-CCM only supports 128-bit keys, but %u bits were given\n",
+ static_cast<unsigned>(key.size() * 8));
return false;
}
if (!EVP_AEAD_CTX_init(ctx, EVP_aead_aes_128_ccm_bluetooth(), key.data(),
key.size(), tag_len_32, nullptr)) {
- fprintf(stderr, "Failed to setup AES-CCM with tag length %u\n",
- static_cast<unsigned>(tag_len_32));
+ LOG_ERROR("Failed to setup AES-CCM with tag length %u\n",
+ static_cast<unsigned>(tag_len_32));
return false;
}
@@ -954,7 +1035,7 @@ static bool AESCCMSetup(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
template <bool (*SetupFunc)(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key)>
-static bool AEADSeal(const Span<const uint8_t> args[]) {
+static bool AEADSeal(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> tag_len_span = args[0];
Span<const uint8_t> key = args[1];
Span<const uint8_t> plaintext = args[2];
@@ -979,12 +1060,12 @@ static bool AEADSeal(const Span<const uint8_t> args[]) {
}
out.resize(out_len);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
template <bool (*SetupFunc)(EVP_AEAD_CTX *ctx, Span<const uint8_t> tag_len_span,
Span<const uint8_t> key)>
-static bool AEADOpen(const Span<const uint8_t> args[]) {
+static bool AEADOpen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> tag_len_span = args[0];
Span<const uint8_t> key = args[1];
Span<const uint8_t> ciphertext = args[2];
@@ -1003,22 +1084,22 @@ static bool AEADOpen(const Span<const uint8_t> args[]) {
if (!EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(),
nonce.data(), nonce.size(), ciphertext.data(),
ciphertext.size(), ad.data(), ad.size())) {
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>());
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
}
out.resize(out_len);
success_flag[0] = 1;
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>(out));
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
}
static bool AESPaddedKeyWrapSetup(AES_KEY *out, bool decrypt,
Span<const uint8_t> key) {
if ((decrypt ? AES_set_decrypt_key : AES_set_encrypt_key)(
key.data(), key.size() * 8, out) != 0) {
- fprintf(stderr, "Invalid AES key length for AES-KW(P): %u\n",
- static_cast<unsigned>(key.size()));
+ LOG_ERROR("Invalid AES key length for AES-KW(P): %u\n",
+ static_cast<unsigned>(key.size()));
return false;
}
return true;
@@ -1031,15 +1112,15 @@ static bool AESKeyWrapSetup(AES_KEY *out, bool decrypt, Span<const uint8_t> key,
}
if (input.size() % 8) {
- fprintf(stderr, "Invalid AES-KW input length: %u\n",
- static_cast<unsigned>(input.size()));
+ LOG_ERROR("Invalid AES-KW input length: %u\n",
+ static_cast<unsigned>(input.size()));
return false;
}
return true;
}
-static bool AESKeyWrapSeal(const Span<const uint8_t> args[]) {
+static bool AESKeyWrapSeal(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> key = args[1];
Span<const uint8_t> plaintext = args[2];
@@ -1052,21 +1133,20 @@ static bool AESKeyWrapSeal(const Span<const uint8_t> args[]) {
std::vector<uint8_t> out(plaintext.size() + 8);
if (AES_wrap_key(&aes, /*iv=*/nullptr, out.data(), plaintext.data(),
plaintext.size()) != static_cast<int>(out.size())) {
- fprintf(stderr, "AES-KW failed\n");
+ LOG_ERROR("AES-KW failed\n");
return false;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
-static bool AESKeyWrapOpen(const Span<const uint8_t> args[]) {
+static bool AESKeyWrapOpen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> key = args[1];
Span<const uint8_t> ciphertext = args[2];
AES_KEY aes;
if (!AESKeyWrapSetup(&aes, /*decrypt=*/true, key, ciphertext) ||
- ciphertext.size() < 8 ||
- ciphertext.size() > INT_MAX) {
+ ciphertext.size() < 8 || ciphertext.size() > INT_MAX) {
return false;
}
@@ -1074,16 +1154,16 @@ static bool AESKeyWrapOpen(const Span<const uint8_t> args[]) {
uint8_t success_flag[1] = {0};
if (AES_unwrap_key(&aes, /*iv=*/nullptr, out.data(), ciphertext.data(),
ciphertext.size()) != static_cast<int>(out.size())) {
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>());
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
}
success_flag[0] = 1;
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>(out));
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
}
-static bool AESPaddedKeyWrapSeal(const Span<const uint8_t> args[]) {
+static bool AESPaddedKeyWrapSeal(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> key = args[1];
Span<const uint8_t> plaintext = args[2];
@@ -1097,15 +1177,15 @@ static bool AESPaddedKeyWrapSeal(const Span<const uint8_t> args[]) {
size_t out_len;
if (!AES_wrap_key_padded(&aes, out.data(), &out_len, out.size(),
plaintext.data(), plaintext.size())) {
- fprintf(stderr, "AES-KWP failed\n");
+ LOG_ERROR("AES-KWP failed\n");
return false;
}
out.resize(out_len);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
-static bool AESPaddedKeyWrapOpen(const Span<const uint8_t> args[]) {
+static bool AESPaddedKeyWrapOpen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
Span<const uint8_t> key = args[1];
Span<const uint8_t> ciphertext = args[2];
@@ -1120,23 +1200,23 @@ static bool AESPaddedKeyWrapOpen(const Span<const uint8_t> args[]) {
uint8_t success_flag[1] = {0};
if (!AES_unwrap_key_padded(&aes, out.data(), &out_len, out.size(),
ciphertext.data(), ciphertext.size())) {
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>());
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>()});
}
success_flag[0] = 1;
out.resize(out_len);
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(success_flag),
- Span<const uint8_t>(out));
+ return write_reply(
+ {Span<const uint8_t>(success_flag), Span<const uint8_t>(out)});
}
template <bool Encrypt>
-static bool TDES(const Span<const uint8_t> args[]) {
+static bool TDES(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const EVP_CIPHER *cipher = EVP_des_ede3();
if (args[0].size() != 24) {
- fprintf(stderr, "Bad key length %u for 3DES.\n",
- static_cast<unsigned>(args[0].size()));
+ LOG_ERROR("Bad key length %u for 3DES.\n",
+ static_cast<unsigned>(args[0].size()));
return false;
}
bssl::ScopedEVP_CIPHER_CTX ctx;
@@ -1147,8 +1227,8 @@ static bool TDES(const Span<const uint8_t> args[]) {
}
if (args[1].size() % 8) {
- fprintf(stderr, "Bad input length %u for 3DES.\n",
- static_cast<unsigned>(args[1].size()));
+ LOG_ERROR("Bad input length %u for 3DES.\n",
+ static_cast<unsigned>(args[1].size()));
return false;
}
std::vector<uint8_t> result(args[1].begin(), args[1].end());
@@ -1171,31 +1251,31 @@ static bool TDES(const Span<const uint8_t> args[]) {
}
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(result),
- Span<const uint8_t>(prev_result),
- Span<const uint8_t>(prev_prev_result));
+ return write_reply({Span<const uint8_t>(result),
+ Span<const uint8_t>(prev_result),
+ Span<const uint8_t>(prev_prev_result)});
}
template <bool Encrypt>
-static bool TDES_CBC(const Span<const uint8_t> args[]) {
+static bool TDES_CBC(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const EVP_CIPHER *cipher = EVP_des_ede3_cbc();
if (args[0].size() != 24) {
- fprintf(stderr, "Bad key length %u for 3DES.\n",
- static_cast<unsigned>(args[0].size()));
+ LOG_ERROR("Bad key length %u for 3DES.\n",
+ static_cast<unsigned>(args[0].size()));
return false;
}
if (args[1].size() % 8 || args[1].size() == 0) {
- fprintf(stderr, "Bad input length %u for 3DES.\n",
- static_cast<unsigned>(args[1].size()));
+ LOG_ERROR("Bad input length %u for 3DES.\n",
+ static_cast<unsigned>(args[1].size()));
return false;
}
std::vector<uint8_t> input(args[1].begin(), args[1].end());
if (args[2].size() != EVP_CIPHER_iv_length(cipher)) {
- fprintf(stderr, "Bad IV length %u for 3DES.\n",
- static_cast<unsigned>(args[2].size()));
+ LOG_ERROR("Bad IV length %u for 3DES.\n",
+ static_cast<unsigned>(args[2].size()));
return false;
}
std::vector<uint8_t> iv(args[2].begin(), args[2].end());
@@ -1237,13 +1317,13 @@ static bool TDES_CBC(const Span<const uint8_t> args[]) {
}
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(result),
- Span<const uint8_t>(prev_result),
- Span<const uint8_t>(prev_prev_result));
+ return write_reply({Span<const uint8_t>(result),
+ Span<const uint8_t>(prev_result),
+ Span<const uint8_t>(prev_prev_result)});
}
template <const EVP_MD *HashFunc()>
-static bool HMAC(const Span<const uint8_t> args[]) {
+static bool HMAC(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const EVP_MD *const md = HashFunc();
uint8_t digest[EVP_MAX_MD_SIZE];
unsigned digest_len;
@@ -1251,10 +1331,10 @@ static bool HMAC(const Span<const uint8_t> args[]) {
digest, &digest_len) == nullptr) {
return false;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(digest, digest_len));
+ return write_reply({Span<const uint8_t>(digest, digest_len)});
}
-static bool DRBG(const Span<const uint8_t> args[]) {
+static bool DRBG(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const auto out_len_bytes = args[0];
const auto entropy = args[1];
const auto personalisation = args[2];
@@ -1285,7 +1365,7 @@ static bool DRBG(const Span<const uint8_t> args[]) {
return false;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(out));
+ return write_reply({Span<const uint8_t>(out)});
}
static bool StringEq(Span<const uint8_t> a, const char *b) {
@@ -1333,7 +1413,7 @@ static std::pair<std::vector<uint8_t>, std::vector<uint8_t>> GetPublicKeyBytes(
return std::make_pair(std::move(x_bytes), std::move(y_bytes));
}
-static bool ECDSAKeyGen(const Span<const uint8_t> args[]) {
+static bool ECDSAKeyGen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
if (!key || !EC_KEY_generate_key_fips(key.get())) {
return false;
@@ -1343,9 +1423,9 @@ static bool ECDSAKeyGen(const Span<const uint8_t> args[]) {
std::vector<uint8_t> d_bytes =
BIGNUMBytes(EC_KEY_get0_private_key(key.get()));
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(d_bytes),
- Span<const uint8_t>(pub_key.first),
- Span<const uint8_t>(pub_key.second));
+ return write_reply({Span<const uint8_t>(d_bytes),
+ Span<const uint8_t>(pub_key.first),
+ Span<const uint8_t>(pub_key.second)});
}
static bssl::UniquePtr<BIGNUM> BytesToBIGNUM(Span<const uint8_t> bytes) {
@@ -1354,7 +1434,7 @@ static bssl::UniquePtr<BIGNUM> BytesToBIGNUM(Span<const uint8_t> bytes) {
return bn;
}
-static bool ECDSAKeyVer(const Span<const uint8_t> args[]) {
+static bool ECDSAKeyVer(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
if (!key) {
return false;
@@ -1375,7 +1455,7 @@ static bool ECDSAKeyVer(const Span<const uint8_t> args[]) {
reply[0] = 1;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(reply));
+ return write_reply({Span<const uint8_t>(reply)});
}
static const EVP_MD *HashFromName(Span<const uint8_t> name) {
@@ -1392,7 +1472,7 @@ static const EVP_MD *HashFromName(Span<const uint8_t> name) {
}
}
-static bool ECDSASigGen(const Span<const uint8_t> args[]) {
+static bool ECDSASigGen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
bssl::UniquePtr<BIGNUM> d = BytesToBIGNUM(args[1]);
const EVP_MD *hash = HashFromName(args[2]);
@@ -1413,11 +1493,11 @@ static bool ECDSASigGen(const Span<const uint8_t> args[]) {
std::vector<uint8_t> r_bytes(BIGNUMBytes(sig->r));
std::vector<uint8_t> s_bytes(BIGNUMBytes(sig->s));
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(r_bytes),
- Span<const uint8_t>(s_bytes));
+ return write_reply(
+ {Span<const uint8_t>(r_bytes), Span<const uint8_t>(s_bytes)});
}
-static bool ECDSASigVer(const Span<const uint8_t> args[]) {
+static bool ECDSASigVer(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<EC_KEY> key = ECKeyFromName(args[0]);
const EVP_MD *hash = HashFromName(args[1]);
auto msg = args[2];
@@ -1450,10 +1530,10 @@ static bool ECDSASigVer(const Span<const uint8_t> args[]) {
reply[0] = 1;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(reply));
+ return write_reply({Span<const uint8_t>(reply)});
}
-static bool CMAC_AES(const Span<const uint8_t> args[]) {
+static bool CMAC_AES(const Span<const uint8_t> args[], ReplyCallback write_reply) {
uint8_t mac[16];
if (!AES_CMAC(mac, args[1].data(), args[1].size(), args[2].data(),
args[2].size())) {
@@ -1469,10 +1549,10 @@ static bool CMAC_AES(const Span<const uint8_t> args[]) {
return false;
}
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(mac, mac_len));
+ return write_reply({Span<const uint8_t>(mac, mac_len)});
}
-static bool CMAC_AESVerify(const Span<const uint8_t> args[]) {
+static bool CMAC_AESVerify(const Span<const uint8_t> args[], ReplyCallback write_reply) {
// This function is just for testing since libcrypto doesn't do the
// verification itself. The regcap doesn't advertise "ver" support.
uint8_t mac[16];
@@ -1483,7 +1563,7 @@ static bool CMAC_AESVerify(const Span<const uint8_t> args[]) {
}
const uint8_t ok = OPENSSL_memcmp(mac, args[2].data(), args[2].size());
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(&ok, sizeof(ok)));
+ return write_reply({Span<const uint8_t>(&ok, sizeof(ok))});
}
static std::map<unsigned, bssl::UniquePtr<RSA>>& CachedRSAKeys() {
@@ -1508,7 +1588,7 @@ static RSA* GetRSAKey(unsigned bits) {
return ret;
}
-static bool RSAKeyGen(const Span<const uint8_t> args[]) {
+static bool RSAKeyGen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
uint32_t bits;
if (args[0].size() != sizeof(bits)) {
return false;
@@ -1517,8 +1597,7 @@ static bool RSAKeyGen(const Span<const uint8_t> args[]) {
bssl::UniquePtr<RSA> key(RSA_new());
if (!RSA_generate_key_fips(key.get(), bits, nullptr)) {
- fprintf(stderr, "RSA_generate_key_fips failed for modulus length %u.\n",
- bits);
+ LOG_ERROR("RSA_generate_key_fips failed for modulus length %u.\n", bits);
return false;
}
@@ -1526,8 +1605,8 @@ static bool RSAKeyGen(const Span<const uint8_t> args[]) {
RSA_get0_key(key.get(), &n, &e, &d);
RSA_get0_factors(key.get(), &p, &q);
- if (!WriteReply(STDOUT_FILENO, BIGNUMBytes(e), BIGNUMBytes(p), BIGNUMBytes(q),
- BIGNUMBytes(n), BIGNUMBytes(d))) {
+ if (!write_reply({BIGNUMBytes(e), BIGNUMBytes(p), BIGNUMBytes(q),
+ BIGNUMBytes(n), BIGNUMBytes(d)})) {
return false;
}
@@ -1535,8 +1614,8 @@ static bool RSAKeyGen(const Span<const uint8_t> args[]) {
return true;
}
-template<const EVP_MD *(MDFunc)(), bool UsePSS>
-static bool RSASigGen(const Span<const uint8_t> args[]) {
+template <const EVP_MD *(MDFunc)(), bool UsePSS>
+static bool RSASigGen(const Span<const uint8_t> args[], ReplyCallback write_reply) {
uint32_t bits;
if (args[0].size() != sizeof(bits)) {
return false;
@@ -1570,12 +1649,12 @@ static bool RSASigGen(const Span<const uint8_t> args[]) {
sig.resize(sig_len);
- return WriteReply(STDOUT_FILENO, BIGNUMBytes(RSA_get0_n(key)),
- BIGNUMBytes(RSA_get0_e(key)), sig);
+ return write_reply(
+ {BIGNUMBytes(RSA_get0_n(key)), BIGNUMBytes(RSA_get0_e(key)), sig});
}
-template<const EVP_MD *(MDFunc)(), bool UsePSS>
-static bool RSASigVer(const Span<const uint8_t> args[]) {
+template <const EVP_MD *(MDFunc)(), bool UsePSS>
+static bool RSASigVer(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const Span<const uint8_t> n_bytes = args[0];
const Span<const uint8_t> e_bytes = args[1];
const Span<const uint8_t> msg = args[2];
@@ -1607,11 +1686,11 @@ static bool RSASigVer(const Span<const uint8_t> args[]) {
}
ERR_clear_error();
- return WriteReply(STDOUT_FILENO, Span<const uint8_t>(&ok, 1));
+ return write_reply({Span<const uint8_t>(&ok, 1)});
}
-template<const EVP_MD *(MDFunc)()>
-static bool TLSKDF(const Span<const uint8_t> args[]) {
+template <const EVP_MD *(MDFunc)()>
+static bool TLSKDF(const Span<const uint8_t> args[], ReplyCallback write_reply) {
const Span<const uint8_t> out_len_bytes = args[0];
const Span<const uint8_t> secret = args[1];
const Span<const uint8_t> label = args[2];
@@ -1633,11 +1712,11 @@ static bool TLSKDF(const Span<const uint8_t> args[]) {
return 0;
}
- return WriteReply(STDOUT_FILENO, out);
+ return write_reply({out});
}
template <int Nid>
-static bool ECDH(const Span<const uint8_t> args[]) {
+static bool ECDH(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<BIGNUM> their_x(BytesToBIGNUM(args[0]));
bssl::UniquePtr<BIGNUM> their_y(BytesToBIGNUM(args[1]));
const Span<const uint8_t> private_key = args[2];
@@ -1649,14 +1728,14 @@ static bool ECDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<EC_POINT> their_point(EC_POINT_new(group));
if (!EC_POINT_set_affine_coordinates_GFp(
group, their_point.get(), their_x.get(), their_y.get(), ctx.get())) {
- fprintf(stderr, "Invalid peer point for ECDH.\n");
+ LOG_ERROR("Invalid peer point for ECDH.\n");
return false;
}
if (!private_key.empty()) {
bssl::UniquePtr<BIGNUM> our_k(BytesToBIGNUM(private_key));
if (!EC_KEY_set_private_key(ec_key.get(), our_k.get())) {
- fprintf(stderr, "EC_KEY_set_private_key failed.\n");
+ LOG_ERROR("EC_KEY_set_private_key failed.\n");
return false;
}
@@ -1664,11 +1743,11 @@ static bool ECDH(const Span<const uint8_t> args[]) {
if (!EC_POINT_mul(group, our_pub.get(), our_k.get(), nullptr, nullptr,
ctx.get()) ||
!EC_KEY_set_public_key(ec_key.get(), our_pub.get())) {
- fprintf(stderr, "Calculating public key failed.\n");
+ LOG_ERROR("Calculating public key failed.\n");
return false;
}
} else if (!EC_KEY_generate_key_fips(ec_key.get())) {
- fprintf(stderr, "EC_KEY_generate_key_fips failed.\n");
+ LOG_ERROR("EC_KEY_generate_key_fips failed.\n");
return false;
}
@@ -1679,10 +1758,10 @@ static bool ECDH(const Span<const uint8_t> args[]) {
ECDH_compute_key(output.data(), output.size(), their_point.get(),
ec_key.get(), /*kdf=*/nullptr);
if (out_len < 0) {
- fprintf(stderr, "ECDH_compute_key failed.\n");
+ LOG_ERROR("ECDH_compute_key failed.\n");
return false;
} else if (static_cast<size_t>(out_len) == output.size()) {
- fprintf(stderr, "ECDH_compute_key output may have been truncated.\n");
+ LOG_ERROR("ECDH_compute_key output may have been truncated.\n");
return false;
}
output.resize(static_cast<size_t>(out_len));
@@ -1692,15 +1771,14 @@ static bool ECDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<BIGNUM> y(BN_new());
if (!EC_POINT_get_affine_coordinates_GFp(group, pub, x.get(), y.get(),
ctx.get())) {
- fprintf(stderr, "EC_POINT_get_affine_coordinates_GFp failed.\n");
+ LOG_ERROR("EC_POINT_get_affine_coordinates_GFp failed.\n");
return false;
}
- return WriteReply(STDOUT_FILENO, BIGNUMBytes(x.get()), BIGNUMBytes(y.get()),
- output);
+ return write_reply({BIGNUMBytes(x.get()), BIGNUMBytes(y.get()), output});
}
-static bool FFDH(const Span<const uint8_t> args[]) {
+static bool FFDH(const Span<const uint8_t> args[], ReplyCallback write_reply) {
bssl::UniquePtr<BIGNUM> p(BytesToBIGNUM(args[0]));
bssl::UniquePtr<BIGNUM> q(BytesToBIGNUM(args[1]));
bssl::UniquePtr<BIGNUM> g(BytesToBIGNUM(args[2]));
@@ -1710,7 +1788,7 @@ static bool FFDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<DH> dh(DH_new());
if (!DH_set0_pqg(dh.get(), p.get(), q.get(), g.get())) {
- fprintf(stderr, "DH_set0_pqg failed.\n");
+ LOG_ERROR("DH_set0_pqg failed.\n");
return 0;
}
@@ -1724,7 +1802,7 @@ static bool FFDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<BIGNUM> public_key(BytesToBIGNUM(public_key_span));
if (!DH_set0_key(dh.get(), public_key.get(), private_key.get())) {
- fprintf(stderr, "DH_set0_key failed.\n");
+ LOG_ERROR("DH_set0_key failed.\n");
return 0;
}
@@ -1732,24 +1810,24 @@ static bool FFDH(const Span<const uint8_t> args[]) {
public_key.release();
private_key.release();
} else if (!DH_generate_key(dh.get())) {
- fprintf(stderr, "DH_generate_key failed.\n");
+ LOG_ERROR("DH_generate_key failed.\n");
return false;
}
std::vector<uint8_t> z(DH_size(dh.get()));
if (DH_compute_key_padded(z.data(), their_pub.get(), dh.get()) !=
static_cast<int>(z.size())) {
- fprintf(stderr, "DH_compute_key_hashed failed.\n");
+ LOG_ERROR("DH_compute_key_hashed failed.\n");
return false;
}
- return WriteReply(STDOUT_FILENO, BIGNUMBytes(DH_get0_pub_key(dh.get())), z);
+ return write_reply({BIGNUMBytes(DH_get0_pub_key(dh.get())), z});
}
static constexpr struct {
- const char name[kMaxNameLength + 1];
- uint8_t expected_args;
- bool (*handler)(const Span<const uint8_t>[]);
+ char name[kMaxNameLength + 1];
+ uint8_t num_expected_args;
+ bool (*handler)(const Span<const uint8_t> args[], ReplyCallback write_reply);
} kFunctions[] = {
{"getConfig", 0, GetConfig},
{"SHA-1", 1, Hash<SHA1, SHA_DIGEST_LENGTH>},
@@ -1820,98 +1898,26 @@ static constexpr struct {
{"FFDH", 6, FFDH},
};
-int main() {
- uint32_t nums[1 + kMaxArgs];
- std::unique_ptr<uint8_t[]> buf;
- size_t buf_len = 0;
- Span<const uint8_t> args[kMaxArgs];
-
- for (;;) {
- if (!ReadAll(STDIN_FILENO, nums, sizeof(uint32_t) * 2)) {
- return 1;
- }
-
- const size_t num_args = nums[0];
- if (num_args == 0) {
- fprintf(stderr, "Invalid, zero-argument operation requested.\n");
- return 2;
- } else if (num_args > kMaxArgs) {
- fprintf(stderr,
- "Operation requested with %zu args, but %zu is the limit.\n",
- num_args, kMaxArgs);
- return 2;
- }
-
- if (num_args > 1 &&
- !ReadAll(STDIN_FILENO, &nums[2], sizeof(uint32_t) * (num_args - 1))) {
- return 1;
- }
-
- size_t need = 0;
- for (size_t i = 0; i < num_args; i++) {
- const size_t arg_length = nums[i + 1];
- if (i == 0 && arg_length > kMaxNameLength) {
- fprintf(stderr,
- "Operation with name of length %zu exceeded limit of %zu.\n",
- arg_length, kMaxNameLength);
- return 2;
- } else if (arg_length > kMaxArgLength) {
- fprintf(
- stderr,
- "Operation with argument of length %zu exceeded limit of %zu.\n",
- arg_length, kMaxArgLength);
- return 2;
+Handler FindHandler(Span<const Span<const uint8_t>> args) {
+ const bssl::Span<const uint8_t> algorithm = args[0];
+ for (const auto &func : kFunctions) {
+ if (algorithm.size() == strlen(func.name) &&
+ memcmp(algorithm.data(), func.name, algorithm.size()) == 0) {
+ if (args.size() - 1 != func.num_expected_args) {
+ LOG_ERROR("\'%s\' operation received %zu arguments but expected %u.\n",
+ func.name, args.size() - 1, func.num_expected_args);
+ return nullptr;
}
- // static_assert around kMaxArgs etc enforces that this doesn't overflow.
- need += arg_length;
- }
-
- if (need > buf_len) {
- size_t alloced = need + (need >> 1);
- if (alloced < need) {
- abort();
- }
- buf.reset(new uint8_t[alloced]);
- buf_len = alloced;
- }
-
- if (!ReadAll(STDIN_FILENO, buf.get(), need)) {
- return 1;
- }
-
- size_t offset = 0;
- for (size_t i = 0; i < num_args; i++) {
- args[i] = Span<const uint8_t>(&buf[offset], nums[i + 1]);
- offset += nums[i + 1];
- }
-
- bool found = false;
- for (const auto &func : kFunctions) {
- if (args[0].size() == strlen(func.name) &&
- memcmp(args[0].data(), func.name, args[0].size()) == 0) {
- if (num_args - 1 != func.expected_args) {
- fprintf(stderr,
- "\'%s\' operation received %zu arguments but expected %u.\n",
- func.name, num_args - 1, func.expected_args);
- return 2;
- }
-
- if (!func.handler(&args[1])) {
- fprintf(stderr, "\'%s\' operation failed.\n", func.name);
- return 4;
- }
-
- found = true;
- break;
- }
- }
-
- if (!found) {
- const std::string name(reinterpret_cast<const char *>(args[0].data()),
- args[0].size());
- fprintf(stderr, "Unknown operation: %s\n", name.c_str());
- return 3;
+ return func.handler;
}
}
+
+ const std::string name(reinterpret_cast<const char *>(algorithm.data()),
+ algorithm.size());
+ LOG_ERROR("Unknown operation: %s\n", name.c_str());
+ return nullptr;
}
+
+} // namespace acvp
+} // namespace bssl
diff --git a/src/util/fipstools/acvp/modulewrapper/modulewrapper.h b/src/util/fipstools/acvp/modulewrapper/modulewrapper.h
new file mode 100644
index 00000000..0472800f
--- /dev/null
+++ b/src/util/fipstools/acvp/modulewrapper/modulewrapper.h
@@ -0,0 +1,69 @@
+/* Copyright (c) 2021, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/base.h>
+
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include <openssl/span.h>
+
+
+namespace bssl {
+namespace acvp {
+
+// kMaxArgs is the maximum number of arguments (including the function name)
+// that an ACVP request can contain.
+constexpr size_t kMaxArgs = 8;
+// kMaxNameLength is the maximum length of a function name in an ACVP request.
+constexpr size_t kMaxNameLength = 30;
+
+// RequestBuffer holds various buffers needed for parsing an ACVP request. It
+// can be reused between requests.
+class RequestBuffer {
+ public:
+ virtual ~RequestBuffer();
+
+ static std::unique_ptr<RequestBuffer> New();
+};
+
+// ParseArgsFromFd returns a span of arguments, the first of which is the name
+// of the requested function, from |fd|. The return values point into |buffer|
+// and so must not be used after |buffer| has been freed or reused for a
+// subsequent call. It returns an empty span on error, because std::optional
+// is still too new.
+Span<const Span<const uint8_t>> ParseArgsFromFd(int fd, RequestBuffer *buffer);
+
+// WriteReplyToFd writes a reply to the given file descriptor.
+bool WriteReplyToFd(int fd, const std::vector<Span<const uint8_t>> &spans);
+
+// ReplyCallback is the type of a callback that writes a reply to an ACVP
+// request.
+typedef std::function<bool(const std::vector<Span<const uint8_t>> &)>
+ ReplyCallback;
+
+// Handler is the type of a function that handles a specific ACVP request. If
+// successful it will call |write_reply| with the response arguments and return
+// |write_reply|'s return value. Otherwise it will return false. The given args
+// must not include the name at the beginning.
+typedef bool (*Handler)(const Span<const uint8_t> args[],
+ ReplyCallback write_reply);
+
+// FindHandler returns a |Handler| that can process the given arguments, or logs
+// a reason and returns |nullptr| if none is found.
+Handler FindHandler(Span<const Span<const uint8_t>> args);
+
+} // namespace acvp
+} // namespace bssl