Mutual TLS

Prev Next

Mutual Transport Layer Security (mTLS) is an authentication method in which both the client and server verify each other’s SSL/TLS certificates. This two-way validation establishes a trusted relationship and ensures secure, authenticated communication.

Configurations

You can set up the mTLS authentication using either of the following methods:

For setting up mTLS authentication using the Traceable platform, you must have the following configurations:

Configuration

Description

Client Certificate

A client certificate is a digital certificate that the client presents during the TLS handshake to prove its identity to the server. This server validates this certificate along with its own to establish a secure and authenticated communication channel. The certificate must be provided in PEM format.

Client Key

A client key is the private key associated with the client's digital certificate.

Client Key Passphrase

A client key passphrase is the password used to protect the private key associated with the client's digital certificate.

Client Authority Certificate

A bundle of trusted CA certificates for validating the server's certificate.

You can set up mTLS authentication directly from the CLI using a JSON file and environment variables. To do so, use the following syntax:

{
    "host:port" : {
        "client_cert": <Path to the Client Certificate>,
        "client_key": <Path to the Client Key>,
        "root_ca": <Path to the Client Authority Certificate>,
        "passphrase": <(Optional) Path to the Client Key Passphrase>
    }
    "host:port" : {
        "client_cert": <Path to the Client Certificate>,
        "client_key": <Path to the Client Key>,
        "root_ca": <Path to the Client Authority Certificate>,
    },
    "default" : {
        "client_cert": "/certs/client_default.crt",
        "client_key": "/certs/client_default.key",
        "root_ca": "/certs/CA_default.pem"
    }
}

Note

The default section in the above JSON acts as a fallback mechanism when Traceable does not find any matching host.

For example, the JSON file would look like the following:

{
    "mysite.local:8443" : {
        "client_cert": "/home/work/traceable/ast/pov_tools/mtls/certs/cas.client.crt",
        "client_key": "/home/work/traceable/ast/pov_tools/mtls/certs/cas.client.key",
        "root_ca": "/home/work/traceable/ast/pov_tools/mtls/certs/CA.pem",
        "passphrase": ""   # This represents an empty passphrase
    }
    "anotherhost.com:443" : {
        "client_cert": "/certs/client.crt",
        "client_key": "/certs/client.key",
        "root_ca": "/certs/CA.pem",
    },
    "default" : {
        "client_cert": "/certs/client_default.crt",
        "client_key": "/certs/client_default.key",
        "root_ca": "/certs/CA_default.pem"
    }
}

After defining the JSON file, export one of the following environment variables in the shell, invoking the CLI:

  • Use one environment variable, for example:

    export TARGET_TLS_CONFIG_FILE = /path/mtls_config.json

    You can define the JSON file (mtls_config.json) like the one above.

    Note

    This method authenticates all hosts mentioned in the JSON file.

  • Use multiple environment variables, for example:

    export ROOT_CA_FILE = /path/CA.pem
    export TARGET_CLIENT_CERT_FILE = /path/client.crt
    export TARGET_CLIENT_KEY_FILE = /path/client.key
    export TARGET_CLIENT_KEY_PASSPHRASE = "<passphrase>"

Example

The following are some samples that you can use to configure the JWT mechanism in the Advanced mode:

Sample 1

from traceable import config
import io
import tempfile
from traceable.ast.constants import (
    DEFAULT_HOST,
    CLIENT_CERT,
    CLIENT_KEY,
    KEY_PASSPHRASE,
    ROOT_CA
)

def mtls_hook(scanctx: ScanContext, pluginctx: PluginContext, testcase: TestCase, **kwargs) -> list[Assertion]:
    def string_to_absolute_filepath(content, file_extension='.txt'):
        # Create a temporary file in a secure location
        with tempfile.NamedTemporaryFile(mode='w', suffix=file_extension, delete=False) as temp_file:
            # Write the string content to the temporary file
            temp_file.write(content)

            # Get the absolute path of the temporary file
            absolute_filepath = os.path.abspath(temp_file.name)

        # The temporary file will be automatically closed and deleted
        # as it goes out of scope, but you can also explicitly delete it here:
        return absolute_filepath
    attributes = testcase.get_attributes()
    url = attributes.get_one("mutated.http.request.url", default="")
    http_client = testcase.get_http_client(url)
    # Typecase http_client
    attributes = testcase.get_attributes()
    # Set the certificate and key contents as strings
    client_cert = "client_cert"
    client_key = "client_key"
    root_ca = "root_ca"

    mtls_dict = {CLIENT_CERT: string_to_absolute_filepath(client_cert),
                 CLIENT_KEY: string_to_absolute_filepath(client_key),
                 }
    if len(root_ca) > 0:
        mtls_dict[ROOT_CA] = string_to_absolute_filepath(root_ca)

    config.TLS_CONFIG[DEFAULT_HOST][CLIENT_CERT] = mtls_dict[CLIENT_CERT]
    config.TLS_CONFIG[DEFAULT_HOST][CLIENT_KEY] = mtls_dict[CLIENT_KEY]
    if ROOT_CA in mtls_dict:
        config.TLS_CONFIG[DEFAULT_HOST][ROOT_CA] = mtls_dict[ROOT_CA]
    return []