{"record":{"id":"ab7cc04077749aa8","repo":"cloudflare/pingora","slug":"failed-to-parse-certificate-from-der-format","errorCode":null,"errorMessage":"Failed to parse certificate from DER format.","messagePattern":"Failed to parse certificate from DER format\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pingora-core/src/utils/tls/rustls.rs","lineNumber":62,"sourceCode":"    get_organization_x509(x509cert.borrow_cert())\n}\n\n/// Return the organization associated with the X509 certificate.\n/// see https://en.wikipedia.org/wiki/X.509#Structure_of_a_certificate\npub fn get_organization_x509(x509cert: &X509Certificate<'_>) -> Option<String> {\n    x509cert\n        .subject\n        .iter_organization()\n        .filter_map(|a| a.as_str().ok())\n        .map(|a| a.to_string())\n        .reduce(|cur, next| cur + &next)\n}\n\n/// Return the organization associated with the X509 certificate (as bytes).\n/// see https://en.wikipedia.org/wiki/X.509#Structure_of_a_certificate\npub fn get_organization_serial_bytes(cert: &[u8]) -> Result<(Option<String>, String)> {\n    let (_, x509cert) = x509_parser::certificate::X509Certificate::from_der(cert)\n        .expect(\"Failed to parse certificate from DER format.\");\n\n    get_organization_serial_x509(&x509cert)\n}\n\n/// Return the organization unit associated with the X509 certificate.\n/// see https://en.wikipedia.org/wiki/X.509#Structure_of_a_certificate\npub fn get_organization_unit(x509cert: &WrappedX509) -> Option<String> {\n    x509cert\n        .borrow_cert()\n        .subject\n        .iter_organizational_unit()\n        .filter_map(|a| a.as_str().ok())\n        .map(|a| a.to_string())\n        .reduce(|cur, next| cur + &next)\n}\n\n/// Get a combination of the common names for the given certificate\n/// see https://en.wikipedia.org/wiki/X.509#Structure_of_a_certificate","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/cloudflare/pingora/blob/0046038bd402bc82912da862dadf9a479f31e9f1/pingora-core/src/utils/tls/rustls.rs#L44-L80","documentation":"get_organization_serial_bytes() in pingora's rustls TLS utils parses a DER-encoded X509 certificate with x509-parser and expects success. DER parsing fails when the bytes are not a complete valid DER certificate — PEM text (-----BEGIN----- armor) or base64 passed where raw DER is required, truncated/corrupted files, or empty input. The panic aborts the calling task.","triggerScenarios":"Calling get_organization_serial_bytes(cert_bytes) (or a pingora path extracting org/serial from a cert) with bytes that are PEM text, base64, truncated, or otherwise not strict DER.","commonSituations":"Reading a .pem file into bytes and passing them where DER is expected; chain files where the wrong offset/bytes are used; certificates corrupted in transit or by secrets-injection systems; empty files from failed mounts.","solutions":["Ensure the input is DER: `openssl x509 -in cert.pem -outform DER -out cert.der` and pass those bytes","Verify before the call: `openssl x509 -inform DER -in cert.der -noout` must succeed","If you only have PEM, decode the CERTIFICATE block's base64 payload first, or parse fallibly yourself with X509Certificate::from_der instead of hitting pingora's expect","Check for truncation/corruption — compare size and checksum against the cert source"],"exampleFix":"// before: PEM text passed where DER is expected — panics\nlet (org, serial) = get_organization_serial_bytes(&pem_bytes);\n\n// after: extract the DER payload from the PEM block first\nuse x509_parser::pem::Pem;\nlet pem = Pem::iter_from_buffer(&pem_bytes).next().unwrap().unwrap();\nlet (org, serial) = get_organization_serial_bytes(&pem.contents);","handlingStrategy":"validation","validationCode":"// Reject invalid DER before calling helpers that expect() it\nfn is_valid_der_cert(bytes: &[u8]) -> bool {\n    x509_parser::certificate::X509Certificate::from_der(bytes).is_ok()\n}\n\nif !is_valid_der_cert(&cert_bytes) {\n    anyhow::bail!(\"cert is not valid DER — convert PEM first: openssl x509 -outform DER\");\n}","typeGuard":"fn is_der_cert(bytes: &[u8]) -> bool {\n    // cheap structural check: DER SEQUENCE tag, then full parse for certainty\n    bytes.first() == Some(&0x30)\n        && x509_parser::certificate::X509Certificate::from_der(bytes).is_ok()\n}","tryCatchPattern":"// If you must call code that may panic on bad certs, isolate it\nlet res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    get_organization_serial_bytes(&cert_bytes)\n}));\nmatch res {\n    Ok(v) => { /* use org/serial */ }\n    Err(_) => { /* bad DER input: log which cert failed and skip */ }\n}","preventionTips":["Standardize on one encoding in your pipeline and convert at the boundary (openssl x509 -outform DER)","Validate certificates during config load, never on the serving path","Never assume chain files are single certs — parse per block"],"tags":["rust","pingora","tls","x509","certificate","der","parsing","panic"],"backgroundTag":"certificate-parsing-failed","analyzedSha":"0046038bd402bc82912da862dadf9a479f31e9f1","analyzedAt":"2026-08-16T21:33:22.341Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}