<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Parag Mali - tag: webauthn</title><description>Posts tagged webauthn.</description><link>https://paragmali.com/</link><language>en-US</language><lastBuildDate>Sun, 07 Jun 2026 04:13:12 GMT</lastBuildDate><atom:link href="https://paragmali.com/tags/webauthn/rss.xml" rel="self" type="application/rss+xml"/><item><title>Direct Anonymous Attestation: The Zero-Knowledge Proof Already in Every TPM</title><link>https://paragmali.com/blog/direct-anonymous-attestation-the-zero-knowledge-proof-alread/</link><guid isPermaLink="true">https://paragmali.com/blog/direct-anonymous-attestation-the-zero-knowledge-proof-alread/</guid><description>TPM 2.0 names a zero-knowledge group-signature primitive in its spec. A billion chips ship it. Almost nobody verifies it. The story of why DAA won every standardization fight and lost every deployment one.</description><pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Direct Anonymous Attestation is the zero-knowledge proof your laptop already has -- and never uses.** Every TPM 2.0 specification since 2014 names a group-signature primitive called `TPM_ALG_ECDAA`, with a normative command pair (`TPM2_Commit`, `TPM2_Sign`) and a mandatory curve (`TPM_ECC_BN_P256`). A TPM with ECDAA enabled can prove &quot;I am a genuine TPM whose endorsement key was certified by a known issuer&quot; without revealing *which* TPM and without an online third party in the verification path. ISO/IEC 20008-2:2013 Mechanism 4 standardizes it. FIDO Alliance bound it to authenticator attestation in 2018. WebAuthn Level 1 registered ECDAA as an attestation type carried inside the `packed` and `tpm` attestation statement formats in March 2019. Three years later, WebAuthn Level 2 removed it entirely. The TCG PC Client Platform TPM Profile made `TPM_ALG_ECDAA` optional in February 2020. Microsoft Azure Attestation, Windows Health Attestation, AWS Nitro, Apple App Attest, and Google Play Integrity all use Privacy-CA-shaped broker flows instead. This article walks the thirty-year cryptographic lineage, the TPM 2.0 normative surface, the FIDO ECDAA failure, and the structural reasons Microsoft chose brokers over math.
&lt;h2&gt;1. A Billion Chips, Zero Verifiers&lt;/h2&gt;
&lt;p&gt;Every TPM 2.0 Library Specification published since 2014 names a zero-knowledge proof of knowledge. The algorithm identifier &lt;code&gt;TPM_ALG_ECDAA&lt;/code&gt; (value &lt;code&gt;0x001A&lt;/code&gt;) appears in Part 2 (Structures). The command pair &lt;code&gt;TPM2_Commit&lt;/code&gt; and &lt;code&gt;TPM2_Sign&lt;/code&gt; appears in Part 3 (Commands). The mathematical construction appears in Part 1 Annex C.5. The mandatory curve is &lt;code&gt;TPM_ECC_BN_P256&lt;/code&gt; (&lt;code&gt;0x0010&lt;/code&gt;), a 256-bit Barreto-Naehrig curve picked specifically because it admits the asymmetric pairings the protocol needs [@tpm-library-spec]. A conforming &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM 2.0 chip&lt;/a&gt; with ECDAA enabled can produce a signature that proves the chip is a genuine TPM whose endorsement key was certified by a known issuer -- without revealing &lt;em&gt;which&lt;/em&gt; TPM, and without an online certificate authority sitting in the verification path. The cryptography is called Direct Anonymous Attestation, and the Wikipedia article notes that the construction is &quot;implemented by both EPID 2.0 and the TPM 2.0 standard&quot; [@wiki-daa].&lt;/p&gt;
&lt;p&gt;Almost nobody uses it.&lt;/p&gt;
&lt;p&gt;Microsoft Azure Attestation does not. Its public architecture document describes a certificate authority that ingests endorsement-key certificates and issues per-key JWTs with a special issuance policy [@azure-attestation]. The Windows Health Attestation Service does not. AWS Nitro Enclaves does not [@aws-nitro-attestation]. Apple App Attest does not [@apple-app-attest]. Google Play Integrity does not [@google-play-integrity]. WebAuthn Level 1 registered ECDAA as an attestation type carried inside the &lt;code&gt;packed&lt;/code&gt; and &lt;code&gt;tpm&lt;/code&gt; formats in March 2019; WebAuthn Level 2 in April 2021 removed it entirely [@webauthn-2]. The TCG PC Client Platform TPM Profile, the document that governs which TPM 2.0 algorithms an OEM must support to ship a Windows-class platform, made &lt;code&gt;TPM_ALG_ECDAA&lt;/code&gt; and &lt;code&gt;TPM_ALG_ECSCHNORR&lt;/code&gt; optional in v1.04 (February 2020) and has carried that designation through v1.07 RC1 (December 2025) [@tcg-ptp]. &lt;a href=&quot;https://paragmali.com/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/&quot; rel=&quot;noopener&quot;&gt;Microsoft Pluton&lt;/a&gt;&apos;s published surface, which enumerates the algorithms the security processor exposes through its TPM 2.0 personality, does not advertise ECDAA at all [@pluton].&lt;/p&gt;
&lt;p&gt;The most thoroughly standardized hardware-anchored group-signature primitive in the history of platform security sits in firmware on a billion-plus machines and runs on almost none.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Direct Anonymous Attestation solves the same problem as a Privacy-CA -- prove the TPM is genuine without disclosing &lt;em&gt;which&lt;/em&gt; TPM -- by moving the trust assumption from operational (the broker promises not to log) to cryptographic (the math forbids the issuer from learning). The interesting question is not whether the cryptography works. It is why an industry that spent thirty years building the math chose, in production, the architecture the math was meant to replace.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This article walks the answer in four moves. Sections 2 through 5 reconstruct the cryptographic lineage: the Privacy-CA architecture DAA was invented against (TPM 1.1, 2003), the group-signature pre-history that made the construction possible (Chaum-van Heyst 1991 through Camenisch-Lysyanskaya 2004), the Brickell-Camenisch-Chen breakthrough at ACM CCS 2004, and the seven-year evolution to the elliptic-curve scheme TPM 2.0 actually ships (Chen-Page-Smart, CARDIS 2010). Sections 6 and 7 walk the normative surfaces: the TPM 2.0 ECDAA command surface and the ISO/IEC 20008-2 / 20009-2 standards. Sections 8 and 9 are case studies in non-deployment: FIDO&apos;s three-year experiment with ECDAA-in-WebAuthn, and Microsoft&apos;s two-decade commitment to broker-mediated attestation. Section 10 names the open problems -- post-quantum DAA, confidential computing, the One-TPM-to-Bind-Them-All fix that has not made it into TCG text. Section 11 closes with a role-keyed practical guide and an FAQ.&lt;/p&gt;

timeline
    title Direct Anonymous Attestation, 1991-2024
    1991 : Chaum-van Heyst (EUROCRYPT)
         : Group signature defined
    1997 : Camenisch-Stadler (CRYPTO)
         : Constant-size signatures
    2000 : ACJT (CRYPTO)
         : Coalition resistance
    2004 : Brickell-Camenisch-Chen (CCS)
         : Boneh-Boyen-Shacham short groupsigs
    2005 : DAA-RSA added to TPM 1.2 rev 94
    2007 : Brickell-Li EPID (WPES)
         : Signature-based revocation
    2008 : Brickell-Chen-Li (TRUST)
         : First pairing DAA
         : CMS asymmetric DAA proposed
    2010 : Chen-Li (IPL)
         : CMS proof flaw
         : Chen-Page-Smart (CARDIS)
         : The scheme TPM 2.0 ships
    2013 : BFGSW (IJIS)
         : User-controlled linkability model
         : ISO/IEC 20008-2 / 20009-2
    2014 : TPM 2.0 Library Spec
         : ECDAA in firmware
    2015 : Smyth-Ryan-Chen
         : Retroactive BCC privacy bug
    2018 : FIDO ECDAA v2.0
    2019 : WebAuthn Level 1
         : ecdaa attestation format
    2020 : TCG PTP v1.04
         : ECDAA made optional
    2021 : WebAuthn Level 2
         : ecdaa format removed
    2024 : CoSNIZK
         : Lattice DAA at 38 kB
&lt;p&gt;To answer the question of why, we have to start where every TPM attestation story does -- with the architecture DAA was invented to replace.&lt;/p&gt;
&lt;h2&gt;2. The Privacy-CA Trap (1999-2003)&lt;/h2&gt;
&lt;p&gt;TPM 1.1, originally published by the Trusted Computing Platform Alliance in 2002 and taken over in April 2003 by the Trusted Computing Group that replaced it [@wiki-tcg], had a privacy story. The story was a broker called the Privacy Certificate Authority. The story had a single load-bearing flaw, and the field spent the next two decades writing papers about it.&lt;/p&gt;
&lt;p&gt;The mechanism, paraphrased from the Wikipedia summary that itself paraphrases the TCG spec, is five steps [@wiki-daa]:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A TPM manufacturer embeds a 2048-bit RSA Endorsement Key (EK) at the time the chip is provisioned, along with a certificate &lt;code&gt;EKCert&lt;/code&gt; signed by the manufacturer [@wiki-tpm].&lt;/li&gt;
&lt;li&gt;The platform generates a fresh Attestation Identity Key (AIK) inside the TPM.&lt;/li&gt;
&lt;li&gt;The platform sends &lt;code&gt;(EKCert, AIKpub, proof-of-binding)&lt;/code&gt; to a Privacy-CA.&lt;/li&gt;
&lt;li&gt;The Privacy-CA validates the EK certificate, confirms the binding proof, and issues &lt;code&gt;Cert(AIKpub)&lt;/code&gt; signed by the CA.&lt;/li&gt;
&lt;li&gt;The platform uses the AIK to sign actual attestations -- platform configuration register quotes, boot logs, key-attestation certificates -- and presents &lt;code&gt;Cert(AIKpub)&lt;/code&gt; to relying parties as proof that the AIK is TPM-resident.&lt;/li&gt;
&lt;/ol&gt;

The Endorsement Key is the long-lived, manufacturer-certified asymmetric key burned into the TPM at provisioning. Its public half is the chip&apos;s permanent cryptographic identity; its certificate, signed by the manufacturer, is the platform&apos;s proof that the chip is a real TPM. The Attestation Identity Key is a short-lived TPM-resident key generated for signing attestation outputs. Because the EK is uniquely identifying, the AIK exists to absorb attestation traffic on the EK&apos;s behalf: the EK certifies the AIK once (or once per Privacy-CA), and the AIK does the signing thereafter [@azure-attestation].

The broker introduced by the TCG in TPM 1.1 to separate the unique-by-design Endorsement Key from the per-attestation Attestation Identity Key. The Privacy-CA verifies the EK certificate, attests that the AIK is bound to a real TPM, and issues a certificate on the AIK that the platform then uses to sign quotes. The privacy property is operational, not cryptographic: the CA promises not to log the linkage between EK and AIK [@wiki-daa].
&lt;p&gt;The architecture has three structural problems, and the Wikipedia summary of the original TPM 1.1 design makes the most uncomfortable one explicit: &quot;privacy requirements may be violated if the privacy CA and verifier collude&quot; [@wiki-daa]. The Privacy-CA &lt;em&gt;can&lt;/em&gt; link AIKs to EKs. It promises not to. That promise is enforceable by audit, by legal contract, by reputation, and by the threat of a regulator finding out. It is not enforceable by mathematics.&lt;/p&gt;
&lt;p&gt;The other two problems are availability and concentration. Wikipedia again, on the TPM 1.1 design: &quot;the privacy CA must take part in every transaction&quot; [@wiki-daa]. Every AIK certification is a synchronous network round-trip to a single CA. The CA is therefore a high-availability target, a high-value attack target, and a high-throughput service obligation for whoever decides to operate one. The FIDO Alliance, fifteen years later, wrote down the operational consequences of that obligation with surprising frankness in its ECDAA Algorithm v2.0 specification [@fido-ecdaa-v2]:&lt;/p&gt;

An alternative approach to &apos;group&apos; keys is the use of individual keys combined with a Privacy-CA [TPMv1-2-Part1]. Translated to FIDO, this approach would require one Privacy-CA interaction for each Uauth key. This means relatively high load and high availability requirements for the Privacy-CA. Additionally the Privacy-CA aggregates sensitive information (i.e. knowing the relying parties the user interacts with). This might make the Privacy-CA an interesting attack target. -- FIDO ECDAA Algorithm v2.0 Implementation Draft, 2018
&lt;p&gt;The FIDO document was written in 2018, but it is operating on a problem that was current in 2003. The Privacy-CA model concentrates the very identifiers it is supposed to anonymize. A regulator with a subpoena, an insider with a database query, or a successful attacker with persistent access can recover the linkage the CA promised to forget. In 2003 the TCG named the missing primitive -- a &lt;em&gt;direct&lt;/em&gt; attestation scheme whose anonymity was guaranteed by math rather than a CA&apos;s promise -- and the cryptographic literature went to work on it.The privacy-advocate criticism of the TPM in the 2003-2005 window came from a small but well-placed group. Ross Anderson at Cambridge had been writing critical surveys of trusted computing since 2002, both in a continuously updated TCPA FAQ [@anderson-tcpa-faq] and in a PODC 2003 paper &quot;Cryptography and Competition Policy -- Issues with Trusted Computing&quot; [@anderson-tcpa-paper]. Seth Schoen and the Electronic Frontier Foundation published a 2003 white paper, &quot;Trusted Computing: Promise and Risk,&quot; on the privacy implications of trusted-computing-class identifiers [@eff-schoen-2003]. European data-protection authorities had begun studying TCPA in the same window [@anderson-tcpa-faq]. The DAA construction was, by 2004, a research community answer to these criticisms more than it was a TCG product requirement.&lt;/p&gt;
&lt;p&gt;The Privacy-CA architecture is still production architecture in 2026. Microsoft Azure Attestation runs a Privacy-CA in everything but name. Its public documentation describes a CA-mediated flow whose five-step shape mirrors the TPM 1.1 Privacy-CA almost line for line: &quot;A certification authority (CA) establishes trust in the TPM either via EKPub or EKCert... The CA issues a certificate with a special issuance policy to denote that the key is now attested as protected by a TPM&quot; [@azure-attestation]. The full verbatim Microsoft Learn quote is reproduced in §9, where it anchors the Windows case study.&lt;/p&gt;
&lt;p&gt;The same pattern repeats across every hyperscaler. AWS Nitro Enclaves issues PKIX certificates rooted in AWS-operated CAs that bind enclave measurements to instance identifiers [@aws-nitro-attestation]. Apple App Attest issues per-app device identifiers from Apple-operated infrastructure [@apple-app-attest]. Google Play Integrity ships integrity verdicts signed by Google-operated infrastructure [@google-play-integrity]. In 2026 the operational descendants of TPM 1.1&apos;s Privacy-CA broker run the production attestation surface of every consumer-grade cloud platform.&lt;/p&gt;

flowchart TD
    M[&quot;TPM manufacturer&quot;] --&amp;gt;|&quot;signs EK with EKCert&quot;| EK[&quot;EK in TPM&quot;]
    EK --&amp;gt; AIK[&quot;TPM generates AIK&quot;]
    AIK --&amp;gt;|&quot;(EKCert, AIKpub, proof)&quot;| CA[&quot;Privacy-CA&quot;]
    CA --&amp;gt;|&quot;issues Cert(AIKpub)&quot;| Plat[&quot;Platform&quot;]
    Plat --&amp;gt;|&quot;AIK signs quote&quot;| V[&quot;Verifier / Relying Party&quot;]
    CA -.-&amp;gt;|&quot;can link AIK to EK&lt;br /&gt;(promises not to)&quot;| AIK
&lt;p&gt;By 2003 the field had a name for the missing primitive: a direct attestation scheme that delivered the Privacy-CA&apos;s anonymity property cryptographically rather than operationally. What followed was an academic lineage that had been quietly building, for a decade and a half, the primitives that lineage required.&lt;/p&gt;
&lt;h2&gt;3. The Pre-History: Group Signatures Before DAA (1991-2003)&lt;/h2&gt;
&lt;p&gt;Direct Anonymous Attestation was invented in 2004. The primitive it was built from was invented in 1991, in a paper that had nothing to do with TPMs.&lt;/p&gt;
&lt;p&gt;David Chaum and Eugene van Heyst presented &quot;Group Signatures&quot; at EUROCRYPT 1991 [@chaum-vh-1991]. The construction was a curiosity: a digital signature scheme in which any one of &lt;code&gt;n&lt;/code&gt; group members could sign on behalf of the group, the verifier could check that &lt;em&gt;some&lt;/em&gt; member of the group signed, and a designated &lt;em&gt;group manager&lt;/em&gt; could, given a signature, recover the identity of the signer. The use case Chaum and van Heyst had in mind was organizational: a company spokesperson signs press releases on behalf of the company; the CEO can, if necessary, recover which spokesperson signed which release.&lt;/p&gt;

A digital signature scheme in which any one of `n` group members can sign on behalf of the group such that (i) verifiers can confirm &quot;some member of the group signed this message&quot; using a single group public key, (ii) verifiers cannot determine which member signed, and (iii) a designated group manager, holding a trapdoor, can *open* any signature to recover the original signer. Chaum and van Heyst introduced the primitive in 1991; the next decade was about making the construction efficient enough to deploy [@wiki-group].
&lt;p&gt;The 1991 construction had a fatal practical property: signature size was linear in the size of the group. A 10,000-member group meant a 10,000-component signature. For a primitive intended to handle organizational use cases at organizational scale, this was a non-starter. The next decade is a sequence of papers, each adding one property to the previous, each addressing the issue that made the previous unfit for deployment.&lt;/p&gt;
&lt;p&gt;Jan Camenisch and Markus Stadler, at CRYPTO 1997, gave the field its first constant-size group signature -- signature length independent of the number of group members, suitable for groups of arbitrary size [@camenisch-stadler-1997]. Their construction relied on a particular kind of zero-knowledge proof of knowledge of a discrete logarithm whose form would, six years later, become the structural template for DAA&apos;s Sign protocol. The CS97 scheme had its own problems -- the security proof made strong assumptions, and the construction was vulnerable to &quot;framing&quot; attacks where a malicious group manager could forge signatures attributable to other members -- but the size barrier was broken.&lt;/p&gt;
&lt;p&gt;Three years later, at CRYPTO 2000, Giuseppe Ateniese, Jan Camenisch, Marc Joye, and Gene Tsudik introduced what the field now calls the ACJT scheme [@acjt-2000]. The Springer abstract is unusually direct about what ACJT contributed: the paper &quot;introduces a new provably secure group signature... proven secure and coalition-resistant under the strong RSA and the decisional Diffie-Hellman assumptions.&quot; The property that made ACJT important was &lt;em&gt;coalition resistance&lt;/em&gt; -- a formal guarantee that no subset of &lt;code&gt;k&lt;/code&gt; group members, no matter how large, could collude to produce a valid signature that did not open to one of them. ACJT&apos;s security proofs were the first in the group-signature literature to treat coalitions as a first-class threat model.Coalition resistance as a property predated ACJT, but coalition resistance as a &lt;em&gt;formal&lt;/em&gt; property -- something proven against an adversary defined in a complexity-theoretic model -- did not. Camenisch and Michels in 1998, and several authors in between, had given coalition-resistance arguments that depended on heuristic assumptions about the underlying hash function or signature scheme [@camenisch-michels-1998]. ACJT 2000 gave the proof under the strong RSA assumption, which by 2000 was a well-understood number-theoretic conjecture that the cryptographic community treated as a load-bearing security primitive.&lt;/p&gt;
&lt;p&gt;ACJT was the construction the DAA designers built on. The reason is in its protocol structure. The ACJT signer holds a &lt;em&gt;signed credential&lt;/em&gt; on a secret membership value &lt;code&gt;f&lt;/code&gt;. Signing a message means producing a non-interactive zero-knowledge proof of knowledge of &lt;code&gt;(f, signature)&lt;/code&gt; satisfying the group manager&apos;s verification equation, bound to the message. The proof is constant-size; the verifier checks it against the group public key and learns only that &lt;em&gt;some&lt;/em&gt; member signed.&lt;/p&gt;
&lt;p&gt;Jan Camenisch and Anna Lysyanskaya, working in parallel, were building the other primitive DAA would need. Their EUROCRYPT 2001 paper introduced what the field now calls CL credentials -- a digital signature scheme with two unusual properties [@cl-2001]. First, a signer can issue a signature on a &lt;em&gt;committed&lt;/em&gt; value &lt;code&gt;Commit(f)&lt;/code&gt; without seeing &lt;code&gt;f&lt;/code&gt; itself, so the holder of &lt;code&gt;f&lt;/code&gt; ends up with a signature on something the signer never learned. Second, a holder of &lt;code&gt;(f, signature)&lt;/code&gt; can prove possession of that pair in zero knowledge, revealing neither &lt;code&gt;f&lt;/code&gt; nor the signature itself.&lt;/p&gt;

A digital signature scheme with two algorithmic protocols on top of the standard sign-and-verify pair. A *blind issuance* protocol lets a signer issue a signature on a value the signer cannot see (the holder commits to a value `f` and proves the commitment well-formed; the signer signs the commitment without learning `f`). A *proof-of-possession* protocol lets a holder of `(f, signature)` prove &quot;I have a CL signature from this signer on some value&quot; without revealing either the value or the signature. CL signatures are the primitive a DAA Issuer uses to issue the long-lived attestation credential the TPM keeps after the Join protocol [@cl-2001] [@cl-2004].
&lt;p&gt;CL signatures gave the field a clean way to issue a member credential without the issuer ever learning the member&apos;s secret -- exactly the property a TPM needs when receiving a long-lived DAA credential from an issuer who, by design, must remain unable to recognize the TPM later. Camenisch and Lysyanskaya&apos;s CRYPTO 2004 paper extended the construction to bilinear pairings [@cl-2004], a generalization that would matter for the elliptic-curve DAA schemes of the next decade.&lt;/p&gt;

flowchart LR
    A[&quot;Chaum-van Heyst 1991&lt;br /&gt;Primitive defined&lt;br /&gt;Linear-size signatures&quot;] --&amp;gt; B[&quot;Camenisch-Stadler 1997&lt;br /&gt;Constant-size signatures&quot;]
    B --&amp;gt; C[&quot;ACJT 2000&lt;br /&gt;Coalition resistance&lt;br /&gt;Strong RSA + DDH&quot;]
    C --&amp;gt; D[&quot;Brickell-Camenisch-Chen 2004&lt;br /&gt;DAA-RSA&quot;]
    A --&amp;gt; E[&quot;Camenisch-Lysyanskaya 2001&lt;br /&gt;Blind issuance&lt;br /&gt;Proof of possession&quot;]
    E --&amp;gt; D
    E --&amp;gt; F[&quot;Camenisch-Lysyanskaya 2004&lt;br /&gt;CL on bilinear pairings&quot;]
    F --&amp;gt; G[&quot;Chen-Page-Smart 2010&lt;br /&gt;EC-DAA&quot;]
&lt;p&gt;A sibling lineage was building in parallel. Dan Boneh, Xavier Boyen, and Hovav Shacham presented &quot;Short Group Signatures&quot; at CRYPTO 2004 [@bbs-2004]. The BBS scheme used bilinear pairings to compress group signatures to a few hundred bytes -- signatures, in the abstract&apos;s words, &quot;approximately the size of a standard RSA signature with the same security.&quot; BBS gave the W3C Verifiable Credentials community a primitive that descendants like BBS+ would later use for selective-disclosure credentials. BBS itself did not become the TPM construction. The DAA designers, working from ACJT and CL, took a different path.&lt;/p&gt;
&lt;p&gt;By 2003 the primitives existed. The TPM community had the use case. The two communities had not yet met. In 2004, three authors at three different industrial labs made the introduction.&lt;/p&gt;
&lt;h2&gt;4. The Breakthrough: DAA-RSA (Brickell-Camenisch-Chen, CCS 2004)&lt;/h2&gt;
&lt;p&gt;The introduction happened at ACM CCS 2004. Ernie Brickell at Intel, Jan Camenisch at IBM Zurich, and Liqun Chen at HP Labs Bristol published &quot;Direct Anonymous Attestation&quot; [@bcc-2004]. The IACR ePrint abstract makes the structural contribution explicit:&lt;/p&gt;

Direct anonymous attestation can be seen as a group signature without the feature that a signature can be opened, i.e., the anonymity is not revocable. Moreover, DAA allows for pseudonyms, i.e., for each signature a user (in agreement with the recipient of the signature) can decide whether or not the signature should be linkable to another signature. DAA furthermore allows for detection of &apos;known&apos; keys: if the DAA secret keys are extracted from a TPM and published, a verifier can detect that a signature was produced using these secret keys. -- BCC 2004 (IACR ePrint 2004/205)
&lt;p&gt;Two design moves did the work, and naming them clearly is the first step in understanding why DAA solved the Privacy-CA problem.&lt;/p&gt;
&lt;p&gt;The first move is a &lt;em&gt;subtraction&lt;/em&gt;. Every prior group-signature scheme -- Chaum-van Heyst, Camenisch-Stadler, ACJT, BBS -- gave a designated group manager the power to &lt;em&gt;open&lt;/em&gt; a signature and recover its signer. For a TPM attestation primitive, the opening capability is undesirable. An issuer who can open is morally a Privacy-CA: it has the linkage information the architecture is supposed to forget. BCC 2004 removes the opening capability entirely. No party can de-anonymize a signature -- not the issuer, not the verifier, not a coalition of either. The IACR ePrint 2004/205 abstract captures the consequence: DAA &quot;can be seen as a group signature without the feature that a signature can be opened, i.e., the anonymity is not revocable&quot; [@bcc-2004]. Once the credential is issued, the issuer has no cryptographic handle left to break the user&apos;s privacy.&lt;/p&gt;

A zero-knowledge attestation primitive in which a TPM holds a long-lived membership credential (the output of a one-time Join protocol with an Issuer) and can subsequently produce signatures that prove &quot;the signing TPM holds a credential certified by this Issuer&quot; without revealing which TPM signed and without an online third party in the verification path. No party -- not the Issuer, not the Verifier, not a coalition of either -- can de-anonymize a DAA signature. The construction first appeared in Brickell-Camenisch-Chen 2004 [@bcc-2004].
&lt;p&gt;The second move is a &lt;em&gt;substitution&lt;/em&gt;. Where prior schemes traced misbehaving signers by manager-controlled opening, DAA introduces a &lt;em&gt;user-controlled&lt;/em&gt; linkability mechanism through what the BCC paper calls a basename-keyed pseudonym. The signing TPM holds a secret membership value &lt;code&gt;f&lt;/code&gt;. The verifier supplies a &lt;em&gt;basename&lt;/em&gt; &lt;code&gt;bsn&lt;/code&gt; (a string the verifier picks per session, per relying party, or per global epoch). The TPM derives a pseudonym&lt;/p&gt;
&lt;p&gt;$$N_V = \zeta^f \pmod \Gamma, \qquad \zeta = H_\Gamma(\text{bsn})$$&lt;/p&gt;
&lt;p&gt;where &lt;code&gt;H_Γ&lt;/code&gt; hashes the basename into a generator of a multiplicative group &lt;code&gt;Γ&lt;/code&gt;. The pseudonym &lt;code&gt;N_V&lt;/code&gt; has two structural properties. If the same verifier reuses the same &lt;code&gt;bsn&lt;/code&gt; across sessions, signatures from the same TPM produce the same &lt;code&gt;N_V&lt;/code&gt;, so the verifier can link them (and blacklist them if needed). If the verifier randomizes &lt;code&gt;bsn&lt;/code&gt; per session, or sets &lt;code&gt;bsn&lt;/code&gt; to the special value &lt;code&gt;⊥&lt;/code&gt; indicating &quot;no linkability,&quot; signatures from the same TPM produce different &lt;code&gt;N_V&lt;/code&gt; values that are indistinguishable from random.&lt;/p&gt;

A DAA property in which the *verifier* chooses a basename `bsn` per session or per relying party. Signatures from the same TPM under the same basename produce the same pseudonym; signatures under different basenames produce pseudonyms indistinguishable from random. The TPM, not a group manager, controls which signatures are linkable to which others. The Bernhard-Fuchsbauer-Ghadafi-Smart-Warinschi 2013 paper gives the canonical formal model [@bfgsw-2013].
&lt;p&gt;Together the subtraction and the substitution define the DAA contract. The Issuer issues a CL signature on the TPM&apos;s secret &lt;code&gt;f&lt;/code&gt; during a one-time Join. The TPM thereafter holds the credential &lt;code&gt;(f, A, e, v)&lt;/code&gt; -- the secret membership value plus the CL signature components. To sign a message &lt;code&gt;m&lt;/code&gt; against a verifier-supplied basename &lt;code&gt;bsn&lt;/code&gt;, the TPM:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Computes the pseudonym &lt;code&gt;N_V = ζ^f mod Γ&lt;/code&gt; where &lt;code&gt;ζ = H_Γ(bsn)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Randomizes the CL signature: picks a fresh &lt;code&gt;w&lt;/code&gt;, computes &lt;code&gt;T_1 = A · S^w mod n&lt;/code&gt; and &lt;code&gt;T_2 = g^e · h^w mod n&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Produces a Fiat-Shamir non-interactive zero-knowledge proof of knowledge of &lt;code&gt;(f, A, e, v, w)&lt;/code&gt; satisfying the CL verification equation&lt;/p&gt;
&lt;p&gt;$$A^e \equiv Z / (R^f \cdot S^{v&apos; + v&apos;&apos;}) \pmod n,$$&lt;/p&gt;
&lt;p&gt;binding the proof to the tuple &lt;code&gt;(m, T_1, T_2, N_V)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A verifier checks the proof against the Issuer&apos;s public key. The verifier learns nothing about &lt;code&gt;f&lt;/code&gt;, nothing about the TPM&apos;s identity, nothing about which CL signature was randomized -- and either gains a linkable pseudonym (if &lt;code&gt;bsn&lt;/code&gt; was reused) or no linkability at all (if &lt;code&gt;bsn&lt;/code&gt; was fresh).&lt;/p&gt;
&lt;p&gt;The architectural picture, set against §2&apos;s Privacy-CA flow, makes the contrast vivid.&lt;/p&gt;

flowchart TD
    I[&quot;Issuer&lt;br /&gt;(holds CL signing key)&quot;]
    T[&quot;TPM&lt;br /&gt;(holds secret f)&quot;]
    V[&quot;Verifier&lt;br /&gt;(holds Issuer pub key)&quot;]
    I -.-&amp;gt;|&quot;one-time Join&lt;br /&gt;CL signature on f&lt;br /&gt;(blind, issuer never sees f)&quot;| T
    T --&amp;gt;|&quot;credential (f, A, e, v)&lt;br /&gt;stored in TPM forever&quot;| T
    T --&amp;gt;|&quot;DAA-Sign(m, bsn)&lt;br /&gt;= randomized credential + NIZK + N_V&quot;| V
    V --&amp;gt;|&quot;Verify against Issuer pub key&lt;br /&gt;(no online interaction)&quot;| V
&lt;p&gt;This is the first aha. The reader entered §3 thinking &quot;anonymity with manager-controlled traceability&quot; was the goal of group signatures. They exit §4 understanding that for TPM attestation the goal is &lt;em&gt;anonymity without any opener&lt;/em&gt; plus &lt;em&gt;user-controlled, per-verifier linkability&lt;/em&gt;. The breakthrough is structurally a subtraction (remove the opener) plus a substitution (per-verifier basename pseudonyms in place of manager-controlled opening). It is not an addition.Eleven years after BCC 2004, Ben Smyth, Mark Ryan, and Liqun Chen ran a formal analysis of the original BCC construction and found a retroactive privacy bug [@smyth-ryan-chen-2015]. The bug allowed certain Issuer-coalition adversaries to link signatures across basenames in ways the original security argument had not anticipated. The bug was fixed in the 2008-2010 redesigns (specifically the BCL 2009 simplified-security-notions paper [@bcl-2009] and the CDL 2016 strong-Diffie-Hellman revisitation). The reader interested in why &quot;we proved this in 2004&quot; is not the same as &quot;this is provably secure in 2026&quot; should read SRC 2015 alongside the original BCC abstract.&lt;/p&gt;
&lt;p&gt;On paper, the BCC 2004 construction solved the Privacy-CA trap. In practice, DAA-RSA was hard to ship. The CL signature in the original scheme used strong RSA moduli at 2048 bits. A single Sign operation took several seconds on the TPM 1.2 hardware of the time. The signature itself was approximately 2.5 kilobytes -- larger than the entire AIK signature output a Privacy-CA-mediated attestation produced. TPM 1.2 shipped DAA-RSA as an optional capability when revision 94 of the spec added it in 2005 [@tpm-library-spec]. Almost no platform integrator turned it on. The cryptography worked. The implementation budget did not.&lt;/p&gt;
&lt;p&gt;The next decade was about making the construction small enough to deploy. The path was anything but straight.&lt;/p&gt;
&lt;h2&gt;5. The Evolution: From RSA-DAA to EC-DAA (2007-2013)&lt;/h2&gt;
&lt;p&gt;Six papers in seven years, two industrial branches, one dead end, one production scheme. Why was the EC-DAA story so much harder than it should have been?&lt;/p&gt;
&lt;p&gt;The honest answer: the entire toolkit of pairing-based cryptography arrived at the same time the TPM industry needed it, and the field discovered in real time that not every choice of pairing was safe. The path from BCC 2004 to the construction the TPM 2.0 spec actually shipped runs through five waypoints, each addressing the problem the previous one created.&lt;/p&gt;
&lt;h3&gt;5.1 Brickell-Li 2007: EPID and signature-based revocation&lt;/h3&gt;
&lt;p&gt;In 2007 Ernie Brickell, now leading Intel&apos;s trusted-computing work, and Jiangtao Li published &quot;Enhanced Privacy ID: A Direct Anonymous Attestation Scheme with Enhanced Revocation Capabilities&quot; at WPES 2007 [@brickell-li-epid-2007]. The journal version appeared at IEEE TDSC in 2012 [@brickell-li-tdsc-2012]. The single feature EPID added was a revocation list called Sig-RL: a list of &lt;em&gt;signatures&lt;/em&gt; the issuer wished to disavow. A verifier, given a signature &lt;code&gt;σ&lt;/code&gt; and a Sig-RL containing entries &lt;code&gt;σ_1, ..., σ_k&lt;/code&gt;, could prove that &lt;code&gt;σ&lt;/code&gt; was not produced by the same TPM as any &lt;code&gt;σ_i&lt;/code&gt; -- without learning the linking information itself.&lt;/p&gt;
&lt;p&gt;EPID became Intel&apos;s production attestation primitive. Wikipedia records the deployment scale: &quot;It has been incorporated in several Intel chipsets since 2008,&quot; and &quot;at RSAC 2016 Intel disclosed that it has shipped over 2.4B EPID keys since 2008&quot; [@wiki-epid]. EPID is what Intel SGX enclaves used to attest, before SGX attestation migrated to the vendor-CA DCAP architecture. EPID is what certain Intel-platform Widevine L1 implementations use to attest content-decryption modules. The Intel EPID SDK (the reference implementation) was eventually marked public-archive on GitHub [@epid-sdk]. The Wikipedia entry notes that the original EPID 2.0 specification was contributed by Intel into ISO/IEC 20008 and 20009 under royalty-free terms [@wiki-epid].&lt;/p&gt;
&lt;p&gt;EPID is not exactly DAA. EPID is a DAA variant with the Sig-RL revocation layer added. The Chen-Page-Smart construction that TPM 2.0 actually ships is closer to BCC 2004 plus an elliptic-curve substrate; EPID 2.0 is closer to BCC 2004 plus EC plus Sig-RL plus Intel&apos;s specific basename and key-management conventions. The two converge at the cryptographic core and diverge at the deployment surface.&lt;/p&gt;
&lt;h3&gt;5.2 Brickell-Chen-Li 2008: the first pairing-based DAA&lt;/h3&gt;
&lt;p&gt;At the TRUST 2008 conference, Ernie Brickell, Liqun Chen, and Jiangtao Li published &quot;A New Direct Anonymous Attestation Scheme from Bilinear Maps&quot; -- the first DAA scheme constructed over bilinear pairings instead of strong RSA [@bcl-2008]. Signature size dropped by an order of magnitude relative to BCC 2004, from roughly 2.5 kilobytes to a few hundred bytes [@bcl-2008]. TPM-side sign time, on hardware that supported elliptic-curve arithmetic, came down from seconds to fractions of a second [@bcl-2008]. The construction used symmetric (Type-1) pairings -- pairings where the two input groups &lt;code&gt;G_1&lt;/code&gt; and &lt;code&gt;G_2&lt;/code&gt; are the same -- which the implementation community would, two or three years later, decide were too inefficient for production TPM hardware.&lt;/p&gt;

A function `e : G_1 × G_2 -&amp;gt; G_T` on three elliptic-curve subgroups satisfying *bilinearity* (for all integers `a, b` and points `P ∈ G_1, Q ∈ G_2`, `e(aP, bQ) = e(P, Q)^(ab)`) and *non-degeneracy*. Type-3 (asymmetric) pairings, in which `G_1 ≠ G_2` and no efficient homomorphism is known between them, are the production pairing for TPM 2.0 ECDAA because they admit faster implementations and tighter security reductions than Type-1 (symmetric) pairings. The Chen-Page-Smart 2010 construction is built on Type-3 pairings over Barreto-Naehrig curves [@cps-2010].
&lt;h3&gt;5.3 Chen-Morrissey-Smart 2008: the asymmetric proposal and its proof flaw&lt;/h3&gt;
&lt;p&gt;Pairing 2008 hosted the next move. Liqun Chen, Paul Morrissey, and Nigel Smart published &quot;Pairings in Trusted Computing&quot; [@cms-pairing-2008], proposing a DAA scheme on asymmetric Type-3 pairings -- the kind that admit Barreto-Naehrig curves and the speed-ups TPM hardware needed. The same authors published a companion ProvSec 2008 paper &quot;On Proofs of Security for DAA Schemes&quot; providing the security argument [@cms-provsec-2008].&lt;/p&gt;
&lt;p&gt;Two years later, in Information Processing Letters, Liqun Chen and Jiangtao Li published &quot;A note on the Chen-Morrissey-Smart Direct Anonymous Attestation scheme&quot; [@chen-li-2010] showing that the CMS asymmetric-pairing construction had a flawed proof. The cryptographic intuition was correct; the proof technique used an assumption that did not hold in the asymmetric-pairing setting the construction relied on.The Chen-Morrissey-Smart episode is, in 2026, one of the most cited proof-flaw stories in pairing-based cryptography precisely because the construction was simple and the flaw was subtle. The mathematical content of the scheme was salvageable. The security argument was not. The lesson the field took away -- a proof in the symmetric-pairing model does not transfer to the asymmetric-pairing model without a separate argument -- has been a load-bearing convention in cryptographic publishing since.&lt;/p&gt;
&lt;h3&gt;5.4 Chen-Page-Smart 2010: the scheme TPM 2.0 actually ships&lt;/h3&gt;
&lt;p&gt;The fix arrived at CARDIS 2010 in Passau in April 2010 [@cardis-book]. Liqun Chen, Dan Page, and Nigel Smart published &quot;On the Design and Implementation of an Efficient DAA Scheme&quot; [@cps-2010] [@cps-2010-eprint], proposing an asymmetric-pairing DAA over Barreto-Naehrig curves with a Sign protocol &lt;em&gt;split&lt;/em&gt; between the TPM and the host. The TPM, in the new design, performed only the cryptographic operations that absolutely required custody of the secret &lt;code&gt;f&lt;/code&gt;: it produced commitment points and computed a Schnorr-style response over those commitments. The host -- a comparatively powerful general-purpose CPU sitting in front of the TPM -- composed the Fiat-Shamir challenge, performed the pairing computations, and assembled the final signature.&lt;/p&gt;
&lt;p&gt;The Chen-Page-Smart construction is the scheme TPM 2.0 actually ships. The Wikipedia DAA article makes the attribution direct, in a sentence that is itself the most-cited single primary-source extract in this article:&lt;/p&gt;

Chen, Page, and Smart proposed a new elliptic curve cryptography scheme using Barreto-Naehrig curves. This scheme is implemented by both EPID 2.0 and the TPM 2.0 standard. -- Wikipedia, *Direct Anonymous Attestation* [@wiki-daa]

A family of pairing-friendly elliptic curves with embedding degree 12, parameterized by an integer `u` to admit Type-3 pairings whose arithmetic is fast enough for resource-constrained devices [@bn-2006]. The curve identifier `TPM_ECC_BN_P256` (`0x0010`) is the specific 256-bit instance the TPM 2.0 Library Specification mandates for ECDAA, picked because of its pairing-friendly structure rather than as a NIST P-256 equivalent.
&lt;p&gt;Six years after CPS 2010, Taechan Kim and Razvan Barbulescu (CRYPTO 2016) published &quot;Extended Tower Number Field Sieve: A New Complexity for the Medium Prime Case,&quot; giving an improved sieve attack against pairing-friendly elliptic curves at the 256-bit BN level. The improvement dropped the practical security of BN-256 from roughly 128 bits to roughly 100 bits [@kim-barbulescu-2016]. The TCG normative text for TPM 2.0 ECDAA did not, as of late 2025, change the mandatory curve in response. This is the kind of cryptographic technical debt that lives quietly in deployed systems for a decade -- specs do not migrate on the same calendar as research moves.&lt;/p&gt;
&lt;h3&gt;5.5 BFGSW 2013 and SRC 2015: the formal closure&lt;/h3&gt;
&lt;p&gt;The cryptographic engineering of EC-DAA was done by 2010. What the field still owed itself was a clean security model: one definition of &quot;secure DAA&quot; that captured the user-controlled-linkability property and the TPM/host split, against which any candidate scheme could be evaluated.&lt;/p&gt;
&lt;p&gt;In 2013 David Bernhard, Georg Fuchsbauer, Essam Ghadafi, Nigel Smart, and Bogdan Warinschi published &quot;Anonymous attestation with user-controlled linkability&quot; in the &lt;em&gt;International Journal of Information Security&lt;/em&gt; [@bfgsw-2013] [@bfgsw-2013-eprint]. The BFGSW paper formalized the user-controlled-linkability property the BCC 2004 abstract had described in prose, introduced a clean separation of &quot;pre-DAA signing&quot; (TPM-side operations) from &quot;DAA signing&quot; (TPM + host composition), and proved the security of a representative construction in the resulting model.&lt;/p&gt;
&lt;p&gt;In 2015, Ben Smyth, Mark Ryan, and Liqun Chen published the retroactive analysis that closed the BCC 2004 privacy bug [@smyth-ryan-chen-2015]. By 2015 the cryptography was, formally, settled.&lt;/p&gt;
&lt;p&gt;In 2016 Jan Camenisch, Manu Drijvers, and Anja Lehmann revisited the construction at TRUST 2016 in &quot;Anonymous Attestation Using the Strong Diffie Hellman Assumption Revisited&quot; [@cdl-2016] [@cdl-2016-eprint], giving a tighter security argument under the q-SDH assumption and providing a fix for a Diffie-Hellman-oracle issue in the TPM 2.0 ECDAA interface that &quot;One TPM to Bind Them All&quot; would document in 2017 [@one-tpm-2017]. The CDL16 scheme is what most modern DAA library code references as the canonical construction.&lt;/p&gt;

flowchart LR
    BCC[&quot;BCC 2004&lt;br /&gt;RSA-DAA&lt;br /&gt;TPM 1.2&quot;] --&amp;gt; BL[&quot;Brickell-Li 2007&lt;br /&gt;EPID + Sig-RL&lt;br /&gt;Intel SGX / Widevine&quot;]
    BCC --&amp;gt; BCL[&quot;BCL 2008&lt;br /&gt;Type-1 pairing DAA&quot;]
    BCL --&amp;gt; CMS[&quot;CMS 2008&lt;br /&gt;Asymmetric pairing&lt;br /&gt;(broken by CL 2010)&quot;]
    BCL --&amp;gt; CPS[&quot;CPS 2010&lt;br /&gt;Type-3 BN-curve DAA&lt;br /&gt;TPM 2.0 ECDAA&quot;]
    CPS --&amp;gt; BFGSW[&quot;BFGSW 2013&lt;br /&gt;Formal user-controlled&lt;br /&gt;linkability model&quot;]
    BFGSW --&amp;gt; CDL[&quot;CDL 2016&lt;br /&gt;q-SDH revisitation&lt;br /&gt;Canonical modern DAA&quot;]
    BCC --&amp;gt; SRC[&quot;SRC 2015&lt;br /&gt;Retroactive BCC&lt;br /&gt;privacy bug&quot;]
&lt;p&gt;By 2013 the cryptography was complete. The standards organizations took the construction and made it official -- in two different specifications, on two parallel tracks.&lt;/p&gt;
&lt;h2&gt;6. The TPM 2.0 ECDAA Surface (2014-Present)&lt;/h2&gt;
&lt;p&gt;If you own a Windows laptop with a TPM 2.0, this section is the part of the chip you have never used. What does the spec actually say?&lt;/p&gt;
&lt;p&gt;The TPM 2.0 Library Specification, the canonical document published by the Trusted Computing Group, is a four-part normative reference [@tpm-library-spec]. Part 1 (Architecture) describes the threat model and the mathematical primitives. Part 2 (Structures) defines the data types every TPM command accepts and returns. Part 3 (Commands) defines the commands themselves. Part 4 (Supporting Routines) gives a reference C implementation. The ECDAA surface lives across all four parts.&lt;/p&gt;

An algorithm identifier defined in TPM 2.0 Library Specification Part 2 and selectable from any `TPMT_SIG_SCHEME` field. A signing key tagged with `TPM_ALG_ECDAA` produces signatures using the Chen-Page-Smart 2010 elliptic-curve DAA construction. The same algorithm identifier appears in any signature-scheme negotiation point in the TPM 2.0 command surface [@tpm-library-spec].

The 256-bit Barreto-Naehrig curve identifier the TPM 2.0 Library Specification mandates for any ECDAA-capable signing key. BN-P256 is *not* NIST P-256: it is a pairing-friendly curve with embedding degree 12 whose group structure admits the Type-3 pairings the DAA verification equation requires. Implementations that confuse the two will produce signatures that verify against the wrong group.

The command pair defined in TPM 2.0 Library Specification Part 3 that implements the Chen-Page-Smart 2010 split-protocol structure. `TPM2_Commit(keyHandle, P1, s2, y2)` returns commitment points `(K, L, E)` plus a `counter`. The host then computes the Fiat-Shamir challenge `c` over the message and the commitment points. `TPM2_Sign(keyHandle, digest, scheme=TPM_ALG_ECDAA, validation)` returns the Schnorr-style response `s = r + c·f mod p`. The host assembles the final signature from the commitment points, the challenge, and the response [@tpm-library-spec].
&lt;p&gt;The protocol split matters. The TPM, in the CPS 2010 construction, holds the secret &lt;code&gt;f&lt;/code&gt; and must perform exactly two cryptographic operations on it: produce a freshly randomized commitment to &lt;code&gt;f&lt;/code&gt; (via &lt;code&gt;TPM2_Commit&lt;/code&gt;), and produce a Schnorr response that proves knowledge of &lt;code&gt;f&lt;/code&gt; modulo the verifier&apos;s challenge (via &lt;code&gt;TPM2_Sign&lt;/code&gt;). Everything else -- the pairing computations, the curve arithmetic in &lt;code&gt;G_T&lt;/code&gt;, the Fiat-Shamir hash, the final signature assembly -- happens on the host CPU. This is the &lt;em&gt;only&lt;/em&gt; reason the construction is practical on a TPM. A monolithic Sign that did pairing arithmetic inside the chip would be unshippable; the split offloads the expensive operations onto silicon that has them for free.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The most common implementer mistake when working with TPM 2.0 ECDAA for the first time is to reuse the NIST P-256 ECDSA code path with the curve identifier swapped. The two curves share a bit length and a hash function and otherwise nothing. BN-P256 has a pairing-friendly group structure with embedding degree 12; NIST P-256 does not admit efficient pairings at all. Signatures produced by ECDSA over NIST P-256 will not verify against an ECDAA verifier expecting BN-P256, and the converse is true. The pairing requirement is what forces the BN curve choice; treat BN-P256 as a separate primitive with a separate code path.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Join protocol -- the one-time exchange between the Issuer and the TPM that produces the long-lived credential -- piggybacks on a TPM 2.0 command pair already present in every Windows attestation flow: &lt;code&gt;TPM2_MakeCredential&lt;/code&gt; and &lt;code&gt;TPM2_ActivateCredential&lt;/code&gt; [@tpm-library-spec]. The Issuer wraps the DAA credential under an encryption key derived from the TPM&apos;s Endorsement Key, ensuring that only the legitimate TPM (the one that holds the EK private key) can decrypt the credential and bind it to its internal &lt;code&gt;f&lt;/code&gt;.The choice of &lt;code&gt;TPM2_ActivateCredential&lt;/code&gt; as the Join anchor is convenient. The same primitive that TPM 2.0 attestation-key certification flows use for AIK-binding gets reused for DAA-credential binding. An OEM that supports &lt;code&gt;TPM2_ActivateCredential&lt;/code&gt; for ordinary AIK enrollment already has 80% of the firmware path the Join protocol needs. The difference is in what the Issuer ships back -- a per-TPM AIK certificate in the AIK case, an Issuer-randomized CL credential in the DAA case.&lt;/p&gt;
&lt;p&gt;Part 1 Annex C.5 contains the informative mathematical description -- the actual ECDAA verification equation, the basename-pseudonym derivation, the proof-of-knowledge template. Part 3 contains the normative command definitions. An implementer who reads only the Part 3 command definitions without reading Annex C.5 will have correct byte-buffer-level semantics and no idea what the protocol is computing; an implementer who reads only Annex C.5 without the normative command definitions will have correct math and the wrong API.&lt;/p&gt;
&lt;p&gt;The implementation surface, gathered into one place:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Artifact&lt;/th&gt;
&lt;th&gt;Identifier / location&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Algorithm selector&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TPM_ALG_ECDAA = 0x001A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TPM 2.0 Library Specification Part 2 [@tpm-library-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mandatory curve&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TPM_ECC_BN_P256 = 0x0010&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Part 2 [@tpm-library-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First-round command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TPM2_Commit(keyHandle, P1, s2, y2) -&amp;gt; (K, L, E, counter)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Part 3 [@tpm-library-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Second-round command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TPM2_Sign(keyHandle, digest, scheme=TPM_ALG_ECDAA, validation) -&amp;gt; signature&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Part 3 [@tpm-library-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Join anchor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TPM2_MakeCredential&lt;/code&gt; / &lt;code&gt;TPM2_ActivateCredential&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Part 3 [@tpm-library-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Math description&lt;/td&gt;
&lt;td&gt;Part 1 Annex C.5 (informative)&lt;/td&gt;
&lt;td&gt;Part 1 [@tpm-library-spec]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optionality status&lt;/td&gt;
&lt;td&gt;Optional since PTP v1.04 (Feb 2020); carried through v1.07 RC1 (Dec 2025)&lt;/td&gt;
&lt;td&gt;TCG PC Client Platform TPM Profile changelog [@tcg-ptp]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

sequenceDiagram
    participant V as Verifier
    participant H as Host (CPU)
    participant T as TPM
    V-&amp;gt;&amp;gt;H: send basename bsn
    H-&amp;gt;&amp;gt;T: TPM2_Commit(keyHandle, P1, s2, y2)
    T--&amp;gt;&amp;gt;H: (K, L, E, counter)
    H-&amp;gt;&amp;gt;H: compute c = H(K, L, E, message, bsn)
    H-&amp;gt;&amp;gt;T: TPM2_Sign(keyHandle, digest=c, scheme=ECDAA)
    T--&amp;gt;&amp;gt;H: response s = r + c*f mod p
    H-&amp;gt;&amp;gt;H: assemble signature (K, L, E, c, s)
    H-&amp;gt;&amp;gt;V: ECDAA signature
    V-&amp;gt;&amp;gt;V: verify pairing equation
&lt;p&gt;The TCG published the TPM 2.0 Library Specification in 2014. From 2014 through early 2020, the PC Client Platform TPM Profile -- the document that says &quot;to ship a TPM 2.0 in a PC-class device, these algorithms must be present&quot; -- listed &lt;code&gt;TPM_ALG_ECDAA&lt;/code&gt; as mandatory-if-the-platform-supports-elliptic-curve-cryptography. In v1.04 (released February 2020) the TCG PTP working group made a quiet but consequential change. The changelog records the line verbatim: &quot;Made TPM_ALG_ECDAA and TPM_ALG_ECSCHNORR optional.&quot; The same designation has carried through v1.06 RC1 (January 2025) and v1.07 RC1 (December 2025) [@tcg-ptp]. After February 2020, an OEM can ship a Windows-class TPM 2.0 platform that does not implement ECDAA at all and remain conformant.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Trusted Computing Group&apos;s resource pages (&lt;code&gt;trustedcomputinggroup.org/resource/tpm-library-specification/&lt;/code&gt; and &lt;code&gt;trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/&lt;/code&gt;) reject non-browser User-Agents at the HTTP layer. This is a long-standing anti-bot policy. Citations in this article to the TPM 2.0 Library Specification and to the PC Client Platform TPM Profile point to the canonical URLs but are flagged in the verified-source registry as UNVERIFIED_FETCH; the verbatim changelog text was extracted under primary-source rules during the Stage 0a focus-premise audit and is the audit-of-record for the optionality claim. The downstream accuracy and fact-check stages of this pipeline carry the same caveat forward.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Pluton question is the second hedge. Microsoft Pluton is the security processor Microsoft has been shipping in successive Windows-class platforms since AMD&apos;s Ryzen 6000 in 2022, in AMD Ryzen 7040 (Phoenix) in 2023, in Qualcomm Snapdragon X Elite in 2024, and in Intel Core Ultra (Meteor Lake, December 2023; Lunar Lake, September 2024) and successive Intel Core Ultra generations. Pluton exposes a TPM 2.0 personality. The Microsoft Learn documentation page enumerates the cryptographic algorithms the processor exposes and the platform-security primitives it implements [@pluton].&lt;/p&gt;
&lt;p&gt;The page contains zero occurrences of &lt;code&gt;ECDAA&lt;/code&gt; or &lt;code&gt;TPM_ALG_ECDAA&lt;/code&gt;. The honest framing here is &lt;em&gt;not&lt;/em&gt; &quot;Pluton does not implement ECDAA&quot; -- the documentation neither confirms nor denies it -- but &quot;Pluton&apos;s published surface does not advertise ECDAA.&quot; That is the hedged statement this article carries from its opening to its FAQ.&lt;/p&gt;
&lt;p&gt;The runnable demonstration below is &lt;em&gt;educational&lt;/em&gt; -- Microsoft ships no &lt;code&gt;BCryptDirectAnonymousAttestation&lt;/code&gt;, no &lt;code&gt;NCryptDaaSign&lt;/code&gt;, no Windows API at all that exposes ECDAA from a user-mode application. The code shows the &lt;em&gt;logic&lt;/em&gt; an admin or platform engineer would follow when probing a TPM&apos;s reported algorithm set, not a working call against any shipping Windows API.&lt;/p&gt;
&lt;p&gt;{`
// Logic only. Microsoft ships no Windows API that surfaces TPM_ALG_ECDAA.
// In practice an admin would parse the output of Get-TpmEndorsementKeyInfo
// or use a vendor-specific tool to inspect the TPM&apos;s algorithm capability table.
const TPM_ALG_ECDAA = 0x001A;
const TPM_ECC_BN_P256 = 0x0010;&lt;/p&gt;
&lt;p&gt;function probeECDAA(tpmAlgList, tpmEccCurveList) {
  const hasECDAA = tpmAlgList.includes(TPM_ALG_ECDAA);
  const hasBN256 = tpmEccCurveList.includes(TPM_ECC_BN_P256);
  if (!hasECDAA) return &apos;no ECDAA: chip omits algorithm 0x001A&apos;;
  if (!hasBN256) return &apos;ECDAA without BN-P256: nominally compliant, practically unusable&apos;;
  return &apos;ECDAA + BN-P256 present (Join still requires Issuer infrastructure)&apos;;
}&lt;/p&gt;
&lt;p&gt;// Example: a Pluton-class chip whose published surface does not advertise ECDAA.
const plutonLike = [0x0001 /* RSA &lt;em&gt;/, 0x0008 /&lt;/em&gt; SHA-256 &lt;em&gt;/, 0x0023 /&lt;/em&gt; ECDSA &lt;em&gt;/];
console.log(probeECDAA(plutonLike, [0x0003 /&lt;/em&gt; NIST P-256 */]));
// -&amp;gt; &quot;no ECDAA: chip omits algorithm 0x001A&quot;&lt;/p&gt;
&lt;p&gt;// Example: a discrete Infineon SLB9670 TPM 2.0 (vendor docs list ECDAA + BN-P256).
const discreteTpm = [0x0001, 0x0008, 0x0023, TPM_ALG_ECDAA];
console.log(probeECDAA(discreteTpm, [0x0003, TPM_ECC_BN_P256]));
// -&amp;gt; &quot;ECDAA + BN-P256 present (Join still requires Issuer infrastructure)&quot;
`}&lt;/p&gt;
&lt;p&gt;The spec was written. The chips shipped. The TCG was satisfied. So why does no one verify ECDAA signatures?&lt;/p&gt;
&lt;h2&gt;7. The Standards Bridge: ISO/IEC 20008 and 20009&lt;/h2&gt;
&lt;p&gt;There is a difference between a TCG specification section number and an ISO/IEC mechanism identifier. The difference is the price of admission to a Common Criteria protection profile and to most government procurement contracts.&lt;/p&gt;
&lt;p&gt;ISO/IEC 20008 is the international-standards anchor for anonymous digital signatures. It comes in three parts. Part 1 (&quot;General&quot;) sets the framework and terminology [@iso-20008-1]. Part 2 (&quot;Mechanisms using a group public key&quot;) catalogues the specific anonymous-signature schemes the international community has standardized -- and Mechanism 4 is the EPID-derived elliptic-curve DAA construction that aligns with the TPM 2.0 ECDAA surface [@iso-20008-2]. Part 3 (&quot;Mechanisms using multiple public keys&quot;) catalogues a different family of schemes that is not the focus of this article.&lt;/p&gt;

The international-standards series titled &quot;Information technology -- Security techniques -- Anonymous digital signatures.&quot; Part 1 (general framework) and Part 2 (mechanisms using a group public key) were both published in 2013. Mechanism 4 in Part 2 standardizes EPID-derived elliptic-curve DAA. ISO/IEC 20008 is the bibliographic anchor cited by Common Criteria protection profiles, FIPS 140-3 module-validation evidence, and government procurement specifications that need to reference a *named, internationally agreed* anonymous-signature mechanism rather than a vendor-specific construction [@iso-20008-2].
&lt;p&gt;A note on the title. Earlier drafts of this article carried the title of ISO/IEC 20008-2 as &quot;anonymous signatures with message recovery.&quot; That phrasing belongs to a different standard, ISO/IEC 9796. The verified ISO catalogue title for 20008-2 is, verbatim, &quot;Information technology -- Security techniques -- Anonymous digital signatures -- Part 2: Mechanisms using a group public key&quot; [@iso-20008-2].&lt;/p&gt;
&lt;p&gt;ISO/IEC 20009 is the companion standard for authentication. Where 20008 standardizes signatures, 20009 standardizes the challenge-response protocols that wrap signatures into entity-authentication exchanges. Part 2 (&quot;Mechanisms based on signatures using a group public key&quot;) is where TPM-style attestation lives in ISO terminology [@iso-20009-2]. A FIDO authenticator or a TPM-backed Kerberos client that performs an attested authentication is, in ISO-speak, executing a 20009-2 mechanism that wraps a 20008-2 signature.&lt;/p&gt;

Intel held patents on the EPID construction. In contributing the EPID 2.0 algorithm to ISO/IEC 20008 and 20009, Intel made the underlying intellectual property available under royalty-free (RAND-Z) terms. The Wikipedia EPID article records the contribution and notes that EPID &quot;complies with international standards ISO/IEC 20008 / 20009&quot; [@wiki-epid]. The licensing structure mattered: it is what made the construction acceptable to the FIDO Alliance, to the TCG for the TPM 2.0 ECDAA surface, and to the European procurement community whose conformance regimes treat royalty-bearing cryptographic primitives differently from royalty-free ones. Exact licensing-event dates are not directly indexed in publicly fetchable Intel materials; this paragraph is inference-grade reconstruction from the Wikipedia citation chain.
&lt;p&gt;The procurement reason ISO standardization mattered is structural. A Common Criteria Protection Profile cannot, in the general case, reference a TCG specification section number. It can reference an ISO mechanism identifier. The Federal Information Processing Standards 140-3 evidence package for a cryptographic module must, in many cases, demonstrate that the cryptographic primitives the module implements are members of an internationally recognized standard family. The European Cyber Resilience Act, drafted in 2024 and applicable in stages from 2027 onward, treats compliance with a recognized international standard as one of the routes to a presumption of conformity. ISO/IEC 20008-2 Mechanism 4 is the door TPM 2.0 ECDAA walks through to be admissible in those regimes.&lt;/p&gt;
&lt;p&gt;Standardization was complete by 2014. Cryptographic primitive: CPS 2010. Security model: BFGSW 2013. ISO mechanism: 20008-2 Mechanism 4. TPM normative surface: &lt;code&gt;TPM_ALG_ECDAA&lt;/code&gt;, &lt;code&gt;TPM_ECC_BN_P256&lt;/code&gt;, &lt;code&gt;TPM2_Commit&lt;/code&gt;, &lt;code&gt;TPM2_Sign&lt;/code&gt;. Every box was checked. The next question -- the one the standardization community could not answer on its own -- was whether anyone would write a verifier.&lt;/p&gt;
&lt;h2&gt;8. The FIDO Bet That Failed (2017-2021)&lt;/h2&gt;
&lt;p&gt;In 2018, the FIDO Alliance bet that ECDAA was the missing privacy story for &lt;a href=&quot;https://paragmali.com/blog/webauthn-and-passkeys-on-windows-from-ctap-to-the-credential/&quot; rel=&quot;noopener&quot;&gt;WebAuthn&lt;/a&gt;. Three years later, W3C took the bet off the table.&lt;/p&gt;
&lt;p&gt;The bet was not casual. FIDO had a real problem. WebAuthn authenticators -- the YubiKey hardware tokens, the &lt;a href=&quot;https://paragmali.com/blog/your-face-is-not-your-password-inside-windows-hellos-hardwar/&quot; rel=&quot;noopener&quot;&gt;Microsoft Hello&lt;/a&gt; platform authenticators, the Touch ID and Face ID modules -- need to attest that they are genuine hardware. The attestation surface FIDO Alliance had inherited from U2F was &lt;em&gt;Basic Attestation&lt;/em&gt;: every authenticator in a manufacturing batch of 100,000 or more units shared one attestation key [@fido-cert-levels], so a relying party that checked the attestation learned only &quot;this is one of 100,000-plus YubiKey 5 NFCs,&quot; not which device specifically. The cohort-size rule gave Basic Attestation a workable operational privacy property. But there was an architectural fork in the road for an organization that wanted &lt;em&gt;cryptographic&lt;/em&gt; attestation privacy without the cohort-key fan-out problem.&lt;/p&gt;
&lt;p&gt;FIDO Alliance picked the cryptographic fork. The FIDO ECDAA Algorithm v2.0 specification was published as an Implementation Draft on February 27, 2018 [@fido-ecdaa-v2]. The document is the most carefully written specification of the DAA contract from a deployment perspective; the editor was Rolf Lindemann at Nok Nok Labs. The motivation section we have already quoted in §2 names the Privacy-CA failure mode in unusually direct terms.&lt;/p&gt;
&lt;p&gt;WebAuthn Level 1 reached W3C Recommendation status on March 4, 2019 [@webauthn-1]. Section 8 defined six attestation statement formats by &lt;code&gt;fmt&lt;/code&gt; identifier: &lt;code&gt;packed&lt;/code&gt;, &lt;code&gt;tpm&lt;/code&gt;, &lt;code&gt;android-key&lt;/code&gt;, &lt;code&gt;android-safetynet&lt;/code&gt;, &lt;code&gt;fido-u2f&lt;/code&gt;, and &lt;code&gt;none&lt;/code&gt;. ECDAA was not a separate format; the WebAuthn-1 §6.4.4 attestation-type list (Basic, Self, AttCA, ECDAA, None) carried ECDAA as an attestation &lt;em&gt;type&lt;/em&gt; supported &lt;em&gt;within&lt;/em&gt; the &lt;code&gt;packed&lt;/code&gt; and &lt;code&gt;tpm&lt;/code&gt; formats. An independent verification of the live HTML returns 63 occurrences of the string &quot;ecdaa&quot; in the Level 1 Recommendation -- ECDAA had its own type identifier, its own signing logic, and its own verification procedure embedded inside the two formats that mattered [@webauthn-1].&lt;/p&gt;
&lt;p&gt;WebAuthn Level 2 reached W3C Recommendation status on April 8, 2021 [@webauthn-2] [@wiki-webauthn]. The same independent verification against the live Level 2 HTML returns zero occurrences of &quot;ecdaa.&quot; Every reference -- the type identifier, the signing rules, the verifier procedure that the &lt;code&gt;packed&lt;/code&gt; and &lt;code&gt;tpm&lt;/code&gt; formats invoked -- was removed in a single editorial pass. The Yubico migration guide for its Java WebAuthn server library makes the vendor view explicit: &quot;This attestation type was removed from WebAuthn Level 2. ECDAA support has not been implemented in this library, so this value could in practice never be returned&quot; [@yubico-migration].&lt;/p&gt;
&lt;p&gt;Why did the bet fail? Four reasons, each visible from the public record.&lt;/p&gt;
&lt;p&gt;First, no major browser ever shipped an ECDAA verifier inside the &lt;code&gt;packed&lt;/code&gt; or &lt;code&gt;tpm&lt;/code&gt; statement format paths. Chromium, Firefox, and Safari implemented WebAuthn with &lt;code&gt;packed&lt;/code&gt;, &lt;code&gt;tpm&lt;/code&gt;, &lt;code&gt;fido-u2f&lt;/code&gt;, and &lt;code&gt;android-safetynet&lt;/code&gt; attestation, but the ECDAA branch within &lt;code&gt;packed&lt;/code&gt; and &lt;code&gt;tpm&lt;/code&gt; stayed unimplemented. The Yubico migration guide quoted above is the vendor-side confirmation of an industry-wide outcome [@yubico-migration].&lt;/p&gt;
&lt;p&gt;Second, the largest authenticator vendors picked the Basic and AttCA attestation types instead of ECDAA. YubiKey 5 series ships with the &lt;code&gt;packed&lt;/code&gt; format using a Basic Attestation key shared across a 100,000+-unit cohort [@yubico-yk5-attestation] [@fido-cert-levels]. Feitian, Google Titan, and other major FIDO2 authenticator vendors ship Basic Attestation under the same FIDO certification-policy cohort rule [@fido-cert-levels]. Microsoft Hello platform authenticators on Windows TPM-backed devices use the &lt;code&gt;tpm&lt;/code&gt; attestation statement format with an AIK that a Microsoft-operated CA certifies -- the AttCA type, functionally a Privacy-CA [@ms-hello-doc] [@azure-attestation]. The vendor base from which a WebAuthn relying party would actually see an attestation statement, in practice, never produced an ECDAA one.&lt;/p&gt;
&lt;p&gt;Third, FIDO ECDAA v2.0 never advanced beyond Implementation Draft. The URL slug for the document literally encodes its status: &lt;code&gt;fido-v2.0-id-20180227&lt;/code&gt; -- the &lt;code&gt;id-20180227&lt;/code&gt; segment names the format &lt;code&gt;&amp;lt;status&amp;gt;-&amp;lt;date&amp;gt;&lt;/code&gt;, and &quot;id&quot; is &quot;Implementation Draft.&quot; It never reached &quot;Proposed Standard&quot; or &quot;Approved Specification&quot; in FIDO&apos;s process [@fido-ecdaa-v2]. A relying party making a long-term technology bet on an attestation statement format that has never advanced past Implementation Draft has no reason to invest in a verifier library.&lt;/p&gt;
&lt;p&gt;Fourth, FIDO Basic Attestation&apos;s cohort-size rule (100,000+ authenticators per attestation group key, enforced contractually on the certified-authenticator side) gave the underlying privacy concern an &lt;em&gt;operational&lt;/em&gt; answer [@fido-cert-levels]. A WebAuthn relying party that sees a Basic Attestation signature learns &quot;this is one of at least 100,000 identical authenticators&quot; -- a cohort large enough that the relying party cannot, in practice, recover individual identifying information from the attestation alone. The cohort rule does not require pairing arithmetic, does not need a verifier library, and works with the same &lt;code&gt;packed&lt;/code&gt; and &lt;code&gt;tpm&lt;/code&gt; attestation formats every relying party already implements.&lt;/p&gt;

The FIDO Basic Attestation cohort minimum is a particularly clean example of how operational rules can compete directly with cryptographic primitives. The privacy property a relying party wants -- &quot;I cannot single out this device from its peers&quot; -- can be obtained by (a) hardware-anchored zero-knowledge proofs that mathematically forbid linkage (cryptographic DAA), or (b) a contractual obligation that every batch of attestation keys covers at least 100,000 devices (FIDO Basic Attestation) [@fido-cert-levels]. The cryptographic answer is mathematically stronger. The operational answer is dramatically easier to debug, audit, and revoke. Production has consistently chosen the latter.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; ECDAA shipped chips. It never shipped verifiers. Standardization is necessary but not sufficient for production deployment: production cryptography needs verifier libraries, and verifier libraries are &lt;em&gt;social&lt;/em&gt; phenomena -- they emerge from relying-party demand, SDK presence, incident-response tooling, and library-maintainer attention, none of which the cryptography itself produces. Cryptographic excellence does not predict deployment; library availability does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the second aha. The reader entered §8 believing that a standardized cryptographic primitive backed by FIDO, three browser vendors, and a publicly authored attestation format would deploy. They exit understanding that ECDAA standardized everything except the social machinery -- and the social machinery is where production attestation actually lives.&lt;/p&gt;
&lt;p&gt;If a consortium with FIDO&apos;s privacy mandate, browser-vendor coalition, and authenticator-vendor base could not generate enough relying-party momentum to keep ECDAA in WebAuthn, what chance did the silent option in TPM 2.0 ever have? The answer requires walking the Microsoft attestation stack.&lt;/p&gt;
&lt;h2&gt;9. Windows: A Billion Chips, Zero Production Use (2014-Present)&lt;/h2&gt;
&lt;p&gt;Microsoft has shipped over a billion Windows TPM 2.0 platforms [@ms-pluton-blog] [@wiki-windows-11]. Microsoft has not shipped a Windows DAA API. The two facts are not in tension. They are the story.&lt;/p&gt;
&lt;p&gt;The shipping Windows attestation stack is documented and unambiguous. Microsoft Azure Attestation is the production-grade attestation service. Its public architecture document describes the protocol in five paragraphs that read, line for line, like TPM 1.1 from 2003 [@azure-attestation]:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Every TPM ships with a unique asymmetric key called the endorsement key (EK)... A certification authority (CA) establishes trust in the TPM either via EKPub or EKCert... A device proves to the CA that the key for which the certificate is being requested is cryptographically bound to the EKPub and that the TPM owns the EKPriv. The CA issues a certificate with a special issuance policy to denote that the key is now attested as protected by a TPM.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The architecture is the Privacy-CA architecture. The Microsoft-operated CA inputs an EK certificate and outputs a JWT that downstream Microsoft services (Defender for Endpoint device-compliance, Intune Conditional Access policies, Entra ID conditional access, customer-defined Azure Attestation policies) consume. The Windows Health Attestation Service, the older Microsoft surface that predated Azure Attestation, used the same broker model with different deployment shape. The Defender for Endpoint device-compliance flow that gates Conditional Access on attested TPM boot state consumes WHAS or Azure Attestation JWTs, not raw DAA quotes.&lt;/p&gt;
&lt;p&gt;Microsoft Pluton&apos;s published surface tells the same story from the silicon side. Pluton is the security processor Microsoft has been shipping in successive Windows-class platforms. Its Microsoft Learn page enumerates the cryptographic algorithms and platform-security primitives the processor exposes [@pluton]. The page is exhaustive about TPM 2.0 baseline algorithms (RSA-2048, ECDSA over NIST P-256, SHA-2 family). It contains zero occurrences of &lt;code&gt;ECDAA&lt;/code&gt;, of &lt;code&gt;TPM_ALG_ECDAA&lt;/code&gt;, or of any phrase like &quot;anonymous attestation.&quot; Insufficient public evidence to assert that Pluton implements ECDAA; sufficient evidence to assert that Pluton&apos;s published surface does not advertise it.&lt;/p&gt;
&lt;p&gt;The Windows API surface gap is the third piece of evidence. The TPM Base Services (&lt;code&gt;Tbsi_*&lt;/code&gt; functions in &lt;code&gt;Tbs.dll&lt;/code&gt;) expose &lt;code&gt;TPM2_Commit&lt;/code&gt; and &lt;code&gt;TPM2_Sign&lt;/code&gt; to user-mode applications -- but only as raw command-buffer submissions. There is no &lt;code&gt;BCryptDirectAnonymousAttestation&lt;/code&gt;. There is no &lt;code&gt;NCryptDaaSign&lt;/code&gt;. There is no Web Authentication API wrapper that surfaces ECDAA.&lt;/p&gt;
&lt;p&gt;The TPM Platform Crypto Provider (PCP) that Windows ships as part of the Cryptography Next Generation (CNG) framework supports RSA and ECDSA TPM-backed keys but does not surface ECDAA. The TSS.MSR open-source TPM stack from Microsoft Research does not ship a DAA wrapper. An application developer who wants ECDAA on Windows today writes raw &lt;code&gt;TBS_SUBMIT_COMMAND&lt;/code&gt; byte buffers against the documented TPM 2.0 command numbering, manages the Join protocol against an Issuer of their own provisioning, and verifies the resulting signatures with a library they wrote themselves or pulled from a research-grade implementation.&lt;/p&gt;
&lt;p&gt;The interesting question is why. Microsoft has never published a &quot;we considered DAA and chose the broker model because...&quot; statement. Treating that absence honestly, the four reasons below are &lt;em&gt;inferences&lt;/em&gt; from observable architecture decisions, not Microsoft-engineer-published rationales. The article labels them as such.&lt;/p&gt;
&lt;p&gt;First, &lt;em&gt;operational simplicity&lt;/em&gt;. A hosted CA with audit logs is more debuggable than a per-relying-party DAA verifier with no central audit point. When a device fails attestation in production, the on-call engineer reading the Azure Attestation logs can answer &quot;why did this device fail?&quot; in seconds; the same question against a DAA verifier requires reasoning about pairing arithmetic, basename derivation, and Issuer-credential validity. Engineering organizations choose architectures whose failure modes they can debug.&lt;/p&gt;
&lt;p&gt;Second, &lt;em&gt;revocation economics&lt;/em&gt;. A Privacy-CA can revoke an AIK by removing one certificate from its issued-certificate store. Revoking a DAA credential, in the construction TPM 2.0 ships, requires either EPID-style signature-based revocation -- which the TPM 2.0 ECDAA scheme does not provide -- or a private-key list distributed to every relying party (extracting the private key from the misbehaving TPM is presumed possible after compromise, and verifiers then check that the signing key is not on the list). The CA&apos;s revocation primitive is a database delete. The DAA revocation primitive is an SDK rollout to every consumer of the verification library.&lt;/p&gt;
&lt;p&gt;Third, &lt;em&gt;the relying-party stack&lt;/em&gt;. DAA verifier libraries are not present in any mainstream cloud platform&apos;s SDK. The .NET CryptoNG surface, the Java JCA, the Python &lt;code&gt;cryptography&lt;/code&gt; library, the Go &lt;code&gt;crypto&lt;/code&gt; standard library, the Rust &lt;code&gt;ring&lt;/code&gt; and &lt;code&gt;dalek&lt;/code&gt; ecosystems -- none ship an ECDAA verifier. X.509 / PKI verifier libraries, by contrast, are everywhere. A relying party building on top of mainstream SDKs gets PKI verification for free; gets DAA verification for nothing close to free.&lt;/p&gt;
&lt;p&gt;Fourth, &lt;em&gt;the Windows API surface gap is itself the obstacle&lt;/em&gt;. Adding a &lt;code&gt;BCrypt&lt;/code&gt; / &lt;code&gt;NCrypt&lt;/code&gt; / WebAuthn DAA wrapper to Windows requires designing a new key-storage provider contract, defining the JOIN-protocol service interface, writing the conformance test suite, drafting the security documentation, and rolling it out on the Windows release calendar. That is a project the size of Windows Hello&apos;s. Microsoft has not, to public knowledge, prioritized it.&lt;/p&gt;

flowchart TD
    HW[&quot;TPM 2.0 hardware&lt;br /&gt;(discrete or Pluton)&lt;br /&gt;TPM_ALG_ECDAA may be present&quot;]
    TBS[&quot;TPM Base Services&lt;br /&gt;(Tbs.dll, kernel)&quot;]
    PCP[&quot;TPM Platform Crypto Provider&lt;br /&gt;(BCrypt / NCrypt)&lt;br /&gt;RSA and ECDSA only&quot;]
    AZ[&quot;Microsoft Azure Attestation&lt;br /&gt;(Privacy-CA architecture)&quot;]
    WHAS[&quot;Windows Health Attestation Service&lt;br /&gt;(Privacy-CA architecture)&quot;]
    RP[&quot;Intune / Defender / Entra&lt;br /&gt;Conditional Access enforcement&quot;]
    HW --&amp;gt; TBS
    TBS --&amp;gt; PCP
    PCP --&amp;gt; AZ
    PCP --&amp;gt; WHAS
    AZ --&amp;gt; RP
    WHAS --&amp;gt; RP
    HW -.-&amp;gt;|&quot;ECDAA path exists&lt;br /&gt;no Windows API&quot;| HW
&lt;p&gt;The deeper reading -- the one that makes Microsoft&apos;s choice look structural rather than accidental -- starts from a comparison the four inferences above already pointed toward.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Privacy-CA brokers and DAA solve the same problem -- prove the TPM is genuine without disclosing which TPM. They differ only in &lt;em&gt;where the trust assumption lives&lt;/em&gt;. The broker treats privacy as an operational policy (the CA promises not to log, audit logs prove it kept the promise, regulators enforce the promise). DAA treats privacy as a mathematical property (the issuer cannot link, period, no audit needed). The architecture that wins in production is the one with the &lt;em&gt;smaller operational surface&lt;/em&gt;, not the one with the &lt;em&gt;better cryptographic guarantee&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the third aha. The reader entered §9 believing that cryptographic superiority should eventually win in production, and that Microsoft&apos;s non-adoption of DAA must be an oversight or a missed product opportunity. They exit understanding that the deployment-economics asymmetry is structural: a broker-mediated attestation flow reduces, end-to-end, to standard X.509 plumbing every cloud SDK already ships, while a DAA-mediated flow requires bespoke verifier libraries, bespoke revocation infrastructure, bespoke debugging tooling, and bespoke incident-response runbooks. Cloud-platform organizations have spent the last ten years building world-class operational machinery for X.509 attestation. They will not throw it away for a cryptographic property no compliance regime currently demands.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The four reasons compound. The broker model gives a single audit point, a database-delete revocation primitive, an SDK that ships in every major language, and a debugging story the on-call engineer can walk through at 3 a.m. DAA gives mathematical privacy and requires every one of those operational properties to be rebuilt from scratch. Cloud platforms have, repeatedly and consistently, picked the architecture whose operational properties are easier to ship -- not because they do not understand the cryptographic alternative, but because the cryptographic alternative would require them to discard the operational machinery they already have. This is the structural reason DAA has stayed in firmware on a billion chips and out of production attestation flows on all of them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the broker calculus is this durable, is there any future world in which DAA wins? Two, and both are research-stage with decade-long horizons.&lt;/p&gt;
&lt;h2&gt;10. Theoretical Limits and Open Problems&lt;/h2&gt;
&lt;p&gt;What can DAA never do? Where does the next decade of research go? Three open problems organize the active research community in 2026.&lt;/p&gt;
&lt;h3&gt;10.1 What DAA cannot do&lt;/h3&gt;
&lt;p&gt;The first honest statement is the negative one. A correctly implemented DAA scheme does not prevent a &lt;em&gt;compromised TPM&lt;/em&gt; from signing for the cohort it belongs to. The EK certificate attestation must be honest at manufacture time; if a TPM&apos;s secret membership value &lt;code&gt;f&lt;/code&gt; leaks to an attacker (through fault injection, through side-channel extraction, through a firmware backdoor), the attacker can produce ECDAA signatures indistinguishable from legitimate ones until the TPM&apos;s &lt;code&gt;f&lt;/code&gt; is added to a revocation list. The same constraint applies to every group-signature scheme.&lt;/p&gt;
&lt;p&gt;A second hard limit is per-basename linkability. The user-controlled-linkability property gives a TPM the choice of linkable or unlinkable signing -- but once a verifier has seen the pseudonym &lt;code&gt;N_V = ζ^f mod Γ&lt;/code&gt; for a particular &lt;code&gt;(TPM, bsn)&lt;/code&gt; pair, the linkage for that basename is permanent. A misbehaving TPM that wants its history with a particular relying party forgotten cannot, by signing under a different basename, retroactively unlink past sessions.&lt;/p&gt;
&lt;p&gt;A third limit is rogue-key scalability. The TPM 2.0 ECDAA scheme detects rogue keys by checking each signature against a list of compromised-&lt;code&gt;f&lt;/code&gt; values the verifier maintains. For small lists this is cheap. For very large lists -- imagine a deployment where 1% of the chip population leaks &lt;code&gt;f&lt;/code&gt; to attackers and the verifier must check every signature against ten million revoked values -- the constant factor matters. EPID&apos;s Sig-RL mechanism uses signature-based revocation that scales better; the TPM 2.0 ECDAA scheme does not include it.&lt;/p&gt;
&lt;h3&gt;10.2 The One-TPM-to-Bind-Them-All fix&lt;/h3&gt;
&lt;p&gt;In 2017 a team consisting of Jan Camenisch, Liqun Chen, Manu Drijvers, Anja Lehmann, David Novick, and Rainer Urian published &quot;One TPM to Bind Them All: Fixing TPM 2.0 for Provably Secure Anonymous Attestation&quot; at IEEE S&amp;amp;P 2017 [@one-tpm-2017]. The paper demonstrated a Diffie-Hellman-oracle attack against the TPM 2.0 ECDAA interface as shipped: a malicious host could query the TPM in a way that gave the host a DH-oracle relative to the TPM&apos;s secret &lt;code&gt;f&lt;/code&gt;, effectively breaking the unlinkability property. The proposed fix had been published the previous year by Camenisch, Drijvers, and Lehmann at TRUST 2016 [@cdl-2016] [@cdl-2016-eprint]; library implementations of DAA published from 2017 onward incorporate the fix.The CDL16 fix is library-level, not silicon-level. The TPM 2.0 ECDAA command surface in the chip remains as shipped; the &lt;em&gt;software&lt;/em&gt; that drives it must use the corrected protocol sequence to avoid presenting the host-controlled DH oracle. As of late 2025, the TCG normative TPM 2.0 Library Specification text has not been amended to require the corrected sequence. Implementations of DAA on top of TPM 2.0 -- the FIDO ECDAA v2.0 library, the Camenisch-Drijvers-Lehmann reference code, modern academic ECDAA implementations -- follow CDL16. Implementations written against the bare TPM 2.0 Library Specification without reading CDL16 are vulnerable.&lt;/p&gt;
&lt;h3&gt;10.3 Post-quantum DAA&lt;/h3&gt;
&lt;p&gt;Shor&apos;s algorithm is fatal to DAA. Every classical DAA construction -- BCC 2004, BCL 2008, CPS 2010, CDL 2016 -- relies on the hardness of discrete logarithms in elliptic-curve groups, the hardness of strong-RSA factoring, or both. A cryptographically relevant quantum computer breaks all of them. &lt;a href=&quot;https://paragmali.com/blog/post-quantum-cryptography-on-windows-the-thirty-year-migrati/&quot; rel=&quot;noopener&quot;&gt;Post-quantum&lt;/a&gt; DAA is therefore active research, with no production deployment as of 2026. Three candidate families are being actively explored:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Symmetric-primitive DAA.&lt;/strong&gt; Dan Boneh, Saba Eskandarian, and Ben Fisch presented &quot;Post-quantum EPID Signatures from Symmetric Primitives&quot; at CT-RSA 2019 [@bef-2019], building a post-quantum group signature from one-way functions and Merkle trees. The construction has classical post-quantum security guarantees but pays a steep size cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lattice-based DAA.&lt;/strong&gt; Rachid El Bansarkhani and Ali El Kaafarani published &quot;Direct Anonymous Attestation from Lattices&quot; as IACR ePrint 2017/1022 [@bk-2017-eprint], the earliest such proposal in the literature. The state-of-the-art lattice DAA construction is the 2024 Collaborative Segregated NIZK (&quot;CoSNIZK&quot;) work by Liqun Chen, Patrick Hough, and Nada El Kassem [@cosnizk-2024], achieving signatures of approximately 38 kilobytes -- an order of magnitude smaller than the earliest lattice proposals but still two orders of magnitude larger than CPS 2010 ECDAA.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hash-based DAA.&lt;/strong&gt; Liqun Chen, Changyu Dong, Nada El Kassem, Christopher Newton, and Yalan Wang published &quot;Hash-Based Direct Anonymous Attestation&quot; at PQCrypto 2023 [@hashdaa-2023], building DAA from SPHINCS+-style stateless hash-based signatures. Size and speed remain unfavorable for TPM 2.0 firmware budgets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The blocker for any of these reaching production TPM firmware is not academic. The TPM 2.0 normative algorithm set does not include lattice primitives. A post-quantum DAA in TPM 2.0 would require introducing &lt;code&gt;TPM_ALG_DILITHIUM&lt;/code&gt;, &lt;code&gt;TPM_ALG_FALCON&lt;/code&gt;, &lt;code&gt;TPM_ALG_KYBER&lt;/code&gt;, or some equivalent into the spec, mandating support in the PC Client Platform TPM Profile, and rolling out across the OEM TPM-vendor base. That is, at minimum, a three-to-five-year standards effort that the TCG has not, as of late 2025, publicly committed to. CoSNIZK at 38 kilobytes is also two to three times larger than the largest signature any deployed TPM 2.0 firmware budgets for; the TPM-side compute time at quantum-safe parameter sets is currently measured in seconds rather than tens of milliseconds.&lt;/p&gt;
&lt;h3&gt;10.4 DAA for confidential computing&lt;/h3&gt;
&lt;p&gt;The other future-world thread is confidential computing -- the family of CPU-anchored isolated-execution primitives (Intel SGX, Intel TDX, AMD SEV-SNP, ARM CCA) that need their own attestation surfaces. Intel SGX attestation initially used EPID and has since migrated to DCAP, a vendor-CA broker similar in shape to Microsoft Azure Attestation. AMD SEV-SNP and Intel TDX use vendor-rooted PKI from the start.&lt;/p&gt;
&lt;p&gt;Whether DAA-style group-signature schemes are appropriate for VM-level attestation -- where cohorts are small (per-region TDX hosts in a given hyperscaler datacenter), where the verifier is often a small set of well-known cloud-platform endpoints, and where traffic-analysis leakage between confidential VMs and Privacy-CA-like services is itself a threat -- is an open architectural question. The 2026 default is &quot;vendor-CA broker&quot;; the academic community continues to argue that cryptographic DAA would be a better match for the threat model. Production has not, so far, agreed.&lt;/p&gt;
&lt;p&gt;A note on Java Card DAA prototypes. A small number of academic implementations of DAA on Java Card secure elements appeared between 2014 and 2017 -- Camenisch and others published smartcard-class implementations as proofs of concept. None reached production deployment. The reasons appear to be the same operational-economics asymmetry that limits TPM 2.0 ECDAA adoption: Java Card environments lack the relying-party verifier libraries that would consume the output. This is inference; no Java Card vendor has, to public knowledge, published a &quot;we evaluated DAA and chose not to ship it&quot; statement.&lt;/p&gt;
&lt;p&gt;These are the open problems for researchers. What about the rest of us, on Monday morning?&lt;/p&gt;
&lt;h2&gt;11. Practical Guide and Frequently Asked Questions&lt;/h2&gt;
&lt;p&gt;Five roles, one Monday morning. Where does this leave you?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For a Windows platform engineer.&lt;/strong&gt; The minimum viable Windows DAA API surface is approximately a &lt;code&gt;BCryptCreateDaaContext&lt;/code&gt;, &lt;code&gt;BCryptDaaJoin&lt;/code&gt;, &lt;code&gt;BCryptDaaSign&lt;/code&gt;, and &lt;code&gt;BCryptDaaVerify&lt;/code&gt; set, plus an &lt;code&gt;NCryptDaaKeyHandle&lt;/code&gt; for key-storage-provider lifecycle, plus a Web Authentication API surface that consumes ECDAA attestation. Shipping all of that costs a Hello-sized engineering investment. If Pluton&apos;s published surface ever advertises ECDAA, an OEM-side integration becomes possible. Today the answer is that DAA is not available through any supported Windows API.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For an attestation-provider product engineer.&lt;/strong&gt; Pick a Privacy-CA broker architecture for production. The comparison table below makes the trade-offs explicit. Cryptographic DAA does not pay for the architectural switch unless the relying-party privacy threat is specifically the broker itself -- a threat model that, in 2026, no shipping production attestation product publicly assumes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For a FIDO authenticator vendor.&lt;/strong&gt; ECDAA attestation is not a viable production choice in 2026. The path to it becoming viable runs through verifier libraries in Chromium, Firefox, and Safari; relying-party SDK support across Auth0, Okta, Microsoft Entra, and Google Identity Platform; and a non-deprecated WebAuthn Level N specification that re-adds the format. None of those preconditions are visibly in progress.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For an academic zero-knowledge-proof researcher.&lt;/strong&gt; Four open problems map onto production needs: post-quantum DAA at TPM-firmware-shippable signature sizes (the current state-of-the-art at 38 kilobytes is too large), threshold-issuer DAA (no single party can issue a credential), confidential-computing DAA (for small-cohort VM attestation), and IoT DAA (for milliwatt-class energy budgets). Each is publishable; none yet has a deployment path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For a privacy-tech advocate or policymaker.&lt;/strong&gt; The framing that helps Microsoft, Google, and AWS engineering teams hear the request is &quot;the broker can be compelled by a subpoena; the math cannot.&quot; The framing that does not help is &quot;your cryptography is worse than the academic alternative.&quot; The first is a threat-model conversation that engineering organizations can engage with; the second is a technology conversation they have already had and decided.&lt;/p&gt;
&lt;h3&gt;Comparison: four production architectures for attested privacy&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Privacy-CA broker&lt;/th&gt;
&lt;th&gt;TPM 2.0 ECDAA&lt;/th&gt;
&lt;th&gt;EPID 2.0&lt;/th&gt;
&lt;th&gt;Vendor-CA (Apple, AWS Nitro, Google)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Trust assumption&lt;/td&gt;
&lt;td&gt;Operational (CA promises not to log)&lt;/td&gt;
&lt;td&gt;Cryptographic (issuer cannot link)&lt;/td&gt;
&lt;td&gt;Cryptographic (issuer cannot link)&lt;/td&gt;
&lt;td&gt;Operational (vendor CA promises not to log)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anonymity from verifier?&lt;/td&gt;
&lt;td&gt;If CA does not log&lt;/td&gt;
&lt;td&gt;Yes (per-basename)&lt;/td&gt;
&lt;td&gt;Yes (per-basename)&lt;/td&gt;
&lt;td&gt;If vendor does not log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TPM-side sign time&lt;/td&gt;
&lt;td&gt;Milliseconds (AIK signing)&lt;/td&gt;
&lt;td&gt;Tens of milliseconds&lt;/td&gt;
&lt;td&gt;Tens of milliseconds&lt;/td&gt;
&lt;td&gt;N/A (signing on vendor silicon)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signature size&lt;/td&gt;
&lt;td&gt;Hundreds of bytes (AIK)&lt;/td&gt;
&lt;td&gt;Hundreds of bytes&lt;/td&gt;
&lt;td&gt;Hundreds of bytes&lt;/td&gt;
&lt;td&gt;Hundreds of bytes (X.509 over signed JWT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revocation&lt;/td&gt;
&lt;td&gt;CA database delete&lt;/td&gt;
&lt;td&gt;Private-key list (TPM 2.0)&lt;/td&gt;
&lt;td&gt;Sig-RL (signature-based)&lt;/td&gt;
&lt;td&gt;Vendor revocation list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementer complexity&lt;/td&gt;
&lt;td&gt;Low (X.509 PKI everywhere)&lt;/td&gt;
&lt;td&gt;High (BN-P256 pairing libraries)&lt;/td&gt;
&lt;td&gt;High (vendor SDK required)&lt;/td&gt;
&lt;td&gt;Low (vendor SDK ships it)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standardization&lt;/td&gt;
&lt;td&gt;TCG (2003)&lt;/td&gt;
&lt;td&gt;TPM 2.0 + ISO 20008-2 Mech 4&lt;/td&gt;
&lt;td&gt;ISO 20008-2 Mech 4&lt;/td&gt;
&lt;td&gt;Vendor-proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best suited for&lt;/td&gt;
&lt;td&gt;Cloud attestation at hyperscaler scale&lt;/td&gt;
&lt;td&gt;Hardware-anchored attestation where broker is the threat&lt;/td&gt;
&lt;td&gt;Intel-deployed enclave attestation&lt;/td&gt;
&lt;td&gt;Vendor-platform attestation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026 deployment scale&lt;/td&gt;
&lt;td&gt;Billions of attestations per day&lt;/td&gt;
&lt;td&gt;Essentially zero production verifiers&lt;/td&gt;
&lt;td&gt;2.4B+ EPID keys per RSAC 2016&lt;/td&gt;
&lt;td&gt;Billions of attestations per day&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The &quot;essentially zero production verifiers&quot; entry for TPM 2.0 ECDAA is the deployment story this article exists to explain. The cryptography is in firmware on hundreds of millions of devices; the verifier side, in 2026, is research-grade libraries and the FIDO ECDAA-Verify reference code. No production cloud-platform SDK ships an ECDAA verifier.&lt;/p&gt;

Four things, in order. First, Pluton&apos;s published surface advertises `TPM_ALG_ECDAA` and an Issuer key-management story (a Microsoft-operated DAA Issuer for Windows devices, with documented enrollment and revocation flows). Second, a Cryptography Next Generation API surface (`BCryptDaaSign`, `NCryptDaaKey*`) that exposes the TPM2_Commit / TPM2_Sign sequence behind a single managed-language call. Third, a Web Authentication API extension that surfaces ECDAA attestation as a first-class statement format the same way the `tpm` format is today. Fourth, an Azure Attestation policy mode that consumes ECDAA signatures and produces JWT outputs downstream Microsoft services already understand. None of these are technically blocking; all four require a multi-year roadmap commitment that, as of late 2025, Microsoft has not publicly made. This is a thought experiment about technical feasibility, not a forecast about Microsoft strategy.
&lt;p&gt;The companion piece to this article is the &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;TPM in Windows&lt;/a&gt; article, which walks the broader TPM 2.0 command surface ECDAA sits inside.&lt;/p&gt;


It depends on what the laptop ships. The TPM 2.0 Library Specification names `TPM_ALG_ECDAA`. The TCG PC Client Platform TPM Profile made the algorithm optional in v1.04 (February 2020) and has carried that designation through v1.07 RC1 (December 2025), so a conformant Windows-class platform is allowed to omit it. Many discrete TPM 2.0 modules (Infineon, STMicroelectronics, Nuvoton) do implement the algorithm; Microsoft Pluton&apos;s published documentation does not advertise it. The honest answer is &quot;look at your specific TPM vendor&apos;s algorithm capability table&quot; -- and that even if your TPM does support the algorithm, Windows ships no API to use it [@tpm-library-spec] [@tcg-ptp] [@pluton] [@wiki-daa].


Microsoft has not published an explicit rationale. Four inferable reasons are visible from the architecture: (1) operational simplicity -- a hosted CA is easier to debug than a per-relying-party DAA verifier; (2) revocation economics -- a CA can revoke an AIK by deleting a certificate, while DAA revocation requires a private-key list distributed to every verifier; (3) a missing relying-party verifier-library stack; (4) no Windows API surface for ECDAA. All four are inferences. The shipped architecture is the Privacy-CA-shaped flow documented at the Microsoft Learn attestation page [@azure-attestation].


WebAuthn Level 1 (March 2019) registered ECDAA as an attestation *type* (Basic, Self, AttCA, ECDAA, None) carried inside the `packed` and `tpm` attestation statement formats. The Level 1 specification text contains 63 references to &quot;ecdaa.&quot; WebAuthn Level 2 (April 2021) removed the type entirely; an independent grep of the Level 2 Recommendation HTML returns zero occurrences of &quot;ecdaa.&quot; The Yubico migration guide for its WebAuthn server library states verbatim that &quot;this attestation type was removed from WebAuthn Level 2&quot; and that &quot;ECDAA support has not been implemented in this library.&quot; The format has not been resurrected as of 2026 [@webauthn-1] [@webauthn-2] [@yubico-migration].


EPID is a DAA variant with one cryptographic addition: signature-based revocation (Sig-RL), which lets a verifier prove that a candidate signature was not produced by the same signer as any signature on a revocation list. The TPM 2.0 ECDAA scheme is the Chen-Page-Smart 2010 construction; EPID 2.0 is essentially the same construction with Sig-RL added. Intel positions EPID separately because of its production deployment (2.4 billion-plus keys shipped per Intel&apos;s RSAC 2016 disclosure, used for SGX attestation, Widevine, and several Intel chipsets), its specific licensing structure (royalty-free under Intel&apos;s contribution to ISO/IEC 20008 / 20009), and its open-source SDK that Intel maintained until archiving in 2023 [@brickell-li-epid-2007] [@brickell-li-tdsc-2012] [@wiki-epid] [@epid-sdk].


Active research, no production deployment as of 2026. The leading constructions are lattice-based (CoSNIZK 2024 at approximately 38 kilobytes per signature [@cosnizk-2024]), hash-based (the 2023 PQCrypto paper from SPHINCS+ [@hashdaa-2023]), and symmetric-primitive-based (Boneh-Eskandarian-Fisch CT-RSA 2019 [@bef-2019]). The barriers to shipping any of them in a TPM are fundamental: TPM 2.0 firmware does not implement lattice primitives, signature sizes at 30+ kilobytes are incompatible with current attestation-latency budgets, and no relying-party verifier library exists. A post-quantum DAA TPM is a 2030s project at the earliest.


No. The Stage 0a focus-premise audit of this article demoted that framing as not supported by evidence. The accurate claim is &quot;standardized in the TPM 2.0 Library Specification (2014); optional in the TCG PC Client Platform TPM Profile since February 2020; present on many discrete TPMs (vendor documentation confirms); absent from Microsoft Pluton&apos;s published algorithm surface; supported by no Windows API.&quot; That hedged statement is the one the article carries from its first 200 words through to this FAQ [@tpm-library-spec] [@tcg-ptp] [@pluton].

&lt;p&gt;The cryptography is finished. The standardization is finished. The hardware is in the field. What is missing is the social machinery -- the verifier libraries, the SDK presence, the operational tooling, the incident-response runbooks, the regulator demand -- that turns cryptography into deployment. Direct Anonymous Attestation is the cleanest example in platform security of a primitive that won every standardization fight and lost every deployment one. The lesson is not that the cryptography is wrong. The lesson is that cryptography is necessary but never sufficient. Production systems are social systems whose mathematical components, however elegant, must compete with operational alternatives whose properties are easier to ship.&lt;/p&gt;
&lt;p&gt;The companion pieces in this series are &lt;a href=&quot;https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/&quot; rel=&quot;noopener&quot;&gt;The TPM in Windows&lt;/a&gt; (the cryptographic primitive plumbing TPM 2.0 ECDAA sits inside) and the Microsoft Pluton continuation article (Pluton&apos;s published capability surface and the negative claim this article rests its §9 hedge on). The Measured Boot piece -- forthcoming -- walks the data that a hypothetical DAA quote would attest. If those three articles arrive together, the picture of Windows attestation as a &lt;em&gt;system&lt;/em&gt; rather than a primitive becomes complete.&lt;/p&gt;
</content:encoded><category>tpm</category><category>attestation</category><category>zero-knowledge-proofs</category><category>cryptography</category><category>windows-security</category><category>pluton</category><category>webauthn</category><category>fido</category><author>noreply@paragmali.com (Parag Mali)</author></item><item><title>WebAuthn and Passkeys on Windows: From CTAP to the Credential Provider Model</title><link>https://paragmali.com/blog/webauthn-and-passkeys-on-windows-from-ctap-to-the-credential/</link><guid isPermaLink="true">https://paragmali.com/blog/webauthn-and-passkeys-on-windows-from-ctap-to-the-credential/</guid><description>The know/have/are taxonomy collapses against modern phishing kits. Passkeys, WebAuthn Level 3, CTAP 2.x, and Windows 11 24H2 third-party providers score against the criteria that actually matter -- and recovery is the load-bearing column.</description><pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate><content:encoded>
**Password plus push-notification MFA is no longer a strong authenticator.** 2024-2026 adversary-in-the-middle phishing kits walk straight through it. WebAuthn and passkeys are strong -- but only if you score them against the right axes (phishing resistance, verifier-compromise resistance, replay/relay resistance, step-up, recovery), not the inherited know/have/are taxonomy. This article walks the five-axis criteria framework, the WebAuthn Level 3 plus CTAP 2.x protocol layer, and the Windows-specific stack: `webauthn.dll`, Windows Hello as the user-verification gesture, the Windows 11 24H2 third-party passkey provider plug-in model, hybrid transport from a phone, and the seven attestation conveyance formats. The thesis the article lands on: every passkey deployment in production is exactly as strong as the weakest path back into the account, and that path is universally weaker than the authentication ceremony itself.
&lt;h2&gt;1. Two factors, no security&lt;/h2&gt;
&lt;p&gt;A junior engineer at a mid-size firm types her Microsoft 365 credentials into what looks exactly like the real &lt;code&gt;login.microsoftonline&lt;/code&gt; page, approves the push notification on her phone, and an hour later the security team is reading her inbox -- because the attacker was, too. The kit is Tycoon 2FA, the technique is reverse-proxy adversary-in-the-middle, and the marketing claim that &quot;password plus MFA is two factors&quot; just lost to a commodity off-the-shelf service. The same class of phishing-as-a-service kit (Evilginx, Caffeine, EvilProxy, Tycoon 2FA) is the dominant phishing toolset in 2024-2026; the kit sits between the user and the real Microsoft login page, captures the credentials and the post-MFA session cookie in flight, and hands a live session to the attacker [@sekoia-tycoon-2fa].&lt;/p&gt;
&lt;p&gt;Replay the exact same attack against a colleague whose only authenticator is a WebAuthn passkey. The kit serves the look-alike page; the page hands the browser a WebAuthn &lt;code&gt;PublicKeyCredentialRequestOptions&lt;/code&gt; blob with a fresh challenge. The browser builds &lt;code&gt;clientDataJSON&lt;/code&gt; with &lt;code&gt;type: &quot;webauthn.get&quot;&lt;/code&gt;, the actual origin the user is on (the look-alike domain &lt;code&gt;login-microsoft0nline.example&lt;/code&gt;, protocol scheme included), and the challenge. The authenticator computes the RP-ID hash from that origin, looks up its stored credential, and finds nothing -- it never registered a passkey for that domain. There is no signature to relay. The kit gets bytes that the real Microsoft server will reject on the first verification step. Microsoft&apos;s own documentation puts it bluntly: passkeys &quot;use origin-bound public key cryptography, ensuring credentials can&apos;t be replayed or shared with malicious actors&quot; [@ms-entra-passwordless].&lt;/p&gt;
&lt;p&gt;The know/have/are taxonomy ranks these two ceremonies as the same. Password plus push is &quot;something you know&quot; plus &quot;something you have,&quot; and so is password plus a passkey on a YubiKey. The taxonomy predicts that both ceremonies are roughly twice as strong as one factor alone. The phishing kit demolishes one and bounces off the other. &lt;em&gt;The taxonomy is wrong.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The right question is not &quot;how many factors did the user produce?&quot; It is &quot;what does the attacker have to defeat?&quot; The know/have/are buckets group authenticators by what the user &lt;em&gt;feels&lt;/em&gt; they are producing. The criteria framework groups them by &lt;em&gt;what an attacker has to defeat&lt;/em&gt;. Only the second taxonomy predicts the outcome of a real-world attack. The phishing kit walks through password plus push because nothing in that ceremony binds the user&apos;s secret to a specific origin. It bounces off the passkey because the passkey signs over the origin the browser is actually on, and no amount of reverse proxying changes that string.&lt;/p&gt;
&lt;p&gt;If the taxonomy is wrong, what is the right one? That is the question §2 answers.&lt;/p&gt;
&lt;h2&gt;2. The criteria framework: five axes that actually predict outcomes&lt;/h2&gt;
&lt;p&gt;The replacement for know/have/are is a five-row table. The rows are &lt;em&gt;what an attacker has to defeat&lt;/em&gt;, not &lt;em&gt;what the user thinks they are producing&lt;/em&gt;. The spine of the table is taken from NIST SP 800-63-4 (final, August 2025) [@sp80063-4-final], NIST SP 800-63B-4 [@sp80063b4-html], the FIDO Alliance Authenticator Certification Levels [@fido-certification-levels], and the IETF channel-binding lineage that runs from RFC 5056 (Williams, November 2007) [@rfc5056] through RFC 9266 (Whited, July 2022) [@rfc9266].&lt;/p&gt;

An authenticator whose protocol prevents a relying party impersonator (an adversary-in-the-middle) from inducing the authenticator to release a usable credential value. NIST SP 800-63B-4 formalises the requirement as *verifier-impersonation resistance*. The practitioner formulation, courtesy of Yubico, is verbatim: an authenticator is phishing-resistant if it binds its output to a communication channel or a verifier name [@yubico-nist-guidance].
&lt;h3&gt;Axis 1: phishing resistance&lt;/h3&gt;
&lt;p&gt;The criterion: can a look-alike domain induce the user (or the user&apos;s authenticator) to release a credential value that the look-alike then replays to the real verifier? Password plus any unbound second factor (SMS-OTP, TOTP, push) fails the criterion -- the kit just forwards every value the user produces. WebAuthn passes it by construction: the authenticator signs over &lt;code&gt;clientDataJSON&lt;/code&gt;, which the &lt;em&gt;browser&lt;/em&gt; fills in with the actual origin the user is on, and the signature is computed jointly over a hash of the RP identifier derived from that origin. The RP refuses any signature whose RP-ID hash does not match the registered &lt;code&gt;rpId&lt;/code&gt;.&lt;/p&gt;

The mechanism by which WebAuthn enforces phishing resistance: the browser writes the user&apos;s actual origin into `clientDataJSON.origin`, the authenticator signs over the SHA-256 hash of the canonical RP identifier (`rpIdHash` in `authenticatorData`), and the relying party validates that `rpIdHash` matches the RP identifier under which the credential was registered. The cryptography is trivial. The value is in the binding.
&lt;p&gt;Microsoft&apos;s Entra documentation states the criterion verbatim: passkeys &quot;provide verifier impersonation resistance, which ensures an authenticator only releases secrets to the Relying Party (RP) the passkey was registered with and not an attacker pretending to be that RP&quot; [@ms-entra-passwordless].&lt;/p&gt;
&lt;h3&gt;Axis 2: verifier-compromise resistance&lt;/h3&gt;
&lt;p&gt;The criterion: if the relying party&apos;s authentication database is exfiltrated, can the attacker use the stolen material to log in? Passwords fail this criterion in the worst possible way -- a salted hash is replayable after offline cracking, and a billion-row password dump is the standard primary input to credential stuffing. The public-key model passes the criterion definitionally. The relying party stores only the credential&apos;s public key; no signature is ever made by the relying party. Even a complete database leak gives the attacker zero authenticators.&lt;/p&gt;
&lt;p&gt;This criterion is older than WebAuthn by half a century. Morris and Thompson&apos;s 1979 password paper made the verifier-compromise case for hashing passwords on a multi-user UNIX system [@morris-thompson-1979]; the WebAuthn move is the realisation that even bcrypt&apos;d password databases lose this criterion eventually, because the work factor that protects them today is one Moore&apos;s-law decade away from being trivial.&lt;/p&gt;
&lt;h3&gt;Axis 3: replay and relay resistance&lt;/h3&gt;
&lt;p&gt;The criterion: can an attacker who observes one successful authentication replay it later, or relay it to a different verifier? OTP-based ceremonies (HOTP [@rfc4226], TOTP [@rfc6238]) provide partial replay resistance via a per-instance counter or timestamp, but they offer almost no relay resistance: the AitM kit forwards the OTP through its proxy within the OTP&apos;s validity window.&lt;/p&gt;
&lt;p&gt;WebAuthn passes the criterion with three layered mechanisms. The first is a fresh challenge issued by the RP for every ceremony, which the authenticator signs over. The second is a per-credential signature counter included in &lt;code&gt;authenticatorData&lt;/code&gt;, monotonically increasing on each use (the relying party rejects any assertion whose counter is not strictly greater than the previous one, modulo the synced-passkey carve-out we will reach in §7). The third is channel binding -- the structurally correct answer to relay attacks, which sits at the TLS layer rather than the application layer.The IETF Token Binding stack (RFC 8471, RFC 8473, both October 2018) [@rfc8471] [@rfc8473] was the most ambitious attempt at the channel-binding criterion at the application layer. Both RFCs remain Proposed Standard at the IETF -- the datatracker history pages record no Historic reclassification event for either [@rfc8471-history] [@rfc8473-history] -- but Chromium removed support in version 70 in October 2018, the same month the RFCs were published, and no major browser has implemented them since [@wiki-token-binding]. The &lt;code&gt;clientDataJSON.tokenBinding&lt;/code&gt; field is therefore a no-op in 2026 production. WebAuthn solves the criterion above the channel by signing the origin into the assertion itself.&lt;/p&gt;
&lt;p&gt;The cleaner channel-binding answer is RFC 9266 &lt;code&gt;tls-exporter&lt;/code&gt; for TLS 1.3 (Whited, July 2022) [@rfc9266], which extends RFC 5056&apos;s channel-binding framework into the TLS 1.3 world -- but no major browser wires &lt;code&gt;tls-exporter&lt;/code&gt; into WebAuthn out of the box as of January 2026. The current WebAuthn deployment treats the origin string in &lt;code&gt;clientDataJSON&lt;/code&gt; as the primary channel binding, with HTTPS itself providing the underlying TLS guarantee.&lt;/p&gt;
&lt;h3&gt;Axis 4: step-up and session continuity&lt;/h3&gt;
&lt;p&gt;The criterion: can the relying party demand a &lt;em&gt;fresh&lt;/em&gt; authentication for a high-value action (transfer money, change password, invite a user), and can it tell the difference between a session that was authenticated with strong factors and one that was authenticated with weak factors? WebAuthn answers this with two flag bits in &lt;code&gt;authenticatorData&lt;/code&gt;. &lt;code&gt;UP&lt;/code&gt; (user present) is set when the authenticator detected a presence test -- a touch, a click, an NFC tap. &lt;code&gt;UV&lt;/code&gt; (user verified) is set when the authenticator additionally verified the user via PIN, biometric, or other gesture. A relying party that demands &lt;code&gt;userVerification: &quot;required&quot;&lt;/code&gt; can force &lt;code&gt;UV=1&lt;/code&gt; on the assertion; an RP that issues a fresh challenge for a high-value action gets a fresh signature tied to that challenge.&lt;/p&gt;
&lt;p&gt;Generic transactional confirmation -- &quot;sign a description of &lt;em&gt;this specific transaction&lt;/em&gt;&quot; -- was attempted in WebAuthn&apos;s earliest drafts via the &lt;code&gt;txAuthSimple&lt;/code&gt; and &lt;code&gt;txAuthGeneric&lt;/code&gt; extensions [@webauthn-fpwd]. Neither extension was ever implemented by browsers, and both are absent from the Level 3 specification surface as of January 2026 [@webauthn-l3-cr-dated]. The Secure Payment Confirmation flow in WebAuthn Level 3 [@webauthn-l3-cr] is the productised replacement for payment transactions; general transactional authorisation remains an open problem.&lt;/p&gt;
&lt;h3&gt;Axis 5: recovery and lifecycle&lt;/h3&gt;
&lt;p&gt;The heretical thesis: this is the only axis that matters in production, and it is the axis on which every modern platform still bottoms out at a single-factor primitive. We will foreshadow it here and land on it in §17. A passkey ceremony that scores AAL3 phishing-resistant at the authentication moment can be a single-factor SMS-OTP at the recovery moment -- and the &lt;em&gt;system&apos;s&lt;/em&gt; AAL is the recovery flow&apos;s AAL, not the authentication ceremony&apos;s. Microsoft&apos;s Entra documentation already flags account recovery as a load-bearing deployment cost: FIDO2 keys &quot;can increase costs for equipment, training, and helpdesk support -- especially when users lose their physical keys and need account recovery&quot; [@ms-entra-passwordless].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The single most predictive question about an authentication system is not &quot;what factor does the user produce at sign-in?&quot; but &quot;what factor produces the credential when the user has lost the original one?&quot; We come back to this in §17.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;The criteria table as a spine&lt;/h3&gt;
&lt;p&gt;The five axes give the article its spine. Every later section fills in a row of the same five-column table. The columns are the strongest authenticators we have shipped: password, password plus SMS-OTP, password plus TOTP, password plus push with number matching, device-bound FIDO2 hardware key, synced passkey, and a hypothetical &quot;recovery-flow-aware&quot; composite. The criteria-aware ranking (§13) re-orders that table in a way the know/have/are taxonomy cannot.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; The know/have/are taxonomy groups authenticators by what the user feels they are producing. The criteria framework groups them by what an attacker has to defeat. Only the second taxonomy predicts the outcome of a real-world attack.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If these are the right axes, when did we figure that out?&lt;/p&gt;
&lt;h2&gt;3. Where the taxonomy came from&lt;/h2&gt;
&lt;p&gt;The know/have/are taxonomy did not appear all at once. The 1970s and 1980s operating-systems literature already grouped authentication factors into &quot;something the user knows,&quot; &quot;something the user has,&quot; and &quot;something the user is&quot; -- it was a way of talking about the design space, not a regulatory criterion. The taxonomy entered U.S. federal procurement via the Department of Defense&apos;s &lt;em&gt;Trusted Computer System Evaluation Criteria&lt;/em&gt; in December 1985 -- the Orange Book, DOD 5200.28-STD [@wiki-orange-book] -- which required identification and authentication at every assurance class above D and made passwords the canonical &lt;em&gt;something you know&lt;/em&gt; in federal IT. The Orange Book did not invent the taxonomy; it codified it.&lt;/p&gt;
&lt;p&gt;Two decades later, in June 2004, NIST canonised the same taxonomy as the U.S. federal regulatory framework. NIST SP 800-63 &lt;em&gt;Electronic Authentication Guideline&lt;/em&gt; -- by William Burr, Donna Dodson, and W. Timothy Polk -- defined four assurance levels and tied each to a combination of authenticator categories that the levels could accept [@sp80063-2004-v1] [@sp80063-2004-pdf]. Burr&apos;s framework absorbed two decades of accumulated practice with hardware OTP tokens. The canonical commercial OTP product, RSA SecurID, had shipped in 1986 -- a key fob that produced a fresh code each minute using a built-in clock and a factory-encoded seed [@wiki-rsa-securid] -- and SP 800-63 explicitly accepted SecurID-class authenticators at the higher assurance levels. The four-level structure (later AAL1 through AAL3 in the post-2017 redesign) lasted through SP 800-63-1 (2011), -2 (2013), -3 (2017), and -4 (2025); every revision is recognisably the same shape [@nist-sp80063-3-final].The CSRC bibliographic page for the 2004 first edition renders the leading author as a blank entry preceded by a stray comma, an artefact of Burr&apos;s retirement from NIST after publication. The actual cover-page authorship is Burr, Dodson, and Polk -- the citation in the references list above uses the correct three-name form.&lt;/p&gt;
&lt;p&gt;In parallel, the cryptographic protocol literature was building the &lt;em&gt;criteria&lt;/em&gt; taxonomy that would eventually displace know/have/are. Bellcore&apos;s Neil Haller published RFC 1760 in February 1995 -- the S/KEY one-time password system, a Lamport hash chain that produced a fresh login secret each time and that an eavesdropper could not replay [@rfc1760]. Haller&apos;s text already says the technique was first suggested by Leslie Lamport, which makes 1995 the first IETF standardisation of replay-resistance as a design criterion. RFC 4226 (HOTP, December 2005) [@rfc4226] and RFC 6238 (TOTP, May 2011) [@rfc6238] generalised the same idea into the synchronised counter and time-based variants the world now calls &quot;authenticator app&quot; codes.&lt;/p&gt;
&lt;p&gt;The verifier-impersonation criterion got its first IETF expression in November 2007. Nico Williams&apos; RFC 5056 &lt;em&gt;On the Use of Channel Bindings to Secure Channels&lt;/em&gt; defined the concept that &quot;the two end-points of a secure channel at one network layer are the same as at a higher layer,&quot; and bound authentication at the higher layer to the channel at the lower layer [@rfc5056]. RFC 5056 was the protocol-literature acknowledgement that authentication needed to be tied to &lt;em&gt;something the network attacker could not change&lt;/em&gt; -- the channel itself, not just the user&apos;s typing.&lt;/p&gt;
&lt;p&gt;Kim Cameron&apos;s &lt;em&gt;The Laws of Identity&lt;/em&gt;, published on identityblog.com in May 2005, captured the same idea from a higher-level perspective. The seven Laws are a framework for federated identity on the open Internet; Laws 2 (&quot;minimal disclosure for a constrained use&quot;) and 4 (&quot;directed identity&quot;) are the conceptual ancestors of WebAuthn&apos;s &lt;em&gt;origin binding&lt;/em&gt; and &lt;em&gt;per-RP key pair&lt;/em&gt; design [@identityblog-laws]. Cameron was Microsoft&apos;s Chief Architect of Identity through this period, and the Laws shaped a generation of Microsoft thinking on identity. The Laws preceded the consortium that would actually ship the protocol by eight years.&lt;/p&gt;

The criteria framework was *available* in the literature by 2007: replay resistance from S/KEY (1995), channel binding from RFC 5056 (2007), origin binding from Cameron&apos;s Laws of Identity (2005). It did not displace know/have/are in regulatory documents until NIST SP 800-63-3 in 2017 (which introduced the &quot;phishing-resistant authenticator&quot; term) and SP 800-63-4 in 2025 (which made verifier-impersonation resistance a first-class criterion). Why the gap? The know/have/are taxonomy is *legible to procurement* -- it produces neat checkboxes. The criteria taxonomy is *cryptographically meaningful* but produces fewer neat checkboxes. Regulation prefers checkboxes until breach data forces a change.

gantt
    title Authentication standards lineage, 1985-2026
    dateFormat YYYY
    axisFormat %Y
    section Regulatory codification
    Orange Book DOD 5200.28-STD :1985, 5y
    NIST SP 800-63 v1 :2004, 7y
    NIST SP 800-63-3 (phishing-resistant) :2017, 8y
    NIST SP 800-63-4 final :2025, 2y
    section Criteria origin (IETF/W3C)
    RFC 1760 S/KEY :1995, 10y
    RFC 4226 HOTP :2005, 6y
    RFC 5056 Channel binding :2007, 4y
    RFC 6238 TOTP :2011, 7y
    RFC 8471 Token Binding :2018, 1y
    RFC 9266 tls-exporter :2022, 4y
    section Identity literature
    Cameron Laws of Identity :2005, 8y
    section FIDO and W3C
    FIDO Alliance launch :2013, 1y
    FIDO U2F 1.0 :2014, 5y
    WebAuthn FPWD :2016, 3y
    WebAuthn L1 + CTAP 2.0 :2019, 2y
    WebAuthn L2 + CTAP 2.1 :2021, 1y
    Passkey commitment May 2022 :2022, 1y
    WebAuthn L3 CR :2023, 3y
    CTAP 2.2 PS :2025, 1y
    section Windows
    Windows 10 1903 webauthn.dll :2019, 3y
    Windows 11 22H2 ECC :2022, 2y
    Windows 11 24H2 plug-in model :2024, 2y
&lt;p&gt;By 2007 the criteria framework was on paper. By 2013 there was a consortium for it: the FIDO Alliance launched on 12 February 2013 [@fido-launch-pdf], with six founding members [@wiki-fido-alliance]. Earlier identity-layer attempts -- Mozilla Persona / BrowserID, launched July 2011, with decommissioning announced January 2016 and the service shut down on 30 November 2016 [@wiki-mozilla-persona] -- had tried to build a browser-mediated identity layer at the HTTP level and failed to achieve traction. The FIDO consortium took a different bet: solve the authentication ceremony first, leave the identity-layer above it to OIDC and SAML. What happened first in a browser?&lt;/p&gt;
&lt;h2&gt;4. U2F: the first browser ceremony designed against phishing&lt;/h2&gt;
&lt;p&gt;December 2014. Yubico, Google, and NXP Semiconductors publish FIDO 1.0 / Universal 2nd Factor (U2F) [@fido-u2f-overview]; U2F 1.0 reached Proposed Standard status on 9 October 2014, with the broader FIDO 1.0 announcement window running through December [@wiki-u2f]. The Universal 2nd Factor Wikipedia article catalogues the design tradeoffs explicitly: U2F&apos;s challenge-response is &quot;signed (encoding originating domain/website) to prevent interception and reuse&quot; [@wiki-u2f]. This was the first time a browser ceremony was designed against the phishing-resistance criterion as a &lt;em&gt;primary&lt;/em&gt; goal rather than as an afterthought.&lt;/p&gt;
&lt;p&gt;The U2F ceremony has five field-level moving parts. An &lt;em&gt;AppID&lt;/em&gt; string identifies the relying party, derived from the page&apos;s origin so a phisher&apos;s domain cannot produce a U2F signature for the real bank. A &lt;em&gt;challenge&lt;/em&gt; is a per-ceremony nonce the relying party generates. A &lt;em&gt;key handle&lt;/em&gt; is an opaque blob the authenticator returns at registration and supplies on every later assertion; the relying party uses it to address the right credential on the next challenge. A &lt;em&gt;signature counter&lt;/em&gt; increments monotonically on every assertion, letting the relying party detect simple cloning. And the &lt;em&gt;signature&lt;/em&gt; itself is an ECDSA P-256 signature over the AppID hash, the challenge, the counter, and a presence flag.&lt;/p&gt;
&lt;p&gt;The AppID rule is the load-bearing piece. The browser computes the AppID from the actual origin the user is on; the authenticator signs over its hash; the relying party compares it to the AppID under which the credential was registered. A look-alike domain produces a different AppID, which produces a different signature, which the real verifier rejects. This is the same trick WebAuthn will later generalise as &lt;code&gt;rpId&lt;/code&gt; binding -- and it is the trick that makes U2F structurally immune to the AitM kits that will demolish password plus push a decade later.&lt;/p&gt;
&lt;p&gt;The canonical deployment paper is &lt;em&gt;Security Keys: Practical Cryptographic Second Factors for the Modern Web&lt;/em&gt;, by Juan Lang, Alexei Czeskis, Dirk Balfanz, Marius Schilder, and Sampath Srinivas, in the Financial Cryptography 2016 preproceedings [@lang-fc2016-pdf]. The paper documents Google&apos;s internal rollout: a hardware second factor for every employee, replacing the company&apos;s previous OTP-based MFA. The empirical scoreboard for the criteria framework gets its first data point here -- after the rollout, Google reported zero phishing-related account takeovers on employee accounts during the deployment period. This is not a controlled study; it is the largest natural experiment in deployed phishing resistance the industry had seen.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; U2F is the moment the authentication community made a structural design choice: phishing resistance is a property of the &lt;em&gt;protocol&lt;/em&gt;, not of &lt;em&gt;user training&lt;/em&gt;. No amount of &quot;look for the lock icon&quot; advice closes the phishing gap; a protocol that signs over the origin closes it by construction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;U2F&apos;s limitation is that it is, by design, a &lt;em&gt;second&lt;/em&gt; factor. The password under it remains the load-bearing weak link: a credential-stuffer can reuse the password against a service that does not require U2F, and a phisher can still capture the password even if they cannot capture the U2F signature. The AppID idea was correct; what was missing was the willingness to make the strong factor &lt;em&gt;the&lt;/em&gt; factor, not a layer on top of a weak one. The bridge from U2F to FIDO2 is exactly that move.&lt;/p&gt;
&lt;p&gt;The other piece U2F got right and FIDO2 inherited is the principle that the credential is &lt;em&gt;device-bound&lt;/em&gt; by default. The U2F Wikipedia summary captures the consequence: &quot;no recovery of the key is possible&quot; if the device is lost [@wiki-u2f]. This is the same property that makes synced passkeys, when they arrive in May 2022, a &lt;em&gt;productisation&lt;/em&gt; rather than a &lt;em&gt;cryptographic&lt;/em&gt; move. The bytes are the same. The lifecycle is different.&lt;/p&gt;
&lt;p&gt;If the second factor is doing all the work, why not make it &lt;em&gt;the&lt;/em&gt; factor?&lt;/p&gt;
&lt;h2&gt;5. FIDO2 + CTAP 2.0 + WebAuthn Level 1: the spec lands&lt;/h2&gt;
&lt;p&gt;March 4, 2019. The World Wide Web Consortium and the FIDO Alliance announced that the Web Authentication specification was an official W3C Recommendation [@w3c-fido-press-release]; the dated Recommendation slug is &lt;code&gt;REC-webauthn-1-20190304&lt;/code&gt; [@webauthn-l1-rec]. Same day, with January 30, 2019 as the underlying CTAP 2.0 Proposed Standard date [@ctap-2-0-ps]. The pair is what the industry markets as &lt;em&gt;FIDO2&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The reframe was decisive. A &lt;em&gt;platform authenticator&lt;/em&gt; -- Windows Hello on Windows, Touch ID on macOS, the Android Keystore on Android -- was now a first-class FIDO authenticator. The user&apos;s laptop or phone could be the authenticator. The browser did not need a separate USB device; it could call into the OS instead. This is the move that made FIDO2 a consumer technology, not just a security-team technology.&lt;/p&gt;

The *relying party* is the web service that owns the user&apos;s account. The *rpId* is a string identifying that party for credential scoping; it must be a registrable suffix of the page&apos;s origin (so `login.bank.com` may use `bank.com` as its `rpId`, but `evil.com` may not). All WebAuthn signatures are made over the SHA-256 hash of the `rpId`, which the browser derives from the actual origin and writes into `clientDataJSON`. The relying party validates the signature against the public key registered for that `rpId`. Phishing resistance is `rpId` binding, full stop [@webauthn-l3-cr].
&lt;p&gt;The Web IDL surface that WebAuthn Level 1 standardised is small. &lt;code&gt;navigator.credentials.create({publicKey: ...})&lt;/code&gt; registers a new credential; &lt;code&gt;navigator.credentials.get({publicKey: ...})&lt;/code&gt; produces an assertion. Both return &lt;code&gt;PublicKeyCredential&lt;/code&gt; objects. The complexity is not in the API; it is in the byte-level structures the API exchanges.&lt;/p&gt;
&lt;p&gt;A registration ceremony looks like this. The relying party generates a &lt;code&gt;PublicKeyCredentialCreationOptions&lt;/code&gt; blob containing a fresh challenge, the &lt;code&gt;rpId&lt;/code&gt;, the user&apos;s account identifier, the list of algorithms the RP supports, the desired user verification, and an optional list of credentials the user already has. The browser passes this to the authenticator and gets back two byte blobs. The first is &lt;code&gt;clientDataJSON&lt;/code&gt; -- a UTF-8 JSON blob containing &lt;code&gt;type: &quot;webauthn.create&quot;&lt;/code&gt;, the origin the browser was actually on, and the challenge. The second is &lt;code&gt;authenticatorData&lt;/code&gt; -- a binary blob containing the &lt;code&gt;rpIdHash&lt;/code&gt; (SHA-256 of the canonical &lt;code&gt;rpId&lt;/code&gt;), the flags byte (with &lt;code&gt;UP&lt;/code&gt;, &lt;code&gt;UV&lt;/code&gt;, &lt;code&gt;AT&lt;/code&gt;, &lt;code&gt;ED&lt;/code&gt; bits), the signature counter (initially zero, sometimes non-zero), the new credential&apos;s identifier, the AAGUID identifying the authenticator model, and the credential&apos;s public key in COSE_Key format. An optional &lt;em&gt;attestation statement&lt;/em&gt; binds those bytes to a hardware root of trust.&lt;/p&gt;

A 16-byte identifier the authenticator includes in `authenticatorData` to identify its make and model. Some authenticators emit an all-zeros AAGUID for privacy. Microsoft&apos;s Entra ID hardware-vendor matrix lists dozens of FIDO2 keys with their AAGUIDs and supported transports [@ms-entra-fido2-hardware]; the FIDO Metadata Service is the authoritative directory.

sequenceDiagram
    participant U as User
    participant B as Browser
    participant A as Authenticator
    participant R as Relying Party
    R-&amp;gt;&amp;gt;B: PublicKeyCredentialCreationOptions {challenge, rpId, user, pubKeyAlgs}
    B-&amp;gt;&amp;gt;B: build clientDataJSON {type:create, origin, challenge}
    B-&amp;gt;&amp;gt;A: authenticatorMakeCredential(clientDataHash, rpId, user, ...)
    A-&amp;gt;&amp;gt;U: prompt for user gesture (UV)
    U-&amp;gt;&amp;gt;A: present gesture (PIN, fingerprint, face)
    A-&amp;gt;&amp;gt;A: generate (pubKey, privKey) and sign attestation
    A-&amp;gt;&amp;gt;B: clientDataJSON, authenticatorData, attestationStatement
    B-&amp;gt;&amp;gt;R: attestationResponse {clientDataJSON, attestationObject}
    R-&amp;gt;&amp;gt;R: verify origin, rpIdHash, signature, then store pubKey, credentialId
    R-&amp;gt;&amp;gt;U: account created
&lt;p&gt;An authentication ceremony is the same shape with one structural change: the RP supplies &lt;code&gt;PublicKeyCredentialRequestOptions&lt;/code&gt; with a fresh challenge, the authenticator finds the credential matching the &lt;code&gt;rpId&lt;/code&gt;, prompts the user for a gesture (if &lt;code&gt;userVerification&lt;/code&gt; is requested), and produces an &lt;em&gt;assertion&lt;/em&gt; -- a signature over &lt;code&gt;authenticatorData || SHA-256(clientDataJSON)&lt;/code&gt; with the credential&apos;s private key. The relying party verifies the signature against the stored public key.&lt;/p&gt;
&lt;p&gt;The Windows-side surface debuts in the same window. Microsoft Learn states verbatim that Microsoft &quot;introduced the W3C/Fast IDentity Online 2 (FIDO2) Win32 WebAuthn platform APIs in Windows 10 (version 1903)&quot; [@ms-learn-webauthn-apis]. May 2019. &lt;code&gt;webauthn.dll&lt;/code&gt; ships. From that moment on, every browser on Windows -- Edge, Chrome, Firefox, Brave -- talks WebAuthn through one Win32 surface. The Microsoft Learn passkey overview makes the underlying architecture explicit: &quot;When these APIs are in use, Windows 10 browsers or applications don&apos;t have direct access to the FIDO2 transports for FIDO-related messaging&quot; [@ms-learn-webauthn-apis]. The OS is the dispatcher.&lt;/p&gt;
&lt;p&gt;The W3C/FIDO press release named the launch implementations: Windows 10, Android, Chrome, Firefox, Edge, and Safari (in preview) [@w3c-fido-press-release]. Microsoft, Google, Mozilla, and Apple all shipped within the same year. WebAuthn became the most-implemented strong-authentication standard on the consumer web inside eighteen months.&lt;/p&gt;
&lt;p&gt;{`
// A reader can paste in their own clientDataJSON and authenticatorData
// (base64url-encoded as Microsoft returns them) to see how the parser
// walks the bytes. Origin binding is one SHA-256 invocation away from
// being a one-liner; the value is in the binding, not the cryptography.&lt;/p&gt;
&lt;p&gt;const clientDataB64 = &quot;eyJ0eXBlIjoid2ViYXV0aG4uZ2V0Iiwib3JpZ2luIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tIiwiY2hhbGxlbmdlIjoiUk5KU2V6NjFqdyJ9&quot;;
const authDataB64 = &quot;Y9JZsAcVeQOLgxs9Ux7QYZpyTaB-OkpdyPwQk7P9YsoFAAAAFw&quot;;&lt;/p&gt;
&lt;p&gt;function b64urlDecode(s) {
  s = s.replace(/-/g,&apos;+&apos;).replace(/_/g,&apos;/&apos;);
  while (s.length % 4) s += &apos;=&apos;;
  return Uint8Array.from(atob(s), c =&amp;gt; c.charCodeAt(0));
}&lt;/p&gt;
&lt;p&gt;const clientDataBytes = b64urlDecode(clientDataB64);
const clientData = JSON.parse(new TextDecoder().decode(clientDataBytes));
console.log(&quot;clientDataJSON.type     =&quot;, clientData.type);
console.log(&quot;clientDataJSON.origin   =&quot;, clientData.origin);
console.log(&quot;clientDataJSON.challenge=&quot;, clientData.challenge);&lt;/p&gt;
&lt;p&gt;const authData = b64urlDecode(authDataB64);
const rpIdHash = authData.slice(0, 32);
const flags = authData[32];
const signCount = (authData[33]&amp;lt;&amp;lt;24) | (authData[34]&amp;lt;&amp;lt;16) | (authData[35]&amp;lt;&amp;lt;8) | authData[36];
console.log(&quot;authenticatorData rpIdHash =&quot;, Array.from(rpIdHash).map(b=&amp;gt;b.toString(16).padStart(2,&apos;0&apos;)).join(&apos;&apos;));
console.log(&quot;authenticatorData flags    = 0x&quot; + flags.toString(16),
            &quot;UP=&quot;+(flags&amp;amp;1), &quot;UV=&quot;+((flags&amp;gt;&amp;gt;2)&amp;amp;1), &quot;BE=&quot;+((flags&amp;gt;&amp;gt;3)&amp;amp;1), &quot;BS=&quot;+((flags&amp;gt;&amp;gt;4)&amp;amp;1), &quot;AT=&quot;+((flags&amp;gt;&amp;gt;6)&amp;amp;1));
console.log(&quot;authenticatorData signCount=&quot;, signCount);
`}&lt;/p&gt;
&lt;p&gt;The credential&apos;s public key is encoded as a COSE_Key map -- a CBOR object whose algorithm identifier is one of the entries in the IANA COSE Algorithms registry [@iana-cose-registry]. As of the registry&apos;s 2026-03-04 update, no post-quantum algorithm is in WebAuthn-recommended status; ECDSA P-256 and EdDSA Ed25519 remain the workhorses. The companion &lt;em&gt;Post-Quantum Cryptography on Windows&lt;/em&gt; article walks the algorithm-side rollout.&lt;/p&gt;
&lt;p&gt;Level 1 settled the field-level shape. What did the next two years sharpen?&lt;/p&gt;
&lt;h2&gt;6. CTAP 2.1: the wire protocol every security key is speaking&lt;/h2&gt;
&lt;p&gt;15 June 2021. The FIDO Alliance published CTAP 2.1 as a Proposed Standard [@ctap-2-1-ps]. CTAP 2.1 is the CBOR-on-the-wire version most security keys in 2024-2026 are running; CTAP 2.2 (Proposed Standard, 14 July 2025) [@ctap-2-2-ps] refines a few corners, and CTAP 2.3 is the Proposed Standard the FIDO Alliance lists alongside it [@fido-specs-download]. Each version adds capability without breaking the previous one&apos;s commands.&lt;/p&gt;

The Client-to-Authenticator Protocol -- the wire format the browser speaks to a roaming authenticator over USB-HID, NFC, or BLE. CTAP1 (the original U2F messages) carries APDU-style binary structures; CTAP2 carries CBOR-encoded commands. A *CTAP2 authenticator* (also called a FIDO2 or WebAuthn authenticator) implements the CTAP2 command set; modern keys also implement CTAP1 for backwards compatibility [@ctap-2-0-ps].
&lt;p&gt;The CTAP2 command-byte table is the surface a browser actually dispatches to. Each command is a single byte followed by a CBOR-encoded request map. The table below names the commands in order and the criterion-table cell each one strengthens.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command byte&lt;/th&gt;
&lt;th&gt;Command name&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Criterion strengthened&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;0x01&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorMakeCredential&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Registration: generate a fresh keypair bound to &lt;code&gt;(rpId, user.id)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Phishing resistance (origin binding)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x02&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorGetAssertion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authentication: sign the challenge with the credential&apos;s private key&lt;/td&gt;
&lt;td&gt;Phishing + replay + verifier-compromise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x04&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorGetInfo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Capability discovery: list supported algorithms, extensions, transports, &lt;code&gt;UV&lt;/code&gt; modes&lt;/td&gt;
&lt;td&gt;Step-up (lets RP know what&apos;s available)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x06&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorClientPIN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Manage the PIN, issue &lt;code&gt;pinUvAuthToken&lt;/code&gt; with permissions bitmap and &lt;code&gt;rpId&lt;/code&gt; scoping&lt;/td&gt;
&lt;td&gt;Step-up + replay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x07&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorReset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wipe all resident credentials on the device&lt;/td&gt;
&lt;td&gt;Lifecycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x09&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorBioEnrollment&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;On-token fingerprint enrolment (CTAP 2.1)&lt;/td&gt;
&lt;td&gt;Step-up (&lt;code&gt;UV=1&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x0A&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorCredentialManagement&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List, enumerate, and delete resident credentials per RP&lt;/td&gt;
&lt;td&gt;Lifecycle / recovery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x0B&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorSelection&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&quot;Pick this device&quot; prompt when multiple authenticators are present&lt;/td&gt;
&lt;td&gt;UX (no criterion change)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x0C&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorLargeBlobs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Per-credential blob store under the credential&lt;/td&gt;
&lt;td&gt;Step-up (extension data)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x0D&lt;/td&gt;
&lt;td&gt;&lt;code&gt;authenticatorConfig&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable enterprise attestation, toggle &lt;code&gt;alwaysUv&lt;/code&gt;, set minimum PIN length&lt;/td&gt;
&lt;td&gt;Verifier-compromise + lifecycle&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Three pieces of CTAP 2.1 are worth pulling out because they meaningfully change the criteria-table cells.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;pinUvAuthToken&lt;/code&gt; and permissions.&lt;/strong&gt; CTAP 2.0&apos;s PIN-protocol let the browser obtain a &lt;code&gt;pinAuthToken&lt;/code&gt; and use it across any command. CTAP 2.1 introduced a &lt;em&gt;permissions bitmap&lt;/em&gt; and &lt;em&gt;rpId scoping&lt;/em&gt; on the token so that a token issued for &lt;em&gt;one&lt;/em&gt; relying party&apos;s ceremony cannot be replayed against a different relying party&apos;s ceremony on the same authenticator [@ctap-2-1-ps]. This closes a class of host-side mischief: an attacker who got the PIN out of one ceremony could not previously be stopped from spending it on a different &lt;code&gt;rpId&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;credProtect&lt;/code&gt;.&lt;/strong&gt; A new extension that lets the RP request a higher protection level on the resident credential -- specifically, that the authenticator should refuse to list the credential without a &lt;code&gt;UV=1&lt;/code&gt; gesture. The first generation of WebAuthn discoverable credentials were enumerable by any host that could speak CTAP2 to the connected key; &lt;code&gt;credProtect&lt;/code&gt; lets the RP say &quot;don&apos;t show this credential&apos;s existence to anything that doesn&apos;t pass user verification first.&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enterprise attestation.&lt;/strong&gt; CTAP 2.1 added an explicit &lt;em&gt;enterprise attestation&lt;/em&gt; mode in which the authenticator binds its attestation statement to a list of relying parties the device&apos;s enrolling organisation has pre-approved. This is the bridge that makes vendor attestation useful in managed enterprises without leaking the user&apos;s specific device identity to every relying party.The largeBlob extension (CTAP 2.1, command 0x0C) gives each credential a small per-credential blob store. RPs use it for things like cached short-lived tokens or per-user policy. The 2024 release notes for the Windows &lt;code&gt;webauthn.dll&lt;/code&gt; API surface flagged largeBlob support as one of the additions in Windows 11 22H2 [@ms-learn-webauthn-apis]; a March 2023 Review Draft [@ctap-2-2-rd] foreshadowed the 2.2 refinements that landed in July 2025.&lt;/p&gt;
&lt;p&gt;All of this is for experts. When did this stop being a security-team conversation and start being a consumer product? What changed in May 2022?&lt;/p&gt;
&lt;h2&gt;7. Passkeys: the productisation moment&lt;/h2&gt;
&lt;p&gt;5 May 2022. Apple, Google, and Microsoft jointly committed at the FIDO Alliance to a common passwordless sign-in standard [@fido-aav-passkey-commitment]. The press release is short on protocol detail and long on user-facing language. The headline commitment, verbatim: &quot;Allow users to automatically access their FIDO sign-in credentials (referred to by some as a &apos;passkey&apos;) on many of their devices, even new ones, without having to reenroll every account&quot; [@fido-aav-passkey-commitment]. &lt;em&gt;Passkey&lt;/em&gt; entered the public lexicon. Andrew Shikiar, the FIDO Alliance&apos;s executive director and CMO at the time, named it in the press call.&lt;/p&gt;

Allow users to automatically access their FIDO sign-in credentials (referred to by some as a &apos;passkey&apos;) on many of their devices, even new ones, without having to reenroll every account. -- Apple, Google, and Microsoft, joint FIDO Alliance announcement, 5 May 2022 [@fido-aav-passkey-commitment]
&lt;p&gt;The &lt;em&gt;cryptographic&lt;/em&gt; move in May 2022 was small. The protocol bytes are the same FIDO2 / WebAuthn / CTAP2 bytes that shipped in March 2019. What changed was twofold: (a) the three platform vendors aligned their sync fabrics so that a passkey created on a user&apos;s phone would appear on the user&apos;s laptop, and (b) the user-facing terminology consolidated from a confusing menagerie (&quot;discoverable credential,&quot; &quot;resident key,&quot; &quot;client-side discoverable credential&quot;) onto a single product term -- &lt;em&gt;passkey&lt;/em&gt;.&lt;/p&gt;

A WebAuthn credential whose `user.id` and account metadata are stored *on the authenticator*, so the authenticator can produce an assertion without the relying party first supplying a credential identifier. The CTAP 2.0 spec calls these *resident keys* [@ctap-2-0-ps]; the WebAuthn Level 2 spec calls them *client-side discoverable credentials* [@webauthn-l2-latest]; the May 2022 vendor commitment rebranded them as *passkeys* [@fido-aav-passkey-commitment]. All three terms refer to the same on-the-wire object.
&lt;p&gt;Discoverable credentials unlock &lt;em&gt;usernameless&lt;/em&gt; sign-in. The relying party does not need to tell the authenticator which credential to use; the authenticator looks up its own resident credentials for the supplied &lt;code&gt;rpId&lt;/code&gt;, shows the user the matching account, and asks for the user-verification gesture. This is the UX primitive every consumer-passkey flow leans on.&lt;/p&gt;
&lt;p&gt;WebAuthn Level 3 (W3C Candidate Recommendation, latest snapshot dated 13 January 2026 [@webauthn-l3-cr] [@webauthn-l3-cr-dated]) is the spec generation that productises passkeys. Level 3 standardises:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;hybrid transport&lt;/strong&gt; (formerly known as caBLE), §6.3.3 of the L3 spec, which lets a phone act as a roaming authenticator for a nearby laptop via QR code plus ephemeral ECDH plus BLE proximity. We cover hybrid in §12.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JSON-serialisation helpers&lt;/strong&gt; -- &lt;code&gt;PublicKeyCredentialCreationOptionsJSON&lt;/code&gt; and &lt;code&gt;PublicKeyCredentialRequestOptionsJSON&lt;/code&gt; -- that make WebAuthn easier to drive from a server SDK without manual base64url juggling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;getClientCapabilities()&lt;/code&gt;&lt;/strong&gt; so the relying party can probe what the client supports before issuing the ceremony.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;code&gt;credProps&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;prf&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;largeBlob&lt;/code&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;code&gt;credProtect&lt;/code&gt;&lt;/strong&gt;, and &lt;strong&gt;Secure Payment Confirmation&lt;/strong&gt; extensions, each of which sharpens one cell of the criteria table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The mid-2025 cadence picked up: CTAP 2.2 Proposed Standard on 14 July 2025 [@ctap-2-2-ps] refined hybrid-transport semantics and tightened &lt;code&gt;credProtect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The synced-vs-bound distinction is the structural new thing about passkeys. Before May 2022 a FIDO2 credential lived in one secure element; lose the YubiKey, lose the credential. Synced passkeys put the private key into a sync fabric -- Apple iCloud Keychain (originally 2013) [@wiki-icloud], Google Password Manager (Chrome password sync, late 2000s onward), Microsoft Authenticator (originally 2015) [@wiki-ms-authenticator], and Microsoft Account passkey sync (general availability for consumer accounts on 2 May 2024) [@ms-security-passkeys-consumer] -- and let it appear on every device the user signs into. The mechanism is end-to-end encryption against a sync-fabric key that the platform vendor cannot read; Apple&apos;s Advanced Data Protection model is the strongest current public realisation [@apple-adp-kb].&lt;/p&gt;
&lt;p&gt;The price: the long-term private key has &lt;em&gt;left&lt;/em&gt; the original authenticator. NIST is unambiguous about the consequence. The April 2024 supplement &lt;em&gt;Incorporating Syncable Authenticators into NIST SP 800-63B&lt;/em&gt; [@sp80063sup1] -- since absorbed into NIST SP 800-63B-4 final, July 2025 [@sp80063b4-html] -- classifies synced passkeys at AAL2, not AAL3, because the key is no longer pinned to a single tamper-resistant element. Yubico&apos;s commentary captures the dichotomy verbatim: &quot;FIDO passkeys that are not synced -- device-bound passkeys like YubiKeys -- and are properly stored in dedicated hardware have an AAL3 rating&quot; [@yubico-nist-guidance].&lt;/p&gt;
&lt;p&gt;The WebAuthn spec made the distinction &lt;em&gt;observable&lt;/em&gt;. Two new flag bits in &lt;code&gt;authenticatorData&lt;/code&gt; -- &lt;code&gt;BE&lt;/code&gt; (Backup Eligible) and &lt;code&gt;BS&lt;/code&gt; (Backup State) -- tell the relying party whether the credential is in principle syncable (&lt;code&gt;BE=1&lt;/code&gt;) and whether it is currently backed up (&lt;code&gt;BS=1&lt;/code&gt;) [@webauthn-l3-cr]. The RP can decide policy from those flags: a banking RP can require &lt;code&gt;BE=0&lt;/code&gt; (device-bound) credentials for AAL3 transactions, while accepting &lt;code&gt;BS=1&lt;/code&gt; (synced) credentials for AAL2 sign-in.&lt;/p&gt;
&lt;p&gt;Microsoft&apos;s own numbers tell the productisation story in raw counts. The May 2024 Microsoft Security blog announcing passkey support for consumer accounts notes that Microsoft was &quot;detecting around 115 password attacks per second&quot; when Windows Hello first shipped in 2015; &quot;less than a decade later, that number has surged 3,378% to more than 4,000 password attacks per second&quot; [@ms-security-passkeys-consumer]. The 1 May 2025 World Passkey Day post escalates again: &quot;we observed a staggering 7,000 password attacks per second (more than double the rate from 2023). [...] now we see nearly a million passkeys registered every day.&quot; It also reports that &quot;passkey sign-ins are eight times faster than a password and multifactor authentication,&quot; and that &quot;more than 99% of people who sign into their Windows devices with their Microsoft account do so using Windows Hello&quot; [@ms-security-world-passkey-day].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Passkeys are not a new cryptographic primitive. They are a productisation moment in which discoverable credentials became consumer-grade UX. The protocol moves were two years earlier; the product move is what changed the criteria-table scoreboard.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Passkeys are a &lt;em&gt;productisation&lt;/em&gt; moment. On Windows specifically, what does the platform actually do between &lt;code&gt;navigator.credentials.create&lt;/code&gt; and the TPM?&lt;/p&gt;
&lt;h2&gt;8. The Windows platform authenticator: &lt;code&gt;webauthn.dll&lt;/code&gt; end-to-end&lt;/h2&gt;
&lt;p&gt;May 2019. Windows 10 version 1903. The Win32 platform WebAuthn API shipped, and from that moment on every browser and every native application on Windows that wants to do WebAuthn calls &lt;code&gt;webauthn.dll&lt;/code&gt;. The header file &lt;code&gt;webauthn.h&lt;/code&gt; is in the Windows SDK and is also published on GitHub at &lt;code&gt;github.com/microsoft/webauthn&lt;/code&gt; [@github-ms-webauthn]. The reference page on Microsoft Learn enumerates every function the API surfaces [@ms-learn-win32-webauthn]. The 1903 ship date and the subsequent feature additions are documented verbatim by Microsoft Learn: &quot;Microsoft has long been a proponent of passwordless authentication, and has introduced the W3C/Fast IDentity Online 2 (FIDO2) Win32 WebAuthn platform APIs in Windows 10 (version 1903). Starting in &lt;strong&gt;Windows 11, version 22H2&lt;/strong&gt;, WebAuthn APIs support ECC algorithms and starting in &lt;strong&gt;Windows 11 version 24H2&lt;/strong&gt; WebAuthn APIs support plugin passkey managers&quot; [@ms-learn-webauthn-apis].&lt;/p&gt;

When these APIs are in use, Windows 10 browsers or applications don&apos;t have direct access to the FIDO2 transports for FIDO-related messaging. -- Microsoft Learn, *WebAuthn APIs for password-less authentication on Windows* [@ms-learn-webauthn-apis]
&lt;p&gt;That sentence is the entire architectural premise. The OS dispatches FIDO2 ceremonies. The browser does not own the CTAP2 stack, the USB-HID transport, the NFC reader, the BLE pairing, or the Hello UV gesture. It hands &lt;code&gt;webauthn.dll&lt;/code&gt; a request and gets back an assertion.&lt;/p&gt;
&lt;p&gt;The API surface is a small set of functions. The ceremony surface is two functions, the management surface is the remainder.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNAuthenticatorMakeCredential&lt;/code&gt;&lt;/strong&gt; -- the registration entry point. Caller supplies origin / &lt;code&gt;rpId&lt;/code&gt; / user / algorithms / attestation preference / authenticator-selection criteria. Returns an attestation object.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNAuthenticatorGetAssertion&lt;/code&gt;&lt;/strong&gt; -- the authentication entry point. Caller supplies origin / &lt;code&gt;rpId&lt;/code&gt; / allowed credential IDs (or empty for usernameless) / user-verification preference / mediation (Conditional UI, see §9). Returns an assertion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNGetApiVersionNumber&lt;/code&gt;&lt;/strong&gt; -- a monotonically increasing integer that lets callers feature-detect. Version 1 is Windows 10 1903; versions step up as Windows adds ECC algorithms (22H2), the plugin model (24H2), and the EXPERIMENTAL_*2 surface (Insider builds via KB5072046 [@github-ms-webauthn]).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNGetCancellationId&lt;/code&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;code&gt;WebAuthNCancelCurrentOperation&lt;/code&gt;&lt;/strong&gt; -- cooperative cancellation; the browser asks &lt;code&gt;webauthn.dll&lt;/code&gt; to drop the active ceremony.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNGetPlatformCredentialList&lt;/code&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;code&gt;WebAuthNDeletePlatformCredential&lt;/code&gt;&lt;/strong&gt; -- resident-credential management for synced passkeys held by the OS provider.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable&lt;/code&gt;&lt;/strong&gt; -- the &lt;code&gt;isUVPAA&lt;/code&gt; capability probe; the RP uses this to decide whether to offer a passkey enrolment flow at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNFreeAssertion&lt;/code&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;code&gt;WebAuthNFreeCredentialAttestation&lt;/code&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;code&gt;WebAuthNFreePlatformCredentialList&lt;/code&gt;&lt;/strong&gt; -- caller-side memory release; the OS allocates on the heap and the caller is responsible for &lt;code&gt;Free&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNGetErrorName&lt;/code&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;code&gt;WebAuthNGetW3CExceptionDOMError&lt;/code&gt;&lt;/strong&gt; -- translate the Win32 &lt;code&gt;HRESULT&lt;/code&gt; into a WebAuthn-spec error string.&lt;/li&gt;
&lt;/ul&gt;

flowchart TD
    A[Browser or native app] --&amp;gt; B[webauthn.dll: WebAuthNAuthenticatorMakeCredential]
    B --&amp;gt; C[Windows Hello UI: prompt for PIN, fingerprint, or face]
    C --&amp;gt; D[Windows Hello / Hello for Business: verify gesture]
    D --&amp;gt; E[CNG NCRYPT: keypair generation request]
    E --&amp;gt; F[TPM 2.0: generate keypair inside the TPM]
    F --&amp;gt; G[TPM 2.0: TPM2_Certify over the new credential public key]
    G --&amp;gt; H[webauthn.dll: build attestation object with packed or tpm format]
    H --&amp;gt; B
    B --&amp;gt; A
    A --&amp;gt; I[Relying party: verify attestation, store credential public key]
&lt;p&gt;The criteria-framework consequence of that call graph is that &lt;em&gt;the private key never leaves the TPM&lt;/em&gt;. Microsoft Learn states the property verbatim: &quot;The private keys can only be used after they&apos;re unlocked by the user using the Windows Hello unlock factor (biometrics or PIN)&quot; [@ms-learn-passkeys]. The TPM enforces use through its own access-control rules; even kernel malware on the host cannot exfiltrate the raw private key, only request operations gated on the user&apos;s gesture. This is what gets a Windows-platform-bound passkey on a TPM to AAL3 even when synced passkeys are bounded at AAL2.&lt;/p&gt;
&lt;p&gt;The API version sentinel tells a clean feature-evolution story.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Windows release&lt;/th&gt;
&lt;th&gt;API version (approx.)&lt;/th&gt;
&lt;th&gt;Notable additions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Windows 10 1903 (May 2019)&lt;/td&gt;
&lt;td&gt;v1&lt;/td&gt;
&lt;td&gt;Initial Win32 surface: make/get credential, isUVPAA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 10 1909 / 20H1&lt;/td&gt;
&lt;td&gt;v2&lt;/td&gt;
&lt;td&gt;UV preference, signal-handling refinements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 11 21H2 (Oct 2021)&lt;/td&gt;
&lt;td&gt;v3&lt;/td&gt;
&lt;td&gt;Hybrid transport (caBLE) entrypoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 11 22H2 (Sep 2022)&lt;/td&gt;
&lt;td&gt;v4-v5&lt;/td&gt;
&lt;td&gt;ECC algorithms (ECDSA P-256 platform credentials), Conditional UI mediation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 11 23H2 (Oct 2023)&lt;/td&gt;
&lt;td&gt;v6&lt;/td&gt;
&lt;td&gt;largeBlob, credProps, refined cancellation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 11 24H2 (Oct 2024)&lt;/td&gt;
&lt;td&gt;v7&lt;/td&gt;
&lt;td&gt;Plug-in passkey managers (&lt;code&gt;WebAuthNPlugin*&lt;/code&gt;), redesigned Hello UX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insider builds (KB5072046)&lt;/td&gt;
&lt;td&gt;v7+&lt;/td&gt;
&lt;td&gt;EXPERIMENTAL_WebAuthNPluginAddAuthenticator2, EXPERIMENTAL_WebAuthNPluginPerformUserVerification2, EXPERIMENTAL_WebAuthNPluginUpdateAuthenticatorDetails2 [@github-ms-webauthn]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The three &lt;code&gt;EXPERIMENTAL_*2&lt;/code&gt; APIs in &lt;code&gt;github.com/microsoft/webauthn&lt;/code&gt; are Insider-only and will lose the &lt;code&gt;EXPERIMENTAL_&lt;/code&gt; prefix as they stabilise. The naming convention is the standard Windows SDK signal for &quot;we want feedback before this becomes load-bearing public API.&quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; On Windows, do not roll your own CTAP2 stack. &lt;code&gt;webauthn.dll&lt;/code&gt; handles USB-HID, NFC, BLE, hybrid transport, Conditional UI, plug-in dispatch, and Windows Hello user verification in a single call. The Win32 reference at &lt;code&gt;learn.microsoft.com/en-us/windows/win32/api/webauthn/&lt;/code&gt; is the source of truth, the header file is at &lt;code&gt;github.com/microsoft/webauthn&lt;/code&gt;, and the YubiKey 5 series [@yubikey5-overview] plus the Entra-listed FIDO2 vendors [@ms-entra-fido2-hardware] are the supported keys.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The criterion-table consequence of dispatching FIDO2 through one OS surface is that &lt;em&gt;every browser is automatically as strong as the OS&lt;/em&gt;. Edge does not need its own attestation logic; neither does Chrome, Firefox, or Brave. They all call the same &lt;code&gt;webauthn.dll&lt;/code&gt;, which routes the registration to the TPM (for platform-bound passkeys), to USB-HID (for roaming security keys), or to a plug-in (for Windows 11 24H2 third-party providers, §10).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;webauthn.dll&lt;/code&gt; surface answers one half of the question. The other half is: what does the user actually &lt;em&gt;see&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;{`
// Origin binding is computationally trivial. The value is in the binding,
// not the cryptography. This snippet computes SHA-256 of an origin&apos;s
// effective rpId and compares against the rpIdHash a real authenticator
// would have signed. Paste in a clientDataJSON.origin and the
// authenticatorData.rpIdHash from the earlier snippet to verify.&lt;/p&gt;
&lt;p&gt;async function rpIdHash(rpId) {
  const enc = new TextEncoder().encode(rpId);
  const hash = await crypto.subtle.digest(&quot;SHA-256&quot;, enc);
  return Array.from(new Uint8Array(hash)).map(b =&amp;gt; b.toString(16).padStart(2,&apos;0&apos;)).join(&apos;&apos;);
}&lt;/p&gt;
&lt;p&gt;(async () =&amp;gt; {
  const goodOrigin = &quot;login.microsoftonline.example&quot;;
  const badOrigin  = &quot;login-microsoft0nline.example&quot;;
  const goodRpId   = &quot;login.microsoftonline.example&quot;;
  const badRpId    = &quot;login-microsoft0nline.example&quot;;
  console.log(&quot;rpIdHash(&quot;, goodRpId, &quot;) =&quot;, await rpIdHash(goodRpId));
  console.log(&quot;rpIdHash(&quot;, badRpId,  &quot;) =&quot;, await rpIdHash(badRpId));
  // The two hashes differ in every byte. A passkey registered against
  // login.microsoftonline.example cannot be induced to sign for the look-alike
  // because the authenticator computes the second hash from clientDataJSON.origin
  // and refuses to use the credential bound to the first one.&lt;/p&gt;
&lt;p&gt;  // Replay resistance illustration: a signCount of 0x10 followed by 0x0F
  // is illegal (counter regressed). RPs reject this for BS=0 credentials.
  const oldCount = 0x10, newCount = 0x0F;
  console.log(&quot;signCount regression (BS=0)?&quot;, newCount &amp;lt;= oldCount ? &quot;REJECT&quot; : &quot;ACCEPT&quot;);
})();
`}&lt;/p&gt;
&lt;h2&gt;9. Conditional UI: passkey autofill that looks like password autofill&lt;/h2&gt;
&lt;p&gt;The bridge between users&apos; password-trained mental model and the new asymmetric-crypto reality is a UX primitive called Conditional Mediation -- the spec name -- or &lt;em&gt;Conditional UI&lt;/em&gt; in informal use. The relying party renders a normal-looking username field. The browser sees that the page has called &lt;code&gt;navigator.credentials.get({mediation: &quot;conditional&quot;, publicKey: {...}})&lt;/code&gt; and quietly offers the user&apos;s passkey as one of the autofill suggestions, alongside whatever the user has typed and whatever the password manager remembers. The user clicks the passkey suggestion, completes a Windows Hello gesture, and they are signed in. No popup. No modal. No &quot;do you want to use a passkey?&quot; dialog.&lt;/p&gt;

A WebAuthn invocation mode in which the browser offers the user&apos;s discoverable credentials *inside* the same autofill UI it uses for saved passwords, rather than via a modal credential picker. The relying party calls `navigator.credentials.get({mediation: &quot;conditional&quot;, publicKey: {...}})`; the browser silently consults the platform authenticator (and, on Windows 11 24H2, the plug-in passkey providers) for credentials matching the `rpId`. The capability is probed via `PublicKeyCredential.isConditionalMediationAvailable()` [@webauthn-l3-cr].
&lt;p&gt;The canonical engineer-perspective walkthrough is Adam Langley&apos;s &lt;em&gt;Passkeys&lt;/em&gt; post on imperialviolet.org, dated 22 September 2022 [@imperialviolet-passkeys]. Langley walks the flag-page invocation needed on early Chrome Canary builds -- &lt;code&gt;chrome://flags#webauthn-conditional-ui&lt;/code&gt; -- and the capability surface: &lt;code&gt;isUserVerifyingPlatformAuthenticatorAvailable()&lt;/code&gt; to decide whether to offer enrolment, &lt;code&gt;isConditionalMediationAvailable()&lt;/code&gt; to decide whether to render the autofill hint at all. The post is the first time most working engineers saw what passkeys would actually look like at the page level.&lt;/p&gt;
&lt;p&gt;On Windows the browser calls &lt;code&gt;WebAuthNAuthenticatorGetAssertion&lt;/code&gt; with the Conditional mediation flag set; &lt;code&gt;webauthn.dll&lt;/code&gt; consults its resident credential store, finds passkeys matching the &lt;code&gt;rpId&lt;/code&gt;, and surfaces a small in-line affordance for each. The full-screen Windows Hello modal becomes a small in-place gesture acquisition. From the user&apos;s perspective the password-manager metaphor is unchanged; from the cryptography&apos;s perspective the work product is a public-key signature over an origin-bound challenge.&lt;/p&gt;
&lt;p&gt;The L3 spec section 5.1.4 is the normative reference for the mediation modes [@webauthn-l3-cr]. The four modes are: &lt;code&gt;silent&lt;/code&gt; (no user interaction), &lt;code&gt;optional&lt;/code&gt; (browser decides), &lt;code&gt;conditional&lt;/code&gt; (autofill), and &lt;code&gt;required&lt;/code&gt; (modal). Conditional is the one that makes passkeys feel like passwords -- and that is precisely why it took the consumer-passkey rollout off the security-team conversation and into product reviews.&lt;/p&gt;
&lt;p&gt;The Microsoft Learn passkey overview ties the UX to the Windows ship vehicle: &quot;Starting in Windows 11, version 22H2 with KB5030310, Windows provides a native experience for passkey management&quot; [@ms-learn-passkeys]. The Settings -&amp;gt; Accounts -&amp;gt; Passkeys page is the management UI; Conditional Mediation surfaces those passkeys at sign-in time. The passkeys.dev developer directory [@passkeys-dev] is the FIDO Alliance&apos;s collected resource for relying parties implementing the flow.&lt;/p&gt;
&lt;p&gt;The UX implication is the one Adam Langley underlined in the September 2022 post: the password-autofill metaphor is the load-bearing UX primitive that makes passkeys consumer-ready. The cryptography was solved in 2014. The UX took eight more years.&lt;/p&gt;
&lt;p&gt;But what if the user&apos;s passkey lives in 1Password or Bitwarden, not in Windows itself?&lt;/p&gt;
&lt;h2&gt;10. The Windows 11 24H2 third-party passkey provider model&lt;/h2&gt;
&lt;p&gt;8 October 2024. Microsoft published the Windows Developer Blog post &lt;em&gt;Passkeys on Windows: authenticate seamlessly with passkey providers&lt;/em&gt; [@ms-windev-passkeys-blog] as a pre-conference announcement ahead of the FIDO Alliance&apos;s Authenticate 2024 conference (14-16 October 2024 in Carlsbad, California). The post announced three deliverables: &quot;1. A plug-in model for third-party passkey providers. 2. Enhanced native UX for passkeys. 3. A Microsoft synced passkey provider.&quot; 1Password and Bitwarden were the named launch partners; Dashlane joined the roster shortly thereafter. The post says verbatim: &quot;Microsoft is partnering closely with 1Password, Bitwarden and others on integrating this capability&quot; [@ms-windev-passkeys-blog].&lt;/p&gt;
&lt;p&gt;The plug-in model is the first OS-level passkey-provider API on a major desktop platform. macOS Sonoma and iOS 17 had shipped a parallel design (&lt;code&gt;ASCredentialIdentityStore&lt;/code&gt; plus &lt;code&gt;ASCredentialProviderExtension&lt;/code&gt;) [@apple-ascredentialprovider]; Android 14 had added Credential Manager support [@android-credman]; Windows 11 24H2 is the desktop OS that matches the mobile platforms. The mechanism is a COM interface called &lt;code&gt;IPluginAuthenticator&lt;/code&gt;, declared in &lt;code&gt;pluginauthenticator.idl&lt;/code&gt; [@github-ms-webauthn]. A passkey-manager vendor ships a packaged Windows app that registers a COM object implementing the interface, supplies an AAGUID and a friendly name, and lets the OS dispatch ceremonies to it.&lt;/p&gt;
&lt;p&gt;The Plugin API surface is six functions on the OS side and one COM interface on the vendor side. From &lt;code&gt;webauthnplugin.h&lt;/code&gt; and the Microsoft Learn reference [@ms-learn-webauthn-apis]:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNPluginAddAuthenticator&lt;/code&gt;&lt;/strong&gt; -- register the plug-in with the OS. The vendor app calls this on first run.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNPluginAuthenticatorAddCredentials&lt;/code&gt;&lt;/strong&gt; -- supply the OS with the credentials the plug-in currently has, so the OS can render them in pickers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNPluginAuthenticatorRemoveCredentials&lt;/code&gt;&lt;/strong&gt; -- the inverse; remove credentials the plug-in no longer holds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNPluginPerformUserVerification&lt;/code&gt;&lt;/strong&gt; -- request Windows Hello UV on behalf of the plug-in. The plug-in does &lt;em&gt;not&lt;/em&gt; take the UV gesture itself; Windows Hello does, so the gesture-to-credential trust path is OS-mediated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNPluginRemoveAuthenticator&lt;/code&gt;&lt;/strong&gt; -- the vendor&apos;s uninstall path.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;WebAuthNPluginGetAuthenticatorList&lt;/code&gt;&lt;/strong&gt; -- enumerate which plug-ins the OS knows about.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Three additional &lt;code&gt;EXPERIMENTAL_*2&lt;/code&gt; functions ship in Insider build KB5072046 and refine the registration, UV, and update flows. The list, verbatim from the &lt;code&gt;github.com/microsoft/webauthn&lt;/code&gt; README: &lt;code&gt;EXPERIMENTAL_WebAuthNPluginAddAuthenticator2&lt;/code&gt;, &lt;code&gt;EXPERIMENTAL_WebAuthNPluginPerformUserVerification2&lt;/code&gt;, &lt;code&gt;EXPERIMENTAL_WebAuthNPluginUpdateAuthenticatorDetails2&lt;/code&gt; [@github-ms-webauthn].&lt;/p&gt;
&lt;p&gt;The Microsoft-authored reference implementation is the Contoso Passkey Manager sample in &lt;code&gt;microsoft/Windows-classic-samples&lt;/code&gt; [@github-ms-passkey-sample]. The sample&apos;s build manifest is explicit: &quot;Windows SDK version 10.0.26100.7175 or higher. Operating system requirements: Windows 11 version 25H2. Build Major Version = 26200 and Minor Version &amp;gt;= 6725. Windows 11 version 24H2. Build Major Version = 26100 and Minor Version &amp;gt;= 6725&quot; [@github-ms-passkey-sample]. The Microsoft Learn tutorial &lt;em&gt;Third-party passkey providers on Windows&lt;/em&gt; walks the same sample step by step [@ms-learn-thirdparty].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The Microsoft Learn third-party tutorial carries an explicit disclaimer: &quot;Contoso Passkey Manager is designed for passkey creation and usage testing only. Don&apos;t use the app for production passkeys&quot; [@ms-learn-thirdparty]. The sample illustrates the COM contract; it does not replace a vetted vendor&apos;s credential vault.&lt;/p&gt;
&lt;/blockquote&gt;

flowchart TD
    A[Browser or native app] --&amp;gt; B[webauthn.dll]
    B --&amp;gt; C{&quot;Provider picker&quot;}
    C --&amp;gt;|Windows Hello / platform| D[CNG + TPM 2.0]
    C --&amp;gt;|Roaming hardware| E[USB-HID / NFC / BLE]
    C --&amp;gt;|Third-party plug-in| F[COM: IPluginAuthenticator]
    F --&amp;gt; G[1Password / Bitwarden / Dashlane vault]
    F --&amp;gt; H[WebAuthNPluginPerformUserVerification]
    H --&amp;gt; I[Windows Hello UI]
    I --&amp;gt; H
    G --&amp;gt; F
    F --&amp;gt; B
    B --&amp;gt; A
&lt;p&gt;The user-facing flow follows the same logic as the macOS / iOS / Android equivalents. The user installs 1Password or Bitwarden from the Microsoft Store. The vendor app calls &lt;code&gt;WebAuthNPluginAddAuthenticator&lt;/code&gt; on first launch. The user enables the provider in Settings -&amp;gt; Accounts -&amp;gt; Passkeys -&amp;gt; Advanced options [@ms-windev-passkeys-blog]. From that point on, when any browser or native app on Windows starts a WebAuthn ceremony, &lt;code&gt;webauthn.dll&lt;/code&gt; presents the user with a picker -- &quot;use a passkey from Windows Hello, from 1Password, from Bitwarden, from a hardware security key, or from your phone&quot; -- and routes the ceremony to the selected provider. The plug-in itself returns an attestation object and an assertion; Windows Hello handles user verification on the plug-in&apos;s behalf via &lt;code&gt;WebAuthNPluginPerformUserVerification&lt;/code&gt;. The Windows trust boundary still owns the gesture acquisition.&lt;/p&gt;

The plug-in model adds credential-store choice; it does not change the lock-screen credential. The plug-in cannot replace Windows Hello at the lock screen; lock-screen sign-in remains the platform authenticator. The plug-in cannot proxy domain credentials -- Kerberos and NTLM are unaffected. The plug-in is *not* a replacement for the legacy `CredMan` (Credential Manager) generic-credential surface; that surface is still where Windows applications stash Basic-Auth-style credentials. The plug-in model is, specifically, a WebAuthn credential store. Everything else stays where it was.
&lt;p&gt;The criterion-table consequence is mixed. The plug-in model strengthens &lt;em&gt;user choice&lt;/em&gt; and &lt;em&gt;recovery&lt;/em&gt;, because a user with an existing 1Password / Bitwarden vault can reuse the recovery primitives they already know. It weakens &lt;em&gt;verifier-compromise resistance&lt;/em&gt; relative to a pure platform-bound passkey, because the long-term key now lives in the vendor&apos;s vault rather than the TPM -- and the vendor&apos;s vault becomes another point of compromise. It does not change phishing resistance, replay resistance, or step-up, because those are properties of the WebAuthn ceremony and the plug-in still produces a WebAuthn-shaped assertion.&lt;/p&gt;
&lt;p&gt;What 1Password, Bitwarden, and Dashlane each ship in their plug-in implementations follows the same template: registration requests get either a &lt;code&gt;packed&lt;/code&gt; attestation statement (for vendor-signed batch attestation keys) or a &lt;code&gt;none&lt;/code&gt; attestation (most consumer flows), and authentication assertions come back the same shape as any other WebAuthn assertion. The plug-in itself decides whether the credential is &lt;code&gt;BE=1, BS=1&lt;/code&gt; (synced in the vendor&apos;s cloud) or &lt;code&gt;BE=0, BS=0&lt;/code&gt; (device-bound to the local install).&lt;/p&gt;
&lt;p&gt;A plug-in supplies the credential. But the &lt;em&gt;attestation statement&lt;/em&gt; on registration tells the relying party &lt;em&gt;what kind of credential it is&lt;/em&gt;. That&apos;s a separate API surface -- what shapes does it come in?&lt;/p&gt;
&lt;h2&gt;11. The seven attestation conveyance formats&lt;/h2&gt;
&lt;p&gt;The IANA WebAuthn registry lists seven format identifiers for the &lt;em&gt;attestation statement&lt;/em&gt; a registration ceremony can produce [@iana-webauthn-registry]. The registry is reachable via RFC 8809 (Hodges, Mandyam, M.B. Jones, August 2020) [@rfc8809] and the canonical normative definitions are in WebAuthn Level 2 §§8.2-8.8 [@webauthn-l2-latest], whose dated Recommendation is at &lt;code&gt;REC-webauthn-2-20210408&lt;/code&gt; [@webauthn-l2-rec]. The seven, in registry order: &lt;code&gt;packed&lt;/code&gt;, &lt;code&gt;tpm&lt;/code&gt;, &lt;code&gt;android-key&lt;/code&gt;, &lt;code&gt;android-safetynet&lt;/code&gt;, &lt;code&gt;fido-u2f&lt;/code&gt;, &lt;code&gt;apple&lt;/code&gt;, and &lt;code&gt;none&lt;/code&gt;. Each is one option a relying party can require, accept, or ignore.&lt;/p&gt;

The mechanism by which a WebAuthn registration ceremony optionally produces a signature over the new credential&apos;s public key (and `authenticatorData` containing the `rpIdHash`), chained to a vendor or platform root. The relying party validates the chain to establish that the new credential&apos;s private key is held by a specific authenticator model or certification level. Attestation is distinct from authentication; attestation runs once at registration, authentication runs every sign-in. The WebAuthn `attestation` parameter on registration controls whether the RP asks for an attestation statement at all (values: `none`, `indirect`, `direct`, `enterprise`).
&lt;p&gt;The table below summarises what each format teaches the relying party.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;What the RP verifies&lt;/th&gt;
&lt;th&gt;Trust anchor required&lt;/th&gt;
&lt;th&gt;Criterion strengthened&lt;/th&gt;
&lt;th&gt;Current adoption&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;packed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Signature over &lt;code&gt;authenticatorData || clientDataHash&lt;/code&gt; by batch attestation key or self-attestation key&lt;/td&gt;
&lt;td&gt;Vendor X.509 cert chain or none (self)&lt;/td&gt;
&lt;td&gt;Verifier-compromise (model identity), optional anti-fraud&lt;/td&gt;
&lt;td&gt;Default for most CTAP2 keys; dominant in production&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tpm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;TPM 2.0 &lt;code&gt;TPM2_Certify&lt;/code&gt;-style quote over the new credential public key&lt;/td&gt;
&lt;td&gt;AIK / EK chain to TPM vendor root&lt;/td&gt;
&lt;td&gt;Verifier-compromise + device-bound storage&lt;/td&gt;
&lt;td&gt;Windows platform-bound passkeys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;android-key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Android Keystore attestation chain&lt;/td&gt;
&lt;td&gt;Google-rooted hardware-attestation CA&lt;/td&gt;
&lt;td&gt;Verifier-compromise + StrongBox / TEE residency&lt;/td&gt;
&lt;td&gt;Android platform passkeys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;android-safetynet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SafetyNet API-derived attestation token&lt;/td&gt;
&lt;td&gt;Google SafetyNet CA&lt;/td&gt;
&lt;td&gt;Legacy; declining&lt;/td&gt;
&lt;td&gt;Legacy Android; SafetyNet deprecation announced June 2022; migration deadline end of January 2024; complete shutdown end of January 2025&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fido-u2f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ECDSA P-256 signature with vendor X.509 cert&lt;/td&gt;
&lt;td&gt;Vendor U2F-era cert&lt;/td&gt;
&lt;td&gt;Verifier-compromise (legacy)&lt;/td&gt;
&lt;td&gt;Legacy U2F-era hardware keys; declining&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apple&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Anonymous Apple-issued attestation chain&lt;/td&gt;
&lt;td&gt;Apple anonymous-attestation CA&lt;/td&gt;
&lt;td&gt;Verifier-compromise without device de-anonymisation&lt;/td&gt;
&lt;td&gt;Apple platform passkeys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No attestation; credential public key plus AAGUID only&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;The default for synced-passkey consumer flows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A few of these deserve a paragraph each.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;packed&lt;/code&gt;&lt;/strong&gt; is the spec default and the most widely deployed. The authenticator emits one signature over the concatenation of &lt;code&gt;authenticatorData&lt;/code&gt; and a hash of &lt;code&gt;clientDataJSON&lt;/code&gt;, using one of three keys: (a) a per-authenticator-model &lt;em&gt;batch attestation key&lt;/em&gt; whose X.509 chain anchors to the vendor&apos;s attestation root (the privacy-vs-anti-fraud trade-off -- the cert reveals the device model, but not which specific user owns which device); (b) an &lt;em&gt;Anonymisation CA&lt;/em&gt; or Enterprise Attestation key, which lets a managed enterprise distinguish its own devices without leaking that information to consumer relying parties; or (c) a &lt;em&gt;self-attestation&lt;/em&gt; key derived from the credential itself, which proves only that the private key signs and makes no identity claim.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;tpm&lt;/code&gt;&lt;/strong&gt; is the format the Windows platform authenticator emits when the user has a TPM 2.0. The signing object is a TPM &lt;code&gt;TPM2_Quote&lt;/code&gt;-style structure with the TPM&apos;s Attestation Identity Key (AIK), chained back to the TPM vendor&apos;s Endorsement Key (EK) root certificate. This is the most cryptographically opinionated attestation in the registry: it proves the credential is held by a specific TPM vendor&apos;s part. The Windows TPM article in this series walks the AIK / EK chain end to end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;apple&lt;/code&gt;&lt;/strong&gt; is Apple&apos;s anonymous-attestation design. The X.509 chain ends in an Apple anonymous-attestation CA; cryptographically the relying party can verify the cert chain back to Apple&apos;s root, but the cert itself is engineered to not reveal the user&apos;s specific device. This is the privacy-vs-anti-fraud trade-off resolved in favour of privacy: a relying party gets &quot;this came from a real Apple device&quot; without learning &lt;em&gt;which&lt;/em&gt; Apple device.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;android-safetynet&lt;/code&gt;&lt;/strong&gt; is the legacy format that lots of installed-base Android passkeys still use. Google announced the SafetyNet Attestation API&apos;s deprecation in June 2022 in favour of Play Integrity; the migration deadline was extended to end of January 2024, with complete shutdown landing end of January 2025 [@android-safetynet-deprecation]. Any new Android passkey registered in 2025 or later uses &lt;code&gt;android-key&lt;/code&gt; or &lt;code&gt;none&lt;/code&gt; instead. Relying parties with old &lt;code&gt;android-safetynet&lt;/code&gt; credentials in their database must accept both formats during the transition window; new credentials use the new path.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;fido-u2f&lt;/code&gt;&lt;/strong&gt; is the U2F-era legacy format, descended directly from the December 2014 U2F design [@fido-u2f-overview]. ECDSA P-256 signing key plus a vendor X.509 cert. Modern keys still emit it for U2F-mode CTAP1 ceremonies, but every modern CTAP2 ceremony uses &lt;code&gt;packed&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;none&lt;/code&gt;&lt;/strong&gt; is the most-deployed format in &lt;em&gt;consumer&lt;/em&gt; flows -- and the recommended default for any relying party that does not have a specific anti-fraud requirement. The RP asks for &lt;code&gt;attestation: &quot;none&quot;&lt;/code&gt;; the authenticator returns just the credential public key and the AAGUID, with no signature chain. The privacy benefit is real: attestation deanonymises the user&apos;s device by model, and a relying party that does not need that information should not collect it. The 2024-2026 best practice is &lt;code&gt;attestation: &quot;none&quot;&lt;/code&gt; for consumer passkey flows. NIST SP 800-63B-4 (final) inherits this caution [@sp80063b4-html].&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Use &lt;code&gt;attestation: &quot;none&quot;&lt;/code&gt; for consumer flows; the privacy cost of &lt;code&gt;direct&lt;/code&gt; outweighs the anti-fraud benefit for low-value accounts. Use &lt;code&gt;attestation: &quot;direct&quot;&lt;/code&gt; only when (a) you have a documented anti-fraud requirement, (b) you can verify the chain against the FIDO Metadata Service, and (c) you accept that the cert reveals the authenticator model. Use &lt;code&gt;attestation: &quot;enterprise&quot;&lt;/code&gt; only inside a managed enterprise where the user&apos;s device is corporately enrolled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All seven formats assume the authenticator is &lt;em&gt;on the same device&lt;/em&gt; as the browser. What happens when it isn&apos;t?&lt;/p&gt;
&lt;h2&gt;12. Hybrid transport: a phone authenticator for a laptop browser&lt;/h2&gt;
&lt;p&gt;A user on a borrowed Windows laptop with no Windows passkey signs in to their bank by scanning a QR code with their iPhone. The phone is the authenticator. The laptop is the WebAuthn client. The protocol that ties them together is &lt;em&gt;hybrid transport&lt;/em&gt;, formerly known as caBLE (Cloud-Assisted Bluetooth Low Energy), standardised in W3C WebAuthn Level 3 §6.3.3 [@webauthn-l3-cr].&lt;/p&gt;

A WebAuthn transport in which a roaming authenticator (typically a mobile phone) cooperates with a WebAuthn client on a nearby device (typically a laptop) via three concurrent channels: an out-of-band channel (QR code) for one-time setup, BLE for proximity, and HTTPS to a discoverable cloud tunnel relay for the actual ceremony bytes. The cryptographic binding is an ephemeral ECDH key exchanged through the QR code; the BLE proves proximity, not identity; the tunnel relay carries the encrypted ceremony [@webauthn-l3-cr-dated].
&lt;p&gt;The ceremony, simplified: the laptop&apos;s browser asks the user to use a phone, generates an ephemeral ECDH keypair, and renders a QR code containing the Tunnel Service URL the phone should connect to, the laptop&apos;s ephemeral public key, and a derived HMAC key. The phone&apos;s camera scans the QR code and derives a shared secret with the laptop via ECDH. The phone then advertises its presence over BLE, the laptop listens for the BLE beacon to confirm physical proximity, and both endpoints connect to the Tunnel Service URL over HTTPS. From that point on, the laptop and the phone exchange CTAP2 ceremony messages, encrypted under the ECDH-derived key, through the tunnel relay. The phone produces a WebAuthn assertion locally using whatever authenticator is on the phone (the Secure Enclave on iPhone, the Android Keystore on Android), encrypts it for the laptop, and the laptop forwards it to the relying party.&lt;/p&gt;

sequenceDiagram
    participant U as User
    participant L as Laptop browser
    participant P as Phone authenticator
    participant T as Tunnel Service
    participant R as Relying Party
    L-&amp;gt;&amp;gt;R: navigator.credentials.get
    R-&amp;gt;&amp;gt;L: PublicKeyCredentialRequestOptions
    L-&amp;gt;&amp;gt;L: generate ephemeral ECDH keypair
    L-&amp;gt;&amp;gt;U: display QR code (tunnel URL, ephem pubkey, HMAC seed)
    U-&amp;gt;&amp;gt;P: scan QR code
    P-&amp;gt;&amp;gt;P: derive shared secret via ECDH
    P-&amp;gt;&amp;gt;L: BLE advertisement (proximity proof)
    L-&amp;gt;&amp;gt;L: confirm BLE advertisement
    P-&amp;gt;&amp;gt;T: HTTPS connect to tunnel URL
    L-&amp;gt;&amp;gt;T: HTTPS connect to tunnel URL
    T-&amp;gt;&amp;gt;L: relay encrypted CTAP2 traffic
    T-&amp;gt;&amp;gt;P: relay encrypted CTAP2 traffic
    P-&amp;gt;&amp;gt;U: prompt for user verification
    U-&amp;gt;&amp;gt;P: present gesture
    P-&amp;gt;&amp;gt;P: produce WebAuthn assertion (origin-bound)
    P-&amp;gt;&amp;gt;T: encrypted assertion
    T-&amp;gt;&amp;gt;L: encrypted assertion
    L-&amp;gt;&amp;gt;R: assertion
    R-&amp;gt;&amp;gt;U: signed in
&lt;p&gt;The criterion-table consequence is precise. Phishing resistance is preserved because the &lt;em&gt;origin&lt;/em&gt; in &lt;code&gt;clientDataJSON&lt;/code&gt; is the laptop&apos;s actual browser origin, which the phone signs over the same way it would for its own browser. The QR code is the cryptographic binding, not the BLE advertisement; the BLE advertisement is a proximity signal that proves the phone is physically near the laptop, but it does not authenticate the phone. The Tunnel Service is a &lt;em&gt;relay&lt;/em&gt;, not a trust anchor; even if the tunnel were compromised, the encrypted ceremony bytes would be unreadable without the ECDH-derived key.&lt;/p&gt;
&lt;p&gt;The design is attributed in the WebAuthn L3 spec to the W3C WebAuthn-3 editor masthead -- Jeff Hodges, J.C. Jones, Michael B. Jones, Akshay Kumar, and Emil Lundberg as current editors, with Dirk Balfanz as a previous editor [@wiki-webauthn]. The original caBLE design and the L3 §6.3.3 productisation were led by Google&apos;s Chrome security and Android Identity teams; the canonical reference is W3C WebAuthn Level 3 §6.3.3 itself.&lt;/p&gt;
&lt;p&gt;Hybrid transport is the only competitor to the Windows platform authenticator that involves no Windows-side credential storage. The Windows laptop holds nothing -- no key, no recovery state, no cached credential. Every ceremony round-trips to the phone. This is the use case the bank-on-a-borrowed-laptop story illustrates: you can sign in to your accounts on a machine you do not own without leaving a credential behind.&lt;/p&gt;
&lt;p&gt;How do other authentication approaches score on the criteria framework?&lt;/p&gt;
&lt;h2&gt;13. Competing approaches scored against the criteria&lt;/h2&gt;
&lt;p&gt;The criteria-framework table makes the competitive field legible. Five rows, six competing columns: password alone, password plus SMS-OTP, password plus TOTP, password plus push with number matching, smart card / PIV, and device-bound or synced passkey. The NIST SP 800-63B-4 AAL grading [@sp80063b4-html] and the NIST syncable-authenticator supplement [@sp80063sup1] anchor the right edge of the table; Yubico&apos;s commentary corroborates the dichotomy between device-bound (AAL3) and synced (AAL2) passkeys [@yubico-nist-guidance].&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;Password&lt;/th&gt;
&lt;th&gt;Password + SMS-OTP&lt;/th&gt;
&lt;th&gt;Password + TOTP&lt;/th&gt;
&lt;th&gt;Password + Push (number match)&lt;/th&gt;
&lt;th&gt;Smart Card / PIV&lt;/th&gt;
&lt;th&gt;Device-bound passkey&lt;/th&gt;
&lt;th&gt;Synced passkey&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Phishing resistance&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None (AitM relays the OTP)&lt;/td&gt;
&lt;td&gt;None (AitM relays the TOTP)&lt;/td&gt;
&lt;td&gt;Partial (number match defeats most kits)&lt;/td&gt;
&lt;td&gt;Strong (origin-bound via TLS client auth)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strong&lt;/strong&gt; (&lt;code&gt;rpId&lt;/code&gt; binding)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strong&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verifier-compromise resistance&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None (SMS infra leaks)&lt;/td&gt;
&lt;td&gt;Partial (TOTP seed on server)&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Strong (public-key only)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strong&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strong&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replay / relay resistance&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Weak (OTP relay in 30-60 s)&lt;/td&gt;
&lt;td&gt;Weak (TOTP relay in 30 s)&lt;/td&gt;
&lt;td&gt;Strong (number match per challenge)&lt;/td&gt;
&lt;td&gt;Strong (per-handshake nonce)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strong&lt;/strong&gt; (challenge + counter)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strong&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Step-up / continuity&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Strong (PIN re-prompt)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strong&lt;/strong&gt; (&lt;code&gt;UV=1&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strong&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recovery floor&lt;/td&gt;
&lt;td&gt;Reset via SMS&lt;/td&gt;
&lt;td&gt;SMS-OTP all the way down&lt;/td&gt;
&lt;td&gt;TOTP seed reset via SMS&lt;/td&gt;
&lt;td&gt;SMS / password&lt;/td&gt;
&lt;td&gt;Admin re-issue&lt;/td&gt;
&lt;td&gt;RP-dependent backup key&lt;/td&gt;
&lt;td&gt;Sync-fabric recovery (Recovery Key + Recovery Contact)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NIST AAL ceiling&lt;/td&gt;
&lt;td&gt;AAL1&lt;/td&gt;
&lt;td&gt;AAL2 nominal (SMS-OTP RESTRICTED in 800-63-3 [@nist-sp80063-3-final]; deprecated in 800-63-4 [@sp80063-4-final])&lt;/td&gt;
&lt;td&gt;AAL2&lt;/td&gt;
&lt;td&gt;AAL2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AAL3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AAL3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AAL2&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Push MFA needs a paragraph of nuance. Vanilla push -- &quot;tap to approve&quot; -- is phishable by default because the attacker can simply trigger the push at the moment they have the password, and a fatigued user taps. Number matching (the user types a code shown on the laptop into the phone, or vice versa) defeats most kits because it ties the push to a specific session. &lt;em&gt;Location binding&lt;/em&gt; (the push is rejected unless the phone is geographically near the laptop) adds another layer. The net is &quot;partial&quot; phishing resistance -- much better than vanilla push, not as strong as origin binding.&lt;/p&gt;
&lt;p&gt;Smart cards and PIV deserve their own paragraph because they are not historically associated with WebAuthn but score well on the criteria. A PIV card with a PIN provides strong phishing resistance via TLS client authentication (origin-bound at the TLS layer), strong verifier-compromise resistance via the public-key model, and strong replay resistance via per-handshake nonces. The weakness is &lt;em&gt;recovery&lt;/em&gt;: a lost card requires an administrative reissue, which scales poorly for consumer flows. The companion &lt;em&gt;App Identity in Windows&lt;/em&gt; article in this series walks the Windows smart-card stack end to end.&lt;/p&gt;
&lt;p&gt;OATH-TOTP is interesting in the criteria table because it is phishing-vulnerable by construction. The TOTP code is the same on the legitimate origin and the look-alike; the AitM kit forwards the code through. Google Authenticator&apos;s cloud-sync feature additionally broke the verifier-compromise property in a subtle way: if the user&apos;s Google account is compromised, the synced TOTP seeds give the attacker a complete second-factor toolkit [@google-auth-sync-2023].&lt;/p&gt;
&lt;p&gt;SAML and OIDC federation are not competitors to WebAuthn in the criteria table -- they are &lt;em&gt;transport layers above&lt;/em&gt; WebAuthn. A SAML or OIDC identity provider does the WebAuthn ceremony for the user; the IdP then issues a SAML assertion or an OIDC ID token to the relying party. WebAuthn underneath is the strong primitive; SAML and OIDC are the enterprise transport for the resulting assertions.&lt;/p&gt;
&lt;p&gt;WebAuthn wins decisively on four of five rows. What&apos;s left in row five? The recovery row.&lt;/p&gt;
&lt;h2&gt;14. Theoretical limits: the corners WebAuthn cannot reach&lt;/h2&gt;
&lt;p&gt;Even with everything from §§4-12 in place, WebAuthn has corners it cannot defend. The relevant impossibility results are well-known in the protocol literature; they are worth naming because they tell a practitioner where defence-in-depth has to come from.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Coerced consent.&lt;/strong&gt; WebAuthn cannot distinguish a willing user from a coerced one. The protocol&apos;s only signal is &quot;the user performed the gesture&quot; -- a fingerprint, a PIN, a face match. No protocol whose only observable is gesture completion can tell whether the user was free at the moment of the gesture. NIST SP 800-63B-4 does not classify physical coercion among the attacks it defends against [@sp80063b4-html]; this is a general impossibility, not a WebAuthn-specific weakness.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A user under duress can be made to present a gesture. WebAuthn cannot detect this. The compensating control is &lt;em&gt;transactional&lt;/em&gt; -- step-up authentication with a fresh challenge for high-value actions, and out-of-band confirmation for transactions above a risk threshold. The protocol cannot solve coercion; the application layer must.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Kernel-level malware on the client.&lt;/strong&gt; Malware with kernel privilege on the user&apos;s device can race the legitimate user. If the malware can call into &lt;code&gt;webauthn.dll&lt;/code&gt; and trigger a Hello UV prompt the user blindly approves, it can extract assertions. The mitigation is TPM-bound keys plus the Hello ESS trustlet (covered in the companion &lt;em&gt;Windows Hello&lt;/em&gt; and &lt;em&gt;Credential Guard&lt;/em&gt; articles), not WebAuthn itself. WebAuthn protects against &lt;em&gt;network&lt;/em&gt; attackers; defending against a kernel-mode attacker on the same device requires the OS&apos;s secure-kernel architecture.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sync-fabric compromise.&lt;/strong&gt; Compromise of Apple iCloud, Google account recovery, or Microsoft&apos;s recovery-key service effectively compromises every passkey held there. Apple&apos;s Advanced Data Protection model [@apple-adp-kb] is the strongest currently-shipped consumer realisation of the end-to-end-encrypted sync invariant, and even it depends on the user retaining their Recovery Contact or Recovery Key in some form. The NIST April 2024 supplement classifies synced passkeys at AAL2 for exactly this reason: the private key leaves the original authenticator [@sp80063sup1]. Yubico&apos;s commentary makes the practitioner consequence explicit: device-bound is AAL3, synced is AAL2 [@yubico-nist-guidance].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Username enumeration and discoverable-credential privacy.&lt;/strong&gt; Discoverable credentials let an authenticator answer &quot;do you have a credential for this &lt;code&gt;rpId&lt;/code&gt;?&quot; without further information. A relying party that asks the question maliciously can enumerate which of its users have set up a passkey. The &lt;code&gt;credProtect&lt;/code&gt; extension introduced in CTAP 2.1 [@ctap-2-1-ps] requires &lt;code&gt;UV=1&lt;/code&gt; to even list the credential, which closes most of the leak; it is not universally deployed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Counter-regression false positives on synced passkeys.&lt;/strong&gt; The per-credential signature counter is per-authenticator. A passkey synced across two devices will see the counter desynchronise between them. WebAuthn L3 §6.1.1 explicitly permits a &lt;em&gt;zero-counter&lt;/em&gt; for synced passkeys; relying parties that treat any counter regression as evidence of cloning will produce false positives. Treat counter regression as evidence of cloning &lt;em&gt;only&lt;/em&gt; for &lt;code&gt;BS=0&lt;/code&gt; (device-bound) credentials. This is a deployment foot-gun, not a protocol flaw.&lt;/p&gt;

flowchart LR
    A[rpId binding / origin in clientDataJSON] --&amp;gt; P[Phishing resistance]
    B[Public-key model / no shared secret] --&amp;gt; V[Verifier-compromise resistance]
    C[Per-RP challenge + signCount + BS=0] --&amp;gt; RR[Replay / relay resistance]
    D[UP and UV flags + freshness] --&amp;gt; S[Step-up / continuity]
    E[BE / BS flags + sync fabric] --&amp;gt; AV[Availability]
    F[Recovery Key + Recovery Contact] --&amp;gt; RC[Recovery]
    G[TPM 2.0 / hardware secure element] --&amp;gt; AAL[AAL3 device-bound]
    H[End-to-end encrypted sync fabric] --&amp;gt; AAL2[AAL2 synced]
&lt;p&gt;These are the &lt;em&gt;protocol&lt;/em&gt; limits. The biggest practical limit is one the protocol cannot fix at all -- recovery. The protocol can specify what factor produces the credential at sign-in; it cannot specify what factor produces the credential when the original one is lost. That is the application-layer question every relying party answers differently, and it is the question §17 will land on.&lt;/p&gt;
&lt;h2&gt;15. Open problems: what&apos;s still moving in late 2025 / early 2026&lt;/h2&gt;
&lt;p&gt;Standardisation is not done. Several major surfaces are still in active draft.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WebAuthn Level 3&lt;/strong&gt; is currently a W3C Candidate Recommendation [@webauthn-l3-cr]; the dated CR snapshot is 13 January 2026 [@webauthn-l3-cr-dated]. The expected progression is Candidate Recommendation to Proposed Recommendation to Recommendation through 2026, with no major spec-breaking changes expected at this point in the process. The active editor masthead is Hodges, J.C. Jones, M.B. Jones, Kumar, and Lundberg [@wiki-webauthn].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CTAP 2.2&lt;/strong&gt; is a FIDO Proposed Standard as of 14 July 2025 [@ctap-2-2-ps]; &lt;strong&gt;CTAP 2.3&lt;/strong&gt; is also listed at FIDO&apos;s specifications download page [@fido-specs-download]. The 2.2 and 2.3 revisions refine hybrid transport, &lt;code&gt;credProtect&lt;/code&gt;, and PIN-protocol handling without breaking 2.1&apos;s command-byte table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cross-vendor passkey portability.&lt;/strong&gt; The FIDO Alliance &lt;em&gt;Credential Exchange Protocol&lt;/em&gt; (CXP) and &lt;em&gt;Credential Exchange Format&lt;/em&gt; (CXF) Working Drafts, dated 3 October 2024 [@fido-cxp-wd], are the standards effort. The draft text identifies the problem: &quot;the transfer of credentials between two different providers has traditionally been an infrequent occurrence... As it becomes more common for users to have multiple credential providers that they use to create [and] manage credentials, it becomes important to address some of the security concerns with regard to migration&quot; [@fido-cxp-wd]. Apple has signalled CXP-based import for iOS; Bitwarden has signalled support. The likely 2026 trajectory is CXP becoming a Proposed Standard and Windows / Android / iOS implementing it as the OS-level import-export passkeys surface.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transactional authorisation.&lt;/strong&gt; The earliest WebAuthn drafts included &lt;code&gt;txAuthSimple&lt;/code&gt; and &lt;code&gt;txAuthGeneric&lt;/code&gt; extensions [@webauthn-fpwd]; neither was ever implemented by browsers, and both are absent from L3. The productised path is Secure Payment Confirmation (a sibling spec to WebAuthn), but it covers only payment transactions. General &quot;sign a description of &lt;em&gt;this transaction&lt;/em&gt;&quot; remains an open problem. Conjecture: payment-confirmation becomes the template that gets generalised in WebAuthn Level 4.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quantum-safe attestation.&lt;/strong&gt; The IANA COSE algorithm registry (last updated 2026-03-04) currently has no PQC algorithm in WebAuthn-recommended status [@iana-cose-registry]. ECDSA P-256, EdDSA Ed25519, RSA-PKCS1.5, and RSA-PSS are the registered options, all quantum-breakable in principle. A long-lived TPM AIK signed today is forgeable to a quantum-capable adversary at any future date. The companion &lt;em&gt;Post-Quantum Cryptography on Windows&lt;/em&gt; article in this series walks the algorithm-side rollout; the WebAuthn deployment side is open. The most plausible trajectory is ML-DSA (FIPS 204) entering the WebAuthn COSE registry by 2027 and existing TPM AIKs receiving a parallel ML-DSA enrolment.&lt;/p&gt;
&lt;p&gt;Standards are still moving. What should a practitioner do &lt;em&gt;today&lt;/em&gt;?&lt;/p&gt;
&lt;h2&gt;16. Practical guide: what to do this week&lt;/h2&gt;
&lt;p&gt;Six pieces of operational advice, each tied to a primary source.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Windows developers: use &lt;code&gt;webauthn.dll&lt;/code&gt;, do not roll your own.&lt;/strong&gt; The Win32 reference at &lt;code&gt;learn.microsoft.com/en-us/windows/win32/api/webauthn/&lt;/code&gt; [@ms-learn-win32-webauthn] is the only surface you should be calling. The OS handles USB-HID, NFC, BLE, hybrid transport, Conditional Mediation, plug-in dispatch, and Windows Hello UV in one call. The header is at &lt;code&gt;github.com/microsoft/webauthn&lt;/code&gt; [@github-ms-webauthn]; the Microsoft Learn overview is at &lt;code&gt;learn.microsoft.com/.../hello-for-business/webauthn-apis&lt;/code&gt; [@ms-learn-webauthn-apis].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Relying parties: default to &lt;code&gt;attestation: &quot;none&quot;&lt;/code&gt;, &lt;code&gt;userVerification: &quot;required&quot;&lt;/code&gt;, &lt;code&gt;residentKey: &quot;preferred&quot;&lt;/code&gt;.&lt;/strong&gt; This is the 2024-2026 consumer-flow baseline. &lt;code&gt;attestation: &quot;none&quot;&lt;/code&gt; preserves user privacy and interoperates with every authenticator type. &lt;code&gt;userVerification: &quot;required&quot;&lt;/code&gt; forces &lt;code&gt;UV=1&lt;/code&gt; and the gesture acquisition. &lt;code&gt;residentKey: &quot;preferred&quot;&lt;/code&gt; enables usernameless sign-in on platforms that support it without burning a credential slot on older authenticators that don&apos;t. The Microsoft Entra passwordless documentation [@ms-entra-passwordless] and the WebAuthn Level 3 spec [@webauthn-l3-cr] are the references.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Enterprise IT: device-bound FIDO2 keys for AAL3 (admin, finance, tier 0); synced passkeys for AAL2 workforce.&lt;/strong&gt; NIST SP 800-63B-4 [@sp80063b4-html] formalises the dichotomy via the syncable-authenticator supplement [@sp80063sup1]. Yubico&apos;s enterprise commentary makes the operational point: device-bound passkeys on dedicated hardware are AAL3; synced passkeys are AAL2 [@yubico-nist-guidance]. For admin accounts use FIDO Alliance L3-certified hardware [@fido-certification-levels] -- YubiKey Bio, Feitian BioPass, the Entra-listed vendors at &lt;code&gt;learn.microsoft.com/.../concept-fido2-hardware-vendor&lt;/code&gt; [@ms-entra-fido2-hardware].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Windows 11 24H2 end users: enable third-party passkey providers in Settings.&lt;/strong&gt; Settings -&amp;gt; Accounts -&amp;gt; Passkeys -&amp;gt; Advanced options. Toggle the provider on for any vendor you trust (1Password, Bitwarden, Dashlane) [@ms-windev-passkeys-blog]. The Microsoft Learn third-party tutorial walks the flow [@ms-learn-thirdparty]. If you do not use a third-party vault, the Microsoft synced passkey provider is enabled by default on 24H2 systems signed in with a Microsoft Account.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. Security architects: write down your recovery flow first.&lt;/strong&gt; Score it against the five-axis criteria table from §2 before you design the authentication factors. The recovery row&apos;s strength is the system&apos;s ceiling, not the floor; the authentication ceremony cannot raise it. Microsoft Entra&apos;s own guidance flags account recovery as a deployment risk: FIDO2 keys &quot;can increase costs for equipment, training, and helpdesk support -- especially when users lose their physical keys and need account recovery&quot; [@ms-entra-passwordless]. §17 lands this argument.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. Incident responders: collect ETW events from the WebAuthn provider.&lt;/strong&gt; Plug-in authenticator registration events on managed devices are a high-signal indicator -- a newly enrolled &lt;code&gt;IPluginAuthenticator&lt;/code&gt; on a privileged user&apos;s machine should be treated as a credential-store change requiring review. The companion &lt;em&gt;ETW on Windows&lt;/em&gt; article in this series walks the WebAuthn provider events end to end.&lt;/p&gt;

Open PowerShell as the signed-in user (no admin needed for your own credentials) and call into the `webauthn.dll` `WebAuthNGetPlatformCredentialList` API via a managed wrapper, or use the Settings -&amp;gt; Accounts -&amp;gt; Passkeys page directly. There is no first-class `Get-WebAuthnCredential` cmdlet as of Windows 11 25H2; the Settings page is the supported management surface. The Microsoft Learn passkey overview is the canonical reference [@ms-learn-passkeys].
&lt;p&gt;Most of this is engineering. One row of the table has resisted engineering for fifty years. That&apos;s where the article lands.&lt;/p&gt;
&lt;h2&gt;17. Recovery: your weakest factor is always your recovery flow&lt;/h2&gt;
&lt;p&gt;The thesis surfaced in §2 and deferred through twelve sections is the one the article lands on. The argument is direct, almost embarrassingly so: every authentication system that admits any external recovery primitive is, in the formal sense, at most as strong as that primitive. Strong authentication ceremonies coexist with weaker recovery ceremonies in every consumer platform in production, and the &lt;em&gt;system&apos;s&lt;/em&gt; assurance level is the minimum of the two, not the maximum.&lt;/p&gt;

*Your weakest factor is always your recovery flow.*
&lt;p&gt;To make the claim concrete, score every major platform&apos;s recovery flow against the same five-axis criteria table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Apple iCloud Keychain (with Advanced Data Protection).&lt;/strong&gt; Apple&apos;s published model has three recovery primitives [@apple-adp-kb]: (a) a &lt;em&gt;trusted device&lt;/em&gt; the user previously signed into; (b) an &lt;em&gt;iCloud Recovery Contact&lt;/em&gt; -- another Apple ID owner the user has nominated to attest their identity; and (c) an &lt;em&gt;iCloud Recovery Key&lt;/em&gt; -- a 28-character string the user must retain [@apple-recovery-key]. Apple&apos;s published architecture is the strongest current consumer realisation of the end-to-end-encrypted invariant: the recovery primitives unlock an HSM-backed escrow cluster that holds the user&apos;s iCloud Keychain encryption material, but Apple itself does not hold the keys in plaintext. The fundamental dependency is the Apple ID password plus, originally, SMS-OTP at device-trust establishment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Google Password Manager (with Google Account end-to-end encrypted passkey sync).&lt;/strong&gt; Trusted-device fallback, security-key fallback, recovery code, recovery phone, recovery email. The recovery floor reduces, in the worst case, to SMS-OTP via the recovery phone. Google&apos;s architecture is end-to-end encrypted in the steady state but the trust establishment depends on Google account recovery, which depends on out-of-band verification primitives the user enrolled at account creation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microsoft Account.&lt;/strong&gt; The October 2024 Windows Developer Blog states the recovery primitive verbatim: &quot;you will be prompted to save a recovery key that will be used to verify your identity and protect your passkeys through end-to-end encryption&quot; [@ms-windev-passkeys-blog]. The recovery key is a high-entropy string the user retains; if they lose it, the recovery flow falls back to the secondary factors the user enrolled (alternate email or SMS-OTP via the recovery phone). As with Google, the worst-case recovery floor is the weakest of the secondary factors the user enrolled.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microsoft Entra ID (enterprise).&lt;/strong&gt; Entra&apos;s Temporary Access Pass (TAP) is the strongest enterprise recovery primitive currently shipped: an administrator issues a time-bound passwordless TAP that the user redeems to bootstrap a new authenticator. TAP is stronger than consumer flows because of &lt;em&gt;accountability&lt;/em&gt; -- the admin&apos;s identity is on the issuance -- but weaker than the authentication ceremony itself because the admin is socially engineerable. Microsoft documents the TAP issuance and redemption flow in detail [@ms-entra-tap].&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1Password, Bitwarden, Dashlane under the 24H2 plug-in model.&lt;/strong&gt; Each vendor&apos;s master password and secondary recovery primitive becomes the &lt;em&gt;de facto&lt;/em&gt; floor of the entire passkey ceremony when the plug-in is the credential store. 1Password&apos;s master password plus Secret Key, Bitwarden&apos;s master password plus 2FA recovery code, and Dashlane&apos;s device trust plus master password -- each is the recovery floor for every passkey the vault holds. The Microsoft Learn third-party tutorial reinforces the warning, in context: &quot;Contoso Passkey Manager is designed for passkey creation and usage testing only. Don&apos;t use the app for production passkeys&quot; [@ms-learn-thirdparty].&lt;/p&gt;

flowchart TD
    A[Apple iCloud Keychain ADP] --&amp;gt; A1[Recovery Contact]
    A --&amp;gt; A2[Recovery Key 28 chars]
    A --&amp;gt; A3[Trusted device]
    A3 --&amp;gt; A4[Apple ID password + SMS-OTP at trust establishment]
    B[Google Password Manager] --&amp;gt; B1[Recovery code]
    B --&amp;gt; B2[Recovery phone]
    B --&amp;gt; B3[Recovery email]
    B2 --&amp;gt; B4[SMS-OTP]
    C[Microsoft Account] --&amp;gt; C1[Recovery Key]
    C --&amp;gt; C3[Alternate email]
    C --&amp;gt; C4[Recovery phone -&amp;gt; SMS-OTP]
    D[Entra ID enterprise] --&amp;gt; D1[Temporary Access Pass]
    D1 --&amp;gt; D2[Admin: socially engineerable]
    E[1Password / Bitwarden / Dashlane vault] --&amp;gt; E1[Master password + Secret Key / 2FA recovery code]
    A4 --&amp;gt; Z[Weak shared-knowledge or SMS-OTP floor]
    B4 --&amp;gt; Z
    C4 --&amp;gt; Z
    D2 --&amp;gt; Z
    E1 --&amp;gt; Z
&lt;p&gt;The diagram looks busy because it is. Every major platform&apos;s recovery flow is a different combination of trusted-device fallback, recovery code or key, recovery contact, and an out-of-band primitive (SMS-OTP, email, or admin attestation). Every one of those out-of-band primitives is weaker than origin-bound public-key cryptography. The cryptographic ceremony scores AAL3 phishing-resistant at the authentication moment; the recovery primitive scores AAL1 or AAL2 at the recovery moment. &lt;em&gt;The system&apos;s AAL is the minimum.&lt;/em&gt;&lt;/p&gt;

NIST SP 800-63B-4&apos;s AAL2 / AAL3 split makes the recovery story explicit. Section 5.1 of SP 800-63B-4 enumerates permitted recovery primitives; every one is at most as strong as its underlying factor. The April 2024 supplement [@sp80063sup1] caps synced passkeys at AAL2 because the long-term private key has left the original authenticator -- the same logic that caps the recovery row applies to the sync fabric. Auditors who care about AAL3 for tier-zero accounts will require *both* a device-bound authenticator and a documented recovery flow whose own strength is at AAL3. The current best-practice composition is two device-bound hardware authenticators in different physical locations, each registered as primary for the other&apos;s recovery.
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key idea:&lt;/strong&gt; Every passkey platform in production in 2026 -- Apple, Google, Microsoft, Entra, 1Password, Dashlane, Bitwarden -- bottoms out, in its recovery flow, in some combination of trusted-device fallback and SMS-OTP-equivalent shared knowledge. That floor is the AAL ceiling for the entire system.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The protocol literature has been clear about this for fifty years and the regulatory literature has been catching up since 2017. NIST SP 800-63-3 introduced &quot;phishing-resistant authenticator&quot; as a first-class term; SP 800-63-4 (2025) [@sp80063-4-final] makes verifier-impersonation resistance a normative criterion. Neither standard solves recovery; both standards explicitly enumerate what counts as a recovery primitive without specifying how to &lt;em&gt;compose&lt;/em&gt; them into an AAL-graded flow. There is no IETF or FIDO Alliance standard that says &quot;here is a recovery flow whose strength is AAL3.&quot; There may never be -- recovery is application-specific, and the only general protocol is &quot;social attestation&quot; (multiple human witnesses), which does not scale.&lt;/p&gt;
&lt;p&gt;The same WebAuthn ceremony that scores AAL3 phishing-resistant at the authentication moment can be a single-factor SMS-OTP at the recovery moment. &lt;em&gt;Your weakest factor is always your recovery flow.&lt;/em&gt; That is the line. It is the line every working security architect should write down, score against, and design recovery against -- &lt;em&gt;before&lt;/em&gt; designing the authentication factors.&lt;/p&gt;
&lt;h2&gt;18. FAQ&lt;/h2&gt;

No. A password is a shared secret -- the user types a string, the server stores a hash of the same string, and an eavesdropper who captures the string in flight or compromises the server&apos;s database has a credential they can replay. A passkey is one half of an asymmetric keypair: the private key lives in the authenticator (TPM, secure enclave, hardware key, or end-to-end-encrypted sync fabric), and only its public key reaches the server. An eavesdropper who captures a passkey ceremony in flight has nothing they can replay; a server-database leak yields public keys that authenticate no one. WebAuthn Level 3 [@webauthn-l3-cr] and the Microsoft Entra &quot;origin-bound public key cryptography&quot; framing [@ms-entra-passwordless] are the references.

Insecure relative to device-bound; secure relative to passwords. The NIST syncable-authenticator supplement (April 2024) [@sp80063sup1] and SP 800-63B-4 (July 2025) [@sp80063b4-html] cap synced passkeys at AAL2, because the long-term private key has left the original authenticator. Device-bound passkeys on dedicated hardware -- &quot;FIDO passkeys that are not synced ... and are properly stored in dedicated hardware have an AAL3 rating&quot; [@yubico-nist-guidance] -- can reach AAL3. The right answer is to use device-bound keys for tier-zero accounts and synced passkeys for the bulk of consumer flows.

Hello *uses* biometrics but provides the *user-verification gesture* for WebAuthn; the credential itself is asymmetric and lives in the TPM. Microsoft Learn states the property verbatim: &quot;The private keys can only be used after they&apos;re unlocked by the user using the Windows Hello unlock factor (biometrics or PIN)&quot; [@ms-learn-passkeys]. The biometric is one mode of the Hello UV gesture, not the credential. If you disable face or fingerprint, your PIN still unlocks the passkey.

No. Attestation is privacy-leaking for synced passkeys; `attestation: &quot;none&quot;` is the 2024-2026 default for consumer flows. Use `attestation: &quot;direct&quot;` only when you have a documented anti-fraud requirement and can verify the chain against the FIDO Metadata Service. Use `attestation: &quot;enterprise&quot;` only inside a managed enterprise where the user&apos;s device is corporately enrolled. The relevant references are WebAuthn Level 2 §§8.2-8.8 [@webauthn-l2-latest] and the IANA WebAuthn registry [@iana-webauthn-registry].

No. The cryptographic binding is the QR-code-encoded ephemeral ECDH key. Bluetooth is a transport and a proximity signal; it is not a trust anchor. The QR code transfers the laptop&apos;s ephemeral public key plus a derived HMAC seed; the phone derives the shared secret via ECDH; the BLE advertisement merely proves the phone is physically close to the laptop. The encrypted CTAP2 ceremony bytes travel over HTTPS through a discoverable tunnel relay. WebAuthn Level 3 §6.3.3 is the normative description [@webauthn-l3-cr].

No. A Windows passkey can be used with PIN-only user verification; the biometric is one mode of the Hello UV gesture, not the credential. The credential is in the TPM, indexed under your Microsoft Account container, and the PIN is one valid unlock factor. If you use a third-party passkey provider via the 24H2 plug-in model, that provider may use its own master password as the UV gesture; the OS still mediates the gesture acquisition through `WebAuthNPluginPerformUserVerification` [@ms-learn-webauthn-apis].

Microsoft cannot see your TPM-sealed Windows Hello private key; the TPM does not expose the raw key material to the OS, let alone to Microsoft. Apple&apos;s iCloud Keychain with Advanced Data Protection [@apple-adp-kb] and Google&apos;s end-to-end-encrypted passkey sync mean the sync provider cannot see the plaintext keys either. *But* the recovery path can still expose them under specific conditions: an attacker who compromises your recovery contact, recovery key, or your account&apos;s out-of-band recovery primitives (SMS-OTP, recovery email) effectively defeats the end-to-end encryption invariant. The plaintext keys are not what gets exfiltrated; the recovery primitives are.
&lt;p&gt;This article is one of a series on Windows authentication primitives. &lt;em&gt;NTLMless: The Death of NTLM in Windows&lt;/em&gt; (2026-05-10) covers the legacy authentication protocol passkeys are displacing. &lt;em&gt;Windows Hello, Demystified&lt;/em&gt; covers the user-verification gesture WebAuthn leans on. &lt;em&gt;Adminless: Administrator Protection in Windows&lt;/em&gt; (2026-05-10) and &lt;em&gt;App Identity in Windows&lt;/em&gt; (2026-05-08) cover the privilege-escalation and code-identity primitives that surround the authentication stack. The companion &lt;em&gt;Kerberos on Windows&lt;/em&gt; (2026-05-11) covers the enterprise transport for the resulting assertions; &lt;em&gt;ETW on Windows&lt;/em&gt; (2026-05-11) covers the telemetry surface for incident responders.&lt;/p&gt;
&lt;p&gt;The Windows passkey stack is the productisation moment for a forty-year-old protocol-literature insight: authentication should be tied to &lt;em&gt;something the network attacker cannot change&lt;/em&gt;. WebAuthn ties it to the origin in &lt;code&gt;clientDataJSON&lt;/code&gt;, signed by a credential whose private key never reaches the wire. Windows 10 1903 made it a Win32 surface; Windows 11 24H2 made it a plug-in surface; Authenticate 2024 made it a default. The protocol bytes are FIDO2; the consumer experience is autofill. The Windows part is the dispatcher between them.&lt;/p&gt;
&lt;p&gt;The criteria framework is the diagnostic kit. Use it on every authentication system you ship. Score it against five axes, not three. Write down the recovery flow first. Match the authentication ceremony to the recovery flow you can actually defend. And remember the line: &lt;em&gt;your weakest factor is always your recovery flow.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;StudyGuide slug=&quot;webauthn-and-passkeys-on-windows-from-ctap-to-the-credential-provider-model&quot; keyTerms={[
  { term: &quot;Phishing-resistant authenticator&quot;, definition: &quot;An authenticator whose protocol prevents a relying party impersonator from inducing the authenticator to release a usable credential value. NIST SP 800-63B-4 calls this verifier-impersonation resistance.&quot; },
  { term: &quot;Origin binding&quot;, definition: &quot;The mechanism by which WebAuthn enforces phishing resistance: the browser writes the origin into clientDataJSON; the authenticator signs over the SHA-256 hash of the canonical rpId; the RP rejects any signature whose rpIdHash does not match the registered rpId.&quot; },
  { term: &quot;rpId&quot;, definition: &quot;A string identifying the WebAuthn relying party for credential scoping. Must be a registrable suffix of the page&apos;s origin. All WebAuthn signatures are made over its SHA-256 hash.&quot; },
  { term: &quot;CTAP 2.x&quot;, definition: &quot;The Client-to-Authenticator Protocol: the wire format browser to roaming authenticator over USB-HID, NFC, or BLE. CTAP1 is APDU-based; CTAP2 is CBOR-based. Modern keys speak CTAP 2.1 (June 2021) or 2.2 (July 2025).&quot; },
  { term: &quot;Discoverable credential (resident key, passkey)&quot;, definition: &quot;A WebAuthn credential whose account metadata is stored on the authenticator, enabling usernameless sign-in. CTAP 2.0 called these resident keys; the May 2022 vendor commitment branded them passkeys.&quot; },
  { term: &quot;Attestation conveyance&quot;, definition: &quot;The mechanism by which a registration ceremony optionally produces a signature over the credential public key, chained to a vendor or platform root. Seven IANA-registered formats: packed, tpm, android-key, android-safetynet, fido-u2f, apple, none.&quot; },
  { term: &quot;Hybrid transport (caBLE)&quot;, definition: &quot;A WebAuthn transport in which a phone acts as a roaming authenticator for a nearby laptop. QR code carries an ephemeral ECDH key; BLE proves proximity; HTTPS tunnel relay carries encrypted CTAP2 bytes.&quot; },
  { term: &quot;AAGUID&quot;, definition: &quot;A 16-byte Authenticator Attestation GUID identifying the authenticator make and model. Some authenticators emit all-zeros for privacy; the FIDO Metadata Service is the authoritative directory.&quot; },
  { term: &quot;Conditional UI / Conditional Mediation&quot;, definition: &quot;A WebAuthn invocation mode in which the browser offers discoverable credentials inside the autofill UI rather than via a modal picker. RP calls navigator.credentials.get with mediation: &apos;conditional&apos;.&quot; },
  { term: &quot;BE / BS flags&quot;, definition: &quot;Backup Eligible and Backup State bits in authenticatorData. BE=1 means the credential is in principle syncable; BS=1 means it is currently backed up. NIST SP 800-63B-4 caps BS=1 credentials at AAL2.&quot; },
  { term: &quot;AAL1 / AAL2 / AAL3&quot;, definition: &quot;NIST SP 800-63B-4 authentication assurance levels. AAL1 is single-factor; AAL2 is multi-factor or phishing-resistant; AAL3 is hardware-bound non-syncable authentication.&quot; }
]} /&amp;gt;&lt;/p&gt;
</content:encoded><category>windows-security</category><category>webauthn</category><category>passkeys</category><category>fido2</category><category>ctap</category><category>phishing-resistance</category><category>windows-hello</category><category>authentication</category><author>noreply@paragmali.com (Parag Mali)</author></item></channel></rss>