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
4 changes: 4 additions & 0 deletions tests/ci/run_openssl_comparison_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,9 @@ 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.*
echo "Running RSAComparisonTests against OpenSSL ${branch}"
LD_LIBRARY_PATH="${install_dir}/openssl-${branch}/${openssl_branches[$branch]}" "${BUILD_ROOT}/tool-openssl/tool_openssl_test" --gtest_filter=RSAComparisonTest.*
echo "Running MD5ComparisonTests against OpenSSL ${branch}"
LD_LIBRARY_PATH="${install_dir}/openssl-${branch}/${openssl_branches[$branch]}" "${BUILD_ROOT}/tool-openssl/tool_openssl_test" --gtest_filter=MD5ComparisonTest.*
ecdeye marked this conversation as resolved.
Show resolved Hide resolved
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 and OpenSSL tools
ecdeye marked this conversation as resolved.
Show resolved Hide resolved

2 changes: 2 additions & 0 deletions tool-openssl/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,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
49 changes: 49 additions & 0 deletions tool-openssl/md5.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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"

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("MD5(stdin)= ");
ecdeye marked this conversation as resolved.
Show resolved Hide resolved
for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
printf("%02x", md5_digest[i]);
}
printf("\n");

return true;
}

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

#include "openssl/rsa.h"
#include <gtest/gtest.h>
#include <openssl/pem.h>
#include "internal.h"
#include <fstream>
#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]);

void RemoveFile(const char* path);

std::string ReadFileToString(const std::string& file_path);

RSA* CreateRSAKey();


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

// Comparison tests cannot run without set up of environment variables:
// AWSLC_TOOL_PATH and OPENSSL_TOOL_PATH.
// TODO: add instructions in readme
ecdeye marked this conversation as resolved.
Show resolved Hide resolved

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);

rsa.reset(CreateRSAKey());
ASSERT_TRUE(rsa);

ScopedFILE in_file(fopen(in_path, "wb"));
ASSERT_TRUE(in_file);
ASSERT_TRUE(PEM_write_RSAPrivateKey(in_file.get(), rsa.get(), nullptr, nullptr, 0, nullptr, nullptr));
}

void RunCommandsAndCompareOutput(const std::string &tool_command, const std::string &openssl_command) {
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;

std::ifstream tool_output(out_path_tool);
this->tool_output_str = std::string((std::istreambuf_iterator<char>(tool_output)), std::istreambuf_iterator<char>());
std::ifstream openssl_output(out_path_openssl);
this->openssl_output_str = std::string((std::istreambuf_iterator<char>(openssl_output)), std::istreambuf_iterator<char>());

std::cout << "AWS-LC tool output:" << std::endl << this->tool_output_str << std::endl;
std::cout << "OpenSSL output:" << std::endl << this->openssl_output_str << std::endl;
}
ecdeye marked this conversation as resolved.
Show resolved Hide resolved


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;
};

const std::string MODULUS = "MD5(stdin)= ";
ecdeye marked this conversation as resolved.
Show resolved Hide resolved

// Test against OpenSSL output "openssl rsa -noout -modulus -in file | openssl md5"
TEST_F(MD5ComparisonTest, MD5ToolCompareOpenSSL) {
std::string tool_command = std::string(tool_executable_path) + " rsa -noout -modulus -in " + in_path + " | openssl md5 > " + out_path_tool;
std::string openssl_command = std::string(openssl_executable_path) + " rsa -noout -modulus -in " + in_path + " | openssl md5 > " + out_path_openssl;
ecdeye marked this conversation as resolved.
Show resolved Hide resolved

RunCommandsAndCompareOutput(tool_command, openssl_command);
ASSERT_EQ(tool_output_str.compare(0, MODULUS.size(), MODULUS), 0);
ASSERT_EQ(openssl_output_str.compare(0, MODULUS.size(), MODULUS), 0);
ASSERT_EQ(tool_output_str.size(), openssl_output_str.size());

}
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