aaif-goose/goose · error
Failed to encode PKCS#8: {}
Error message
Failed to encode PKCS#8: {} What it means
Second stage of native-tls key conversion: for a 'RSA PRIVATE KEY' (PKCS#1) PEM, convert_key_to_pkcs8_pem wraps the parsed PKCS#1 bytes in a PKCS8 PrivateKeyInfo and encodes them to DER. If the RSA key payload is structurally invalid (corrupted Base64 body, truncated modulus, zero-length integers), to_der() fails with 'Failed to encode PKCS#8: {err}'.
Source
Thrown at crates/goose-providers/src/api_client.rs:173
/// PKI, etc.) would get a cryptic "Failed to create identity" error and need to manually
/// run `openssl pkey -in key.pem -out key-pkcs8.pem`.
///
/// Note: the rustls code path (`Identity::from_pem`) accepts all formats natively,
/// so this conversion is only needed for native-tls.
#[cfg(feature = "native-tls")]
fn convert_key_to_pkcs8_pem(key_pem_str: &str) -> Result<String> {
use pkcs8::der::{Decode, Encode};
let parsed =
pem::parse(key_pem_str).map_err(|e| anyhow::anyhow!("Failed to parse PEM key: {}", e))?;
match parsed.tag() {
"PRIVATE KEY" => Ok(key_pem_str.to_string()),
"RSA PRIVATE KEY" => {
let info = pkcs8::PrivateKeyInfo::new(pkcs1::ALGORITHM_ID, parsed.contents());
let der_bytes = info
.to_der()
.map_err(|e| anyhow::anyhow!("Failed to encode PKCS#8: {}", e))?;
Ok(pem::encode(&pem::Pem::new("PRIVATE KEY", der_bytes)))
}
"EC PRIVATE KEY" => {
let ec_key = sec1::EcPrivateKey::from_der(parsed.contents())
.map_err(|e| anyhow::anyhow!("Failed to parse EC key: {}", e))?;
let curve_oid = ec_key
.parameters
.and_then(|p| p.named_curve())
.ok_or_else(|| {
anyhow::anyhow!(
"EC key missing curve parameters. Convert to PKCS#8: \
openssl pkey -in key.pem -out key-pkcs8.pem"
)
})?;
let algorithm = pkcs8::AlgorithmIdentifierRef {
oid: sec1::ALGORITHM_OID,
parameters: Some((&curve_oid).into()),
};View on GitHub (pinned to 3810898a74)
Solutions
- Validate the key independently: openssl rsa -in key.pem -check -noout
- Re-copy the key preserving line breaks, or re-transfer the file (checksum it)
- If validation fails, regenerate the key pair and reissue the certificate
- Or convert on a trusted machine with openssl pkey and ship the resulting PKCS#8 PEM ('PRIVATE KEY' tag) which bypasses this conversion path
Example fix
# before client_identity: key_path: /etc/goose/tls/client-key.pem # 'RSA PRIVATE KEY', corrupted Base64 # after (shell): validate then convert to PKCS#8 on a trusted host $ openssl rsa -in client-key.pem -check -noout $ openssl pkey -in client-key.pem -out client-key-pkcs8.pem # key_path: /etc/goose/tls/client-key-pkcs8.pem
Defensive patterns
Strategy: validation
Validate before calling
let key_text = std::fs::read_to_string(&key_path)?;
if key_text.contains("-----BEGIN RSA PRIVATE KEY-----") {
let ok = std::process::Command::new("openssl")
.args(["rsa", "-in", &key_path, "-check", "-noout"])
.status().map(|s| s.success()).unwrap_or(false);
anyhow::ensure!(ok, "RSA key is corrupt; regenerate or re-transfer it");
} Prevention
- Checksum TLS material after every copy (sha256sum on both ends)
- Avoid pasting keys through channels that wrap or truncate lines; use file transfer
- Convert to PKCS#8 once with openssl pkey and store that — the 'PRIVATE KEY' path needs no runtime conversion
- Regenerate and reissue on any checksum mismatch instead of hand-repairing Base64
When it happens
Trigger: The key file has correct PEM armor and tag 'RSA PRIVATE KEY', but the enclosed PKCS#1 structure is malformed — truncated file, mangled Base64 from copy-paste, or a key produced by a broken generator. pem::parse succeeded (error 258 did not fire); the DER-level re-encode is what fails.
Common situations: Keys pasted into YAML/JSON with line-wrap corruption; CI redacting chunks of long Base64 lines; partially overwritten secret files; keys truncated by editor line-length limits.
Related errors
- Failed to parse PEM key: {}
- Failed to create identity from cert and key: {}
- Failed to parse CA certificate bundle: {}
- Failed to parse EC key: {}
- EC key missing curve parameters. Convert to PKCS#8: openssl
AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16).
Data as JSON: /api/errors/1defaf85b888aa8b.
Report an issue: GitHub.