All API communication in the context of PSD2 will be handled by using a combination of certificates. There are 2 distinct flows that 3rd party clients need to use in every transaction:
- Identification and Authentication
- This is achieved by establishing a mutual TLS connection, using a QTSP issued QWAC certificate
- Non-Repudiation and Message Integrity
- This is achieving by signing each request, according to the documentation, using a QTSP issued QSEAL certificate.
Note
- wherever TLS is mentioned, we explicitly refer to TLS 1.2 or higher.
Also note that though we refer to BEC PSD2 APIs, BEC is a technical provider for our member banks, not an ASPSP. So rather than providing our own APIs, we provide PSD2 APIs on behalf of all of the Included ASPSPs. All examples are always implicitly in context of a specific bank from this list. Security model is implemented with strict separation between banks.
Getting Started
Certificates
To get started using the BEC PSD2 API's you need to have to the correct certificates. The certificates are issued by QTSP, and a list of them can be found here https://webgate.ec.europa.eu/tl-browser/#/. You need to obtain a QWAC and QSEAL certificate. In the context of the Development Sandbox you should use your production certificates also (or contact support for other options*).
The root certificate of the QTSP needs to be known by BEC. We monitor the above list on a regular basis, so as a rule of thumb we have installed root certificates for all QTSPs on this list. If your QTSP is not on this list - or if it has only been recently added - please get in touch with us to verify that we have QTSP's root certificate installed on our end.
Same certificates can be used to get access to all banks under BEC umbrella, but separate enrollment/onboarding is required for each bank and there is no implicit or explicit sharing of authorizations or access control between banks.
*) PSD2 support can help if you want to use certificates issued as test-certificates. Please include a reference to the CA and the specific certificate in your request.
OR if you have not yet received you certificates BEC can issue temporary test-certificates valid in the Sandbox only.
Enrollment
Before you can use the BEC API's you need to perform enrollment, this is described in detail more detail in the Onboarding section and in the documentation for the PSD2 TPP Enrollment API.
Request Flow
This section will describe a request flow, as seen from a TPP. There are several security features to be considered in order to achieve the highest level of Confidentiality, Integrity and Assurance.
Mutual TLS Authentication
The first step in the request flow is to authenticate by way of Mutal TLS Connection using a QTSP Issued QWAC Certificate. Please be aware that the Root Certificates of your QTSP must be known by BEC.
cURL example request should produce 403 but not 401 |
---|
curl -E |
Message Signing
Introduction
TPP's are required to sign request messages, this is in order to ensure the integrity of the message. The signature must be included in the HTTP header as defined in the following sections. The electronic signature of the TPP has to be based on a qualified certificate for electronic seals (QSEAL) issued by a QTSP as referred to earlier in this document. The certificate of the TPP has to indicate all roles the TPP is authorised to use. It should be noted that at the time of the request a TPP will only be granted use of the roles indicated in the specific certificate used at the time of the transaction, regardless of if that corresponds with the full set of roles the TPP as actually approved to use.
For further information and detailed examples please refer to the NextGenPSD2 XS2A Framework Implementation Guide, section 12, Page 216
Request Headers
Attribute | Type | Condition | Description |
---|---|---|---|
X-Request-ID | UUID | Mandatory | The ID of the request, unique to the call as determined by the initiating party. |
Digest | String | Mandatory | Digest of the request body created using either SHA-256 or SHA-512. Also for request with an empty/no body. In base64 encoding prefixed with the selected hash algorithm and a equals sign e.g. "SHA-256=xyz...." |
Signature | String | Mandatory | As described below under Signature Header |
TPP-Signature-Certificate | String | Mandatory | The TPP certificate used for signing the request, in base64 encoding. |
TPP-Redirect-URI | String | Conditional | URI of where the transaction flow shall be redirected to if required. |
TPP-Nok-Redirect-URI | String | Conditional | URI of where the transaction flow shall be redirected to if an error is encountered if required. |
Signature Header
For all requests, a "Signature" header must be present. The structure of a "Signature" header is defined in the following table which lists the requirements on the "Signature" header.
Element | Type | Condition | Requirement |
---|---|---|---|
keyId | String | Mandatory | The serial number and issuer-name of the Certificate included in the "TPP-Signature-Certificate" header. Formated as "SN= |
algorithm | String | Mandatory | The algorithm must identify the same algorithm for the signature as presented in the certificate of this Request. Currently "rsa-sha256" (SHA-256 with RSA) and "rsa-sha512" (SHA-512 with RSA) are supported. |
headers | String | Mandatory | This is the list of headers that the signing string (see below) is based upon, this should include: Mandatory Attributes:
Conditional Attributes:
Please note that the headers must also actually be present in the request |
signature | String | Mandatory | The "signature" parameter is a base 64 encoded digital signature (using the QSeal privatekey), described as Base64(RSA-SHA256(signing string)) where the signing string is a newline (\n) separated list of key-values - constructed like this: In the exact same order as described in the "headers" attribute. Example (matching header attribute "digest x-request-id tpp-redirect-uri"). The SHA-256 with RSA signature of: digest: SHA-256=ZuYiOtZkVxhjWmwTO5lOpsPevUNMezvk6dfb6fVhebM= |
Example
Signature = 'keyId="SN=1213456789,CA=CN=PSD2 Test,OU=IT,O=BEC,C=DK",algorithm="rsa-sha256",headers="digest x-request-id tpp-redirect-uri",signature="38dlkjDLFJkdjf...."'
Signing example
Below request signs an empty body - hence the SHA 256 of the empty string - and the headers X-Request-ID "requestId" and TPP-Redirect-URI "http://test/test".
Then the signing string is |
---|
x-request-id: requestId digest: SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= tpp-redirect-uri: http%3A%2F%2Ftest%2Ftest |
Using this example private key |
---|
-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDE7cr3NcKowA9ta2s2A8PBP76onnPT9qcD02QdVybjtcNr3PLHbCPHwvO0LJ59uLW5MHmp17jH9drskrl115a5jWwLCeB0/040N5VygmuNLCHH0H3UQXWxP7exPXqcZQ5PIcpXhsLLAxNKpg9dG6AwGypWsYLjScFMXxaRHRFOBxIKPYqWSlSJJCCGoU/iBxY7HX2bEpZo1Kh87pxj44FagIT8htO91JC6fj7hV+iHW2vxikoh0y2jHj5akGraeKj5ORp763nRv/ONsxz8VyiHyNsVXitm5EQaj7v8sqOR+LmgcrfCLH+wkoPKNKUS449BnXcdZn+fvwcntOw5wRw1AgMBAAECggEAd4Ygd3TAxi1z76SP+MPGL2eiL7Okd5Uv/2lxTUGVUAYFK1V6YUGoYdlYkxW1yHawjUr3vPc6ptr42jefqv+D8vD8D6MaAcjnTVgjM9ImtxN/GUjY5lgot8EFm+TFo2DOk4bdycv4NMGUFu29S3S2ABys0NuCprMgSFs6Vi8/Tox5c6sPnwDxl0ETRdGKZXJg1G4Bi0RQlfGgPjyYQWDXlR7UZwbp2eu3El1SOyhd4uqLwLOlwgCeLAhyhlGB8gwkfYuU1UAREOmbJmQKV6luQlp5+g/7bEyNgtlfaZL77iJTpG1fKOQ/Vl/UaS6o5YIT0pnmjaAAKT54hSct+abgYQKBgQDkn8+iFJpoPHlXIHo/zYCKnn0b3qZflPXaZz8gHC1ZHoIWOQh9ZNxf0seVNINBOMtPrpvHhJ3Db6hhVvsIRuGUqiD3/UHvGNTIg8uF6QLpHuGXCR34BnW+oMXGQkKr4ttaAY1XBV4d43C94ptNWD/1q/CPG4F6NQq3LwdDpdEwTQKBgQDcgmZRhuCYAeqiOXnVUhe3vMmizQ90bHulbh2TEDU4k0ZOInjhZVKfI2xPyd2SyZhJPX9J74B4DaOhuMQnJN+GSlgZOMTuUvua3loRHVT4EcaxExryWmoRqNRaJcxU/0JUbIDDEdP14WW+aCRygfcBvrmpRF4EX2R2xPE3EcDPiQKBgFXfUPXoFzcfv9Ph9wkP/0AR15woPQWZxd6K+ULuUnou413FflLbF4tGeICqgMJ2uqbrRsfiH//QaMZnDVNGjGRyon+DOMi94u6N0lwx8U3us30vh3opswAvExosuS4mv41HF/efpIJFc4tfGkYq55s3Qdv+0Ns+IRA9MdVO6wvhAoGAbgHj97I5I7x5CLtxy3lr+a8GTODOX/+q48n+mRqR4oqenWZXNeMth9TNOTT1BEDsZ0V11jXUuo/bXVfnC7w6gy1drB+FJ3xgp09cUYN3m1aK8FYesF9o4Sx/3AVVXeYGekWzKx4ex2DOOGKOJE4wIz+6Mfa4jKfmX9Y6nIWP0jkCgYEA2IXyqYOCrScTjPNB9TygDSZe0/ZKjHNnkGJrmT5850bP+ADXY0JNVN6ROC0ROQ/ilkVjgZ6N8G/ojs+AK6RbkkLFAnV990frWA3CVMMTx0CIlwXckW/gzMMU6iNlSSblLE8uUTDG2oOd51isT12LVthfs84U4UR64G9En9Xnp6A= -----END PRIVATE KEY----- |
Using openssl produces below signature |
---|
> openssl dgst -sha256 -sign file_with_private.key file_with_signing_string.txt | base64 SS4Le+sNOhqeGN/pqgbPgF9DlzAA3rlz3Al71pZsEzjA71EDCTn/QPhSEYYDNN0X8/UuOpLsy2UE KNx9HvIJRrd39QnXwUv4YBWUSfPbFR/65FXGjkcesRJGBW9HiGBeEDecw5ZGSmvXRF5h22SR+hT7 FrRLMp/Uuq8tNU8RQnbz6CtpZRZX+Ae9fWcgazNtNZEEivfKX/uBOfQJ+g5NQ1LBdvmgEHDy3Ogr L+/wK4faFHIQI8tFo+7+RlQuXaFl10kz+9AE2H8twaEfCGhARxM8uTPSKwi94pwHGZwwtOSERBhw BOi9wIM2dtfA6zp3Ykf93m9B5nM4RgyiwhMr4g== |
Request (redacted) |
---|
X-Request-ID: requestId Digest: SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= Signature: keyId="SN=5e20 ...,CA=...",algorithm="rsa-sha256",headers="x-request-id digest tpp-redirect-uri",signature="SS4Le+sNOhqeGN/pqgbPgF9DlzAA3rlz3Al71pZsEzjA71EDCTn/QPhSEYYDNN0X8/UuOpLsy2UEKNx9HvIJRrd39QnXwUv4YBWUSfPbFR/65FXGjkcesRJGBW9HiGBeEDecw5ZGSmvXRF5h22SR+hT7FrRLMp/Uuq8tNU8RQnbz6CtpZRZX+Ae9fWcgazNtNZEEivfKX/uBOfQJ+g5NQ1LBdvmgEHDy3OgrL+/wK4faFHIQI8tFo+7+RlQuXaFl10kz+9AE2H8twaEfCGhARxM8uTPSKwi94pwHGZwwtOSERBhwBOi9wIM2dtfA6zp3Ykf93m9B5nM4RgyiwhMr4g==" TPP-Signature-Certificate: MIIEzTCCA7WgAwIBAgIUXiB4 ... DRjdbTI5YebVRci1/mFjbtmHl+SpV8gr91X9un TPP-Redirect-URI: http%3A%2F%2Ftest%2Ftest |