Skip to content
ayanworksPublic
forked from microsoft/did-x509

About

did:x509 Decentralized Identifier Method Specification

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

 
 

Repository files navigation

CI

did:x509

This repository contains the specification and reference implementations of the did:x509 DID method. It aims to achieve interoperability between existing X.509 solutions and Decentralized Identifiers (DIDs) to support operational models in which a full transition to DIDs is not achievable or desired yet. It is registered as a DID method with the did-wg in the W3C.

Why did:x509?

If you already hold an X.509 certificate from a CA — whether public PKI, enterprise PKI, or Fulcio/Sigstore — you already have a DID. No blockchain, no new key infrastructure, no additional registration.

CA-issued X.509 cert ──► did:x509 DID ──► Use across decentralized trust infrastructure

This enables you to:

  • Issue verifiable credentials using your DID as the issuer identifier
  • Verify credentials presented by holders with CA-backed identity
  • Register in trust registries using your cert-derived DID
  • Sign software artifacts (Fulcio/Sigstore) with a DID identity
  • Bridge enterprise PKI to decentralized identity workflows

See the Practical Guide for real-world workflows.

Specification

See specification.md.

Reference Implementations

Language Maintainer Location
TypeScript (pure TS) AyanWorks typescript/
TypeScript (native, wraps Microsoft's C++) AyanWorks typescript-native/
TypeScript (credo-ts module) AyanWorks typescript-credo/

TypeScript (@didx509/core)

Cross-runtime package (Node.js, Deno, Bun, browser, React Native). Derives DIDs from your existing CA-issued certificates.

cd typescript
npm install
npm test
import { resolveDidFromPem } from '@didx509/core';

const doc = await resolveDidFromPem(did, pemChain);
console.log(doc.verificationMethod[0].publicKeyJwk);

TypeScript, native (@didx509/native)

Same API as @didx509/core, but every resolution runs inside Microsoft's C++ reference implementation (didx509cpp) through a Node-API addon — identical behaviour to the reference, verified against all 220 official test vectors on every CI build. For Node.js, Electron, Bun, and Deno; browsers and React Native keep using @didx509/core.

Not yet published to npm. The source is in this repository and builds locally, but the package has no release yet, so the install below is from the checkout rather than the registry.

cd typescript-native
npm install
REQUIRE_CORE=true npm test
import { resolveDidFromPem } from '@didx509/native';

const doc = await resolveDidFromPem(did, pemChain);
  • Package README — Overview, platform support, quick start
  • Migration from @didx509/core — Including the generated list of known behaviour differences (19 cases where @didx509/core accepts chains the C++ resolver rejects)
  • Architecture — How the wrapper works and how parity is tested

TypeScript, credo-ts module (@didx509/credo)

Use did:x509 inside a credo-ts agent. The resolver plugs into DidsModule, so any part of the framework that resolves DIDs — including the verification helpers used when signing and verifying credentials — can work with certificate-backed identities.

import { Agent, DidsModule } from '@credo-ts/core';
import { X509DidResolver } from '@didx509/credo';

const agent = new Agent({
  config: { /* ... */ },
  modules: {
    dids: new DidsModule({ resolvers: [new X509DidResolver()] }),
  },
});

// Resolve with the issuer's certificate chain supplied out-of-band.
const result = await agent.dids.resolve(did, { x509chain });

Resolution runs on @didx509/core by default, or on the native @didx509/native addon when it is installed (selectable with implementation: 'auto' | 'native' | 'core').

Usage examples

Runnable end-to-end examples live in examples/ — each one generates a throwaway CA + leaf certificate chain, derives the did:x509 DID, and then uses it:

cd examples
npm install
npm run all
Script Run What it shows
01-resolve.ts npm run resolve Resolving a DID directly and through the did-resolver plugin
02-jsonld.ts npm run sign:jsonld Issuing and verifying a JSON-LD Verifiable Credential (Data Integrity, eddsa-rdfc-2022)
03-sd-jwt.ts npm run sign:sd-jwt Issuing and verifying an SD-JWT VC (ES256) with selective disclosure
04-mdoc.ts npm run sign:mdoc Issuing and verifying an mDoc (ISO/IEC 18013-5) with the certificate in the x5chain

See examples/README.md for a walkthrough of each.

Supported key types

A did:x509 DID is backed by a certificate, so what you can resolve is bounded by what the certificate chain is signed with. @didx509/core verifies certificate signatures and exports the subject public key as a JWK through the Web Crypto API, so support follows the runtime's Web Crypto implementation rather than anything specific to this library.

The table below is what has been tested end-to-end — a certificate chain is generated, a DID is derived from it, and the DID is resolved back to a JWK.

Key / curve Status JWK emitted Notes
RSA 2048–4096, PKCS#1 v1.5 Supported kty=RSA Most common CA-issued type; Let's Encrypt R-series, DigiCert G2
RSA-PSS (SHA-256, SHA-512) Supported kty=RSA Verification re-imports the issuer key as RSA-PSS; salt length comes from the certificate
ECDSA P-256 Supported kty=EC, crv=P-256 Fulcio; most modern intermediate CAs
ECDSA P-384 Supported kty=EC, crv=P-384 Let's Encrypt E-series, ISRG Root X2, DigiCert G3
ECDSA P-521 Supported kty=EC, crv=P-521 NIST/Secure Hash style PKIs
Ed25519 Supported kty=OKP, crv=Ed25519 Used by some internal PKIs; supported by Web Crypto on modern runtimes
Ed448 Not supported — Web Crypto supports it, but @peculiar/x509 cannot map it to ASN.1
ML-DSA (post-quantum, 44/65/87) Not supported — Not supported by the C++ reference either; see below

Mixed chains are fine: the signature is verified with the issuer's key, so a P-256 leaf signed by a P-384 CA (the shape fulcio produces) resolves correctly and the resulting JWK describes the leaf's own key.

This covers what you would get from a typical publicly-trusted CA (Let's Encrypt, DigiCert, ISRG, Sectigo), an OpenBao/Vault-style internal PKI, and most national PKI roots, all of which issue RSA or NIST-curve ECDSA certificates. Two caveats are worth stating plainly:

  • Ed448 and ML-DSA are not supported — by the reference implementation either. The pure-TypeScript resolver is blocked by @peculiar/x509, which has no ASN.1 mapping for either algorithm. But the same limit applies to Microsoft's C++ reference (didx509cpp): its public_jwk() handles only RSA, EC (P-256/P-384/ P-521), and Ed25519, and throws unsupported key base id for anything else. No released version, including 1.0.0, supports ML-DSA. The two implementations intentionally agree here, so this is a shared boundary rather than a gap unique to this package.
  • Trust is still your decision. Resolving a DID proves the chain is internally consistent; it does not tell you whether that CA is one you trust. Pin the CA (the DID's fingerprint already does this), or check the chain against your own trust roots, before you act on a credential — see the confidence and trust discussion.

Contributing

This project welcomes contributions and suggestions. Please see the Contribution guidelines.

Credits

  • Specification: did:x509 method specification by Microsoft Corporation (Maik Riechert, Antoine Delignat-Lavaud)
  • TypeScript implementation: Contributed by AyanWorks

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

About

did:x509 Decentralized Identifier Method Specification

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages