aaif-goose/goose · error

EC key missing curve parameters. Convert to PKCS#8: openssl

Error message

EC key missing curve parameters. Convert to PKCS#8: openssl pkey -in key.pem -out key-pkcs8.pem

What it means

The SEC1 EC private key parsed successfully, but ec_key.parameters.named_curve() returned None, meaning the key does not identify its curve by a standard named-curve OID (prime256v1, secp384r1, ...). goose's EC-to-PKCS#8 re-wrapper needs a named curve to build the PKCS#8 AlgorithmIdentifier, so it refuses the key and tells you to convert it with openssl pkey.

Source

Thrown at crates/goose-providers/src/api_client.rs:183

        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()),
            };
            let info = pkcs8::PrivateKeyInfo::new(algorithm, 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)))
        }
        tag => Err(anyhow::anyhow!(
            "Unsupported key format '{}'. Expected PKCS#8, PKCS#1, or SEC1. \
             Convert with: openssl pkey -in key.pem -out key-pkcs8.pem",
            tag

View on GitHub (pinned to 3810898a74)

Solutions

  1. Convert the key so the curve becomes a named OID: openssl pkey -in key.pem -out key-pkcs8.pem (PKCS#8 also bypasses this whole conversion path)
  2. If openssl also refuses, regenerate the key on a standard named curve: openssl ecparam -name prime256v1 -genkey -noout -out key.pem
  3. Verify the curve is representable: openssl ec -in key.pem -noout -text should show 'ASN1 OID: prime256v1' (or secp384r1/secp521r1)

Example fix

# before: parameters omitted or explicit
openssl ec -in old-key.pem -noout -text   # shows no 'ASN1 OID' line

# after
openssl pkey -in old-key.pem -out key-pkcs8.pem   # named curve + PKCS#8 wrapper
Defensive patterns

Strategy: validation

Validate before calling

fn has_named_curve(path: &str) -> anyhow::Result<()> {
    let out = std::process::Command::new("openssl")
        .args(["ec", "-in", path, "-noout", "-text"])
        .output()?;
    let text = String::from_utf8_lossy(&out.stdout);
    anyhow::ensure!(out.status.success() && text.contains("ASN1 OID:"),
        "key lacks a named curve; openssl pkey -in {path} -out {path}.pkcs8");
    Ok(())
}

Try / catch

match build_client_with_mtls(cert, key) {
    Err(e) if e.to_string().contains("missing curve parameters") => {
        // auto-remediate once: convert with `openssl pkey`, retry, else surface the hint
    }
    r => r?,
}

Prevention

When it happens

Trigger: A '-----BEGIN EC PRIVATE KEY-----' mTLS key whose parameters use an explicit/encoded curve (generated by very old OpenSSL, BouncyCastle, or an HSM export) or omit the curve entirely, supplied via TlsConfig::with_client_cert_and_key under the native-tls feature.

Common situations: Corporate PKI or IoT device certificates issuing keys with explicit parameters for curve agility; keys moved between crypto libraries that re-encode parameters; exotic curves (brainpool via explicit encoding) that have no registered named-curve OID in the sec1 crate's table.

Related errors


AI-assisted analysis of aaif-goose/goose@3810898a74 (2026-08-16). Data as JSON: /api/errors/f51e9682e932d898. Report an issue: GitHub.