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 silentlyView on GitHub (pinned to 4c8573c808)
Solutions
- Inspect the fetched bytes (curl | openssl x509 -inform der -text) to identify the actual format
- If the endpoint returns PEM, strip the PEM armor and base64-decode before parsing
- If it returns PKCS#7, parse with encoding/pem + crypto/x509/pkix or the appropriate PKCS#7 handling before caching
- 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
- Sniff the first byte for an ASN.1 SEQUENCE (0x30) before parsing
- Handle PEM/PKCS#7 responses explicitly if an endpoint serves them
- Verify with `openssl x509 -inform der` what the AIA URL actually returns
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- intermediate certificate from %s exceeds %d bytes
- signer certificate is required
- intermediate certificate fetch recently failed for signer is
- no fetched intermediate certificates matched signer issuer %
- fetching intermediate certificate from %s: %w
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/b852b73054a5d912.
Report an issue: GitHub.