AWS Security Blog
Post-quantum TLS in Python
At Amazon Web Services (AWS), security is a top priority. Maintaining data confidentiality is a substantial component of operating environment security for AWS and our customers. Though not yet available, a cryptographically relevant quantum computer (CRQC) could be used to break public key algorithms that are used today to provide data confidentiality. To prepare for a world where CRQCs might exist, the National Institute of Standards and Technology (NIST) initiated a search for new algorithms that are robust against potential CRQCs. In August 2024, after eight years of intense scrutiny by the cryptography community, NIST selected three post-quantum cryptography (PQC) standards, including FIPS 203’s ML-KEM, to supplement and eventually replace classical public key algorithms.
A few recent AWS blog posts have discussed PQC at AWS, particularly post-quantum Transport Layer Security (PQ TLS) using ML-KEM:
- What PQ TLS is and how it works
- Deep dive into PQ TLS performance
- Using PQ TLS with the AWS SDK for Java v2
- AWS PQC migration plan
In this post, we demonstrate how you can test PQ TLS in Python applications today.
Testing PQ TLS in Python
As described in detail elsewhere, AWS currently deploys PQ TLS in a hybrid configuration where a classical key exchange is used alongside ML-KEM to provide defense-in-depth for data confidentiality. ML-KEM has much larger keys than classical schemes, so hybrid TLS handshakes send and receive more data when establishing a connection. As with other protocol updates, it’s important to test hybrid TLS in your network to validate that security appliances and network devices can handle these connections appropriately. We hope that you find the provided AWS Sample useful for such tests.
To negotiate hybrid TLS, PQ-ready software is required on both ends of the connection: client and server. AWS is currently rolling out hybrid TLS on the server side transparently with no customer configuration required. On the client side, each language SDK’s story for enabling hybrid TLS will be slightly different.
The AWS SDK for Python (Boto3) relies the on the Python interpreter’s ssl
module for TLS, which in turn uses the operating system’s cryptography library. For most Linux distributions, this is OpenSSL. OpenSSL recently announced support for hybrid TLS and has enabled it by default in version 3.5. However, OpenSSL 3.5 is not yet the default on most operating system distributions.
To unblock testing, we provide a container definition that installs OpenSSL 3.5 alongside a standard Python distribution, allowing Python applications to perform PQ hybrid TLS connections. The container definition also installs common packages such as boto3
and requests
. We provide example Python code for basic interactions with: AWS services (using boto3
and the AWS Command Line Interface (AWS CLI)), arbitrary HTTPS endpoints (using requests
), and TLS-secured TCP servers (using Python’s standard library ssl
module).
In the following sections, we walk through how to use this container definition to test PQ TLS connections from Python applications to AWS services.
Build the container
You can build this container on your local machine, or you can build it in a cloud environment such as Amazon Elastic Compute Cloud (Amazon EC2) or AWS CloudShell. Note that if you want to exercise the network path between your machine and AWS, you must build and run the container locally. The only prerequisite for building the container is having Docker (or an equivalent container tool) installed. For simplicity, the following steps mostly assume that you’re running these commands in a Linux CloudShell environment.
- Clone the sample repo:
git clone https://github.com/aws-samples/sample-post-quantum-tls-python
- Change into the sample’s directory and build the container by executing the following command:
cd sample-post-quantum-tls-python && docker build . -t pq-tls-python
Run the container
To run the samples described earlier, execute the following:
The preceding command assumes that you have an AWS CLI default profile with permission to call the AWS Secrets Manager ListSecrets API. With this permission, you can make a basic, read-only test call to Secrets Manager PQ-enabled API endpoints that won’t return sensitive or secret values. In CloudShell, you’ll need to set access key and secret key values with aws configure
. In Amazon EC2, you can configure an instance profile and remove the access key and secret key environment.
After printing out the name and version of the cryptography library used by Python, test.sh
will test hybrid TLS connections used to secure (in order):
- TCP sockets using Python’s
socket
andssl
modules - HTTP requests using the
requests
library - AWS API requests using
boto3
and the AWS CLI
If the tests are successful you should see the following output:
You can inspect, modify, and extend the examples in the tests/
directory as needed for your experiments. Instead of running the provided test.sh
script, you can access an interactive shell with the following command.
docker run --rm -it pq-tls-python
Make sure to rebuild the container if you add or modify the files for testing.
Confirm PQ TLS negotiation
To confirm that PQ hybrid TLS is negotiated, inspect the samples’ TLS handshakes to confirm that the PQ hybrid TLS key exchange is performed. To do this, you must capture host network traffic. In CloudShell, you can do this using the following command:
sudo tcpdump -A -i docker0 -w pq_tls.pcap
This will capture TCP traffic to port 443, the standard port for TLS. Modify the command as needed if you’re capturing traffic for a non-standard port. Alternatively, if you’re running the container locally, you can perform the packet capture in Wireshark’s GUI on a local network device, such as docker0
on Linux or en0
on MacOS.
Next, run the test suite in a separate terminal using the Docker run command from Run the container. As before, you should see the success messages in your terminal, and a new file named docker_443.pcap
if you’re using tcpdump
. You can download this file from CloudShell to view locally in Wireshark. Specifically, look for the key_share
extension in client or server Hello
handshake messages. If you’re using Wireshark to view the packet capture, you can specify the display filter tls.handshake
to only show handshake messages. Your packet capture should look something like Figure 1:

Figure 1: Wireshark view of packet capture
You can see in Figure 1 that X25519MLKEM768
is selected in the server Hello
handshake message, showing that PQ hybrid TLS was successfully negotiated.
Conclusion
In this post, you’ve seen how to use a container definition to test PQ hybrid TLS in Python today. The linked AWS Sample shows how to establish PQ hybrid TLS connections for:
- AWS API requests with
boto3
or the AWS CLI - General HTTPS requests with
requests
- TLS-secured TCP sockets with Python’s
socket
andssl
modules
We encourage you to use the AWS Sample to start vetting your networks and Python applications in preparation for upcoming PQ hybrid TLS migrations. AWS is committed to supporting our customers through their migration journeys, and PQ hybrid TLS is no exception.
If you have feedback about this post, submit comments in the Comments section below. If you have questions about this post, contact AWS Support.