This project contains known security vulnerabilities. Find detailed information at the bottom.

Crate iron-hmac

Dependencies

(8 total, 3 outdated, 2 insecure, 1 possibly insecure)

CrateRequiredLatestStatus
 bodyparser^0.80.8.0up to date
 constant_time_eq^0.10.3.0out of date
 iron^0.60.6.1up to date
 openssl ⚠️^0.90.10.64out of date
 persistent^0.40.4.0up to date
 rust-crypto ⚠️^0.20.2.36insecure
 rustc-serialize ⚠️^0.30.3.25insecure
 url^1.62.5.0out of date

Dev dependencies

(2 total, 2 outdated, 1 possibly insecure)

CrateRequiredLatestStatus
 hyper ⚠️^0.111.3.1out of date
 reqwest^0.80.12.3out of date

Security Vulnerabilities

hyper: Flaw in hyper allows request smuggling by sending a body in GET requests

RUSTSEC-2020-0008

Vulnerable versions of hyper allow GET requests to have bodies, even if there is no Transfer-Encoding or Content-Length header. As per the HTTP 1.1 specification, such requests do not have bodies, so the body will be interpreted as a separate HTTP request.

This allows an attacker who can control the body and method of an HTTP request made by hyper to inject a request with headers that would not otherwise be allowed, as demonstrated by sending a malformed HTTP request from a Substrate runtime. This allows bypassing CORS restrictions. In combination with other vulnerabilities, such as an exploitable web server listening on loopback, it may allow remote code execution.

The flaw was corrected in hyper version 0.12.34.

hyper: Lenient `hyper` header parsing of `Content-Length` could allow request smuggling

RUSTSEC-2021-0078

hyper's HTTP header parser accepted, according to RFC 7230, illegal contents inside Content-Length headers. Due to this, upstream HTTP proxies that ignore the header may still forward them along if it chooses to ignore the error.

To be vulnerable, hyper must be used as an HTTP/1 server and using an HTTP proxy upstream that ignores the header's contents but still forwards it. Due to all the factors that must line up, an attack exploiting this vulnerability is unlikely.

hyper: Integer overflow in `hyper`'s parsing of the `Transfer-Encoding` header leads to data loss

RUSTSEC-2021-0079

When decoding chunk sizes that are too large, hyper's code would encounter an integer overflow. Depending on the situation, this could lead to data loss from an incorrect total size, or in rarer cases, a request smuggling attack.

To be vulnerable, you must be using hyper for any HTTP/1 purpose, including as a client or server, and consumers must send requests or responses that specify a chunk size greater than 18 exabytes. For a possible request smuggling attack to be possible, any upstream proxies must accept a chunk size greater than 64 bits.

rustc-serialize: Stack overflow in rustc_serialize when parsing deeply nested JSON

RUSTSEC-2022-0004

When parsing JSON using json::Json::from_str, there is no limit to the depth of the stack, therefore deeply nested objects can cause a stack overflow, which aborts the process.

Example code that triggers the vulnerability is

fn main() {
    let _ = rustc_serialize::json::Json::from_str(&"[0,[".repeat(10000));
}

serde is recommended as a replacement to rustc_serialize.

rust-crypto: Miscomputation when performing AES encryption in rust-crypto

RUSTSEC-2022-0011

The following Rust program demonstrates some strangeness in AES encryption - if you have an immutable key slice and then operate on that slice, you get different encryption output than if you operate on a copy of that key.

For these functions, we expect that extending a 16 byte key to a 32 byte key by repeating it gives the same encrypted data, because the underlying rust-crypto functions repeat key data up to the necessary key size for the cipher.

use crypto::{
    aes, blockmodes, buffer,
    buffer::{BufferResult, ReadBuffer, WriteBuffer},
    symmetriccipher,
};

fn encrypt(
    key: &[u8],
    iv: &[u8],
    data: &str,
) -> Result<String, symmetriccipher::SymmetricCipherError> {
    let mut encryptor =
        aes::cbc_encryptor(aes::KeySize::KeySize256, key, iv, blockmodes::PkcsPadding);

    let mut encrypted_data = Vec::<u8>::new();
    let mut read_buffer = buffer::RefReadBuffer::new(data.as_bytes());
    let mut buffer = [0; 4096];
    let mut write_buffer = buffer::RefWriteBuffer::new(&mut buffer);

    loop {
        let result = encryptor.encrypt(&mut read_buffer, &mut write_buffer, true)?;

        encrypted_data.extend(
            write_buffer
                .take_read_buffer()
                .take_remaining()
                .iter()
                .copied(),
        );

        match result {
            BufferResult::BufferUnderflow => break,
            BufferResult::BufferOverflow => {}
        }
    }

    Ok(hex::encode(encrypted_data))
}

fn working() {
    let data = "data";
    let iv = [
        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE,
        0xFF,
    ];
    let key = [
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
        0x0F,
    ];
    // The copy here makes the code work.
    let key_copy = key;
    let key2: Vec<u8> = key_copy.iter().cycle().take(32).copied().collect();
    println!("key1:{} key2: {}", hex::encode(&key), hex::encode(&key2));

    let x1 = encrypt(&key, &iv, data).unwrap();
    println!("X1: {}", x1);

    let x2 = encrypt(&key2, &iv, data).unwrap();
    println!("X2: {}", x2);

    assert_eq!(x1, x2);
}

fn broken() {
    let data = "data";
    let iv = [
        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE,
        0xFF,
    ];
    let key = [
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
        0x0F,
    ];
    // This operation shouldn't affect the contents of key at all.
    let key2: Vec<u8> = key.iter().cycle().take(32).copied().collect();
    println!("key1:{} key2: {}", hex::encode(&key), hex::encode(&key2));

    let x1 = encrypt(&key, &iv, data).unwrap();
    println!("X1: {}", x1);

    let x2 = encrypt(&key2, &iv, data).unwrap();
    println!("X2: {}", x2);

    assert_eq!(x1, x2);
}

fn main() {
    working();
    broken();
}

The output from this program:

     Running `target/host/debug/rust-crypto-test`
key1:000102030405060708090a0b0c0d0e0f key2: 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
X1: 90462bbe32965c8e7ea0addbbed4cddb
X2: 90462bbe32965c8e7ea0addbbed4cddb
key1:000102030405060708090a0b0c0d0e0f key2: 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
X1: 26e847e5e7df1947bf82a650548a7d5b
X2: 90462bbe32965c8e7ea0addbbed4cddb
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `"26e847e5e7df1947bf82a650548a7d5b"`,
 right: `"90462bbe32965c8e7ea0addbbed4cddb"`', src/main.rs:83:5

Notably, the X1 key in the broken() test changes every time after rerunning the program.

openssl: `openssl` `X509NameBuilder::build` returned object is not thread safe

RUSTSEC-2023-0022

OpenSSL has a modified bit that it can set on on X509_NAME objects. If this bit is set then the object is not thread-safe even when it appears the code is not modifying the value.

Thanks to David Benjamin (Google) for reporting this issue.

openssl: `openssl` `SubjectAlternativeName` and `ExtendedKeyUsage::other` allow arbitrary file read

RUSTSEC-2023-0023

SubjectAlternativeName and ExtendedKeyUsage arguments were parsed using the OpenSSL function X509V3_EXT_nconf. This function parses all input using an OpenSSL mini-language which can perform arbitrary file reads.

Thanks to David Benjamin (Google) for reporting this issue.

openssl: `openssl` `X509Extension::new` and `X509Extension::new_nid` null pointer dereference

RUSTSEC-2023-0024

These functions would crash when the context argument was None with certain extension types.

Thanks to David Benjamin (Google) for reporting this issue.

openssl: `openssl` `X509VerifyParamRef::set_host` buffer over-read

RUSTSEC-2023-0044

When this function was passed an empty string, openssl would attempt to call strlen on it, reading arbitrary memory until it reached a NUL byte.