diff options
author | Pete Bentley <prb@google.com> | 2021-03-03 14:46:47 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-03-03 14:46:47 +0000 |
commit | 2de7559e47c141dcdb33fad468146c22a7c06228 (patch) | |
tree | 47a1e4993815ca9633235a86567a56a8fe8d74f2 | |
parent | c46dcead384cc4f628bd6d16c5f63f3bd159098e (diff) | |
parent | ff86bdb9ab7cfab0cc856e7cb9609fe8c778adfc (diff) | |
download | boringssl-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.bp | 28 | ||||
-rw-r--r-- | src/util/fipstools/acvp/modulewrapper/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/util/fipstools/acvp/modulewrapper/main.cc | 49 | ||||
-rw-r--r-- | src/util/fipstools/acvp/modulewrapper/modulewrapper.cc | 482 | ||||
-rw-r--r-- | src/util/fipstools/acvp/modulewrapper/modulewrapper.h | 69 |
5 files changed, 390 insertions, 239 deletions
@@ -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 |