How to Configure mTLS Client Certificates for Enterprise HTTPS Servers in GeoLibre

Set three environment variables (GEOLIBRE_HTTP_CA_CERT, GEOLIBRE_HTTP_CLIENT_CERT, and GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD) before starting the GeoLibre desktop app, and the native HTTP client will automatically present the client certificate when enterprise servers request mutual TLS authentication.

GeoLibre's desktop application uses a native Rust HTTP client to fetch tiles, OGC services, and remote rasters. When your organization requires mutual TLS (mTLS)—where the client must authenticate with a certificate—GeoLibre supports this through environment-based configuration without modifying source code. This guide explains how to configure mTLS client certificates for enterprise HTTPS servers based on the actual implementation in the GeoLibre codebase.


Supported Certificate Formats and Variables

GeoLibre recognizes three environment variables controlling TLS behavior. These are processed once at startup in apps/geolibre-desktop/src-tauri/src/lib.rs and apply to all HTTPS requests made by the native client.

Variable Required Purpose
GEOLIBRE_HTTP_CA_CERT No Path to additional trusted CA certificates (PEM format). Appends to the OS trust store.
GEOLIBRE_HTTP_CLIENT_CERT Yes for mTLS Path to client certificate. Supports PEM (certificate chain + unencrypted PKCS-8 private key) or PKCS#12 (.p12 / .pfx bundle).
GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD Conditional Password for PKCS-12 files. Presence forces the PKCS-12 code path even without .p12 extension.

The constants are defined in lib.rs at lines 680-940:

const HTTP_CLIENT_CERT_ENV: &str = "GEOLIBRE_HTTP_CLIENT_CERT";
const HTTP_CLIENT_CERT_PASSWORD_ENV: &str = "GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD";

How to Configure mTLS Client Certificates

Step 1: Prepare Your Certificate Files

Obtain your enterprise client certificate from your security team. GeoLibre accepts two formats:

  • PEM format: A single file containing the certificate chain followed by an unencrypted PKCS-8 private key. No password required.
  • PKCS#12 format: A .p12 or .pfx file containing both certificate and encrypted private key. Requires the GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD variable.

Step 2: Set Environment Variables

Create a .env file in the GeoLibre desktop application folder or export variables in your shell session.

Example: PKCS-12 with password

GEOLIBRE_HTTP_CA_CERT=/etc/ssl/certs/enterprise-root-ca.pem
GEOLIBRE_HTTP_CLIENT_CERT=/home/user/certs/client-identity.p12
GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD=EnterpriseSecret2024

Example: PEM without password

GEOLIBRE_HTTP_CLIENT_CERT=/home/user/certs/client.pem

# No password variable → triggers PEM path via rustls

Step 3: Restart GeoLibre

The native HTTP client is built as a shared singleton at application startup. Changes to environment variables require a restart to take effect.


How the Native Client Loads Certificates

The certificate loading logic in lib.rs follows this decision tree:

  1. CA certificates: If GEOLIBRE_HTTP_CA_CERT is set, the file is read as PEM and added to the rustls trust store using add_root_certificate().

  2. Client identity: If GEOLIBRE_HTTP_CLIENT_CERT is set:

    • PKCS-12 path: Triggered if file ends with .p12/.pfx or GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD is non-empty. Uses Identity::from_pkcs12_der() with the platform's native-tls backend (SChannel on Windows, Secure Transport on macOS, OpenSSL on Linux).
    • PEM path: Default fallback. Uses Identity::from_pem() via rustls.

This simplified Rust excerpt shows the core logic:

use std::env;
use reqwest::ClientBuilder;

fn build_http_client() -> reqwest::Result<reqwest::Client> {
    let mut builder = ClientBuilder::new();

    // Add enterprise CA if configured
    if let Ok(ca_path) = env::var("GEOLIBRE_HTTP_CA_CERT") {
        let ca_pem = std::fs::read(ca_path)?;
        builder = builder.add_root_certificate(
            reqwest::Certificate::from_pem(&ca_pem)?
        );
    }

    // Load client certificate for mTLS
    if let Ok(cert_path) = env::var("GEOLIBRE_HTTP_CLIENT_CERT") {
        let cert_data = std::fs::read(&cert_path)?;
        
        let is_pkcs12 = cert_path.ends_with(".p12") 
            || cert_path.ends_with(".pfx")
            || env::var("GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD").is_ok();
        
        if is_pkcs12 {
            let password = env::var("GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD")
                .unwrap_or_default();
            builder = builder.identity(
                reqwest::Identity::from_pkcs12_der(&cert_data, &password)?
            );
        } else {
            builder = builder.identity(
                reqwest::Identity::from_pem(&cert_data)?
            );
        }
    }

    builder.build()
}

Any certificate loading errors surface in the UI with messages like "Could not read client certificate …" sourced from lib.rs lines 680-940.


When Does the Client Certificate Get Sent?

The configured certificate is not transmitted to every server. According to the architecture documentation at docs/architecture.md (lines 119-139), the native client behaves as follows:

  • The singleton HTTP client stores the identity for the process lifetime.
  • The underlying TLS library (rustls or native-tls) only presents the certificate when the server sends a CertificateRequest during the TLS handshake.
  • If the server does not request client authentication, the certificate remains undisclosed.

This design ensures your client certificate is never leaked to arbitrary hosts. It is only exposed to endpoints that explicitly require mTLS.


Using mTLS in JavaScript Fetch Calls

From the web-based UI, use standard fetch() calls. The request is proxied through the native client automatically:

// Standard fetch—no special configuration needed
const response = await fetch('https://secure.enterprise.com/api/layers');
const tiles = await fetch('https://secure.enterprise.com/tiles/{z}/{x}/{y}.pbf');

The native client intercepts these requests and attaches the configured client certificate when the enterprise server demands it.


Troubleshooting mTLS Configuration

Symptom Likely Cause Solution
"Could not read client certificate" File path incorrect or permissions denied Verify GEOLIBRE_HTTP_CLIENT_CERT path and file readability
"invalid password" Wrong PKCS-12 password Check GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD value
Server rejects connection CA not trusted Set GEOLIBRE_HTTP_CA_CERT to your enterprise root CA
Certificate not sent Server does not request mTLS Verify server configuration requires client certificates

Summary

  • Three environment variables control mTLS: GEOLIBRE_HTTP_CA_CERT (optional CA trust), GEOLIBRE_HTTP_CLIENT_CERT (required), and GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD (for PKCS-12).
  • Two formats supported: PEM (no password) and PKCS-12 (password-protected).
  • Singleton client: Certificate is loaded once at startup in apps/geolibre-desktop/src-tauri/src/lib.rs and reused for all HTTPS requests.
  • Automatic presentation: Certificate is only sent when servers explicitly request it during TLS handshake, per docs/architecture.md lines 135-139.

Frequently Asked Questions

What file formats does GeoLibre accept for mTLS client certificates?

GeoLibre accepts PEM files containing a certificate chain plus unencrypted PKCS-8 private key, or PKCS-12 files (.p12 or .pfx) with encrypted private keys. PEM files require no password variable; PKCS-12 files require GEOLIBRE_HTTP_CLIENT_CERT_PASSWORD.

Do I need to modify GeoLibre source code to enable mTLS?

No. Configuration is entirely environment-driven. Set the appropriate variables before launching the desktop application and restart. The native client in lib.rs reads these variables automatically.

Will my client certificate be sent to every HTTPS server?

No. The TLS libraries (rustls or native-tls) only transmit the client certificate when a server explicitly requests one via a CertificateRequest message during the TLS handshake. Arbitrary servers never receive your certificate.

Where are the environment variables processed in the GeoLibre codebase?

The variables are defined as constants and consumed in apps/geolibre-desktop/src-tauri/src/lib.rs (lines 680-940). The architecture and security model are documented in docs/architecture.md (lines 119-139).

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 →