BCSS - enterprice signing (eSeal)

Abstract

The validation service enables the user to validate existing signatures. It also returns all relevant revocation- and certificate chain information. This information may be stored together with the signature and enables the signature to be validated at a later time, even if the CA is out of service and revocation information is no longer available online. The validation service supports signatures created by certificates issued by most major Certificate Authorities.

The remote enterprice and person signing services signs hash values supplied through the signing API, provided a valid token authorizing access to the centrally stored private signing key is also supplied. 

The signing algorithms supported by the services is RSA.

 

 

Authentication - access to Signing Service

To gain access to the remote signing services you need to be authenticated. Authentication is performed by sending a signed JWT to the Buypass enterprise OIDC server. The JWT must be signed with a merchant certificate.

The response from the OIDC server is a json with an access_token. This token should be provided with each request to the remote signing service as a header property with the key 'Authorization' and value 'Bearer TOKEN'. The access_token expires after a relatively short period. To be able to continue to send requests to the remote signing service, a new token must then be acquired.

Scopes

There are three available scopes

  1. The service scope, this scope gives access to the api

  2. The credential scope, this scope gives access to the signing service

  3. The validation scope, this scope gives access to the validation services - see https://buypassdev.atlassian.net/wiki/spaces/DEVSPACE/pages/2999877657

All requests to the remote signing api should contain a token with at least the service scope. If the signing- or validation services are requested, the token needs either the credential or the validation scope in addition. Clients who use both signing and validation services may requests all three scopes for their token and use it for all services.

Servers

  • For the test environment, the oidc services are accessible at https://auth.tsp.test4.buypass.no/auth/realms/enterpriseid

  • For production, the oidc services are accessible at https://auth.tsp.buypass.no/auth/realms/enterpriseid

Example code

$ curl -X POST https://auth.tsp.test4.buypass.no/auth/realms/enterpriseid/protocol/openid-connect/token
-H "Content-Type application/x-www-form-urlencoded"
-d "grant_type=client_credentials\
&scope=service%20credential%20validation\
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer\
&client_assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiJiNWE3YjYwZi00ODM4LTQxOTktODg5Zi1kYTA5ZjBlZDE2YWUiLCJpYXQiOjE2MDMyMDIzMzksInN1YiI6InJlbW90ZS1zaWduYXR1cmUtY2xpZW50LTc3ODg5OSIsImlzcyI6InJlbW90ZS1zaWduYXR1cmUtY2xpZW50LTc3ODg5OSIsIm5iZiI6MTYwMzIwMjMzOSwiZXhwIjoxNjAzMjA1OTM5LCJhdWQiOiJodHRwczovL2F1dGgudHNwLnRlc3Q0LmJ1eXBhc3Mubm8vYXV0aC9yZWFsbXMvZW50ZXJwcmlzZWlkIn0.g7zG9EZzMg07yw3auKY5eAtXOs_atIYN6-XstoOctfgibFVTompYHdX20H6TaTYc2HBMC8sYkO0qNpd4H9sCKf2MrmMCZ4nZRvcOlMrl3UpEv01-GkwxnR8hkA11ciQtKNHZ5qtClzaaswTWKZ7RN2Xr41p3kXeD4g40KTwdFAgzBwcgZoXN23hjeOkpxhll2mI8zSLBf-COMzuq0DnLXYIkzyvcqDcs8xu4Wo7wzyF5rZHCZ4i7cu1_Ju17Ijn-kmrMyXimQ15rr-GyqmwwJmvuCZ6eogUtBIcx1IlDfkq9o0ykoEALp-hPna5aUb96jSn0RCUnI_v4FZ_-GA0Y0g"

The client requesting authentication needs to set the correct scopes after &scope=. The scopes should be space separated and URL-encoded.

The client also need to construct a valid client_assertion, which is a base 64 encoded signed jwt. There are numerous libraries that are capable to do this. Here are some details regarding the assertion

Assertion header

{
  "typ": "JWT",
  "alg": "RS256"
}

These values are currently fixed.

Assertion payload

{
  "jti": "d90854d1-7df9-4541-b0df-bdca97209065",    // A unique requestid
  "iat": 1574940763,                                // Issued at 'seconds since epoch'. The client should provide 'now'
  "sub": "remote-signature-client-778899",          // The id of the client
  "iss": "remote-signature-client-778899",          // The id of the client
  "nbf": 1574940763,                                // Not valid before 'seconds since epoch'. The client should provide 'now'
  "exp": 1574944363,                                // Expiry date of the refresh token - not that relevant in this flow. Can be set til 'now' + 1 hour
  "aud": "https://auth.tsp.test4.buypass.no/auth/realms/enterpriseid"   // URL of the OIDC server
}

Java example

In java the client assertion can be created with the following code:

private String createSignedJWT()
    KeyStore keystore = ...
    keystore.load(...);
    PrivateKey key = (PrivateKey)keystore.getKey(...);
 
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key.getEncoded());
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PrivateKey privKey = kf.generatePrivate(keySpec);
 
    JwtBuilder builder = Jwts.builder()
        .setHeaderParam("typ", "JWT")
        .setId(createUniqueId())
        .setIssuedAt(now())
        .setSubject("remote-signature-client-778899")
        .setIssuer("remote-signature-client-778899")
        .setNotBefore(now())
        .setExpiration(nowPlusOneHour())
        .setAudience("https://auth.tsp.buypass.no/auth/realms/enterpriseid")
        .signWith(RS256, privKey);
 
    return builder.compact();
}

 

 


 

Signing

The signing service currently implements only a mandatory subset of the endpoints specified in the CSC specification.

Authorization

Use of the centrally stored private signing key to create a signature must be authorized by presenting a SAD ( Signature Activation Data) to the signing API.

The SAD must be obtained from the OIDC server using the following URL:

  • Test environment : https://auth.tsp.test4.buypass.no/auth/realms/enterpriseid/protocol/openid-connect/token?_tlsclientauth=1

  • Production environment :  https://auth.tsp.buypass.no/auth/realms/enterpriseid/protocol/openid-connect/token?_tlsclientauth=1

Example:

$ curl -X POST https://auth.tsp.test4.buypass.no/auth/realms/enterpriseid/protocol/openid-connect/token?_tlsclientauth=1

  • H "Content-Type application/x-www-form-urlencoded"

  • d "grant_type=client_credentials&client_id=SAD

$ curl -X POST https://auth.tsp.test4.buypass.no/auth/realms/enterpriseid/protocol/openid-connect/token?_tlsclientauth=1

  • H "Content-Type application/x-www-form-urlencoded"

  • d "grant_type=client_credentials&client_id=SAD

The TLS connection in this case requires client authentication, which must be set up using the PKCS#12 keystore received when ordering the Enterprise Certificate for signing.

Provided the TLS connection is successful, the HTTP response from the OIDC server returns contains a JSON body like this:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5c...",
"expires_in": 60,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR.....",
"token_type": "bearer",
"not-before-policy": 0,
"session_state": "69ab03e6-9ce4-4085-9e84-80310d55de1a",
"scope": ""
}

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5c...",
"expires_in": 60,
"refresh_expires_in": 1800,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR.....",
"token_type": "bearer",
"not-before-policy": 0,
"session_state": "69ab03e6-9ce4-4085-9e84-80310d55de1a",
"scope": ""
}

The value of the access_token attribute (a signed JWT) is the SAD.

Endpoints

Request

The signing request has the format:

{
"SAD": "eyJhbGciOiJSUzI1NiIsInR5cCIg.....",
"credentialID": "123456",
"hash": [
"n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="
],
"signAlgo": "RSA",
"signAlgoParams" : "string",
"hashAlgo": "SHA-256",
"clientData" : "string"

}

{
"SAD": "eyJhbGciOiJSUzI1NiIsInR5cCIg.....",
"credentialID": "123456",
"hash": [
"n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="
],
"signAlgo": "RSA",
"signAlgoParams" : "string",
"hashAlgo": "SHA-256",
"clientData" : "string"

}

The attributes have the following meaning:

  • SAD : The access token authorizing the use of the signing key - described above

  • credentialID : Identifier of the signing key to be used. This attribute is currently not in use, as the credential ID is included in the SAD.

  • hash : An array of Base64-encoded hash values to be signed. These should be raw document hashes, as the signing service wraps each hash in a DigestInfo structure before signing.

  • signAlgo : The signing algorithm. Currently only RSA is supported. The algorithm name is case-insensitive, and may alternatively be given as an Object Identifier.

  • signAlgoParams : Not used.

  • hashAlgo : The hash algorithm. May be given by name (e.g. "SHA-256") or Object Identifier.

  • clientData : Not used.

Note that in addition to the SAD, which is included in the request body, the "Authorization" header with the Bearer token containing the API scopes must be set.

See section 11.9 in https://cloudsignatureconsortium.org/wp-content/uploads/2019/07/CSC_API_V1_1.0.4.0.pdf for further details

Response

The signing response has the format : 

{ "signatures": [ "string" ] }
{ "signatures": [ "string" ] }

The attributes have the following meaning:

  • signatures: An array of Base64-encoded signatures, in the same ordering as the hash values in the request.

See section 11.9 in https://cloudsignatureconsortium.org/wp-content/uploads/2019/07/CSC_API_V1_1.0.4.0.pdf for further details.