Every federal civilian agency has to send OMB its post-quantum cryptography migration plan by 22 October 2026. OMB Memorandum M-26-15, which implements Executive Order 14412, requires each plan to include a third-party coordination plan, and it gives program offices the job of making sure vendor requirements include PQC readiness and cryptographic agility. So the next round of questions about your product's cryptography is already being written, before any contract clause requires an answer.
This guide is for software and SaaS vendors that sell to US federal agencies, and the engineers who'll answer for the product's cryptography. It sets out what EO 14412 and M-26-15 require and when, where CISA's product list puts your category, what agencies are likely to ask, and a Go tool that checks whether your TLS endpoints accept a post-quantum key exchange today.
The short answer
Executive Order 14412, signed on 22 June 2026, sets 31 December 2030 for federal high value assets and high impact systems to use post-quantum cryptography for key establishment, and 31 December 2031 for digital signatures. It also orders two FAR rules for contractors: a proposed rule, due about 19 December 2026, requiring compliance with NIST's FIPS, including the post-quantum standards, by 31 December 2030; and one, due about 19 March 2027, requiring vulnerability disclosure programs that accept reports of cryptographic weaknesses. Neither rule exists yet. What exists now is M-26-15, which tells agencies to inventory their cryptography, prioritize systems, buy PQC-capable products where they're widely available, and coordinate with vendors. A vendor that can show a cryptographic inventory, hybrid post-quantum key exchange on its TLS endpoints, and a plan for signatures will have the answers ready.
What EO 14412 orders, and when
The order runs on fixed day counts from 22 June 2026:
| Deadline | Section | Who | What |
|---|---|---|---|
| 22 Jul 2026 (30 days) | 4(a) | Each agency | Name a PQC migration lead |
| 20 Sep 2026 (90 days) | 4(b) | OMB | Issue migration guidance (done early, as M-26-15 on 24 June) |
| 19 Dec 2026 (180 days) | 6(c) | FAR Council | Proposed rule: covered contractors comply with NIST FIPS, including PQC, by 31 Dec 2030 |
| 19 Dec 2026 (180 days) | 6(b) | NIST | Revise the Cryptographic Module Validation Program to speed up validations |
| 19 Mar 2027 (270 days) | 6(d) | FAR Council | Proposed rule: contractor vulnerability disclosure policies that cover cryptographic vulnerabilities, "including testing for lack of encryption and the use of non-FIPS approved algorithms" |
| 19 Mar 2027 (270 days) | 5(d) | CISA with NIST | Public guidance on minimum elements for a cryptographic bill of materials |
| 31 Dec 2030 | 4(b)(ii) | Agencies | High value assets and high impact systems use PQC for key establishment |
| 31 Dec 2031 | 4(b)(iii) | Agencies | The same systems use PQC for digital signatures |
The FAR dates are for proposed rules. A final rule, its exact scope and the clause text will come later, after public comment. National security systems are handled separately, through the NSA.
What M-26-15 asks of agencies
M-26-15 turns the order into a plan. Agencies must aim to mitigate "as much quantum risk as feasible" by the end of 2030, in phases:
| Phase | Years | Focus |
|---|---|---|
| 1 | 2026 to 2027 | Strategy, planning and discovery, including the cryptographic inventory |
| 2 | 2027 to 2028 | Pilots and early migration |
| 3 | 2028 to 2030 | PQC key establishment for prioritized systems |
| 4 | 2031 | PQC digital signatures for the same systems |
| 5 | 2035 | Remaining systems |
Priority goes to high impact systems, high value assets, logical access control built on asymmetric cryptography such as PKI, and data expected to stay mission-sensitive in 2030. Appendix A lists the quantum-vulnerable algorithms: ECDH, MQV, ECDSA, finite-field Diffie-Hellman, RSA for signatures and key establishment, DSA, and any other asymmetric algorithm "not definitively known to be quantum-resistant". The replacements are ML-KEM (FIPS 203) for key establishment and ML-DSA (FIPS 204) or SLH-DSA (FIPS 205) for signatures.
Three parts of the memo reach vendors directly:
- TLS 1.3. Agencies must support TLS 1.3 or a successor by 2 January 2030, the date EO 14306 set. The memo calls TLS 1.3 foundational for PQC because hybrid key exchange runs on its handshake.
- Automation. It says the inventory should be built with automated tools where possible, naming software composition analysis of SBOMs, SAST and DAST to find cryptographic functions in code, and network scanners for protocols and cipher suites, feeding a central cryptographic bill of materials.
- Products. Agencies should use CISA's list of PQC product categories and require PQC integration for products in them. CISA and the Department of War, with GSA, will lead the work with FedRAMP-authorized cloud providers and with SaaS, PaaS and IaaS offerings used by more than one agency.
Where CISA's list puts your product
CISA published its "Product Categories for Technologies That Use Post-Quantum Cryptography Standards" on 23 January 2026, under EO 14306. It has two tables.
Widely available, so agencies "should plan acquisitions to procure only PQC-capable products": cloud services (PaaS and IaaS), chat and messaging, web browsers and web servers, and data-at-rest encryption. CISA notes that most of these have PQC for key establishment but not yet for signatures.
Transitioning, where manufacturers are encouraged to implement and test PQC: SaaS, networking hardware and software, operating systems, hypervisors and containers, identity and access management including certificate authorities and HSMs, email and conferencing, databases, and security tools such as SIEM and intrusion detection. CISA asks that products here use PQC for secondary functions too, "such as for software updates".
If you sell a web-facing service on PaaS or IaaS, or a web server, you're in the first table, and a buyer following the guidance can treat missing PQC key exchange as a reason not to buy. If you sell SaaS, you're in the second. That isn't a pass. It's where CISA expects movement, and products move to the first table as the category matures.
What agencies will likely ask
M-26-15 doesn't publish a vendor questionnaire, so treat this as a reading of the memo, not a list of official questions. Expect some version of:
- What cryptography does the product use, and where? Libraries and versions, algorithms in code, protocols on the wire, certificate and key types.
- Do your endpoints negotiate hybrid post-quantum key exchange? For TLS, that means a group such as X25519MLKEM768.
- Do you support TLS 1.3?
- Is the cryptography configurable? The memo's agility section says algorithm choices "must be specified in external configuration files, not compiled into the application binary".
- What's your plan for signatures? Code signing, update signing, JWT and API token signing, certificates.
- Are your cryptographic modules FIPS 140-3 validated?
- Does your vulnerability disclosure policy accept cryptographic findings?
Our guide to what crypto agility means in practice covers question 4 in depth.
Check your TLS endpoints
The fastest question to answer is the second one. This Go program connects to each endpoint three times with only one hybrid group offered, X25519MLKEM768, SecP256r1MLKEM768 or SecP384r1MLKEM1024, and records which the server accepts. It also reports the default negotiation and the certificate's key, which stays quantum-vulnerable until certificates move to ML-DSA. It needs Go 1.26 or later, uses only the standard library, and does nothing but TLS handshakes. Use -cafile for internal endpoints with a private CA.
// pqtls checks whether TLS endpoints accept a post-quantum hybrid key exchange
// and reports the quantum-vulnerable parts of each handshake (certificate key
// and signature). It needs Go 1.26 or later and only performs TLS handshakes.
//
// go run . example.com api.example.com:8443
// go run . -cafile internal-ca.pem portal.internal:8443
package main
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"flag"
"fmt"
"net"
"os"
"strings"
"time"
)
var hybrids = []tls.CurveID{tls.X25519MLKEM768, tls.SecP256r1MLKEM768, tls.SecP384r1MLKEM1024}
var roots *x509.CertPool // nil means the system trust store
func dial(addr string, curves []tls.CurveID) (tls.ConnectionState, error) {
host, _, _ := net.SplitHostPort(addr)
d := &net.Dialer{Timeout: 10 * time.Second}
conn, err := tls.DialWithDialer(d, "tcp", addr, &tls.Config{
ServerName: host,
MinVersion: tls.VersionTLS12,
CurvePreferences: curves,
RootCAs: roots,
})
if err != nil {
return tls.ConnectionState{}, err
}
defer conn.Close()
return conn.ConnectionState(), nil
}
func keyDesc(c *x509.Certificate) string {
switch k := c.PublicKey.(type) {
case *rsa.PublicKey:
return fmt.Sprintf("RSA-%d (quantum-vulnerable)", k.N.BitLen())
case *ecdsa.PublicKey:
return fmt.Sprintf("ECDSA %s (quantum-vulnerable)", k.Curve.Params().Name)
case ed25519.PublicKey:
return "Ed25519 (quantum-vulnerable)"
default:
return c.PublicKeyAlgorithm.String()
}
}
func main() {
cafile := flag.String("cafile", "", "PEM file of extra CA certificates, for internal endpoints")
flag.Parse()
if flag.NArg() == 0 {
fmt.Fprintln(os.Stderr, "usage: pqtls [-cafile ca.pem] host[:port] ...")
os.Exit(2)
}
if *cafile != "" {
pem, err := os.ReadFile(*cafile)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(2)
}
roots, _ = x509.SystemCertPool()
if roots == nil {
roots = x509.NewCertPool()
}
roots.AppendCertsFromPEM(pem)
}
missing := 0
for _, arg := range flag.Args() {
addr := arg
if !strings.Contains(addr, ":") {
addr += ":443"
}
def, err := dial(addr, nil)
if err != nil {
fmt.Printf("%s\n error: %v\n", addr, err)
missing++
continue
}
var accepted []string
for _, h := range hybrids {
if st, err := dial(addr, []tls.CurveID{h}); err == nil && st.CurveID == h {
accepted = append(accepted, h.String())
}
}
leaf := def.PeerCertificates[0]
fmt.Printf("%s\n", addr)
fmt.Printf(" default handshake: %s, key exchange %s\n", tls.VersionName(def.Version), def.CurveID)
if len(accepted) > 0 {
fmt.Printf(" hybrid PQC key exchange accepted: %s\n", strings.Join(accepted, ", "))
} else {
fmt.Printf(" hybrid PQC key exchange accepted: none\n")
missing++
}
fmt.Printf(" certificate key: %s, signed with %s\n", keyDesc(leaf), leaf.SignatureAlgorithm)
}
if missing > 0 {
os.Exit(1)
}
}
Save it as main.go beside a go.mod containing module pqtls and go 1.26. We ran it on 16 October against three federal sites:
$ go run . www.cisa.gov login.gov sam.gov
www.cisa.gov:443
default handshake: TLS 1.3, key exchange X25519MLKEM768
hybrid PQC key exchange accepted: X25519MLKEM768
certificate key: ECDSA P-256 (quantum-vulnerable), signed with ECDSA-SHA384
login.gov:443
default handshake: TLS 1.3, key exchange X25519MLKEM768
hybrid PQC key exchange accepted: X25519MLKEM768, SecP256r1MLKEM768
certificate key: RSA-2048 (quantum-vulnerable), signed with SHA256-RSA
sam.gov:443
default handshake: TLS 1.3, key exchange X25519MLKEM768
hybrid PQC key exchange accepted: X25519MLKEM768, SecP256r1MLKEM768
certificate key: RSA-2048 (quantum-vulnerable), signed with SHA256-RSA
All three already negotiate a hybrid key exchange by default, and all three still present RSA or ECDSA certificates. That's the state CISA's footnote describes: key establishment first, signatures later. For the failing case, we started two local OpenSSL 4.0.3 test servers, one limited to classical groups with -groups X25519:P-256:
$ go run . -cafile c.pem localhost:8443 localhost:8444
localhost:8443
default handshake: TLS 1.3, key exchange X25519
hybrid PQC key exchange accepted: none
certificate key: ECDSA P-256 (quantum-vulnerable), signed with ECDSA-SHA256
localhost:8444
default handshake: TLS 1.3, key exchange X25519MLKEM768
hybrid PQC key exchange accepted: X25519MLKEM768, SecP256r1MLKEM768
certificate key: ECDSA P-256 (quantum-vulnerable), signed with ECDSA-SHA256
The program exits with status 1 when any endpoint accepts no hybrid group, so it can run in CI against staging. Without Go, OpenSSL 3.5 or later answers the same question for one group:
openssl s_client -connect www.cisa.gov:443 -groups X25519MLKEM768 </dev/null 2>&1 | grep "Negotiated TLS1.3 group:"
It prints Negotiated TLS1.3 group: X25519MLKEM768 when the server accepts the group. When it doesn't, the handshake fails with a handshake_failure alert and the command prints nothing.
Most fixes are an upgrade
If your endpoints fail, the cause is usually the TLS library or the load balancer in front of the service, not your code. The baselines we confirmed:
- OpenSSL 3.5.0 (8 April 2025) added ML-KEM, ML-DSA and SLH-DSA, and changed the default TLS key shares to offer X25519MLKEM768 and X25519.
- Go 1.24 added
crypto/mlkemand enabled X25519MLKEM768 by default incrypto/tls. Go 1.26 added SecP256r1MLKEM768 and SecP384r1MLKEM1024 to the default, and Go 1.27 addedcrypto/mldsa. SettingCurvePreferencesexplicitly, orGODEBUG=tlsmlkem=0, turns the hybrids off, so check your config. - Java: JDK 24 added ML-KEM (JEP 496) and ML-DSA (JEP 497) as APIs.
Then look in front of the service. A load balancer, CDN or API gateway terminates TLS and decides the key exchange, which is why the memo lists "cloud gateways" and "API proxies" among the network devices that must support PQC key exchange.
Build the inventory you'll be asked for
A first-pass cryptographic inventory takes four sources, the same ones M-26-15 names:
- Dependencies. From your SBOM, list every cryptographic library and its version: OpenSSL, BoringSSL, Go's standard library, Bouncy Castle, libsodium, language bindings.
- Code. Search first-party code for direct use of RSA, ECDSA, ECDH, DH and DSA, for hardcoded algorithm names, and for key sizes. These are the places configuration can't change.
- Network. Run the checker above against every public and internal TLS endpoint, including the ones behind gateways.
- Keys and signatures. Certificates, code-signing and update-signing keys, JWT signing keys, and what your KMS or HSM can generate.
Record it in a format a buyer can read. CycloneDX supports cryptographic assets today, and CISA's minimum elements for a CBOM are due by March 2027. Our explainer on what a cryptographic bill of materials is covers the format.
What to do
- Run the TLS check against production and staging. Fix failures by upgrading the TLS library or the terminating proxy.
- Support TLS 1.3 everywhere. It's a prerequisite for hybrid key exchange, and agencies have to support it by January 2030.
- Write the inventory down from the four sources above, and keep it current with automation.
- Move algorithm choices into configuration wherever code hardcodes them.
- Publish a signature plan with dates for code signing, update signing and tokens, even if they depend on your vendors.
- Update your vulnerability disclosure policy to accept cryptographic findings, before the FAR rule requires it.
The fair view
None of this is a contract requirement yet. The FAR rules are proposals due this winter and next spring, the 2030 and 2031 dates apply to agency systems rather than vendors, and M-26-15 is guidance to agencies. A vendor could wait for the final rule and lose nothing on paper.
The memo is also candid about the costs. It calls hybrid architecture "an intricate and resource-intensive stopgap" and asks agencies to weigh the trade-offs. PQC signatures are larger: 2,420 bytes for ML-DSA-44 and 3,309 for ML-DSA-65, against 64 bytes for an ECDSA P-256 signature. Signature migration will be harder than key exchange because it touches certificates, firmware and every verifier.
But key exchange is mostly an upgrade, it protects data recorded now from decryption later, and federal sites already do it. A buyer comparing two vendors in a widely available category has an official reason to prefer the one that negotiates X25519MLKEM768. For most vendors, the cheapest time to be that one is before the plans due on 22 October turn into requirements.