Signing Service — Relying Party Developer Guide
The signing service gives your customers a way to conveniently sign digital documents using qualified electronic signatures based on the identity data and credentials associated with their online banking accounts.
1. Overview
The following sequence diagram depicts the message flow for a remote signing process with a focus on the messages flowing from the RP to IDP or QTSP and back.
We will go through the details of these messages in the following!
You need to implement the following steps to create signatures with the identity service:
-
Document Preparation: First, you have to prepare the document(s) that the user is about to sign. Once the document is ready for signing, you need to show them to the user and calculate the hash(es) of the document(s).
-
OP (Bank) Selection: Then, just as in the identity flow and as explained in the base document, you send the user to the account chooser to select a bank. You will receive an issuer URL from that process. The issuer URL identifies the user’s bank.
-
Service Configuration Retrieval: You then contact the Service Configuration Service to obtain endpoint URLs for the involved QTSP (Qualified Trust Service Provider) that will generate the signature on the user’s behalf.
-
Authorization Process: Afterwards, you send the user to the previously selected bank to authorize the signature using OAuth 2.0. You do not pass the document(s) to the bank, but just the hash(es). When the user consents to sign the document(s), you will receive an access token from the bank.
-
Signature Creation: You then use this access token to create and retrieve the signatures at the QTSP’s API.
-
Document Finalization Phase: You finally add the received signature(s) to the documents and present them to the user.
Those steps are described in detail in the rest of this document.
1.1. Technologies Used
OAuth 2.0 (grant type authorization code) is the technical foundation of the protocol. It is combined with further OAuth extensions, such as PKCE and OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens, to achieve an appropriate protection level.
The API for creating electronic signatures is provided by a Qualified Trust Service Provider (QTSP). Those remote signatures are based on on-demand, short-term certificates created by the QTSP using data asserted by the IDP. This API is based on ETSI TS 119 432.
Most parameter names and JSON keys used in this flow use
snake_case notation (as usual in the
ecosystem). Some parameters, however, are taken from or
aligned with other specifications by external entities
and use other notations, such as camelCase .
|
1.2. QES, QESID, and QID
Besides signing just signing PDF or text files, you can use this service for other use cases as well:
-
QESID: You can ask the QTSP to embed user identity information into the short-lived certificate that is created to sign the document. Some user information like the user’s name is always included in the certificate, but using QESID you can request that a certain set of data is included on top. This is useful if you need to identify the user using the qualified electronic signature.
-
QID: Some regulated use cases require an electronic signature, but don’t require that a specific document is signed. With QID, you can request that a simple pre-defined text string, a default document is signed instead of a custom document. This is cheaper for you and often times easier to handle, since you don’t need to process a PDF file and signature.
Product |
Documents to sign |
ID claims in certificate |
Pricing |
Standard QES |
Custom PDF or text documents |
Base set by QTSP |
Standard |
QESID |
Custom PDF or text documents |
Base set + requested ID data |
Standard plus any additional claims |
QID |
Pre-defined default text documents |
Base set + requested ID data |
Reduced plus any additional claims |
As always, please refer to your contract for pricing information.
On a technical level, you can decide for each request if you want the user to sign a custom PDF or text document or a default document (QES/QESID vs. QID) and if you want to include additional user claims. You can also mix default documents with custom documents in the same flow.
The following table shows the additional user claims ("identity assurance claims") that are defined and the location where the data will end up in the X.509 signer certificate:
Claim name | X.509 container | X.509 attribute name | OID |
---|---|---|---|
|
SubjectDN |
|
2.5.4.4 |
|
SubjectDN |
|
2.5.4.42 |
|
SubjectDN |
|
2.5.4.6 2.5.4.17 2.5.4.9 |
|
Subject Directory Attributes |
|
1.3.6.1.5.5.7.9.1 |
|
Subject Directory Attributes |
|
1.3.6.1.5.5.7.9.2 |
|
Subject Directory Attributes |
|
1.3.6.1.5.5.7.9.4 |
2. Document Preparation
2.1. Custom Documents
In case of a QES or QESID, you present the user one or more documents (e.g., a contract proposal PDF document) and ask whether the user accepts and wants to sign the document(s) electronically.
You are contractually bound to show all custom document(s) the user is about to sign in their original form to the user and to use only these documents in the following. |
2.2. Default Documents
In case of QID, you take one of the default documents for the selected QTSP from the service configuration, described below. This default document must not be modified and must be handled like a text document in the following. The AS will show the text of the document to the user and ask the user if they want to sign this text.
Default documents are available in various languages. You can select the language when selecting the default document from the service configuration, as explained later.
2.3. Hashing Documents
You need to calculate the hash(es) of the PDF or text document(s). To this end, you take the raw bytes of the document, hash them using one of the hash algorithms listed in the following, and encode the hash bytes in Base64, as defined in RFC4648, Section 4.
Any changes to the document need to be made before the hashing. In particular, embedding the signature into a PDF may require that the structure of the document is prepared beforehand to define a placeholder for the signature. |
The hash algorithm SHA-256 is supported by all QTSPs, the use of other hash algorithms depends on the QTSP. The following algorithms are defined (based on ETSI TS 119 432):
Hash algorithm OID |
Hash algorithm name |
2.16.840.1.101.3.4.2.1 |
SHA-256 |
2.16.840.1.101.3.4.2.2 |
SHA-384 |
2.16.840.1.101.3.4.2.3 |
SHA-512 |
2.16.840.1.101.3.4.2.8 |
SHA3-256 |
2.16.840.1.101.3.4.2.9 |
SHA3-384 |
2.16.840.1.101.3.4.2.10 |
SHA3-512 |
For a text document, the following python code produces the hash:
from base64 import b64encode
from hashlib import sha256
document = "Hiermit bestätige ich, dass ich die angegebenen Daten sorgfältig geprüft habe und diese auf meine Person zutreffen."
document_bytes = document.encode("utf-8")
hash = b64encode(sha256(document_bytes).digest()).decode("ascii")
This example outputs
hhZiIQste6V0dvTsil1RMY07EIMgPEHFLQE2GvebWf4=
.
Instead of document_bytes
, the raw bytes
from a prepared PDF file can be used as well.
The raw bytes produced by the hashes must not be Hex encoded, but Base64 encoded! If your hash library outputs Hex encoded strings, you must request 'raw' output or decode the hex representation to bytes first and then re-encode using Base64. |
This online tool can demonstrate the calculation of hashes suitable for the signing service. Obviously, this should not be used in production. |
For the same text as above, compare the following outputs:
1. valid: MJPleish2cowx7NHhBpzniGG/SlYb61qXhpTTZWiDr70Gyifuu7708aqmITBrnYlAPsAdMGyAjuA8ZYNhvN8sw== (1) 2. wrong: 3093e57a2b21d9ca30c7b347841a739e2186fd29586fad6a5e1a534d95a20ebef41b289fbaeefbd3c6aa9884c1ae762500fb0074c1b2023b80f1960d86f37cb3 (2) 3. wrong: MJPleish2cowx7NHhBpzniGG_SlYb61qXhpTTZWiDr70Gyifuu7708aqmITBrnYlAPsAdMGyAjuA8ZYNhvN8sw (3) 4. wrong: MzA5M2U1N2EyYjIxZDljYTMwYzdiMzQ3ODQxYTczOWUyMTg2ZmQyOTU4NmZhZDZhNWUxYTUzNGQ5NWEyMGViZWY0MWIyODlmYmFlZWZiZDNjNmFhOTg4NGMxYWU3NjI1MDBmYjAwNzRjMWIyMDIzYjgwZjE5NjBkODZmMzdjYjM= (4)
1 | This is a valid hash using SHA-512. |
2 | This is not properly encoded (it is hex encoded). |
3 | This is not properly encoded (it uses Base64 URL-safe). |
4 | This is not properly encoded (the hex string was encoded, not the raw bytes). Note that it is much longer than the correct hash above, and it uses just a limited set of characters. Decoding this hash shows the original hex string, not the bytes of the hash. |
You need to store the documents, the hashes, and the hash algorithm OIDs for later use, securely bound to the user’s browser session.
At this point, you must show a button to the user (as explained in the base document) to start the signature process.
2.4. OP (Bank) Selection
The next step, just as in other flows, is to send the user through the OP (Bank) selection at the account chooser. Please refer to the base document for details.
2.5. Service Configuration Retrieval
As a result from the previous step, you will be provided with the Issuer URL of the chosen Bank. You now need to obtain the service configuration from the Service Configuration service.
This part MUST take place in the backend, not in the user’s browser. |
To do that, send an HTTP GET request from your backend to
the service configuration service URL, attaching the issuer
URL in the iss
parameter.
For the sandbox, the URL is as follows (here shown with an
example issuer):
https://api.sandbox.openbanking.verimi.cloud/service-configuration/v1/?iss=https://testidp.sandbox.openbanking.verimi.cloud/issuer/10000001
For production, the URL is the following:
https://api.openbanking.verimi.de/service-configuration/v1/?iss={issuer_url}
As with all URL parameters, make sure to properly
URL-encode the iss parameter.
|
GET /service-configuration/v1/?iss=https://
testidp.sandbox.openbanking.verimi.cloud/issuer/10000001 HTTP/2
Host: api.sandbox.openbanking.verimi.cloud
Accept: */*
The API returns an HTTP status code and the service configuration document.
-
If the issuer is found and active, the returned status code is
200
(found). -
If the issuer is not a valid URI, the returned status code is
400
(bad request). -
If the issuer is not found, the returned status code is
404
(not found). -
If the issuer is found but not active, the returned status code is
423
(locked).
If an error is indicated, a JSON document explaining the
error is contained in the response body, e.g.:
{"error":"invalid_request","error_description":"The
issuer 'https://accounts.inactivetestbank.de' is not
active"}
When a service configuration document is returned, it is of the following form:
{
"identity": {
"iss": "https://testidp.sandbox.openbanking.verimi.cloud/issuer/10000001" (1)
},
"remote_signature_creation": [ (2)
{
"qtsp_id": "sp:sandbox.yes.com:811b0c29-4556-05e9-ad2f-17248ad946d9", (3)
"signDoc": "https://example.com/signDoc", (4)
"conformance_levels_supported": [ (5)
"AdES-B-B",
"AdES-B-T"
],
"identity_assurance_claims_supported": [ (6)
"place_of_birth",
"birthdate",
"address",
"nationalities",
"given_name",
"family_name"
],
"default_signing_documents": [ (7)
{
"lang": "de",
"text": "Hiermit bestätige ich, dass ich die angegebenen Daten sorgfältig geprüft habe und diese auf meine Person zutreffen."
},
{
"lang": "en",
"text": "I hereby confirm that I have carefully checked the data provided and that they apply to my person."
}
]
},
{
"qtsp_id": "sp:sandbox.yes.com:f38d2a84-48e8-26bf-bc6d-378a090b09ca",
"signDoc": "https://other.example/signDoc",
"conformance_levels_supported": [
"AdES-B-B",
"AdES-B-T"
],
"identity_assurance_claims_supported": [
"birthdate",
"nationalities",
"given_name",
"family_name"
],
"default_signing_documents": [
{
"lang": "de",
"text": "Hiermit bestätige ich, dass ich die angegebenen Daten sorgfältig geprüft habe und diese auf meine Person zutreffen."
},
{
"lang": "it",
"text": "Confermo di aver controllato attentamente i dati forniti e che si riferiscono alla mia persona."
}
]
}
],
(...)
}
1 | This element indicates the OAuth issuer URL that is to be used in the following. Note that this can be different from the issuer URL used so far. |
2 |
The section designated
remote_signature_creation contains the
one or more sets of configuration information for
different QTSPs that can be used with this issuer
(bank). It is up to you to select one of the QTSPs.
|
3 |
The qtsp_id is a unique identifier for
the QTSP.
|
4 |
signDoc is the endpoint where you will
be able to retrieve the signature from.
|
5 |
conformance_levels_supported indicates
the signature conformance levels supported by the
specific QTSP (see
ETSI EN 319 142).
|
6 |
identity_assurance_claims_supported
indicates the identity assurance claims supported by
the QTSP (cf. QESID and QID described above)
|
7 |
default_signing_documents is a list of
default signing documents in different languages
defined by the QTSP. If you want to use QID, you
need to select one of these documents.
|
You need to select one of the QTSPs, store its
configuration, and store the OAuth issuer URL obtained from
the identity
element.
If the section remote_signature_creation is
missing or empty, this bank does not support the signing
service. You must test for this and guide the user to
select a different bank or signing method.
|
3. Authorization Process
3.1. Retrieving the OAuth Configuration (Authorization Server Metadata)
First, you (or your OAuth library) need to retrieve the OAuth Configuration, or Authorization Server Metadata document. This document will tell you about the endpoints that you need to use in the following.
The URL of this document is created as follows:
{oauth_issuer_url}/.well-known/oauth-authorization-server
Recall that from here on, only the issuer URL retrieved in the last step is used, not the one returned from the authorization endpoint. |
The OAuth Configuration document contains, among others, the following keys:
{
"issuer": "https://testidp.sandbox.openbanking.verimi.cloud/issuer/10000003",
"pushed_authorization_request_endpoint": "https://testidp.sandbox.openbanking.verimi.cloud/issuer/10000003/par",
"authorization_endpoint": "https://testidp.sandbox.openbanking.verimi.cloud/services/authz/10000003",
"token_endpoint": "https://testidp.sandbox.openbanking.verimi.cloud/issuer/10000003/token",
...
}
You need to check that the issuer in the configuration document matches the issuer URI which you received from the service configuration! |
The pushed authorization request endpoint, authorization endpoint, and token endpoint URLs are used in the following.
3.2. Pushed Authorization Request
The authorization request is sent as a Pushed Authorization Requests to the authorization server. That means that most of the parameters usually sent in the OAuth authorization request are sent in an MTLS-protected POST request to the backend of the authorization server instead.
This ensures that the data contained in the authorization request remains confidential and cannot be altered by the user or an attacker.
The parameters in the pushed authorization request are shown in the following:
Note that you MUST use your TLS certificate to authenticate at the authorization server for this request.
POST /par HTTP/1.1
Host: as.example-bank.com
Content-Type: application/x-www-form-urlencoded
response_type=code (1)
&client_id=s6BhdRkqt3 (2)
&state=af0ifjsldkj (3)
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM (4)
&code_challenge_method=S256 (5)
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb (6)
&purpose=Kaufvertrag (7)
&authorization_details=%5B%7B%22type%22:%22sign%22,%22locations (8)
%22:%5B%22sp:yes.com:6a256bca-1e0b-4b0c-84fe-c9f78e0cb4a3
%22%5D,%22credentialID%22:%22qes_eidas%22,%22hashAlgorith
mOID%22:%222.16.840.1.101.3.4.2.1%22%22documentDigests%22
:%5B%7B%22hash%22:%22sTOgwOm+474gFj0q0x1iSNspKqbcse4Ieiql
Dg/HWuI=%22,%22label%22:%22Kreditvertrag%22%7D,%7B%22hash
%22:%22HZQzZmMAIWekfGH0/ZKW1nsdt0xg3H6bZYztgsMTLw0=%22,%2
2label%22:%22VertragRestschuldversicherung%22%7D,%7B%22ha
sh%22:%22hhZiIQste6V0dvTsil1RMY07EIMgPEHFLQE2GvebWf4=%22,
%22label%22:%22%22%7D%5D%7D%5D
1 |
response_type MUST be
code .
|
2 | client_id is your client ID. |
3 |
state is an optional value to carry
session state. Note that because PKCE or nonce are
used, state is not needed for
protection against Cross-Site Reqest Frogery and is
therefore optional.
|
4 |
code_challenge is the PKCE code
challenge. Note the rules in
PKCE, Section 4.1. You may additionally use the
nonce parameter if this flow is used
together with OpenID Connect.
|
5 |
code_challenge_method must be
S256
|
6 |
redirect_uri MUST be one of your
pre-registered redirect URIs.
|
7 |
purpose is an optional parameter to
inform the user about the purpose of the
transaction.
|
8 |
authorization_details : see below.
|
3.2.1. Authorization Details
The authorization_details
parameter is an
array of objects as described in
Rich Authorization Requests. Each object has a type
. The array MUST NOT
contain more than one object of type sign
,
but may contain other objects, e.g., to combine the
signature with a payment, see
Advanced Use Cases - Combined Flows.
authorization_details
[
{
"type": "sign", (1)
"locations": [ (2)
"sp:yes.com:6a256bca-1e0b-4b0c-84fe-c9f78e0cb4a3"
],
"credentialID": "qes_eidas", (3)
"hashAlgorithmOID": "2.16.840.1.101.3.4.2.1", (4)
"documentDigests": [ (5)
{
"hash": "sTOgwOm+474gFj0q0x1iSNspKqbcse4IeiqlDg/HWuI=",
"label": "Kreditvertrag"
},
{
"hash": "HZQzZmMAIWekfGH0/ZKW1nsdt0xg3H6bZYztgsMTLw0=",
"label": "Vertrag Restschuldversicherung"
},
{
"hash": "hhZiIQste6V0dvTsil1RMY07EIMgPEHFLQE2GvebWf4=",
"label": "" (6)
}
],
"identity_assurance_claims": { (7)
"given_name": null,
"family_name": null,
"birthdate": null,
"place_of_birth": {
"essential": true
},
"nationalities": null,
"address": null
}
}
]
1 |
type is always sign .
|
2 |
locations is an array with exactly
one element: the qtsp_id selected
previously.
|
3 |
credentialID determined the signature
to be created; currently only
qes_eidas is available.
|
4 |
hashAlgorithmOID is the OID for the
hash algorithm that you used to hash the
documents, as shown above.
|
5 |
documentDigests is an array
containing an object for each document to be
signed. Each document object must contain the
document hash and a user-friendly,
descriptive label . The authorization
server will show the label to the user.
|
6 |
For default documents (cf. QID), the
label MUST remain empty!
|
7 |
Optional: For QESID and QID, you may list identity
assurance claims here. null means
that the element is requested on a best-effort
basis (default). Marking a claims as
{"essential":true} means that the
transaction should be aborted when data for the
claim is not available.
|
3.2.2. Authorization Server Response
The authorization server will respond with a JSON object
containing a request_uri
parameter
representing the newly created pushed authorization
request information:
request_uri
HTTP/1.1 201 Created
Cache-Control: no-cache, no-store
Content-Type: application/json
{
"request_uri": "urn:example:bwc4JK-ESC0w8acc191e-Y1LTC2",
"expires_in": 90
}
The request_uri
serves as an identifier that
will be used in the next step, the authorization request.
3.2.3. Error Response
In case of an error the response will be structured as described in Pushed Authorization Requests and shown in the following example:
HTTP/1.x 400 Bad Request
Content-Type: application/json
{
"error": "invalid_request",
"error_description": "the field credentialID must not be empty"
}
Possible errors:
HTTP status code |
error |
error_description (examples) |
400 |
|
|
400 |
|
|
400 |
|
|
400 |
|
|
415 |
|
|
422 |
|
|
3.3. Authorization Request
In the next step, you need to redirect the user’s
browser to the authorization endpoint of the bank, passing
the request_uri
and
client_id
parameters.
Usually, the redirection is done via a Location header and an HTTP status code 302:
HTTP/1.1 302 Found
Location: https://testidp.sandbox.openbanking.verimi.cloud/services/authz/10000003?
request_uri=urn%3Aexample%3Abwc4JK-ESC0w8acc191e-Y1LTC2&
client_id=sandbox.yes.com:6a256bca-1e0b-4b0c-84fe-c9f78e0cb4a3`
As always, remember to encode URI parameters properly.
Also, the authorization endpoint URL retrieved from the
OAuth configuration may already contain parameters that
must not be removed. Please make sure that your code or
the library used supports parameters in endpoint URIs so
that you don’t run into problems because of
parameters being cut off or a duplicate
? being used resulting in an invalid URI.
|
Screen control is with the OP now which will guide your user through login and consent. The OP requires information about your app in the course of this flow. You therefore have to provide a privacy policy and may provide an optional terms of service document and label upon registration.
3.4. Authentication Response
After successful authentication, authorization, and consent,
the OP will redirect (HTTP status code 302) your user to the
{redirect_uri}
given in the Authentication
Request including the following request parameters:
-
state
: if you provided astate
value in the pushed authorization request, you MUST check that this value is equal to thestate
parameter passed to the OP. -
code
: the authorization code you need to get the access token -
iss
: the issuer URL of the OP that created this response. You app MUST check that this value is equal to the issuer URL used in the previous steps. This is a countermeasure against mix-up attacks.
The state value must now be invalidated;
i.e., double usage of the same state value
MUST result in an error.
|
The check and the token endpoint request MUST be implemented in the backend logic of the application as this does not expose the results to client side attacks and allows to use MTLS to authenticate the client. |
GET /yes/oidccb?code=rDx7qadXAgCrkTGxF7WjrA.gs8gNEgMhH6Ww-VBZbz04w&
iss=https://testidp.sandbox.openbanking.verimi.cloud/issuer/10000001&state=V1F
4gV3fDx6y110UzQJpk HTTP/1.1
Host: rpbackend.acme.com
3.5. Authentication Error Response
Errors according to
OAuth 2.0 Authorization Error Response
and
OAuth 2.0 Error Response
may occur and must be handled. In case of an error the
parameter error
will deliver an error code with
optional details in the parameter
error_description
.
There is a identity service specific error code
account_selection_requested which is
returned by the OP if the user clicks 'Select another
bank' during the online banking login and shall cause a
forced bank selection in the account chooser. You MUST
handle this error as described
here.
|
The error
unable_to_meet_service_requirements
is sent in
case the user’s data is not sufficient to create the
signature.
3.6. Token Request
If your app received a successful authentication response,
your backend at {redirect_uri}
needs to
exchange the authorization code for an access token at the
token_endpoint
. The token request is a POST
request with content type
application/x-www-form-urlencoded
and the
following parameters:
-
grant_type
: must be set toauthorization_code
. -
code
: authorization code returned in the authorization response. -
client_id
: yourclient_id
. -
redirect_uri
: sameredirect_uri
as used in the authorization request. This is a security countermeasure against client impersonation. -
code_verifier
: the PKCE code verifier.
Your RP backend has to perform client authentication with the OP via mutual TLS (aka. TLS client authentication): Your RP has to be configured so that it uses the self-signed certificate with which you registered your RP for the TLS handshake with the OP. |
POST testidp.sandbox.openbanking.verimi.cloud/issuer/10000001/token
Accept: application/json
Accept-encoding: gzip, deflate
Content-type: application/x-www-form-urlencoded
Content-length: 261
Host: testidp.sandbox.openbanking.verimi.cloud
grant_type=authorization_code&code=rDx7qadXAgCrkTGxF7WjrA.gs8gNEgMhH6W
w-VBZbz04w&redirect_uri=http%3A%2F%2Frpbackend.acme.com%2Fyes%2Foidccb
&client_id=sandbox.yes.com%3Ae85ff3bc-96f8-4ae7-b6b1-894d8dde9ebe&code
_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
3.7. Token Response
The IDP will respond with a JSON object, i.e., the response
will contain the header
Content-Type: application/json;charset=UTF-8
.
The JSON object has the following attributes (and may have others)
-
access_token
: the access token -
token_type
: always set tobearer
-
expires_in
: seconds until expiration (optional) -
authorization_details
: the authorization details object(s) as in the authorization request
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
{
"access_token":"eyJraWQiOiJDWHVwIiwiYWxnI...",
"token_type":"bearer",
"expires_in":3600,
"authorization_details": [ ... ]
}
3.8. Token Error Response
Errors according to
OAuth 2.0 Error Response, or
OIDC 1.0 Token Error Response
may occur and must be handled. In case of an error the
returned JSON object will normally contain an
error
attribute.
4. Creating the Signature
After obtaining the access token, you can request the actual signature from the QTSP. Before this request, you should ask the user one final time for a confirmation of the signature, as this is the "point of no return" for the user.
4.1. Signature Request
The signature request is authenticated using mutual TLS and is a POST request containing a JSON body. The contents of the request follow the definition given in ETSI TS 119 432, as can be seen in the following annotated example:
POST 5634/csc/v1/signatures/signDoc
Content-Type: application/json
Host: qtsp.com
{
"SAD":"eyJraWQiOiJDWHVwIiwiYWxnI...", (1)
"credentialID":"qes_eidas", (2)
"documentDigests":{ (3)
"hashes":[
"sTOgwOm+474gFj0q0x1iSNspKqbcse4IeiqlDg/HWuI=",
"HZQzZmMAIWekfGH0/ZKW1nsdt0xg3H6bZYztgsMTLw0="
],
"hashAlgorithmOID":"2.16.840.1.101.3.4.2.1"
},
"profile":"http://uri.etsi.org/19432/v1.1.1#/creationprofile#", (4)
"signature_format":"P", (5)
"conformance_level":"AdES-B-T" (6)
}
1 |
SAD : The request authorization data.
Here: the access token obtained in the previous
steps.
|
2 |
credentialID : Denotes the kind of
signature the RP wants the QTSP to create. MUST be
qes_eidas (only supported value
currently). MUST match the
credentialID value as specified in the
corresponding consent resource.
|
3 |
documentDigests is an object
encapsulating an array of Base64-encoded hash values
(hashes ) and the OID of the hash
algorithm (hashAlgorithmOID ) used to
generate the respective hash values, as above. The
hashes array contains one hash value
per document to be signed and MUST NOT be empty.
This MUST be a subset of the hashes in the consent
resource.
|
4 |
profile : String that identifies the
protocol being used by the client to communicate to
the signature creation endpoint. The value MUST be
http://uri.etsi.org/19432/v1.1.1#/creationprofile# .
|
5 | signature_format : See below. |
6 |
conformance_level : See below, optional.
|
Additionally, the optional key signAlgo
may
be used to specify the OID of the signing algorithm to
use. Some algorithms require additional parameters,
which can be specified in the key
signAlgoParams
.
Creating the signature can take same time. ⌛ Please ensure that your HTTP library waits at least 60 seconds until a timeout is triggered. Some HTTP libraries have a default of 15 seconds. A loading/waiting indicator should be shown to the user in the meantime. |
4.1.1. Signature Format and Conformance Level
The signature formats and corresponding conformance levels relate to ETSI EN 319 122 and ETSI EN 319 142.
signature_format
determines the required
signature format, possible values are:
-
C
shall be used to request the creation of a CAdES signature; -
P
shall be used to request the creation of a PAdES signature.
conformance_level
determines the required
baseline level format:
-
AdES-B-B
shall be used to request the creation of a baseline level B signature; -
AdES-B-T
shall be used to request the creation of a baseline level T signature; -
AdES-B-LT
shall be used to request the creation of a baseline level LT signature.
The parameter conformance_level
is optional.
The values supported by the QTSP are returned in the
service configuration (see above) in the section
conformance_levels_supported
. The default
baseline level according to
ETSI EN 319 142
is AdES-B-B
in case it is omitted.
If a timestamp is needed, its request and inclusion is
managed by the signature creation service according to its
configuration and policies. Since the identity service
utilizes on-demand, short-lived certificates for signature
creation, you should request signature creation using a
conformance level that includes a timestamp into the
signature, e.g.,
AdES-B-T
. This ensures successful signature
validation even after certificate expiration.
4.2. Signature Response
If an error occurs while processing the request, the QTSP returns an HTTP status code 400 along with error information as specified in ETSI TS 119 432, Section 7.24.2.
Otherwise, the QTSP returns a document as follows:
HTTP/1.1 200 OK +
{
"SignatureObject":[ (1)
"KedJuTob5gtvYx9qM3k3gm7kbLBwV…bEQRl26S2tmXjqNND7MRGtoew==",
"AedJuTob5gtvYx9qM3k3gm7kbLBwV…bEQRl26S2tmXjqNND7MRGtoes=="
],
"revocationInfo":{ (2)
"ocsp":[
"MIIJg...jSc="
],
"crl":[
"MIIC4...X7M="
]
}
}
1 |
SignatureObject is an array containing
Base64-encoded signature elements detached from the
documents (see below). If multiple hash values are
signed in a single request, the order of the
elements in the SignatureObject array follows the
order of the entries in the documentDigests
parameter of the request.
|
2 |
revocationInfo is a JSON Object
containing revocation data that MUST be included in
the signing response in case of signature_format
P and conformance_level
AdES-B-LT (see below).
|
4.2.1. Signature Elements
The structure of every signature element is built in accordance with RFC 5652.
In case the request parameter
signature_format
was set to C
,
every object conforms to
ETSI EN 319 122.
In case signature_format
was P
,
every object conforms to
ETSI EN 319 142. The result can be embedded in a PDF signature object
according to
ETSI EN 319 142.