Credential Request encrypted when it asks for an encrypted response
OID4VCI 1.0 §8.2MUSTRoles: issuer
Requirement as recorded in the ProtocolSoup registry
Credential Request encryption MUST be used if the credential_response_encryption parameter is included, to prevent it being substituted by an attacker.
Read §8.2 in OID4VCI 1.0Self-test verdict
PassCommit 011029cEvaluated
This is ProtocolSoup's result against its own implementation at the commit shown. It is not a certification of ProtocolSoup or of any other product.
Tests
- TestPlaintextRequestCannotAskForEncryptedResponse
./internal/protocols/oid4vci
Pass
Implementation
Explainer
What this requires
A Wallet asks for an encrypted Credential Response by putting a credential_response_encryption object, carrying its public key, in the Credential Request. Section 8.2 then requires the request itself to be encrypted: "Credential Request encryption MUST be used if the credential_response_encryption parameter is included, to prevent it being substituted by an attacker." Section 9.1 says the same of the Deferred Credential Request: "Deferred Credential Request encryption MUST but used if the credential_response_encryption parameter is included, to prevent it being substituted by an attacker." The "but" is the specification's own wording.
A request may be plaintext JSON or encrypted, but not plaintext and asking for an encrypted response at once.
Why it exists
The sentence gives the reason: the response key must not be "substituted by an attacker". In a plaintext request, anyone able to alter the body can replace the Wallet's key with their own. The Issuer would then encrypt the Credential to the attacker, and the encryption the Wallet asked for would protect the Credential for the wrong party. Encrypting the request to the Issuer's key keeps the response key out of reach.
What non-compliance looks like
An Issuer accepts Content-Type: application/json with a credential_response_encryption object and returns an application/jwt response encrypted to whatever key the body named. A Wallet sends its response key in a plaintext request because the Issuer advertises no credential_request_encryption key, instead of not asking for an encrypted response.
How ProtocolSoup tests it
decodeJSONOrEncryptedJWTRequest reports whether the body arrived as an encrypted application/jwt JWE. The Credential and Deferred Credential handlers refuse a plaintext body that carries credential_response_encryption with HTTP 400 invalid_encryption_parameters. The description names Sections 8.2 and 9.1. The hosted wallet encrypts the request whenever it asks for an encrypted response, and stops with an error when the Issuer advertises no request-encryption key.
TestPlaintextRequestCannotAskForEncryptedResponse sends a plaintext JSON request with credential_response_encryption to both the Credential Endpoint and the Deferred Credential Endpoint. It asserts HTTP 400, invalid_encryption_parameters, and the exact description for each. The encrypted path is covered by TestCredentialResponseEncryptionRoundTrip and TestCredentialResponseEncryptionRejectsUnsupportedEnc, which now send their requests encrypted.