The End of ClientAuth EKU…Oh Mercy…What to do?
If you’ve spent any time recently monitoring the cryptography and/or Public Key Infrastructure (PKI) spaces…beyond that ever-present “Post Quantum” thing, you may have read that starting in May of 2026, Google Chrome Root Program Policy will start requiring public certificate authorities (CAs) to stop issuing certificates with the Client Authentication Extended Key Usage (ClientAuth EKU) extension. If you haven’t heard, or don’t know what this means, no worries, I’ll do a quick recap.
A Quick TLS Handshake Recap
My sincerest apologies upfront for what may seem pedantically frustrating, but I’m purposely not digging into the weeds of a TLS handshake so that I can get to the finer points. For all of my esteemed TLS experts, I welcome you to skip ahead. In any case…in any given TLS handshake, a client and a server start with some cryptographic formalities, and then one or both parties will pass its public certificate to the other. For all handshakes, the server will always send its certificate to the client, allowing the client to initiate some validations to ensure it trusts who it’s talking to. We’ll call this “server certificate authentication”. On some occasions, where the server also needs to authenticate the client, the server will specifically ask for the client’s certificate during the handshake, and we’ll call this “client certificate authentication”. And because both parties are now authenticating, we can then call this "mutual authentication", “mutual TLS”, or “mTLS” for short. With me so far? Excellent.
Now, inside these certificates are a set of attributes embedded by the CA at issuance that define properties of the certificate, including what the certificate can be used for. A Key Usage (KU) extension specifies a certificate’s primary cryptographic functions, while an Extended Key Usage (EKU) defines the more specific purposes for which this certificate (and corresponding public key) can be used. Technically speaking, Extended Key Usage is an X.509 extension "field" in the certificate, and ClientAuth is one of several possible "purposes". Below is an example set of X.509 extensions, including a Subject Alternative Name (SAN) and the aforementioned EKU field.
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:www.foo.com
X509v3 Extended Key Usage:
TLS Web Client Authentication, TLS Web Server Authentication
The EKU Issue
And this brings us back to the issue at hand. Up to now, most public CAs have issued certificates intended for TLS servers with both the “Web Server Auth” and “Client Auth” EKU values. This means that a TLS server certificate, intended for server-side TLS (i.e., the “S” in HTTPS) could also be used to authenticate (as a client) to another TLS server. As unintuitive as that may sound, on the surface, organizations have found valid reasons to use these certificates this way, including machine-to-machine communications and internal API-based processes. And so, when CAs start removing the ClientAuth EKU value from new and renewed TLS server certificates, that has the potential to start breaking some (mostly backend) TLS infrastructure.
At this point you may, of course, be asking, “…but…but…why?”, and so it’s important to point out that this is actually a good decision. Removing the ClientAuth EKU value from TLS server certificates correctly reduces the scope of these certificates, thus also reducing a not-insignificant threat vector in the process.
But the most important thing, and the reason I'm writing this article in the first place, is to clarify F5’s position:
It is, per standard, incorrect to perform client certificate authentication using a certificate that is not in the correct scope -- in this case, a certificate that does not possess the ClientAuth EKU.
If you have an F5 platform that is configured to perform mTLS, it will not accept “client” certificates that are missing this EKU. This may mean that some internal client certificate authenticated TLS machine-to-machine and API workloads could fail when new/renewed certificates are received from a public CA.
** Note: It's worth mentioning here, as a technicality, that BIG-IP will accept for client authentication a certificate that does not have an EKU extension at all. The challenge here is that public CAs should always issue TLS server certificates with the EKU extension, just that now they will be removing ClientAuth by default. TLS servers should not allow client authentication if the certificate has the EKU field, but the ClientAuth purpose is missing.
Options?
There are some options you should explore, and RSAC succinctly defines these here:
- Private Public Key Infrastructure – Issue your internal TLS certificates from a private CA running in your organization, in which case you can issue certificates with whatever EKU values you need. At the bottom of this article, I’ll show you some handy OpenSSL scripts to generate TLS server certificates from a "local" CA.
- PKI-as-a-Service – Use a managed PKI solution to issue TLS server certificates with the EKU extensions you need.
- Sector-specific solutions – Notably, some public CAs will continue issuing TLS certificates with the ClientAuth EKU, but under a different process and/or different name. Consult with your public certificate provider directly to explore those options.
Change is rarely easy, and industry-wide changes to TLS and certificates are no exception. The important takeaway is that, while potentially uncomfortable, this is ultimately a good thing. F5 has a long tradition of leading-edge cryptography and stands with Google and the industry at large in advancing the security of TLS certificates. We’ve got your back.
Thanks.
Addendum
I mentioned in the “Options?” section above that I’d show you a quick set of OpenSSL scripts for issuing TLS certificates. I’d point out here that a command line-based PKI architecture is perhaps not the best fit for a larger organization, but it could still get the job done. For enterprise-wide solutions, consider an enterprise CA option like Microsoft’s CA services. Below I’ll show how to create a simple 3-tiered PKI architecture with OpenSSL and a set of Bash scripts:
Self-Signed Root CA -> Subordinate CA -> TLS Server
It's generally good practice, even in a local PKI like this one, to create a multi-tiered architecture. Once you've created the subordinate CA, you can take it offline and secure the root CA. The basic assumption for the below is a Linux-based system with a supported version of OpenSSL installed.
Creating a Self-Signed Root CA
The following Bash script includes a set of “const_” variables that define the parameters of the operations. As shown, the root CA will be named “myca”, will support SHA256 and RSA:2048, have a lifetime of 1024 days, and have a Subject name value of “My_Certificate_Authority”. Change any of these values as required before executing the script.
#!/usr/bin/env bash
const_ca_root_name=myca
const_sha=sha256
const_rsa=2048
const_days=1024
const_subj="My_Certificate_Authority"
## ================================
## Test for potential overwrite
if [ -e "${const_ca_root_name}.cer" ]; then
while true; do
read -p "${const_ca_root_name} already exists. Are you sure you want to overwrite? [yes|no] " yn
case $yn in
yes ) break;;
no ) exit 0;;
* ) echo "Please answer yes or no";;
esac
done
fi
## Create root CA
touch ca.cnf && openssl req -new -x509 -${const_sha} -newkey rsa:${const_rsa} -days ${const_days} -keyout ${const_ca_root_name}.key -out ${const_ca_root_name}.cer -batch -subj "/CN=${const_subj}" \
-config <(cat ca.cnf <(printf "[req]\ndistinguished_name=rdn\nx509_extensions=v3_ca\n[rdn]\n[v3_ca]\nsubjectKeyIdentifier=hash\nbasicConstraints=critical, CA:TRUE\nkeyUsage=digitalSignature, keyCertSign, cRLSign"))
rm -f ca.cnf
Make the script executable and then run it:
chmod +x make-ca-root.sh
./make-ca-root.sh
The root CA creation will prompt you to create a passphrase. This passphrase will be required for any further signing functions from the root. In this case, when issuing the subordinate CA from the root CA, you'll be prompted. This script will create myca.cer and myca.key in the current folder. Hold on to this CA cert/key pair (and the passphrase). You'll use it to issue a subordinate CA.
Create a Subordinate CA
Like the previous, this script includes a set of “const_” variables that define the parameters of the operations. Update as needed. I've also included two Boolean options (yes|no):
- const_create_bundle: If 'yes', the script creates a CA bundle file from the concatenation of the root and subordinate CAs. Any server that must trust your TLS certificates must have a copy of this bundle.
- const_set_pw: By default, the root CA mandates a passphrase on the private key, so that this passphrase is required for any signing functions. You may choose to mandate the same security level on the subordinate CA (require a passphrase for signing functions) by setting this value to 'yes'. When 'yes', you will be prompted first to create a passphrase for the subordinate CA, and then prompted again for the root CA's passphrase to complete the signing operation.
#!/usr/bin/env bash
const_ca_root_name=myca
const_ca_sub_name=mysubca
const_ca_bundle=mycabundle
const_sha=sha256
const_rsa=2048
const_days=1024
## Do you want to put a password on the subordinate CA?
const_set_pw=yes
## Do you want to create a CA bundle file?
const_create_bundle=yes
const_subj="My_Subordinate_Certificate_Authority"
## ================================
## Test for potential overwrite
if [ -e "${const_ca_sub_name}.cer" ]; then
while true; do
read -p "${const_ca_sub_name} already exists. Are you sure you want to overwrite? [yes|no] " yn
case $yn in
yes ) break;;
no ) exit 0;;
* ) echo "Please answer yes or no";;
esac
done
fi
## Test for create password on subca
if [ "$const_set_pw" == "yes" ]; then nodes=""; else nodes="-nodes"; fi
## Create and sign subordinate CA
touch csr.cnf && openssl req -new -newkey rsa:${const_rsa} -${const_sha} ${nodes} -days ${const_days} -keyout ${const_ca_sub_name}.key -out ${const_ca_sub_name}.csr -subj "/CN=${const_subj}"
openssl x509 -req -${const_sha} -days ${const_days} -CA ${const_ca_root_name}.cer -CAkey ${const_ca_root_name}.key -CAcreateserial -in ${const_ca_sub_name}.csr -out ${const_ca_sub_name}.cer \
-extensions v3_ext \
-extfile <(cat csr.cnf <(printf "[v3_ext]\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid,issuer\nbasicConstraints=critical, CA:TRUE\nkeyUsage=digitalSignature, keyCertSign, cRLSign"))
rm -f ${const_ca_sub_name}.csr csr.cnf
## Test for create CA bundle file
if [ "$const_create_bundle" == "yes" ]; then cat ${const_ca_root_name}.cer ${const_ca_sub_name}.cer > ${const_ca_bundle}.pem; fi
This will create mysubca.cer and mysubca.key in the current folder. The subordinate CA will now be used to create your TLS server certificate(s).
Create a TLS Server Certificate
Like the previous, this script includes a set of “const_” variables that define the parameters of the operations. In particular, the script ensures that the TLS server certificate contains both the “clientAuth” and “serverAuth” EKU values. The "const_tls_name" variable defines both the Subject and SAN values in the certificate, as well as the name of the files. You should set this to the "public" or "fully qualified domain name" that the certificate will represent.
#!/usr/bin/env bash
const_ca_sub_name=mysubca
const_sha=sha256
const_rsa=2048
const_days=1024
const_tls_name=www.foo.com
## ================================
## Create and sign TLS server certificate
touch csr.cnf && openssl req -new -nodes -newkey rsa:${const_rsa} -keyout ${const_tls_name}.key -out ${const_tls_name}.csr -batch -subj "/CN=${const_tls_name}"
openssl x509 -req -${const_sha} -days ${const_days} -CA ${const_ca_sub_name}.cer -CAkey ${const_ca_sub_name}.key -CAcreateserial -in ${const_tls_name}.csr -out ${const_tls_name}.crt \
-extensions v3_ext \
-extfile <(cat csr.cnf <(printf "[v3_ext]\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid,issuer\nsubjectAltName=DNS:${const_tls_name}\nextendedKeyUsage=clientAuth, serverAuth"))
rm -f ${const_tls_name}.csr csr.cnf
This will create www.foo.com.crt and www.foo.com.key in the current folder. You can then verify the contents of this certificate with the following OpenSSL command:
openssl x509 -noout -text -in www.foo.com.crt
In the X509v3 extensions section, you should see these important values, indicating that your TLS server certificate can also be used for client certificate authentication:
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:www.foo.com
X509v3 Extended Key Usage:
TLS Web Client Authentication, TLS Web Server Authentication
At the end of running these scripts you should have something similar to the following in the current folder:
- myca.cer and myca.key: the root CA certificate and private key
- myca.srl: a text file the CA uses to track the last serial number issued
- mysubca.cer & mysubca.key: the subordinate CA certificate and private key
- mysubca.srl: a text file the subordinate CA uses to track the last serial number issued
- mycabundle.pem: the CA bundle file if you chose to create it
- www.foo.com.crt & www.foo.com.key: the TLS server certificate and private key
You can then issue as many TLS server certificates as needed simply by changing the "const_tls_name" value in the server script and running it again. Keep the root and subordinate files (and passphrases) in a safe place for later use.
And there you have it. I would caution again that this method is probably not optimal for a large organization’s PKI but could be suitable for small and ad hoc environments. Thanks again.