Skip to content

Commit

Permalink
rsa and md5 tools (#1722)
Browse files Browse the repository at this point in the history
Description:
* Added rsa (-in, -out, -noout, -modulus) and md5 openssl tools
* Updated CI script, CMake, tool.cc, internal.h, readme to include new
tools

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license and the ISC license.

(cherry picked from commit b862b16)
  • Loading branch information
ecdeye authored and samuel40791765 committed Aug 15, 2024
1 parent 0eeef3e commit aa28a74
Show file tree
Hide file tree
Showing 11 changed files with 589 additions and 52 deletions.
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, "" }
};

// 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

0 comments on commit aa28a74

Please sign in to comment.