Using mTLS
Mutual TLS (mTLS) provides enhanced security for API communications by requiring both the client and server to authenticate each other using X.509 certificates. This guide explains how to use your Caf certificates to establish mTLS connections with Caf APIs.
Overview
In traditional TLS, only the server authenticates itself to the client. In mTLS, both parties authenticate to each other:
Client initiates a connection to Caf API
Caf server presents its certificate
Client verifies the server certificate
Client presents its own certificate
Caf server verifies the client certificate
If both verifications succeed, a secure connection is established
This bidirectional authentication ensures that only trusted clients can access Caf APIs, and clients only connect to legitimate Caf servers.
Prerequisites
Before implementing mTLS, ensure you have:
Access Created a certificate in the Trust
Downloaded your client certificate (
.crt
file) and have your private key (.key
file)The correct Caf API endpoint for your production environment
Implementing mTLS in your application
Converting certificate formats (if needed)
Depending on your programming language and framework, you might need to convert your certificate format:
Converting .crt to other formats (if needed):
# Convert .crt to .pem (if needed)
# In many cases, .crt and .pem are compatible, but some libraries prefer specific extensions
cp certificate.crt certificate.pem
# If you need to combine certificate and private key into PKCS#12 (.p12) format
openssl pkcs12 -export -out certificate.p12 -inkey private.key -in certificate.crt
Code examples
Below are examples of implementing mTLS in various programming languages:
Java (OkHttp)
import okhttp3.OkHttpClient;
import okhttp3.Request;
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
public class MtlsClient {
public static void main(String[] args) throws Exception {
// Load your certificate and private key files
X509Certificate certificate = loadCertificate("certificate.crt");
PrivateKey privateKey = loadPrivateKey("private.key");
// Create a KeyManager with your certificate and private key
KeyManager[] keyManagers = createKeyManagers(certificate, privateKey);
// Create a TrustManager that trusts the server's certificate
TrustManager[] trustManagers = createTrustManagers();
// Create an SSL context with the key and trust managers
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
// Create an OkHttpClient with the SSL context
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0])
.build();
// Make a request to the `API`
Request request = new Request.Builder()
.url("https://mtls.us.prd.caf.io/v1/transactions")
.build();
client.newCall(request).execute();
}
private static X509Certificate loadCertificate(String filename) throws CertificateException, IOException {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
try (FileInputStream fis = new FileInputStream(filename)) {
return (X509Certificate) factory.generateCertificate(fis);
}
}
private static PrivateKey loadPrivateKey(String filename) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
// Read private key file (assumes PKCS#8 format)
byte[] keyBytes = java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(filename));
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
private static KeyManager[] createKeyManagers(X509Certificate certificate, PrivateKey privateKey) throws Exception {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("certificate", certificate);
keyStore.setKeyEntry("private-key", privateKey, new char[0], new java.security.cert.Certificate[]{certificate});
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, new char[0]);
return kmf.getKeyManagers();
}
private static TrustManager[] createTrustManagers() throws Exception {
// For production use, you should use a proper trust store
return new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
}
}
Python (Requests)
import requests
# Path to your certificate files
cert_file = "certificate.crt"
key_file = "private.key"
# Make a request to the `API`
response = requests.get(
"https://mtls.us.prd.caf.io/v1/transactions",
cert=(cert_file, key_file)
)
print(response.json())
Node.js
const https = require("https");
const fs = require("fs");
// Read certificate files
const cert = fs.readFileSync("certificate.crt");
const key = fs.readFileSync("private.key");
// Configure the request options
const options = {
hostname: "mtls.us.prd.caf.io",
port: 443,
path: "/v1/transactions",
method: "GET",
cert: cert,
key: key,
};
// Make the request
const req = https.request(options, (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
console.log(JSON.parse(data));
});
});
req.on("error", (error) => {
console.error(error);
});
req.end();
Curl
Testing mTLS
connections from the command line can be helpful for debugging. Here's how to use curl with mTLS
certificates:
# Basic `mTLS` request
curl --cert certificate.crt --key private.key https://mtls.us.prd.caf.io/v1/transactions
# With additional options
curl --cert certificate.crt \
--key private.key \
--cacert ca.crt \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
https://mtls.us.prd.caf.io/v1/transactions
# With data payload
curl --cert certificate.crt \
--key private.key \
--cacert ca.crt \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{"key1": "value1", "key2": "value2"}' \
https://mtls.us.prd.caf.io/v1/transactions
Troubleshooting mTLS
connections
mTLS
connectionsIf you encounter issues with your mTLS
connection, consider the following troubleshooting steps:
Certificate Validation Failed: Ensure your certificate is active and not expired or revoked.
Private Key Issues: Verify that your private key matches the certificate.
Incorrect Certificate Format: Make sure you're using the correct format for your language/framework.
Certificate Issues: Confirm your certificate is still valid and not revoked.
Network Issues: Check if there are any firewalls or proxies interfering with your
HTTPS
connection.
Best practices
Keep certificates and private keys secure in your application's deployment environment.
Use secure storage for certificate files in your deployment environments.
Implement certificate rotation procedures to handle certificate expiration.
Set up monitoring for certificate expiration to avoid service interruptions.
Follow the principle of least privilege when assigning permissions to services using
mTLS
.
Last updated