{"record":{"id":"83dd3b092fb10423","repo":"hyperledger/fabric","slug":"failed-to-parse-certificate","errorCode":null,"errorMessage":"failed to parse certificate","messagePattern":"failed to parse certificate","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/util.go","lineNumber":835,"sourceCode":"\t\tif height >= maxHeight {\n\t\t\tmaxHeight = height\n\t\t\tmostUpToDateEndpoint = endpoint\n\t\t}\n\t}\n\treturn mostUpToDateEndpoint, maxHeight, nil\n}\n\nfunc EncodeTimestamp(t *timestamppb.Timestamp) []byte {\n\tb := make([]byte, 8)\n\tbinary.LittleEndian.PutUint64(b, uint64(t.Seconds))\n\treturn b\n}\n\n// ExtractPublicKeyFromCert extracts the public key from an X.509 certificate\nfunc ExtractPublicKeyFromCert(der []byte) ([]byte, error) {\n\tcert, err := x509.ParseCertificate(der)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to parse certificate\")\n\t}\n\n\treturn x509.MarshalPKIXPublicKey(cert.PublicKey)\n}\n\nfunc CompareCertPublicKeys(cert1, cert2 []byte) (bool, error) {\n\t// Extract public key using the same approach as IsConsenterOfChannel\n\tbl, _ := pem.Decode(cert1)\n\tif bl == nil {\n\t\treturn false, errors.Errorf(\"node identity certificate %s is not a valid PEM\", string(cert1))\n\t}\n\n\tpublicKey1, err := ExtractPublicKeyFromCert(bl.Bytes)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\tbl, _ = pem.Decode(cert2)","sourceCodeStart":817,"sourceCodeEnd":853,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/util.go#L817-L853","documentation":"ExtractPublicKeyFromCert parses raw DER certificate bytes with x509.ParseCertificate and wraps any failure with this message before marshaling the public key. It is the DER-level entry point, unlike VerifySignature which takes PEM.","triggerScenarios":"Passing malformed DER bytes, a PEM block's Bytes taken incorrectly, or a certificate with an encoding the local x509 parser rejects (unknown critical extension, truncated ASN.1) into ExtractPublicKeyFromCert or CompareCertPublicKeys.","commonSituations":"Caller passed a full PEM file (with BEGIN/END headers) instead of bare DER (bl.Bytes); certificates generated by non-Go tooling with unusual encodings; corrupted cert storage.","solutions":["Pass only the DER payload (the Bytes field of the pem.Block), not the PEM-encoded text","Validate the cert with openssl x509 -inform DER before calling","Read the wrapped inner error to identify the specific ASN.1 problem and re-export the certificate if corrupted","If starting from PEM, decode first: blk, _ := pem.Decode(data); use blk.Bytes"],"exampleFix":"// before\npk, err := ExtractPublicKeyFromCert(pemFileBytes) // PEM text, not DER\n// after\nblk, _ := pem.Decode(pemFileBytes)\npk, err := ExtractPublicKeyFromCert(blk.Bytes)","handlingStrategy":"validation","validationCode":"if len(der) == 0 { return errors.New(\"empty DER input\") }\nif _, err := x509.ParseCertificate(der); err != nil {\n    return fmt.Errorf(\"not a valid DER certificate: %w\", err)\n}","typeGuard":"func isDERCertificate(der []byte) bool {\n    _, err := x509.ParseCertificate(der)\n    return err == nil\n}","tryCatchPattern":"pk, err := cluster.ExtractPublicKeyFromCert(der)\nif err != nil && strings.Contains(err.Error(), \"failed to parse certificate\") {\n    return fmt.Errorf(\"pass DER bytes (pemBlock.Bytes), not PEM text: %w\", err)\n}","preventionTips":["Pass pemBlock.Bytes (DER), never the raw PEM-encoded file","Validate inputs with openssl x509 -inform DER before use","Keep a helper that normalizes PEM-or-DER input to DER","Read the wrapped inner error for the specific ASN.1 cause"],"tags":["x509","certificate","der"],"backgroundTag":"certificate-parse-failed","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}