ducaale/xh · error

message-signature: RSA private keys require an explicit…

Error message

message-signature: RSA private keys require an explicit algorithm. Use --unstable-m-sig-alg=rsa-v1_5-sha256 or --unstable-m-sig-alg=rsa-pss-sha512

What it means

When the signing key material is a PEM RSA private key, build_signing_key refuses to guess the algorithm and requires the user to select one explicitly via --unstable-m-sig-alg (rsa-v1_5-sha256 or rsa-pss-sha512), since RSA PEM keys alone don't determine the signature scheme.

Solutions

  1. Pass --unstable-m-sig-alg=rsa-v1_5-sha256 (classic RSASSA-PKCS1v15)
  2. Or pass --unstable-m-sig-alg=rsa-pss-sha512 (RSASSA-PSS)
  3. Or use a non-RSA key (ed25519/ECDSA) if explicit algorithm selection is undesirable

Example fix

# before
http --message-signature key=rsa_key.pem ...
# after
http --message-signature key=rsa_key.pem --unstable-m-sig-alg=rsa-v1_5-sha256 ...
Defensive patterns

Strategy: validation

Validate before calling

// before signing, require an explicit algorithm for RSA PEM keys
if pem_contains_rsa_private_key(key_material) && m_sig_alg.is_none() {
    anyhow::bail!("RSA keys require --unstable-m-sig-alg=rsa-v1_5-sha256 or rsa-pss-sha512");
}

Type guard

fn needs_explicit_alg(pem: &str, alg: Option<&AlgorithmName>) -> bool {
    alg.is_none() && pem.contains("BEGIN") && parse_pem_secret_key(pem, &[AlgorithmName::RsaV1_5Sha256, AlgorithmName::RsaPssSha512]).is_some()
}

Try / catch

match sign_request(&req, &components, &key) {
    Ok(s) => s,
    Err(e) if e.to_string().contains("RSA private keys require an explicit algorithm") => {
        eprintln!("re-run with --unstable-m-sig-alg=rsa-v1_5-sha256 or rsa-pss-sha512");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: sign_request called with an RSA PEM private key and no explicit algorithm (m_sig_alg unset or set to a non-RSA algorithm).

Common situations: Users supplying a standard RSA .pem signing key without the --unstable-m-sig-alg flag; defaults tuned for ed25519/ECDSA keys.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13). Data as JSON: /api/errors/03df4331000b349e. Report an issue: GitHub.

Appendix: source

Thrown at src/message_signature.rs:271

        if pem.contains("-----BEGIN") {
            if let Some(secret) = parse_pem_secret_key(
                pem,
                &[
                    AlgorithmName::Ed25519,
                    AlgorithmName::EcdsaP256Sha256,
                    AlgorithmName::EcdsaP384Sha384,
                ],
            ) {
                let alg = secret.alg();
                return Ok((MessageSigningKey::Secret(secret, key_id.to_string()), alg));
            }
            if parse_pem_secret_key(
                pem,
                &[AlgorithmName::RsaV1_5Sha256, AlgorithmName::RsaPssSha512],
            )
            .is_some()
            {
                bail!(
                    "message-signature: RSA private keys require an explicit algorithm. Use --unstable-m-sig-alg=rsa-v1_5-sha256 or --unstable-m-sig-alg=rsa-pss-sha512"
                );
            }
            bail!(
                "message-signature: Failed to parse PEM private key. Supported algorithms: ed25519, ecdsa-p256-sha256, ecdsa-p384-sha384, rsa-v1_5-sha256, rsa-pss-sha512"
            );
        }
    }

    build_hmac_signing_key(key_material, key_id)
}

fn build_hmac_signing_key(
    key_material: &[u8],
    key_id: &str,
) -> Result<(MessageSigningKey, AlgorithmName)> {
    let encoded = STANDARD.encode(key_material);
    let shared_key = SharedKey::from_base64(&AlgorithmName::HmacSha256, &encoded)

View on GitHub (pinned to 2404aceecc)