kubernetes/kops · error

parsing intermediate certificate from %s: %w

Error message

parsing intermediate certificate from %s: %w

What it means

The downloaded body must be a valid DER-encoded X.509 certificate. If x509.ParseCertificate fails, this error wraps the parse error with the source URL. It usually means the endpoint returned something other than the expected DER bytes (PEM, HTML, JSON, or corrupt data).

Source

Thrown at upup/pkg/fi/cloudup/azure/attest.go:452

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("fetching intermediate certificate from %s: status %d", url, resp.StatusCode)
	}

	// Cap the body read to reject pathologically large responses. Read one extra byte so we can
	// distinguish "at the limit" from "exceeded limit".
	body, err := io.ReadAll(io.LimitReader(resp.Body, intermediateCertMaxResponseBytes+1))
	if err != nil {
		return nil, fmt.Errorf("reading intermediate certificate from %s: %w", url, err)
	}
	if len(body) > intermediateCertMaxResponseBytes {
		return nil, fmt.Errorf("intermediate certificate from %s exceeds %d bytes", url, intermediateCertMaxResponseBytes)
	}

	cert, err := x509.ParseCertificate(body)
	if err != nil {
		return nil, fmt.Errorf("parsing intermediate certificate from %s: %w", url, err)
	}
	return cert, nil
}

// validateFetchedIntermediateForSigner checks that a fetched intermediate is actually the issuer
// referenced by the signer certificate before it is used or cached. This is a structural check
// only; the cryptographic signature is verified later by verifySignerCertChain.
func validateFetchedIntermediateForSigner(signer *x509.Certificate, cert *x509.Certificate) error {
	if signer == nil {
		return fmt.Errorf("signer certificate is required")
	}
	if cert == nil {
		return fmt.Errorf("fetched certificate is required")
	}
	if !cert.IsCA {
		return fmt.Errorf("fetched certificate is not a CA certificate")
	}
	// Require at least one issuer identifier so the per-field length guards below cannot silently

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Inspect the fetched bytes (curl | openssl x509 -inform der -text) to identify the actual format
  2. If the endpoint returns PEM, strip the PEM armor and base64-decode before parsing
  3. If it returns PKCS#7, parse with encoding/pem + crypto/x509/pkix or the appropriate PKCS#7 handling before caching
  4. Confirm no middlebox rewrites the response body

Example fix

// before
body, _ := io.ReadAll(resp.Body)
cert, err := x509.ParseCertificate(body) // fails on PEM input
// after
body, _ := io.ReadAll(resp.Body)
if bytes.HasPrefix(body, []byte("-----BEGIN")) {
    block, _ := pem.Decode(body)
    body = block.Bytes
}
cert, err := x509.ParseCertificate(body)
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate DER structure before parsing
if len(body) == 0 || body[0] != 0x30 { // not an ASN.1 SEQUENCE => not DER
    return fmt.Errorf("endpoint did not return DER data")
}

Type guard

func isDERCertificate(b []byte) bool {
    return len(b) > 2 && b[0] == 0x30 && (b[1]&0x80) == 0
}

Try / catch

cert, err := fetchCertificate(client, url)
var parseErr *x509.CertificateInvalidError
if err != nil && !errors.As(err, &parseErr) && strings.Contains(err.Error(), "parsing intermediate certificate") {
    return nil, fmt.Errorf("AIA endpoint returned non-DER content: %w", err)
}

Prevention

When it happens

Trigger: fetchCertificate obtains an HTTP 200 body that is not parseable DER — a PEM-encoded certificate, an HTML error page, a PKCS#7 chain blob, or truncated/corrupt bytes.

Common situations: AIA endpoint serving PEM instead of DER; proxy injecting a consent/error page with status 200; endpoint serving a full PKCS#7 certs-only message which Go's x509.ParseCertificate cannot decode.

Understand the failure class

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/b852b73054a5d912. Report an issue: GitHub.