Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for X25519 and X448 #391

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open

Conversation

jvdsn
Copy link

@jvdsn jvdsn commented Mar 24, 2025

This pull request adds support for the X25519 and X448 to the server (also known as Curve25519 / Curve448 Diffie-Hellman). Three algorithms are implemented: KeyGen, KeyVer, and SSC (Shared Secret Computation). The different commits modify different layers of the server for easier review.

Some points that were considered while implementing this code:

  • RFC 7748 is the only reference used for this implementation.
  • All existing ECC code was part of "NIST.CVP.ACVTS.Libraries.Crypto/DSA.ECC" or "NIST.CVP.ACVTS.Libraries.Crypto/DSA.Ed". Because X25519 and X448 are not DSA algorithms, this is not a right fit for these algorithms. To avoid a very large refactor, the code was separated into a separate directory "NIST.CVP.ACVTS.Libraries.Crypto/XECDH".
  • As a result, there are also no general-purpose classes or interfaces for Montgomery curves or points on Montgomery curves. They were initially implemented, but cumbersome to work with as X25519/X448 are much more specialized. The algorithms rely on the theory, but use several shortcuts. For example, X25519/X448 only use the u coordinate (Montgomery points are (u, v)) as an input to the Diffie-Hellman process.
  • Initially, I considered an "ECX_Component" similar to the existing "ECC_Component", that was fully integrated in the existing KAS code. However, as KeyGen and KeyVer algorithms (similar to EdDSA) were added later, I decided to pull out the code and completely separate it from KAS.
  • The cryptographic code uses BitString but does not fully use its capabilities. For example, converting a BitString to an integer in a little-endian manner is explicitly implemented following the RFC. This was to
    a) Make sure the code clearly maps to the RFC
    b) Avoid any potential endianness issues since the BitString internally uses big-endian
  • For X25519/X448, the RFC requires that the implementation accepts basically any 32-byte (resp. 48-byte) string as a valid public key. Therefore, the KeyVer testing is very limited. As the private key is currently not provided to the IUT, pair-wise consistency is not in scope (similar to EdDSA). It could be considered to expand this, as long as compliance with the RFC is maintained.
  • Test cases for the cryptographic code are taken from RFC 7748. In particular, the iterated test cases are using only 1,000 iterations at this point. 1,000,000 should be possible but may take much longer (perhaps 30 minutes per test, on my hardware) 1,000,000 does not provide too much extra value compared to 1,000.

@jvdsn
Copy link
Author

jvdsn commented Mar 24, 2025

I am also very open to code style changes, I tried to follow the existing style but didn't see anything explicitly documented (e.g., line limit / wrapping)

@celic
Copy link
Collaborator

celic commented Mar 24, 2025

No formal code style guidelines. We use basic C# styling though I see several syntactic sugars on that page that didn't exist when we started the project.

It is strongly preferred for unit tests to finish in a matter of minutes or seconds. It is OK to define longer running tests but they should be identified with the [LongRunningCryptoTest] attribute. The iterated tests on 1000 iterations make sense here.

@celic
Copy link
Collaborator

celic commented Mar 24, 2025

Note if/when we accept this PR, it will not be merged here. This is an external repository used for our production code once published. We maintain an internal repository where this would be merged. Just a heads up if anyone looks at this PR later to see why it was "closed" versus "merged".

@jvdsn
Copy link
Author

jvdsn commented Mar 28, 2025

It is strongly preferred for unit tests to finish in a matter of minutes or seconds. It is OK to define longer running tests but they should be identified with the [LongRunningCryptoTest] attribute. The iterated tests on 1000 iterations make sense here.

Right now the 1,000 iterations finish in about 5 seconds on my machine. That test case is identified using [LongRunningCryptoTest] though, I just didn't have time to test the full 1,000,000 iterations yet. A naive extrapolation of the 1,000 iterations runtime indicates it should take about 1.4 hours, which would make [LongRunningCryptoTest] on that test case justified.

@jvdsn
Copy link
Author

jvdsn commented Mar 28, 2025

@celic additional tests were implemented in a2d3314

@livebe01 due to the force push, your commit to add the xecdh solution was overwritten. I can try to add it again, or maybe you can add it after this PR is merged?

@jvdsn jvdsn marked this pull request as ready for review March 29, 2025 00:26
@livebe01
Copy link
Collaborator

livebe01 commented Apr 1, 2025

@jvdsn @celic I'm thinking it may make sense to remove the XECDH KeyGen and KeyVer testing. KeyGen effectively gets tested by the SSC tests.

@livebe01
Copy link
Collaborator

livebe01 commented Apr 1, 2025

@celic @jvdsn right now, the XECDH SSC testing provides the server's public key in the prompt for each test case. In the response, the IUT provides its public key along with the value it computed for z. What do you think about instead having the prompt include both the server's public key and the private key that should be used by the IUT? The response would then only contain the value computed for k by the IUT. I believe this would be better testing as it would allow ACVTS to vary the private keys used by the IUT in performing the SSC.

@jvdsn
Copy link
Author

jvdsn commented Apr 1, 2025

@celic @jvdsn right now, the XECDH SSC testing provides the server's public key in the prompt for each test case. In the response, the IUT provides its public key along with the value it computed for z. What do you think about instead having the prompt include both the server's public key and the private key that should be used by the IUT? The response would then only contain the value computed for k by the IUT. I believe this would be better testing as it would allow ACVTS to vary the private keys used by the IUT in performing the SSC.

@livebe01 it makes sense to me, right now the XECDH SSC testing was modeled after the ECC CDH component, but I'm open to changing this. The only constraint may be that some IUTs may not accept a private key from the outside?

@jvdsn
Copy link
Author

jvdsn commented Apr 1, 2025

@livebe01 in that case, KeyGen and KeyVer would remain though, right? Since then KeyGen wouldn't be covered by SSC anymore

@livebe01
Copy link
Collaborator

livebe01 commented Apr 2, 2025

@celic @jvdsn right now, the XECDH SSC testing provides the server's public key in the prompt for each test case. In the response, the IUT provides its public key along with the value it computed for z. What do you think about instead having the prompt include both the server's public key and the private key that should be used by the IUT? The response would then only contain the value computed for k by the IUT. I believe this would be better testing as it would allow ACVTS to vary the private keys used by the IUT in performing the SSC.

@livebe01 it makes sense to me, right now the XECDH SSC testing was modeled after the ECC CDH component, but I'm open to changing this. The only constraint may be that some IUTs may not accept a private key from the outside?

@jvdsn I'd thought of that as well. @celic what are your thoughts?

@livebe01
Copy link
Collaborator

livebe01 commented Apr 2, 2025

@livebe01 in that case, KeyGen and KeyVer would remain though, right? Since then KeyGen wouldn't be covered by SSC anymore

I guess I don't understand why you implemented KeyGen and KeyVer and could use your help to understand. Full disclosure, I don't know a lot about X25519 and X448. I read RFC 7748 yesterday and that's about it.

It seemed to me that RFC 7748 is describing a key agreement scheme. If you look through the RFC, it doesn't seem to break out key generation and key verification functions. What it does define are the X25519 and X448 functions (Section 5). Section 6 specifies how the X25519 and X448 functions can be used in an ECDH protocol. Performing the ECDH protocol requires each party to execute the X25519 or X448 function
two times. The first time a party executes the X____ function, they are computing their public key. The second time they are executing the X____ function they are computing the shared secret. My thought is that having XECDH SSC testing alone is sufficient. The prompt provides the IUT private key and the server public key. I suppose it would make sense to require the IUT to provide both its public key and the computed shared secret in the response. This would require the IUT to exercise the X____ function both times. The first time to produce its public key and the second time to produce the shared secret.

If the purpose of adding XECDH testing to ACVTS is to allow testing to RFC7748, then I don't think there's a point to implementing an XECDH KeyGen algorithm. We'd only want to implement XECDH KeyGen algorithm testing if there were some use for X25519 and X448 key pairs outside of the key agreement scheme defined in RFC7748. For example, if it were useful to have XECDH KeyGen algorithm testing because X25519 and X448 key pairs are used separately from RFC7748 in digital signature schemes.

@jvdsn
Copy link
Author

jvdsn commented Apr 2, 2025

@livebe01 keys used by X25519 and X448 are not (should not) be used for any other cryptographic schemes. The reason why I added KeyGen and KeyVer was just for consistency with EdDSA (after all, keys used by EdDSA are not and should not be used by any other cryptographic schemes either).

KeyVer could probably be dropped without any issue. KeyGen may still be useful because it is specifically defined as X25519 using the private key as the scalar and the base point as the u coordinate. I can imagine some cryptographic libraries / modules have a separate function for that. That is Section 6 of RFC7748 as you pointed out:

Alice generates 32 random bytes in a[0] to a[31] and transmits K_A =
X25519(a, 9) to Bob, where 9 is the u-coordinate of the base point
and is encoded as a byte with value 9, followed by 31 zero bytes.

@livebe01
Copy link
Collaborator

livebe01 commented Apr 2, 2025 via email

@jvdsn
Copy link
Author

jvdsn commented Apr 2, 2025

I'm not sure that we would want two certificates (both keygen and SSC) for a module that implements XECDH? I’m trying to think what would normally show up on a CAVP certificate that includes a KAS * SSC * algorithm. Do keyGen entries normally accompany SSC entries on certs?

@livebe01 I would say so, yes.

For KAS-ECC-SSC, ECDSA KeyGen is generally repurposed. For KAS-FFC-SSC, Safe Primes KeyGen generally used. I don't think this is mandatory (it's certainly not required here https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/prerequisites) but I do see it pretty often. Especially since it is mandatory for ephemeral key exchanges, which a very common claim for cryptographic modules.

Furthermore, for NIAP (Common Criteria) evaluations, key generation is almost always a prerequisite for SSC. E.g., from PP_MDF_V3.3:

FCS_CKM.2/LOCKED Cryptographic Key Establishment

The TSF shall perform cryptographic key establishment in accordance with a
specified cryptographic key establishment method: [selection:
...
[Elliptic curve-based key establishment schemes] that meet the following:
[selection:
...
RFC 7748, "Elliptic Curves for Security"
]
...] for the purposes of encrypting sensitive data received while the device
is locked.
The elliptic curves used for the key establishment scheme must correlate with
the curves specified in FCS_CKM.1.1.

TSS

The evaluator shall ensure that the supported key establishment schemes correspond to the key
generation schemes identified in FCS_CKM.1.1. If the ST specifies more than one scheme, the
evaluator shall examine the TSS to verify that it identifies the usage for each scheme.

FCS_CKM.1 Cryptographic Key Generation

The TSF shall generate asymmetric cryptographic keys in accordance with a
specified cryptographic key generation algorithm [selection:
...
ECC schemes using: [selection:
...
Curve25519 schemes that meet the following: [RFC 7748]
]
...
].
Application Note: The ST author must select all key generation schemes used
for key establishment and entity authentication

@jvdsn
Copy link
Author

jvdsn commented Apr 2, 2025

As to the usefulness for KeyVer, I would agree, but then I would also question the usefulness of ECDSA, EdDSA, and Safe Primes KeyVer :)

@celic
Copy link
Collaborator

celic commented Apr 2, 2025

RFC 7748 doesn't talk about key generation. Is there a separate RFC for that?

@jvdsn
Copy link
Author

jvdsn commented Apr 2, 2025

@celic it is Section 6 of RFC7748:

Alice generates 32 random bytes in a[0] to a[31] and transmits K_A =
X25519(a, 9) to Bob, where 9 is the u-coordinate of the base point
and is encoded as a byte with value 9, followed by 31 zero bytes.

The 32 random bytes are the private key and K_A is the public key

@celic
Copy link
Collaborator

celic commented Apr 2, 2025

Ah I see. The more involved process I'm thinking of is the EdDSA key pairs. The key pairs for X25519 and X448 are very simple.

In practice, because this would typically be used in TLS, are the public keys computed ahead of time as part of a certificate? Or are they essentially ephemeral for the computation?

Context: I'm seeing a slight discrepancy between the testing and the RFC and that could be because you are fitting the RFC into a mold of SP 800-56A. I don't have any preference one way or another, but it may affect how the tests are used. Normally we get to target an SP or FIPS that defines the algorithms that need to be tested. Targeting an RFC leaves it a bit ambiguous due to the flexibility a protocol could take when implementing the RFC. That may be more of a philosophical discussion than we need though.

@jvdsn
Copy link
Author

jvdsn commented Apr 2, 2025

@celic as far as I know, they will always be ephemeral in the context of TLS. I'm not sure if there's other non-ephemeral users. Apple uses it for their file protection (https://help.apple.com/pdf/security/en_US/apple-platform-security-guide.pdf page 105) but that's probably ephemeral.

There are parties asking for KeyGen testing though, e.g. NIAP as shown above.

@kriskwiatkowski
Copy link

Hello,
It's great to see this development. Does it mean it will be possible to do a FIPS 140-3 certification for x25519/x448 in a future?

@jvdsn
Copy link
Author

jvdsn commented Apr 3, 2025

Hello, It's great to see this development. Does it mean it will be possible to do a FIPS 140-3 certification for x25519/x448 in a future?

@kriskwiatkowski I am not affiliated with NIST nor CMVP, so I would not read too much into this PR. If you're interested in how/why I worked on this you're welcome to attend my ICMC talk https://icmconference.org/?post_type=session&p=23836

@celic
Copy link
Collaborator

celic commented Apr 3, 2025

Hello, It's great to see this development. Does it mean it will be possible to do a FIPS 140-3 certification for x25519/x448 in a future?

No it would not. The CAVP who manages ACVTS is interested in providing testing for non-approved algorithms if there is a need for it. @jvdsn was kind enough to offer code for X25519/X448. It has no relation to the NIST cryptographic standards.

@kriskwiatkowski
Copy link

Got it. Thanks @celic and @jvdsn

@celic
Copy link
Collaborator

celic commented Apr 3, 2025

@jvdsn, @livebe01 I'd say leave it as it is then.

Edit: I'm referring to keeping KeyGen, KeyVer, and SSC as distinct algorithms. There may be some improvements that could be made to SSC to smooth over things we've had users point out to us in the past.

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.

4 participants