Skip to content

Conversation

jakemas
Copy link
Collaborator

@jakemas jakemas commented Sep 23, 2025

Issues:

Resolves #N/A
Addresses #aws/aws-lc-rs#799

Description of changes:

This PR adds support for the parsing of ML-KEM private keys encoded in the ASN.1 seed format, as described in https://datatracker.ietf.org/doc/draft-ietf-lamps-kyber-certificates/.

As such, 64 byte ASN.1 encoded private keys, such as this example ml-kem-512 private key from the IETF draft can now be parsed in aws-lc using EVP_parse_private_key:

   -----BEGIN PRIVATE KEY-----
   MFQCAQAwCwYJYIZIAWUDBAQBBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
   GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
   -----END PRIVATE KEY-----

The EVP_PKEY produced will have both the full private and public ML-KEM key expanded material within.

This very much follows a similar PR for ML-DSA #2157.

While there are a few ways to tackle the issue of getting the public key when the private is provided, for example making use of the OneAsymmetricKey structure as in https://datatracker.ietf.org/doc/html/draft-ietf-lamps-kyber-certificates-11#section-6. However as PKCS8 v2 isn't well supported, I feel encoding OneAsymmetricKey won't be easy for those wanting to bring key material into aws-lc/-rs. Python Cryptography doesn't support it today, for example. OpenSSL encodes keys by default using the BOTH approach (seed and expanded material), so importing from OpenSSL produced private seeds will now be possible, and populate both pub and priv keys.

Background

The IETF draft standard defines three private key formats for ML-KEM certificates:

  1. seed [0] OCTET STRING - 64-byte deterministic seed (added in this PR)
  2. expandedKey OCTET STRING - Full private key material (Add expandedKey ASN.1 encoding for KEM keys #2624)
  3. both SEQUENCE {seed, expandedKey} - Both formats together (future work)

Previously, AWS-LC only supported the expandedKey format. This PR adds support for the more compact seed format, which uses deterministic key generation from a 64-byte seed.

How does this help aws/aws-lc-rs#799?

When the private key is provided as a seed, both the expanded private and secret key are populated within the EVP_PKEY structure, allowing, for the first time, a fully populated key on import.

Call-outs:

Core Implementation:

  • crypto/evp_extra/p_kem_asn1.c: Enhanced kem_priv_decode() to detect and parse seed format using ASN.1 context-specific tag [0] (stubbed out BOTH format)
  • crypto/fipsmodule/kem/kem.c: Added KEM_KEY_set_raw_keypair_from_seed() function to generate keypairs from seeds using deterministic ML-KEM functions
  • crypto/fipsmodule/kem/internal.h: Added function declaration for seed-based key generation

FIPS Questions:

Are we allowed to expose this functionality as part of the FIPS module? Yes, see https://csrc.nist.gov/projects/post-quantum-cryptography/faqs Question 1:

Are cryptographic modules implementing FIPS 203 or FIPS 204 allowed to use seeds as the default key format instead of expanded keys? For example, in FIPS 203, can a cryptographic module store a 64-byte seed (d, z) instead of the output (dk, ek) of Algorithm 19 (ML-KEM.KeyGen), and compute (dk, ek) as needed via (dk, ek) <-- ML-KEM.KeyGen_internal(d, z)?

Response:
For both FIPS 203 and FIPS 204, a KeyGen seed is considered an acceptable alternative format for a key-pair, or for the private (i.e., decapsulation or signing) key. In particular, generating the seed in one cryptographic module and then importing or exporting it into another cryptographic module is allowed. The internal key generation functions ML-KEM.KeyGen_Internal(d, z) and ML-DSA.KeyGen_internal(ξ) can be accessed for this purpose.

Testing:

  • crypto/evp_extra/p_kem_test.cc: Added comprehensive ParsePrivateKeySeed test using IETF standard test vectors
  • Added test vectors for ML-KEM-512, ML-KEM-768, and ML-KEM-1024 seed formats from Appendix C of the draft standard
  • Tests verify that seed-generated keypairs match expected public keys from the standard

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.

@codecov-commenter
Copy link

codecov-commenter commented Sep 23, 2025

Codecov Report

❌ Patch coverage is 70.68966% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.14%. Comparing base (eaaa97b) to head (fb1b7cd).

Files with missing lines Patch % Lines
crypto/fipsmodule/kem/kem.c 50.00% 13 Missing ⚠️
crypto/evp_extra/p_kem_asn1.c 75.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2707      +/-   ##
==========================================
+ Coverage   78.96%   79.14%   +0.18%     
==========================================
  Files         669      669              
  Lines      114582   114634      +52     
  Branches    16119    16128       +9     
==========================================
+ Hits        90475    90731     +256     
+ Misses      23326    23121     -205     
- Partials      781      782       +1     

☔ 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.

@jakemas jakemas marked this pull request as ready for review September 23, 2025 21:51
@jakemas jakemas requested a review from a team as a code owner September 23, 2025 21:51
@dkostic dkostic self-requested a review September 29, 2025 17:25
justsmth
justsmth previously approved these changes Oct 1, 2025
justsmth
justsmth previously approved these changes Oct 1, 2025
justsmth
justsmth previously approved these changes Oct 3, 2025
justsmth
justsmth previously approved these changes Oct 6, 2025
justsmth
justsmth previously approved these changes Oct 6, 2025
@jakemas jakemas merged commit 822b016 into aws:main Oct 6, 2025
365 of 369 checks passed
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.

5 participants