The implementation and the setup follows version 0.7.1 of the Italian profile
https://github.com/italia/eudi-wallet-it-docs/tree/versione-corrente/docs/en
The environment consists of a small federation containing a Trust Anchor (TA), a Wallet provider (WP), a Trust Mark issuer (TMI) and the PID Issuer (PI).
All of these is expressed in two docker containers. The TA,TMI and WP in one and the PID Issuer in another.
See https://wiki.sunet.se/display/Projekt/EUDIW+pilot+setup for more information.
Even though a wallet, who wants to use the PID issuer provided by this setup, does not need to know OpenID Federation as a whole, it needs to know parts.
This includes sending a request to an endpoint and then being able to interpret the response.
In order to be able to do this the Wallet MUST:
There is one services that the SUNET OpenID federation provides that the wallet MUST know about. That is resolver service. The resolve service does all the OpenID Federation steps for you:
and returns the result to you.
According to the Italian profile needs to do 5 steps to complete the Wallet Instance Initialization and Registration and 8 steps to complete the Wallet Attestation Issuance. I've paired that down to 4 :-)
In this scaled down version the wallet needs to know one endpoint expressed as an URL from the metadata for the Wallet Provider and that is the token_endpoint.
If it doesn't know how to collect and evaluate trust chains then the Wallet must use the resolve service provided by the trust anchor.
If we assume that the wallet knows no more than the entity ID of the Trust Anchor then it has to do this:
Now when the wallet knows the resolve endpoint it can do the next step in the process.
The pilot setup information tells you the entity ID of the Wallet Provider (https://openidfed-test-1.sunet.se:5001) so the wallet should pose the following query to the resolve endpoint using HTTP GET.
sub=https%3A%2F%2Fopenidfed-test-1.sunet.se%2F5001&
type=wallet_provider&
anchor=https%3A%2F%2openidfed-test-1.sunet.se%2F7001
The response is again a signed JWT. Since the Wallet has the public part of the TA's signing keys it should have no problem verifying the signatur on the response.
What the wallet wants out of the response is the token endpoint. Can be found under metadata/wallet_provider/token_endpoint.
The only necessary claims of the ones listed in the profile document are:
The remaining claims:
MUST all be assigned the value "__not__applicable__" . This signals to the wallet provider that it should work according to the scaled down version.
presentation_definition_uri_supported should be present with the value False.
The constructed JSON object should look something like this:
{
"iss": "https://openidfed-test-1.sunet.se:5001/vbeXJksM45xphtANnCiG6mCyuU4jfGNzopGuKvogg9c",
"challenge": "__not__applicable__",
"hardware_signature": "__not__applicable__",
"integrity_assertion": "__not__applicable__",
"hardware_key_tag": "__not__applicable__",
"cnf": {
"jwk": {
"crv": "P-256",
"kty": "EC",
"x": "4HNptI-xr2pjyRJKGMnz4WmdnQD_uJSq4R95Nj98b44",
"y": "LIZnSB39vFJhYgS3k7jXE4r3-CoGFQwZtPBIRqpNlrg",
"kid": "vbeXJksM45xphtANnCiG6mCyuU4jfGNzopGuKvogg9c"
}
},
"vp_formats_supported": {
"jwt_vc_json": {
"alg_values_supported": [
"ES256K",
"ES384"
]
},
"jwt_vp_json": {
"alg_values_supported": [
"ES256K",
"EdDSA"
]
}
},
"iat": 1686645115,
"exp": 1686652315
}
This JSON object should now be wrapped into a signed JWT and sent to the token_endpoint URL.
The token endpoint (as defined in RFC 7523 section 4) requires the following parameters encoded in application/x-www-form-urlencoded format:
POST /token HTTP/1.1
Host: openidfed-test-1.sunet.se
Content-Type: application/x-www-form-urlencoded
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
&assertion=eyJhbGciOiJFUzI1NiIsImtpZCI6ImtoakZWTE9nRjNHeG...
The response (the Wallet Instance Attestation) JSON should look something like this:
{
"iss": "https://openidfed-test-1.sunet.se:5001",
"sub": "vbeXJksM45xphtANnCiG6mCyuU4jfGNzopGuKvogg9c",
"aal": "something_or_other",
"cnf": {
"jwk": {
"crv": "P-256",
"kty": "EC",
"x": "4HNptI-xr2pjyRJKGMnz4WmdnQD_uJSq4R95Nj98b44",
"y": "LIZnSB39vFJhYgS3k7jXE4r3-CoGFQwZtPBIRqpNlrg",
"kid": "vbeXJksM45xphtANnCiG6mCyuU4jfGNzopGuKvogg9c"
}
},
"vp_formats_supported": {
"jwt_vc_json": {
"alg_values_supported": [
"ES256K",
"ES384"
]
},
"jwt_vp_json": {
"alg_values_supported": [
"ES256K",
"EdDSA"
]
}
},
"authorization_endpoint": "__not__applicable__",
"response_types_supported": "__not__applicable__",
"response_modes_supported": "__not__applicable__",
"request_object_signing_alg_values_supported": "__not__applicable__",
"presentation_definition_uri_supported": false,
"iat": 1687281195,
"exp": 1687288395
}
That taken care of we can go on to the conversation with the PID Issuer.
But first to summaries the initial steps:
Eventually there will be a special endpoint that the SUNET setup provides. It's hosted at a entity called the query server. This seervice will traverse the federation and find all entities that match a given filter.
The filter consists of three parts:
The wallet can again collect the metadata for the found entity by using the resolver. The query server's service endpoint URL can be found at metadata/federation_entity/query_endpoint
Right now we can cheat and assume we have done the above and know that the PID Issuer can be found at https://satosa-test-1.sunet.se/
A three step process. We use normal OAuth2 authorization if possible. Pushed Authorization is also available.