Skip to content

Conversation

kingstjo
Copy link
Contributor

@kingstjo kingstjo commented Jul 10, 2025

Issues:

Addresses CryptoAlg-3387

Description of changes:

This PR implements the genrsa command for the openssl tool, which generates RSA private keys. This is part of the ongoing effort to implement OpenSSL-compatible CLI tools in AWS-LC.

The implementation includes:

  • Generate RSA private keys with customizable key size
  • Output to file or stdout
  • Proper argument order validation
  • Comprehensive error handling

Call-outs:

  • RSA Key Size Enforcement: The genrsa tool enforces a minimum RSA key size of 1024 bits via the kMinKeySize constant. Key generation requests below this threshold are rejected with a clear error message.

Testing:

  • Added unit tests for basic functionality
  • Added tests for error handling
  • Added cross-compatibility tests with OpenSSL
  • Added parameterized tests for different key sizes (1024, 2048, 3072, 4096)

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.

kingstjo added 12 commits June 30, 2025 11:24
- Add genrsa.cc with basic option parsing for -out and key size
- Register genrsaTool in kTools array and internal.h
- Update CMakeLists.txt to include genrsa.cc in build
- Implement barebones functionality that outputs detected options
- Support required options: -out <file> and <keysize> (default: 2048)

🤖 Assisted by Amazon Q Developer
- Replace barebones implementation with actual RSA key generation
- Add RSA_generate_key_ex() with RSA_F4 exponent (65537)
- Support key size parsing from positional argument with validation
- Add BIO-based output handling for both stdout and file output
- Include proper error handling for key generation and file operations
- Use bssl::UniquePtr for automatic memory management
- Generate PEM-formatted RSA private keys compatible with OpenSSL

Tested functionality:
- Default 2048-bit key generation to stdout
- Custom key sizes (e.g., 4096-bit)
- File output with -out option
- Input validation and error handling

🤖 Assisted by Amazon Q Developer
- Add genrsa command to tool-openssl with argument parsing
- Enforce OpenSSL-compatible argument order: [options] numbits
- Support -out option and custom key sizes (default: 2048-bit)
- Generate RSA keys in traditional PEM format for broad compatibility
- Add comprehensive test suite with 14 tests covering:
  * Basic functionality (key generation, error handling)
  * Cross-compatibility with OpenSSL (argument order, interoperability)
  * PEM format validation and RSA key component verification
- Use ordered argument parsing to match OpenSSL's strict ordering requirements
- Include environment variable support for CI/CD cross-compatibility testing

Follows AWS-LC CLI tool patterns and PKCS#8 PR feedback on argument order.

🤖 Assisted by Amazon Q Developer
- Replace system() calls with direct genrsaTool() function calls for basic tests
- Add parameterized tests for various key sizes (1024, 2048, 3072, 4096)
- Keep system() calls only for cross-compatibility tests with OpenSSL
- Improve test execution speed by ~10x (no process spawning overhead)
- Add ArgumentOrderValidation test for OpenSSL compatibility
- Maintain all existing functionality while reducing complexity

Performance improvements:
- 19 tests total (was 14): +5 tests with parameterized approach
- 23.1 lines per test (was 24.3): slight improvement in code density
- Direct function calls eliminate process spawning overhead
- Better error reporting with direct stack traces

🤖 Assisted by Amazon Q Developer
…ation and bracing

- Initialize all variables to satisfy cppcoreguidelines-init-variables
- Add braces around single-line if statements per readability-braces-around-statements
- Fix args_list_t, BIGNUM pointer, and primitive variable initialization
- Ensure consistent code style across genrsa.cc, genrsa_test.cc, and tool.cc

All 90 AWS-LC CLI tests now pass with full OpenSSL compatibility.

🤖 Assisted by Amazon Q Developer
…ized testing

- Merge GenRSATest and GenRSAKeySizeTest into single unified class
- Add support for both parameterized and non-parameterized tests in one class
- Fix segmentation fault by using inline checks with explicit returns
- Eliminate code duplication between test classes
- Improve cross-compatibility test coverage for all key sizes (1024, 2048, 3072, 4096)
- Reduce excessive error messages while keeping contextual ones
- Reduce file size from 332 to 300 lines while maintaining full test coverage

🤖 Assisted by Amazon Q Developer
- Add static constants kDefaultKeySize (2048) and kUsageFormat for consistency
- Extract ValidateArgumentOrder() helper function to improve readability
- Extract ParseKeySize() helper function to centralize key size validation
- Reduce main function complexity from ~100 lines to ~55 lines
- Maintain all existing functionality and OpenSSL compatibility
- All 19 genrsa tests continue to pass

This refactoring improves maintainability and makes it easier to modify
validation logic when team feedback is received.

🤖 Assisted by Amazon Q Developer
…exity

- Add ParseArguments helper to centralize argument parsing
- Add GenerateRSAKey helper to encapsulate key generation logic
- Add CreateOutputBIO helper to manage output destination setup
- Add WriteRSAKeyToBIO helper to handle key writing
- Reduce main function complexity from ~55 lines to ~25 lines
- Maintain all existing functionality and OpenSSL compatibility
- All 19 genrsa tests continue to pass

🤖 Assisted by Amazon Q Developer
…nd non-parameterized tests

This change refactors the genrsa_test.cc file to use a hybrid approach:
- Creates a base test fixture with common functionality
- Uses parameterized tests for operations that benefit from testing with different key sizes
- Keeps non-parameterized tests for operations that don't depend on key size
- Reduces test count from 52 to 28 while maintaining comprehensive coverage
- Improves test names and organization for better readability

🤖 Assisted by Amazon Q Developer
- Update DisplayHelp to use BIO for output instead of std::cout
- Add dynamic option lookup with FindOptionByName function
- Fix segmentation faults in tests when environment variables aren't set
- Improve code maintainability for future option additions

🤖 Assisted by Amazon Q Developer
@kingstjo kingstjo requested a review from a team as a code owner July 10, 2025 22:21
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

@codecov-commenter
Copy link

codecov-commenter commented Jul 10, 2025

Codecov Report

❌ Patch coverage is 74.69880% with 42 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.75%. Comparing base (6d2eb62) to head (29ccac3).

Files with missing lines Patch % Lines
tool-openssl/genrsa_test.cc 65.67% 17 Missing and 6 partials ⚠️
tool-openssl/genrsa.cc 81.63% 18 Missing ⚠️
tool-openssl/tool.cc 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2535      +/-   ##
==========================================
+ Coverage   78.74%   78.75%   +0.01%     
==========================================
  Files         646      648       +2     
  Lines      111238   111403     +165     
  Branches    15712    15740      +28     
==========================================
+ Hits        87591    87737     +146     
- Misses      22953    22967      +14     
- Partials      694      699       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@kingstjo
Copy link
Contributor Author

See AWS-LC-865 for (aws-lc-ci-integration) build failure

kingstjo added 4 commits July 11, 2025 11:57
This change initializes the bits variable to 0 to address the clang-tidy warning about uninitialized variables.

🤖 Assisted by Amazon Q Developer
…andling

- Added kMinKeySize and kKeyArgName constants
- Updated ParseKeySize to use these constants
- Simplified argument handling by using ordered_args functions

🤖 Assisted by Amazon Q Developer
Use local boolean variable with GetBoolArgument instead of passing nullptr directly
to maintain compatibility with the current implementation.
kingstjo added 8 commits July 17, 2025 10:21
This restores the kTools array size that was incorrectly changed to 12.
The array needs to match the actual number of tool entries.
… handling

- Consolidate key validation into single ValidateKey method
- Add descriptive error messages to assertions
- Improve file handling with ScopedFILE
- Remove redundant test cases
- Clean up code organization and formatting

🤖 Assisted by Amazon Q
…ccess violation

The KeyUniqueness test was opening files twice - once with ScopedFILE and again
inside ReadFileToString. This caused an access violation (0xc0000005) on Windows
in the msys2 ucrt64 CI environment. This change removes the redundant ScopedFILE
handles and directly uses ReadFileToString to avoid the file handle conflict.

🤖 Assisted by Amazon Q Developer
Add a RAII-based cleanup guard to ensure proper BIO flushing and closing
on all exit paths. This approach is more maintainable and scalable as
new features are added to the tool. The guard ensures that file handles
are properly released before the function returns, which is especially
important on Windows where file locking is more restrictive.

This fixes the access violation (0xc0000005) errors in the CI pipeline
when running the GenRSAParamTest.KeyUniqueness test.

🤖 Assisted by Amazon Q Developer
…mpatibility

Use binary mode ("wb") instead of text mode ("w") when opening output files
to ensure proper handling of binary data on Windows platforms. This prevents
line ending conversions and other text-mode processing that can corrupt
binary data in RSA key files.

🤖 Assisted by Amazon Q Developer
kingstjo added 10 commits July 28, 2025 11:35
Add comprehensive null pointer checks in genrsa implementation:

- CreateOutputBIO: Add null check for BIO_new_fp(stdout) failure
- GenerateRSAKey: Add null checks for RSA_new() and BN_new() allocation failures
- ValidateKey: Add null check for path parameter
- BIOCleanupGuard: Improve error handling for BIO_flush failures

These changes prevent potential crashes when OpenSSL allocation functions
fail or when invalid parameters are passed, improving robustness especially
in low-memory conditions or when stdout is redirected.

🤖 Assisted by Amazon Q Developer
…ations

Modify BIOCleanupGuard to only flush file BIOs, not stdout/stderr BIOs.
This prevents Windows access violation (0xc0000005) errors that can occur
when flushing stdout BIOs in the KeyUniqueness test.

The guard now tracks whether the BIO is a file BIO and only performs
flush operations on actual files, avoiding potential Windows-specific
issues with stdout/stderr handling.

🤖 Assisted by Amazon Q Developer
Remove custom BIOCleanupGuard and adopt the standard AWS-LC approach:
- Rely on bssl::UniquePtr<BIO> automatic cleanup via BIO_free()
- Use BIO_NOCLOSE for stdout/stderr BIOs (prevents closing shared streams)
- Only flush file BIOs on successful completion
- Matches patterns used in pkcs8.cc, pkey.cc, x509.cc

This eliminates potential Windows access violations while maintaining
proper resource management through the standard BIO destructor chain.

🤖 Assisted by Amazon Q Developer
…t validation

Replace manual RSA key component checking with AWS-LC's built-in RSA_check_key()
function. This reduces code duplication and leverages the proven validation logic
already implemented in the library.

Changes:
- Remove manual component extraction using RSA_get0_* functions
- Remove manual public exponent validation
- Use RSA_check_key() for comprehensive key validation
- Maintain same test functionality with less code

This simplification reduces maintenance burden while providing equivalent
or better validation coverage through the library's standard validation.

🤖 Assisted by Amazon Q Developer
Refactor CLI tests to properly separate CLI concerns from library concerns:

CLI-focused changes:
- Replace ValidateKey() with ValidateKeyFile() focusing on file I/O and PEM format
- Remove library-level tests: KeyUniqueness, KeyComponentsValidation
- Remove key size validation (library responsibility)
- Add comprehensive CLI behavior tests: stdout output, file I/O, argument parsing
- Improve error case coverage with separate FileIOErrors and ArgumentParsingErrors tests

New test structure:
- GeneratesKeyFile: Tests CLI can create valid PEM files
- OpenSSLCompatibility: Tests PEM format compatibility (CLI integration concern)
- StdoutOutput: Tests CLI stdout behavior
- FileVsStdoutOutput: Tests CLI output routing
- ArgumentParsingErrors: Tests CLI argument validation
- FileIOErrors: Tests CLI file handling
- ArgumentValidation: Tests CLI default behavior and precedence

This follows software engineering best practices by having CLI tests focus on
user interface, argument parsing, and file I/O rather than cryptographic
properties which belong at the library level.

🤖 Assisted by Amazon Q Developer
- Fix double-read issue in ValidateKeyFile function
- Replace problematic ScopedFILE + ReadFileToString pattern with single BIO operation
- Add OpenSSL error stack reporting for better debugging
- Add RSA_check_key() for enhanced key validation
- Improve consistency with pkcs8_test.cc and genrsa.cc patterns
- Maintain all existing test functionality while fixing file handle confusion

🤖 Assisted by Amazon Q Developer
Replace direct RSA API calls with EVP_PKEY API while maintaining
RSA key generation functionality. This change:

- Uses EVP_PKEY_CTX_new_id(EVP_PKEY_RSA) for RSA key generation
- Simplifies code by removing separate WriteRSAKeyToBIO function
- Improves error handling with consistent goto err pattern
- Uses PEM_write_bio_PrivateKey which handles RSA keys generically

The tool still generates RSA keys as before, but uses the EVP layer
which provides a consistent interface over the underlying RSA operations.

🤖 Assisted by Amazon Q Developer
- Remove excessive comments explaining obvious concepts
- Enhance ValidateKeyFile with optional key size validation
- Combine GenerateKey and GenerateKeyToStdout into single flexible function
- Remove ERR_print_errors_fp calls from test validation for cleaner output
- Update parameterized tests to validate actual key sizes match expected

The test functionality remains identical while improving code clarity
and reducing unnecessary verbosity in test output.

🤖 Assisted by Amazon Q Developer
Add FIPS_mode() checks to skip 1024-bit RSA key tests when FIPS mode is
enabled. FIPS mode requires 2048-bit minimum key size as enforced in
crypto/fipsmodule/rsa/rsa_impl.c.

This prevents CI failures in FIPS-enabled environments while maintaining
full test coverage in non-FIPS environments.

🤖 Assisted by Amazon Q Developer
…cess violations

Remove redundant ReadFileToString operations in FileOutput test that were
causing 0xc0000005 access violations in Windows/MSYS2 CI environments.

ValidateKeyFile already confirms file existence, validity, and proper
content, making the additional file reads unnecessary and problematic
due to Windows file handle conflicts.

Also renamed FileVsStdoutOutput to FileOutput to better reflect the
actual test purpose.

Fixes Windows CI failures similar to those seen in PR aws#2575.

🤖 Assisted by Amazon Q Developer
@justsmth
Copy link
Contributor

justsmth commented Jul 31, 2025

Test failure with Clang 7.x compiler -- only fails for 1024?

[ RUN      ] StandardKeySizes/GenRSAParamTest.GeneratesKeyFile/0
Error: Failed to generate RSA key
106927505839680:error:04000068:RSA routines:OPENSSL_internal:BAD_RSA_PARAMETERS:../crypto/fipsmodule/rsa/rsa_impl.c:1276:
../tool-openssl/genrsa_test.cc:111: Failure
Value of: GenerateKey(key_size, out_path_tool)
  Actual: false
Expected: true
Key generation failed
../tool-openssl/genrsa_test.cc:53: Failure
Failed
Failed to parse RSA key from PEM file
../tool-openssl/genrsa_test.cc:112: Failure
Value of: ValidateKeyFile(out_path_tool, key_size)
  Actual: false
Expected: true
Generated key file validation failed
106927505839680:error:0900006e:PEM routines:OPENSSL_internal:NO_START_LINE:../crypto/pem/pem_lib.c:635:Expecting: ANY PRIVATE KEY
[  FAILED  ] StandardKeySizes/GenRSAParamTest.GeneratesKeyFile/0, where GetParam() = 1024 (1 ms)

**kingstjo: Tests involving 1024 keysizes were failing as FIPS build is verified differently (runtime/compile-time) for different OS. Previously the test was not accounting for both FIPS build checks and attempting to generate keys disallowed in FIPS mode

- Add validation for multiple key size arguments with specific error message
- Simplify argument order validation logic
- Remove redundant kMinKeySize validation (library handles this)
- Reorder validation to give specific error for multiple key sizes

Addresses feedback from justsmth in PR 2535:
- Multiple key sizes now show 'Only one key size argument allowed'
- Simplified argument order check to verify key size is last argument
- Removed duplication of library's key size validation

🤖 Assisted by Amazon Q Developer
Use both compile-time BORINGSSL_FIPS and runtime FIPS_mode() checks
to properly skip 1024-bit key tests in all FIPS configurations,
including when ASAN is enabled and FIPS_mode() returns 0.

Assisted by AmazonQ
- Add kMinKeySize constant set to 1024 bits
- Add validation to reject key sizes below minimum
- Rename 'bits' variable to 'KeySizeBits' for clarity
- All tests pass with new validation

Assisted by Amazon Q
@kingstjo kingstjo requested a review from justsmth August 25, 2025 15:38
Fail fast on output file issues (invalid paths, permissions) before
the expensive RSA key generation operation to improve performance.
Remove conditional flush logic - BIO_flush works correctly for both
stdout and file outputs, making the path-specific logic unnecessary.
Warn users when requesting key sizes larger than 16384 bits, as these
can take extremely long to generate and may not behave as expected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants