Coder Social home page Coder Social logo

eu-digital-identity-wallet / eudi-srv-pid-issuer Goto Github PK

View Code? Open in Web Editor NEW
10.0 10.0 4.0 778 KB

A micro-service acting like PID/mDL Issuer according to OpenID4VCI

License: Apache License 2.0

Shell 0.06% FreeMarker 5.36% Kotlin 92.36% CSS 0.04% HTML 2.17%
keycloak kotlin openid4vci sd-jwt-vc springboot3 mdl

eudi-srv-pid-issuer's Introduction

PID Issuer

Important! Before you proceed, please read the EUDI Wallet Reference Implementation project description

License

Overview

An implementation of a credential issuing service, according to OpenId4VCI - draft13

The service provides generic support for mso_mdoc and SD-JWT-VC formats using PID and mDL as an example and requires the use of a suitable OAUTH2 server.

Credential/Attestation Format
PID mso_mdoc
PID SD-JWT-VC
mDL mso_mdoc

OpenId4VCI coverage

Feature Coverage
Authorization Code flow ✅ Using a suitable OAUTH2 server
Pre-authorized code flow
mso_mdoc format
SD-JWT-VC format ✅ Except revocation list & meta
W3C VC DM
Credential Offer authorization_code , ❌ pre-authorized_code
Credential Endpoint Yes, including proofs, encryption, repeatable invocations
Credential Issuer MetaData Yes, using scopes
Batch Endpoint
Deferred Endpoint
Proof ✅ JWT (jwk, x5c, did:key, did:jwk) , ❌ CWT

How to use docker

Folder docker-compose contains the following services to be used in a local development environment:

Keycloak

A Keycloak instance accessible via https://localhost/idp/ with the Realm pid-issuer-realm.

The Realm pid-issuer-realm:

  • has user self-registration active with a custom registration page accessible via https://localhost/idp/realms/pid-issuer-realm/account/#/
  • defines eu.europa.ec.eudiw.pid_vc_sd_jwt scope for requesting PID issuance in SD JWT VC format
  • defines eu.europa.ec.eudiw.pid_mso_mdoc scope for requesting PID issuance in MSO MDOC format
  • defines wallet-dev and pid-issuer-srv clients
  • contains sample user with credentials: tneal / password

The Administration console is accessible via https://localhost/idp/admin/ using the credential admin / password

PID mDL Issuer

A PID mDL Issuer instance accessible via https://localhost/pid-issuer/

It uses the configured Keycloak instance as an Authorization Server, and supports issuing of PID and mDL. Additionally, deferred issuance is enabled for PID in SD JWT VC format.

The issuing country is set to GR (Greece).

HA Proxy

An HA Proxy instance is also configured. This instance exposes both Keyclaok and PID Issuer via https. The certificate and respective private key can be found in docker-compose/haproxy/certs.

docker compose usage

cd docker-compose
docker-compose up -d

or

cd docker-compose
docker compose up -d

Configuration

The PID Issuer application can be configured using the following environment variables:

Variable: SPRING_PROFILES_ACTIVE
Description: Spring profiles to enable. Enable insecure profile to disable SSL certificates verification.
Default value: N/A

Variable: SPRING_WEBFLUX_BASE_PATH
Description: Context path for the PID issuer application.
Default value: /

Variable: SERVER_PORT
Description: Port for the HTTP listener of the PID Issuer application
Default value: 8080

Variable: SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_ID
Description: Client Id of the OAuth2 client registered in the Authorization Server
Default value: N/A

Variable: SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET
Description: Client Server of the OAuth2 client registered in the Authorization Server
Default value: N/A

Variable: SERVER_FORWARD_HEADERS_STRATEGY
Description: Whether the server should consider X-Forwarded headers. In case the application is behind a reverse proxy, set this to FRAMEWORK.
Possible values: FRAMEWORK, NONE
Default value: FRAMEWORK

Variable: ISSUER_PUBLICURL
Description: URL the PID Issuer application is accessible from
Default value: http://localhost:${SERVER_PORT}${SPRING_WEBFLUX_BASE_PATH}

Variable: ISSUER_AUTHORIZATIONSERVER_PUBLICURL
Description: URL of the Authorization Server advertised via the issuer metadata
Default value: N/A

Variable: ISSUER_AUTHORIZATIONSERVER_METADATA
Description: URL used to fetch the metadata of the Authorization Server
Default value: N/A

Variable: ISSUER_AUTHORIZATIONSERVER_INTROSPECTION
Description: URL of the Token Introspection endpoint of the Authorization Server
Default value: N/A

Variable: ISSUER_CREDENTIALRESPONSEENCRYPTION_SUPPORTED
Description: Whether to enable support for credential response encryption.
Default value: true

Variable: ISSUER_CREDENTIALRESPONSEENCRYPTION_REQUIRED
Description: Whether credential response encryption is required.
Default value: true

Variable: ISSUER_CREDENTIALRESPONSEENCRYPTION_ALGORITHMSSUPPORTED
Description: Comma separated list of supported encryption algorithms for credential response encryption.
Default value: RSA-OAEP-256

Variable: ISSUER_CREDENTIALRESPONSEENCRYPTION_ENCRYPTIONMETHODS
Description: Comma separated list of supported encryption method for credential response encryption.
Default value: A128CBC-HS256

Variable: ISSUER_PID_MSO_MDOC_ENABLED
Description: Whether to enable support for PID issuance in MSO MDOC format
Default value: true

Variable: ISSUER_PID_MSO_MDOC_ENCODER
Description: Configures the CBOR encoder to use for encoding PIDs. Either Internal or Microservice.
Default value: Internal

Variable: ISSUER_PID_MSO_MDOC_ENCODER_DURATION
Description: Configures the validity of issued PIDs when using the internal encoder. Uses Period syntax. Required when ISSUER_PID_MSO_MDOC_ENCODER is set to Internal.
Default value: P30D

Variable: ISSUER_PID_MSO_MDOC_ENCODER_URL
Description: URL of the CBOR encoder microservice to use for PIDs. Required when ISSUER_PID_MSO_MDOC_ENCODER is set to Microservice
Default value: N/A

Variable: ISSUER_PID_MSO_MDOC_NOTIFICATIONS_ENABLED
Description: Whether to enabled Notifications Endpoint support for PIDs issued in MSO MDOC.
Default value: true

Variable: ISSUER_PID_SD_JWT_VC_ENABLED
Description: Whether to enable support for PID issuance in SD JWT VC format.
Default value: true

Variable: ISSUER_PID_SD_JWT_VC_NOTUSEBEFORE
Description: Period after which a PID issued in SD JWT VC becomes valid. Used to calculate the value of the nbf claim.
Default value: PT20

Variable: ISSUER_PID_SD_JWT_VC_COMPLEXOBJECTSSDOPTION
Description: Configured how complex objects should be selectively disclosed in the PID issued in SD JWT VC.
Possible values: Flat, Structured, Recursive
Default value: Structured

Variable: ISSUER_PID_SD_JWT_VC_DEFERRED
Description: Whether PID issuance in SD JWT VC format should be deferred or immediate.
Default value: true (i.e. deferred issuance)

Variable: ISSUER_PID_SD_JWT_VC_NOTIFICATIONS_ENABLED
Description: Whether to enabled Notifications Endpoint support for PIDs issued in SD JWT VC.
Default value: true

Variable: ISSUER_PID_ISSUING_COUNTRY
Description: Code of the Country issuing the PID
Default value: GR

Variable: ISSUER_MDL_ENABLED
Description: Whether to enable support for issuing mDL.
Default value: true

Variable: ISSUER_MDL_MSO_MDOC_ENCODER
Description: Configures the CBOR encoder to use for encoding mDLs. Either Internal or Microservice.
Default value: Internal

Variable: ISSUER_MDL_MSO_MDOC_ENCODER_DURATION
Description: Configures the validity of issued mDLs when using the internal encoder. Uses Period syntax. Required when ISSUER_MDL_MSO_MDOC_ENCODER is set to Internal.
Default value: P5D

Variable: ISSUER_MDL_MSO_MDOC_ENCODER_URL
Description: URL of the CBOR encoder microservice to use. Required when ISSUER_MDL_MSO_MDOC_ENCODER is set to Microservice
Default value: N/A

Variable: ISSUER_MDL_NOTIFICATIONS_ENABLED
Description: Whether to enabled Notifications Endpoint support for mDLs.
Default value: true

Variable: ISSUER_CREDENTIALOFFER_URI
Description: URI to use when generating Credential Offers.
Default value: eudi-openid4ci://

Variable: ISSUER_SIGNING_KEY
Description: Whether to generate a new, or use an existing key-pair for signing.
Possible values: GenerateRandom, LoadFromKeystore
Default value: GenerateRandom

Variable: ISSUER_SIGNING_KEY_KEYSTORE
Description: Location of the keystore from which to load the key-pair for signing. Uses Spring Resource URL syntax.
Default value: N/A

Variable: ISSUER_SIGNING_KEY_KEYSTORE_TYPE
Description: Type of the keystore from which to load the key-pair for signing.
Default value: N/A

Variable: ISSUER_SIGNING_KEY_KEYSTORE_PASSWORD
Description: Password of the keystore from which to load the key-pair for signing.
Default value: N/A

Variable: ISSUER_SIGNING_KEY_ALIAS
Description: Alias of the key-pair for signing.
Default value: N/A

Variable: ISSUER_SIGNING_KEY_PASSWORD
Description: Password of the key-pair for signing.
Default value: N/A

Variable: ISSUER_KEYCLOAK_SERVER_URL
Description: URL of the Keycloak authorization server
Default value: N/A
Example: https://localhost/idp

Variable: ISSUER_KEYCLOAK_AUTHENTICATION_REALM
Description: Authentication realm for the administrator user of Keycloak
Default value: N/A
Example: master

Variable: ISSUER_KEYCLOAK_CLIENT_ID
Description: Id of the OAuth2 client used for management of Keycloak
Default value: N/A
Example: admin-cli

Variable: ISSUER_KEYCLOAK_USERNAME
Description: Username of the Keycloak administrator user
Default value: N/A
Example: admin

Variable: ISSUER_KEYCLOAK_PASSWORD
Description: Password of the Keycloak administrator user
Default value: N/A
Example: password

Variable: ISSUER_KEYCLOAK_USER_REALM
Description: Realm of the administered users in Keycloak
Default value: N/A
Example: password

Variable: ISSUER_DPOP_PROOF_MAX_AGE
Description: Max duration a DPoP Access Token is considered active
Default value: PT1M

Variable: ISSUER_DPOP_CACHE_PURGE_INTERVAL
Description: Interval after which cached DPoP Access Tokens are deleted
Default value: PT10M

Variable: ISSUER_DPOP_REALM
Description: Realm to report in the WWW-Authenticate header in case of DPoP authentication/authorization failure
Default value: pid-issuer

Signing Key

When either PID issuance in SD-JWT is enabled, or the internal MSO MDoc encoder is used, an EC Key is required for signing the issued credentials.

By default, the server generates a random EC Key alongside a self-signed certificate using the P-256/secp256r1 curve on startup. If the server is restarted, a new EC Key and self-signed certificate is generated.

In case you opt to use your own EC Key and certificate make sure to use an EC Key that uses one of the following curves:

  • P-256/secp256r1
  • P-384/secp384r1
  • P-521/secp521r1

The signing algorithm is determined by the EC Key used. The server will use one of the following signing algorithms:

  • ES256
  • ES384
  • ES512

To generate an EC Key and self-signed certificate using keytool you can use the following command:

keytool -genkeypair \
  -alias signingKey \
  -keyalg EC \
  -groupname secp256r1 \
  -sigalg SHA256withECDSA \
  -validity 365 \
  -dname "CN=pid-issuer" \
  -storetype JKS \
  -keystore signingKey.jks \
  -storepass 123456 \
  -keypass 654321

This command will create a JKS keystore named signingKey.jks in the current directory, protected by the password 123456. The keystore will contain an EC Key generated using the curve P-256/secp256r1 and a self-signed certificate signed using the algorithm SHA256withECDSA, with the alias signingKey, protected with the password 654321.

Note: When loading an EC Key and certificate from a keystore, make sure the certificate chain is associated with the EC Key alias.

Endpoints

Credential Issuer MetaData

curl http://localhost:8080/.well-known/openid-credential-issuer | jq .

Credential Endpoint

Credentials Offer

Generate sample offer

curl http://localhost:8080/issuer/credentialsOffer | jq .

How to contribute

We welcome contributions to this project. To ensure that the process is smooth for everyone involved, follow the guidelines found in CONTRIBUTING.md.

License

License details

Copyright (c) 2023 European Commission

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

eudi-srv-pid-issuer's People

Contributors

babisroutis avatar christosservosncin avatar dependabot[bot] avatar dzarras avatar vafeini avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

eudi-srv-pid-issuer's Issues

Update docker image tags

Currently publish-to-container-registry.yml workflow uses the following tags:

  1. type=semver,pattern=v{{version}}
  2. type=edge

From the documentation type=edge we read the following:

An edge tag reflects the last commit of the active branch on your Git repository. I usually prefer to use edge as a Docker tag for a better distinction or common pattern. This is also used by official images like Alpine.

My understanding is that the edge tag always points to the latest Docker image that has been created, regardless of the branch that was used to create it. i.e.:

  1. Trigger Docker image creation using main branch. edge tag points to this Docker image.
  2. Trigger Docker image creation using release/0.1.0. edge tag now points to this Docker image.

This can lead to unpredictable behavior in case we restart an already deployed service that uses the edge tag.

We should remove the type=edge tag and instead introduce a new tag type=ref,event=branch which produces predictable tags. The documentation can be found here

By using type=ref,event=branch instead of type=edge the following will happen:

  1. Trigger Docker image creation using main branch. main tag points to this Docker image.
  2. Trigger Docker image creation using release/0.1.0. release/0.1.0 tag points to this Docker image.
  3. We no longer have an edge tag that is always updated to point to the latest Docker image generated regardless of the branch that was used to create it.

If we opt to use the above, we must apply this change both to main and release/0.1.0 branches.

Update Issuer Metadata

Attribute supported_credentials has been change from a list of credential metadata, to map where each entry is a key (a unique identifier for the specific credential) and the value is an object with the credential metadata

Issuing PID in SD-JWT-VC format results in "unsupported_credential_type"

Hello, I am trying to issue a PID in SD-JWT-VC format and I am getting an "unsupported_credential_type" error.

  • Trying without a "vct" field (as shown in file pid-issuer.http):
# curl -s -XPOST http://localhost/pid-issuer/wallet/credentialEndpoint -H 'Content-type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer ...' --data '{
  "format": "vc+sd-jwt",
  "credential_definition": {
    "type": "eu.europa.ec.eudiw.pid.1"
  },
  "proof": {
    "proof_type": "jwt",
    "jwt": "eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoicDJObi1kV19ibWdNMFRHTHhqQ0Q5TGFfMW5vZjhLaUZCTjhzNFQ1QS0xQSIsImFsZyI6Il
JTMjU2IiwibiI6InRwUFNEWkNjTmtBak9BRmNUakYzRjNrUVdkdjZ5UlpxT3NEUW5TMGZYU053all5V2lDZmw4MXlpNWt2VVRFSjZrcXo4QjFXYW90UVlyRldmY2VTV2cycVpfdkZxcV9TUFE0VmtmaDVIdVF2MmhVdFNsU1Z0a2NJTDZIZXcycUt3bVJLUVFDU1Q5ZE9UQ2l2
X3RhOHZNQmhJdjdrTmhGUWxnbmsyRHBVNUtQZHN2V2ZCTExHb25tOTdremE2LWx0SjZqUlJ4YVdjU1B5clJBVVQtQ19QUzctTnpDYWdmWVU1TE5ObVZwbVBpZ01ycmFNVGtWVk5JMnpQU0p3U2RKWkl2MVV2TkkzZ1NzOXlFQlNqU1BpVkFzM1VBTkdONF9sblF3aUpicUFoYn
dJUTFiS1ZMMXloWXJXSlhGRWlqcUtpUmdqUHhVSnJxUHpxWHdTOFVLQllaUSJ9fQ.eyJleHAiOjE3MTM0NTk5MjksImlhdCI6MTcxMzM1OTkyOSwianRpIjoiYWM2NmI4NmUtMWNhNC00MjI5LTk2MjItMzYwZmNmMTdkMmVhIiwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Qva
WRwL3JlYWxtcy9waWQtaXNzdWVyLXJlYWxtIiwic3ViIjoiNjBiOGJhNWYtYzczZi00OTc2LWIwZGEtNDhkMGU1MzMzNWRlIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2FsbGV0LWRldiIsInNlc3Npb25fc3RhdGUiOiI2MDg1ZGM2OC00NjdhLTQ4MTktOTgzZC1lMzBjM2U
yNzMxMzMiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwic2NvcGUiOiJvcGVuaWQgZXUuZXVyb3BhLmVjLmV1ZGl3LnBpZF92Y19zZF9qd3QgZXUuZXVyb3BhLmVjLmV1ZGl3LnBpZF9tc29fbWRvYyIsInNpZCI6IjYwODVkYzY4LTQ2N2EtNDgxOS05ODNkLWUzMGMzZTI3M
zEzMyIsImF1ZCI6WyJodHRwczovL2xvY2FsaG9zdC9waWQtaXNzdWVyIl0sIm5vbmNlIjoiZjRiN2VhOWYtNWE4NS00MDE3LTk0ZjYtYjZjN2RmZGQ0MzZkIn0.aZyx2G8d-YJpEpCS6FJ6rApNHm5HERGifzl-2Zd3EOpySFxgW6cP-Q6ogKKldIesWogg8J8Xycs0U9Epr1n
10TZoK_bTR0BqyQTvc5tP5YwIP3VASDWwRghtAoLkKqW4HanPyrP9Oz5HK2J7eQ5vzaRkL0KEixHO7n0S8QbHAGyeNN96nRjKwzrInCaGoG24glQ1pLTtMjJ4q_qNrNRP4f658mSFDF_M3oT5k4y6q5F48K5wPjlnKjJFayEsFVO5zgWoOQ7gKNa0IB3xWIENVKX9LJcmO-QcP
EZRyLmam0-AU1czgq8c5i0ZNgpisIJIQBaegGB9k5FyYpGeyeDsrw"
  }
}'
{
  "error": "unsupported_credential_type",
  "error_description": "Unsupported format 'vc+sd-jwt' type `[]`",
  "c_nonce": "0891ab38-41b0-42a8-bef4-2c0f244d9533",
  "c_nonce_expires_in": 300
}
  • Trying with a "vct" field (as shown in test CredentialRequestTOTest):
# curl -s -XPOST http://localhost/pid-issuer/wallet/credentialEndpoint -H 'Content-type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer ...' --data '{
  "format": "vc+sd-jwt",
  "vct": "IdentityCredential",
  "credential_definition": {
    "type": "eu.europa.ec.eudiw.pid.1"
  },
  "proof": {
    "proof_type": "jwt",
    "jwt": "eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoicDJObi1kV19ibWdNMFRHTHhqQ0Q5TGFfMW5vZjhLaUZCTjhzNFQ1QS0xQSIsImFsZyI6Il
JTMjU2IiwibiI6InRwUFNEWkNjTmtBak9BRmNUakYzRjNrUVdkdjZ5UlpxT3NEUW5TMGZYU053all5V2lDZmw4MXlpNWt2VVRFSjZrcXo4QjFXYW90UVlyRldmY2VTV2cycVpfdkZxcV9TUFE0VmtmaDVIdVF2MmhVdFNsU1Z0a2NJTDZIZXcycUt3bVJLUVFDU1Q5ZE9UQ2l2
X3RhOHZNQmhJdjdrTmhGUWxnbmsyRHBVNUtQZHN2V2ZCTExHb25tOTdremE2LWx0SjZqUlJ4YVdjU1B5clJBVVQtQ19QUzctTnpDYWdmWVU1TE5ObVZwbVBpZ01ycmFNVGtWVk5JMnpQU0p3U2RKWkl2MVV2TkkzZ1NzOXlFQlNqU1BpVkFzM1VBTkdONF9sblF3aUpicUFoYn
dJUTFiS1ZMMXloWXJXSlhGRWlqcUtpUmdqUHhVSnJxUHpxWHdTOFVLQllaUSJ9fQ.eyJleHAiOjE3MTM0NjAyMzIsImlhdCI6MTcxMzM2MDIzMiwianRpIjoiYWM2NmI4NmUtMWNhNC00MjI5LTk2MjItMzYwZmNmMTdkMmVhIiwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Qva
WRwL3JlYWxtcy9waWQtaXNzdWVyLXJlYWxtIiwic3ViIjoiNjBiOGJhNWYtYzczZi00OTc2LWIwZGEtNDhkMGU1MzMzNWRlIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2FsbGV0LWRldiIsInNlc3Npb25fc3RhdGUiOiI2MDg1ZGM2OC00NjdhLTQ4MTktOTgzZC1lMzBjM2U
yNzMxMzMiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwic2NvcGUiOiJvcGVuaWQgZXUuZXVyb3BhLmVjLmV1ZGl3LnBpZF92Y19zZF9qd3QgZXUuZXVyb3BhLmVjLmV1ZGl3LnBpZF9tc29fbWRvYyIsInNpZCI6IjYwODVkYzY4LTQ2N2EtNDgxOS05ODNkLWUzMGMzZTI3M
zEzMyIsImF1ZCI6WyJodHRwczovL2xvY2FsaG9zdC9waWQtaXNzdWVyIl0sIm5vbmNlIjoiZjRiN2VhOWYtNWE4NS00MDE3LTk0ZjYtYjZjN2RmZGQ0MzZkIn0.KMLLyge577f8_2PVn7hbOrI2wJXL-65-IU5-tnCtG-XW4C6KP-__MgK7xbrUMqLolJeRRtVdXRqsMjWr0SF
VaH5eKIp7YV8ewl0IuvBqmveJ1x1WpFV0GRbZdo-3wfAocgwYjk3Fo0_mLCOTIdiuuQYK6wY9uj0-RGZ6fvi74KR7LY06APQixDptUyNdSVz-3-FYGsYsVnbMHl-NwjzhzUTCrYQPOUA_kFPA_JVSBeqNZYHJFQ6Y8SRR_xSZsr3ELPN6lzQLC-Q_zwnN2bfeFZ1zngKlSv0PL
Bsv8M90wdU3RgXIsAEewHE4B-m_mloRCxQ1swojYzifJ-d3EN4pOg"
  }
}'
{
  "error": "unsupported_credential_type",
  "error_description": "Unsupported format 'vc+sd-jwt' type `[IdentityCredential]`",
  "c_nonce": "dcd36b27-6d1d-4c7b-94ee-285ab31ddd54",
  "c_nonce_expires_in": 300
}

In the snippets above, I have replaced the access token with "..." to avoid clutter.

Environment: I am using the docker-compose infrastructure locally.

Batch Credentials endpoint

Batch Credential Request

It seems that the implementation is straight forward, at least for the happy path.

A batch credential request is a container for one or more individual credentials requests.
The same is true for the response.

Considerations:
Given that the batch issuance follows an or all or none approach, there is the unhappy path that while serving a batch request, there are some credentials issued and at least one that fails.

This means that either
a. Issuance of each specific credential should have NO permanent side effects, or
b. Issuance should have some compensation function to immediately cancelled an issued credential.

I believe that (a) cannot be met.

For instance, to fully comply with SD-JWT-VC the issue must add revocation information to the credential which requires the permanent association of the credential to a JWT-CWT Status list, which is a permanent side-effect.

Update Keycloak realm

  • Remove place_of_birth attribute and protocol mappers
  • Convert gender and age_over_18 registration form elements to select with known values

Reference IEC5218

Use version agnostic webjar urls

Webjar resources must not be used using version specific URLs.

When using version specific urls we risk breakage when upgrading to newer versions.
For instance #110 introduced a breakage in the UI for creating Credential Offers.

Any href/src attributes in thymeleaf templates must be updated to use version agnostic urls instead.

Document `docker-compose`

We need to document a "how to" use the docker-compose.

  • Add to docker-compose the pid-issuer service. This should point to the github package
  • Add either in the README.MD "how-to", configuraiton options, commands etc

Use DPoP authentication scheme for issuer's endpoints

RFC9449 defines DPoP authorization scheme.
It should be an option for protecting issuer's endpoints

  • Replace Bearer Authentication scheme with DPoP. Spring security doesn't support this
  • Enable Keycloak docker image DPoP feature
  • Find an alternative way of accessing user claims from Keycloak (used as a source for PID credentials). Currently, issuer just uses the bearer access_token send by the wallet to access userinfo endpoint

Simplify error handing in `EncodePidInCborWithMicroService`

cbor-formatter returns error responses using 200/OK status code.

the following block

            .awaitExchange { response ->
                val statusCode = response.statusCode()
                when {
                    statusCode.is2xxSuccessful -> response.awaitBody<CreateMsoMdocResponse>()
                    statusCode.is4xxClientError -> response.awaitBody<CreateMsoMdocResponse>()
                    else -> error("Unexpected error statusCode = $statusCode")
                }
            }

is not necessary.

SD-JWT-VC PID request returns "invalid_proof" (lack of proof of possession)

Based on the example of a valid request in #136, I get an "invalid_proof" error:

My invocation:

curl -s -XPOST http://localhost/pid-issuer/wallet/credentialEndpoint -H 'Content-type: application/json' -H 'Accept: application/json' -H 'Authorization: Bearer ...' --data '{
  "format": "vc+sd-jwt",
  "vct": "eu.europa.ec.eudiw.pid.1",
  "proof": {
    "proof_type": "jwt",
    "jwt": "eyJ0eXAiOiJvcGVuaWQ0dmNpLXByb29mK2p3dCIsImFsZyI6IlJTMjU2IiwiandrIjp7Imt0eSI6IlJTQSIsImUiOiJBUUFCIiwidXNlIjoic2lnIiwia2lkIjoiYTg1YWU5NzctMTIwYi00ZDBmLWJmZGMtMTZjOTk1YjUwMzA2IiwiaWF0IjoxNzEzNDUwNTg1LCJuIjoiaVlBeGFVeEY3VnBvZEMwUGRpZkMwdTJTVTg1NHJYdG5qX01Oa0dpSFhGR0NXLWoyR0NVbUtpWWFYYVV2TlpMNzB5aGxfNW10LWxsVUc4WlJ3LVgwaURVSVRxdFJLaHVCa1JSbWFITjFqMmd2ZlJ6M3RsTzlHNHFlSURaUThoa1dnbm5vb09oaTFDaV8tY3dtcXFwSkg1YjMwbElSVnA0Z3VBWFAyd1dIZ0ZkLVJJcjEyN3BoUnoyYWJORGFCR2tMUWpCSnZfSTRXbm9YVDdYcG1KMEVfVU9zTEVBRUpBMzQ3YnhKa1Y5VlpWZThKeVl2djA0VDhnWDBYclFWLXNyNU1PQUhMd09rT3NFQ2JUOGE2dUJYempDSXVnTlVYN3dzWnBQZno3VkpJYS16V3R3djQ3bFFtVDUwR2FycTc2UVptZUMtRkFRcWFnM2owSHFEWW03dFhRIn19.eyJhdWQiOiJodHRwczovL2xvY2FsaG9zdC9waWQtaXNzdWVyIiwibm9uY2UiOiIwMTI5OWI3Yy05MGE3LTRlMWMtYTFiZi1hZTk2NGUzOTIyYmYiLCJpYXQiOjE3MTM0NTA1ODZ9.hP5C_bNnswr3vMWbKAKA4jvg-240mBPZynql8pDLkLWk5tQVQzxdLdsIBHYPQ0XVrkObdIU4rocc6Mo3SAyGudHBnuuPua9ZPaMm5Hhlvam24x4b_nO04IpTg2PB38SWhZZg_ANVt7cQTGAuf8Zf1z8jxJKl3CVsFRCTB6csDr2Or68oUd0gZHzP104wyvX1A0-h7CgYSuvT8JdE1NYaMIVmBTH24nnGWx5l5b8uf3PR3lR1nhqIZIf0UFa6Xt-kQoO37AHKNZhJ4TSgf-VUHLCtyoHxvQXioiFaNQAqiO3VYcL3zAsy6v8Eah0DSvT4hc9H7NepIYdFzcvViI0hog"
  },
  "credential_response_encryption": {
    "jwk": {
      "kty": "RSA",
      "e": "AQAB",
      "use": "enc",
      "kid": "b4cc97d3-c993-4dc9-9a6f-8ec788b9760f",
      "iat": 1713450586,
      "n": "jaT6TN6YPEvLVPcJChWfF6d6S0LyhXSjw72ZCkE0282hwT0ZjwC2sx1RKIpWzfvci41JTzgOEJb9w14RgspPQ_RlpNzo8hIHhfgS5cJ-HeB_YDZqP197wQJmt5EXQr_nOPdUbUlsc81lMXjY2OOXA-KTqAr6_UlP-HPscG9WC8a-bEGgX30BjtIj2N_GUTBCh3
xAOdXIbnvuoyPQbcnEqu0OmYh0iiSJs4_Fae3LRxTEEycOMhkYPcx4vgs9_F2N6dXsK_-wYWEaI3b9-lI5mS6INxmvduRjdApkFyjk5IwXTmsULDpnY3qQMuZgJZ2ckmxkEBudlRL-6eNZg4Z8iw"
    },
    "alg": "RSA-OAEP-256",
    "enc": "A128CBC-HS256"
  }
}'

and the result:

{
  "error": "invalid_proof",
  "error_description": "The Credential Request must include Proof of Possession",
  "c_nonce": "de2c0ed6-640a-49ce-b015-cf9074b18348",
  "c_nonce_expires_in": 300
}

Repo access

docker compose up
[+] Running 3/3
 ✘ pid-issuer Error                                                                                          1.0s 
 ✘ haproxy Error                                                                                             1.0s 
 ✘ keycloak Error                                                                                            1.0s 
Error response from daemon: Head "https://ghcr.io/v2/eu-digital-identity-wallet/eudi-srv-pid-issuer/manifests/edge": unauthorized

Update Credential Offer

Credential offer parameters

  • Changed the definition of credentials parameter. Now, it is only an array of string
  • grantsChanged to optional. If not provided, Wallet must take the flows supported from OAuth2 server metadata.
  • the contents of Grant Types has been changed. In both case a new option field named authorization_server has been added

Add support for Mobile Driving Licence (mDL) issuance

Add support for issuing a Mobile Driving Licence.
Tasks:

  • Add domain models for mDL as per ISO/IEC 18013-5
  • Add out port for fetching a random mDL data
  • Add out port for encoding mDL data in CBOR using CBOR encoder microservice
  • Add issuance service for mDL
  • Add metadata for mDL
  • Wire issuance service for mDL in issuer
  • Update Keycloack realm adding new mDL scope
  • Test with OpenID for VCI library example

Support CWT proof

Athlete provides a new library for CBOR, COSE & CWT

Perhaps we should check it to implement CWT Proof

Add the abilty to make `CredentialOffer`

We can rather easily allow our issuer to make CredentialOffer that use the authorization code grant.

  • Add a new endpoint, let's call it, IssuerUI
  • To this IssuerUI and a POST that would accept of list of CredentialId and in response it would return a CredentialOffer in JSON
  • Add a simple web page to Issuer. The web page should present the list of supported credentilas and would allow the user to select one or more in order to ask from Issuer to make an Offer.
  • Add a new use case CreateCredentialOffer

Migrate to draft 13

Migrate issuer app to draft 13.

Draft 13 introduced several breaking changes, especially related to the issuer meta-data. The functional scope of the mirgation will be the same as with draft 12.

  • Support Authz code flow, without issuer_state, without (authorization_details, RAR)
  • Migrate issuer meta-data
  • Add the newly defined notification endpoint

Use a single signing key for all formats, owned by the isser.

Currently, issuer depends on an external service for signing credentials in mso_mdoc format.
In addition, this external service owns the key that is being used to sign the credentials.

For SD-JWT-VC and W3C DM formats, it is the issuer that controls the signing key (either randomly generated upon application startup or externally provided via a keystore).

This is problematic. Issuer should use a single signing key used for all formats to simplify key management

Wrong `proof_signing_alg_values_supported` for PID, mDL in mso_mdoc

Issuer supports only ECKey for mso_modc credentials.
Yet it advertises proof_signing_alg_values_supported that contain RSA algorithm.

{
   "proof_types_supported": {
        "jwt": {
          "proof_signing_alg_values_supported": [
            "RS256",
            "ES256"
          ]
        }
      }
}

To fix this, it should define only EC signing algorithms.

Improve/cleanup build.gradle.kts

  1. The function getVersionFromCatalog() is not needed. Versions can be resolved from the libs property.
  2. Rename ktlintVersion to ktlint in libs.versions.toml to align with the naming convention used.

Spring Boot improvements

  • Deduplicate properties between default and prod profile. prod profile simply provides some overrides for certain properties. No need to keep the duplicates.
  • Remove @EnableWebFlux and @EnableWebFluxSecurity annotations.

Concerning the second task:
First of all these annotations are not needed. The autoconfiguration classes merely check for their presence on the classpath to enable the relevant autoconfiguration aspects.
In the case of @EnableWebFlux though, things get particularly nasty. When a @Configuration class is annotated with @EnableWebFlux and a WebFluxConfigurer is present, Spring Boot disables all autoconfiguration for WebFlux. This is bad because it causes the autoconfiguration for libraries like Thymeleaf to be ignored. (this is required for #80)
To avoid the issue with @EnableWebFlux instead provide customizers like CodecsCustomizer that get picked up by the autoconfiguration for WebFlux and apply the required customizations.

Load signing key from a keystore

Currently, application generates a random key pair, for signing credentials with format SD-JWT-VC during startup.

We could load this key pair from an externally defined keystore, similar to that the verifier does.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.