AdguardTeam/AdGuardHome · error
certificate does not verify: %w
Error message
certificate does not verify: %w
What it means
x509 certificate verification failed while validating the certificate chain. The main certificate was checked against the provided (or system) root CAs and optional intermediates, and Verify rejected it: expired cert, unknown authority, hostname mismatch, or constraint violations.
Source
Thrown at internal/aghtls/defaultmanager.go:711
}
othersLen := len(others)
if othersLen > 0 {
logger.InfoContext(
ctx,
"verifying certificate chain: got an intermediate cert",
"num", othersLen,
)
}
opts := x509.VerifyOptions{
DNSName: srvName,
Roots: rootCAs,
Intermediates: pool,
}
_, err = main.Verify(opts)
if err != nil {
return fmt.Errorf("certificate does not verify: %w", err)
}
return nil
}
// errNoIPInCert is the error that is returned from [parseCertChain]
// if the leaf certificate doesn't contain IPs.
const errNoIPInCert errors.Error = `certificates has no IP addresses; ` +
`DNS-over-TLS won't be advertised via DDR`
// parseCertChain parses the certificate chain from raw data, and returns it.
// If ok is true, the returned error, if any, is not critical. logger must not
// be nil.
func parseCertChain(
ctx context.Context,
logger *slog.Logger,
chain []byte,
) (parsedCerts []*x509.Certificate, ok bool, err error) {View on GitHub (pinned to b41aefbe51)
Solutions
- Check expiry: openssl x509 -in cert.pem -noout -dates and renew if expired
- Verify the chain: openssl verify -CAfile ca.pem -untrusted intermediates.pem cert.pem
- Ensure the SANs include the DNS name being validated (srvName)
- Add the signing CA to the trusted root pool used for validation
Example fix
// before roots absent / self-signed leaf only // after rootCAs.AppendCertsFromPEM(selfSignedCAPEM)
Defensive patterns
Strategy: validation
Validate before calling
leaf, _ := x509.ParseCertificate(certDER)
if _, err := leaf.Verify(x509.VerifyOptions{DNSName: srvName, Roots: rootCAs, Intermediates: pool}); err != nil {
return fmt.Errorf("pre-flight verify failed: %w", err)
} Try / catch
if err := mgr.LoadTLSConfig(ctx, conf); err != nil {
var x509Err x509.CertificateInvalidError
if errors.As(err, &x509Err) { /* expiry, hostname, constraints */ }
} Prevention
- Automate certificate renewal well before expiry
- Include full intermediate chain in the configured file
- Keep self-signed CAs in the trust pool used for validation
When it happens
Trigger: validateCertChain runs when the configured chain is validated with srvName and rootCAs; triggers include an expired certificate, a self-signed cert without its CA in the trust pool, a chain missing intermediates, or DNSName not matching the cert's SANs.
Common situations: Let's Encrypt cert not renewed before the 90-day expiry; corporate self-signed CA not added to the trusted roots; serving an internal hostname not present in the certificate SANs; incomplete chain (leaf only, no intermediates).
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- parsing tls certificate: %w
- loading tls certificate: %w
- parsing certificate at index %d: %w
- certificate-key pair: %w
- unknown cipher %q
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/a88e5c18374e3e0b.
Report an issue: GitHub.