Swiss Profile Issuance
Status: draft - technically complete, but might to be reformulated
Introduction
This profile defines the capabilities required to issue Verifiable Credentials (VCs) to a holder’s wallet. It deliberately does not cover the structure or semantics of the credentials themselves, nor does it address trust establishment between wallets, issuers, or other ecosystem entities.
Cryptography
To decrease complexity, initially the cryptographic options are limited to following algorithms.
- JWS algorithm MUST be ES256.
- Encryption MUST use only ECDH-ES with P-256 Keys with A256GCM algorithm.
- If zipping is possible, Deflate (DEF) MUST be used.
- If using encryption is possible, it MUST be used.
Specifications
All underlying specifications referenced by the included standards are considered fully supported unless explicitly noted otherwise.
| Contained Specifications | Version | Link to referenced Specification |
|---|---|---|
| OpenID4VCI | 1.0 | OpenID for Verifiable Credential Issuance (OID4VCI) v1.0 |
| OAuth 2.0 DPoP | RFC-9449 | RFC9449 - Demonstrating Proof of Possession (DPoP) |
KEY WORDS for this swiss profile expand on RFC 2119 “Key words for use in RFCs to Indicate Requirement Levels”. They are explained in the general introduction for the specifications. They are to be interpreted as such when, and only when, they appear bold and CAPITALIZED.
OpenID for Verifiable Credential Issuance (OID4VCI) v1.0
This section details the implementation notes and gaps pertaining to the supported specifications.
The specifications are fully supported by this profile (and components adhering to it) except for the specific cases mentioned in the following subsections.
3. Overview
3.3. Core Concepts
3.3.1. Credential Formats and Credential Format Profiles
Swiss Profile Issuance only supports IETF SD-JWT VC (see Swiss Profile VC)
Credential Format Profiles “ISO mdoc” and “W3C VCDM” are NOT SUPPORTED.
3.3.3 Issuance Flow Variations
Pre-Authorized Code Flow MUST be supported.
Authorization Code Flow and Wallet initiated communication are NOT SUPPORTED.
3.3.4. Identifying Credentials Being Issued Throughout the Issuance Flow
authorization_details is NOT SUPPORTED. It is expected that the credential issuer links the credential to be issued to the wallet through the pre-authorized_code.
scope is NOT SUPPORTED.
3.4. Authorization Code Flow
Authorization Code Flow is NOT SUPPORTED.
3.5. Pre-Authorized Code Flow
(4) Token Request MUST use of Demonstrating Proof of Possession (DPoP)
Registering a DPoP key MUST come with a key attestation (with the same security level as allowed by the issuer for the holder binding key) in case where a hardware-bound credential is requested.
Transaction Code tx_code MUST be supported. The use of Transaction Code is OPTIONAL.
Wallets MUST support 6 digit tx_codes. Issuers SHOULD invalidate a credential offer after 5 failed retries.
4. Credential Offer Endpoint
4.1. Credential Offer
credential_offer MUST be supported.
credential_offer_uri is NOT SUPPORTED.
4.1.1.Credential Offer Parameters
Grant Type authorization_code is NOT SUPPORTED.
authorization_server is NOT SUPPORTED. It is expected that the Credential Issuer Server is also the authorization server.
The array credential_configuration_ids SHOULD have only one (1) entry. If there are more than one entries the wallet SHOULD only use the first.
4.1.2. Sending Credential Offer by Value Using credential_offer Parameter
Both URL schemes openid-credential-offer:// and swiyu:// MUST be supported by wallets.
5. Authorization Endpoint
Authorization Endpoint is NOT SUPPORTED.
6. Token Endpoint
Issuers and Wallets MUST support pre-authorized_code.
For Verifiable Credential Lifecycle such as renewal, Wallets MUST support refresh_token. Issuers MAY support refresh_tokens.
Requests to the token endpoint MUST be sent with a DPoP Header.
6.1.1 Request Credential Issuance using authorization_details Parameter
authorization_details are NOT SUPPORTED
6.2. Successful Token Response
Authorization server MUST NOT return authorization_details
7. Nonce Endpoint
It is RECOMMENDED that the nonce is a a self contained nonce, which the issuer can decern to be not valid without registering every nonce which has been requested from this public endpoint.
A self-contained nonce refers to a single-use string or number that carries all necessary information for its validation within itself, eliminating the need for storing possible valid nonces which have not been used.
7.2. Nonce Response
Issuers MUST provide a DPoP nonce.
8. Credential Endpoint
Wallets MUST support key attestation.
8.2. Credential Request
Requests MUST be sent with a DPoP Header.
credential_identifier is NOT SUPPORTED.
credential_configuration_id MUST be set to credential_configuration_id from the credential offer.
credential_response_encryption MUST be used and encryption_required MUST be true.
8.3. Credential Response
The number of elements in the credentials array MUST match the exact number of keys that the Wallet has provided via the proofs parameter of the Credential Request.
notification_id is NOT SUPPORTED.
Implementation Recommendation
Generally issuers are recommended to fit the size of issued VCs to their usecase and to keep them as small as possible. The same goes for the batch payload limit.
The max batch payload limit SUPPORTED by the swiyu Wallet is 20MB (measured decompressed but potentially still encrypted payload).
9. Deferred Credential Endpoint
Requests MUST be sent with a DPoP Header.
11. Notification Endpoint
Notification Endpoint MUST NOT be supported by the wallet for privacy reasons.
12. Metadata
12.1. Client Metadata
Client Metadata is NOT SUPPORTED.
12.2. Credential Issuer Metadata
12.2.2. Credential Issuer Metadata Retrieval
Issuers and Wallets MUST support well-known URIs as described in OID Connect Discovery (OIDC) with appended .well-known path.
Example for OIDC style .well-known URI: https://example.com/issuer1 will lead to an HTTP call:
GET https://example.com/issuer1/.well-known/openid-configuration
Wallets MUST support well-known URIs as described in IETF RFC 5785 where the well-known URI is inserted at the beginning of the path component of an URI.
Issuers SHOULD support these well-known URIs.
Example for RFC 5785 style .well-known URI: https://example.com/issuer1 will lead to an HTTP call:
GET https://example.com/.well-known/openid-configuration/issuer1
12.2.3. Signed Metadata
Issuers MUST also provide Signed Metadata.
The Wallet MUST request and use Signed Metadata.
Signed Metadata MUST be used.
The Signed Metadata MUST be verified according to swiss-profile-anchor.
The kid header claim is REQUIRED and MUST be an absolute fragment containing a DID as described in swiss-profile-anchor.
Swiss Profile version indication with parameter profile_version in Credential Issuer Metadata JWT header is REQUIRED.
{
// header
"typ":"openidvci-issuer-metadata+jwt",
"alg":"ES256",
"profile_version": "swiss-profile-issuance:1.0.0"
}
.
{
// payload
}
12.2.4. Credential Issuer Metadata Parameters
authorization_serversis NOT SUPPORTED.notification_endpointis NOT SUPPORTED.nonce_endpointis REQUIRED.credential_request_encryptionis REQUIRED.encryption_requiredMUST betrue.
credential_response_encryptionis REQUIRED.encryption_requiredMUST betrue.
batch_credential_issuanceis RECOMMENDED for privacy relevant use-cases.batch_sizeis REQUIRED. Integer value MUST be at least 10 specifying the maximum array size for the proofs parameter in a Credential Request. The Wallet MAY send fewer proofs than defined in the batch size. The Issuer MUST create as many Credentials as proofs received.
displayis RECOMMENDED to properly display issuer information to Walletslogoremains OPTIONAL.uriMUST be a Data-URL (data URI schema) with MIME typeimage/jpegorimage/pngand be base64 encoded. This means theuriMUST begin withdata:image/png;base64ordata:image/jpeg;base64.
credential_configurations_supportedremaind REQUIRED.scopeis NOT SUPPORTED.cryptographic_binding_methods_supportedMUST bejwkas only JWK format for holder bindings are supported.proof_types_supportedMUST bejwtas only JWT format is supported.key_attestations_requiredMUST be supported by Wallets, and MAY be used by Issuers.
credential_metadataremains OPTIONAL.displayMAY be used as visualisation fallback to OCA Bundle.logoremains OPTIONAL.uriMUST be a Data-URL (data URI schema) with MIME typeimage/jpegorimage/pngand be base64 encoded. This means theuriMUST begin withdata:image/png;base64ordata:image/jpeg;base64.
background_imageis NOT SUPPORTED.text_coloris NOT SUPPORTED.
claimsremains OPTIONAL.mandatoryis NOT SUPPORTED.
Swiss Profile version indication with parameter profile_version in Credential Issuer Metadata JSON body is REQUIRED.
{
"profile_version": "swiss-profile-issuance:1.0.0"
...
}
12.3. OAuth 2.0 Authorization Server Metadata
If used, pre-authorized_grant_anonymous_access_supported and any other additional OAuth 2.0 Authorization Server Metadata MUST be provided and signed as application/jwt in the same way as defined in “12.2.3. Signed Metadata” for credential issuer metadata.
13. Security Considerations
13.6. Pre-Authorized Code Flow
Issuer SHOULD accept pre-authorized codes only once.
When providing the Pre-Authorized Code for example as QR, Issuers SHOULD use the transaction code (tx_code) and provide it though a secondary channel (text message or email).
13.11. Application-Layer Encryption
Application-Layer encryption MUST be used for request and response.
Encryption JWK MUST include the alg claim. The alg claim MUST be ECDH-ES.
14. Implementation Considerations
14.5. Refreshing Issued Credentials
Wallets can refresh Credentials by re-requesting them at the Credential Endpoint with a valid Access Token and DPoP.
Issuers can always refuse the refresh.
If refused because a refresh is already in progress, Issuer MUST respond with error code 429 (Too Many Requests).
14.6. Batch Issuing Credentials
The Wallet MUST send at maximum the amount of proofs defined in the issuer metadata batch_size.
The Issuer MUST send exactly as many credentials as proofs received.
The Issuer should only use Batch Issuing if unlinkability of Verifiers is desired.
Batch Issuance should not be used for credentials that rely on use cases where the data itself can be used to link different presentations.
There is no guarantee that any Wallet uses a credential of a batch only once. Issuers and Verifiers should not rely on the fact that a credential in a batch is only shown once in the Wallet. Batch issuing is therefore not suited for a batch of credentials like e.g., day passes, multi ride tickets or loyalty cards as the content of a credential in a batch is required to be equal.
14.A Batch Issuance - Batch Size
The batch size MUST be at least 10, to ensure Holder privacy. If holder were to refresh credentials often due to a small batch size, Issuers could easily gather telemetry data.
Wallets SHOULD define a limit how many credentials can be issued in one batch, to prevent being overloaded by exceedingly large batch sizes. This can be done by limiting the amount of proof of possessions being created.
Appendix A. Credential Format Profiles
Only supported Credential Format Profile is IETF SD-JWT VC
A.3. IETF SD-JWT VC
A.3.2. Credential Issuer Metadata
The following additional Credential Issuer Metadata parameters are defined for this Credential Format for use in the credential_configurations_supported parameter, in addition to those defined in Section 12.2.4 and A3.2.
vct_metadata_uriOPTIONAL - If used in the Credential being issued RECOMMENDEDvct_metadata_uri#integrityOPTIONAL
See usage of this additional parameters in swiss-profile-vc.
Appendix D. Key Attestations
Wallets MUST support key attestations.
D.1. Key Attestation in JWT format
Swiss Profile version indication with parameter profile_version in the key attestation JWT header is REQUIRED.
{
// header
"typ":"key-attestation+jwt",
"alg":"ES256",
"profile_version": "swiss-profile-issuance:1.0.0"
}
.
{
// payload
}
OAuth 2.0 Demonstrating Proof of Possession (DPoP) - RFC 9449
4. DPoP Proof JWTs
4.2. DPoP Proof JWT Syntax
Swiss Profile version indication with parameter profile_version in DPoP JWT header is REQUIRED.
{
// header
"typ":"dpop+jwt",
"alg":"ES256",
"profile_version": "swiss-profile-issuance:1.0.0"
}
.
{
// payload
}
5. DPoP Access Token Request
5.1. Authorization Server Metadata
If dpop_signing_alg_values_supported is missing it MUST be assumed that the list of supported JWS alg values are the ones listed in this profile under Cryptography.
5.2. Client Registration Metadata
Client Registration Metadata is NOT SUPPORTED. dpop_bound_access_tokens are always presumed to be true.
6. Public Key Confirmation
NOT SUPPORTED. It is assumed that both roles of resource server and authorization server will be fulfilled by the credential issuer.
8. Authorization Server-Provided Nonce
Credential Issuers MUST provide DPoP Nonces.
Fresh DPoP Nonces MUST be provided in the response of the OID4VCI Nonce Endpoint.
10. Authorization Code Binding to a DPoP Key
Credential Issuer MUST bind Authorization Code to the Holder’s DPoP key.
Appendix
DPoP is expanded with the additional features
Key Attestation
When the one of the credentials offered by the issuer require a key attestation for a hardware bound key (iso_18045_high) , the key used for DPoP has the same requirement. In this case, the wallet MUST provide a Key Attestation JWT as described in OID4VCI Appendix D as part of the DPoP used when registering the public key with the first DPoP Access Token Request. The Issuer MUST validate this first key attestation. If the key attestation is not valid, the Issuer MUST reject the whole DPoP.
In further requests using the same key, the wallet SHOULD NOT include the key attestation in the DPoP. The issuer MUST treat these additional key attestations as unknown parameters. This is to prevent to accidentally invalidating DPoPs and making refresh impossible should the key_attestation jwt date run out or the key attestation service perform a key rotation.
The key attestation is included in the JWT-Header of the DPoP as the claim key_attestation.
{
"typ": "dpop+jwt",
"alg": "ES256",
"jwk": {
"kty": "EC",
"crv": "P-256",
"x": "TCAER19Zvu3OHF4j4W4vfSVoHIP1ILilDls7vCeGemc",
"y": "ZxjiWWbZMQGHVWKVQ4hbSIirsVfuecCE6t4jT9F2HZQ"
},
"key_attestation": "eyJ0eXAiOiJrZXktYXR0ZXN0YXRpb24rand0IiwiYWxnIjoiRVMyNTYiLCJraWQiOiJkaWQ6d2Vidmg6ZXhhbXBsZS5jb20ja2V5LTEiLCJwcm9maWxlX3ZlcnNpb24iOiJzd2lzcy1wcm9maWxlLWlzc3VhbmNlOjEuMC4wIn0.eyJpc3MiOiJkaWQ6d2Vidmg6ZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyNDcwMjIsImV4cCI6MTU0MTQ5MzcyNCwia2V5X3N0b3JhZ2UiOlsiaXNvXzE4MDQ1X2hpZ2giXSwiYXR0ZXN0ZWRfa2V5cyI6W3sia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiJUQ0FFUjE5WnZ1M09IRjRqNFc0dmZTVm9ISVAxSUxpbERsczd2Q2VHZW1jIiwieSI6Ilp4amlXV2JaTVFHSFZXS1ZRNGhiU0lpcnNWZnVlY0NFNnQ0alQ5RjJIWlEifV19.sj4ulKVk8Xm-Nd-9aODEXI_YpVqPv7llM2fJqZz9R279QN-2g08Rw6U-Dy3u84BVXPYi9B1Wki7mcubO21RrXw",
"profile_version": "swiss-profile-issuance:1.0.0"
}.{
"jti": "-BwC3ESc6acc2lTc",
"htm": "POST",
"htu": "https://server.example.com/token",
"iat": 1562262616
}
Example DPoP Access Token Request with key attestation:
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYiLCJ4IjoiVENBRVIxOVp2dTNPSEY0ajRXNHZmU1ZvSElQMUlMaWxEbHM3dkNlR2VtYyIsInkiOiJaeGppV1diWk1RR0hWV0tWUTRoYlNJaXJzVmZ1ZWNDRTZ0NGpUOUYySFpRIn0sImtleV9hdHRlc3RhdGlvbiI6ImV5SjBlWEFpT2lKclpYa3RZWFIwWlhOMFlYUnBiMjRyYW5kMElpd2lZV3huSWpvaVJWTXlOVFlpTENKcmFXUWlPaUprYVdRNmQyVmlkbWc2WlhoaGJYQnNaUzVqYjIwamEyVjVMVEVpTENKd2NtOW1hV3hsWDNabGNuTnBiMjRpT2lKemQybHpjeTF3Y205bWFXeGxMV2x6YzNWaGJtTmxPakV1TUM0d0luMC5leUpwYzNNaU9pSmthV1E2ZDJWaWRtZzZaWGhoYlhCc1pTNWpiMjBpTENKcFlYUWlPakUxTVRZeU5EY3dNaklzSW1WNGNDSTZNVFUwTVRRNU16Y3lOQ3dpYTJWNVgzTjBiM0poWjJVaU9sc2lhWE52WHpFNE1EUTFYMmhwWjJnaVhTd2lZWFIwWlhOMFpXUmZhMlY1Y3lJNlczc2lhM1I1SWpvaVJVTWlMQ0pqY25ZaU9pSlFMVEkxTmlJc0luZ2lPaUpVUTBGRlVqRTVXbloxTTA5SVJqUnFORmMwZG1aVFZtOUlTVkF4U1V4cGJFUnNjemQyUTJWSFpXMWpJaXdpZVNJNklscDRhbWxYVjJKYVRWRkhTRlpYUzFaUk5HaGlVMGxwY25OV1puVmxZME5GTm5RMGFsUTVSakpJV2xFaWZWMTkuc2o0dWxLVms4WG0tTmQtOWFPREVYSV9ZcFZxUHY3bGxNMmZKcVp6OVIyNzlRTi0yZzA4Unc2VS1EeTN1ODRCVlhQWWk5QjFXa2k3bWN1Yk8yMVJyWHciLCJwcm9maWxlX3ZlcnNpb24iOiJzd2lzcy1wcm9maWxlLWlzc3VhbmNlOjEuMC4wIn0.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwiaWF0IjoxNTYyMjYyNjE2fQ.wWQJzvfLCFqsEWN2UoiavFf_taZv33sRFFc5WuPYKn4WsJ2HKE3bppWXtkPHh20WIZiYkjH4GRW_VQAJQF9huQ