Blauwe Knop Connect

Overheidsbrede Standaard
Werkversie

Laatst gepubliceerde versie:
https://vorijk.nl/standaard/
Vorige versie:
https://vorijk.nl/standaard/
Redacteur:
Team Vorderingenoverzicht Rijk (Centraal Justitieel Incasso Bureau)
Auteur:
Team Vorderingenoverzicht Rijk (Centraal Justitieel Incasso Bureau), Contact

Samenvatting

Deze Blauwe Knop Connect (BK Connect) standaard beschrijft hoe burgers (op gestandaardiseerde wijze) diensten kunnen gebruiken bij overheidsorganisaties. De basis van de standaard is de Blauwe Knop Connect specificatie. Blauwe Knop Connect bevat alle protocollen die nodig zijn voor het veilig leggen en gebruiken van verbindingen tussen burgers en overheidsorganisaties. Via deze verbindingen kunnen diensten worden aangeroepen. Dienstprofielen bevatten specifieke afspraken voor specifieke diensten.

Status van dit document

Dit is een werkversie die op elk moment kan worden gewijzigd, verwijderd of vervangen door andere documenten. Het is geen goedgekeurde consultatieversie.

1. Introductie

1.1 Aanleiding

Waardengedreven ontwikkeling van digitale dienstverlening vereist een manier waarop burgers eenvoudig, veilig en vertrouwd gegevens kunnen uitwisselen met overheden. In het bijzonder in gevallen waar voor het oplossen van een specifiek probleem of het uitvoeren van een specifieke taak gegevens van meerdere organisaties moeten worden gecombineerd en/of communicatie met meerdere organisaties dient plaats te vinden (ketendiensten).

Voorbeelden van dergelijke (typen) ketendiensten zijn:

1.2 Blauwe Knop Connect

Met Blauwe Knop Connect kunnen organisaties diensten op betrouwbare wijze aan burgers aanbieden, en kunnen burgers deze diensten op betrouwbare en veilige wijze gebruiken.

Het basisprincipe van Blauwe Knop Connect is dat een burger een gestandaardiseerd (informatie)verzoek verstuurt naar een (overheids)organisatie, en als antwoord ook weer een gestandaardiseerd (informatie)document terug ontvangt van de betreffende organisatie.

Het Blauwe Knop Connect protocol is ontworpen met het doel dat burgers en (overheids)organisaties elk hun wettelijke rechten, taken en plichten effectief en zelfstandig kunnen uitvoeren, waarbij de rechtspositie van elke partij maximaal geborgd is:

Hoewel het Blauwe Knop protocol ontwikkeld is om de kansen die automatisering biedt maximaal te benutten, is het basisprincipe (het uitwisselen van documenten) zo eenvoudig, dat het ook op papier uitgevoerd kan worden. Dit basisprincipe fungeert als een toetssteen waarmee bewaakt wordt dat zo min mogelijk onnodige complexiteit geïntroduceerd wordt. Daardoor blijft het Blauwe Knop protocol eenvoudig te begrijpen, wat bijdraagt aan de robuustheid en het vertrouwen dat gebruikers erin stellen.

1.3 Terminologie

1.4 Cryptografie

1.4.1 Digitale handekeningen

Voor alle digitale handtekeningen in deze standard MOETEN een van de volgende algoritmes gebruiken:

  • ECDSA, waarbij gebruik gemaakt MOET worden van een van de volgende curves:
    • P-256 (ook bekend als secp256r1 en prime256v1),
    • P-384 (ook bekend als secp384r1),
    • P-512 (ook bekend als secp512r1).
  • EdDSA, waarbij gebruik gemaakt MOET worden van een van de volgende curves:
    • Curve25519 (EdDSA op Curve25519 wordt ook wel Ed25519 genoemd),
    • Curve448 (EdDSA op Curve448 wordt ook wel Ed448 genoemd).

Merk op dat de Secure Enclave (SE) van iPhones en de Trusted Execution Environment (TEE) van Android telefoons uitsluitend ECDSA op P-256 ondersteunen. Wanneer een private key in een SE/TEE beveiligd dient te worden is dit dan dus de enige optie.

Deze standaard maakt veelvuldig gebruik van JWS (RFC 7515) om digitaal ondertekende datastructuren te encoderen. In het vervolg van deze standaard tonen we een JWS steeds als JSON structuur. Dus gegeven het volgende JWS voorbeeld:

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFt
ZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.yt1lkupgb536FyX2_IzrElyQJ7
ep3MJhZ_7w4wpz0GIzWnLkESQ6RDvRmk_HTwTbLsJdLhGLj-7KB_FEvOo8sQ

Schrijven we het volgende:

{
  "alg": "ES256",
  "typ": "JWT"
}
.
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Deze weergave toont niet de handtekening (het laatste deel van de JWS, na de tweede punt). Alle whitespace (spaties en newlines) zijn enkel voor leesbaarheid en dienen te worden verwijderd bij het tekenen van een JWS.

Elk digitaal ondertekend bericht in deze standaard MOET in de vorm van een JWS (RFC 7515) zijn.

1.4.2 Asymmetrische encryptie

Voor alle asymmetrische encryptie in deze standaard MOET ECIES gebruikt worden (dit heet ECDH-ES in JWEs (RFC 7518)), met de volgende parameters:

  • Bij het genereren van een public/private keypair voor deze encryptie MOET een van de elliptic curves uit de voorgaande subsectie gekozen worden.
  • Het algoritme voor symmetrische encryptie MOET voldoen aan onderstaande subsectie.

NB: Een versleuteld bericht wordt soms verstuurd in de vorm van een JWE. JWS en JWE zijn allebei vormen van een JWT (JSON Web Token, RFC 7519). De term JWT kan naar zowel een JWS als een JWE refereren. In dit document gebruiken we consistent "JWS" of "JWE" om expliciet te zijn.

1.4.3 Symmetrische encryptie

Voor alle symmetrische encryptie in deze standaard MOET AES gebruikt worden, met als parameters een van de volgende twee:

  • 128, 192 of 256-bit AES-GCM (A128GCM, A192GCM of A256GCM in JWEs), of
  • 128, 192 of 256-bit AES-CTR samen met de SHA2 HMAC van tenminste 256 bits.

1.4.4 JWE headers

Wanneer een bericht wordt versleuteld in de vorm van een JWE, dan geldt voor de headers van die JWE het volgende:

  • enc: MOET per bovenstaande A128GCM, A192GCM of A256GCM zijn.
  • alg:
    • Als het bericht asymmetrisch versleuteld moet worden, dan MOET deze header de waarde ECDH-ES hebben per voorgaande sectie. (In dit geval zal de header ook een epk veld moeten bevatten, en optioneel ook apu en apv; zie dit voorbeeld in RFC 7518.)
    • Als het bericht symmetrisch versleuteld moet worden, dus middels AES per voorgaande sectie, dan MOET deze header een van de volgende waardes hebben: dir, A128KW, A192KW, of A256KW, waarbij dir wordt aangeraden. Zie RFC 7518 voor de betekenis van deze velden.
  • kid: MAG gebruikt worden om te verwijzen naar een public key waarnaar de JWE versleuteld is, zodat de ontvanger kan weten welke private key gebruikt moet worden om de JWE te ontsleutelen. MOET een string zijn indien aanwezig. Dit veld kan gebruikt worden bijvoorbeeld in protocollen die key rollover ondersteunen, zodat bijvoorbeeld met "kid": "2" aangegeven kan worden dat de tweede sleutel gebruikt moet worden om de JWE te ontsleutelen. Wanneer de ontvanger van de JWE uit de context al weet welke sleutel gebruikt moet worden dan is gebruik van deze header niet nodig.

1.4.5 Transport

Alle verkeer tussen de App en de (infrastructuur van de) Verifier, Dienst, of Credential Issuer MOET gebruik maken van minstens TLS 1.3.

2. Architectuur

2.1 Doelen

De Blauwe Knop Connect standaard beschrijft hoe organisaties diensten kunnen aanbieden aan natuurlijke personen, zodat die personen (gebruikers, burgers) die diensten makkelijk, veilig en efficiënt kunnen gebruiken om een bepaalde taak uit te voeren.

2.1.1 Eenvoudig

Het aanbieden en gebruiken van diensten moet gebruikersvriendelijk en in de praktijk eenvoudig zijn voor aanbieder en gebruiker. Daarom is Blauwe Knop Connect ontworpen vanuit de principes van Gebruiker Centraal.

  • Voor organisaties betekent dit: lage beheerlast, eenvoudig (niet ingewikkeld) uitvoerbaar en integreerbaar.
  • Voor gebruikers betekent dit: maakt goede UX mogelijk, begrijpelijk en uitlegbaar, waardevol in de praktijk.

2.1.2 Veilig

Het aanbieden en gebruiken van diensten moet veilig zijn voor aanbieder en gebruiker, en de informatieveiligheid moet op elk moment maximaal geborgd zijn. Daarom is Blauwe Knop Connect ontworpen vanuit de principes van Security en Privacy by Design.

  • Voor organisaties betekent dat: voldoen aan veiligheidseisen en best practices informatiebeveiliging.
  • Voor gebruikers betekent dit: met aandacht voor publieke waarden, de rechtspositie en informatiepositie van de burger, en privacy en informatiebeveiliging geborgd.

2.1.3 Efficiënt

Het aanbieden en gebruiken van diensten moet efficiënt zijn voor de aanbieder en gebruiker. Dat betekent dat de meerwaarde van technologie benut wordt voor zover aanbieders en gebruikers dat willen.

  • Voor organisaties betekent dit: de standaard stimuleert dat technologie organisaties helpt om verzoeken efficiënt te ontvangen en af te handelen.
  • Voor gebruikers betekent dit: de standaard stimuleert dat technologie burgers helpt om verzoeken efficiënt te versturen, en resultaten te ontvangen en te gebruiken.

2.2 Functies

2.2.1 Diensten aanbieden en afnemen (basisprincipe)

Een organisatie biedt een dienst aan die door een burger wordt afgenomen. Om de dienst te gebruiken, stuurt de burger een verzoek naar een de organisatie. De organisatie ontvangt het verzoek, stelt een antwoord op, en stuurt het antwoord direct terug naar de burger. Als het opstellen van een antwoord enige tijd kost, kan de organisatie in plaats van het daadwerkelijke antwoord op het verzoek, ook een antwoord geven dat aangeeft hoe een burger de status van de afhandeling van het verzoek kan volgen. De inrichting hiervan kan voor specifieke diensten zelf worden bepaald.

Diensten aanbieden en afnemen
Figuur 1 Diensten aanbieden en afnemen

Basisprincipe: Het basisprincipe van Blauwe Knop Connect is dus dat een burger een gestandaardiseerd (informatie)verzoek verstuurt naar een (overheids)organisatie, en als antwoord ook weer een gestandaardiseerd (informatie)document terug ontvangt van de betreffende organisatie.

Voorbeeld (Vorderingenoverzicht Rijk): een gebruiker dient een verzoek in bij een organisatie om een overzicht te verkrijgen van zijn financiële verplichtingen jegens die organisatie, en ontvangt als antwoord het betreffende overzicht.

Architectuurvereisten:

  • De werking MOET van een dienst moet gedocumenteerd zijn in een dienstenspecificatie die beschrijft welke verzoeken kunnen worden gedaan, en welke antwoorden kunnen worden terugverwacht.
  • Voor een digitale dienst MOET deze dienst een API zijn die voorzien is van een OpenAPI3 specificatie.

2.2.2 Meerdere diensten combineren om een taak uit te voeren (ketendienst)

Bij veel maatschappelijke uitdagingen is het zo dat om een bepaalde taak uit te voeren, een combinatie van meerdere diensten beschikbaar dient te zijn om de uiteindelijke taak uit te voeren. Informatie uit verschillende bronnen wordt bijvoorbeeld door de gebruiker gecombineerd om op basis van persoonlijke omstandigheden de juiste vervolgactie te ondernemen (die actie op zichzelf kan ook weer een dienst zijn). De benodigde combinatie van diensten vormen samen een ketendienst. Het is mogelijk dat diensten een rol spelen in meerdere ketendiensten. De precieze werking van een specifieke ketendienst wordt beschreven in een toepassingsprofiel.

Meerdere diensten combineren
Figuur 2 Meerdere diensten combineren

Voorbeeld (Vorderingenoverzicht Rijk): een gebruiker spreekt bij meerdere (bijvoorbeeld drie) organisaties een informatiedienst aan (informatie over financiële verplichtingen opvragen) om één totaaloverzicht te verkrijgen van financiële verplichtingen. Daarna spreekt de gebruiker bij een vierde organisaties een andere dienst aan om een regeling (bijvoorbeeld een overheidsbrede betalingsregeling) aan te vragen op basis van de eerder opgehaalde informatie.

Architectuurvereisten:

  • Voor een ketendienst MOET toepassingsprofiel worden opgesteld waarin aspecten waar de Blauwe Knop Connect keuzevrijheid laat (zoals de gebruikte implementatievariant of de structuur van het stelseldocument voor de betreffende ketendienst) worden ingevuld.
  • Het toepassingsprofiel voor de ketendienst MOET alle aanvullende standaarden voor en afspraken over de werking van de specifieke ketendienst documenteren.

2.2.3 Diensten vinden die nodig zijn voor een ketendienst (stelseldocument)

Om een ketendienst te laten werken, moeten de achterliggende specifiek diensten vindbaar zijn voor gebruikers. Voor het beheren van informatie en afspraken voer de werking van een ketendienst, zoals de vindbaarheid van organisaties die er bij betrokken zijn, kan voor een specifieke ketendienst een centraal beheerd stelseldocument worden ingezet. Bij het ontwerpen van een ketendienst is er behoorlijk veel flexibiliteit voor de specifieke structuur van het stelseldocument voor een specifieiek dients. Zo kan de inrichting hiervan passend gemaakt worden bij de gebruikscontext(en) waarvoor de dienst wordt ontworpen. De structuur en werking van het stelseldocument voor een specifieke dienst moet beschreven worden in het toepassingsprofiel voor de betreffende ketendienst. Indien in het dienstprofiel een stelseldocument wordt beschreven moet bij de uitvoering van de ketendienst een beheerder voor het stelseldocument worden aangewezen (stelselbeheerder).

Diensten vinden behorend bij een ketendienst
Figuur 3 Diensten vinden behorend bij een ketendienst

Voorbeeld (Vorderingenoverzicht Rijk): voor de ketendienst Vorderingenoverzicht Rijk wordt een stelseldocument beheerd door een stelselbeheerder. In het stelseldocument zijn alle deelnemende organisaties opgenomen. Zo kunnen gebruikers de voor hen benodigde diensten vinden om de ketendienst te gebruiken.

Architectuurvereisten:

  • Een ketendienst MAG een lijst van voor een ketendienst relevante diensten publiceren in een stelseldocument.
  • Het stelseldocument MOET een beheerder hebben (stelselbeheerder).
  • Het stelseldocument MOET op een publieke locatie beschikbaar worden gesteld.
  • Het stelseldocument MOET door de stelselbeheerder ondertekend worden.
  • Organisaties en gebruikers MOETEN de handtekening van de stelselbeheerder controleren voordat ze het stelseldocument gebruiken.
  • De stelselbeheerder MAG eisen stellen voor deelname aan de ketendienst.
  • De stelselbeheerder MOET gestelde eisen handhaven/controleren.
  • De stelselbeheerder MOET kwaliteitsmeting uitvoeren van diensten in het stelsel.
  • Een dienstaanbieder MOET meewerking verlenen aan kwaliteitsmeting in het stelsel.

2.2.4 Diensten vinden bij een organisatie (vindbaarheidsconfiguratie)

Om bij een organisatie diensten te kunnen gebruiken, moet het bij gebruikers bekend zijn waar zij deze diensten kunnen gebruiken. Een organisatie moet dus vindbaarheidsconfiguratie publiceren. Bovendien moet bij gebruikers bekend zijn hoe zij een specifieke dienst kunnen gebruiken. Voor elke dienst moet er dus een specificatie zijn die beschrijft hoe de dienst werkt. Gebruikers kunnen dan eerst de vindbaarheidsconfiguratie opvragen, en vervolgens met de daarin aanwezig informatie de dienst afnemen.

Diensten vinden bij een organisatie
Figuur 4 Diensten vinden bij een organisatie

Voorbeeld (Vorderingenoverzicht Rijk): een gebruiker haalt de vindbaarheidsconfiguratie van elke organisatie die deelneemt aan Vorderingenoverzicht Rijk op. Deze informatie wordt vervolgens gebruikt om de dienst voor het opvragen van informatie over financiële verplichtingen aan de betreffende organisatie (citizen-financial-claims-process) af te nemen.

Architectuurvereisten:

  • Een organisatie die diensten aanbiedt op basis van Blauwe Knop Connect MOET een actuele lijst van de diensten die door de betreffende organisatie worden aangeboden publiek beschikbaar stellen.
  • Voor elke aangeboden dienst, MOET de aanbiedende organisatie het versienummer en de specificatie van de dienst opnemen in de vindbaarheidsconfiguratie.
  • Voor elke aangeboden dienst, MOET de aanbiedende organisatie de locatie van de aangeboden dienst opnemen in de vindbaarheidsconfiguratie.

2.2.5 Hulpmiddelen bij het gebruiken van diensten (technieken en tools)

Ketendiensten stellen bijna altijd gebruikersvriendelijke hulpmiddelen ter beschikking aan gebruikers zodat de ketendienst gemakkelijk en efficiënt te gebruiken is. Hulpmiddelen ondersteunen de gebruiker tijdens het gebruik van een ketendienst door de uit te voeren handelingen volgorderlijk te structuren, door het toegankelijk en begrijpelijk maken van de mogelijkheden van de ketendienst, en/of door het automatiseren van handelingen. Het gebruik van hulpmiddelen bij Blauwe Knop Connect maakt het mogelijk de balans te bewaken tussen eigen controle/autonomie van gebruikers en de zorgplicht/wens om gebruikers te helpen met het gebruiken van een ketendienst.

Een hulpmiddel gebruiken
Figuur 5 Een hulpmiddel gebruiken

Voorbeeld (Vorderingenoverzicht Rijk): De Vorderingenoverzicht Rijk applicatie automatiseert een flink deel van de handelingen die nodig zijn om de ketendienst te gebruiken waarmee burgers een overzicht kunnen samenstellen van hun financiële verplichtingen aan overheidsorganisatie. De software handelt alle communicatie met de overheidsorganisaties af, fungeert als persoonlijke digitale ordner (in het domein van de burger zelf) voor het verzamelen van de antwoorden, en brengt overzicht aan in de ontvangen informatie, zodat deze waardevol en bruikbaar is.

Architectuurvereisten:

  • Een hulpmiddel MOET ontworpen zijn zodat het makkelijk bruikbaar en waardevol is voor gebruikers (bijvoorbeeld op basis van user centered design, of de principes van Gebruiker Centraal).
  • Een hulpmiddel MOET zelfstandig door burgers kunnen worden gebruikt.
  • De werking van hulpmiddelen MOET transparant inzichtelijk zijn. Voor software betekent dit dat de broncode van het hulpmiddel onder een open source licentie beschikbaar moet worden gesteld.
  • Een leverancier van een hulpmiddel MAG NIET gegevens verwerken van of over de gebruiker van het hulpmiddel.
  • Een leverancier van een hulpmiddel MAG NIET volgen en/of bijhouden wat een burger met een hulpmiddel doet.
  • Een leverancier van een hulpmiddel MAG NIET uitvoerend betrokken zijn bij het gebruik van een hulpmiddel.
  • Een leverancier van een hulpmiddel MAG gebruikers leren hoe zij het hulpmiddel op de juiste wijze kunnen gebruiken.

2.2.6 Veilig diensten gebruiken (geauthenticeerde communicatie)

Blauwe Knop Connect is ontworpen volgens de principes van security by design om de veiligheid (beschikbaarheid, integriteit, confidentialiteit) van gegevens te waarborgen bij het gebruiken van diensten. Blauwe Knop Connect stelt eisen aan zowel organisatie als gebruiker op het gebied van communicatie en authenticatie. Diensten kunnen vervolgens vertrouwen op deze veiligheidsaspecten en kunnen daardor zelf eenvoudiger blijven.

2.2.6.1 Communicatie

Communicatie bij het afnemen van diensten dient plaats te vinden via een kanaal dat de veiligheid waarborgt. Dit kanaal kan per dienst verschillen.

Enkele voorbeelden zijn:

Publiek internet: met gebruik van TLS (HTTPS)
Publiek internet: met gebruik van tweezijdig TLS (mTLS)
Directe communicatie op locatie (bezorgen van berichten ter adres van de wederpartij)
Postdienst (bewaking van briefgeheim)

Diensten kunnen zelf aanvullende maatregelen nemen om de veiligheid verder te vergroten. Bijvoorbeeld extra versleuteling, dataminimalisatie of andere vormen van bescherming.

2.2.6.2 Authenticatie

Authenticatie bestaat over het algemeen uit twee stappen:

  1. Partij A levert controleerbaar bewijs aan partij B (presentatie, vaak ook identificatie genoemd)
  2. Partij B controleert het bewijs (verificatie)

Voorbeelden van controleerbaar bewijs zijn:

Het tonen van (digitale) certificaten of credentials
Het zetten van een digitale handtekening
Het zetten van een natte handtekening

Het controleren van het bewijs geschiedt op de wijze die past bij het aangeleverde bewijsmateriaal.

Authenticatie: bewijs presenteren en controleren
Figuur 6 Authenticatie: bewijs presenteren en controleren

2.2.6.3 Wederzijdse authenticatie: veilige digitale verbindingen

Veilige digitale verbindingen op basis van Blauwe Knop Connect werken als volgt:

  1. De organisatie kiest een digitaal sleutelpaar.
  2. De organisatie registreert het gekozen sleutelpaar bij de stelselbeheerder.
  3. Het hulpmiddel van de gebruiker kiest een digitaal sleutelpaar.
  1. Bij het verbinden met de organisatie controleert de gebruiker de sleutels van de organisatie (authenticatie #1)
  • Vertrouwen over de juistheid van de sleutels wordt afgeleid uit het stelseldocument.
  1. Bij het accepteren van verbindingen van gebruikers controleert de organisatie de sleutels van de gebruiker (authenticatie #2)
  • Vertrouwen over identiteit van de gebruiker wordt afgeleid uit eventueel aanwezige certificaten

De partijen zijn nu wederzijds geauthenticeerd.

  • De sleutels worden vervolgens gebruikt om een veilig transportkanaal op te zetten.
2.2.6.4 Resultaat authenticatie beschikbaar voor dienst

Het resultaat van de authenticatie wordt beschikbaar gesteld aan de afgenomen dienst, zodat die erop kan vertrouwen en identiteitsinformatie en/of sleutelparen kan (her)gebruiken voor verdere veiligheidsmaatregelen zoals toegangscontrole tot de specifieke dienst, personalisatie en/of versleuteling.

Architectuurvereisten:

  • De stelselbeheerder MOET de publieke sleutels van deelnemende organisaties opnemen in het stelseldocument.
  • De gebruiker MOET het stelseldocument raadplegen en de sleutels van deelnemende organisaties gebruiken om verbindingen met die betreffende organisaties te beveiligen (dus alleen verbindingen aangaan met organisaties die deze sleutels gebruiken)
  • De gebruiker MOET bewijslast presenteren aan de organisatie waarmee verbonden wordt.
  • De organisatie MOET de door de gebruiker aangeleverde bewijslast (handtekening, certificaten, credentials) controleren.
  • De organisatie MOET authenticatieresultaten beschikbaar stellen aan de dienst die wordt aangesproken.
  • De dienst MOET identiteitsinformatie (uit de authenticatieresultaten) gebruiken voor toegangscontrole tot de dienst.
  • De dienst MAG identiteitsinformatie (uit de authenticatieresultaten) gebruiken voor het personaliseren van de dienst.
  • De dienst MOET de sleutelinformatie van de gebruiker (uit de authenticatieresultaten) gebruiken voor versleuteling van informatie die digitaal wordt teruggestuurd naar de burger.

2.2.7 Een sleutelpaar van een gebruiker certificeren (hulpmiddelen activeren)

Aan een zelfgekozen sleutelpaar in een hulpmiddel kan (net als bij een zelfgekozen natte handtekening) enkel vertrouwen worden gesteld indien het sleutelpaar (of natte handtekening) reeds bij de partij die de sleutel controleert bekend is (alleen dan kan een gepresenteerde sleutel of handtekening worden vergeleken met de eerder bekende sleutel of handtekening).

Als dat nog niet het geval is, en zekerheid over de identiteit van de gebruiker voor het leveren van de dienst vereist is, is het nodig om extra bewijsmateriaal in de vorm van certificaten en/of credentials aan te leveren bij het opzetten van veilige verbindingen.

De gebruiker kan dit aanvullende bewijsmateriaal verkrijgen via het proces van legaliseren. Tijdens het legaliseren wordt de identiteit van de burger gecontroleerd en wordt de digitale sleutel (of natte handtekening) gekoppeld aan de persoon. Dit is een reeds lang bestaande juridische praktijk genaamd Legaliseren (van handtekeningen), waarvoor men in de papieren wereld onder meer terecht kan bij gemeenten, notarissen en/of (in het buitenland) bij een Nederlandse ambassade.

Digitaal kan dit op tenminste twee manieren:

  • Certificering met behulp van een wallet
  • Certificering door een derde partij (legalisator)

Digitaal legaliseren
Figuur 7 Digitaal legaliseren

Architectuurvereisten:

  • De stelselbeheerder MOET toegestane legalisatiemethoden opnemen in het stelseldocument
  • De stelselbeheerder MOET vertrouwde legalisators aanwijzen en opnemen in het stelseldocument
  • Een legalisator MOET beheer voeren over toegelaten hulpmiddelen voor specifieke ketendiensten
  • Een legalisator MOET de identiteit van de gebruiker controleren
  • Een legalisator MOET elk door de gebruiker gekozen sleutel certificeren (die aan de vereiste cryptografische specificaties voldoet)
  • Een legalisator MOET aan het einde van het legaliseerproces een certificaat en/of credential verstrekken aan de gebruiker dat gekoppeld is aan de door de gebruiker gekozen sleutel.
  • Een legalisator MOET elke gebruiker inzage geven in gelegaliseerde sleutels en bijbehorende certificaten/credentials.
  • Een legalisator MOET elke gebruiker de mogelijkheid geven certificaten/credentials in te trekken (revocation).
  • Een legalisator MOET certificaten/credentials intrekken indien er gegronde signalen zijn dat sprake is van misbruik (revocation).

2.2.8 Toegang krijgen tot diensten (autorisatie)

Omdat tijdens het verbinden met een dienst geregeld is dat een gebruiker van een dienst geauthenticeerd is, kan er bij de afhandeling van de dienst op worden vertrouwd dat de gebruiker van de dienst inderdaad is wie hij zegt dat hij is. De dienst kan dus zelf eenvoudiger blijven, omdat de complexiteit voor het veilig verbinden buiten de dienst wordt gehouden.

Een dienst krijgt bovendien toegang tot de informatie die tijdens de authenticatie van de gebruiker gecontroleerd is. Deze informatie kan daarom vervolgens worden gebruikt bij het bepalen of de dienst wordt verleend (autorisatie), en tijdens het afhandelen van de dienst (personalisatie). Deze en andere gegevens die worden gebruikt tijdens het afhandelen van de dienst mogen niet gebruikt worden voor andere doeleinden dan het afhandelen van de dienst.

Voorbeeld (Vorderingenoverzicht Rijk): Omdat de dienst waarmee een gebruiker informatie over betalingsverplichting aan een organisatie opvraagt wordt aangesproken via een veilige Blauwe Knop Connect verbinding, kan deze dienst bij de afhandeling (het verwerken van het informatieverzoek) gebruik maken van de tijdens de authenticatie verstrekte identiteitsgegevens (het BSN) om een persoonlijk antwoord op te stellen. Bovendien kan het tijdens het verbinden gebruikte sleutelmateriaal worden gebruikt om het persoonlijke antwoord te versleutelen zodat alleen de betreffende gebruiker het antwoord kan openen.

Een dienst gebruiken via een veilige verbinding
Figuur 8 Een dienst gebruiken via een veilige verbinding

Architectuurvereisten:

  • Een gebruiker MOET een dienst altijd aanroepen via een veilige verbinding.
  • Een gebruiker MOET bij het aanroepen van de dienst een verwijzing naar het authenticatieresultaat (toegangstoken) meesturen.
  • Een organisatie MAG NIET gegevens over de gebruiker van de dienst voor andere doeleinden gebruiken dan het uitvoeren van de dienst.
  • Een dienst MOET controleren of de gebruiker geautoriseerd is voor het gebruik van de dienst.
  • Een dienst MAG de gegevens over de gebruiker van de dienst gebruiken bij de afhandeling van de dienst.

2.3 De standaard in de praktijk brengen (specificaties en (referentie-)implementaties)

De architectuur zoals hier beschreven kan op verschillende manieren in de praktijk worden gebracht. Via verschillende media (fysiek, digitaal, etc.), met verschillende soorten hulpmiddelen (pen en papier, formulieren, hard- en software). De rollen van stelselbeheerder, legalisator en deelnemende gebruikers en organisaties kunnen op verschillende manieren belegd worden (overheden, notarissen, dienstverleners, etc.), maar ook digitaal met toepassing van meer klassieke (OpenID4VP) of moderne standaarden (FSC voor natuurlijke personen). En met gebruik van verschilende wijzen van identiteitscontrole bij deelname van natuurlijke personen aan het stelsel (DigiD, Digitale Identiteit, identiteitscontrole in persoon). In het volgende hoofdstuk worden een aantal van deze implementaties in detail gespecificeerd.

3. Specificaties

3.1 Stelselbeheer ⌛

⌛ nog niet beschikbaar: specificaties stelselbeheer

3.2 Vindbaarheidsconfiguratie ⌛

⌛ nog niet beschikbaar: specificaties vindbaarheidsconfiguratie

3.3 Diensten aanbieden via veilige verbindingen

3.3.1 Publiek internet (HTTPS-JWT): CreateSession

Deze sectie beschrijft een protocol waarmee de app aan een verifier kan aantonen dat hij controle heeft over de private key behorende bij een bepaalde public key. Dit protocol kan vervolgens gebruikt worden door:

  1. Een uitgever die de public key van de app in een Verifiable Credential (de App Manager JWS) stopt en deze vervolgens aan de app uitreikt;
  2. Een verifier, die middels dit protocol en het Verifiable Credential de gebruiker kan authenticeren.

Het protocol levert ook een sessietoken op die de gecreëerde sessie representeert voor gebruik in verdere applicatie-specifieke protocollen, en sleutelmateriaal om verder protocolverkeer te versleutelen.

In hoofdlijnen ziet dit protocol er als volgt uit.

`CreateSession` protocol (beknopte weergave)
Figuur 9 CreateSession protocol (beknopte weergave)

3.3.1.1 Scope

Het protocol in deze sectie is generiek in de zin dat deze voor authenticatie bij verschillende organisaties kan worden toegepast, voor verschillende en (mogelijk) ongerelateerde toepassingen, zoals hierboven beschreven in de sectie over Architectuur en functies. Er zijn daarom dus verschillende domeinen, of scopes, waarin authenticatie plaats moet kunnen vinden. Om ervoor te zorgen dat authenticatie binnen het ene domein niet verward kan worden met authenticatie in het andere domein (bijvoorbeeld dat een gebruiker met een Verifiable Credential verkregen voor de ene toepassing zich kan authenticeren bij een andere ongerelateerde toepassing) bevat het Verifiable Credential wat gebruikt wordt in dit protocol een scope parameter met een string als waarde.

Een organisatie gebruikt het protocol in deze sectie om een gebruiker te authenticeren teneinde een specifieke dienst aan te kunnen bieden. Het domein van die dienst wordt gerepresenteerd door de scope. De organisatie MOET nadat het protocol in deze sectie is afgerond de scope uit het Verifiable Credential vergelijken met de scope die hij verwacht, en afbreken als die niet overeenkomen.

De App MAG meerdere Verifiable Credentials hebben met verschillende waardes voor de scope parameter, zodat hij zich kan authenticeren in verschillende toepassingen. De App moet voordat het protocol in deze sectie begint weten welke scope de Verifier verwacht.

3.3.1.2 Verifiable Credentials en Presentations
3.3.1.2.1 Verifiable Credentials

Het Verifiable Credential die de App ontvangt van de App Manager en tijdens authenticatie richting de Verifier presenteert MOET een JWS zijn, met daarin de volgende velden (claims):

Claim Name Claim Description
app_public_key Public key van de burger in DER formaat, Base64-encoded
scope Scope (zie "Scope" sectie hierboven)
iss Organisatie-identificatienummer van de app manager
iat (Issued At) Moment van uitgifte (Unix timestamp)
nbf (Not Before) Begindatum van geldigheid (Unix timestamp)
exp (Expiry) Verloopdatum (Unix timestap)
bsn Burgerservicenummer
given_name Voornaam/voornamen
family_name Achternaam/achternamen

Hierin zijn alle drieletterige claims behalve bsn gestandaardiseerd in het IANA "JSON Web Token Claims" register.

De JWS MAG een kid veld in de header bevatten die de public key van de App Manager identificeert waarmee de JWS geverifieerd kan worden. Indien aanwezig MOET dit veld een string zijn. Samen met het iss veld kan de App Manager public key worden opgezocht middels een proces dat kan verschillen per scope (zie de "App manager public key lookup" sectie hieronder).

Voorbeeld:

{
  "typ": "jwt",
  "alg": "ES256",
  "kid": "1"
}
.
{
  "app_public_key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0Ejs8jmnIjkb+wMpaQugg6VY6j7bpgYQYGTt7Ji/RhSJvQKT9Q63RsfD0XtdIlgosZkV70ocwbYhL8HadgVulQ==",
  "scope": "nl.vorijk.oauth_scope.blauwe_knop",
  "iss": "00000001234567890000", // OIN
  "iat": 1704063600,
  "nbf": 1704063600,
  "exp": 1735686000,
  "bsn": "999991772",
  "given_name": "Willeke Liselotte",
  "family_name": "De Bruijn"
}
3.3.1.2.2 Verifiable Presentation

Voordat de App zich authenticeert aan een Verifier MOET hij controleren dat het Verifiable Credential volgens de timestamp in het exp veld niet verlopen is, of gaat verlopen binnen één minuut. Als dat wel zo is, dan MOET de App het Verifiable Credential eerst verversen voordat hij aan het protocol begint.

Tijdens authenticatie ondertekent de App met diens private key (waarvan de public key in de app_public_key claim in het Verifiable Credential staat) een willekeurige string, genaamd de nonce, die gegenereerd is door de Verifier. Dit resulteert in een JWS waarin de volgende claims MOETEN staan:

Claim naam Claim beschrijving
sub String die de waarde "challenge_response" MOET hebben
aud OIN van de Verifier waar de App naar authenticeert
nonce Willekeurige string gegenereerd door de Verifier

Voorbeeld:

{
  "typ": "jwt",
  "alg": "ES256",
}
.
{
  "sub": "challenge_response",
  "aud": "00000001234567890001",
  "nonce": "L9E4aGM9ZzhhC7WLVxa1XKOzie7bzKh0"
}

Vervolgens maakt de App een Verifiable Presentation, die in deze standaard een JSON object is met daarin de volgende velden:

Naam Beschrijving
app_nonce_signature Bovenstaande JWS
certificate_type MOET zijn ofwel "app_manager_jwt_certificate" ofwel "certificate_type_self_signed"
certificate Het Verifiable Credential als certificate_type gelijk is aan "app_manager_jwt_certificate"; of een self-signed JWT (zie hieronder) met daarin de app public key als certificate_type gelijk is aan "certificate_type_self_signed"
session_aes_key AES key (Base64-encoded) voor versleuteling van verder verkeer

Als certificate_type gelijk is aan certificate_type_self_signed, dan MOET het certificate veld een JWS hebben van de volgende vorm:

{
  "typ": "jwt",
  "alg": "ES256",
}
.
{
  "app_public_key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE16YiVsBE1K+I5iksaBbkc1Evfk6/0wPSO3Rwni1HVqOcmy5Hjr61/arQxibswOj+v/8uBCA/AzMFVvqFOI96Vg==",
  "sub": "certificate_type_self_signed"
}

Deze JWS MOET getekend zijn met de private key waarvan de public key in het app_public_key veld staat, en de JWS in het app_nonce_signature MOET ook met deze private key getekend zijn.

Voorbeelden van Verifiable Presentations:

  • Als certificate_type gelijk is aan app_manager_jwt_certificate:
    {
      "app_nonce_signature": "eyJ0eXAiOiJqd3QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJjaGFsbGVuZ2VfcmVzcG9uc2UiLCJhdWQiOiIwMDAwMDAwMTIzNDU2Nzg5MDAwMSIsIm5vbmNlIjoiTDlFNGFHTTlaemhoQzdXTFZ4YTFYS096aWU3YnpLaDAifQ.1TtHJXzBS3OGZzMKcalw5qoQb8H-WAwTIeOIWROM0hCDxKRKQdQyz_jESVycQSwnk9Ldgv87_e9KZr4SkOh_NQ",
      "certificate_type": "app_manager_jwt_certificate",
      "certificate": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBfcHVibGljX2tleSI6Ik1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTE2WWlWc0JFMUsrSTVpa3NhQmJrYzFFdmZrNi8wd1BTTzNSd25pMUhWcU9jbXk1SGpyNjEvYXJReGlic3dPait2Lzh1QkNBL0F6TUZWdnFGT0k5NlZnPT0iLCJzY29wZSI6Im5sLnZvcmlqay5vYXV0aF9zY29wZS5ibGF1d2Vfa25vcCIsImlzcyI6IjAwMDAwMDAxMjM0NTY3ODkwMDAwIiwiaWF0IjoxNzA0MDYzNjAwLCJuYmYiOjE3MDQwNjM2MDAsImV4cCI6MTczNTY4NjAwMCwiYnNuIjoiOTk5OTkxNzcyIiwiZ2l2ZW5fbmFtZSI6IldpbGxla2UgTGlzZWxvdHRlIiwiZmFtaWx5X25hbWUiOiJEZSBCcnVpam4ifQ.3r49YRPFBj6imBBMJHH9NHS-G9WZW6omC78wFlqC8Z3vV7TnKzdQBc3b3_2P6TgqwAjB4gZs9Gd-NNijygkv3w",
      "session_aes_key": "/YyG+FNLinwQqZFgGUribQ=="
    }
    
  • Als certificate_type gelijk is aan certificate_type_self_signed:
    {
      "app_nonce_signature": "eyJ0eXAiOiJqd3QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJjaGFsbGVuZ2VfcmVzcG9uc2UiLCJhdWQiOiIwMDAwMDAwMTIzNDU2Nzg5MDAwMSIsIm5vbmNlIjoiTDlFNGFHTTlaemhoQzdXTFZ4YTFYS096aWU3YnpLaDAifQ.1TtHJXzBS3OGZzMKcalw5qoQb8H-WAwTIeOIWROM0hCDxKRKQdQyz_jESVycQSwnk9Ldgv87_e9KZr4SkOh_NQ",
      "certificate_type": "certificate_type_self_signed",
      "certificate": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBfcHVibGljX2tleSI6Ik1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTE2WWlWc0JFMUsrSTVpa3NhQmJrYzFFdmZrNi8wd1BTTzNSd25pMUhWcU9jbXk1SGpyNjEvYXJReGlic3dPait2Lzh1QkNBL0F6TUZWdnFGT0k5NlZnPT0iLCJzdWIiOiJjZXJ0aWZpY2F0ZV90eXBlX3NlbGZfc2lnbmVkIn0.N5ukfBIFd-17vx8I5SszixkZGW4Ay4Zq2-e1eXqmJ5l-kIC_TVWmc5b72-SB5e7yER2Kaq1GS3g4SFQjD9LuVA",
      "session_aes_key": "/YyG+FNLinwQqZFgGUribQ=="
    }
    

De Verifier MOET de volgende stappen uitvoeren bij het verifiëren van de Verifiable Presentation:

  1. Controleer dat de Verifiable Presentation een JSON object is met daarin de velden uit de tabel hierboven, van de juiste JSON datatypes.
  2. Controleer dat de session_aes_key in de Verifiable Presentation bestaat uit 16 bytes na Base64 decoding.
  3. Controleer dat het certificate veld een string is van de vorm van een JWS, en parse de header en body van de JWS (nog zonder de JWS te verifiëren).
  4. Controleer dat certificate_type in de Verifiable Presentation een van de volgende twee waardes bevat.
    1. "certificate_type_self_signed". Verifieer in dit geval de JWS in het certificate veld als volgt.
      1. Controleer dat de body van de JWS een app_public_key veld bevat, met daarin een Base64-encoded DER-encoded EC public key van een ondersteund algoritme en curve die geldig is (de coördinaten refereren naar een bestaand element van de elliptic curve).
      2. Verifieer de JWS tegen deze public key.
      3. Controleer dat de JWS een sub veld met waarde "certificate_type_self_signed" bevat.
    2. "app_manager_jwt_certificate". Verifieer in dit geval de JWS in het certificate veld als volgt.
      1. Gegeven het kid veld uit de header (indien aanwezig), en de iss en scope velden uit de body, zoek de public key van de app manager op. (Dit proces kan verschillen per scope, zie de "App manager public key lookup" sectie hieronder.)
      2. Gegeven de public key van de app manager, verifieer het certificate veld als JWS. Controleer hierbij ook de nbf en exp velden als in § 4.1 van RFC 7519.
      3. Controleer dat de JWS de velden uit de Verifiable Credentials sectie bevat, en dat die van het juiste JSON datatypes zijn.
      4. Voor gebruik in de volgende stap, parse het app_public_key veld uit de JWS als Base64-encoded DER-encoded EC public key, en controleer dat hij van een ondersteund algoritme en curve is en dat hij geldig is (de coördinaten refereren naar een bestaand element van de elliptic curve).
  5. Verifieer dat de app_nonce_signature in de Verifiable Presentation een geldige JWS is ten opzichte van de geparseerde app_public_key uit de JWS van de vorige stap, met als claims:
    • sub met als vaste waarde challenge_response,
    • de OIN van de Verifier in het aud veld,
    • de nonce die de Verifier eerder naar de App heeft gestuurd.

De bsn, given_name, en family_name velden uit het Verifiable Credential (in het geval van app_manager_jwt_certificate) of de app_public_key uit het certificate (in het geval van certificate_type_self_signed) zijn nu gevalideerd en klaar voor gebruik.

3.3.1.3 App manager public key lookup

Apps en organisaties moeten gegeven de scope, de iss en de kid uit het Verifiable Credential de public key van de App Manager (de uitgever van het Verifiable Credential) kunnen opzoeken, waarmee het Verifiable Credential kan worden geverifieerd. Hoe dit gedaan moet worden verschilt per scope. In het geval dat de scope gelijk is aan nl.vorijk.oauth_scope.blauwe_knop gaat dit proces als volgt.

App Manager key lookup
Figuur 10 App Manager key lookup

3.3.1.4 Protocolbeschrijving
3.3.1.4.1 Sequence diagram

Het protocol ziet er in een sequence diagram als volgt uit.

`CreateSession` protocol
Figuur 11 CreateSession protocol

3.3.1.4.2 Protocolberichten

Er volgt een expliciete beschrijving van de protocolberichten, die refereert aan de genummerde stappen in bovenstaand sequence diagram. Alle whitespace in JSON structuren is enkel bedoeld voor de leesbaarheid van deze standaard en dient niet te worden opgenomen in implementaties.

3.3.1.4.2.1 Stap 2

De App vraagt een nieuwe challenge op met een HTTP POST request zonder body naar /v1/challenge.

3.3.1.4.2.2 Stap 4

De Verifier genereert met een CSPRNG een verse nonce bestaande uit minimaal 16 willekeurige bytes.

3.3.1.4.2.3 Stap 9

De Verifier antwoordt op het HTTP request van de App uit stap 2 met een JWS, ondertekend met de root organization EC private key, en met de volgende claims:

  • sub: een string die de waarde "challenge" MOET hebben.
  • nonce: de nonce uit Stap 4, Base64-encoded.
  • ephemeral_organization_ec_public_key: de Base64-encoding van de DER-encoded ephemeral organization EC public key.

De JWS MAG een kid header gebruiken om de public key aan te duiden waarmee de JWS geverifieerd moet worden.

Voorbeeld:

{
  "typ": "jwt",
  "alg": "ES256",
  "kid": "1"
}
.
{
  "sub": "challenge",
  "nonce": "BZpwbYf2TIYxvJEQY2FtAg==",
  "ephemeral_organization_ec_public_key": "MFkw....Wzhw=="
}
3.3.1.4.2.4 Stap 10 t/m 12

De App:

  • Controleert dat de root organization EC public key van een ondersteund algoritme en curve is en dat hij geldig is (de coördinaten refereren naar een bestaand element van de elliptic curve).
  • Verifieert de JWS van de Verifier uit bovenstaande stap met de root organization EC public key.
  • Controleert dat de JWS een sub veld met waarde challenge bevat.
  • Controleert dat de ephemeral organization EC public key van een ondersteund algoritme en curve is en dat hij geldig is.
3.3.1.4.2.5 Stap 13

De App genereert met een CSPRNG een nieuwe willekeurige AES key van de juiste grootte (128 bits in het geval van AES128 en 256 bits in het geval van AES256).

3.3.1.4.2.6 Stap 14 t/m 19

De App maakt het Verifiable Presentation als in de "Verifiable Presentation" sectie hierboven, en versleutelt deze middels ECDH-ES in de vorm van een JWE naar de ephemeral organization EC public key van de Verifier.

3.3.1.4.2.7 Stap 20

De App stuurt middels een HTTP POST naar /v1/complete het volgende JSON object naar de Verifier:

  • nonce: de nonce die de Verifier eerder aanleverde.
  • encrypted_challenge_result: de Verifiable Presentation JWE uit de vorige stap.

Voorbeeld:

{
    "nonce": "BZpwbYf2TIYxvJEQY2FtAg==",
    "encrypted_challenge_result": "eyBLyPjsJZs...5Y2tNYLRui"
}
3.3.1.4.2.8 Stap 25

De Verifier MOET de Verifiable Presentation verifiëren als in de "Verifiable Presentation" sectie hierboven.

3.3.1.4.2.9 Stap 26

De Verifier genereert met een CSPRNG een willekeurige alfanumerieke session token die minimaal 22 karakters MOET zijn (zodat hij minimaal 128 bit entropie heeft).

3.3.2 Publiek Internet (HTTPS-OpenID4VP)

In deze variant maakt de app gebruik van het OpenID4VP protocol voor authenticeren richting een organisatie. Dit protocol is gebaseerd op OpenID Connect en OAuth (RFC 6749), met als belangrijkste verschil dat de eindgebruiker (de app) tijdens het protocol rechtstreeks en uitsluitend communiceert met de Relying Party/Verifier (de organisatie), zonder rechtstreekse betrokkenheid van de partij die de identiteit van de eindgebruiker attesteert (de App Manager). Tijdens het protocol authenticeert de app zich richting de organisatie middels een Verifiable Credential, in ons geval de App Manager JWS.

NB: het OpenID4VP protocol is in actieve ontwikkeling, en geregeld worden er nieuwe draft versies van uitgebracht. Deze sectie is gebaseerd op draft 20 van OpenID4VP. Inmiddels bestaan er een aantal nieuwe draft versies.

De eenvoudigste variant van dit protocol ziet er in het algemeen als volgt uit.

OpenID4VP protocol (beknopte weergave)
Figuur 12 OpenID4VP protocol (beknopte weergave)

In het Authorization Request staan de gegevens die de Verifier van de App opvraagt, de nonce die de App moet ondertekenen met de private keys van de Verifiable Credentials die hij gebruikt, en de identiteit van de Verifier. De Authorization Response bevat de disclosure (de Verifiable Presentation(s)).

3.3.2.1 Terminologie

Dezelfde terminologie als in de Terminologie sectie, met daaraan toegevoegd:

  • Authorization Request: een OAuth databericht die de Verifier (OAuth Client) stuurt aan de App (OAuth Authorization Server) met daarin de identiteit van de Verifier, de gevraagde gegevens uit de Verifiable Credential(s), en een nonce (soms ook challenge genoemd) ter verdediging tegen replay attacks.
  • Authorization Response: een OAuth databericht die de App stuurt aan de Verifier, met daarin de Verifiable Presentation.

Tijdens het protocol fungeert de Verifier als een OAuth Client ten opzichte van de App, die fungeert als een OAuth Authorization Server.

Voor de duidelijkheid volgt hier een overzicht van hoe de verschillende standaarden naar de twee partijen refereren.

OAuth OpenID Connect OpenID4VP Deze standaard
Verstuurt Authorization Request Client Client Verifier Verifier
Verstuurt Authorization Response Authorization Server OP (OpenID Provider) Wallet App
3.3.2.2 Cryptografie

Bovenop de "Cryptografie" sectie geldt in deze sectie het volgende:

Elk versleuteld bericht in deze sectie MOET in de vorm van een JWE zijn (RFC 7516; zie ook de Cryptografie sectie hierboven).

3.3.2.3 Verifiable Credentials en Presentations
3.3.2.3.1 Verifiable Credentials

Het Verifiable Credential die de App ontvangt van de App Manager en tijdens authenticatie richting de Verifier presenteert MOET een JWS zijn, met daarin de volgende velden (claims):

Claim naam Claim beschrijving
iss Organisatie-identificatienummer (OIN) van de App Manager
iat Issued At (tijdstip van uitgifte)
nbf Not Before (niet geldig voor)
exp Expiration Time (verloopdatum)
cnf Public key van de App, als in RFC 7800
given_name Voornaam/voornamen
family_name Achternaam/achternamen
bsn Burgerservicenummer

Hierin zijn alle claims behalve de laatste gestandaardiseerd in het IANA "JSON Web Token Claims" register.

De JWS MAG een kid veld in de header bevatten die de public key van de App Manager identificeert waarmee de JWS geverifieerd kan worden.

Voorbeeld:

{
  "typ": "jwt",
  "alg": "ES256",
  "kid": "1"
}
.
{
  "iss": "00000001234567890000", // OIN
  "iat": 1704063600,
  "nbf": 1704063600,
  "exp": 1735686000,
  "cnf": {
    "jwk": {
      "kty": "EC",
      "alg": "ES256",
      "crv": "P-256",
      "use": "sig",
      "x": "2xJs8w74D4glCnAF5W8Ax9EJf6XGSLCTlotBDrMbRd0",
      "y": "YQtuD1-gqVB6XDWIr76jRYL2xNr7YdnV1V7hGogwHgw"
    },
  },
  "given_name": "Willeke Liselotte",
  "family_name": "De Bruijn",
  "bsn": "999991772"
}
3.3.2.3.2 Verifiable Presentation

Tijdens authenticatie van de App richting een Verifier ondertekent de App met diens private key (waarvan de public key in de cnf claim in het Verifiable Credential staat) een willekeurige string, genaamd de nonce, die gegenereerd is door de Verifier. Dit resulteert in een JWS waarin de volgende claims MOETEN staan:

Claim naam Claim beschrijving
aud URL van de Verifier waar de App naar authenticeert
nonce Willekeurige string gegenereerd door de Verifier

Voorbeeld:

{
  "typ": "jwt",
  "alg": "ES256",
}
.
{
  "aud": "https://openid4vp-authentication-process.example.com",
  "nonce": "L9E4aGM9ZzhhC7WLVxa1XKOzie7bzKh0"
}

Vervolgens maakt de App een Verifiable Presentation, die in deze standaard een JSON object is waarin beide JWS MOETEN staan:

{
  "vc": "eyJjc....5TRSJ9", // Verifiable Credential
  "disclosure": "eyJjc....f7B-q2" // Bovenstaande JWS
}

De Verifier MOET de volgende stappen uitvoeren bij het verifiëren van de Verifiable Presentation:

  1. Controleer dat de Verifiable Presentation een JSON object is die de vc en disclosure velden bevat, en dat dit strings zijn.
  2. Verifieer de vc string als JWS tegen de public key(s) van de App Manager(s), eventueel met behulp van het iss veld uit de JWS body en/of het kid veld in de JWS header. Controleer hierbij ook dat het iss veld de OIN bevat van een vertrouwde App Manager, en valideer de nbf en exp velden als in § 4.1 van RFC 7519.
  3. Controleer dat de vc JWS een cnf veld heeft, met daarin een jwk veld, en parse de public key die daarin staat.
  4. Met de public key uit bovenstaande stap, verifieer de disclosure string als JWS.
  5. Controleer dat de disclosure JWS een aud veld heeft en dat de waarde daarvan de URL van de Verifier is.
  6. Controleer dat de disclosure JWS een nonce heeft en dat de waarde daarvan overeenkomt met wat de Verifier eerder had gegenereerd.
  7. Controleer dat de vc JWS alle velden uit de tabel in voorgaande sectie heeft, voor zover niet al gecontroleerd in bovenstaande stappen.
3.3.2.4 Protocolstructuur

In deze sectie beschrijven we het protocol op hoog niveau door keuzes te nemen in bepaalde parameters die de OpenID4VP standaard aanbiedt, en door te beschrijven hoe we encryptie op applicatieniveau realiseren.

3.3.2.4.1 OpenID4VP parameters

De OpenID4VP standaard biedt op een aantal plekken verschillende opties en varianten aan. Deze standaard maakt daarin de volgende keuzes.

  1. "JWT-Secured Authorization Request (JAR)" (RFC 9101). Deze uitbreiding op OAuth en OpenID4VP is optioneel in OpenID4VP maar MOET gebruikt worden in deze standaard. Het voegt het volgende toe:
    • Het Authorization Request wordt door de Verifier digitaal ondertekend in de vorm van een JWS, genaamd de Request Object, zodat de App het Authorization Request kan authenticeren als afkomstig van een bekende Verifier.
    • De Verifier stuurt het Request Object niet rechtstreeks naar de App, maar stuurt in plaats daarvan een URL genaamd de Request URI. De App voert een HTTP GET uit op de Request URI om het Request Object te verkrijgen. Deze uitbreiding is optioneel in RFC 9101, maar MOET in deze standaard gebruikt worden.
  2. "JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)". Deze uitbreiding op OAuth en OpenID4VP is optioneel in OpenID4VP maar MOET gebruikt worden in deze standaard. In deze uitbreiding versleutelt de App de Authorization Response (waarin de Verifiable Presentation staat), in de vorm van een JWE. De App gebruikt voor deze versleuteling een ephemeral (dus verschillend per sessie) public key van de Verifier die de Verifier meestuurt naar de App in het Request Object.
  3. De response_type parameter van het Authorization Request (gedefinieerd in OAuth) MOET de waarde vp_token hebben, gedefinieerd in § 5.4 van OpenID4VP. Deze waarde bepaalt dat de App een Verifiable Presentation op moet nemen in een parameter genaamd vp_token in de Authorization Response.
  4. De waarde van de client_id_scheme parameter van het Authorization Request MOET pre-registered zijn. De waarde van de client_id parameter van het Authorization Request MOET dus per de OpenID4VP standaard een identifier van de Verifier zijn die de App van tevoren al kent. De App gebruikt deze identifier tijdens de sessie om de public keys van de Verifier op te zoeken waarmee het Request Object JWS geverifieerd kan worden en waarnaar de Authorization Response JWE versleuteld kan worden.
  5. De waarde van de scope parameter van het Authorization Request MOET zijn nl.vorijk.oauth_scope.blauwe_knop.vp. Per de OpenID4VP standaard MOETEN de presentation_definition en presentation_definition_uri parameters dus NIET opgenomen zijn in het Authorization Request.
  6. "OAuth 2.0 Multiple Response Type Encoding Practices": voegt een parameter genaamd response_mode toe aan het Authorization Request, die bepaalt hoe de App de Authorization Response terug moet geven. In deze standaard MOET de response_mode parameter de waarde direct_post.jwt hebben, zoals gespecificeerd in § 6.2 van OpenID4VP. Deze waarde bepaalt het volgende:
    • In het Authorization Request MOET de Verifier een response_uri parameter opnemen.
    • De App MOET de Authorization Response naar de response_uri versturen, URL-encoded in een HTTP POST naar de response_uri.
    • De App MOET gebruik maken van JARM, dus de Authorization Response moet versleuteld versturen in de vorm van een JWE.
  7. Bovenstaand response_uri endpoint van de Verifier MOET, als de Verifier de Authorization Response met succes heeft geverifieerd, antwoorden met een JSON object met daarin een redirect_uri parameter. Dit is gedefinieerd als optioneel in § 6.2 van OpenID4VP maar is verplicht in deze standaard. (Deze redirect_uri moet niet verward worden met de identiek genaamde redirect_uri parameter die normaal gesproken in OAuth in het Authorization Request staat.) Er MOET een vers willekeurige string gegenereerd met een CSPRNG in deze request_uri parameter staan zodat deze uniek is per sessie.
3.3.2.4.2 Redirect URI

Het protocol eindigt met de App die van de Verifier de redirect_uri genoemd in het laatste punt hierboven ontvangt. Normaal gesproken in OpenID4VP opent de App vervolgens deze redirect_uri in een browser, zodat daarin de flow van de applicatie verder kan gaan. In deze standaard wordt in plaats daarvan de redirect_uri gebruikt als drager van een access token, in de volgende vorm:

bk-connect://organization-discovery-url/?access-token=example-access-token&access-token-type=OpenID4VP

Het access token hierin verleent de App toegang tot geauthenticeerde endpoints van de Dienst (dat wil zeggen, endpoints die alleen geauthenticeerde gebruikers mogen aanroepen, voor bijvoorbeeld het ophalen van documenten die betrekking hebben op de gebruiker).

3.3.2.4.3 Encryptie

Alle verkeer tussen de App en de (infrastructuur van de) Verifier en/of Dienst MOET gebruik maken van minstens TLS 1.3.

In de praktijk eindigt de TLS-tunnel in de infrastructuur van de Verifier of Dienst vaak bij een reverse proxy, en is het gegevensverkeer dus in plain text zichtbaar voor die reverse proxy en mogelijke middleware die daarachter staat. Daarom gebruikt deze standaard ook encryptie op applicatieniveau (dat wil zeggen, bovenop de TLS-encryptie van de transportlaag) om de gegevens die verstuurd worden tijdens en na de OpenID4VP-sessie te beschermen als volgt.

  • Tijdens het aanmaken van het Request Object MOET de Verifier een ephemeral (dus verschillend per sessie) public/private keypair voor encryptie aanmaken, en de public key hiervan leveren aan de app in het Request Object. De App gebruikt deze als volgt.
    • De App MOET (zoals in de vorige subsectie beschreven) zijn Authorization Response naar deze public key versleutelen middels JARM.
    • Nadat de OpenID4VP-sessie is afgelopen, en de applicatie van de Dienst het overneemt, MAG de App deze public key gebruiken om verdere informatie voor de Dienst te versleutelen op applicatieniveau.
  • Tijdens het aanmaken van het Authorization Response MOET de App een AES key aanmaken, en die meeleveren aan de Verifier in het Authorization Response. (Dit is een toevoeging van deze standaard en niet gedefinieerd in OpenID4VP.) Nadat de OpenID4VP-sessie is afgelopen, en de applicatie van de Dienst het overneemt, MOET de Dienst informatie voor de App versleutelen op applicatieniveau met deze AES key.
3.3.2.5 Protocolbeschrijving

De keuzes beschreven in bovenstaande sectie resulteren bij elkaar in een protocol die we in deze sectie verder uitwerken en expliciet maken.

3.3.2.5.1 Sequence diagram

Het protocol ziet er in een sequence diagram als volgt uit.

OpenID4VP protocol
Figuur 13 OpenID4VP protocol

3.3.2.5.2 Protocolberichten

Er volgt een expliciete beschrijving van de protocolberichten, die refereert aan de genummerde stappen in bovenstaand sequence diagram. Alle whitespace in JSON structuren is enkel bedoeld voor de leesbaarheid van deze standaard en dient niet te worden opgenomen in implementaties.

3.3.2.5.2.1 Stap 1

De App voert een GET uit op de request_uri van de Verifier:

GET /request_uri HTTP/1.1
3.3.2.5.2.2 Stap 4

De Verifier genereert de Request Object JWS, met daarin de volgende velden in de payload:

  • client_id: URL die de Verifier identificeert.
  • response_uri: URL waarnaar de App het Authorization Response dient te sturen.
  • nonce: een willekeurige string gebruik makend van de URL-safe Base64 karakterset, genereerd met een CSPRNG, die minimaal 22 karakters MOET zijn (zodat hij minimaal 128 bit entropie heeft).
  • client_metadata: JSON object met een jwks veld erin, met een keys veld daarin die de ephemeral verifier encryption public key uit Stap 2 bevat, als per RFC 7591 en RFC 7517.

De Verifier MAG een kid veld opnemen in de JWS header om aan te duiden met welke public key de JWS geverifieerd moet worden.

Voorbeeld:

{
  "typ": "jwt",
  "alg": "RS256",
  "kid": "1",
}
.
{
  "response_type": "vp_token",
  "response_mode": "direct_post.jwt",
  "client_id_scheme": "pre-registered",
  "client_id": "https://organization.example.com",
  "response_uri": "https://organization.example.com/response_uri",
  "scope": "nl.vorijk.oauth_scope.blauwe_knop.vp",
  "nonce": "L9E4aGM9ZzhhC7WLVxa1XKOzie7bzKh0",
  "client_metadata": {
    "jwks": {
      "keys": [{
        "kty": "EC",
        "crv": "P-256",
        "alg": "ECDH-ES",
        "use": "enc",
        "x": "GD006BBz6L9x1cQZQtihWeL_CBcJqjMerlFhGNHt6q8",
        "y": "dUCZyFZXdDNDTC_mRRveNtY_qT8D-LCDGoaNwE8i8rU"
      }]
    }
  }
}

De Verifier antwoordt het GET request uit stap 1 met bovenstaande JWS als volgt:

HTTP/1.1 200 OK
Content-type: application/oauth-authz-req+jwt

eyJhb...x5Nz-g
3.3.2.5.2.3 Stap 7 t/m 9

Gegeven het Verifiable Credential produceert de App een Verifiable Presentation per de "Verifiable Presentation" sectie hierboven. Vervolgens plaatst de App de Verifiable Presentation in het vp_token veld in de Authentication Response, samen met de ephemeral app encryption public key.

Voorbeeld:

{
  "vp_token": {
    "vc": "eyJjc....5TRSJ9",
    "disclosure": "eyJjc....f7B-q2"
  },
  "presentation_submission": {
    "id": "nl.vorijk.presentation_submission.blauwe_knop",
    "definition_id": "nl.vorijk.presentation_definition.blauwe_knop",
    "descriptor_map": [
      {
        "id": "nl.vorijk.descriptor_map.blauwe_knop",
        "format": "jwt",
        "path": "$",
        "path_nested": {
          "format": "jwt",
          "path": "$.vc"
        }
      }
    ]
  },
  "jwks": {
    "keys": [{
      "kty": "oct",
      "alg": "A128KW",
      "k": "GawgguFyGrWKav7AX4VKUg"
    }]
  }
}

Hierin MOET presentation_submission altijd bovenstaande waarde hebben, per § 6.1 van OpenID4VP. Dit geeft aan de Verifier aan waar deze het Verifiable Credential kan vinden binnen de ontvangen Verifiable Presentation.

Het jwks veld hierin maakt het mogelijk voor de app om een AES encryption key te versturen waarmee de app en de gebruikende applicatie data op applicatieniveau kunnen versleutelen, wanneer ze verkeer naar elkaar sturen nadat de OpenID4VP-sessie is afgerond. Dit is een toevoeging van deze standaard en niet gedefinieerd in OpenID4VP. De JSON-structuur van het jwks veld is gedefinieerd in RFC 7591 en RFC 7517 en net als in het Request Object. Bovenstaand voorbeeld maakt gebruik van de A128KW waarde voor alg, als gedefinieerd in § 4.1 van RFC 7518, welke aangeeft dat wanneer deze key gebruikt wordt om een JWE mee te maken deze JWE ook gebruik moet maken van A128KW voor alg. Andere waardes uit deze RFC die gebruikt MOGEN worden:

  • A192KW
  • A256KW
  • dir

Na het produceren van bovenstaand Authorization Response versleutelt de App hem naar de ephemeral verifier encryption public key uit het Request Object, door het op te nemen als payload in een JWE als in § 6.3 van OpenID4VP, en stuurt het op naar de response_uri uit het Request Object, als volgt:

POST /response_uri HTTP/1.1
Content-Type: application/x-www-form-urlencoded

response=eyJra...9t2LQ
3.3.2.5.2.4 Stap 12

De Verifier MOET de Verifiable Presentation in de Authorization Response valideren als in § 6.5 van OpenID4VP en de "Verifiable Presentation" sectie hierboven.

3.3.2.5.2.5 Stap 14

De Verifier genereert met een CSPRNG een willekeurige alfanumerieke access-token die minimaal 32 karakters MOET zijn, en plaatst deze in een URI van de volgende vorm:

bk-connect://organization-discovery-url/?access-token=9YryEzKheqpx5iS2JsDNRHoydCBIsAKV&access-token-type=OpenID4VP
3.3.2.5.2.6 Stap 17

De Verifier antwoordt op de HTTP POST uit stap 10 met bovenstaande URI als volgt:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "redirect_uri": "bk-connect://organization-discovery-url/?access-token=9YryEzKheqpx5iS2JsDNRHoydCBIsAKV&access-token-type=OpenID4VP"
}

Als het valideren van de Authorization Response faalt MOET de Verifier in plaats van bovenstaande antwoorden als in § 6.4 van OpenID4VP.

3.4 Hulpmiddelen activeren

3.4.1 Publiek internet (HTTPS-JWT)

Dit protocol maakt gebruik van het CreateSession protocol voor het uitgeven of verversen van een Verifiable Credential, met certificate_type_self_signed als waarde voor de certificate_type parameter. Hiermee wordt het volgende bereikt:

  • De App maakt de public key die in het Verifiable Credential moet komen kenbaar aan de Credential Issuer, en bewijst tegelijk controle te hebben over de corresponderende private key.
  • Er wordt een AES key bepaald waarmee de rest van het verkeer in dit protocol versleuteld wordt, bovenop de encryptie van de transportlaag (TLS).

Vervolgens opent de App de browser om daarin de gebruiker te identificeren en authenticeren, middels DigiD. Indien dit slaagt wordt de app weer vanuit de browser geopend middels de Universal Link van de App, met een registration_token als (versleutelde) parameter, die daarna ingewisseld kan worden bij de Credential Issuer voor het Verifiable Credential.

Nadat het Verifiable Credential is geregistreerd geldt de gebruiker als geregistreerd bij de Credential Issuer. De App en de Credential Issuer slaan het registration_token beiden op voor later hergebruik. De Credential Issuer slaat daarbij ook de attributen van de gebruiker op die hij eerder in het Verifiable Credential heeft uitgegeven. Wanneer het Verifiable Credential van de App is verlopen, kan deze middels het eerder ontvangen registration_token een vers Verifiable Credential opvragen bij de Credential Isser.

3.4.1.1 Protocolbeschrijving
3.4.1.1.1 Sequence diagram

Het protocol ziet er in een sequence diagram als volgt uit.

`Issuance` protocol
Figuur 14 Issuance protocol

3.4.1.1.2 Protocolberichten

Er volgt een expliciete beschrijving van de protocolberichten, die refereert aan de genummerde stappen in bovenstaand sequence diagram. Alle whitespace in JSON structuren is enkel bedoeld voor de leesbaarheid van deze standaard en dient niet te worden opgenomen in implementaties.

3.4.1.1.2.1 Stap 2

De App en de Credential Issuer voeren het CreateSession protocol uit. De App MOET hierbij voor de certificate_type parameter de waarde certificate_type_self_signed gebruiken. Dit protocol resulteert in een session_token en een AES key voor later gebruik.

3.4.1.1.2.2 Stap 3

De App navigeert naar https://credential-issuer.example.com/register_app?session_token=..., waarbij het session_token uit de vorige stap wordt ingevuld.

(NB: in andere protocollen in deze standaard wordt het session_token uit het CreateSession protocol verstuurd in de Authorization HTTP header van een POST request. Dat is in dit geval echter niet mogelijk. Daarom wordt het session_token in dit geval middels een URL parameter in de URL van de issuer meegegeven.)

3.4.1.1.2.3 Stap 6 en 7

De eindgebruiker wordt geïndentificeerd middels DigiD want resulteert in diens BSN.

3.4.1.1.2.4 Stap 10

De Credential Issuer genereert met een CSPRNG een willekeurige alfanumerieke registration_token die minimaal 22 karakters MOET zijn (zodat hij minimaal 128 bit entropie heeft).

3.4.1.1.2.5 Stap 13

De Credential Issuer maakt een JSON object met daarin de volgende velden:

  • sub: MOET de vaste waarde registration_token hebben.
  • iss: de URL van de Credential Issuer (dat wil zeggen, de URL waar de App naartoe navigeert in stap 3, zonder register_app?session_token=...).
  • registration_token: het registration_token uit stap 8.

Voorbeeld:

{
  "sub": "registration_token",
  "iss": "https://credential-issuer.example.com/",
  "registration_token": "LarRGSbmUPYtRYO6BQ4yn8"
}

Vervolgens versleutelt de Credential Issuer dit object met de session AES key in de vorm van een JWE (zie de Cryptografie sectie hierboven).

3.4.1.1.2.6 Stap 14

De Credential Issuer roept de Universal Link van de App aan, bijvoorbeeld door de Universal Link te plaatsen in een link op zijn website die de eindgebruiker moet gebruiken, of door een HTTP redirect naar de Universal Link. De Credential Issuer levert de volgende parameters URL-encoded mee in de Universal Link:

  • registration_token: het registration token JWE uit de vorige stap.

De app ontvangt de Universal Link en parseert daaruit de registration_token.

Voorbeeld:

https://app.vorijk.nl/ul/issuance?registration_token=eyBwMry...

NB: de reden voor deze tussenstap waarin een registration_token wordt gegeven aan de app, in plaats van rechtstreeks het Verifiable Credential, is om ervoor te zorgen dat het Verifiable Credential in een latere stap rechtstreeks door de App bij de Credential Issuer kan worden opgehaald, in plaats van dat het Verifiable Credential in deze stap ook nog eens door de browser heen zou gaan voordat hij bij de App terecht komt. Bovendien zou het encoderen van het Verifiable Credential in de Universal Link deze dermate groot kunnen maken dat hij door het mobiele besturingssysteem wordt afgekapt.

3.4.1.1.2.7 Stap 15 en 16

De App ontsleutelt de JWE met de session AES key, en valideert dat:

  1. dit resulteert in een JSON object, en
  2. dat dit JSON object de velden uit Stap 11 bevat, met iss en sub de waardes zoals daar gespecificeerd.
3.4.1.1.2.8 Stap 19

De App maakt een JSON object met daarin de volgende velden:

  • sub: MOET de vaste waarde registration_token hebben.
  • iss: MOET de vaste waarde bk-connect://app/ hebben.
  • registration_token: het registration_token uit stap 8.

Voorbeeld:

{
  "sub": "registration_token",
  "iss": "bk-connect://app/",
  "registration_token": "LarRGSbmUPYtRYO6BQ4yn8"
}

Vervolgens versleutelt de App dit object met de session AES key in de vorm van een JWE (zie de Cryptografie sectie hierboven).

3.4.1.1.2.9 Stap 20

De App verstuurt het versleutelde registration_token object naar de Credential Issuer, middels een HTTP POST naar /credential, met het session_token uit Stap 2 in de Authorization HTTP header.

Voorbeeld:

POST /credential HTTP/1.1
Host: credential-issuer.example.com
Authorization: tFNqe50B2nRSwo59ghKd6O

eyNaIioBb2_Jhb...x5Nz-g

NB: de reden dat de gebruiker het registration_token eerst moet ontsleutelen in Stap 13 en dan opnieuw moet versleutelen in Stap 15, in plaats van dat de gebruiker de versleutelde JWE die hij ontvangt in stap 12 rechtstreeks in deze stap zou kunnen versturen, is om het onmogelijk te maken voor een aanvaller die binnenin de TLS tunnel zit, en die dus het verkeer tussen de App en Credential Issuer kan zien, om de versleutelde JWE in stap 12 op te vangen en die dan in deze stap te versturen in plaats van de echte gebruiker, om op die manier het Verifiable Credential te stelen.

3.4.1.1.2.10 Stap 23 t/m 24

De Credential Issuer ontsleutelt de JWE uit de HTTP POST body van de App met de session AES key, en valideert dat:

  1. dit resulteert in een JSON object, en
  2. dat dit JSON object de velden uit Stap 14 bevat, met iss en sub de waardes zoals daar gespecificeerd.
3.4.1.1.2.11 Stap 28

De Credential Issuer tekent met zijn private key het Verifiable Credential, in de vorm van een JWS. Hierbij plaatst hij de root app EC public key in het app_public_key veld van de Verifiable Credential JWS. Zie de Verifiable Credentials sectie hierboven voor alle velden en een voorbeeld.

3.4.1.2 Deregistratie

De App kan zichzelf deregisteren bij de Credential Issuer om aan te geven dat hij geen vers Verifiable Credential meer zal opvragen middels het protocol gedocumenteerd in deze sectie.

Nadat de Credential Issuer dit protocol heeft uitgevoerd voor een zeker registration_token, dan MOET de Credential Issuer eventuele latere aanroepingen van het /credential HTTP endpoint in het uitgifteprotocol van bovenstaande sectie die gebruik maken van het betreffende registration_token afbreken met een foutmelding.

3.4.1.2.1 Sequence diagram

Het protocol ziet er in een sequence diagram als volgt uit.

`Deregistratie` protocol
Figuur 15 Deregistratie protocol

3.4.1.2.2 Protocolberichten

Er volgt een expliciete beschrijving van de protocolberichten, die refereert aan de genummerde stappen in bovenstaand sequence diagram. Alle whitespace in JSON structuren is enkel bedoeld voor de leesbaarheid van deze standaard en dient niet te worden opgenomen in implementaties.

3.4.1.2.2.1 Stap 2

De App en de Credential Issuer voeren het CreateSession protocol uit. De App MOET hierbij voor de certificate_type parameter de waarde app_manager_jwt_certificate gebruiken. Dit protocol resulteert in een session_token en een AES key voor later gebruik.

3.4.1.2.2.2 Stap 3

De App maakt een JSON object met daarin de volgende velden:

  • sub: MOET de vaste waarde unregister_app hebben.
  • iss: MOET de vaste waarde bk-connect://app/ hebben.
  • registration_token: het registration_token van de App.

Voorbeeld:

{
  "sub": "unregister_app",
  "iss": "bk-connect://app/",
  "registration_token": "LarRGSbmUPYtRYO6BQ4yn8"
}

Vervolgens versleutelt de App bovenstaand object met de session AES key in de vorm van een JWE (zie de Cryptografie sectie hierboven).

3.4.1.2.2.3 Stap 4

De App verstuurt het JWE naar de Credential Issuer, middels een HTTP POST naar /unregister_app, waarbij het session_token uit Stap 2 wordt meegegeven in de Authorization HTTP header.

Voorbeeld:

POST /unregister_app HTTP/1.1
Host: credential-issuer.example.com
Authorization: tFNqe50B2nRSwo59ghKd6O

eyNaIioBb2_Jhb...x5Nz-g
3.4.1.2.2.4 Stap 7 en 8

De Credential Issuer ontsleutelt de JWE uit de HTTP POST body van de App met de session AES key, en valideert dat:

  1. dit resulteert in een JSON object, en
  2. dat dit JSON object de velden uit Stap 3 bevat, met iss en sub de waardes zoals daar gespecificeerd.
3.4.1.2.2.5 Stap 9

De Credential Issuer verwijdert de registratie onder registration_token, of markeert deze als zijnde inactief, zodat een eventuele latere aanroep van het /credential HTTP endpoint in het uitgifteprotocol van voorgaande sectie die gebruik maakt van het betreffende registration_token afbreekt met een foutmelding.

3.4.2 Publiek Internet (HTTPS-OpenID4VCI)

In deze variant maakt de app gebruik van het OpenID4VCI protocol voor het verkrijgen van een Verifiable Credential waarmee de app zich later kan authenticeren richting dienstverleners. Dit protocol kent twee varianten: de Authorized Code Flow en de Pre-Authorized Code Flow. Deze standaard maakt gebruik van de Authorized Code Flow. Deze flow kan gezien worden als een uitbreiding van OAuth (RFC 6749), en doet twee dingen:

  • Het identificeert middels (een uitbreiding van) OAuth de eindgebruiker van de app richting de uitgever van het Verifiable Credential (de App Manager),
  • Het geeft een (of meer) Verifiable Credential(s) uit aan de app.

NB: het OpenID4VCI protocol is in actieve ontwikkeling, en geregeld worden er nieuwe draft versies van uitgebracht. Deze sectie is gebaseerd op draft 13 van OpenID4VCI. Inmiddels bestaan er een aantal nieuwe draft versies.

3.4.2.1 Terminologie

Dezelfde terminologie als in de terminologie sectie, met daaraan toegevoegd:

  • Proof of possession: een databericht die (1) een public key en vaak ook een nonce bevat, en (2) een digitale handtekening over die public key en nonce, gezet met de bijbehorende private key. Dit communiceert aan de ontvangende partij niet alleen de public key, maar toont ook aan dat degene die hem stuurt controle heeft over de bijbehorende private key.
3.4.2.2 Introductie

In deze standaard ziet dit protocol er schematisch als volgt uit. Dit diagram toont in de tweede regel binnen de haakjes telkens de belangrijkste gegevens die verstuurd worden.

OpenID4VCI protocol (beknopte weergave)
Figuur 16 OpenID4VCI protocol (beknopte weergave)

Dit kan gezien worden als een OAuth sessie die toegang verschaft tot het Credential endpoint onderaan, waarbij de app de rol speelt van zowel de User Agent als de OAuth Client.

In implementaties kunnen de Credential Issuer en de Authorization Server één en dezelfde server zijn die beide rollen vervult. In bovenstaand diagram worden ze apart getoond om verantwoordelijkheden te scheiden en om de gelijkenis met OAuth aan te tonen.

Refererend naar de genummerde stappen gebeurt het volgende in het protocol:

  • stap 1, 2: de app verkrijgt de issuer metadata middels een GET op een JSON datastructuur die de issuer publiceert onder /.well-known/openid-credential-issuer. De issuer publiceert daarin gegevens over zichzelf, onder andere de URL naar de Authorization Server die hij gebruikt. De app gebruikt vervolgens het OAuth metadata discovery mechanisme (RFC 8414) om de OAuth metadata van de Authorization Server te verkrijgen.
  • stap 3, 4: de app opent een browser en verstuurt daarbij een Authorization Request in het GET request van de browser. In de browser wordt de eindgebruiker geïdentificeerd en geauthenticeerd bijvoorbeeld middels gebruikersnaam/wachtwoord of een identificatieapp zoals DigiD. Als identificatie slaagt wordt de Authorization Response naar de app gestuurd, met daarin een authorization code. De app opent en parse't de authorization code uit de Authorization Response.
  • stap 5, 6: de app wisselt de authorization code in voor een access token en een c_nonce. Het access token geeft toegang tot het Credential endpoint van de issuer, welke een OAuth 2.0 protected resource is als in RFC 6750.
  • stap 7: de app tekent het c_nonce, resulterend in een proof of possession.
  • stap 8: de app stuurt het proof of possession op naar de issuer, samen met het access token.
  • stap 9, 10: de issuer gebruikt het access token om bij de Authorization Server op te halen om welke gebruiker het gaat, en welke c_nonce aan de gebruiker gegeven is.
  • stap 11: de issuer controleert dat het proof of possession een geldige signature is over de c_nonce. Zoja maakt hij een Verifiable Credential met daarin de public key uit het proof of possession en de attributen van de gebruiker, en stuurt deze naar de app.
3.4.2.3 Asymmetrische encryptie

Elk versleuteld bericht in deze sectie MOET in de vorm van een JWE zijn (RFC 7516, zie ook de Cryptografie sectie hierboven).

3.4.2.4 Protocolstructuur

In deze sectie beschrijven we het protocol op hoog niveau door keuzes te nemen in bepaalde parameters die de OpenID4VCI standaard aanbiedt.

3.4.2.4.1 Credential Issuer metadata

De Credential Issuer MOET onder GET /.well-known/openid-credential-issuer een JSON datastructuur zoals de volgende publiceren (zonder commentaar):

{
  "credential_issuer": "https://credential-issuer.example.com",
  "credential_endpoint": "https://credential-issuer.example.com/credential",
  "credential_identifiers_supported": false,
  "credential_response_encryption": {
    "encryption_required": true, // (1)
    "alg_values_supported" : [ "ECDH-ES" ], // (2)
    "enc_values_supported" : [ "A128GCM", "A192GCM", "A256GCM" ] // (3)
  },
  "credential_configurations_supported": {
    "nl.vorijk.vc.blauwe_knop": { // (4)
      "scope": "nl.vorijk.oauth_scope.blauwe_knop.vc",
      "format": "jwt",
      "cryptographic_binding_methods_supported": [ "jwk" ],
      "credential_signing_alg_values_supported": [ "ES256" ], // (5)
      "proof_types_supported": {
        "jwt": {
          "proof_signing_alg_values_supported": [ "ES256" ] // (6)
        }
      }
    }
  }
}

Er volgt een korte uitleg van sommige van de parameters (voor meer informatie, zie § 11.2.3 van OpenID4VCI). Refererend naar de nummers hierboven:

  1. encryption_required kondigt aan dat de Credential Issuer het Verifiable Credential aan het eind van het protocol in versleutelde vorm zal geven aan de app, en dat de app daar voorafgaand bij het Credential Request daarom een public key zal moeten aanleveren waarnaar het Verifiable Credential versleuteld gaat worden.
  2. Toegestane waardes voor de alg JWE header parameter. Per de "Asymmetrische encryptie" sectie hierboven MOET deze array enkel ECDH-ES bevatten.
  3. Toegestane waardoes voor de enc JWE header parameter. Per de "Asymmetrische encryptie" sectie hierboven MOET dit A128GCM, A192GCM, A256GCM zijn; het MAG ook een subset van die drie zijn als de Credential Issuer niet alledrie ondersteunt.
  4. Dit object publiceert metadata over het Verifiable Credential wat de Credential Issuer aanbiedt.
  5. Deze array bevat de algoritmes die de Credential Issuer kan gebruiken voor het ondertekenen van het Verifiable Credential. In deze standaard MOET deze array enkel het algoritme bevatten waarmee het Verifiable Credential ondertekend wordt.
  6. Array van algoritmes ondersteund door de Credential Issuer die de app mag gebruiken voor het maken van het Proof of Possession.
3.4.2.4.2 OAuth metadata

De Credential Issuer metadata MAG volgens § 11.2.3 van OpenID4VCI een array genaamd authorization_servers bevatten, welke URLs bevat van OAuth server(s) die de app mag gebruiken voor het versturen van de Authorization Request en Token Request. De afwezigheid daarvan betekent dat de Credential Issuer zelf fungeert als OAuth server, dat wil zeggen de Authorization en Token endpoints host. Deze moet dan ook een OAuth 2.0 metadata document publiceren onder .well-known/oauth-authorization-server. Deze MOET minimaal als volgt zijn, maar MAG ook andere velden als gedefinieerd in RFC 8414 bevatten:

{
  "issuer": "https://oauth-server.example.com",
  "authorization_endpoint": "https://oauth-server.example.com/authorize",
  "token_endpoint": "https://oauth-server.example.com/token",
  "response_types_supported":  ["code"],
  "grant_types_supported": ["authorization_code"],
  "code_challenge_methods_supported": ["S256"]
}
3.4.2.4.3 OpenID4VCI parameters

De OpenID4VCI standaard biedt op een aantal plekken verschillende opties en varianten aan. Deze standaard maakt daarin de volgende keuzes.

  1. "Proof Key for Code Exchange (PKCE)" (RFC 7636, wordt uitgesproken als "pixy"). Deze uitbreiding op OAuth authenticeert de app bij het Token Request als zijnde dezelfde app die het Authorization Request stuurde, doordat de app bij het Authorization Request de (SHA256) hash van een willekeurig secret moet sturen, en bij het Token request het secret zelf. Dit voorkomt dat een aanvaller die erin slaagt om het authorization code te onderscheppen deze kan gebruiken om het access token te bemachtigen.
  2. "Demonstrating Proof of Possession (DPoP)" (RFC 9449): deze uitbreiding op OAuth vervult een vergelijkbare rol als PKCE, maar dan bij het Credential Request. Het authenticeert de app bij het Credential Request als zijnde dezelfde app die het Token Request verstuurde, doordat de app bij het versturen van het Token Request een ephemeral public key aankondigt waarmee hij vervolgens het access token ondertekent bij het Credential Request. Dit voorkomt dat een aanvaller die erin slaagt om het access token te onderscheppen deze kan gebruiken om het Verifiable Credential te bemachtigen.
  3. In het Authorization Request MOET de app middels de authorization_details parameter, als in § 5.1.1 van OpenID4VCI, aangeven welk Verifiable Credential hij geïssued wil krijgen:
    [{
        "type": "openid_credential",
        "credential_configuration_id": "nl.vorijk.vc.blauwe_knop"
    }]
    
    Het credential_configuration_id refereert naar de corresponderende entry in de credential_configurations_supported object in de Credential Issuer metadata. Dit object MOET ook worden opgenomen in het Token Response.
  4. In het Token Response MOET een c_nonce parameter worden opgenomen, die een willekeurige string bevat. Deze moet door de app ondertekend worden met de private key waarvan de public key in het Verifiable Credential moet komen, resulterend in een Proof of Possession.
  5. Het Credential Request MOET de Proof of Possession bevatten in de proof parameter, en een credential_response_encryption object waarin de app een ephemeral ECDH-ES public key zet waarnaar de Credential Issuer het Verifiable Credential moet versleutelen.
  6. Het Credential Response MOET door de Credential Issuer in de vorm van een JWE versleuteld worden naar de public key in het credential_response_encryption object in het Credential Request.

OpenID4VCI maakt het gebruik van PAR (Pushed Authorization Requests, RFC 9126) optioneel voor het versturen van het Authorization Request. In deze uitbreiding stuurt de OAuth Client het Authorization Request niet via de User Agent van de eindgebruiker naar de Authorization Server, maar stuurt de Client het Authorization Request rechtstreeks in een HTTP POST naar de Authorization Server. Deze antwoordt vervolgens met een referentie naar de sessie genaamd de request_uri, die de eindgebruiker in de URL naar het Authorization Endpoint stopt wanneer hij daar naartoe navigeert. De Authorization Server herkent de request_uri en weet daardoor om welk Authorization Request het gaat. Dit biedt in traditionele OAuth-gebaseerde protocollen drie voordelen:

  1. Integriteit van het Authorization Request: doordat het Authorization Request niet meer via de User Agent van de eindgebruiker wordt verstuurd, kan deze ook niet worden aangepast door de eindgebruiker, diens browser, of een man-in-the-middle tussen de eindgebruiker en de Client of Authorization Server.
  2. Vertrouwelijkheid van het Authorization Request: doordat het Authorization Request rechtstreeks van de Client naar de Authorization Server gaat kan deze desgewenst ook geheime informatie bevatten, zoals bijvoorbeeld een identificatietoken van de Client richting de Authorization Server of persoonsgegevens van de eindgebruiker.
  3. Het voorkomt problemen als het Authorization Request groter is dan ondersteund wordt in URLs.

Deze uitbreiding MAG NIET gebruikt worden in deze standaard. De reden hiervoor is dat het wel complexiteit en runtime kosten met zich meebrengt, terwijl beide bovenstaande voordelen die het biedt in traditionele OAuth in dit protocol niet van toepassing zijn:

  • In het OpenID4VCI protocol zijn de eindgebruiker en de client dezelfde partij, waardoor de eerste twee punten wegvallen.
  • In deze standaard is het Authorization Request nooit dermate groot dat deze niet in een URL zou passen.
3.4.2.5 Protocolbeschrijving

De keuzes beschreven in bovenstaande sectie resulteren bij elkaar in een protocol die we in deze sectie verder uitwerken en expliciet maken.

3.4.2.5.1 Sequence diagram

Het protocol ziet er in een sequence diagram als volgt uit. In dit diagram wordt de rol van de Authorization Server en de Credential Issuer gespeeld door dezelfde partij, maar we voegen DigiD en BRP (Basisregistratie Personen) als partijen toe. Verder nemen we aan dat de Authorization, Token en Credential endpoints /authorize, /token en /credential zijn respectievelijk. Net als in het vorige diagram tonen we telkens in de tweede regel binnen haakjes de belangrijkste gegevens die verstuurd worden. (Deze lijst is meestal niet compleet, dat wil zeggen dat er vaak meer wordt verstuurd dan wat in deze tweede regel staat; we tonen hier alleen de belangrijkste gegegvens.)

OpenID4VCI protocol
Figuur 17 OpenID4VCI protocol

3.4.2.5.2 Protocolberichten

Er volgt een expliciete beschrijving van de protocolberichten, die refereert aan de genummerde stappen in bovenstaand sequence diagram. Alle whitespace in JSON structuren en HTTP requests is enkel bedoeld voor de leesbaarheid van deze standaard en dient niet te worden opgenomen in implementaties.

In onderstaand protocol wordt een aantal keer Base64-encodering gebruikt. Dit moet altijd de URL-safe variant zijn zonder padding.

3.4.2.5.2.1 Stap 1 en 2

De App gebruikt de OpenID4VCI en OAuth metadata discovery mechanismes door een GET uit te voeren op /.well-known/openid-credential-issuer en /.well-known/oauth-authorization-server, respectievelijk. De server(s) antwoorden met JSON structuren zoals in de Credential Issuer metadata en OAuth metadata secties hierboven. De App parseert de JSON en ontdekt op die manier de URLs van de Authorization, Token en Credential endpoints.

In het vervolg van dit document nemen we aan dat deze endpoints als volgt zijn:

  • https://issuer.example.com/authorize
  • https://issuer.example.com/token
  • https://issuer.example.com/credential
3.4.2.5.2.2 Stap 3

De App genereert een PKCE verifier (genaamd code_verifier in onderstaande HTTP berichten) door 32 willekeurige bytes te genereren met een CSPRNG en deze te Base64url-encoderen, resulterend in een PKCE verifier van 43 karakters. De App genereert vervolgens de bijbehorende PKCE challenge middels de volgende pseudocode:

code_challenge := BASE64URL-ENCODE(SHA256(code_verifier))

Zie ook § 4.1 en 4.2 van RFC 7636.

3.4.2.5.2.3 Stap 4

De App navigeert in de browser naar het Authorization endpoint van de Credential Issuer, met URL-encoded in de URL het Authorization Request als in § 5 van OpenID4VCI en § 4.1.1 van OAuth, met de volgende parameters:

  • response_type: MOET de waarde code hebben (refererend naar de authorization code grant type van § 4.1 van OAuth).
  • client_id: een identifier van de App die een vaste waarde MOET hebben over alle App instanties, bijvoorbeeld nl.vorijk.app.
  • code_challenge: de PKCE challenge gegenereerd zoals hierboven.
  • code_challenge_method: MOET de waarde S256 hebben (per § 4.2 van de PKCE RFC).
  • scope: MOET de waarde nl.vorijk.oauth_scope.blauwe_knop.vc hebben, welke refereert naar de corresponderende scope uit de Credential Issuer Metadata.
  • redirect_uri: dit MOET een Universal Link (UL) zijn die de App opent. Nadat authenticatie en identificatie van de eindgebruiker is gelukt zal de gebruiker in Stap 10 naar deze link worden geredirect door de Credential Issuer, waardoor de App opent.
  • state: MAG aanwezig zijn en de waarde hiervan mag vrij bepaald worden door de App. Als state gebruikt wordt dan ontvangt de App dezelfde state ook terug in het Authorization Response, zie stap 10. De App kan deze parameter gebruiken voor het bijhouden van bepaalde state, bijvoorbeeld voor het tracken van verschillende sessies.

Voorbeeld (met newlines voor leesbaarheid):

https://issuer.example.com/authorize?
  response_type=code
  &client_id=nl.vorijk.app
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
  &scope=nl.vorijk.oauth_scope.blauwe_knop.vc
  &redirect_uri=https%3A%2F%2Fapp.vorijk.nl%2Ful%2Fissuance
  &state=xyz
3.4.2.5.2.4 Stap 5 en 6

De eindgebruiker wordt geïndentificeerd middels DigiD want resulteert in diens BSN.

3.4.2.5.2.5 Stap 7

De Credential Issuer genereert met een CSPRNG een nieuwe authorization code, die een willekeurige string gebruik makend van de URL-safe Base64 karakterset MOET zijn, van minimaal 22 karakters (zodat hij minimaal 128 bit entropie heeft).

3.4.2.5.2.6 Stap 8 en 9

De Credential Issuer slaat de PKCE challenge en het BSN van de gebruiker op onder het authorization code voor later gebruik.

3.4.2.5.2.7 Stap 10

De Credential Issuer roept de redirect_uri uit Stap 4 met daarin de Universal Link van de App aan, bijvoorbeeld door de Universal Link te plaatsen in een link op zijn website die de eindgebruiker moet gebruiken, of door een HTTP redirect naar de Universal Link. De Credential Issuer levert de volgende parameters URL-encoded mee in de Universal Link:

  • code: de authorization code.
  • state: alleen aanwezig als de App in het Authorization Request (stap 4) een state parameter heeft meegegeven, in dat geval met dezelfde waarde als in het Authorization Request.

De app ontvangt de Universal Link en parseert daaruit de authorization code.

Voorbeeld:

https://app.vorijk.nl/ul/issuance?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
3.4.2.5.2.8 Stap 11

De App genereert een nieuw ephemeral EC keypair, en produceert daarmee een DPoP Proof of Possession per § 4.2 van RFC 9449, welke een JWS is als volgt:

{
  "typ": "dpop+jwt",
  "alg": "ES256",
  "jwk": {
    "kty": "EC",
    "x": "l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
    "y": "9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
    "crv": "P-256"
  }
}
.
{
  "jti": "-BwC3ESc6acc2lTc",
  "htm": "POST",
  "htu": "https://issuer.example.com/token",
  "iat": 1562262616
}

In deze JWS zijn de velden als volgt:

  • jwk: de zojuist gegenereerde public key in JWK formaat (RFC 7517);
  • jti: De Base64url-encoding van minimaal 12 bytes aan willekeurige data gegenereerd met een CSPRNG;
  • htm: de HTTP methode waarbij deze DPoP in de volgende stap gebruikt wordt;
  • htu: de URL waarbij deze DPoP in de volgende stap gebruikt wordt;
  • iat: de Unix timestamp van het moment van creatie van deze JWS.
3.4.2.5.2.9 Stap 12

De App doet een Token Request als in § 6 van OpenID4VCI en § 4.1.3 van OAuth bij de Credential Issuer, gebruik makend van de authorization code die hij eerder heeft ontvangen. De App stuurt hierbij ook bovenstaand DPoP Proof of Possession mee, per § 4.1 van RFC 9449.

De App verstuurt het Token Request URL-encoded in de HTTP POST body, met de volgende parameters:

  • grant_type: MOET de waarde authorization_code hebben.
  • client_id en redirect_uri: MOETEN dezelfde waardes als in het Authorization Request hebben.
  • code: de authorization code ontvangen in stap 10.
  • code_verifier: de PKCE verifier gegenereerd in stap 3.

Voorbeeld (met newlines voor leesbaarheid):

POST /token HTTP/1.1
Host: issuer.example.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik
 VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR
 nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE
 QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj
 oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia
 WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg
 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg

grant_type=authorization_code
&client_id=nl.vorijk.app
&redirect_uri=https%3A%2F%2Fapp.vorijk.nl%2Ful%2Fissuance
&code=SplxlOBeZQQYbYS6WxSbIA
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
3.4.2.5.2.10 Stap 13 en 14

De Credential Issuer haalt middels de authorization code de PKCE challenge en het BSN van de gebruiker op.

3.4.2.5.2.11 Stap 15

De Credential Issuer verifieert de PKCE verifier per § 4.6 van RFC 7636, door vast te stellen dat het volgende geldt:

code_challenge == BASE64URL-ENCODE(SHA256(code_verifier))

Als deze gelijkheid niet geldt, dan MOET de Credential Issuer afbreken met de foutmelding invalid_grant als per § 5.2 van OAuth.

3.4.2.5.2.12 Stap 16

De Credential Issuer verifieert de DPoP Proof of Possession uit de DPoP HTTP header middels de instructies in § 4.3 van RFC 9449.

Als de DPoP JWS niet geldig is, dan MOET de Credential Issuer afbreken met de foutmelding invalid_dpop_proof als per § 5.2 van OAuth.

Als de DPoP JWS wel geldig is, dan parseert de Credential Issuer de DPoP public key in de DPoP JWS voor later gebruik.

3.4.2.5.2.13 Stap 17

De Credential Issuer genereert met een CSPRNG een nieuw access_token en c_nonce, die beiden willekeurige strings gebruik makend van de URL-safe Base64 karakterset MOETEN zijn, van minimaal 22 karakters (zodat ze minimaal 128 bit entropie hebben).

3.4.2.5.2.14 Stap 18 en 19

De Credential Issuer slaat het BSN van de gebruiker, de c_nonce en de DPoP public key op onder het access_token voor later gebruik.

3.4.2.5.2.15 Stap 20

De Credential Issuer antwoordt op het HTTP POST request van de App uit stap 12 met een JSON object met daarin de volgende parameters:

  • access_token: het access token gegenereerd in de vorige stap, die toegang geeft tot het Credential Endpoint (zie Stap 25).
  • c_nonce: de nonce gegenereerd in de vorige stap.
  • token_type: MOET de waarde DPoP hebben per § 5 van RFC 9449, wat aangeeft aan de App dat DPoP gebruikt MOET worden bij het gebruik van het access token (dus bij het opvragen van het Verifiable Credential).
  • expires_in: MAG aanwezig zijn en MOET in dat geval in seconden aangeven hoe lang het access token geldig is.

Voorbeeld:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "access_token": "JhbGciOiJSUzI1NiIsInR5",
  "c_nonce": "LarRGSbmUPYtRYO6BQ4yn8",
  "token_type": "DPoP",
  "expires_in": 60,
}
3.4.2.5.2.16 Stap 21

Als er niet al eerder een hardware-bound ECDSA keypair voor gebruik in het Verifiable Credential was aangemaakt doet de app dit nu.

3.4.2.5.2.17 Stap 22

De App genereert een Proof of Possession van de public key gegenereerd in de vorige stap als per § 7.2.1.1 van OpenID4VCI, in de vorm van een JWS met daarin de volgende velden:

  • JWS header:
    • typ: MOET de waarde openid4vci-proof+jwt zijn.
    • alg: MOET de waarde ES256 zijn.
    • jwk: de ECDSA public key in JWK formaat (RFC 7517).
  • JWS body:
    • aud: MOET de Credential Issuer Identifier zijn, dat wil zeggen de URL die /.well-known/openid-credential-issuer host.
    • iat: Unix timestamp van het moment van creatie van deze JWS.
    • nonce: MOET de waarde van de c_nonce hebben die de App ontving in Stap 20.

Voorbeeld:

{
  "typ": "openid4vci-proof+jwt",
  "alg": "ES256",
  "jwk": {
    "kty": "EC",
    "crv": "P-256",
    "x": "nUWAoAv3XZith8E7i19OdaxOLYFOwM-Z2EuM02TirT4",
    "y": "HskHU8BjUi1U9Xqi7Swmj8gwAK_0xkcDjEW_71SosEY"
  }
}
.
{
  "aud": "https://issuer.example.com",
  "iat": 1701960444,
  "nonce": "LarRGSbmUPYtRYO6BQ4yn8"
}
3.4.2.5.2.18 Stap 23

De App genereert een nieuw ephemeral EC keypair voor encryptie. Deze wordt later door de Credential Issuer gebruikt in Stap 34 om het Verifiable Credential te versleutelen voordat hij naar de App verstuurd wordt.

3.4.2.5.2.19 Stap 24

De App genereert een nieuw DPoP JWS zoals in stap 11, middels hetzelfde EC keypair, met een vers willekeurig jti veld, en dit keer inclusief een ath veld in de JWS body, met als waarde de Base64url-encoding van de SHA256 hash van het access_token, dus schematisch BASE64URL(SHA256(access_token)).

Voorbeeld:

{
  "typ": "dpop+jwt",
  "alg": "ES256",
  "jwk": {
    "kty": "EC",
    "x":" l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
    "y": "9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
    "crv": "P-256"
  }
}
.
{
  "jti": "e1j3V_bKic8-LAEB",
  "htm": "POST",
  "htu": "https://issuer.example.org/credential",
  "iat": 1562262618,
  "ath": "LnCUSTkzMbG3p5Bw35U4EAOl-pXwcgOdhXxgK6CFYY4"
}
3.4.2.5.2.20 Stap 25

De App stuurt een Credential Request naar het Credential endpoint van de Credential Issuer als in § 7 van OpenID4VCI, middels een HTTP POST met de volgende HTTP headers:

  • Authorization: het access token met DPoP als authentication scheme.
  • DPoP: de DPoP JWS uit de vorige stap.

In de HTTP body verstuurt de App JSON-encoded een object met de volgende parameters:

  • proof: een object met daarin:
    • proof_type: MOET de waarde jwt hebben.
    • jwt: de JWS uit stap 22.
  • credential_response_encryption: een object dat aangeeft hoe de Credential Issuer het Verifiable Credential moet versleutelen voordat het naar de App gestuurd wordt, middels de volgende velden:
    • jwk: de public key gegenereerd in Stap 23.
    • alg: het asymmetrische encryptie-algoritme die de app verwacht. MOET de waarde ECDH-ES hebben.
    • enc: het symmetrische encryptie-algoritme die de app verwacht. MOET de waarde A128GCM, A192GCM, of A256GCM hebben.

Voorbeeld (newlines en whitespace enkel voor leesbaarheid):

POST /credential HTTP/1.1
Host: issuer.example.com
Content-Type: application/json
Authorization: DPoP JhbGciOiJSUzI1NiIsInR5
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik
 VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR
 nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE
 QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiJlMWozVl9iS2ljOC1MQUVCIiwiaHRtIj
 oiR0VUIiwiaHR1IjoiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLm9yZy9wcm90ZWN0Z
 WRyZXNvdXJjZSIsImlhdCI6MTU2MjI2MjYxOCwiYXRoIjoiZlVIeU8ycjJaM0RaNTNF
 c05yV0JiMHhXWG9hTnk1OUlpS0NBcWtzbVFFbyJ9.2oW9RP35yRqzhrtNP86L-Ey71E
 OptxRimPPToA1plemAgR6pxHF8y6-yqyVnmcw6Fy1dqd-jfxSYoMxhAJpLjA

{
  "proof": {
    "proof_type": "jwt",
    "jwt":
      "eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IkVTMjU2IiwiandrI
      jp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiblVXQW9BdjNYWml0aDhFN2k
      xOU9kYXhPTFlGT3dNLVoyRXVNMDJUaXJUNCIsInkiOiJIc2tIVThCalVpMVU5WHFpN
      1N3bWo4Z3dBS18weGtjRGpFV183MVNvc0VZIn19.eyJhdWQiOiJodHRwczovL2NyZW
      RlbnRpYWwtaXNzdWVyLmV4YW1wbGUuY29tIiwiaWF0IjoxNzAxOTYwNDQ0LCJub25j
      ZSI6IkxhclJHU2JtVVBZdFJZTzZCUTR5bjgifQ.-a3EDsxClUB4O3LeDD5DVGEnNMT
      01FCQW4P6-2-BNBqc_Zxf0Qw4CWayLEpqkAomlkLb9zioZoipdP-jvh1WlA"
  },
  "credential_response_encryption": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "gUOuh9dfi-44HT-2YL5HdEZ9opP_ItHrpp28JtQyaOY",
      "y": "0UOvHfidVyKFN4gDz9bIstU0o0qWCaZrRaVhplgkm58"
    },
    "alg": "ECDH-ES",
    "enc": "A128GCM"
  }
}
3.4.2.5.2.21 Stap 26 en 27

De Credential Issuer haalt middels het access token het BSN van de gebruiker, de c_nonce en de DPoP public key op.

3.4.2.5.2.22 Stap 28

De Credential Issuer verifieert de DPoP JWS uit de DPoP HTTP header net als in stap 16, dit keer met de volgende extra checks:

  • de DPoP JWS MOET een ath veld hebben met daarin de Base64url-encoding van de SHA256 hash van het access token;
  • de public key in het JWK veld MOET gelijk zijn aan degene die de Credential Issuer aantrof in stap 16.
3.4.2.5.2.23 Stap 29

De Credential Issuer verifieert de Proof of Possession in het jwt veld in het proof object van de Credential Response als volgt.

  1. Parseer de JWS header (nog zonder de JWS geverifieerd te hebben).
  2. Controleer dat het typ veld in de JWS header de waarde openid4vci-proof+jwt bevat.
  3. Controleer dat het alg veld in de JWS header de waarde ES256 bevat.
  4. Controleer dat het jwk veld in de JWS header een object bevat die een P-256 public key is geëncodeerd als JWK, en dat dit object niet een d veld (een private key) in zich heeft.
  5. Verifieer de JWS tegen de public key uit bovenstaande stap.
  6. Controleer dat het aud veld in de JWS body de Credential Issuer Identifier bevat (de URL die /.well-known/openid-credential-issuer host).
  7. Controleer dat de JWS volgens het iat veld in de JWS body niet ouder is dan een bepaalde grens, bijvoorbeeld 60 seconden.
  8. Controleer dat de nonce in de JWS body gelijk is aan de c_nonce die in Stap 20 aan de App is verstrekt.
3.4.2.5.2.24 Stap 30 en 31

Middels het BSN worden de gegevens van de eindgebruiker die geïssued moeten worden als attributen in het Verifiable Credential opgehaald uit de BRP.

3.4.2.5.2.25 Stap 32

De Credential Issuer tekent met zijn private key het Verifiable Credential, in de vorm van een JWS. Hierbij plaatst hij de public key in het jwk veld van het Proof of Possession (zie Stap 29) in het cnf veld van de Verifiable Credential JWS. Zie de Verifiable Credentials sectie hierboven voor alle velden en een voorbeeld.

3.4.2.5.2.26 Stap 33

De Credential Issuer maakt het Credential Response, een JSON object met daarin enkel een credential veld met als waarde de JWS uit de vorige stap:

{
  "credential": "eyBRa..."
}

De Credential Issuer versleutelt dit object in de vorm van een JWE naar de public key in het jwk veld in het credential_response_encryption object in het Credential Request uit Stap 25.

3.4.2.5.2.27 Stap 34

De Credential Issuer verstuurt bovenstaand JWE naar de App.

3.4.2.5.2.28 Stap 35

De App controleert dat het Credential Response versleuteld in de vorm van een JWE is, en breekt af zoniet. Hij ontsleutelt de JWE met de private key gegenereerd in Stap 23, parseert de inhoud van de JWE als JSON object, en vindt daarin het Verifiable Credential in het credential veld.

3.4.2.5.2.29 Stap 36

De App verifieert het Verifiable Credential tegen de public key van de Credential Issuer, eventueel gebruik makend van het kid veld in de JWS header om de juiste public key te identificeren.

4. Lijst met figuren

5. Conformiteit

Naast onderdelen die als niet normatief gemarkeerd zijn, zijn ook alle diagrammen, voorbeelden, en noten in dit document niet normatief. Verder is alles in dit document normatief.

De trefwoorden MAG, MOET, MOETEN en MOGEN in dit document moeten worden geïnterpreteerd als in BCP 14 [RFC2119] [RFC8174] als, en alleen als deze in hoofdletters zijn weergegeven, zoals hier getoond.

A. Referenties

A.1 Normatieve referenties

[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
Overheidsbrede Standaard - Werkversie