Mutual TLS client authentication adds a second factor of identity on top of passwords or tokens, which is especially useful for automated downloads, internal APIs, and sensitive batch jobs. Client certificates enable strict allow‑lists at the edge, so only holders of the correct private key can reach protected endpoints, even if other credentials leak. This pattern avoids interactive prompts and keeps non‑interactive tools such as wget viable in cron jobs and CI pipelines.

During a mutual TLS handshake, the server requests a client certificate, validates it against trusted certificate authorities, and checks that it chains to an allowed issuer. On the caller side, wget delegates the cryptography to OpenSSL or GnuTLS, while command‑line switches such as --certificate, --private-key, and --ca-certificate bind a specific certificate, private key, and CA bundle to a single download. On typical Ubuntu builds, wget links against GnuTLS and uses the system trust store unless a custom bundle is supplied.

Incorrect certificate files, mismatched keys, or incomplete CA chains often surface only as generic certificate verify failed errors in wget output, so clear structure for TLS assets and cautious filesystem permissions are crucial for reliable automation. Careless handling of .pem files can expose private keys to other users on the same host, while incorrect trust configuration can silently fall back to insecure endpoints if options such as --https-only are omitted.

Steps to use client certificates with wget:

  1. Check that wget supports HTTPS using a terminal.
    $ wget --version
    GNU Wget 1.21.2 built on linux-gnu.
    
    ##### snipped #####
    +digest +https +ipv6 +iri +large-file +nls +ntlm +opie +psl +ssl/gnutls

    Presence of +https together with an SSL backend such as GnuTLS or OpenSSL indicates that wget can perform HTTPS requests; if the binary is missing, install it with sudo apt-get install --assume-yes wget ca-certificates on Ubuntu.

  2. Convert a provided .p12 or .pfx bundle into a client certificate .pem file using OpenSSL.
    $ openssl pkcs12 -in client.p12 -out client-cert.pem -clcerts -nokeys
    Enter Import Password:
    MAC verified OK

    Replace client.p12 with the actual bundle supplied by the service owner and adjust the output name client-cert.pem to fit local naming conventions.

  3. Extract the matching private key .pem file from the same bundle for use with wget.
    $ openssl pkcs12 -in client.p12 -out client-key.pem -nocerts -nodes
    Enter Import Password:
    MAC verified OK

    Using -nodes leaves the private key unencrypted on disk, which avoids interactive passphrase prompts in automation at the cost of requiring stricter filesystem permissions.

  4. Limit access to the private key .pem file so that only the owning user can read it.
    $ chmod 600 client-key.pem
    $ ls -l client-key.pem
    -rw------- 1 user user 1704 Dec  7 10:20 client-key.pem

    World-readable private keys allow other local users to impersonate the client identity on mutual TLS endpoints, potentially exposing protected data and corrupting audit trails.

  5. Store any private CA chain in a local file if the service uses an internal certificate authority.
    $ cp /path/from/provider/ca-chain.pem ca-chain.pem
    $ ls -l ca-chain.pem
    -rw-r--r-- 1 user user 2456 Dec  7 10:22 ca-chain.pem

    Use a custom ca-chain.pem when the server certificate chains to a non‑public CA; public CAs are normally covered by the system trust store.

  6. Call wget with the client certificate, private key, and optional CA chain to access the mutual TLS endpoint.
    $ wget --certificate=client-cert.pem --private-key=client-key.pem --ca-certificate=ca-chain.pem --https-only --secure-protocol=auto https://mtls.example.internal/protected/data.json
    --2025-12-07 10:30:41--  https://mtls.example.internal/protected/data.json
    Resolving mtls.example.internal (mtls.example.internal)... 10.0.0.10
    Connecting to mtls.example.internal (mtls.example.internal)|10.0.0.10|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 532 (application/json)
    Saving to: ‘data.json’
    
    data.json         100%[===================>]     532  --.-KB/s    in 0s
    
    2025-12-07 10:30:41 (12.3 MB/s) - ‘data.json’ saved [532/532]

    Options --https-only and --secure-protocol=auto prevent accidental downgrade to plain HTTP and let the underlying TLS library negotiate the best available protocol version.

  7. Configure optional defaults in a personal /home/user/.wgetrc file when repeated access to the same endpoint is required.
    ~/.wgetrc
    certificate = /home/user/client-cert.pem
    private_key = /home/user/client-key.pem
    ca_certificate = /home/user/ca-chain.pem

    Client certificate paths in /home/user/.wgetrc should not be committed to shared version control systems or exposed in world-readable home directory snapshots.

  8. Confirm that the protected resource downloaded successfully by inspecting the saved file and a few lines of content.
    $ ls -lh data.json
    -rw-r--r-- 1 user user 532 Dec  7 10:30 data.json
    $ head -n3 data.json
    {"status":"ok","message":"client authenticated","items":[
    ##### snipped #####

    Successful mutual TLS access typically returns HTTP status 200 OK without certificate‑related errors in wget output and produces a file size consistent with expectations.

Discuss the article:

Comment anonymously. Login not required.