nautechsystems/nautilus_trader · error

PEM does not contain a private key

Error message

PEM does not contain a private key

What it means

After successfully parsing the PEM structure, `rsa_signature` checks that the PEM tag ends with 'PRIVATE KEY' (i.e. 'PRIVATE KEY' for PKCS#8 or 'RSA PRIVATE KEY'). This error means the PEM block is well-formed but is not a private key — commonly a public key, certificate, or another object type.

Source

Thrown at crates/cryptography/src/signing.rs:55

///
/// # Errors
///
/// Returns an error if:
/// - `data` is empty.
/// - `private_key_pem` is not a valid PEM-encoded PKCS#8 RSA private key or cannot be parsed.
/// - Signature generation fails due to key or cryptographic errors.
pub fn rsa_signature(private_key_pem: &str, data: &str) -> anyhow::Result<String> {
    if data.is_empty() {
        anyhow::bail!("Query string cannot be empty");
    }

    // Remove PEM headings and decode to DER bytes using the `pem` crate
    let pem = pem::parse(private_key_pem.trim())
        .map_err(|e| anyhow::anyhow!("Failed to parse PEM: {e}"))?;

    // Ensure this is a private key
    if !pem.tag().ends_with("PRIVATE KEY") {
        anyhow::bail!("PEM does not contain a private key");
    }

    // Construct RSA key pair from PKCS#8 DER bytes
    let key_pair = KeyPair::from_pkcs8(pem.contents())
        .map_err(|_| anyhow::anyhow!("Failed to decode RSA private key"))?;

    // Prepare RNG and output buffer (signature length = modulus length)
    let rng = lc_rand::SystemRandom::new();
    let mut signature = vec![0u8; key_pair.public_modulus_len()];

    key_pair
        .sign(
            &lc_signature::RSA_PKCS1_SHA256,
            &rng,
            data.as_bytes(),
            &mut signature,
        )
        .map_err(|_| anyhow::anyhow!("Failed to generate RSA signature"))?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Point the key path/env var at the actual private key PEM file (BEGIN PRIVATE KEY or BEGIN RSA PRIVATE KEY)
  2. If you only have a certificate, extract the private key from where it was generated — you cannot sign with a certificate
  3. Generate a proper key: openssl genpkey -algorithm RSA -out key.pem
  4. Check for 'ENCRYPTED PRIVATE KEY' — decrypt it (openssl pkcs8 -topk8 -nocrypt) since this API expects an unencrypted key

Example fix

// before
let pem = std::fs::read_to_string("cert.pem")?; // certificate, not a key
// after
let pem = std::fs::read_to_string("private_key.pem")?; // -----BEGIN PRIVATE KEY-----
Defensive patterns

Strategy: validation

Validate before calling

let pem = pem::parse(key_text.trim())?;
if !pem.tag().ends_with("PRIVATE KEY") {
    return Err(anyhow::anyhow!("expected a private key PEM, got tag: {}", pem.tag()));
}

Type guard

fn pem_is_private_key(s: &str) -> bool {
    pem::parse(s.trim())
        .map(|p| p.tag().ends_with("PRIVATE KEY"))
        .unwrap_or(false)
}

Try / catch

match rsa_signature(&key, query) {
    Ok(sig) => use(sig),
    Err(e) if e.to_string().contains("does not contain a private key") => {
        tracing::error!("configured key is a public key/certificate");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `rsa_signature` with a PEM whose tag is e.g. 'PUBLIC KEY', 'CERTIFICATE', or 'ENCRYPTED PRIVATE KEY' (which also ends with 'PRIVATE KEY'... note encrypted keys do end with that tag but will then fail later at decode). The immediate trigger is any tag not ending in 'PRIVATE KEY'.

Common situations: Pointing the config at the public key or TLS certificate file instead of the private key; a keychain/cloud secret returning the certificate chain; mixing up the files generated alongside the keypair.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/dee939bc51009280. Report an issue: GitHub.