Client-side mutual TLS authentication
Risk Management requires Mutual TLS authentication when sending requests to the production environment. Although this is optional for the integration environment, Thales highly recommends implementing it there as well, in preparation for production deployment.
CSR generation process
-
The Thales Customer Onboarding Team (COT) asks you to provide a certificate signing request (CSR). The process to generate a CSR is written in detail in the Onboarding Input Form from COT.
-
During the CSR generation process, aside from the CSR, a private key is also generated. You MUST KEEP this file for configuration later.
-
A passphrase is also required during the CSR generation process. You NEED TO TAKE NOTE of this passphrase.
-
You provide the generated CSR to COT.
-
COT submits the CSR, which then generates the client certificate files.
-
These client certificate files are then sent back to you.
Output
By the end of the steps above, the following output is generated:
-
The .csr file is shared between you and COT.
-
The customer1.key file is the private key that you keep.
-
The customer1_01.pem file is the client certificate file (base64 encoded) that is shared between you and COT.
-
The passphrase that you keep.
Mutual TLS client-side setup
The steps below describe the process to set up client-side Mutual TLS.
Optional: Use cURL to check the customer1.key and customer1_01.pem files
Prerequisites
- customer1.key file created when the CSR was generated
- Passphrase used when the CSR was generated
- customer1_01.pem file that Thales provided (specifically for Mutual TLS)
Steps
You can use the following commands to independently check that the customer1.key and customer1_01.pem files are good before generating the keystore.
Update the variables below and execute the command:
- JWT is the sample valid JWT. If not available, the HTTP 401 response is received.
- ENDPOINT is the endpoint of the Thales Risk Management service.
- KEYFILE is the
customer1.keyfilename. - PASSPHRASE is the passphrase of the key file.
- PEMFILE is the
customer1_01.pemfile from Thales (specifically for Mutual TLS).JWT="valid-JWT" ENDPOINT= "https://scs-ol-demo.rnd.gemaltodigitalbankingidcloud.com/scs/v1/scenarios" KEYFILE=customer1.key PASSPHRASE="abc123abc123" PEMFILE=customer1_01.pem curl -v -d'{"name": "Connect_Verify_Document"}' \ -H "Content-Type: application/json" \ -H "Authorization:Bearer $JWT" \ --cert $PEMFILE:$PASSPHRASE --key $KEYFILE -k $ENDPOINT \ -w '\n\n{"Code": "HTTP %{http_code}","RT": "%{time_total}"}'
The payload of the cURL request should be updated based on the targeted Risk Management service.
The expected response should have an HTTP 201 code:
{"id":"be8cf02d-5cb3-4596-944c-afd549e471df","name":"Connect_Verify_Document","status":"Waiting","state":{"steps":[{"id":"frontWhiteImage","name":"frontWhiteImage","status":"Waiting"},{"id":"backWhiteImage","name":"backWhiteImage","status":"Waiting"},{"id":"frontIRImage","name":"frontIRImage","status":"Waiting"},{"id":"backIRImage","name":"backIRImage","status":"Waiting"},{"id":"frontUVImage","name":"frontUVImage","status":"Waiting"},{"id":"backUVImage","name":"backUVImage","status":"Waiting"},{"id":"verifyResults","name":"verifyResults","status":"Waiting"}],"result":{"code":"0","message":"Request successfully submitted"}}}
{"Code": "HTTP 201","RT": "0,712100"}
Generate a keystore
You need to generate a keystore in which to store the key file.
Prerequisites
- customer1.key file created when the CSR was generated
- Passphrase used when the CSR was generated
- customer1_01.pem file (client certificate file - base64 encoded) provided by Thales (specifically for Mutual TLS)
Steps
-
Concatenate the
customer1.keyandcustomer1_01.pemfile to one file in a shell command as follows:$ cat customer1.key customer1_01.pem > mykeycertificate.pem.txt -
Execute the following openssl command.
-
mykeycertificate.pem.txt is the file that you just generated.
- mykeystore.pkcs12 is the file that is generated when you run this command.
-
myalias can be any alias value, but TAKE NOTE of the value used.
$ openssl pkcs12 -export -in mykeycertificate.pem.txt -out mykeystore.pkcs12 -name myalias -noiter -nomaciter Enter pass phrase for mykeycertificate.pem.txt: Enter Export Password: <new export password> Verifying - Enter Export Password: <new export password>You are prompted to enter the values for the passphrase and the export password for the pkcs12 file.
Note the export password and alias, because you use them later in the code.
Output
The following are the outputs of executing the above steps. Be sure to have the files and take note of the password and alias set.
- mykeycertificate.pem.txt is the text file concatenation of the key and certificate.
- mykeystore.pkcs12 is the key store you just generated.
- export password for pkscs12 (the keystore)
- alias for the certificate in the keystore
Final testing using sample Java code
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.PrivateKeyDetails;
import org.apache.http.ssl.PrivateKeyStrategy;
import org.apache.http.ssl.SSLContexts;
import org.json.simple.JSONObject;
import javax.net.ssl.SSLContext;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.security.KeyStore;
import java.util.Map;
public class SSLMutualAuthTest {
public static void main (String[] args) {
System.out.println("Mutual TLS Authentication test");
try {
//TODO: update IDC_ENDPOINT value with the URL of the targeted Risk Management scenario endpoint
final String IDC_ENDPOINT = "https:// *** .gemaltodigitalbankingidcloud.com/scs/v1/scenarios";
//TODO: update JWT value with your JWT token
final String JWT = "TBD";
//TODO: update CERT_ALIAS to the alias value set during the keystore creation
//TODO: update CERT_PASSWORD to the password value set during the keystore creation
final String CERT_ALIAS = "myalias", CERT_PASSWORD = "abc12345678";
KeyStore identityKeyStore = KeyStore.getInstance("pkcs12");
//TODO: update IDKEYSTORE_FILENAME to the filename of the keystore file created
final String IDKEYSTORE_FILENAME = "conf/mykeystore.pkcs12";
FileInputStream identityKeyStoreFile = new FileInputStream(new File(IDKEYSTORE_FILENAME));
identityKeyStore.load(identityKeyStoreFile, CERT_PASSWORD.toCharArray());
SSLContext sslContext = SSLContexts.custom()
// load identity keystore
.loadKeyMaterial(identityKeyStore, CERT_PASSWORD.toCharArray(), new PrivateKeyStrategy() {
@Override
public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
return CERT_ALIAS;
}
})
.build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1.2", "TLSv1.1"},
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();
// Call a SSL-endpoint
JSONObject testContent= new JSONObject();
//TODO: Update as needed the API payload to match requirement for the Risk Management Service
testContent.put("name", "Connect_Verify_Document");
System.out.println("Calling URL: " + IDC_ENDPOINT);
HttpPost post = new HttpPost(IDC_ENDPOINT);
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/json");
post.setHeader("Authorization", "Bearer " + JWT);
StringEntity entity = new StringEntity(testContent.toString());
post.setEntity(entity);
System.out.println("**POST** request Url: " + post.getURI());
System.out.println("Parameters : " + testContent);
HttpResponse response = client.execute(post);
int responseCode = response.getStatusLine().getStatusCode();
System.out.println("Response Code: " + responseCode);
System.out.println("Content:-\n");
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
} catch (Exception ex) {
System.out.println("ERROR: " + ex);
ex.printStackTrace();
}
}
}
The sample java code has comments labelled TODO with instructions on which values to update.
The values you need to update are:
- IDC_ENDPOINT is the URL of the Risk Management scenario services.
- JWT is your JWT to connect to Risk Management services. If a valid JWT is not provided, the expected result is HTTP 401.
- CERT_ALIAS is
myaliasin the sample above. - CERT_PASSWORD is the password set when generating the keystore and truststore.
- IDKEYSTORE_FILENAME is the keystore file generated.
- You can also update the JSON payload according to the service that you are targeting.
Output
Response Code: 201 means successful execution.
When successfully executed, the sample java code has the following output:
Mutual TLS Authentication test
Calling URL: https:// *** .gemaltodigitalbankingidcloud.com/scs/v1/scenarios
**POST** request Url: https:// *** .gemaltodigitalbankingidcloud.com/scs/v1/scenarios
Parameters : {"name":"Connect_Verify_Document"}
Response Code: 201
Content:- {"id":"b9029134-0e3a-4ca8-bc17-92e59071dfb8","name":"Connect_Verify_Document","status":"Waiting","state":{"steps":[{"id":"frontWhiteImage","name":"frontWhiteImage","status":"Waiting"},{"id":"backWhiteImage","name":"backWhiteImage","status":"Waiting"},{"id":"frontIRImage","name":"frontIRImage","status":"Waiting"},{"id":"backIRImage","name":"backIRImage","status":"Waiting"},{"id":"frontUVImage","name":"frontUVImage","status":"Waiting"},{"id":"backUVImage","name":"backUVImage","status":"Waiting"},{"id":"verifyResults","name":"verifyResults","status":"Waiting"}],"result":{"code":"0","message":"Request successfully submitted"}}}
Process finished with exit code 0