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

  1. Check expiry: openssl x509 -in cert.pem -noout -dates and renew if expired
  2. Verify the chain: openssl verify -CAfile ca.pem -untrusted intermediates.pem cert.pem
  3. Ensure the SANs include the DNS name being validated (srvName)
  4. 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

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

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/a88e5c18374e3e0b. Report an issue: GitHub.