{"record":{"id":"36856a32107ef004","repo":"rathole-org/rathole","slug":"missing-pkcs12-or-pkcs12-password","errorCode":null,"errorMessage":"Missing `pkcs12` or `pkcs12_password`","messagePattern":"Missing `pkcs12` or `pkcs12_password`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/config.rs","lineNumber":317,"sourceCode":"            .as_ref()\n            .map_or(Ok(()), |u| match u.scheme() {\n                \"socks5\" => Ok(()),\n                \"http\" => Ok(()),\n                _ => Err(anyhow!(format!(\"Unknown proxy scheme: {}\", u.scheme()))),\n            })?;\n        match config.transport_type {\n            TransportType::Tcp => Ok(()),\n            TransportType::Tls => {\n                let tls_config = config\n                    .tls\n                    .as_ref()\n                    .ok_or_else(|| anyhow!(\"Missing TLS configuration\"))?;\n                if is_server {\n                    tls_config\n                        .pkcs12\n                        .as_ref()\n                        .and(tls_config.pkcs12_password.as_ref())\n                        .ok_or_else(|| anyhow!(\"Missing `pkcs12` or `pkcs12_password`\"))?;\n                }\n                Ok(())\n            }\n            TransportType::Noise => {\n                // The check is done in transport\n                Ok(())\n            }\n            TransportType::Websocket => Ok(()),\n        }\n    }\n\n    pub async fn from_file(path: &Path) -> Result<Config> {\n        let s: String = fs::read_to_string(path)\n            .await\n            .with_context(|| format!(\"Failed to read the config {:?}\", path))?;\n        Config::from_str(&s).with_context(|| {\n            \"Configuration is invalid. Please refer to the configuration specification.\"\n        })","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/rathole-org/rathole/blob/a292f7ed5402f840415fc6a53827da2f34337856/src/config.rs#L299-L335","documentation":"The TLS transport is enabled and a `[transport.tls]` section exists, but on the server side either `pkcs12` (the certificate file) or `pkcs12_password` is missing. The validator requires BOTH fields via `pkcs12.as_ref().and(pkcs12_password.as_ref())` before the server can load its identity.","triggerScenarios":"Running rathole in server mode with `transport.type = \"tls\"` where `[transport.tls]` defines only one of `pkcs12` or `pkcs12_password`, or neither; also when the keys are placed in the wrong table so they don't deserialize into `TlsConfig`.","commonSituations":"Server operators generate a certificate but forget the export password; they move the p12 file without updating the config; client-side configs mistakenly include server fields or omit them while the same config is reused for a server.","solutions":["Add both `pkcs12 = \"path/to/cert.p12\"` and `pkcs12_password = \"...\"` under `[transport.tls]` on the server","If you only have a PEM cert/key, convert it: `openssl pkcs12 -export -out cert.p12 -inkey key.pem -in cert.pem`","Confirm the config is intended for a server — clients don't need pkcs12; check `is_server` matches your role section","Verify the keys are inside `[transport.tls]`, not a sibling table"],"exampleFix":"# before\n[transport.tls]\npkcs12 = \"server.p12\"\n\n# after\n[transport.tls]\npkcs12 = \"server.p12\"\npkcs12_password = \"changeit\"","handlingStrategy":"validation","validationCode":"let raw: toml::Value = toml::from_str(&cfg)?;\nlet tls = &raw[\"transport\"][\"tls\"];\nlet is_server = raw.get(\"server\").is_some();\nif is_server && (tls[\"pkcs12\"].is_none() || tls[\"pkcs12_password\"].is_none()) {\n    return Err(\"server TLS config needs both pkcs12 and pkcs12_password\".into());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Store pkcs12 path and password together (e.g. via env/secret manager) and set both keys","Convert certs to PKCS#12 with openssl before writing the config","Confirm which role (server/client) a config file serves before reusing it"],"tags":["config","tls","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"a292f7ed5402f840415fc6a53827da2f34337856","analyzedAt":"2026-09-07T09:56:55.739Z","contentChangedAt":"2026-09-07T09:56:55.739Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}