Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ae63347
Implement ecparam CLI tool with proper memory management and high-lev…
kingstjo Sep 22, 2025
ec8b2d6
refactor: Replace ScopedFILE with BIO in ecparam_test.cc
kingstjo Sep 23, 2025
c5aa4f0
refactor: Replace manual system() calls with RunCommandsAndCompareOut…
kingstjo Sep 23, 2025
48e266e
refactor: Replace defines with type-safe enums in ecparam
kingstjo Sep 23, 2025
621f805
improve: Add comprehensive error handling to ecparam
kingstjo Sep 23, 2025
b9e9ea5
refactor: Simplify EC key generation using higher-level APIs
kingstjo Sep 23, 2025
fd9655e
feat(ecparam): improve curve validation and error messages
kingstjo Sep 26, 2025
2ae38dd
Fix ecparam_test.cc compilation and improve cross-compatibility testing
kingstjo Sep 26, 2025
e23e245
Refactor ecparam tests to use Google Test parameterization
kingstjo Sep 26, 2025
2b0a395
Enhance EcparamTest with cryptographic content validation
kingstjo Sep 26, 2025
120b750
Implement dynamic curve detection for parameterized tests
kingstjo Sep 26, 2025
30e6faf
Refactor ecparam_test.cc for better maintainability and code quality
kingstjo Sep 26, 2025
22b765d
Reorganize ecparam_test.cc structure and eliminate duplicates
kingstjo Sep 26, 2025
4c50e45
Address PR review feedback: simplify format validation and enum usage
kingstjo Oct 2, 2025
46844aa
Address PR review feedback: simplify function parameters and code str…
kingstjo Oct 2, 2025
634bbb5
Address PR review feedback: simplify test class hierarchy
kingstjo Oct 2, 2025
5906718
Address PR review feedback: improve curve validation with group creation
kingstjo Oct 2, 2025
517dfa3
Fix valgrind error: initialize char arrays in test classes
kingstjo Oct 3, 2025
36f6537
Merge branch 'main' into implement-ecparam-cli
kingstjo Oct 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tool-openssl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_executable(

crl.cc
dgst.cc
ecparam.cc
pass_util.cc
pkcs8.cc
pkey.cc
Expand Down Expand Up @@ -88,6 +89,8 @@ if(BUILD_TESTING)
crl_test.cc
dgst.cc
dgst_test.cc
ecparam.cc
ecparam_test.cc
pass_util.cc
pass_util_test.cc
pkcs8.cc
Expand Down
189 changes: 189 additions & 0 deletions tool-openssl/ecparam.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

#include <openssl/ec.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/obj.h>
#include "../tool/internal.h"
#include "internal.h"

enum OutputFormat {
FORMAT_PEM = 1,
FORMAT_DER = 2
};

static bssl::UniquePtr<EC_GROUP> ValidateAndCreateECGroup(const std::string& curve_name) {
int nid = OBJ_sn2nid(curve_name.c_str());
if (nid == NID_undef) {
nid = EC_curve_nist2nid(curve_name.c_str());
}

bssl::UniquePtr<EC_GROUP> group;
if (nid != NID_undef) {
group.reset(EC_GROUP_new_by_curve_name(nid));
}

if (!group) {
fprintf(stderr, "unknown curve name (%s)\n", curve_name.c_str());

size_t num_curves = EC_get_builtin_curves(nullptr, 0);
std::vector<EC_builtin_curve> curves(num_curves);
EC_get_builtin_curves(curves.data(), num_curves);

fprintf(stderr, "Supported curves:\n");
for (const auto& curve : curves) {
const char* nist_name = EC_curve_nid2nist(curve.nid);
const char* sn = OBJ_nid2sn(curve.nid);

if (nist_name) {
fprintf(stderr, " %s (%s) - %s\n", sn, nist_name, curve.comment);
} else {
fprintf(stderr, " %s - %s\n", sn, curve.comment);
}
}
return nullptr;
}

return group;
}

static const argument_t kArguments[] = {
{ "-help", kBooleanArgument, "Display option summary" },
{ "-name", kOptionalArgument, "Use the ec parameters with specified 'short name'" },
{ "-out", kOptionalArgument, "Output file, default stdout" },
{ "-outform", kOptionalArgument, "Output format (PEM or DER), default PEM" },
{ "-conv_form", kOptionalArgument, "Point conversion form (compressed or uncompressed)" },
{ "-noout", kBooleanArgument, "Do not print the ec parameter" },
{ "-genkey", kBooleanArgument, "Generate ec key" },
{ "", kOptionalArgument, "" }
};

bool ecparamTool(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;
}

if (HasArgument(parsed_args, "-help")) {
PrintUsage(kArguments);
return true;
}

bool ret = false;
std::string curve_name, out_path, outform, conv_form;
bool noout = false, genkey = false;
point_conversion_form_t point_form = POINT_CONVERSION_UNCOMPRESSED;
OutputFormat output_format = FORMAT_PEM;
bssl::UniquePtr<EC_GROUP> group;
bssl::UniquePtr<EC_KEY> eckey;
bssl::UniquePtr<BIO> out_bio;

GetString(&curve_name, "-name", "", parsed_args);
GetString(&out_path, "-out", "", parsed_args);
GetString(&outform, "-outform", "", parsed_args);
GetString(&conv_form, "-conv_form", "", parsed_args);
GetBoolArgument(&noout, "-noout", parsed_args);
GetBoolArgument(&genkey, "-genkey", parsed_args);

if (curve_name.empty()) {
fprintf(stderr, "No curve specified\n");
goto err;
}

// Parse output format
if (!outform.empty()) {
if (isStringUpperCaseEqual(outform, "DER")) {
output_format = FORMAT_DER;
} else if (isStringUpperCaseEqual(outform, "PEM")) {
output_format = FORMAT_PEM;
} else {
fprintf(stderr, "Invalid output format: %s\n", outform.c_str());
goto err;
}
}

// Parse point conversion form
if (!conv_form.empty()) {
if (conv_form == "compressed") {
point_form = POINT_CONVERSION_COMPRESSED;
} else if (conv_form == "uncompressed") {
point_form = POINT_CONVERSION_UNCOMPRESSED;
} else {
fprintf(stderr, "Invalid point conversion form: %s\n", conv_form.c_str());
goto err;
}
}

// Validate curve and create group
group = ValidateAndCreateECGroup(curve_name);
if (!group) {
goto err;
}

// Set up output BIO
if (out_path.empty()) {
out_bio.reset(BIO_new_fp(stdout, BIO_NOCLOSE));
} else {
out_bio.reset(BIO_new_file(out_path.c_str(), output_format == FORMAT_DER ? "wb" : "w"));
}
if (!out_bio) {
fprintf(stderr, "Error opening output\n");
goto err;
}

if (genkey) {
// Generate EC key using existing group
eckey.reset(EC_KEY_new());
if (!eckey || !EC_KEY_set_group(eckey.get(), group.get())) {
fprintf(stderr, "Failed to create EC key for curve\n");
goto err;
}

if (!EC_KEY_generate_key(eckey.get())) {
fprintf(stderr, "Failed to generate EC key\n");
goto err;
}

// Set point conversion form on the key
EC_KEY_set_conv_form(eckey.get(), point_form);

if (!noout) {
if (output_format == FORMAT_PEM) {
if (!PEM_write_bio_ECPrivateKey(out_bio.get(), eckey.get(), nullptr, nullptr, 0, nullptr, nullptr)) {
fprintf(stderr, "Failed to write private key in PEM format\n");
goto err;
}
} else {
if (!i2d_ECPrivateKey_bio(out_bio.get(), eckey.get())) {
fprintf(stderr, "Failed to write private key in DER format\n");
goto err;
}
}
}
} else if (!noout) {
// Output parameters
if (output_format == FORMAT_PEM) {
if (!PEM_write_bio_ECPKParameters(out_bio.get(), group.get())) {
fprintf(stderr, "Failed to write EC parameters in PEM format\n");
goto err;
}
} else {
if (!i2d_ECPKParameters_bio(out_bio.get(), group.get())) {
fprintf(stderr, "Failed to write EC parameters in DER format\n");
goto err;
}
}
}

ret = true;

err:
ERR_print_errors_fp(stderr);
return ret;
}
Loading
Loading