{"record":{"id":"b852b73054a5d912","repo":"kubernetes/kops","slug":"parsing-intermediate-certificate-from-s-w","errorCode":null,"errorMessage":"parsing intermediate certificate from %s: %w","messagePattern":"parsing intermediate certificate from (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/azure/attest.go","lineNumber":452,"sourceCode":"\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"fetching intermediate certificate from %s: status %d\", url, resp.StatusCode)\n\t}\n\n\t// Cap the body read to reject pathologically large responses. Read one extra byte so we can\n\t// distinguish \"at the limit\" from \"exceeded limit\".\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, intermediateCertMaxResponseBytes+1))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading intermediate certificate from %s: %w\", url, err)\n\t}\n\tif len(body) > intermediateCertMaxResponseBytes {\n\t\treturn nil, fmt.Errorf(\"intermediate certificate from %s exceeds %d bytes\", url, intermediateCertMaxResponseBytes)\n\t}\n\n\tcert, err := x509.ParseCertificate(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing intermediate certificate from %s: %w\", url, err)\n\t}\n\treturn cert, nil\n}\n\n// validateFetchedIntermediateForSigner checks that a fetched intermediate is actually the issuer\n// referenced by the signer certificate before it is used or cached. This is a structural check\n// only; the cryptographic signature is verified later by verifySignerCertChain.\nfunc validateFetchedIntermediateForSigner(signer *x509.Certificate, cert *x509.Certificate) error {\n\tif signer == nil {\n\t\treturn fmt.Errorf(\"signer certificate is required\")\n\t}\n\tif cert == nil {\n\t\treturn fmt.Errorf(\"fetched certificate is required\")\n\t}\n\tif !cert.IsCA {\n\t\treturn fmt.Errorf(\"fetched certificate is not a CA certificate\")\n\t}\n\t// Require at least one issuer identifier so the per-field length guards below cannot silently","sourceCodeStart":434,"sourceCodeEnd":470,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azure/attest.go#L434-L470","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nbody, _ := io.ReadAll(resp.Body)\ncert, err := x509.ParseCertificate(body) // fails on PEM input\n// after\nbody, _ := io.ReadAll(resp.Body)\nif bytes.HasPrefix(body, []byte(\"-----BEGIN\")) {\n    block, _ := pem.Decode(body)\n    body = block.Bytes\n}\ncert, err := x509.ParseCertificate(body)","handlingStrategy":"type-guard","validationCode":"// Validate DER structure before parsing\nif len(body) == 0 || body[0] != 0x30 { // not an ASN.1 SEQUENCE => not DER\n    return fmt.Errorf(\"endpoint did not return DER data\")\n}","typeGuard":"func isDERCertificate(b []byte) bool {\n    return len(b) > 2 && b[0] == 0x30 && (b[1]&0x80) == 0\n}","tryCatchPattern":"cert, err := fetchCertificate(client, url)\nvar parseErr *x509.CertificateInvalidError\nif err != nil && !errors.As(err, &parseErr) && strings.Contains(err.Error(), \"parsing intermediate certificate\") {\n    return nil, fmt.Errorf(\"AIA endpoint returned non-DER content: %w\", err)\n}","preventionTips":["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"],"tags":["azure","tls","certificates","der-parsing","aia-fetch"],"backgroundTag":"certificate-parse-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}