{"record":{"id":"992dfc19848a8dae","repo":"nats-io/nats-server","slug":"failed-to-parse-ocsp-response-w","errorCode":null,"errorMessage":"failed to parse OCSP response: %w","messagePattern":"failed to parse OCSP response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ocsp/ocsp.go","lineNumber":243,"sourceCode":"\t\tt.Fatalf(\"failed to decode PEM %s\", pemPath)\n\t}\n\treturn block\n}\n\nfunc GetOCSPStatus(s tls.ConnectionState) (*ocsp.Response, error) {\n\tif len(s.VerifiedChains) == 0 {\n\t\treturn nil, fmt.Errorf(\"missing TLS verified chains\")\n\t}\n\tchain := s.VerifiedChains[0]\n\n\tif got, want := len(chain), 2; got < want {\n\t\treturn nil, fmt.Errorf(\"incomplete cert chain, got %d, want at least %d\", got, want)\n\t}\n\tleaf, issuer := chain[0], chain[1]\n\n\tresp, err := ocsp.ParseResponseForCert(s.OCSPResponse, leaf, issuer)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse OCSP response: %w\", err)\n\t}\n\tif err := resp.CheckSignatureFrom(issuer); err != nil {\n\t\treturn resp, err\n\t}\n\treturn resp, nil\n}\n\nfunc SetOCSPStatus(t *testing.T, ocspURL, certPEM string, status int) {\n\tt.Helper()\n\n\tcert := parseCertPEM(t, certPEM)\n\n\thc := &http.Client{Timeout: 10 * time.Second}\n\tresp, err := hc.Post(\n\t\tfmt.Sprintf(\"%s/statuses/%s\", ocspURL, cert.SerialNumber),\n\t\t\"\",\n\t\tstrings.NewReader(fmt.Sprint(status)),\n\t)","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/internal/ocsp/ocsp.go#L225-L261","documentation":"After extracting the leaf and issuer from the verified chain, GetOCSPStatus parses the stapled OCSPResponse via ocsp.ParseResponseForCert. If the response bytes are missing, malformed, or don't correspond to the certificate, the underlying parse error is wrapped with this message.","triggerScenarios":"Calling GetOCSPStatus on a connection where tls.ConnectionState.OCSPResponse is empty or not a valid DER-encoded OCSP response for the leaf/issuer pair.","commonSituations":"Client did not staple an OCSP response (empty OCSPResponse); stapled response is stale, re-signed, or for a different serial; intermediary proxy stripped the stapled response.","solutions":["Verify OCSPResponse is non-empty before calling GetOCSPStatus and skip OCSP checks if absent","Confirm the OCSP responder serves a response for the leaf's serial signed by the expected issuer","Re-staple: have the client fetch a fresh OCSP response from the CA's responder"],"exampleFix":"// before\nresp, err := GetOCSPStatus(cs)\n// after\nif len(cs.OCSPResponse) == 0 {\n    return nil, errors.New(\"no stapled OCSP response\")\n}\nresp, err := GetOCSPStatus(cs)","handlingStrategy":"validation","validationCode":"cs := conn.ConnectionState()\nif len(cs.OCSPResponse) == 0 {\n    return errors.New(\"no stapled OCSP response to check\")\n}","typeGuard":null,"tryCatchPattern":"resp, err := GetOCSPStatus(cs)\nif err != nil {\n    var inner error\n    if strings.HasPrefix(err.Error(), \"failed to parse OCSP response:\") {\n        errors.As(err, &inner) // inspect underlying ocsp/asn1 error\n        return nil, fmt.Errorf(\"stapled OCSP unusable: %w\", inner)\n    }\n    return err\n}","preventionTips":["Verify clients staple fresh OCSP responses (must-staple where possible)","Ensure responder responses match the leaf serial and issuer","Watch for proxies that strip tls-native OCSP stapling"],"tags":["tls","ocsp","asn1","certificate"],"backgroundTag":"ocsp-response-parse-failed","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}