Implementing Client-Side Mutual TLS Authentication
IdCloud 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
Steps
- The Thales Customer Onboarding Team (COT) will ask you to provide a certificate signing request (CSR). The process to generate a CSR is written in detail in the Onboarding Input Form that is provided to you.
- 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 will also be required during the CSR generation process. You NEED TO TAKE NOTE of this passphrase.
- The generated CSR is then provided to COT.
- COT will submit the CSR which in turn will generate 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:
- *.csr file - to be shared between yourself and COT
- customer1.key file - private key to be kept by you
- customer1_01.pem file - client certificate file (base64 encoded) to be shared between yourself and COT
- passphrase - to be kept by you
Mutual TLS Client-Side Setup
The steps below describe the process to setup client-side Mutual TLS.
Optional: Using cURL to check the customer1.key and customer1_01.pem files
The following commands can be used to independently check that the customer1.key and customer1_01.pem files to be used are good before going through the effort of generating the keystore.
Prerequisites
- customer1.key file created when the CSR was generated
- Passphrase used when the CSR was generated
- customer1_01.pem file provided by Thales (specifically for Mutual TLS)
Steps
- Update the variables below and execute the command. Note that
- JWT – is the sample valid JWT. If not available, the response that will be received is HTTP 401
- ENDPOINT – is the endpoint of the Thales IdCloud service
- KEYFILE - is the customer1.key file filename
- PASSPHRASE – is the passphrase of the key file
- PEMFILE - is the customer1_01.pem file provided by 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}"}'
Note:
The payload of the cURL request should be updated based on the targeted IdCloud service.
- The expected response should have a Code of HTTP 201:
{"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"}
Generating 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.key and customer1_01.pem file to one file in a shell command as follows:
$ cat customer1.key customer1_01.pem > mykeycertificate.pem.txt
-
Execute the following openssl command. Note that:
-
mykeycertificate.pem.txt - is the file generated in Step #1
- mykeystore.pkcs12 - is the file that will be generated by running 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 will be prompted to enter the values for the passphrase and the export password for the pkcs12 file.
Note:
The export password and alias as this will be used 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 - text file concatenation of the key and certificate.
- mykeystore.pkcs12 - the key store you have 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 IdCloud 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 IdCloud 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();
}
}
}
Note:
The sample java code has comments labelled TODO with instructions on which values to update.
The values you need to update are:
- IDC_ENDPOINT – The URL of the IdCloud scenario services.
- JWT – Your JWT to connect to IdCloud services. If a valid JWT is not provided, the expected result is HTTP 401.
- CERT_ALIAS – “myalias” in the sample above
- CERT_PASSWORD – password set when generating the keystore and truststore
- IDKEYSTORE_FILENAME – keystore file generated
- You may also update the JSON payload according to the service that you are targeting.
Output
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
Note:
The Response Code: 201 means successful execution.