briansmith / ring

Safe, fast, small crypto using Rust
Other
3.77k stars 708 forks source link

failure to verify rsa signature on x509 csr #2007

Closed uglyoldbob closed 6 months ago

uglyoldbob commented 8 months ago

I have a certificate signing request that I have generated and am trying to validate the signature. Here is a minimal example of code to do the verification (rsa 4096).

use der::DecodePem;
use der::Encode;
use ring::signature::UnparsedPublicKey;
use ring::signature::RSA_PKCS1_2048_8192_SHA256;
use tokio::io::AsyncReadExt;
use yasna::parse_der;

pub async fn verify_request2<'a>(
    csr: &'a x509_cert::request::CertReq,
) -> Result<&'a x509_cert::request::CertReq, ()> {
    let info = csr.info.to_der().unwrap();
    let pubkey = &csr.info.public_key;
    let signature = &csr.signature;

    let p = &pubkey.subject_public_key;
    let pder = p.to_der().unwrap();

    let pkey = parse_der(&pder, |r| {
        let (data, _size) = r.read_bitvec_bytes()?;
        Ok(data)
    })
    .unwrap();

    let csr_key = UnparsedPublicKey::new(&RSA_PKCS1_2048_8192_SHA256, &pkey);
    println!("Cert is {:?}", csr_key);
    println!("info {:02X?}", info);
    csr_key
        .verify(&info, signature.as_bytes().unwrap())
        .map_err(|_| {
            println!("Error verifying the signature on the csr 1");
            ()
        })?;
    //TODO perform more validation of the csr
    return Ok(csr);
}

#[tokio::main]
async fn main() {
    println!("Running test2 program");

    let mut settings_con = Vec::new();
    let mut f = tokio::fs::File::open("./cert.pub").await.unwrap();
    f.read_to_end(&mut settings_con).await.unwrap();
    let pem = std::str::from_utf8(&settings_con).unwrap();
    println!("{}", pem);
    let csr = x509_cert::request::CertReq::from_pem(pem).unwrap();
    let a = verify_request2(&csr).await;
    println!("Result is {:?}", a);
}

And here is the certificate request. (Saved as cert.pub)

-----BEGIN CERTIFICATE REQUEST-----
MIIEoTCCAokCAQAwFDESMBAGA1UEAxMJc29tZXdoZXJlMIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEAymfD7A9sB8Lkz4FtJBMzuEST8qUqsDA0hk9pmtGo
Wsvnue0kblMRfTbqtRP6wm0I8cMlD43dTpbSqXsvvQOjHixVH59113JaP6/88GNw
WsEVGzUpYeRkF0Qk3xCk8mQ2jrIqY5jVBm4ZgaGd8jAtI/IywF+gasOwfoV871uG
lzRVUwj79t4xdtoRldgPHl+PnuwLhutNV4tj5Sb69ZullRNVCE4CY4IKCyQZhzAp
rDtNsa06IcMB5cvi3la43pVw6xc4Mm4682BZ2tS9NT+aaJGw9t/HBXBcABqBFzRE
PZFsKZNbsQ4wANjwnIeOAeqNf+Em9G53lHM9N+bUSD5bavguEuPTiyw5al7aWKD8
wZWVz1zyoAMNuHbhRXn9+JszRFvvDE5OEYUPdrsLPIKHHJ4nhA7WzTq6vEGLTtIJ
xhKb//YbDywffcp2/2IJnInUCAO4yn1ONksj54rkHCJNUbRA++PmFXXqPRZminQd
RVSel9spFQS7/x0qxZ7JzhRhMV7DJ0z+H4B1Jmc5r3OkctHd46g+TLJdDveWIAoa
fhjJXfpre2i3cctzSc51MCw34lk6gTOCOgnLafqsRLZBsSMocd9Yp8UnoV750Clw
HrfzNG+8MingkKFzVpkxAlm7x37rsqgEFpffPuGFsFA0LhzomxmOFhsQxR3rMGup
/tMCAwEAAaBIMA8GCSqGSIb3DQEJBzECDAAwDwYJKoZIhvcNAQkCMQIMADAkBgkq
hkiG9w0BCQ4xFzAVMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUA
A4ICAQAq6uVde2CR3XQVfHsg75t8l/UspgEC4oky4k6Y98G2+Dqjte/AEKri+OkL
eJcEAczc2HV0G3mEPLpkFjUPWP5c0TnJ2sJuQ6N4BzWGoKuWT9dvW2a1Prnei74D
l6qKz75PF0Rn5BZsVBhZvwqPfgMDzXDscJLMxGZcgnNVteJ7+PlRFCY/fWGHPvo1
N74nrkHTNpWYIbu21mxZ9SxYlm+d12B8jO71cAahR6B/xizyHXwiknRAVF4k9JoR
GZzeXGz10H2g1ZLb53b97NqOG33Bvp51JFoWmD4okuSZPz5BPC6cJimhUiJn3Njl
3YsJBfDSMlUvF9kHmuvlCl6VJNF0DolVBNO6bLnKePry40/KA2WhztTYKj7UsigE
lC+VfWEwG6EFVa/+ZmhhFRcklcZ6rQbCaOoEjhExhD8ihgx1qW+vKiNWiPRKp3iI
9ATInT/mDeV6T/QhPQT6owa7b9rtw2NRW7D5TkAHFIiAPPhzxzvSesCSnUpOnUpT
rLrZpbrM/poVQvbdu6euy+5V0BgJTkltqUyenqeDS/anmEOHfjQGRUu7T4bvbLG2
0sgU1C+NWTOUAVcqkAR3yHjZtjzDGUtpe5S6Abi1C11wbCdtE89RvKzMl4gIVUUS
45/gd3albZrXsRdzHcfxwf1TiU483wwioQSAZw8+jd6CgzEZ/A==
-----END CERTIFICATE REQUEST-----

Best I can tell so far is that in PKCS1::verify (src/rsa/padding/pkcs1.rs) m.read_bytes_to_end().as_slice_less_safe() does not equal calculated. The last 32 bytes of the vectors do not match.

openssl req -in ./cert.pub -noout -verify
Certificate request self-signature verify OK
uglyoldbob commented 6 months ago

It looks like if I extract the info portion of the request and run sha256sum on it, I get the same thing that ring calculates. Here are the hex contents of the info section

3082028902010030143112301006035504031309736f6d65776865726530
820222300d06092a864886f70d01010105000382020f003082020a028202
0100ca67c3ec0f6c07c2e4cf816d241333b84493f2a52ab03034864f699a
d1a85acbe7b9ed246e53117d36eab513fac26d08f1c3250f8ddd4e96d2a9
7b2fbd03a31e2c551f9f75d7725a3faffcf063705ac1151b352961e46417
4424df10a4f264368eb22a6398d5066e1981a19df2302d23f232c05fa06a
c3b07e857cef5b869734555308fbf6de3176da1195d80f1e5f8f9eec0b86
eb4d578b63e526faf59ba5951355084e0263820a0b2419873029ac3b4db1
ad3a21c301e5cbe2de56b8de9570eb1738326e3af36059dad4bd353f9a68
91b0f6dfc705705c001a811734443d916c29935bb10e3000d8f09c878e01
ea8d7fe126f46e7794733d37e6d4483e5b6af82e12e3d38b2c396a5eda58
a0fcc19595cf5cf2a0030db876e14579fdf89b33445bef0c4e4e11850f76
bb0b3c82871c9e27840ed6cd3ababc418b4ed209c6129bfff61b0f2c1f7d
ca76ff62099c89d40803b8ca7d4e364b23e78ae41c224d51b440fbe3e615
75ea3d16668a741d45549e97db291504bbff1d2ac59ec9ce1461315ec327
4cfe1f8075266739af73a472d1dde3a83e4cb25d0ef796200a1a7e18c95d
fa6b7b68b771cb7349ce75302c37e2593a8133823a09cb69faac44b641b1
232871df58a7c527a15ef9d029701eb7f3346fbc3229e090a17356993102
59bbc77eebb2a8041697df3ee185b050342e1ce89b198e161b10c51deb30
6ba9fed30203010001a048300f06092a864886f70d01090231020c00300f
06092a864886f70d01090731020c00302406092a864886f70d01090e3117
301530130603551d25040c300a06082b06010505070302

and the corresponding shasum 74aa8106d16b55c514359679681f3a35a96aea650c9c5c6987c09156b98d6b4c

This shasum matches the last 32 bytes of the vector calculated by ring

uglyoldbob commented 6 months ago

It appears the problem is in the x509_cert crate, the attributes of the CertReqInfo are not kept in the right order, causing the bytes to be different.