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

[TLS 1.3] Hybrid PQ/T key establishment #3609

Merged
merged 10 commits into from
Oct 5, 2023

Conversation

reneme
Copy link
Collaborator

@reneme reneme commented Jun 30, 2023

Pull Request Dependencies

Things to do

  • Tests (at least a round-trip test -- e.g. as a new configuration in test_cli.py cli_tls_socket_tests)
  • Decide and introduce preliminary code points for compatibility with existing PQ/T endpoints -- e.g. cloudflare, Amazon KMS, Microsoft, IBM, ??)
    • How to handle support for those?
  • Try to build/test with hybrid KEX module disabled
  • Update the BoGo tests, that seem to support Kyber since May '23
  • Act on [TLS 1.3] Hybrid PQ/T key establishment #3609 (comment)

Description

This (finally) follows up on #2983 and is a more serious attempt in delivering hybrid key exchange based on draft-ietf-tls-hybrid-design-06.

Hybrid key exchange is handled by an adapter class Hybrid_KEM_PrivateKey that combines 2 or more KEX/KEM keys as specified in draft-ietf-tls-hybrid-design-06. To upstream users it provides a KEM interface.

Internally Hybrid_KEM_PrivateKey uses another adapter KEX_to_KEM_Adapter_PrivateKey that takes a single Key Agreement key (e.g. X25519) and exposes a KEM interface based on it. "KEM-Encaps" is implemented by generating a matching ephemeral key pair and using the ephemeral public key as the "encapsulated secret".

There are plenty of TODO where we needed to workaround short-comings of the Public_Key API. Potential improvements are collected in #3706.

IANA did not define code points for PQ and PQ/T key exchange groups in TLS, yet. As a result, different (beta) services define incompatible algorithm identifiers. We're providing a number of algorithm aliases to be compatible to both libOQS and Cloudflare's implementation. This is certainly a moving target that might change in the near future.

To give this a test run and connect to cloudflare.com using PQC (see their blog post -- section "What we deployed" -- for more details):

  1. Create a TLS policy file (pqc_tls.txt):
allow_tls13 = true
allow_tls12 = false
x25519/Kyber-512-r3 secp256r1/Kyber-512-r3 x25519/Kyber-512-r3/cloudflare
  1. Start the CLI like so:
./botan tls_client --tls-version=1.3 --debug cloudflare.com --policy=./pqc_tls.txt

You'll see that the exchanged Client Hello and Server Hello messages in the debug output are unusually large. The kyber public key weighs about 800bytes.

src/lib/tls/tls13_pqc/info.txt Outdated Show resolved Hide resolved
@reneme
Copy link
Collaborator Author

reneme commented Jul 4, 2023

With this policy:

allow_tls13 = true
allow_tls12 = false
key_exchange_groups = x25519/Kyber-512-r3 secp256r1/Kyber-512-r3 x25519/Kyber-512-r3/cloudflare

We tested successfully against:

  • cloudflare.com (documentation, blog)
    Unfortunately they use incompatible algo identifiers (hence the x25519/Kyber-512-r3/cloudflare hack in the policy). They use Curve25519 and don't support the NIST curves.
  • qsc.eu-de.kms.cloud.ibm.com (documentation)
    IBM uses the algo identifiers proposed by liboqs. It does not support Curve25519. Apart from the hybrid exchange this endpoint can also handle just Kyber-512-r3.
  • test.openquantumsafe.org (documentation)
    Yeah. Everything should role.

We couldn't negotiate against:

@coveralls
Copy link

coveralls commented Jul 4, 2023

Coverage Status

coverage: 91.67% (-0.07%) from 91.743% when pulling 4486d90 on Rohde-Schwarz:tls13/kem_establishment into ae37d65 on randombit:master.

@reneme reneme marked this pull request as ready for review July 4, 2023 12:44
@reneme reneme mentioned this pull request Jul 5, 2023
@reneme
Copy link
Collaborator Author

reneme commented Jul 10, 2023

Do we need to establish one or more new key_exchange_method in the policy?

I believe we should. See for example Session_Summary::kex_algo() which would currently report UNDEFINED for hybrid and/or KEM.

Edit: done

@reneme
Copy link
Collaborator Author

reneme commented Jul 17, 2023

Rebased to master after merging #3611.

Copy link
Owner

@randombit randombit left a comment

Choose a reason for hiding this comment

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

This is only a partial review - I haven't reviewed the KEX->KEM adapter at all and only partially reviewed hybrid_public_key.cpp. I will finish the review asap.

src/lib/pubkey/pubkey.cpp Show resolved Hide resolved
src/lib/pubkey/pubkey.h Outdated Show resolved Hide resolved
src/lib/tls/msg_client_hello.cpp Outdated Show resolved Hide resolved
src/lib/tls/tls13_pqc/info.txt Outdated Show resolved Hide resolved
src/lib/tls/tls_algos.h Outdated Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.cpp Outdated Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.cpp Outdated Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.cpp Outdated Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.cpp Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.cpp Outdated Show resolved Hide resolved
@reneme
Copy link
Collaborator Author

reneme commented Jul 26, 2023

Thanks for the review. Unfortunately, I won't be able to look into it before August 7th. Perhaps @FAlbertDev wants to give it a go, though. 😃

@FAlbertDev
Copy link
Collaborator

Perhaps @FAlbertDev wants to give it a go, though. 😃

Yeah, I'll give it a try 👍

FAlbertDev added a commit to Rohde-Schwarz/botan that referenced this pull request Jul 27, 2023
@FAlbertDev FAlbertDev force-pushed the tls13/kem_establishment branch 3 times, most recently from 4a159c8 to 745dae8 Compare July 28, 2023 12:29
@randombit
Copy link
Owner

Thanks for addressing the review comments @FAlbertDev, on a quick review of just your commit things looked good.

I want to do another full pass review, I'll get this in sometime before next week.

@reneme
Copy link
Collaborator Author

reneme commented Aug 7, 2023

Rebased to master to solve conflicts in test_cli.py after merging #3618.

Comment on lines 83 to 103
/**
* This helper determines the length of the agreed-upon value depending
* on the key agreement public key's algorithm type. It would be better
* to get this value via PK_Key_Agreement::agreed_value_size(), but
* instantiating a PK_Key_Agreement object requires a PrivateKey object
* which we don't have (yet) in the context this is used.
*
* TODO: Find a way to get this information without duplicating those
* implementation details of the key agreement algorithms.
*/
size_t kex_shared_key_length(const Public_Key& kex_public_key) {
return std::visit(
overloaded{[](const ECDH_PublicKey& ecdh_public_key) { return ecdh_public_key.domain().get_p_bytes(); },
[](const DH_PublicKey& dh_public_key) { return dh_public_key.group().p_bytes(); },
[](const Curve25519_PublicKey&) { return size_t(32) /* TODO: magic number */; }},
as_kex_public_key(kex_public_key));
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It would be great if we could access certain basic information of specific algorithms statically.

Copy link
Owner

Choose a reason for hiding this comment

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

Thought I had left a comment on this earlier? Hm.

Statically might be difficult given how DH/ECDH are defined over arbitrary groups, but it seems pretty possible to have something like virtual size_t raw_shared_key_length() = 0 the challenge is on what type to put it since PK_Key_Agreement_Key is only for the private keys ...

Conceivably we could have something on Public_Key like so

/**
* Return the length of the relevant artifact of this key.
* 
* Throws Not_Implemented if the key does not support an operation of this type.
*
* For KeyAgreement, returns the raw (non-KDF) output length.
*/
virtual size_t output_length(PublicKeyOperation op) = 0
```

Copy link
Owner

@randombit randombit left a comment

Choose a reason for hiding this comment

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

Looks very good, left a few comments, ptal

doc/api_ref/tls.rst Show resolved Hide resolved
src/lib/tls/msg_client_hello.cpp Outdated Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.cpp Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.h Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.h Outdated Show resolved Hide resolved
src/lib/tls/tls13_pqc/info.txt Outdated Show resolved Hide resolved
src/lib/tls/tls13_pqc/kex_to_kem_adapter.cpp Outdated Show resolved Hide resolved
@reneme
Copy link
Collaborator Author

reneme commented Sep 19, 2023

Done with your latest review comments. I updated the PR description (mainly for future reference) and created #3706 to collect future improvements on the Pubkey-APIs.

I committed the review fixes into new commits for easy review. Let me know if I should squash before we merge eventually.

@reneme
Copy link
Collaborator Author

reneme commented Sep 29, 2023

Rebased to master.

Copy link
Owner

@randombit randombit left a comment

Choose a reason for hiding this comment

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

Did a full review, left a few minor comments. Approving to unblock since I didn't notice anything major. This certainly points out some nasty holes in our API surface; in principle it should be possible to implement the hybrid and kex->kem adaptors without referencing any algorithm specific details.

src/lib/tls/tls13_pqc/info.txt Show resolved Hide resolved
src/lib/tls/tls13_pqc/kex_to_kem_adapter.cpp Outdated Show resolved Hide resolved
src/tests/test_tls_hybrid_kem_key.cpp Show resolved Hide resolved
src/lib/tls/tls13_pqc/hybrid_public_key.h Show resolved Hide resolved
@reneme reneme merged commit 2f15b3e into randombit:master Oct 5, 2023
37 checks passed
@reneme reneme deleted the tls13/kem_establishment branch October 5, 2023 15:44
@reneme reneme mentioned this pull request Mar 8, 2024
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