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:

  1. Client initiates a connection to Caf API

  2. Caf server presents its certificate

  3. Client verifies the server certificate

  4. Client presents its own certificate

  5. Caf server verifies the client certificate

  6. 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:

  1. Downloaded your client certificate (.crt file) and have your private key (.key file)

  2. The correct Caf API endpoint for your production environment

API Endpoint: For all mTLS-enabled API requests, use the base URL https://mtls.us.prd.caf.io. This is the production endpoint that supports mutual TLS authentication.

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

When using curl for testing, you may need to provide the full certificate chain using the --cert option or specify the certificate authority with --cacert if you're using a non-public CA.

For more information about certificate validity, renewal, and management best practices, see Managing Certificates.

Troubleshooting mTLS connections

If you encounter issues with your mTLS connection, consider the following troubleshooting steps:

  1. Certificate Validation Failed: Ensure your certificate is active and not expired or revoked.

  2. Private Key Issues: Verify that your private key matches the certificate.

  3. Incorrect Certificate Format: Make sure you're using the correct format for your language/framework.

  4. Certificate Issues: Confirm your certificate is still valid and not revoked.

  5. 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