System architecture

eMudhra's weak CA keys: why emSign ECC Root CA - G3 is distrusted, and how to replace affected certificates

eMudhra's CA keys were numbers below 256. Why that breaks P-384, what the emSign ECC G3 distrust breaks, and how to replace affected certificates.

Kemo
10 min read
A worn padlock hanging from a rusted hasp on a weathered wooden door post.
On this page
  1. What happened to eMudhra's CA keys?
  2. Why a private key below 256 can be found in milliseconds
  3. How a key ceremony produced the wrong keys
  4. What browsers and operating systems did
  5. Is my site affected? Check the chain
  6. Replace the certificate now; don't wait for renewal
  7. Clients: update the trust stores you forget
  8. What to do today
  9. Questions people ask about the eMudhra distrust
  10. Sources and further reading

Eight intermediate CA certificates run by the Indian certificate authority eMudhra had private keys that were whole numbers below 256. On a P-384 curve that is not a weak key; it is a published one, because anyone holding the certificate can try all 255 values in milliseconds and forge certificates for any domain. Browsers blocked the intermediates within hours of the 17 October report, Mozilla has removed the root that signed them, emSign ECC Root CA - G3, Chrome removes it on 27 October, and on 22 October eMudhra said it will leave the global SSL/TLS business (Google, Mozilla bug 2083449, eMudhra).

This article shows why a small private scalar is fatal, with a script that recovers one; how a key ceremony produced the wrong keys; and what the distrust breaks. If you run a site with a certificate from this hierarchy (most were issued through InCommon to universities and research institutions), you need a new certificate before Chrome's update lands. If you run clients, you need to check the trust stores you ship.

Keys exposed8 intermediates under emSign ECC Root CA - G3: six TLS, two code signing; P-384 private keys between 4 and 237
Root removedemSign ECC Root CA - G3: Mozilla on 20 October; Chrome Root Store on 27 October (expected)
Live certificates hitAbout 30,800 unexpired precertificates chain to the root, nearly all from two InCommon subordinate CAs (Chrome's count, 21 October)
Fraudulent certificates seenNone in Certificate Transparency logs before the block, per Google
Cause givenA flawed script in an April 2025 key ceremony created a second, weak key pair that was used for the CSRs
Business outcomeeMudhra will exit the global SSL/TLS certificate business; revocation services continue until certificates expire or are replaced
The eMudhra incident at a glance, from Google, Mozilla bug 2083449 and eMudhra

What happened to eMudhra's CA keys?

On Saturday 17 October a researcher sent Apple, Google, Microsoft, Mozilla and eMudhra proof of control of the private keys for eight eMudhra intermediates. Mozilla's Dennis Jackson recovered the keys independently and found the P-384 private scalars were all below 256 (bug 2083449). Google describes them as "generated with insufficient randomness" (Google).

Each key had been used in two certificates, one issued by eMudhra and a cross-certificate from Sectigo, so 16 certificates had to be revoked (Scott Helme). eMudhra revoked its eight on 18 October with reason caCompromise, and Sectigo finished revoking its cross-signed copies around 20 October. eMudhra says none of the eight keys issued an end-entity certificate, and that its systems were not breached (eMudhra).

Why a private key below 256 can be found in milliseconds

An elliptic-curve private key is a number d; the public key is the curve's fixed generator point G added to itself d times. Going forwards is cheap. Going backwards is the discrete logarithm problem, which is only hard because d is drawn from a space as large as the curve's order:

Q=d⋅G,d∈[1, n−1],n≈2384 for P-384Q = d \cdot G, \qquad d \in [1,\, n-1], \quad n \approx 2^{384} \text{ for P-384}

Every certificate carries Q. If d is below 256, an attacker computes 1·G, 2·G, 3·G and stops when the point matches, at most 255 steps. Helme reports the eight keys "fell over instantly" on a laptop (Scott Helme). The script below does the same against a key it builds itself with d = 4, the value recovered for EM OV TLS CA - G3C, using only the public point:

weak_p384.pyPython
"""Why a P-384 private key below 256 is no key at all. Builds a key pair with d = 4 (the value Scott Helme recovered forEM OV TLS CA - G3C), then recovers d from the public key alone.Needs: pip install cryptography"""import time from cryptography.hazmat.primitives.asymmetric import ecfrom cryptography.hazmat.primitives.serialization import Encoding, PublicFormat  def public_point(key):    return key.public_key().public_bytes(Encoding.X962, PublicFormat.UncompressedPoint)  def recover(target, limit=256):    """Try d = 1, 2, 3 ... and compare d·G with the published point."""    for d in range(1, limit):        if public_point(ec.derive_private_key(d, ec.SECP384R1())) == target:            return d    return None  weak = ec.derive_private_key(4, ec.SECP384R1())start = time.perf_counter()d = recover(public_point(weak))print(f"weak key:   d = {d} recovered in {(time.perf_counter() - start) * 1000:.1f} ms") strong = ec.generate_private_key(ec.SECP384R1())print(f"strong key: d has {strong.private_numbers().private_value.bit_length()} bits;",      "recover() finds", recover(public_point(strong)))
Recovering a tiny P-384 keyShell
$ pip install cryptography$ python3 weak_p384.pyweak key:   d = 4 recovered in 2.2 msstrong key: d has 382 bits; recover() finds None

The strong key's scalar happens to have 382 significant bits; a properly random one is close to 384, and no loop will reach it. With the weak key, the attacker holds the intermediate CA's signing key, and can sign a certificate for any domain that clients trusting the root will accept.

A certificate publishes its public key, so a key chosen from 255 values is published too.
IntermediateUsed
EM DV TLS CA - G3BTLS156
EM DV TLS CA - G3CTLS230
EM EV TLS CA - G3BTLS115
EM EV TLS CA - G3CTLS56
EM OV TLS CA - G3BTLS155
EM OV TLS CA - G3CTLS4
EM OV CS CA - G3BCode signing66
EM OV CS CA - G3CCode signing237
The eight eMudhra intermediates and their recovered private scalars, from Scott Helme's write-up

How a key ceremony produced the wrong keys

eMudhra's account, posted to the Mozilla bug, is that the keys came from a key generation ceremony on 30 April 2025 using Utimaco HSMs. An approved deviation to test key wrapping was added to the ceremony; a flaw in that code generated a second, weak key pair on the HSM; and because the key labels were similar, the weak pair was used for the certificate signing requests that the root signed and Sectigo cross-signed (bug 2083449).

Key ceremony30 April 2025HSMtwo key pairs, similar labelsIntended keyrandom P-384Weak keyd below 256emSign ECC Root CA - G3signs the CSRSectigocross-signsBrowser trust storesaccept the chain2025 CRLsre-signed with weak keysscript flawCSRCSR
  • Key ceremony → HSM: script flaw
  • HSM → Intended key
  • HSM → Weak key
  • Weak key → emSign ECC Root CA - G3: CSR
  • Weak key → Sectigo: CSR
  • emSign ECC Root CA - G3 → Browser trust stores
  • Sectigo → Browser trust stores
  • Weak key → 2025 CRLs
eMudhra's explanation: the weak pair, not the intended one, went into the CSRs, the cross-signs and later the CRLs.

There was an earlier clue. In 2025 eMudhra published invalid CRLs for six of the same intermediates (bug 1970728). It has now told Mozilla those CRLs were first signed with the intended keys, failed verification, and were then "resigned with flawed keys". Chrome called this a serious transparency concern and asked, in a list of questions, why the 2025 report did not mention two key pairs per CA (The Hacker News).

The questions are not finished. Participants in the bug found that a CRL for emSign Root TLS CA - G1, the RSA hierarchy eMudhra is moving customers to, was signed with an OCSP certificate's key, not the CA's own. Others asked how a certified HSM's generator could produce such keys unnoticed; that was unanswered when this was written (bug 2083449).

What browsers and operating systems did

The intermediates were blocked fast, without users updating anything. The root removal is what breaks legitimate sites.

When (UTC unless noted)WhoAction
17 Oct, 18:05Chrome Root ProgramReceives the report (Google)
17 Oct, 19:45ChromeCRLSet update blocks the intermediates' SPKI hashes; no browser restart needed
17–18 OctFirefoxIntermediates added to OneCRL (bug 2083449)
19 Oct, ~22:00AndroidEquivalent block through Google Play Services
19–20 OctApple, MicrosoftBlock the certificates (CyberScoop)
20 OctMozilla, UbuntuDistrust of emSign ECC Root CA - G3; Ubuntu ca-certificates 20260816 removes it (USN-8944-1)
27 Oct (PDT, expected)ChromeRemoves emSign ECC Root CA - G3 from the Chrome Root Store
Ecosystem response to the eMudhra key compromise, October 2026

Mozilla said on 20 October it was not removing trust in eMudhra's RSA root, emSign Root CA - G1. Chrome is still reviewing whether eMudhra's remaining roots stay in its store (Google, The Hacker News).

Is my site affected? Check the chain

Your site is affected if its certificate chains to emSign ECC Root CA - G3. In practice that means an ECC certificate from InCommon: Chrome counts about 30,791 of the roughly 30,800 unexpired certificates as issued by two InCommon subordinate CAs, after InCommon moved to eMudhra's CertiNext platform earlier this year (bug 2083449, The Hacker News). Look at the issuer names your server sends:

check-chain.shShell
host=www.example.eduopenssl s_client -connect "$host:443" -servername "$host" -showcerts </dev/null 2>/dev/null \  | grep -E '^ *[0-9]+ s:|^ +i:'# Affected if any issuer (i:) line names an emSign ECC ... G3 CA

Check every endpoint, not only the main site: load balancers, mail servers and internal services often carry their own certificates from the same account.

Replace the certificate now; don't wait for renewal

Google's instruction to operators is to "immediately acquire and install a new TLS certificate from another PKI hierarchy" in the Chrome Root Store (Google). About 97% of the affected certificates were issued via ACME, according to eMudhra, and that is the trap: a standard ACME client will not replace a certificate that is still outside its renewal window unless it supports ARI or someone forces it (The Hacker News).

ARI, ACME Renewal Information (RFC 9773), lets a CA tell clients to renew early. If your client does not support it, or you cannot confirm the CA has set the window, force a renewal and ask for RSA, which chains to the G1 root, or move to another CA entirely:

force-renewal.shShell
certbot renew --cert-name www.example.edu --force-renewal --key-type rsa# changing key type on an existing certificate may ask for confirmation; check your certbot version# or issue from a different CA altogether and repoint your server config

Clients: update the trust stores you forget

Browsers fixed themselves. Everything that carries its own CA bundle did not. Helme lists operating system ca-certificates, Python's certifi, Node.js, Homebrew and container base images; Go and several Linux distributions also shipped updates (Scott Helme, CyberScoop). On an updated Ubuntu 24.04 host with a current certifi, the root is gone:

Checking two trust storesShell
$ dpkg-query -W ca-certificatesca-certificates	20260816ubuntu0.24.04.1$ ls /etc/ssl/certs | grep -ci emsign0$ python3 -c "import certifi; print(certifi.__version__)"2026.10.18$ grep -c 'emSign ECC Root CA - G3' "$(python3 -c 'import certifi; print(certifi.where())')"0

Container images are where this lingers: an image built last month keeps last month's bundle until you rebuild it on an updated base. Devices that are hard to update, such as routers, printers and televisions, will trust the root until it expires in 2039, so Helme recommends turning on revocation checking where you can, for example on Windows, where CryptoAPI accepted the chain unless revocation checking was enabled.

What to do today

  • To do: Inventory certificates issued through InCommon or eMudhra, and run the chain check on every endpoint.
  • To do: Replace any certificate chaining to emSign ECC Root CA - G3 before 27 October; force renewal if your ACME client lacks ARI.
  • To do: Decide whether RSA G1 or another CA is your next hierarchy, given Chrome's open review.
  • To do: Update ca-certificates, certifi, Node.js and other bundled stores, and rebuild container images on patched bases.
  • To do: If you rely on eMudhra code-signing certificates, check the status of the G3 code-signing intermediates with eMudhra.

Questions people ask about the eMudhra distrust

What happened to eMudhra?

Eight of its intermediate CA certificates had P-384 private keys below 256, which anyone could recover from the public certificate. Browsers blocked them, Mozilla and Chrome are removing the emSign ECC Root CA - G3 root, and eMudhra announced on 22 October 2026 that it is leaving the global SSL/TLS business.

Which root certificate is being distrusted?

emSign ECC Root CA - G3. Mozilla removed it on 20 October 2026 and Chrome's removal is expected on 27 October. Mozilla said it was not removing emSign Root CA - G1, the RSA root, though Chrome is still reviewing eMudhra's remaining roots.

Were any fraudulent certificates issued?

Google found no TLS certificates chaining to the affected intermediates in Certificate Transparency logs before the block, and eMudhra says none were issued. Whether anyone used the keys privately is not known.

Is my InCommon certificate affected?

If it is an ECC certificate that chains to emSign ECC Root CA - G3, yes. Nearly all of the roughly 30,800 affected certificates came from two InCommon subordinate CAs; check the issuer names your server sends.

Will my ACME client replace the certificate automatically?

Not necessarily. Standard ACME clients renew only inside their renewal window unless they support ARI (RFC 9773) and the CA signals early renewal, so force a renewal or reissue manually.

How were the keys cracked so fast?

An elliptic-curve public key is the private number times a fixed point. With the private number below 256, trying every value takes at most 255 multiplications, which runs in milliseconds.

Do I need to update anything on servers that only make outbound calls?

Yes, if they ship their own trust store. Update ca-certificates, certifi, Node.js and similar bundles, and rebuild container images, so they no longer trust the removed root.

Sources and further reading

Discussion

Join the discussion

Sign in with Google, Apple or an email code to comment and reply.

One practical article a week

Follow k13 in any RSS reader. No account needed.