Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rsa and md5 tools #1722

Merged
merged 18 commits into from
Jul 30, 2024
7 changes: 5 additions & 2 deletions tests/ci/run_openssl_comparison_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ declare -A openssl_branches=(
export AWSLC_TOOL_PATH="${BUILD_ROOT}/tool-openssl/openssl"
for branch in "${!openssl_branches[@]}"; do
export OPENSSL_TOOL_PATH="${install_dir}/openssl-${branch}/bin/openssl"
echo "Running X509ComparisonTests against OpenSSL ${branch}"
LD_LIBRARY_PATH="${install_dir}/openssl-${branch}/${openssl_branches[$branch]}" "${BUILD_ROOT}/tool-openssl/tool_openssl_test" --gtest_filter=X509ComparisonTest.*
LD_LIBRARY_PATH="${install_dir}/openssl-${branch}/${openssl_branches[$branch]}"
for test in X509ComparisonTest RSAComparisonTest MD5ComparisonTest; do
echo "Running ${test} against OpenSSL ${branch}"
LD_LIBRARY_PATH="${install_dir}/openssl-${branch}/${openssl_branches[$branch]}" "${BUILD_ROOT}/tool-openssl/tool_openssl_test" --gtest_filter=${test}.*
done
done

8 changes: 7 additions & 1 deletion tool-openssl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ add_executable(
../tool/file.cc
tool.cc
x509.cc
rsa.cc
md5.cc
)

target_include_directories(openssl PUBLIC ${PROJECT_SOURCE_DIR}/include)
Expand Down Expand Up @@ -43,10 +45,14 @@ if(BUILD_TESTING)
add_executable(
tool_openssl_test

x509_test.cc
../tool/args.cc
../tool/file.cc
x509_test.cc
rsa_test.cc
md5_test.cc
x509.cc
rsa.cc
md5.cc
)

target_link_libraries(tool_openssl_test boringssl_gtest_main ssl crypto)
Expand Down
11 changes: 8 additions & 3 deletions tool-openssl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
*Files expected to change*

Current status:
* Contains initial implementation for OpenSSL x509 tool, options -in -out, -req, -signkey, -modulus, -days, -dates,
-checkend, -noout (x509.cc), and unit test (x509_test.cc)
* OpenSSL rsa tool yet to be implemented
* Contains initial implementation for OpenSSL x509, rsa, and md5 tools
* x509 options: -in -out, -req, -signkey, -modulus, -days, -dates,
-checkend, -noout (x509.cc)
* rsa options: -in, -out, -noout, -modulus (rsa.cc)
* md5 options: N/A (md5.cc)
* Unit, integration, and OpenSSL comparison tests (x509_test.cc, rsa_test.cc, md5_test.cc)
* OpenSSL comparison tests require environment variables for both AWS-LC ("AWSLC_TOOL_PATH") and OpenSSL ("OPENSSL_TOOL_PATH") tools

4 changes: 4 additions & 0 deletions tool-openssl/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <string>
#include <vector>



typedef bool (*tool_func_t)(const std::vector<std::string> &args);

bool IsNumeric(const std::string& str);
Expand All @@ -22,5 +24,7 @@ tool_func_t FindTool(const std::string &name);
tool_func_t FindTool(int argc, char **argv, int &starting_arg);

bool X509Tool(const args_list_t &args);
bool rsaTool(const args_list_t &args);
bool md5Tool(const args_list_t &args);

#endif //INTERNAL_H
50 changes: 50 additions & 0 deletions tool-openssl/md5.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#include <openssl/md5.h>
#include <iostream>
#include "internal.h"

// MD5 command currently only supports stdin
static const argument_t kArguments[] = {
{ "-help", kBooleanArgument, "Display option summary" },
{ "", kOptionalArgument, "" }
ecdeye marked this conversation as resolved.
Show resolved Hide resolved
};

// Map arguments using tool/args.cc
bool md5Tool(const args_list_t &args) {
args_map_t parsed_args;
if (!ParseKeyValueArguments(&parsed_args, args, kArguments)) {
PrintUsage(kArguments);
return false;
}

bool help = false;
GetBoolArgument(&help, "-help", parsed_args);

if (help) {
PrintUsage(kArguments);
return false;
}

// Read input from stdin
std::string input;
std::getline(std::cin, input);

if (input.empty()) {
fprintf(stderr, "Error: no input provided\n");
return false;
}

unsigned char md5_digest[MD5_DIGEST_LENGTH];
MD5(reinterpret_cast<const unsigned char*>(input.c_str()), input.length(), md5_digest);

printf("(stdin)= ");
for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
printf("%02x", md5_digest[i]);
}
printf("\n");

return true;
}

93 changes: 93 additions & 0 deletions tool-openssl/md5_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#include <gtest/gtest.h>
#include <openssl/pem.h>
#include "internal.h"
#include "test_util.h"
#include <cctype>


#ifdef _WIN32
#include <windows.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#else
#include <unistd.h>
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#endif

size_t createTempFILEpath(char buffer[PATH_MAX]);

std::string GetHash(const std::string& str);


// -------------------- MD5 OpenSSL Comparison Test ---------------------------

// Comparison tests cannot run without set up of environment variables:
// AWSLC_TOOL_PATH and OPENSSL_TOOL_PATH.

class MD5ComparisonTest : 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);
}
void TearDown() override {
if (tool_executable_path != nullptr && openssl_executable_path != nullptr) {
RemoveFile(in_path);
RemoveFile(out_path_tool);
RemoveFile(out_path_openssl);
}
}
char in_path[PATH_MAX];
char out_path_tool[PATH_MAX];
char out_path_openssl[PATH_MAX];
bssl::UniquePtr<RSA> rsa;
const char* tool_executable_path;
const char* openssl_executable_path;
std::string tool_output_str;
std::string openssl_output_str;
};

// OpenSSL versions 3.1.0 and later change from "(stdin)= " to "MD5(stdin) ="
std::string GetHash(const std::string& str) {
size_t pos = str.find('=');
if (pos == std::string::npos) {
return "";
}
return str.substr(pos + 1);
}

// Test against OpenSSL output
TEST_F(MD5ComparisonTest, MD5ToolCompareOpenSSL) {
std::string input_file = std::string(in_path);
std::ofstream ofs(input_file);
ofs << "AWS_LC_TEST_STRING_INPUT";
ofs.close();

std::string tool_command = std::string(tool_executable_path) + " md5 < " + input_file + " > " + out_path_tool;
std::string openssl_command = std::string(openssl_executable_path) + " md5 < " + input_file + " > " + out_path_openssl;

RunCommandsAndCompareOutput(tool_command, openssl_command, out_path_tool, out_path_openssl, tool_output_str, openssl_output_str);

std::string tool_hash = GetHash(tool_output_str);
std::string openssl_hash = GetHash(openssl_output_str);
tool_hash = trim(tool_hash);
openssl_hash = trim(openssl_hash);

ASSERT_EQ(tool_hash, openssl_hash);

RemoveFile(input_file.c_str());
}
102 changes: 102 additions & 0 deletions tool-openssl/rsa.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#include <openssl/rsa.h>
#include <openssl/pem.h>
#include "internal.h"

static const argument_t kArguments[] = {
{ "-help", kBooleanArgument, "Display option summary" },
{ "-in", kOptionalArgument, "RSA key input file" },
{ "-out", kOptionalArgument, "Output file to write to" },
{ "-noout", kBooleanArgument, "Prevents output of the encoded version of the RSA key" },
{ "-modulus", kBooleanArgument, "Prints out the value of the modulus of the RSA key" },
{ "", kOptionalArgument, "" }
};

// Map arguments using tool/args.cc
bool rsaTool(const args_list_t &args) {
args_map_t parsed_args;
if (!ParseKeyValueArguments(&parsed_args, args, kArguments)) {
PrintUsage(kArguments);
return false;
}

std::string in_path, out_path;
bool noout = false, modulus = false;
bool help = false;

GetBoolArgument(&help, "-help", parsed_args);
GetString(&in_path, "-in", "", parsed_args);
GetString(&out_path, "-out", "", parsed_args);
GetBoolArgument(&noout, "-noout", parsed_args);
GetBoolArgument(&modulus, "-modulus", parsed_args);

// Display rsa tool option summary
if (help) {
PrintUsage(kArguments);
return false;
}

// Check for required option -in
if (in_path.empty()) {
fprintf(stderr, "Error: missing required argument '-in'\n");
return false;
}

ScopedFILE in_file(fopen(in_path.c_str(), "rb"));
if (!in_file) {
fprintf(stderr, "Error: unable to load RSA key from '%s'\n", in_path.c_str());
return false;
}

bssl::UniquePtr<RSA> rsa(PEM_read_RSAPrivateKey(in_file.get(), nullptr, nullptr, nullptr));
if (!rsa) {
fprintf(stderr, "Error: unable to read RSA private key from '%s'\n", in_path.c_str());
return false;
}

ScopedFILE out_file;
if (!out_path.empty()) {
out_file.reset(fopen(out_path.c_str(), "wb"));
if (!out_file) {
fprintf(stderr, "Error: unable to open output file '%s'\n", out_path.c_str());
return false;
}
}

if (modulus) {
const BIGNUM *n = RSA_get0_n(rsa.get());
if (!n) {
fprintf(stderr, "Error: unable to load modulus\n");
return false;
}
char *hex_modulus = BN_bn2hex(n);
if (!hex_modulus) {
fprintf(stderr, "Error: unable to convert modulus to hex\n");
return false;
}
for (char *p = hex_modulus; *p; ++p) {
*p = toupper(*p);
}
if (out_file) {
fprintf(out_file.get(), "Modulus=%s\n", hex_modulus);
} else {
printf("Modulus=%s\n", hex_modulus);
}
OPENSSL_free(hex_modulus);
}

if (!noout) {
if (out_file) {
if (!PEM_write_RSAPrivateKey(out_file.get(), rsa.get(), nullptr, nullptr, 0, nullptr, nullptr)) {
fprintf(stderr, "Error: unable to write RSA private key to '%s'\n", out_path.c_str());
return false;
}
} else {
PEM_write_RSAPrivateKey(stdout, rsa.get(), nullptr, nullptr, 0, nullptr, nullptr);
}
}

return true;
}
Loading
Loading