diff --git a/.github/workflows/windows-alt.yml b/.github/workflows/windows-alt.yml index cd25417e390..5a269cc1cb0 100644 --- a/.github/workflows/windows-alt.yml +++ b/.github/workflows/windows-alt.yml @@ -228,7 +228,7 @@ jobs: echo "GOPATH=${SYSROOT}" >> $GITHUB_ENV echo "GOROOT=${SYSROOT}/lib/go" >> $GITHUB_ENV echo "CMAKE_GENERATOR=${{ matrix.generator }}" >> $GITHUB_ENV - cygpath -w ${SYSROOT}/bin >> $GITHUB_PATH + cygpath -m ${SYSROOT}/bin >> $GITHUB_PATH - name: Checkout uses: actions/checkout@v4 - name: Setup CMake @@ -244,10 +244,5 @@ jobs: CMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ CMAKE_BUILD_TYPE=Release \ - name: Run tests - if: matrix.generator != 'MSYS Makefiles' - shell: 'bash' - run: cmake --build ./build --target run_tests - - name: Run tests - if: matrix.generator == 'MSYS Makefiles' shell: 'msys2 {0}' run: cmake --build ./build --target run_tests diff --git a/tool-openssl/CMakeLists.txt b/tool-openssl/CMakeLists.txt index e831809a294..4c356787480 100644 --- a/tool-openssl/CMakeLists.txt +++ b/tool-openssl/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable( pass_util.cc pkcs8.cc pkey.cc + pkeyutl.cc rehash.cc req.cc ordered_args.cc @@ -100,6 +101,8 @@ if(BUILD_TESTING) pkcs8_test.cc pkey.cc pkey_test.cc + pkeyutl.cc + pkeyutl_test.cc rehash.cc rehash_test.cc req.cc diff --git a/tool-openssl/internal.h b/tool-openssl/internal.h index 058cabfbfd6..abc9f5ef4b7 100644 --- a/tool-openssl/internal.h +++ b/tool-openssl/internal.h @@ -96,6 +96,7 @@ bool ecTool(const args_list_t &args); bool md5Tool(const args_list_t &args); bool pkcs8Tool(const args_list_t &args); bool pkeyTool(const args_list_t &args); +bool pkeyutlTool(const args_list_t &args); bool RehashTool(const args_list_t &args); bool reqTool(const args_list_t &args); bool rsaTool(const args_list_t &args); diff --git a/tool-openssl/pkeyutl.cc b/tool-openssl/pkeyutl.cc new file mode 100644 index 00000000000..be5592deac3 --- /dev/null +++ b/tool-openssl/pkeyutl.cc @@ -0,0 +1,318 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include +#include +#include +#include +#include +#include "internal.h" +#include + +#define KEY_NONE 0 +#define KEY_PRIVKEY 1 +#define KEY_PUBKEY 2 + +static const argument_t kArguments[] = { + { "-help", kBooleanArgument, "Display option summary" }, + { "-in", kOptionalArgument, "Input file - default stdin" }, + { "-out", kOptionalArgument, "Output file - default stdout" }, + { "-sign", kBooleanArgument, "Sign input data with private key" }, + { "-verify", kBooleanArgument, "Verify with public key" }, + { "-sigfile", kOptionalArgument, "Signature file, required for verify operations only" }, + { "-inkey", kOptionalArgument, "Input private key file" }, + { "-pubin", kBooleanArgument, "Input is a public key" }, + { "-passin", kOptionalArgument, "Input file pass phrase source" }, + { "", kOptionalArgument, "" } +}; + +static bool LoadPrivateKey(const std::string &keyfile, bssl::UniquePtr &passin_arg, + bssl::UniquePtr &pkey) { + ScopedFILE key_file; + if (keyfile.empty()) { + fprintf(stderr, "Error: no private key given (-inkey parameter)\n"); + return false; + } + + key_file.reset(fopen(keyfile.c_str(), "rb")); + if (!key_file) { + fprintf(stderr, "Error: unable to load private key from '%s'\n", keyfile.c_str()); + return false; + } + + // Extract password using pass_util if provided + const char *password = nullptr; + if (passin_arg && !passin_arg->empty()) { + if (!pass_util::ExtractPassword(passin_arg)) { + fprintf(stderr, "Error: failed to extract password\n"); + return false; + } + password = passin_arg->c_str(); + } + + pkey.reset(PEM_read_PrivateKey(key_file.get(), nullptr, nullptr, + const_cast(password))); + if (!pkey) { + fprintf(stderr, "Error: error reading private key from '%s'\n", keyfile.c_str()); + ERR_print_errors_fp(stderr); + return false; + } + + return true; +} + +static bool LoadPublicKey(const std::string &keyfile, bssl::UniquePtr &pkey) { + ScopedFILE key_file; + if (keyfile.empty()) { + fprintf(stderr, "Error: no public key given (-inkey parameter)\n"); + return false; + } + + key_file.reset(fopen(keyfile.c_str(), "rb")); + if (!key_file) { + fprintf(stderr, "Error: unable to load public key from '%s'\n", keyfile.c_str()); + return false; + } + + pkey.reset(PEM_read_PUBKEY(key_file.get(), nullptr, nullptr, nullptr)); + if (!pkey) { + fprintf(stderr, "Error: error reading public key from '%s'\n", keyfile.c_str()); + ERR_print_errors_fp(stderr); + return false; + } + + return true; +} + +static bool ReadInputData(const std::string &in_path, std::vector &data) { + ScopedFILE in_file; + if (in_path.empty()) { + in_file.reset(stdin); + } else { + in_file.reset(fopen(in_path.c_str(), "rb")); + if (!in_file) { + fprintf(stderr, "Error: unable to open input file '%s'\n", in_path.c_str()); + return false; + } + } + + if (!ReadAll(&data, in_file.get())) { + fprintf(stderr, "Error: error reading input data\n"); + return false; + } + + return true; +} + +static bool DoSign(EVP_PKEY *pkey, const std::vector &input_data, + std::vector &signature) { + bssl::UniquePtr ctx(EVP_PKEY_CTX_new(pkey, nullptr)); + if (!ctx) { + fprintf(stderr, "Error: failed to create signing context\n"); + return false; + } + + if (EVP_PKEY_sign_init(ctx.get()) <= 0) { + fprintf(stderr, "Error: failed to initialize signing context\n"); + ERR_print_errors_fp(stderr); + return false; + } + + size_t sig_len = 0; + if (EVP_PKEY_sign(ctx.get(), nullptr, &sig_len, input_data.data(), input_data.size()) <= 0) { + fprintf(stderr, "Error: failed to determine signature length\n"); + ERR_print_errors_fp(stderr); + return false; + } + + signature.resize(sig_len); + if (EVP_PKEY_sign(ctx.get(), signature.data(), &sig_len, + input_data.data(), input_data.size()) <= 0) { + fprintf(stderr, "Error: failed to sign data\n"); + ERR_print_errors_fp(stderr); + return false; + } + + signature.resize(sig_len); + return true; +} + +static bool DoVerify(EVP_PKEY *pkey, const std::vector &input_data, + const std::vector &signature) { + bssl::UniquePtr ctx(EVP_PKEY_CTX_new(pkey, nullptr)); + if (!ctx) { + fprintf(stderr, "Error: failed to create verification context\n"); + return false; + } + + if (EVP_PKEY_verify_init(ctx.get()) <= 0) { + fprintf(stderr, "Error: failed to initialize verification context\n"); + ERR_print_errors_fp(stderr); + return false; + } + + int result = EVP_PKEY_verify(ctx.get(), signature.data(), signature.size(), + input_data.data(), input_data.size()); + if (result == 1) { + return true; + } else if (result == 0) { + return false; // Verification failed + } else { + fprintf(stderr, "Error: verification operation failed\n"); + ERR_print_errors_fp(stderr); + return false; + } +} + +static bool WriteOutput(const std::vector &data, const std::string &out_path) { + bssl::UniquePtr output_bio; + if (out_path.empty()) { + output_bio.reset(BIO_new_fp(stdout, BIO_CLOSE)); + } else { + output_bio.reset(BIO_new(BIO_s_file())); + if (BIO_write_filename(output_bio.get(), out_path.c_str()) <= 0) { + fprintf(stderr, "Error: failed to open output file '%s'\n", out_path.c_str()); + return false; + } + } + + if (!output_bio) { + fprintf(stderr, "Error: unable to create output BIO\n"); + return false; + } + + BIO_write(output_bio.get(), data.data(), data.size()); + return true; +} + +bool pkeyutlTool(const args_list_t &args) { + using namespace ordered_args; + ordered_args_map_t parsed_args; + args_list_t extra_args; + + if (!ParseOrderedKeyValueArguments(parsed_args, extra_args, args, kArguments) || + extra_args.size() > 0) { + PrintUsage(kArguments); + return false; + } + + std::string in_path, out_path, inkey_path, sigfile_path; + // Use sensitive string handling for password + bssl::UniquePtr passin_arg(new std::string()); + bool sign = false, verify = false, pubin = false; + + GetString(&in_path, "-in", "", parsed_args); + GetString(&out_path, "-out", "", parsed_args); + GetString(&inkey_path, "-inkey", "", parsed_args); + GetString(passin_arg.get(), "-passin", "", parsed_args); + GetString(&sigfile_path, "-sigfile", "", parsed_args); + GetBoolArgument(&sign, "-sign", parsed_args); + GetBoolArgument(&verify, "-verify", parsed_args); + GetBoolArgument(&pubin, "-pubin", parsed_args); + + // Display help + if (HasArgument(parsed_args, "-help")) { + PrintUsage(kArguments); + return true; + } + + // Validate arguments + if (!sign && !verify) { + fprintf(stderr, "Error: must specify either -sign or -verify\n"); + return false; + } + + if (sign && verify) { + fprintf(stderr, "Error: cannot specify both -sign and -verify\n"); + return false; + } + + if (verify && sigfile_path.empty()) { + fprintf(stderr, "Error: No signature file specified for verify (-sigfile parameter)\n"); + return false; + } + + if (!verify && !sigfile_path.empty()) { + fprintf(stderr, "Error: Signature file specified for non-verify operation\n"); + return false; + } + + if (inkey_path.empty()) { + fprintf(stderr, "Error: no key given (-inkey parameter)\n"); + return false; + } + + // Load the key + bssl::UniquePtr pkey; + if (pubin || verify) { + if (!LoadPublicKey(inkey_path, pkey)) { + return false; + } + } else { + if (!LoadPrivateKey(inkey_path, passin_arg, pkey)) { + return false; + } + } + + if (sign) { + std::vector signature; + std::vector input_data; + if (!ReadInputData(in_path, input_data)) { + return false; + } + + // Sanity check for non-raw input + if (input_data.size() > EVP_MAX_MD_SIZE) { + fprintf(stderr, "Error: input data looks too long to be a hash\n"); + return false; + } + + if (!DoSign(pkey.get(), input_data, signature)) { + return false; + } + + if (!WriteOutput(signature, out_path)) { + return false; + } + } else if (verify) { + // Read signature from sigfile + std::vector signature; + ScopedFILE sig_file; + sig_file.reset(fopen(sigfile_path.c_str(), "rb")); + if (!sig_file) { + fprintf(stderr, "Error: unable to open signature file '%s'\n", sigfile_path.c_str()); + return false; + } + + if (!ReadAll(&signature, sig_file.get())) { + fprintf(stderr, "Error: error reading signature data\n"); + return false; + } + + std::vector input_data; + if (!ReadInputData(in_path, input_data)) { + return false; + } + + bool success = DoVerify(pkey.get(), input_data, signature); + + bssl::UniquePtr output_bio; + if (out_path.empty()) { + output_bio.reset(BIO_new_fp(stdout, BIO_CLOSE)); + } else { + output_bio.reset(BIO_new(BIO_s_file())); + if (BIO_write_filename(output_bio.get(), out_path.c_str()) <= 0) { + fprintf(stderr, "Error: failed to open output file '%s'\n", out_path.c_str()); + return false; + } + } + + if (success) { + BIO_puts(output_bio.get(), "Signature Verified Successfully\n"); + } else { + BIO_puts(output_bio.get(), "Signature Verification Failure\n"); + } + } + + return true; +} diff --git a/tool-openssl/pkeyutl_test.cc b/tool-openssl/pkeyutl_test.cc new file mode 100644 index 00000000000..91bd86e6ebe --- /dev/null +++ b/tool-openssl/pkeyutl_test.cc @@ -0,0 +1,296 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include +#include +#include +#include +#include "internal.h" +#include "test_util.h" +#include "../crypto/test/test_util.h" +#include + +class PKeyUtlTest : public ::testing::Test { +protected: + void SetUp() override { + ASSERT_GT(createTempFILEpath(in_path), 0u); + ASSERT_GT(createTempFILEpath(out_path), 0u); + ASSERT_GT(createTempFILEpath(sig_path), 0u); + ASSERT_GT(createTempFILEpath(key_path), 0u); + ASSERT_GT(createTempFILEpath(pubkey_path), 0u); + ASSERT_GT(createTempFILEpath(protected_key_path), 0u); + + // Create and save a private key in PEM format + bssl::UniquePtr pkey(CreateTestKey(2048)); + ASSERT_TRUE(pkey); + + ScopedFILE key_file(fopen(key_path, "wb")); + ASSERT_TRUE(key_file); + ASSERT_TRUE(PEM_write_PrivateKey(key_file.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr)); + + // Create a public key file + ScopedFILE pubkey_file(fopen(pubkey_path, "wb")); + ASSERT_TRUE(pubkey_file); + ASSERT_TRUE(PEM_write_PUBKEY(pubkey_file.get(), pkey.get())); + + // Create a password-protected private key + ScopedFILE protected_key_file(fopen(protected_key_path, "wb")); + ASSERT_TRUE(protected_key_file); + ASSERT_TRUE(PEM_write_PrivateKey(protected_key_file.get(), pkey.get(), + EVP_aes_256_cbc(), + (unsigned char*)"testpassword", 12, + nullptr, nullptr)); + + // Create a test input file with some data + ScopedFILE in_file(fopen(in_path, "wb")); + ASSERT_TRUE(in_file); + const char* test_data = "Test data for signing and verification"; + ASSERT_EQ(fwrite(test_data, 1, strlen(test_data), in_file.get()), strlen(test_data)); + } + + void TearDown() override { + RemoveFile(in_path); + RemoveFile(out_path); + RemoveFile(sig_path); + RemoveFile(key_path); + RemoveFile(pubkey_path); + RemoveFile(protected_key_path); + } + + char in_path[PATH_MAX]; + char out_path[PATH_MAX]; + char sig_path[PATH_MAX]; + char key_path[PATH_MAX]; + char pubkey_path[PATH_MAX]; + char protected_key_path[PATH_MAX]; +}; + +// ----------------------------- PKeyUtl Option Tests ----------------------------- + +// Test basic signing operation +TEST_F(PKeyUtlTest, SignTest) { + args_list_t args = {"-sign", "-inkey", key_path, "-in", in_path, "-out", out_path}; + bool result = pkeyutlTool(args); + ASSERT_TRUE(result); + + // Verify the signature file was created and has content + struct stat st; + ASSERT_EQ(stat(out_path, &st), 0); + ASSERT_GT(st.st_size, 0); +} + +// Test basic verification operation +TEST_F(PKeyUtlTest, VerifyTest) { + // First sign the data + { + args_list_t args = {"-sign", "-inkey", key_path, "-in", in_path, "-out", sig_path}; + bool result = pkeyutlTool(args); + ASSERT_TRUE(result); + } + + // Then verify the signature + { + args_list_t args = {"-verify", "-pubin", "-inkey", pubkey_path, "-in", in_path, + "-sigfile", sig_path, "-out", out_path}; + bool result = pkeyutlTool(args); + ASSERT_TRUE(result); + + // Check that the output contains "Signature Verified Successfully" + std::string output = ReadFileToString(out_path); + ASSERT_NE(output.find("Signature Verified Successfully"), std::string::npos); + } +} + +// Test basic passin integration with password-protected key +TEST_F(PKeyUtlTest, PassinBasicIntegrationTest) { + args_list_t args = {"-sign", "-inkey", protected_key_path, "-passin", "pass:testpassword", "-in", in_path, "-out", out_path}; + bool result = pkeyutlTool(args); + ASSERT_TRUE(result); + + struct stat st; + ASSERT_EQ(stat(out_path, &st), 0); + ASSERT_GT(st.st_size, 0); +} + +// Test that pass_util errors are properly propagated +TEST_F(PKeyUtlTest, PassinErrorHandlingTest) { + args_list_t args = {"-sign", "-inkey", protected_key_path, "-passin", "invalid:format", "-in", in_path, "-out", out_path}; + bool result = pkeyutlTool(args); + ASSERT_FALSE(result); + + args_list_t args2 = {"-sign", "-inkey", protected_key_path, "-passin", "pass:wrongpassword", "-in", in_path, "-out", out_path}; + bool result2 = pkeyutlTool(args2); + ASSERT_FALSE(result2); +} + +// Test that unprotected key works without passin +TEST_F(PKeyUtlTest, NoPassinRequiredTest) { + args_list_t args = {"-sign", "-inkey", key_path, "-in", in_path, "-out", out_path}; + bool result = pkeyutlTool(args); + ASSERT_TRUE(result); + + // Verify the signature file was created and has content + struct stat st; + ASSERT_EQ(stat(out_path, &st), 0); + ASSERT_GT(st.st_size, 0); +} + +// -------------------- PKeyUtl Option Usage Error Tests -------------------------- + +class PKeyUtlOptionUsageErrorsTest : public PKeyUtlTest { +protected: + void TestOptionUsageErrors(const std::vector& args) { + args_list_t c_args; + for (const auto& arg : args) { + c_args.push_back(arg.c_str()); + } + bool result = pkeyutlTool(c_args); + ASSERT_FALSE(result); + } +}; + +// Test invalid option combinations +TEST_F(PKeyUtlOptionUsageErrorsTest, InvalidOptionCombinationsTest) { + std::vector> testparams = { + // Both sign and verify specified + {"-sign", "-verify", "-inkey", key_path, "-in", in_path}, + // Missing inkey + {"-sign", "-in", in_path}, + // Verify without sigfile + {"-verify", "-inkey", key_path, "-in", in_path}, + // Sigfile with sign operation + {"-sign", "-inkey", key_path, "-in", in_path, "-sigfile", sig_path}, + }; + + for (const auto& args : testparams) { + TestOptionUsageErrors(args); + } +} + +// -------------------- PKeyUtl OpenSSL Comparison Tests -------------------------- + +// Comparison tests cannot run without set up of environment variables: +// AWSLC_TOOL_PATH and OPENSSL_TOOL_PATH. + +class PKeyUtlComparisonTest : public ::testing::Test { +protected: + void SetUp() override { + // Skip gtests if env variables not set + tool_executable_path = getenv("AWSLC_TOOL_PATH"); + openssl_executable_path = getenv("OPENSSL_TOOL_PATH"); + if (tool_executable_path == nullptr || openssl_executable_path == nullptr) { + GTEST_SKIP() << "Skipping test: AWSLC_TOOL_PATH and/or OPENSSL_TOOL_PATH environment variables are not set"; + } + + ASSERT_GT(createTempFILEpath(in_path), 0u); + ASSERT_GT(createTempFILEpath(out_path_tool), 0u); + ASSERT_GT(createTempFILEpath(out_path_openssl), 0u); + ASSERT_GT(createTempFILEpath(sig_path_tool), 0u); + ASSERT_GT(createTempFILEpath(sig_path_openssl), 0u); + ASSERT_GT(createTempFILEpath(key_path), 0u); + ASSERT_GT(createTempFILEpath(pubkey_path), 0u); + + // Create and save a private key + pkey.reset(CreateTestKey(2048)); + ASSERT_TRUE(pkey); + + ScopedFILE key_file(fopen(key_path, "wb")); + ASSERT_TRUE(key_file); + ASSERT_TRUE(PEM_write_PrivateKey(key_file.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr)); + + // Create a public key file + ScopedFILE pubkey_file(fopen(pubkey_path, "wb")); + ASSERT_TRUE(pubkey_file); + ASSERT_TRUE(PEM_write_PUBKEY(pubkey_file.get(), pkey.get())); + + // Create a test input file with some data + ScopedFILE in_file(fopen(in_path, "wb")); + ASSERT_TRUE(in_file); + const char* test_data = "Test data for signing and verification"; + ASSERT_EQ(fwrite(test_data, 1, strlen(test_data), in_file.get()), strlen(test_data)); + } + + void TearDown() override { + if (tool_executable_path != nullptr && openssl_executable_path != nullptr) { + RemoveFile(in_path); + RemoveFile(out_path_tool); + RemoveFile(out_path_openssl); + RemoveFile(sig_path_tool); + RemoveFile(sig_path_openssl); + RemoveFile(key_path); + RemoveFile(pubkey_path); + } + } + + char in_path[PATH_MAX]; + char out_path_tool[PATH_MAX]; + char out_path_openssl[PATH_MAX]; + char sig_path_tool[PATH_MAX]; + char sig_path_openssl[PATH_MAX]; + char key_path[PATH_MAX]; + char pubkey_path[PATH_MAX]; + bssl::UniquePtr pkey; + const char* tool_executable_path; + const char* openssl_executable_path; + std::string tool_output_str; + std::string openssl_output_str; +}; + +// Test signing operation against OpenSSL +TEST_F(PKeyUtlComparisonTest, SignCompareOpenSSL) { + std::string tool_command = std::string(tool_executable_path) + " pkeyutl -sign -inkey " + + key_path + " -in " + in_path + " -out " + sig_path_tool; + std::string openssl_command = std::string(openssl_executable_path) + " pkeyutl -sign -inkey " + + key_path + " -in " + in_path + " -out " + sig_path_openssl; + + int tool_result = system(tool_command.c_str()); + ASSERT_EQ(tool_result, 0) << "AWS-LC tool command failed: " << tool_command; + + int openssl_result = system(openssl_command.c_str()); + ASSERT_EQ(openssl_result, 0) << "OpenSSL command failed: " << openssl_command; + + // Verify both signatures with the public key + std::string tool_verify_cmd = std::string(tool_executable_path) + " pkeyutl -verify -pubin -inkey " + + pubkey_path + " -in " + in_path + " -sigfile " + sig_path_tool + + " > " + out_path_tool; + std::string openssl_verify_cmd = std::string(openssl_executable_path) + " pkeyutl -verify -pubin -inkey " + + pubkey_path + " -in " + in_path + " -sigfile " + sig_path_openssl + + " > " + out_path_openssl; + + ASSERT_EQ(system(tool_verify_cmd.c_str()), 0); + ASSERT_EQ(system(openssl_verify_cmd.c_str()), 0); + + // Read verification results + std::ifstream tool_output(out_path_tool); + tool_output_str = std::string((std::istreambuf_iterator(tool_output)), std::istreambuf_iterator()); + std::ifstream openssl_output(out_path_openssl); + openssl_output_str = std::string((std::istreambuf_iterator(openssl_output)), std::istreambuf_iterator()); + + // Both should verify successfully + ASSERT_NE(tool_output_str.find("Signature Verified Successfully"), std::string::npos); + ASSERT_NE(openssl_output_str.find("Signature Verified Successfully"), std::string::npos); + + // Cross-verification testing: + // 1. AWS-LC signs → OpenSSL verifies + std::string cross_verify_1 = std::string(openssl_executable_path) + " pkeyutl -verify -pubin -inkey " + + pubkey_path + " -in " + in_path + " -sigfile " + sig_path_tool + + " > " + out_path_tool; + ASSERT_EQ(system(cross_verify_1.c_str()), 0) << "OpenSSL failed to verify AWS-LC signature"; + + // 2. OpenSSL signs → AWS-LC verifies + std::string cross_verify_2 = std::string(tool_executable_path) + " pkeyutl -verify -pubin -inkey " + + pubkey_path + " -in " + in_path + " -sigfile " + sig_path_openssl + + " > " + out_path_openssl; + ASSERT_EQ(system(cross_verify_2.c_str()), 0) << "AWS-LC failed to verify OpenSSL signature"; + + // Read cross-verification results + std::ifstream cross_1_output(out_path_tool); + std::string cross_1_str = std::string((std::istreambuf_iterator(cross_1_output)), std::istreambuf_iterator()); + std::ifstream cross_2_output(out_path_openssl); + std::string cross_2_str = std::string((std::istreambuf_iterator(cross_2_output)), std::istreambuf_iterator()); + + ASSERT_NE(cross_1_str.find("Signature Verified Successfully"), std::string::npos) + << "OpenSSL should successfully verify AWS-LC signature"; + ASSERT_NE(cross_2_str.find("Signature Verified Successfully"), std::string::npos) + << "AWS-LC should successfully verify OpenSSL signature"; +} diff --git a/tool-openssl/tool.cc b/tool-openssl/tool.cc index ab2514dc708..832284c0c20 100644 --- a/tool-openssl/tool.cc +++ b/tool-openssl/tool.cc @@ -15,7 +15,7 @@ #include "./internal.h" -static const std::array kTools = {{ +static const std::array kTools = {{ {"crl", CRLTool}, {"dgst", dgstTool}, {"genrsa", genrsaTool}, @@ -23,6 +23,7 @@ static const std::array kTools = {{ {"md5", md5Tool}, {"pkcs8", pkcs8Tool}, {"pkey", pkeyTool}, + {"pkeyutl", pkeyutlTool}, {"rehash", RehashTool}, {"req", reqTool}, {"rsa", rsaTool},