use {bssl, c, error, private, signature};
use super::{BIGNUM, PositiveInteger, PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN,
RSAParameters, parse_public_key};
use untrusted;
impl signature::VerificationAlgorithm for RSAParameters {
fn verify(&self, public_key: untrusted::Input, msg: untrusted::Input,
signature: untrusted::Input)
-> Result<(), error::Unspecified> {
let public_key = try!(parse_public_key(public_key));
verify_rsa(self, public_key, msg, signature)
}
}
impl private::Private for RSAParameters {}
macro_rules! rsa_params {
( $VERIFY_ALGORITHM:ident, $min_bits:expr, $PADDING_ALGORITHM:expr,
$doc_str:expr ) => {
#[doc=$doc_str]
pub static $VERIFY_ALGORITHM: RSAParameters =
RSAParameters {
padding_alg: $PADDING_ALGORITHM,
min_bits: $min_bits,
};
}
}
rsa_params!(RSA_PKCS1_2048_8192_SHA1, 2048, &super::padding::RSA_PKCS1_SHA1,
"Verification of signatures using RSA keys of 2048-8192 bits,
PKCS#1.5 padding, and SHA-1.\n\nSee \"`RSA_PKCS1_*` Details\" in
`ring::signature`'s module-level documentation for more details.");
rsa_params!(RSA_PKCS1_2048_8192_SHA256, 2048, &super::RSA_PKCS1_SHA256,
"Verification of signatures using RSA keys of 2048-8192 bits,
PKCS#1.5 padding, and SHA-256.\n\nSee \"`RSA_PKCS1_*` Details\" in
`ring::signature`'s module-level documentation for more details.");
rsa_params!(RSA_PKCS1_2048_8192_SHA384, 2048, &super::RSA_PKCS1_SHA384,
"Verification of signatures using RSA keys of 2048-8192 bits,
PKCS#1.5 padding, and SHA-384.\n\nSee \"`RSA_PKCS1_*` Details\" in
`ring::signature`'s module-level documentation for more details.");
rsa_params!(RSA_PKCS1_2048_8192_SHA512, 2048, &super::RSA_PKCS1_SHA512,
"Verification of signatures using RSA keys of 2048-8192 bits,
PKCS#1.5 padding, and SHA-512.\n\nSee \"`RSA_PKCS1_*` Details\" in
`ring::signature`'s module-level documentation for more details.");
rsa_params!(RSA_PKCS1_3072_8192_SHA384, 3072, &super::RSA_PKCS1_SHA384,
"Verification of signatures using RSA keys of 3072-8192 bits,
PKCS#1.5 padding, and SHA-384.\n\nSee \"`RSA_PKCS1_*` Details\" in
`ring::signature`'s module-level documentation for more details.");
rsa_params!(RSA_PSS_2048_8192_SHA256, 2048, &super::RSA_PSS_SHA256,
"Verification of signatures using RSA keys of 2048-8192 bits,
PSS padding, and SHA-256.\n\nSee \"`RSA_PSS_*` Details\" in
`ring::signature`'s module-level documentation for more details.");
rsa_params!(RSA_PSS_2048_8192_SHA384, 2048, &super::RSA_PSS_SHA384,
"Verification of signatures using RSA keys of 2048-8192 bits,
PSS padding, and SHA-384.\n\nSee \"`RSA_PSS_*` Details\" in
`ring::signature`'s module-level documentation for more details.");
rsa_params!(RSA_PSS_2048_8192_SHA512, 2048, &super::RSA_PSS_SHA512,
"Verification of signatures using RSA keys of 2048-8192 bits,
PSS padding, and SHA-512.\n\nSee \"`RSA_PSS_*` Details\" in
`ring::signature`'s module-level documentation for more details.");
pub fn verify_rsa(params: &RSAParameters,
(n, e): (untrusted::Input, untrusted::Input),
msg: untrusted::Input, signature: untrusted::Input)
-> Result<(), error::Unspecified> {
let signature = signature.as_slice_less_safe();
let mut decoded = [0u8; PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN];
if signature.len() > decoded.len() {
return Err(error::Unspecified);
}
let n = try!(PositiveInteger::from_be_bytes(n));
let e = try!(PositiveInteger::from_be_bytes(e));
let decoded = &mut decoded[..signature.len()];
try!(bssl::map_result(unsafe {
GFp_rsa_public_decrypt(decoded.as_mut_ptr(), decoded.len(), n.as_ref(),
e.as_ref(), signature.as_ptr(), signature.len(),
params.min_bits,
PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN * 8)
}));
untrusted::Input::from(decoded).read_all(
error::Unspecified,
|m| params.padding_alg.verify(msg, m, n.bit_length()))
}
extern {
fn GFp_rsa_public_decrypt(out: *mut u8, out_len: c::size_t,
public_key_n: *const BIGNUM,
public_key_e: *const BIGNUM,
ciphertext: *const u8,
ciphertext_len: c::size_t, min_bits: c::size_t,
max_bits: c::size_t) -> c::int;
}
#[cfg(test)]
mod tests {
use {der, error, signature, test};
use untrusted;
#[test]
fn test_signature_rsa_pkcs1_verify() {
test::from_file("src/rsa/rsa_pkcs1_verify_tests.txt",
|section, test_case| {
assert_eq!(section, "");
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA1" => &signature::RSA_PKCS1_2048_8192_SHA1,
"SHA256" => &signature::RSA_PKCS1_2048_8192_SHA256,
"SHA384" => &signature::RSA_PKCS1_2048_8192_SHA384,
"SHA512" => &signature::RSA_PKCS1_2048_8192_SHA512,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let public_key = test_case.consume_bytes("Key");
let public_key = untrusted::Input::from(&public_key);
assert!(public_key.read_all(error::Unspecified, |input| {
der::nested(input, der::Tag::Sequence, error::Unspecified,
|input| {
let _ = try!(der::positive_integer(input));
let _ = try!(der::positive_integer(input));
Ok(())
})
}).is_ok());
let msg = test_case.consume_bytes("Msg");
let msg = untrusted::Input::from(&msg);
let sig = test_case.consume_bytes("Sig");
let sig = untrusted::Input::from(&sig);
let expected_result = test_case.consume_string("Result");
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P");
Ok(())
});
}
#[test]
fn test_signature_rsa_pss_verify() {
test::from_file("src/rsa/rsa_pss_verify_tests.txt",
|section, test_case| {
assert_eq!(section, "");
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA256" => &signature::RSA_PSS_2048_8192_SHA256,
"SHA384" => &signature::RSA_PSS_2048_8192_SHA384,
"SHA512" => &signature::RSA_PSS_2048_8192_SHA512,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let public_key = test_case.consume_bytes("Key");
let public_key = untrusted::Input::from(&public_key);
assert!(public_key.read_all(error::Unspecified, |input| {
der::nested(input, der::Tag::Sequence, error::Unspecified,
|input| {
let _ = try!(der::positive_integer(input));
let _ = try!(der::positive_integer(input));
Ok(())
})
}).is_ok());
let msg = test_case.consume_bytes("Msg");
let msg = untrusted::Input::from(&msg);
let sig = test_case.consume_bytes("Sig");
let sig = untrusted::Input::from(&sig);
let expected_result = test_case.consume_string("Result");
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P");
Ok(())
});
}
#[test]
fn test_signature_rsa_primitive_verification() {
test::from_file("src/rsa/rsa_primitive_verify_tests.txt",
|section, test_case| {
assert_eq!(section, "");
let n = test_case.consume_bytes("n");
let e = test_case.consume_bytes("e");
let msg = test_case.consume_bytes("Msg");
let sig = test_case.consume_bytes("Sig");
let expected = test_case.consume_string("Result");
let result = signature::primitive::verify_rsa(
&signature::RSA_PKCS1_2048_8192_SHA256,
(untrusted::Input::from(&n), untrusted::Input::from(&e)),
untrusted::Input::from(&msg), untrusted::Input::from(&sig));
assert_eq!(result.is_ok(), expected == "Pass");
Ok(())
})
}
}