How to Configure mTLS Client Certificates in the GeoLibre Tauri Desktop Build

GeoLibre configures mutual TLS (mTLS) client certificates through three environment variables that the Tauri desktop process reads at startup in src-tauri/src/lib.rs, where the client_identity() function loads the certificate material and build_guarded_http_client() selects the appropriate TLS backend (rustls for PEM, native-tls for PKCS-12).

The GeoLibre desktop application uses a native Rust HTTP client to perform privileged network operations such as tile fetching and OGC GetCapabilities requests. According to the opengeos/GeoLibre source code, this client is built once per process lifetime and cached, with mTLS configuration driven entirely by environment variables that determine the certificate format and trust store.

Environment Variable Configuration

The Tauri backend recognizes three environment variables for TLS configuration. These are read during the initialization of the guarded HTTP client in apps/geolibre-desktop/src-tauri/src/lib.rs (lines 718–724).

Variable Purpose
GEOLIBRE_HTTP_CLIENT_CERT Path to the client certificate file. Accepts either a PEM bundle (certificate chain + unencrypted PKCS#8 private key) or a PKCS-12 bundle (.p12 or .pfx).
GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD Passphrase for a PKCS-12 bundle. When present, this forces the PKCS-12 loading path.
GEOLIBRE_HTTP_CA_CERT Optional path to a PEM bundle of additional CA certificates to trust alongside the OS certificate store.

If GEOLIBRE_HTTP_CLIENT_CERT is omitted or empty, the client operates without client authentication unless a password is supplied without a corresponding certificate path, which triggers a configuration error.

Certificate Loading Logic in src-tauri/src/lib.rs

The core logic for mTLS setup resides in the client_identity() function (lines 966–1032). This function follows a deterministic sequence to validate inputs and load cryptographic material.

Step 1: Password Detection

The function first checks for the GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD variable. An empty string is treated as unset, while non-UTF-8 passwords cause an immediate error (lines 73–80). The presence of a password forces the loader to treat the file as PKCS-12, regardless of file extension.

let password = match env::var(HTTP_CLIENT_CERT_PASSWORD_ENV) { … };

Step 2: Path Validation

If the certificate path is missing but a password was provided, the code aborts with a clear error indicating misconfiguration (lines 85–92). This prevents attempting to decrypt a non-existent file.

Step 3: Format Detection

The helper client_cert_is_pkcs12(&path, password.is_some()) determines the parsing strategy by checking for the .p12 or .pfx extension, or by confirming that a password was provided (lines 41–43).

Step 4: Backend-Specific Loading

PKCS-12 Path: When loading a PKCS-12 bundle, the code uses reqwest::Identity::from_pkcs12_der with the native-tls backend (SChannel on Windows, Secure Transport on macOS, OpenSSL on Linux). Note that Android does not support PKCS-12 client certificates in this implementation, which triggers an explicit error (lines 1014–1022).

PEM Path: For PEM files, the code uses reqwest::Identity::from_pem with the rustls backend, which reads the certificate chain and private key directly (lines 1024–1030).

// PKCS-12 loading (native-tls)
let identity = reqwest::Identity::from_pkcs12_der(&cert_bytes, password)?;

// PEM loading (rustls)
let identity = reqwest::Identity::from_pem(&cert_bytes)?;

Step 5: Client Initialization and Caching

In build_guarded_http_client() (lines 1068–1075), the builder switches TLS backends based on the presence and format of the client identity:

  • PEM identity → use_rustls_tls()
  • PKCS-12 identity → use_native_tls()

The resulting reqwest::blocking::Client is cached in a std::sync::OnceLock at lines 48–53, ensuring that the mTLS configuration remains static for the entire desktop session and is reused across all network requests.

Supported Certificate Formats

GeoLibre supports two distinct certificate formats, each with specific requirements:

  • PEM Format: Must contain the certificate chain concatenated with an unencrypted PKCS#8 private key. This path leverages the rustls TLS stack.
  • PKCS-12 Format: Must be a .p12 or .pfx file encrypted with a passphrase. This path leverages the native-tls stack and is not available on Android builds.

The design intentionally separates these formats by backend to maximize platform compatibility while maintaining security constraints.

Practical Configuration Examples

Configure mTLS before launching the GeoLibre desktop application by exporting the environment variables in your shell:


# Option 1: PEM certificate (unencrypted private key)

export GEOLIBRE_HTTP_CLIENT_CERT=/path/to/client.pem

# Option 2: PKCS-12 bundle with passphrase

export GEOLIBRE_HTTP_CLIENT_CERT=/path/to/client.p12
export GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD=secretpass

# Optional: Trust a private CA certificate

export GEOLIBRE_HTTP_CA_CERT=/path/to/extra-ca.pem

# Launch the application

./geolibre-desktop

Within the Rust codebase, the guarded client is accessed as a singleton:

// Returns the cached client instance with mTLS configured
let client = guarded_http_client()?;
let resp = client.get("https://secure.tileserver.com/tiles")
                 .timeout(Duration::from_secs(30))
                 .send()?;

Architectural Security Context

The guarded_http_client serves as the single entry point for all privileged network operations in the native layer. Beyond mTLS, this client incorporates a SSRF guard that blocks connections to private, link-local, and multicast addresses via the is_disallowed_ip check (lines 41–78 in the same file).

By default, the client trusts the OS certificate store through the rustls-tls-native-roots feature, plus any additional CAs specified via GEOLIBRE_HTTP_CA_CERT. Because the reqwest::blocking::Client is cached in a OnceLock, the mTLS configuration is immutable for the process lifetime—any changes to certificates require a full application restart to take effect.

Summary

  • GeoLibre uses three environment variables (GEOLIBRE_HTTP_CLIENT_CERT, GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD, GEOLIBRE_HTTP_CA_CERT) to configure mTLS.
  • Certificate loading is handled by the client_identity() function in src-tauri/src/lib.rs (lines 966–1032).
  • The system automatically selects between rustls (for PEM) and native-tls (for PKCS-12) backends based on file format and password presence.
  • The HTTP client is cached for the process lifetime in a OnceLock, making mTLS configuration static after startup.
  • Android builds do not support PKCS-12 client certificates and will emit an explicit error if attempted.

Frequently Asked Questions

What environment variables configure mTLS in GeoLibre Desktop?

You must set GEOLIBRE_HTTP_CLIENT_CERT to the file path, optionally set GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD if using a PKCS-12 bundle, and optionally set GEOLIBRE_HTTP_CA_CERT to trust additional certificate authorities. These are read at startup by the Tauri process in src-tauri/src/lib.rs.

Why does GeoLibre use different TLS backends for PEM and PKCS-12 certificates?

The implementation uses rustls for PEM files via reqwest::Identity::from_pem and native-tls for PKCS-12 files via reqwest::Identity::from_pkcs12_der. This separation ensures maximum cross-platform compatibility, as rustls handles PEM parsing efficiently while native-tls provides robust PKCS-12 support through OS-specific cryptographic libraries (SChannel, Secure Transport, or OpenSSL).

Can I change the client certificate without restarting the GeoLibre desktop application?

No. The HTTP client is built once and stored in a std::sync::OnceLock when the Tauri process starts. Because the reqwest::blocking::Client is cached and immutable, any changes to the GEOLIBRE_HTTP_CLIENT_CERT environment variable require a full application restart to take effect.

Does GeoLibre support encrypted private keys in PEM files?

No. According to the source code in src-tauri/src/lib.rs, PEM-formatted client certificates must contain an unencrypted PKCS#8 private key. If you require passphrase protection for your private key, you must use a PKCS-12 bundle (.p12 or .pfx) with the GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD variable instead.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →