diff --git a/tool-openssl/internal.h b/tool-openssl/internal.h index b93a9731f3..192e570d32 100644 --- a/tool-openssl/internal.h +++ b/tool-openssl/internal.h @@ -6,6 +6,8 @@ #include "../tool/internal.h" +X509* CreateAndSignX509Certificate(); + bool X509Tool(const args_list_t &args) ; #endif //INTERNAL_H diff --git a/tool-openssl/tool.cc b/tool-openssl/tool.cc index 8a8160d7a2..9c3248be7f 100644 --- a/tool-openssl/tool.cc +++ b/tool-openssl/tool.cc @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include @@ -17,8 +19,7 @@ #endif #include "../tool/internal.h" - -extern bool X509Tool(const args_list_t &args); +#include "./internal.h" typedef bool (*tool_func_t)(const std::vector &args); @@ -27,35 +28,24 @@ struct Tool { tool_func_t func; }; -static const Tool kTools[] = { +static const std::array kTools = {{ { "x509", X509Tool }, { "", nullptr }, -}; +}}; -static void usage(const char *name) { - printf("Usage: %s COMMAND\n", name); - printf("\n"); - printf("Available commands:\n"); +static void usage(const std::string &name) { + std::cout << "Usage: " << name << " COMMAND\n\n"; + std::cout << "Available commands:\n"; - for (size_t i = 0;; i++) { - const Tool &tool = kTools[i]; + for (const auto& tool : kTools) { if (tool.func == nullptr) { break; } - printf(" %s\n", tool.name); - } -} - -static tool_func_t FindTool(const std::string &name) { - for (size_t i = 0;; i++) { - const Tool &tool = kTools[i]; - if (tool.func == nullptr || name == tool.name) { - return tool.func; - } + std::cout << " " << tool.name << "\n"; } } -int main(int argc, char **argv) { +static void initialize() { #if defined(OPENSSL_WINDOWS) // Read and write in binary mode. This makes bssl on Windows consistent with // bssl on other platforms, and also makes it consistent with MSYS's commands @@ -63,33 +53,54 @@ int main(int argc, char **argv) { // commands. if (_setmode(_fileno(stdin), _O_BINARY) == -1) { perror("_setmode(_fileno(stdin), O_BINARY)"); - return 1; + exit(1); } if (_setmode(_fileno(stdout), _O_BINARY) == -1) { perror("_setmode(_fileno(stdout), O_BINARY)"); - return 1; + exit(1); } if (_setmode(_fileno(stderr), _O_BINARY) == -1) { perror("_setmode(_fileno(stderr), O_BINARY)"); - return 1; + exit(1); } #else + // Ignore SIGPIPE to prevent the process from terminating if it tries to + // write to a pipe that has been closed by the reading end. SIGPIPE can be + // received when writing to sockets or pipes that are no longer connected. signal(SIGPIPE, SIG_IGN); #endif +} - CRYPTO_library_init(); +tool_func_t FindTool(const std::string &name) { + for (const auto& tool : kTools) { + if (tool.name == name) { + return tool.func; + } + } + return nullptr; +} - int starting_arg = 1; - tool_func_t tool = nullptr; +tool_func_t FindTool(int argc, char **argv, int &starting_arg) { #if !defined(OPENSSL_WINDOWS) - tool = FindTool(basename(argv[0])); + tool_func_t tool = FindTool(basename(argv[0])); + if (tool != nullptr) { + return tool; + } #endif - if (tool == nullptr) { - starting_arg++; - if (argc > 1) { - tool = FindTool(argv[1]); - } + starting_arg++; + if (argc > 1) { + return FindTool(argv[1]); } + return nullptr; +} + +int main(int argc, char **argv) { + initialize(); + CRYPTO_library_init(); + + int starting_arg = 1; + tool_func_t tool = FindTool(argc, argv, starting_arg); + if (tool == nullptr) { usage(argv[0]); return 1; @@ -97,7 +108,7 @@ int main(int argc, char **argv) { args_list_t args; for (int i = starting_arg; i < argc; i++) { - args.push_back(argv[i]); + args.emplace_back(argv[i]); } if (!tool(args)) { @@ -106,4 +117,4 @@ int main(int argc, char **argv) { } return 0; -} +} \ No newline at end of file diff --git a/tool-openssl/x509.cc b/tool-openssl/x509.cc index f8a92a9840..5bb2849227 100644 --- a/tool-openssl/x509.cc +++ b/tool-openssl/x509.cc @@ -6,6 +6,7 @@ #include #include #include +#include #include "../tool/internal.h" #include "internal.h" @@ -54,7 +55,8 @@ bool X509Tool(const args_list_t &args) { // Parse x509 certificate from input file const uint8_t *p = input_data.data(); - X509 *x509 = d2i_X509(nullptr, &p, input_data.size()); + auto x509Deleter = [](X509* x509) { X509_free(x509); }; + std::unique_ptr x509(d2i_X509(nullptr, &p, input_data.size()), x509Deleter); if (!x509) { fprintf(stderr, "Failed to parse X509 certificate from '%s'.\n", in_path.c_str()); ERR_print_errors_fp(stderr); @@ -63,11 +65,10 @@ bool X509Tool(const args_list_t &args) { // Serialize certificate to DER format uint8_t *out_data = nullptr; - int len = i2d_X509(x509, &out_data); + int len = i2d_X509(x509.get(), &out_data); if (len < 0) { fprintf(stderr, "Failed to serialize X509 certificate.\n"); ERR_print_errors_fp(stderr); - X509_free(x509); return false; } @@ -75,11 +76,9 @@ bool X509Tool(const args_list_t &args) { if (!WriteToFile(out_path, out_data, len)) { fprintf(stderr, "Failed to write X509 certificate to '%s'.\n", out_path.c_str()); OPENSSL_free(out_data); - X509_free(x509); return false; } OPENSSL_free(out_data); - X509_free(x509); return true; } diff --git a/tool-openssl/x509_test.cc b/tool-openssl/x509_test.cc index 4029e68962..239cc88387 100644 --- a/tool-openssl/x509_test.cc +++ b/tool-openssl/x509_test.cc @@ -7,40 +7,66 @@ #include #include #include +#include #include "../tool/internal.h" #include "internal.h" +X509* CreateAndSignX509Certificate() { + X509 *x509 = X509_new(); + if (!x509) return nullptr; + + // Set validity period + if (!X509_gmtime_adj(X509_getm_notBefore(x509), 0) || + !X509_gmtime_adj(X509_getm_notAfter(x509), 31536000L)) { + X509_free(x509); + return nullptr; + } + + // Generate and set the public key + EVP_PKEY *pkey = EVP_PKEY_new(); + if (!pkey) { + X509_free(x509); + return nullptr; + } + RSA *rsa = RSA_new(); + BIGNUM *bn = BN_new(); + if (!bn || !BN_set_word(bn, RSA_F4) || + !RSA_generate_key_ex(rsa, 2048, bn, nullptr) || + !EVP_PKEY_assign_RSA(pkey, rsa)) { + BN_free(bn); + EVP_PKEY_free(pkey); + X509_free(x509); + return nullptr; + } + BN_free(bn); + if (!X509_set_pubkey(x509, pkey)) { + EVP_PKEY_free(pkey); + X509_free(x509); + return nullptr; + } + + // Sign certificate + if (X509_sign(x509, pkey, EVP_sha256()) <= 0) { + EVP_PKEY_free(pkey); + X509_free(x509); + return nullptr; + } + + EVP_PKEY_free(pkey); + return x509; +} + // Test x509 -in and -out TEST(X509Test, X509ToolTest) { std::string in_path = "test_input.der"; std::string out_path = "test_output.der"; - X509 *x509 = X509_new(); + std::unique_ptr x509(CreateAndSignX509Certificate(), X509_free); ASSERT_TRUE(x509 != nullptr); - // Set validity period - ASSERT_TRUE(X509_gmtime_adj(X509_getm_notBefore(x509), 0)); - ASSERT_TRUE(X509_gmtime_adj(X509_getm_notAfter(x509), 31536000L)); - - // Generate and set the public key - EVP_PKEY *pkey = EVP_PKEY_new(); - ASSERT_TRUE(pkey != nullptr); - RSA *rsa = RSA_new(); - BIGNUM *bn = BN_new(); - ASSERT_TRUE(bn != nullptr); - ASSERT_TRUE(BN_set_word(bn, RSA_F4)); - ASSERT_TRUE(RSA_generate_key_ex(rsa, 2048, bn, nullptr)); - ASSERT_TRUE(EVP_PKEY_assign_RSA(pkey, rsa)); - BN_free(bn); - ASSERT_TRUE(X509_set_pubkey(x509, pkey)); - - // Sign certificate - ASSERT_TRUE(X509_sign(x509, pkey, EVP_sha256()) > 0); - EVP_PKEY_free(pkey); - // Serialize certificate to DER format uint8_t *der_data = nullptr; - int len = i2d_X509(x509, &der_data); + int len = i2d_X509(x509.get(), &der_data); if (len <= 0) { ERR_print_errors_fp(stderr); } @@ -72,11 +98,9 @@ TEST(X509Test, X509ToolTest) { // Parse x509 cert from output file const uint8_t *p = output_data.data(); - X509 *parsed_x509 = d2i_X509(nullptr, &p, output_data.size()); + std::unique_ptr parsed_x509(d2i_X509(nullptr, &p, output_data.size()), X509_free); ASSERT_TRUE(parsed_x509 != nullptr); - X509_free(parsed_x509); - X509_free(x509); remove(in_path.c_str()); remove(out_path.c_str()); }