grpc/grpc-go · error

spiffe: verify function could not parse input certificate

Error message

spiffe: verify function could not parse input certificate: %v

What it means

Emitted by the SPIFFE certificate verification callback inside reloadingCreds.ClientHandshake (bundle.go:166). When the server presents a certificate chain, each ASN.1 blob is parsed with x509.ParseCertificate; if any blob is malformed the handshake is aborted with the underlying parse error. This guard runs only when a SPIFFE trust bundle map is configured.

Solutions

  1. Inspect the server's presented certificate chain with openssl s_client -connect <host:port> -showcerts and confirm each certificate parses.
  2. Verify the management server is actually sending X.509 DER certificates and not, e.g., a raw public key or a JWT-SVID.
  3. Confirm spiffe_trust_bundle_map_file in the bootstrap points at a valid bundle and that GRPC_XDS_SPIFFE is enabled.
  4. Re-issue or reload the server certificate if it is malformed.
Defensive patterns

Strategy: try-catch

Try / catch

// The error surfaces during ClientHandshake; handle at the RPC level:
if _, err := conn.Dial(...); err != nil {
    var sev errdetails.SecurityErrorCode // or string-match the prefix
    if strings.Contains(err.Error(), "spiffe: verify function could not parse input certificate") {
        // peer cert is malformed; alert the server operator
    }
}

Prevention

When it happens

Trigger: An xDS management server (or any peer reached via this bundle) presents a certificate whose DER bytes are not a valid X.509 certificate. Triggered during ClientHandshake after the TLS layer hands rawCerts to buildSPIFFEVerifyFunc.

Common situations: Server is misconfigured and sends a non-PEM/DER blob or a truncated certificate; a proxy strips or rewrites the chain; version skew between the server's crypto library and the x509 parser; corrupted SPIFFE bundle map causing the wrong bytes to be evaluated.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/7ea05dfaca2e98f6. Report an issue: GitHub.

Appendix: source

Thrown at internal/xds/bootstrap/tlscreds/bundle.go:166

func (c *reloadingCreds) Clone() credentials.TransportCredentials {
	return &reloadingCreds{provider: c.provider}
}

func (c *reloadingCreds) OverrideServerName(string) error {
	return errors.New("overriding server name is not supported by xDS client TLS credentials")
}

func (c *reloadingCreds) ServerHandshake(net.Conn) (net.Conn, credentials.AuthInfo, error) {
	return nil, nil, errors.New("server handshake is not supported by xDS client TLS credentials")
}

func buildSPIFFEVerifyFunc(spiffeBundleMap map[string]*spiffebundle.Bundle) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
	return func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
		rawCertList := make([]*x509.Certificate, len(rawCerts))
		for i, asn1Data := range rawCerts {
			cert, err := x509.ParseCertificate(asn1Data)
			if err != nil {
				return fmt.Errorf("spiffe: verify function could not parse input certificate: %v", err)
			}
			rawCertList[i] = cert
		}
		if len(rawCertList) == 0 {
			return fmt.Errorf("spiffe: verify function has no valid input certificates")
		}
		leafCert := rawCertList[0]
		roots, err := spiffe.GetRootsFromSPIFFEBundleMap(spiffeBundleMap, leafCert)
		if err != nil {
			return err
		}

		opts := x509.VerifyOptions{
			Roots:         roots,
			CurrentTime:   time.Now(),
			Intermediates: x509.NewCertPool(),
		}

View on GitHub (pinned to 0c51461d27)