Netherlands - Generic Functions for data exchange Implementation Guide
0.3.0 - ci-build Netherlands

Netherlands - Generic Functions for data exchange Implementation Guide, published by Stichting Nuts. This guide is not an authorized publication; it is the continuous build for version 0.3.0 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/nuts-foundation/nl-generic-functions-ig/ and changes regularly. See the Directory of published versions

X509Credential

X509Credential

The X509Credential is a verifiable credential that bridges traditional X.509 Public Key Infrastructure (PKI) with decentralized identity systems. It enables organizations and systems that rely on existing X.509 certificate implementations (such as healthcare or government frameworks) to leverage those certificates within the Nuts decentralized identity ecosystem using the did:x509 DID method.

Data model: W3C Verifiable Credentials Data Model 1.1

Issuer: A did:x509 identifier, anchored in a trusted Certificate Authority (CA) through the certificate chain.

Subject: Any entity identified by a DID (e.g., did:web), typically a healthcare provider organization or system.

Status: production use

Proof type: JWT

Signature algorithm: ES256, RS256 or PS256

Revocation method: Bitstring Status List v1.0, and certificate revocation checks (OCSP/CRL) through the did:x509 DID resolution.

Proof of Possession: presenter is holder: the identifier of the presenter must equal the credential subject identifier.

Standards used

Background

The did:x509 DID method creates a Decentralized Identifier based on an X.509 certificate chain, with trust anchored through a ca-fingerprint property that references a trusted Certificate Authority (CA). This enables organizations with existing X.509 PKI infrastructure to use their certificates within the Nuts decentralized identity ecosystem.

Attributes

The X509Credential credentialSubject contains fields from the certificate's DID policies, grouped by policy type:

JSON Path did:x509 policy Attribute Description Example
credentialSubject.subject.C subject C Country NL
credentialSubject.subject.CN subject CN Common Name example.com
credentialSubject.subject.L subject L Locality Amsterdam
credentialSubject.subject.ST subject ST State/Province Noord-Holland
credentialSubject.subject.O subject O Organisation Ziekenhuis Oost
credentialSubject.subject.OU subject OU Organisation Unit Cardiology
credentialSubject.subject.STREET subject STREET Street Address Oosterpark 101
credentialSubject.san.email san email Email address from Subject Alternative Name info@example.com
credentialSubject.san.dns san dns DNS name from Subject Alternative Name example.com
credentialSubject.san.uri san uri URI from Subject Alternative Name https://example.com
credentialSubject.san.otherName san otherName Free-form attribute (e.g., string containing UZI and URA number) 2.16.528.1.1007.99.2110-1-900025039-S-90000382-00.000-00000000
credentialSubject.eku.<OID> eku Any OID Extended Key Usage 1.3.6.1.5.5.7.3.2

Every field in the credentialSubject expresses an attribute from the certificate, through the did:x509 policies. The fields in the credentialSubject are nested with their DID policies as keys, so subject:L:Amsterdam, becomes:

{
  "sub": "did:x509:0:sha256:GwlhBZuEFlSHXSRUXQuTs3_YpQxAahColwJJj35US1A::san:otherName:2.16.528.1.1007.99.2110-1-900025039-S-90000382-00.000-00000000::subject:L:%2527S-GRAVENHAGE:o:T%25C3%25A9st%2520Zorginstelling%252003",
  "credentialSubject": {
    "id": "did:web:example.com:zorginstelling",
    "subject": {
      "L": "S-GRAVENHAGE",
      "O": "Tést Zorginstelling 03"
    },
    "san": {
      "otherName": "2.16.528.1.1007.99.2110-1-900025039-S-90000382-00.000-00000000"
    }
  }
}

Non-normative example:

JWT Header:

{
  "alg": "PS256",
  "typ": "JWT",
  "x5c": [
    "<base64 encoded leaf certificate>",
    "<base64 encoded intermediate CA certificate>",
    "<base64 encoded root CA certificate>"
  ],
  "x5t#S256": "WE4P5dd8DnLHSkyHaIjhp4udlkF9LqoKwCvu9gl38jk",
  "kid": "did:x509:0:sha256:did:x509:0:sha256:GwlhBZuEFlSHXSRUXQuTs3_YpQxAahColwJJj35US1A::san:otherName:2.16.528.1.1007.99.2110-1-900025039-S-90000382-00.000-00000000::subject:L:%2527S-GRAVENHAGE:o:T%25C3%25A9st%2520Zorginstelling%252003"
}

JWT Payload:

{
  "vc": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1",
      "https://nuts.nl/credentials/v1"
    ],
    "type": ["VerifiableCredential", "X509Credential"],
    "issuer": "did:x509:0:sha256:GwlhBZuEFlSHXSRUXQuTs3_YpQxAahColwJJj35US1A::san:otherName:2.16.528.1.1007.99.2110-1-900025039-S-90000382-00.000-00000000::subject:L:%2527S-GRAVENHAGE:o:T%25C3%25A9st%2520Zorginstelling%252003",
    "issuanceDate": "2024-12-01T00:00:00Z",
    "credentialSubject": {
      "id": "did:web:example.com",
      "subject": {
        "O": "Tést Zorginstelling 03",
        "L": "S-GRAVENHAGE"
      },
      "san": {
        "otherName": "2.16.528.1.1007.99.2110-1-900025039-S-90000382-00.000-00000000"
      }
    }
  },
  "sub": "did:web:example.com",
  "iss": "did:x509:0:sha256:GwlhBZuEFlSHXSRUXQuTs3_YpQxAahColwJJj35US1A::san:otherName:2.16.528.1.1007.99.2110-1-900025039-S-90000382-00.000-00000000::subject:L:%2527S-GRAVENHAGE:o:T%25C3%25A9st%2520Zorginstelling%252003",
  "iat": 1733011200
}

Revocation

Credentials are considered to be revoked if either:

  • The certificate used to issue the credential is revoked (check using OCSP or CRL). This MUST be reflected in the did:x509 DID resolution result, so it's technically not part of the credential revocation checks.
  • The credential is listed as revoked in the Bitstring Status List

Validation

Aside from standard JWT, Verifiable Credential, and did:x509 validation steps (DID resolution, signature, expiration, revocation), verifiers MUST perform the following, additional checks specific to the X509Credential below.

  1. Issuer is a did:x509 DID
  2. All fields in credentialSubject are present in the did:x509 DID policies.
  3. Check that the JWT's sub claim matches the credentialSubject.id field.
  4. Check credential time validity:
    • issuanceDate is equal to or later than certificate's notBefore
    • expirationDate (if present) is equal to or earlier than certificate's notAfter

If any of these checks fail, the credential MUST be rejected as invalid.

Example use cases

  • Healthcare organizations using UZI server certificates to authenticate and establish organizational identity in the Nuts network.
  • Data holders verifying the organizational identity of a data requester based on their X.509 certificate attributes ( e.g., organization name, URA number).
  • Systems requiring both traditional PKI trust and decentralized identity verification.

Security Considerations

Implementers MUST be aware of the following security considerations:

  • Trust anchor verification: Always verify the ca-fingerprint matches an accepted CA (e.g., UZI register for healthcare certificates)
  • Revocation checks: Failure to check certificate revocation status may allow compromised certificates to be trusted
  • Credential subject validation: All attributes must align with the certificate's DID policies to prevent impersonation

Original work

The X509Credential was originally defined by the Nuts Foundation as RFC023.