Skip to content

Add rsa::KeyPair::from_components for constructing RSA key pairs from raw components - #1175

Merged
justsmth merged 2 commits into
aws:mainfrom
justsmth:rsa-from-components
Aug 6, 2026
Merged

justsmth merged 2 commits into
aws:mainfrom
justsmth:rsa-from-components

Conversation

@justsmth

@justsmth justsmth commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Issues:

Resolves #791

Description of changes:

Adds rsa::KeyPairComponents and rsa::KeyPair::from_components, matching ring 0.17's API for constructing RSA key pairs from raw components. This allows callers to construct a signing key directly from formats such as JWK without first encoding the components as DER.

This also removes unnecessary generic bounds from PublicKeyComponents and applies the existing canonical encoding requirements for n and e consistently across RSA construction paths.

Call-outs:

  • Unlike ring, this implementation validates d and the CRT parameters at construction using RSA_check_key. Keys with inconsistent or placeholder values that ring accepts may therefore be rejected.
  • Leading zeros are rejected for n and e, consistent with their existing API contract and ring's behavior. Leading zeros remain permitted for private components.
  • p and q are not primality tested, matching ring.
  • The use of EVP_PKEY_set1_RSA and the ownership handling around RSA_set0_* are intentional to avoid leaks or double frees.

Testing:

Adds coverage for supported key-size boundaries, public exponent and encoding rules, corrupted components, DER parity, signing and verification, trait bounds, and Debug redaction.

Verified with cargo test under the default and fips features, make clippy, make format, and rustdoc with -D warnings.

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.

@justsmth
justsmth requested a review from a team as a code owner July 15, 2026 14:10
@codecov-commenter

codecov-commenter commented Jul 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.88235% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.82%. Comparing base (c358484) to head (e09b8f3).
⚠️ Report is 433 commits behind head on main.

Files with missing lines Patch % Lines
aws-lc-rs/src/rsa/key.rs 80.88% 4 Missing and 9 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1175      +/-   ##
==========================================
- Coverage   95.80%   92.82%   -2.98%     
==========================================
  Files          61       72      +11     
  Lines        8143    10586    +2443     
  Branches        0    10586   +10586     
==========================================
+ Hits         7801     9826    +2025     
- Misses        342      455     +113     
- Partials        0      305     +305     

☔ View full report in Codecov by Harness.
📢 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.

@justsmth
justsmth force-pushed the rsa-from-components branch from 0618dcd to 94254ee Compare July 15, 2026 14:56
…ents

Implements the ring-compatible rsa::KeyPairComponents struct and
rsa::KeyPair::from_components API (issue aws#791), allowing an RSA key
pair to be constructed from its raw big-endian-encoded components
without a DER-encoding round trip.

- KeyPairComponents matches ring's type: same path (rsa module), same
  fields (public_key, d, p, q, dP, dQ, qInv), Clone + Copy, and a
  Debug impl that redacts the private components.
- CRT parameters are installed via RSA_set0_crt_params so signing uses
  the CRT path and RSA_check_key validates all components (n == p*q,
  d*e consistency, dP/dQ/qInv consistency) at construction.
- Tests cover round-trip against the same key parsed from DER,
  sign/verify, trait impls, Debug redaction, and rejection of
  inconsistent components.
@justsmth
justsmth force-pushed the rsa-from-components branch from 94254ee to 4fde08b Compare August 5, 2026 13:03
Enforce the documented component encoding, document how this API
differs from ring's, and close gaps in the test coverage.

- PublicKeyComponents documents n and e as being encoded without
  leading zeros, and PublicKeyComponents::build_rsa enforces that, but
  from_components did not. The same PublicKeyComponents value was
  therefore accepted by from_components while being rejected by AsDer,
  TryInto<PublicEncryptingKey>, and verification. Hoist the check into
  a shared public_component_to_bn helper used by both paths, reporting
  InvalidEncoding to match ring. Leading zeros remain permitted on the
  private components, where the type makes no such claim.

- Add a ring compatibility section to from_components. It covers both
  the cases where we are more permissive (modulus up to 8192 bits, no
  minimum public exponent) and the two where we are stricter: we fully
  validate d, which ring never uses and does not check, and we validate
  the CRT parameters at construction instead of deferring to the first
  signature.

- Note why EVP_PKEY_set1_RSA is used here while the surrounding code
  uses EVP_PKEY_assign_RSA.

- Assert the specific KeyRejected variant in the negative tests, and add
  a regression test that the public key APIs agree with from_components
  on leading zeros.

- Add data/rsa_from_components_tests.txt, covering the 2048 to 8192 bit
  key size window and the public exponent rules. The valid keys are the
  components of the PKCS#8 test keys already in tests/data, so no new
  key material is introduced.
@justsmth
justsmth requested review from prasden and sgmenda August 5, 2026 18:14
Comment thread aws-lc-rs/src/rsa/key.rs
Comment on lines +116 to +123
/// `p`'s CRT exponent: `d mod (p - 1)`.
pub dP: Private,

/// `q`'s CRT exponent: `d mod (q - 1)`.
pub dQ: Private,

/// The CRT coefficient: `q**-1 mod p`.
pub qInv: Private,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I believe these components are optional? Could we reflect that in the API to allow creation from d, p, and q alone? Or are we trying to be strictly compatible with a ring API here?

@justsmth
justsmth merged commit 90c687e into aws:main Aug 6, 2026
505 of 514 checks passed
@justsmth
justsmth deleted the rsa-from-components branch August 6, 2026 11:45
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.

Construct an RSA Key pair from raw private components

4 participants