The PKI ecosystem treats the Hardware Security Module (HSM) as a vault. If a Certificate Authority (CA) generates keys during a ceremony in a WebTrust-audited facility on FIPS-validated hardware, auditors and relying parties assume those keys have full entropy and never left a tamper-resistant boundary. In October 2026, that assumption failed for eMudhra (CCADB ID: A005678).
A third-party researcher showed that the private keys for eight publicly trusted ECDSA P-384 subordinate CAs could be recovered straight from their public certificates. The private scalars were 4, 56, 66, 115, 155, 156, 230, and 237. A key that should offer 192-bit security could be brute-forced on one CPU core in microseconds.
The HSMs did not fail. Their random number generators ran within spec, their elliptic curve arithmetic was sound, and the cryptographic libraries had no zero-days. The damage happened in the gap between the cryptographic module and the host operating system. During an April 2025 key ceremony, eMudhra’s PKI Operations team ran a custom Python script to rehearse a cross-vendor HSM key migration. The script disabled FIPS mode on the source module, unwrapped freshly generated private keys, pulled their raw attributes into the RAM of the ceremony host, and re-imported them. In that round trip, one line of Python cut each 48-byte ECDSA private scalar down to its first byte.
Eight RSA-4096 intermediate keys went through the same ceremony and escaped truncation. Their private exponents and prime factors still passed through unencrypted host memory, which broke their security guarantees anyway. Within weeks of disclosure, eMudhra revoked all sixteen intermediate CAs and announced it was leaving the public TLS business.
Why eMudhra wrote a custom key-migration script
Historically, eMudhra and virtually every other compliant CA generated root and issuing CA keys in place. The keys were born inside the HSMs that would operate them in production, so nothing ever had to be exported or transported.
In November 2024, eMudhra approved an international expansion with new hosting environments in the United States and the European Union, plus a cross-certification agreement with Sectigo (under the AAA Certificate Services root) to speed up root ubiquity for its newer hierarchies. The plan called for two geographic sets of issuing CAs, a “B” series and a “C” series. Each spanned RSA-4096 (chaining to emSign Root TLS CA – G1 and emSign Root CS CA – G2) and ECDSA P-384 (chaining to emSign Root TLS CA – G3 and emSign Root CS CA – G3).
By April 2025, global supply-chain delays had held up the Crypto4A HSMs ordered for the new US facility. Normally a CA would postpone the ceremony until the destination hardware arrived and the facility passed its WebTrust audit. Two deadlines ruled that out:
- Root store policy changes effective 15 June 2025 required any subordinate CA disclosed in an applicant hierarchy on or after that date to be strictly dedicated to TLS server authentication, which changed multipurpose hierarchy designs.
- The Sectigo cross-certification agreement required the subordinate CA certificates to be generated, signed, and submitted before the June cutoff.
Management committed to generating keys inside an active WebTrust-certified environment before the end of May 2025. In mid-April they settled on a two-stage plan. They would generate all sixteen B-series and C-series subordinate CAs on the Utimaco HSMs in their existing certified datacenter, then move the C-series keys across vendors and geographies to the Crypto4A HSMs once the US datacenter was live.
A third group of domestic intermediates, the “A” series (replaced in May 2025 by the “A-1” series to adjust component encoding in the Common Name attribute), was generated on a separate HSM platform with standard, unmodified ceremony scripts. It was not affected.
Moving private keys between HSMs from different vendors is hard in practice. PKCS#11 defines C_WrapKey and C_UnwrapKey so a source HSM can encrypt a private key under a Key Encryption Key (KEK) and export it as an opaque blob for a destination HSM to unwrap internally. Vendors implement this differently: AES Key Wrap with Padding under PKCS#11 v2.40 versus vendor-specific mechanisms, attribute-binding metadata, proprietary key-blob formats. A blob exported by one vendor often cannot be ingested cleanly by another vendor’s native tooling.
📬 Stay Ahead of Cyber Threats
Get the latest cybersecurity news, critical vulnerabilities, threat intelligence, tutorials, and exclusive giveaways delivered straight to your inbox. No spam. Unsubscribe anytime.
To bridge Utimaco and Crypto4A, the PKI Operations team wrote a one-off Python script to run on an isolated ceremony host during the 30 April 2025 key-generation ceremony. The aim was a full wrap/unwrap round-trip rehearsal on the source Utimaco module before certifying the keys.
Inside the 30 April 2025 key ceremony
The ceremony was witnessed by eMudhra’s compliance function. The team generated sixteen subordinate CAs:
- Eight ECDSA P-384 CAs: EM DV TLS CA, EM OV TLS CA, EM EV TLS CA, and EM OV CS CA, across the G3B and G3C series.
- Eight RSA-4096 CAs: the matching DV, OV, EV TLS, and OV Code Signing intermediates across the G2B and G2C series.
The Utimaco HSM first generated all sixteen key pairs onboard, in full compliance with cryptographic standards. If the ceremony had stopped there and the Certificate Signing Requests (CSRs) had been built from those original key handles, there would have been no incident.
Instead, the team started the approved wrap/unwrap deviation. To let the script manipulate key material for cross-vendor bridging, the operators disabled FIPS-approved mode on the Utimaco HSM, a deviation recorded in the ceremony script. Under strict FIPS 140-2/140-3 Level 3 operation, a key generated with CKA_SENSITIVE = True and CKA_EXTRACTABLE = False cannot have its raw private attributes read over PKCS#11. Even extractable keys can only leave in encrypted form through approved wrapping mechanisms that preserve attribute enforcement. Turning off FIPS mode loosened the module’s policy enforcement around wrapping, unwrapping, and attribute extraction.
A purely internal HSM-to-HSM unwrap would have kept the key opaque to the host. The script did something else. After wrapping and unwrapping a key on the module, it queried the unwrapped object, read the raw private key value into the memory of the Python process on the ceremony host, then called object-creation routines (analogous to C_CreateObject) to build a brand-new private key object inside the HSM from that host-side buffer.
How a one-byte truncation broke the ECDSA P-384 keys
For the eight ECDSA objects, that read-back contained an indexing bug. Under NIST P-384 (secp384r1), a private key is a random scalar d in the interval [1, n-1], where the curve order n is a 384-bit prime:
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973
Across PKCS#11, the scalar sits in the CKA_VALUE attribute as a 48-byte array. When the script read the unwrapped key into host memory, one line sliced or indexed the buffer down to its leading byte. This is the classic Python confusion over a bytes object: key_bytes[0] returns an integer between 0 and 255, key_bytes[:1] returns a one-byte slice, and neither is the full 48-byte buffer. When the script re-created the key on the HSM, it populated CKA_VALUE with a single byte.
The new HSM object held a private scalar d’ between 1 and 255. The script derived the public key point Q’ = d’G (G being the P-384 base point) from it and used it to build and sign the CSR. That public key was mathematically valid and lay on the curve, and the Proof-of-Possession signature verified cleanly against Q’.
The discrete logarithm space, however, had collapsed from 2^384 to 2^8. Anyone holding the public key in the issued CA certificate could precompute 1G, 2G, 3G, and so on up to 255G in under a millisecond and read off the private key. Across the eight G3B and G3C ECDSA intermediates, the truncation produced the scalars 4, 56, 66, 115, 155, 156, 230, and 237.
Why the RSA-4096 keys were revoked too
The eight RSA-4096 keys (G2B and G2C) from the same ceremony were affected differently.
An ECDSA private key is a single raw scalar. A PKCS#11 RSA private key object using Chinese Remainder Theorem (CRT) optimization needs a multi-attribute template: the modulus (CKA_MODULUS), public exponent (CKA_PUBLIC_EXPONENT), private exponent (CKA_PRIVATE_EXPONENT), primes p and q (CKA_PRIME_1, CKA_PRIME_2), the CRT exponents d mod (p-1) and d mod (q-1) (CKA_EXPONENT_1, CKA_EXPONENT_2), and the CRT coefficient q^-1 mod p (CKA_COEFFICIENT). If p, q, or d were truncated to a single byte, the relationships n = p × q and e·d ≡ 1 (mod λ(n)) would fail internal consistency checks or produce signatures that fail against the 4096-bit modulus.
In eMudhra’s script, the code path for RSA attributes copied the full multi-byte arrays without triggering the truncation bug. Every signature from the re-created G2B and G2C objects verified against the full 4096-bit public moduli.
The keys were still compromised from a compliance standpoint. Because the script used the same read-and-recreate pattern on RSA objects, the raw CRT components, including CKA_PRIVATE_EXPONENT and CKA_PRIME_1, were read out of the HSM and held in the heap of the Python interpreter on the ceremony host before being written back.
Section 6.2.6 of the CA/Browser Forum TLS Baseline Requirements and Section 6.2.6 of eMudhra’s Certification Practice Statement (CPS v1.08) say a CA private key must never exist in plaintext outside the physical and logical boundary of a FIPS-validated cryptographic module. Between modules, it must travel encrypted (wrapped) or as split knowledge under multi-party control. Pulling the private exponent and first prime into host RAM broke that rule.
The air-gapped ceremony host does not rescue the situation. Modern operating systems and runtimes like Python give no deterministic memory zeroization for ordinary byte strings, so key material can linger in unallocated heap pages or end up in swap or paging files. In its incident report, written after discussions with root program operators in early November 2026, eMudhra noted that reviewing ceremony logs, system logs, and filesystem artifacts cannot prove that key material handled in volatile memory stayed confidential.
So the two sets were revoked under different reason codes. The eight ECDSA intermediates were revoked on 18 October 2026 with RFC 5280 reason code cACompromise (2). The eight RSA intermediates were revoked on 7 November 2026 with cessationOfOperation (5), because they could not be reconciled with CPS §6.2.6.
There is one further irony. On 14 and 15 July 2025, eMudhra moved the eight C-series keys (four ECDSA G3C, four RSA G2C) to the Crypto4A HSMs in the US facility. The PKCS#11 interface on the destination module could not complete the import as planned, so the team built a second custom import workflow with the vendor’s native tooling. That workflow had no truncation bug, but by then the damage was in the keys. What migrated in July were the already-truncated ECDSA objects and the host-exposed RSA objects from April 30.
Control gaps that hid the defect for 18 months
One scripting bug during an unusual ceremony is an understandable human error. What needs explaining is how eight intermediate CAs with 8-bit private keys passed ceremony witnessing, entered the Common CA Database (CCADB), received cross-certificates from Sectigo, cleared two annual WebTrust audit cycles (2025 and 2026), and stayed trusted in public root stores for eighteen months. That points to systemic gaps, both inside eMudhra and across industry verification standards.
No key-strength or public-key binding check. Baseline Requirements §6.1.6 requires CAs to run automated key-strength and quality checks on subscriber public keys, such as testing RSA moduli for small prime factors or validating ECDSA points. §6.1.1.1, which governs CA key pair generation, has no equivalent mandatory post-generation test for the CA’s own keys, because the rules assume a validated HSM generated the key and nobody touched it afterward.
Standard linters (zlint, cablint, pkilint) check X.509 syntax, extension criticality, and profile adherence. Multiplying d’ = 4 by the P-384 generator gives an uncompressed 97-byte ANSI X9.62 point (0x04 || X || Y). Both coordinates are full-width, random-looking 384-bit field elements that satisfy the Weierstrass equation y² ≡ x³ – 3x + b (mod p). To a linter, or to an auditor reading a hex dump, 4G is indistinguishable from a full-entropy public key. A check that d exceeds 2^300, or a comparison between the public key in the CSR and the public key of the originally generated HSM object, would have stopped the ceremony on the spot.
Ambiguous object labeling inside the HSM. The April 30 script left the original full-strength key pair and the re-created truncated pair in the same HSM partition with nearly identical CKA_LABEL strings. The operators and the CSR-generation routine picked the re-created handle without noticing a duplicate existed. No strict maker/checker comparison of raw CKA_ID and CKA_LABEL handles against hardware generation logs was in place, so the defective object went straight into the signing ceremony.
A symptom-level fix of the June 2025 CRL anomaly. This was the most frustrating miss. Between 29 May and 6 June 2025, about a month after the keys were disclosed in CCADB (Bugzilla Bug 1965559), an external monitor filed Mozilla Bugzilla Bug 1970728. It reported that the CRLs for the six G3B and G3C TLS intermediates failed signature verification against the public keys in the corresponding CA certificates.
The cause is clear in hindsight. eMudhra’s automated CRL signing responder had been bound to the HSM handle of the originally generated, full-strength P-384 key pairs, while the issued CA certificates contained the public keys of the re-created, truncated objects.
Investigating Bug 1970728 properly would have surfaced the whole problem more than a year before the third-party report. The right questions were why each intermediate CA had two nearly identically labeled private keys in the HSM, and why the certified public key did not match the primary generated key pair. The operations team treated it as a configuration pointer mismatch instead. They pointed CRL signing at the second (truncated) key handle, confirmed the CRL now verified, and closed the ticket. That left an unapproved secondary key handle with a 1-byte scalar in operation for over a year.
Blast radius and revocation timeline
The researcher reported the recoverable ECDSA keys to eMudhra and the root programs on 17 October 2026, and root program operators reproduced the private scalars the same day. One operational detail prevented an internet-wide TLS emergency: neither the eight ECDSA G3B/G3C intermediates nor the four RSA G2B intermediates had ever issued end-entity subscriber certificates. All twelve sat dormant.
On 18 October 2026, between 09:24 and 09:38 UTC, roughly 15 hours after the initial report and well within the 24-hour and 7-day windows in Baseline Requirements §4.9.1.2, eMudhra revoked all eight ECDSA G3B/G3C subordinate CA certificates with reason code cACompromise and published updated CRLs and OCSP responses. On 19 October, Sectigo revoked its eight corresponding cross-certificates chaining to AAA Certificate Services, and eMudhra halted issuance across the entire ECC G3 root hierarchy.
Some friction remained. Mozilla Bugzilla Bug 2085612 noted that eMudhra’s CRL distribution points returned availability errors for certain HTTP User-Agent headers, which complicated automated revocation checks for non-browser relying parties.
Live subscribers were affected through the four RSA-4096 G2C intermediates (EM DV TLS CA – G2C, EM OV TLS CA – G2C, EM EV TLS CA – G2C, and EM OV CS CA – G2C). They had been migrated to the US facility and put into production in May 2026, and had issued production TLS and code-signing certificates. Issuance stopped on these dates:
- Final code-signing certificate: 7 October 2026, 20:11:57 UTC
- Final DV TLS certificate: 27 October 2026, 19:14:35 UTC
- Final OV TLS certificate: 3 November 2026, 13:48:16 UTC
Once root program discussions in early November established that the host-memory exposure of the RSA attributes violated CPS §6.2.6, eMudhra started subscriber replacement and revoked all eight RSA G2B and G2C intermediates on 7 November 2026.
Revoked intermediate and cross-certificates
The table below lists all twenty-four revoked intermediate and cross-certificates, for threat hunters, CT log analysts, and anyone auditing a trust store.
Series & Type Subordinate CA Common Name Issuing CA Serial Number (Hex) SHA-256 Certificate Fingerprint Revocation Date & Reason ECDSA P-384 (Native) EM DV TLS CA – G3B emSign Root TLS CA – G3 a4aee678f23362b4c0e460b772f21442C4ACCD12C4F59597925E1A08A7A90102608543809308D50EC427E118BA149318 Oct 2026 ( cACompromise)ECDSA P-384 (Native) EM DV TLS CA – G3C emSign Root TLS CA – G3 588b2e3c2bb8cda13e1a12092543210164D7CEAE5BB909C272AF151FF44B1177AE9B47D9424B94F1D9558C30934D1918 Oct 2026 ( cACompromise)ECDSA P-384 (Native) EM EV TLS CA – G3B emSign Root TLS CA – G3 c7c41efe92d825f05eae841a4a82c1E7568FE6E12331F4FD7DE61DA4C7559D0F8EB192A218D4741A3BA7518433383818 Oct 2026 ( cACompromise)ECDSA P-384 (Native) EM EV TLS CA – G3C emSign Root TLS CA – G3 8009928a64107601af05fa2f19f109432EC25F0D28DE9006D97BF752F17BBB2CD41F669933FCB072D9A1148D0261F318 Oct 2026 ( cACompromise)ECDSA P-384 (Native) EM OV TLS CA – G3B emSign Root TLS CA – G3 6cada367fb1c100088120ea202d56898B896625C0C230ADEEC3EB2CF6AAD5001ECF9156A68644E82374CE5833BC25B18 Oct 2026 ( cACompromise)ECDSA P-384 (Native) EM OV TLS CA – G3C emSign Root TLS CA – G3 296926c227a3a1526392b19482a504CB6E15165AC802E9B3F993F16C25D41F4E81C21EBDE71AE1B012AC00BF9C7C3F18 Oct 2026 ( cACompromise)ECDSA P-384 (Native) EM OV CS CA – G3B emSign Root CS CA – G3 7818933f8f85b4619a2b35fba83d0a9E39DE2881273ACC225A149C72BA3E0F51424963669AB633EE1DC7DF5DB067B418 Oct 2026 ( cACompromise)ECDSA P-384 (Native) EM OV CS CA – G3C emSign Root CS CA – G3 544b7f922c31ae220a4a922916f6e64B2460A466F95FD40113BCDCCA2CEB29B3B093921DE45474DA7DF48874C630B118 Oct 2026 ( cACompromise)ECDSA P-384 (Cross-Cert) EM DV TLS CA – G3B Sectigo (AAA Cert Services) a024fdf4ba665c785ce4a020483858b745A883F349AEDFD5F3A649B5498FFB121712BA8B448F3F2A91DBC5A766FCDDBE19 Oct 2026 (Revoked) ECDSA P-384 (Cross-Cert) EM DV TLS CA – G3C Sectigo (AAA Cert Services) 91f347f1a5b7d39962b95e0ee4e299d162B7F9868263F72F6911FC78CEAF72C1979158B7368BF648683BB2AA39B02E7219 Oct 2026 (Revoked) ECDSA P-384 (Cross-Cert) EM OV TLS CA – G3B Sectigo (AAA Cert Services) e94223bde92f914e5ab9acabfdac37105F1DED4DD590AF74631290CF073B122A2AAC6A1FA479778A0BD43579BD83269919 Oct 2026 (Revoked) ECDSA P-384 (Cross-Cert) EM OV TLS CA – G3C Sectigo (AAA Cert Services) 8d5a4811939ef447d77111cdd9849ae97485B51C0ED192878FA1D2F948FB529AE1842CC5086C4B67F7BE5B2039DE948919 Oct 2026 (Revoked) ECDSA P-384 (Cross-Cert) EM EV TLS CA – G3B Sectigo (AAA Cert Services) d8f8685e4f2bd9d82402a85a1c1eb731579480AEA166290BD3C643589E795FC0D0E54E86505D180F1DFF99EFD319951219 Oct 2026 (Revoked) ECDSA P-384 (Cross-Cert) EM EV TLS CA – G3C Sectigo (AAA Cert Services) 05f078752dece7a1bb8595d303167171FD9D5C2DBBD4995AB69B8D50C439D9527B00529199C2FD01B2174EB58F07021F19 Oct 2026 (Revoked) ECDSA P-384 (Cross-Cert) EM OV CS CA – G3B Sectigo (AAA Cert Services) 41e32b73ac185d6ce0d7480bacf84e69A496E23AC0CAB8155FC9B117B97EAE368EFCBB9041AEC8804D5A308D2D01C2D819 Oct 2026 (Revoked) ECDSA P-384 (Cross-Cert) EM OV CS CA – G3C Sectigo (AAA Cert Services) d6a5ef613b390f32ef9cdf349f77284184112972B8E59D14560AE7E7119654474AAD119990CF3722BFC1E3B91615E1FD19 Oct 2026 (Revoked) RSA-4096 (Native) EM DV TLS CA – G2B emSign Root TLS CA – G1 F0A030825E22BB2E1D88E3889DC073829EC444B8BE3DFD2D030A0D9E7A1D0DD2A3C2C325D39589C27AC9A065BAE79307 Nov 2026 ( cessationOfOperation)RSA-4096 (Native) EM DV TLS CA – G2C emSign Root TLS CA – G1 AB5DEA38BDC920D5FA4736DA54BEBE0427EA3CB4A7B4CB205E77A7B166D332BEDB8E8EF469BC5E883169C8D0AC876D07 Nov 2026 ( cessationOfOperation)RSA-4096 (Native) EM OV TLS CA – G2B emSign Root TLS CA – G1 C164DB9804F563241ED32C4100A5666A7A93861982B664001710A0EFD04C8A72F6A23E252B280911797E0BF1BD901207 Nov 2026 ( cessationOfOperation)RSA-4096 (Native) EM OV TLS CA – G2C emSign Root TLS CA – G1 CBDCFA0D64112709CF14B7E4858250DE767792E870BD32F331029FC89DC24C53F9DF970DC70F1EA30CF29DB3F94BA907 Nov 2026 ( cessationOfOperation)RSA-4096 (Native) EM EV TLS CA – G2B emSign Root TLS CA – G1 8F06A3F1D6A2FC71D29393C71CD48EE072B30D7F5B8BCF0080E51D6CC7765767072DB2319E9BB1CD3D02A08689875007 Nov 2026 ( cessationOfOperation)RSA-4096 (Native) EM EV TLS CA – G2C emSign Root TLS CA – G1 B28103309375C0CBB9E9B80B66C430C3BC2B480FB1A1AB4D0BA1ED6C7B53E096447045733620991A32D6798D77AA2007 Nov 2026 ( cessationOfOperation)RSA-4096 (Native) EM OV CS CA – G2B emSign Root CS CA – G2 33E8C5A8046D443E8FA5F1AF733188913F1A04B02814B604AC5275ACB201B1C802B2C0F1B4986FB1A1EB595958E07207 Nov 2026 ( cessationOfOperation)RSA-4096 (Native) EM OV CS CA – G2C emSign Root CS CA – G2 7F7C7D863DC9B3541E9D0C4B91237EEBAC91B8EC9853323779EDB393C595FADB29DD4DDB20C47E336F2A021684F27B07 Nov 2026 ( cessationOfOperation)
eMudhra’s exit from public TLS
The severity of the incident led eMudhra to leave the public TLS market. Its remaining issuance under the legacy emSign Root CA – G1 hierarchy, which mainly served a North American university federation, was set for a hard stop before 16 November 2026 at 23:59 UTC. The federation is moving to another publicly trusted CA under existing contractual arrangements.
eMudhra also committed to finishing a full lifecycle inventory of all CA keys and end-entity expiry dates by 30 November 2026, so it can keep CRL and OCSP services running. An independent review of its PKI key-ceremony controls is due by 4 December 2026.
Lessons for PKI engineers, auditors, and root programs
The incident undercuts a common audit shortcut: that a key-generation ceremony in a WebTrust-audited room with a FIPS-validated HSM produces trustworthy output by default. Once a CA introduces host-side orchestration scripts, especially one-off scripts bridging incompatible HSM vendors, those scripts become part of the Trusted Computing Base. If a script disables FIPS mode or extracts key attributes into host memory, the HSM’s security boundary no longer exists.
Three concrete changes follow.
Replace procedural trust with hardware key attestation. Modern HSMs, including Utimaco and Crypto4A modules, support key-origin attestation: the module signs a statement with a hardware-embedded key confirming that a public key was generated onboard with CKA_SENSITIVE = True, CKA_EXTRACTABLE = False (or wrapped only under approved FIPS mechanisms), and CKA_NEVER_EXTRACTABLE = True. If CAs had to submit attestation blobs to CCADB alongside new intermediate certificates, it would have been obvious that the eMudhra keys came from host-side object creation (CKA_LOCAL = False) and not from local generation inside the HSM (CKA_LOCAL = True).
Bind public keys and test for small scalars. Testing an arbitrary P-384 point for a weak discrete logarithm across the full 2^384 space is infeasible. Ceremony tooling and CCADB ingestion pipelines can still keep a lookup filter for small scalars (for example d up to 2^24, using baby-step giant-step or precomputed hash tables). They can also confirm that the public key captured at C_GenerateKeyPair is byte-for-byte identical to the SubjectPublicKeyInfo (SPKI) field in the signed CA certificate.
Never close a cryptographic anomaly at the symptom level. A fresh intermediate CA whose CRL fails verification against its own certificate has not made a configuration typo. It is evidence that the ceremony produced split or mismatched key objects. Tracing the June 2025 CRL failure down to the PKCS#11 object attributes (CKA_LOCAL, CKA_ID, creation timestamps) would have exposed the duplicate keys and the April 2025 script defect more than a year earlier.
It took one unreviewed line of Python during a rushed cross-vendor migration rehearsal to turn 384-bit elliptic curve keys into 8-bit integers and end a public TLS CA operation.









