ob-p-ideal-security
The Ideal interface has a few additional security features regarding Digital Signatures on top of what is described in the Security page.
Digital Signatures, iDEAL specific
Signing requests for iDEAL by the Initiating Party
If signatures are enforced by the Initiating Party's Acquirer, the following headers will be mandatory in the API requests sent by the Initiating Party to the Open Banking Service:
- Signature
- Digest
The Signature header
The digital signing is done by applying the “Signature” scheme as described in https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12. This is equivalent to the “Authorization” scheme (see Signing the authorization request) and the same procedure is followed to generate the signature and header parts but it uses the Signature header instead of the Authorization header.
In order to generate the signature string that is signed with a key, the Initiating Party must use the values of following HTTP header fields:
- Digest
- X-Request-ID
- MessageCreateDateTime
The headers used to generate the signature string also have to appear in the `headers` parameter of the Signature header, in the fixed order appearing below:
headers=”digest x-request-id messagecreatedatetime (request-target)”
To include the HTTP request target in the signature calculation, use the special `(request-target)` header field name. You can generate the header field value by concatenating the lowercased :method, an ASCII space, and the :path.
The (request-target) header field value to be used for the different APIs is:
API | (request-target) header field value |
POST /payments | post /xs2a/routingservice/services/ob/pis/v3/payments |
GET /payments/{paymentId}/status | get /xs2a/routingservice/services/ob/pis/v3/payments/{{paymentId}}/status* |
GET /preferences/{Psuid} | get /xs2a/routingservice/services/ob/pis/v3/preferences/{{psuId}}* |
*The placeholders {{paymentId}} and {{psuId}} must be substituted with the values as obtained within the respective flows.
The signature string is created by concatenating the lowercased header field names followed with an ASCII colon `:`, an ASCII space ` `, and the header field value. Leading and trailing optional whitespace (OWS) in the header field value MUST be omitted. If the value is not the last value, then an ASCII newline `\n` is appended.
Example: For the payment request with the following required headers
POST /payments HTTP/1.1> Digest: SHA-256=B/O1sG0L8+bEAqWF3aMZn3I0rx5YVi8r5cM6JHlTW7Q= X-Request-ID: 1aad5e0f-02d7-aefb-61e3-6f4d3322cf71 MessageCreateDateTime: 2023-03-15T10:07:26.264Z
The concatenated "Signature String" would be:
Digest: SHA-256=B/O1sG0L8+bEAqWF3aMZn3I0rx5YVi8r5cM6JHlTW7Q= X-Request-ID: 1aad5e0f-02d7-aefb-61e3-6f4d3322cf71 MessageCreateDateTime: 2023-03-15T10:07:26.264Z (request-target): post /xs2a/routingservice/services/ob/pis/v3/payments
The resulting signature parameter of the Signature header would be:
signature="N7kFLMMi/2R5hCd1gdO+GYhS70DOLMl+n8hborf42nFuu0HFjreoqU70gvxFWzgTPaWjdmNYY/7sOAUAQWudsM61Vc536XmaOGrrSxOINlH9l9QBk31xZMlJBf/+1+GtPb1BR26PYBjxKDMbN9W7PEVZLCDoObSnVLkvKbkLRWl0U8a39mDkUBu70Jw8yWusDU0g1OVN+5YRfENPNtC2ZnVD80gxih4JoFV6f4WCcX4HXVl229veFNO5joNQyUc7qOkXUGN2g0omgN4iJxVGnzEJ9BCrNe+vK9T25LC0fwSp/W6A9dDfuHQzMZgDJZZKpaX0Gg34i68etmi5oLrM3A=="
The algorithm parameter of the Signature header is fixed:
algorithm=”SHA256withRSA”
The ‘keyId’ parameter of the Signature header is the thumbprint of the used certificate, viewed with the SHA1 algorithm. The private key associated with `keyId` is used to generate a digital signature on the concatenated signature string applying the SHA256withRSA algorithm. The complete SIgnature header looks then like this:
Signature: Signature keyId=”DCAC7209573D506FC56095B8B23E8555A8F38B29”, algorithm=”SHA256withRSA”, headers=”digest x-request-id messagecreatedatetime (request-target)”, signature="N7kFLMMi/2R5hCd1gdO+GYhS70DOLMl+n8hborf42nFuu0HFjreoqU70gvxFWzgTPaWjdmNYY/7sOAUAQWudsM61Vc536XmaOGrrSxOINlH9l9QBk31xZMlJBf/+1+GtPb1BR26PYBjxKDMbN9W7PEVZLCDoObSnVLkvKbkLRWl0U8a39mDkUBu70Jw8yWusDU0g1OVN+5YRfENPNtC2ZnVD80gxih4JoFV6f4WCcX4HXVl229veFNO5joNQyUc7qOkXUGN2g0omgN4iJxVGnzEJ9BCrNe+vK9T25LC0fwSp/W6A9dDfuHQzMZgDJZZKpaX0Gg34i68etmi5oLrM3A=="
The Initiating Party must upload the used public certificate in the Back-office so that Open Banking Service is able to validate the signature. If the signature could be validated and the sender has a valid iDEAL subscription a successful response is returned.
The Digest header
Calculate the Digest header as follows:
- Step1: Create a SHA-256 hash of the Payload
- Note-1: if the output is hex-encoded, please make sure to convert it to binary data (convert the hex-encoded string to a byte array)
- Note-2: payload formatting is important. If you generate the Digest by using an unformatted JSON payload, then please make sure that it matches with an unformatted request body used in the API request
- Step 2: Base64-encode the SHA-256 hash
- Step 3: Prepend 'SHA-256=' to the resulting base64-encoded value
Example: For the following payload:
{ "PaymentProduct": [ "IDEAL" ], "CommonPaymentData": "Amount": "Type": "Fixed", "Amount": "10.00", "Currency": "EUR" }, "RemittanceInformation": "Cookie", "RemittanceInformationStructured": "Reference": "iDEALpurchase21" } }, "IDEALPayments": "UseDebtorToken": false, "FlowType": "Standard" } }
Step 1: The SHA-256 hash of this request body is: "07f3b5b06d0bf3e6c402a585dda3199f7234af1e58562f2be5c33a2479535bb4" (Note: this is a hex-encoded representation)
Step 2: The base64-encoded hash (Note: hex to base64 encoding): "B/O1sG0L8+bEAqWF3aMZn3I0rx5YVi8r5cM6JHlTW7Q="
Step 3: The Digest header value: "SHA-256=B/O1sG0L8+bEAqWF3aMZn3I0rx5YVi8r5cM6JHlTW7Q="
Signing Requests to the Initiating Party (notification requests) and Responses sent to the Initiating Party
If signatures are enforced by the Initiating Party's Acquirer, the following headers will be present in the API requests and responses sent by the Open Banking Service to the Initiating Party:
- Digest
- Signature
The digital signing performed by the Open Banking Service is done by applying the same “Signature” scheme as described above.
A notification request or response from Open Banking Service to the Initiating Party may contain for example a header like:
Signature: keyId="2DOXXL7lNBNKJSMHKO2IBQC1", algorithm="SHA256withRSA", headers="digest x-request-id messagecreatedatetime (request-target)", signature="lulVhOhRwFs5G8+uGCh3BjJHBG540AyTCyaKhr9QE71YTtljxFt1b7i55C9QROw/zGt+iac3cBfGGRiTAfW4ta9Hn8+u7LvyfYHFcdxBhNj7T6dgrv+MLG6aI6hw/3Cwmkz/OwESBrQJzISWf8/0bgYNuXnuPf5r7BGMhHdhIr+RNxocW6wkSOEVQfOGYazy7YsoJhVEwNEt9gN++sw9HVfaxmwjl8MqxGNcLoVAgoGMcUOvNhjATA1MSzOj2cmw6kdi2yY2w7XiMuU9Tma0jQ3CGKhxIkD8Na2Vq1K2bs/n2DOxxL7lNbnKjsmhkO2ibQc1+RV3pXQJ1SDSI3EW/w=="
In order to ensure that the contents of the sent messages are correct and have not been altered during transmission or storage the Initiating Party can validate the received signature. For the validation of the signature, the Initiating Party can use the public certificate of the Open Banking Service which can be downloaded from the Back-office.