tls-ca-fetch connects to a hostname over TLS, walks the certificate chain the server presents, and writes the CA certificate(s) to a PEM file. It can also chase the AIA extension to fetch the root CA directly from the issuer's URL. Zero dependencies, single static binary.
- π One command β
tls-ca-fetch github.comwritesgithub.com-ca.pem, done - π Full chain inspection β prints every cert's role, CN, issuer, expiry, and AIA URL
- πΏ AIA chasing (
-fetch-root) β follows the Authority Information Access URL to also grab the root CA - π Stdout mode (
-o -) β pipe directly intoopenssl,keytool, or any other tool - π₯οΈ Cross-platform β Linux, macOS, Windows; amd64 and arm64
- π¦ Single static binary, zero runtime dependencies
| Requirement | Notes |
|---|---|
| Go 1.22+ | Only needed if building from source |
| Network access to target host | TCP port 443 (or custom with -port) |
| No root required | Pure userspace TLS dial |
# Linux (amd64)
curl -Lo tls-ca-fetch https://github.com/binRick/tls-ca-fetch/raw/main/releases/v1.0.0/tls-ca-fetch-linux-amd64
chmod +x tls-ca-fetch
sudo mv tls-ca-fetch /usr/local/bin/
# macOS (Apple Silicon)
curl -Lo tls-ca-fetch https://github.com/binRick/tls-ca-fetch/raw/main/releases/v1.0.0/tls-ca-fetch-darwin-arm64
chmod +x tls-ca-fetch
sudo mv tls-ca-fetch /usr/local/bin/
# macOS (Intel)
curl -Lo tls-ca-fetch https://github.com/binRick/tls-ca-fetch/raw/main/releases/v1.0.0/tls-ca-fetch-darwin-amd64
chmod +x tls-ca-fetch
sudo mv tls-ca-fetch /usr/local/bin/
# Windows (amd64) β download and add to PATH
# releases/v1.0.0/tls-ca-fetch-windows-amd64.exeRequires Go 1.22+.
git clone https://github.com/binRick/tls-ca-fetch.git
cd tls-ca-fetch
make build # β ./tls-ca-fetchmake cross # β releases/v1.0.0/tls-ca-fetch-{linux,darwin,windows}-{amd64,arm64}Or via Docker (no local Go needed):
./build.shtls-ca-fetch [flags] <hostname> [port]
| Flag | Default | Description |
|---|---|---|
-port |
443 |
TLS port to connect to |
-o |
<hostname>-ca.pem |
Output file path (- for stdout) |
-all |
off | Save full chain including leaf certificate |
-fetch-root |
off | Chase AIA extension to fetch root CA |
-insecure |
off | Skip TLS certificate verification |
-timeout |
10 |
Connection timeout in seconds |
-version |
β | Print version and exit |
tls-ca-fetch github.comβ Connecting to github.com:443 β¦
Chain received: 2 certificate(s)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[0] leaf CN=github.com IsCA=false
Issuer : DigiCert TLS Hybrid ECC SHA384 2020 CA1
Expires: 2026-03-26
[1] intermediate CA CN=DigiCert TLS Hybrid ECC SHA384 2020 IsCA=true
Issuer : DigiCert Global Root CA
Expires: 2031-04-13
AIA : http://cacerts.digicert.com/DigiCertGlobalRootCA.crt
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Saved 1 CA certificate(s) β github.com-ca.pem
Verified: 1 PEM block(s) readable in output file
tls-ca-fetch -o - internal.corp.example | openssl x509 -noout -texttls-ca-fetch -all -o chain.pem api.example.comtls-ca-fetch -fetch-root -o full-chain.pem smtp.example.com 587# Port as flag
tls-ca-fetch -port 8443 internal.example.com
# Port as positional arg
tls-ca-fetch internal.example.com 8443tls-ca-fetch -insecure -o my-internal-ca.pem vault.internaltls-ca-fetch corp-proxy.internal
sudo cp corp-proxy.internal-ca.pem /usr/local/share/ca-certificates/corp-proxy.crt
sudo update-ca-certificates- Opens a raw TLS connection to
hostname:port - Reads the
PeerCertificatesslice from the TLS handshake state β no HTTP, no SNI tricks needed - Prints a summary of every certificate in the chain (role, CN, issuer, expiry, AIA URL)
- Filters out the leaf cert (unless
-all) and writes remaining CA certs as concatenated PEM blocks - If
-fetch-rootis set, fetches the DER cert at the topmost certificate's AIA URL, parses it, and appends it to the output
| Role | Meaning |
|---|---|
leaf |
End-entity cert β presented by the server, not saved by default |
intermediate CA |
Signed by the root, signs the leaf β saved |
root CA |
Self-signed, trust anchor β only included via -fetch-root or if the server sends it |
The build.sh script uses a Docker golang:1.22-alpine container for reproducible, CGO-disabled, stripped binaries without needing Go on the host:
VERSION=v1.1.0 ./build.shOutput lands in releases/v1.1.0/.
- proc-trace-exec β trace
exec()calls system-wide via Linux proc connector - proc-trace-net β trace network connections system-wide via Linux conntrack
MIT