Pumpkin-MC/Pumpkin · error · AuthError

ECDSA signature error

Error message

ECDSA signature error: {0}

What it means

This variant wraps an underlying ecdsa::Error from the `ecdsa` crate, covering low-level ECDSA signature operation failures during JWT verification. It is distinct from InvalidSignature: it signals malformed signature encoding or internal crypto errors rather than a simple verification mismatch.

Solutions

  1. Check the signature byte length and format (64-byte r||s vs DER) before constructing the Signature
  2. Log the wrapped ecdsa::Error to distinguish malformed encoding from verification failure
  3. Pin consistent versions of the p256/ecdsa crates; format handling changed across versions
  4. Treat as an auth failure and reject the client, since the signature cannot be processed

Example fix

// before
let sig = Signature::<NistP256>::from_slice(&sig_bytes)?;
// after
let sig = Signature::<NistP256>::from_slice(&sig_bytes)
    .map_err(|e| {
        log::warn!("client sent malformed ECDSA signature: {e}");
        AuthError::Ecdsa(e)
    })?;
Defensive patterns

Strategy: try-catch

Validate before calling

// ECDSA P-256 signatures are 64 bytes (r || s)
fn signature_bytes_look_valid(sig: &[u8]) -> bool {
    sig.len() == 64
}

Type guard

fn is_raw_ecdsa_signature(sig: &[u8]) -> bool {
    sig.len() == 64
}

Try / catch

match jwt::verify(&token) {
    Err(jwt::Error::Ecdsa(e)) => {
        log::warn!("ECDSA operation failed on token: {e}; rejecting client");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Constructing a Signature from bytes of the wrong length/format, or calling sign/verify APIs where the ecdsa crate returns an operational error, during Mojang token validation.

Common situations: Tokens whose signature field is not exactly 64 bytes of r||s; corrupted DER-encoded signatures; using a crypto crate version whose signature format expectations changed.

Related errors


AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09). Data as JSON: /api/errors/afd48f1b9c4e2df6. Report an issue: GitHub.

Appendix: source

Thrown at crates/pumpkin-auth/src/jwt/mod.rs:54

    #[error("x5u not found in header")]
    MissingX5U,
    /// Indicates a failure in Base64 decoding.
    #[error("Base64 decoding failed: {0}")]
    Base64Decode(#[from] base64::DecodeError),
    /// Indicates a failure in parsing JSON data.
    #[error("JSON parse error: {0}")]
    JsonParse(#[from] serde_json::Error),
    /// Indicates a failure in building a public key from its representation.
    #[error("Public key build failed: {0}")]
    PublicKeyBuild(String),
    /// Indicates that the token was not signed by the trusted Mojang public key.
    #[error("Token not signed by trusted Mojang key")]
    MojangKeyMismatch,
    /// Indicates that the token's signature is invalid.
    #[error("Invalid signature")]
    InvalidSignature,
    /// Indicates an error related to ECDSA signature operations.
    #[error("ECDSA signature error: {0}")]
    Ecdsa(#[from] ecdsa::Error),
}

/// Decodes a Base64 URL-safe encoded string with no padding.
///
/// # Arguments
///
/// * `s` - The Base64 URL-safe encoded string to decode.
///
/// # Returns
///
/// A `Result` containing the decoded bytes or a `base64::DecodeError`.
pub fn decode_b64_url_nopad(s: &str) -> Result<Vec<u8>, base64::DecodeError> {
    general_purpose::URL_SAFE_NO_PAD.decode(s)
}

/// Decodes a standard Base64 encoded string.
///

View on GitHub (pinned to 8d4639e25a)