Skip to content

Corporate internal CA certificates not trusted: rustls-tls ignores the OS certificate store #11

Description

@elliothallais

Problem

When running confluence2md against a Confluence instance whose TLS certificate is signed by a corporate / internal Certificate Authority, the tool fails with:

Error: HTTP request failed: https://<internal-confluence>/rest/api/content/...: 
client error (Connect): invalid peer certificate: UnknownIssuer

The corporate root CA is present in the Windows certificate store (verified), but confluence2md does not see it.

Root cause

Cargo.toml declares:

reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }

The rustls-tls feature bundles Mozilla's WebPKI root CA store at compile time (via webpki-roots). It never consults the OS certificate store (Windows CryptoAPI / macOS Keychain / Linux NSS). Corporate / self-signed CAs that exist only in the system store are therefore unknown to rustls and the TLS handshake fails.

Environment

  • OS: Windows 11 (corporate environment)
  • confluence2md version: 2.3.1
  • Confluence server certificate issuer: CN=XXX, O=XXX
  • CA present in Windows certificate store: yes
  • Standard env vars tried (SSL_CERT_FILE, CURL_CA_BUNDLE, REQUESTS_CA_BUNDLE): no effect (none are supported by rustls)

Suggested fix

Replace the rustls-tls feature with rustls-tls-native-roots, which uses rustls-native-certs to load root CAs from the OS store at runtime:

# Cargo.toml
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-native-roots"] }

This is a one-line change and makes the tool work out-of-the-box in corporate environments without any user configuration.

Alternatively, a --ca-bundle <path> CLI option (and matching CONFLUENCE2MD_CA_BUNDLE env var) would let users point to a custom PEM CA bundle — useful for environments where the native cert store is not straightforward to access.

Workaround

As a temporary workaround, we extracted the corporate CA chain from the Windows store into a PEM bundle and wrote a Python wrapper that passes it via ssl.create_default_context(cafile=...). The page converts successfully this way, confirming the issue is purely the CA trust store.

References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions