package main import "crypto/x509" // verifyChain builds and checks every path from leaf to root: signatures,// validity periods, CA constraints, key usage and the host name.func verifyChain(leaf *x509.Certificate, intermediates []*x509.Certificate, root *x509.Certificate, host string) ([][]*x509.Certificate, error) { roots := x509.NewCertPool() // only this root is trusted, not the system store roots.AddCert(root) pool := x509.NewCertPool() // candidates for the path, not trusted on their own for _, cert := range intermediates { pool.AddCert(cert) } return leaf.Verify(x509.VerifyOptions{ Roots: roots, Intermediates: pool, DNSName: host, KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, // the default when empty })} How it works
x509.NewCertPool()plusAddCert(root)makes a trust store with just your root; a nilRootswould mean the system store.Intermediatesholds certificates that may appear in the path but are not trusted by themselves — typically the extra certificates a server sent.Verifychecks signatures, validity, basic constraints, name constraints and extended key usage (ExtKeyUsageServerAuthby default), and the host name whenDNSNameis set.- The result is a slice of chains, leaf first; the run prints
api.example.com → ECDSA.com Howto Issuing CA 1 → ECDSA.com Howto Root CA.
Gotchas
- A look-alike root fails with
x509: certificate signed by unknown authority (possibly because of "x509: ECDSA verification failure" while trying to verify candidate authority certificate …)— Go found a root with the right name, but its key did not sign the intermediate. - The missing intermediate gives the same
x509: certificate signed by unknown authority, without the hint; Go does not fetch issuers from AIA URLs. - The expired leaf fails with
x509: certificate has expired or is not yet valid: current time … is after 2025-03-31T23:59:59Z; setCurrentTimeto validate at another moment. - Leave
KeyUsagesempty and Go requires serverAuth; asking for another usage the certificate lacks fails withx509: certificate specifies an incompatible key usage(code signing in the run). Pass the usage you need, orx509.ExtKeyUsageAnydeliberately.
Related recipes
- How to verify a certificate chain against your own trust store with OpenSSL
- How to verify a certificate chain against your own trust store in Python
- How to verify a certificate chain against your own trust store in Rust
- How to check SSL certificate expiration date in Go
- How to decode an X.509 certificate in Go