Skip to content

RsaPrivateKey::from_components might panic  #163

@Erik1000

Description

@Erik1000

Some internals of the num-bigint-dig crate might panic under some conditions and rsa does not check for these. Therefore, users of the rsa crate experience panics.

I've stumbled upon this while implementing some jose stuff, so this examples uses a key in JsonWebKey format:

use base64ct::{Base64UrlUnpadded, Encoding};
use rsa::{BigUint, RsaPrivateKey};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let n = BigUint::from_bytes_be(&base64ct::Base64UrlUnpadded::decode_vec("w8XZRYEMzHbSMJXM6kSS2BGicmF5o9_cdlklKYXwey_HpWvI6XtRA9jq_SksGudyvhrLeyNr5P8mUoNPy9DiweXLoidv9kRbU33XLIvJkqbjIXKSwgk9RuQn-v8BoJj8e2uc7sH0eS3RVDtNZ1V1dRbyspC-e2zh9lgcgTRMUVM99pWijcrVD_Wt9hqYlFLM2HA_IoE-9gRrtqrRDwSOrISz_7pzRtJ3RFe3rVkh6MdZVUZ3bNa-D3A6acYmU74YFoVTyKlgSqNmuzFc9yOMM3z4amzLdvfeX_nUxWJdurK80M93vdTqw4-WIzlkkNkUOXq1LUjwZOvtke-t3y87JQ")?);

    let e = BigUint::from_bytes_be(&Base64UrlUnpadded::decode_vec("AQAB")?);

    let d = BigUint::from_bytes_be(&Base64UrlUnpadded::decode_vec("QThDVsVURzV6dpchKhZoOTU-wg45IN_uKTsvhzLI17EmOLS8vRPI_JgiSO6Tc-8RKcXxbfdx9VsPIEQArGzNbj0o5r9urEM_jYQJ0BxNrd6NIlJyE9RSJrDRpOuZVjBBRLioEl5pHImoCACtm7Q7qiNX_Sb9Xk76xD-8V0rd9eVJJBLXpoSV_b_Q80IB9YeZvE8VxzG9dzVjyowzn59SkvG-59G6SteOvLMb9i1in1dzXEKBzauYrExCOlT5t0skJenBVxgD-RNa9Bkjed_4QcNtO3x08F7j2ziqa8iNOtQWRThiArCd14iM2YhdHIZrzPeOYj9DmXIThOlacQ1NAQ")?);

    // original p value
    let p = BigUint::from_bytes_be(&Base64UrlUnpadded::decode_vec("11_iIv_gwowCkC32vALSm3Po9vfirnhX5jIyh2U2mzH9PvLx4OaUQ_O2WWyYRkpTNivSf0erFNjf9xz2efAhVrMX4Y11XPNpWAAsmuawA23Ptgjy6-PGSSHj8PJXXK6jTpoYe6uDtYIe509ODYdTeBU6KNg91T0EbNSV_A4K40E")?);

    let q = BigUint::from_bytes_be(&Base64UrlUnpadded::decode_vec("6LNts0tPvK6J2XgLaWI9rvvztJNzKTznmA5WPDpkApPpKp9U2lDucAyjAIFYJxYuOPN4kJ6tBeFGJAKEU1rv7hW5gXbbkVt6r_v23lV_LQ841pEnsmwvdUEgw3gE7iEviI6ZuiaSQQ-yUSoiKQc0rXeXhdmyVck_y5s1JHl_cuU")?);

    // malicious p
    // when set to zero, it panics and the backtrace points to https://docs.rs/num-bigint-dig/latest/src/num_bigint_dig/algorithms/sub.rs.html#75-79
    // when set to 1 it panics because of a divison by zero, probably because of https://docs.rs/rsa/latest/src/rsa/key.rs.html#344-345
    let p = BigUint::from_bytes_be(&[0x0]);

    // `precompute` in this method will panic
    let private_key = RsaPrivateKey::from_components(n, e, d, vec![p, q]);

    // it could be catched here (maybe, dont know tbh), but since it panics, there's
    // no way
    private_key.validate().unwrap();
    Ok(())
}

This can lead to denial of service attacks if untrusted keys are parsed and isn't mention in the docs at all.
I haven't tried malicious pem/der encoded keys, but it seems realistic that they suffer from the same problem.

I've also noticed that the sign method might loop if an incorrect parameter is used but that can probably be prevented by using RsaPrivateKey::validate.

Also, I really don't like the way primes are passed to RsaPrivateKey::from_components since passing an array with a length < 2 leads to panic because of out of bounds access and that isn't mention in the docs either.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions