1 // Copyright 2017 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 #[cfg(feature = "alloc")]
16 use ring::{
17     error,
18     io::der,
19     rand,
20     signature::{self, KeyPair},
21     test, test_file,
22 };
23 use std::convert::TryFrom;
24 
25 #[cfg(all(target_arch = "wasm32", feature = "wasm32_c"))]
26 use wasm_bindgen_test::{wasm_bindgen_test, wasm_bindgen_test_configure};
27 
28 #[cfg(all(target_arch = "wasm32", feature = "wasm32_c"))]
29 wasm_bindgen_test_configure!(run_in_browser);
30 
31 #[cfg(feature = "alloc")]
32 #[test]
33 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm32_c"), wasm_bindgen_test)]
rsa_from_pkcs8_test()34 fn rsa_from_pkcs8_test() {
35     test::run(
36         test_file!("rsa_from_pkcs8_tests.txt"),
37         |section, test_case| {
38             assert_eq!(section, "");
39 
40             let input = test_case.consume_bytes("Input");
41             let error = test_case.consume_optional_string("Error");
42 
43             match (signature::RsaKeyPair::from_pkcs8(&input), error) {
44                 (Ok(_), None) => (),
45                 (Err(e), None) => panic!("Failed with error \"{}\", but expected to succeed", e),
46                 (Ok(_), Some(e)) => panic!("Succeeded, but expected error \"{}\"", e),
47                 (Err(actual), Some(expected)) => assert_eq!(format!("{}", actual), expected),
48             };
49 
50             Ok(())
51         },
52     );
53 }
54 
55 #[cfg(feature = "alloc")]
56 #[test]
57 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm32_c"), wasm_bindgen_test)]
test_signature_rsa_pkcs1_sign()58 fn test_signature_rsa_pkcs1_sign() {
59     let rng = rand::SystemRandom::new();
60     test::run(
61         test_file!("rsa_pkcs1_sign_tests.txt"),
62         |section, test_case| {
63             assert_eq!(section, "");
64 
65             let digest_name = test_case.consume_string("Digest");
66             let alg = match digest_name.as_ref() {
67                 "SHA256" => &signature::RSA_PKCS1_SHA256,
68                 "SHA384" => &signature::RSA_PKCS1_SHA384,
69                 "SHA512" => &signature::RSA_PKCS1_SHA512,
70                 _ => panic!("Unsupported digest: {}", digest_name),
71             };
72 
73             let private_key = test_case.consume_bytes("Key");
74             let msg = test_case.consume_bytes("Msg");
75             let expected = test_case.consume_bytes("Sig");
76             let result = test_case.consume_string("Result");
77 
78             let key_pair = signature::RsaKeyPair::from_der(&private_key);
79             if result == "Fail-Invalid-Key" {
80                 assert!(key_pair.is_err());
81                 return Ok(());
82             }
83             let key_pair = key_pair.unwrap();
84 
85             // XXX: This test is too slow on Android ARM Travis CI builds.
86             // TODO: re-enable these tests on Android ARM.
87             let mut actual = vec![0u8; key_pair.public_modulus_len()];
88             key_pair
89                 .sign(alg, &rng, &msg, actual.as_mut_slice())
90                 .unwrap();
91             assert_eq!(actual.as_slice() == &expected[..], result == "Pass");
92             Ok(())
93         },
94     );
95 }
96 
97 #[cfg(feature = "alloc")]
98 #[test]
99 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm32_c"), wasm_bindgen_test)]
test_signature_rsa_pss_sign()100 fn test_signature_rsa_pss_sign() {
101     test::run(
102         test_file!("rsa_pss_sign_tests.txt"),
103         |section, test_case| {
104             assert_eq!(section, "");
105 
106             let digest_name = test_case.consume_string("Digest");
107             let alg = match digest_name.as_ref() {
108                 "SHA256" => &signature::RSA_PSS_SHA256,
109                 "SHA384" => &signature::RSA_PSS_SHA384,
110                 "SHA512" => &signature::RSA_PSS_SHA512,
111                 _ => panic!("Unsupported digest: {}", digest_name),
112             };
113 
114             let result = test_case.consume_string("Result");
115             let private_key = test_case.consume_bytes("Key");
116             let key_pair = signature::RsaKeyPair::from_der(&private_key);
117             if key_pair.is_err() && result == "Fail-Invalid-Key" {
118                 return Ok(());
119             }
120             let key_pair = key_pair.unwrap();
121             let msg = test_case.consume_bytes("Msg");
122             let salt = test_case.consume_bytes("Salt");
123             let expected = test_case.consume_bytes("Sig");
124 
125             let rng = test::rand::FixedSliceRandom { bytes: &salt };
126 
127             let mut actual = vec![0u8; key_pair.public_modulus_len()];
128             key_pair.sign(alg, &rng, &msg, actual.as_mut_slice())?;
129             assert_eq!(actual.as_slice() == &expected[..], result == "Pass");
130             Ok(())
131         },
132     );
133 }
134 
135 #[cfg(feature = "alloc")]
136 #[test]
137 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm32_c"), wasm_bindgen_test)]
test_signature_rsa_pkcs1_verify()138 fn test_signature_rsa_pkcs1_verify() {
139     let sha1_params = &[
140         (
141             &signature::RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
142             1024,
143         ),
144         (
145             &signature::RSA_PKCS1_2048_8192_SHA1_FOR_LEGACY_USE_ONLY,
146             2048,
147         ),
148     ];
149     let sha256_params = &[
150         (
151             &signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
152             1024,
153         ),
154         (&signature::RSA_PKCS1_2048_8192_SHA256, 2048),
155     ];
156     let sha384_params = &[
157         (&signature::RSA_PKCS1_2048_8192_SHA384, 2048),
158         (&signature::RSA_PKCS1_3072_8192_SHA384, 3072),
159     ];
160     let sha512_params = &[
161         (
162             &signature::RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY,
163             1024,
164         ),
165         (&signature::RSA_PKCS1_2048_8192_SHA512, 2048),
166     ];
167     test::run(
168         test_file!("rsa_pkcs1_verify_tests.txt"),
169         |section, test_case| {
170             assert_eq!(section, "");
171 
172             let digest_name = test_case.consume_string("Digest");
173             let params: &[_] = match digest_name.as_ref() {
174                 "SHA1" => sha1_params,
175                 "SHA256" => sha256_params,
176                 "SHA384" => sha384_params,
177                 "SHA512" => sha512_params,
178                 _ => panic!("Unsupported digest: {}", digest_name),
179             };
180 
181             let public_key = test_case.consume_bytes("Key");
182 
183             // Sanity check that we correctly DER-encoded the originally-
184             // provided separate (n, e) components. When we add test vectors
185             // for improperly-encoded signatures, we'll have to revisit this.
186             let key_bits = untrusted::Input::from(&public_key)
187                 .read_all(error::Unspecified, |input| {
188                     der::nested(input, der::Tag::Sequence, error::Unspecified, |input| {
189                         let n_bytes =
190                             der::positive_integer(input)?.big_endian_without_leading_zero();
191                         let _e = der::positive_integer(input)?;
192 
193                         // Because `n_bytes` has the leading zeros stripped and is big-endian, there
194                         // must be less than 8 leading zero bits.
195                         let n_leading_zeros = usize::try_from(n_bytes[0].leading_zeros()).unwrap();
196                         assert!(n_leading_zeros < 8);
197                         Ok((n_bytes.len() * 8) - n_leading_zeros)
198                     })
199                 })
200                 .expect("invalid DER");
201 
202             let msg = test_case.consume_bytes("Msg");
203             let sig = test_case.consume_bytes("Sig");
204             let is_valid = test_case.consume_string("Result") == "P";
205             for &(alg, min_bits) in params {
206                 let width_ok = key_bits >= min_bits;
207                 let actual_result =
208                     signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
209                 assert_eq!(actual_result.is_ok(), is_valid && width_ok);
210             }
211 
212             Ok(())
213         },
214     );
215 }
216 
217 #[cfg(feature = "alloc")]
218 #[test]
219 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm32_c"), wasm_bindgen_test)]
test_signature_rsa_pss_verify()220 fn test_signature_rsa_pss_verify() {
221     test::run(
222         test_file!("rsa_pss_verify_tests.txt"),
223         |section, test_case| {
224             assert_eq!(section, "");
225 
226             let digest_name = test_case.consume_string("Digest");
227             let alg = match digest_name.as_ref() {
228                 "SHA256" => &signature::RSA_PSS_2048_8192_SHA256,
229                 "SHA384" => &signature::RSA_PSS_2048_8192_SHA384,
230                 "SHA512" => &signature::RSA_PSS_2048_8192_SHA512,
231                 _ => panic!("Unsupported digest: {}", digest_name),
232             };
233 
234             let public_key = test_case.consume_bytes("Key");
235 
236             // Sanity check that we correctly DER-encoded the originally-
237             // provided separate (n, e) components. When we add test vectors
238             // for improperly-encoded signatures, we'll have to revisit this.
239             assert!(untrusted::Input::from(&public_key)
240                 .read_all(error::Unspecified, |input| der::nested(
241                     input,
242                     der::Tag::Sequence,
243                     error::Unspecified,
244                     |input| {
245                         let _ = der::positive_integer(input)?;
246                         let _ = der::positive_integer(input)?;
247                         Ok(())
248                     }
249                 ))
250                 .is_ok());
251 
252             let msg = test_case.consume_bytes("Msg");
253             let sig = test_case.consume_bytes("Sig");
254             let is_valid = test_case.consume_string("Result") == "P";
255 
256             let actual_result =
257                 signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
258             assert_eq!(actual_result.is_ok(), is_valid);
259 
260             Ok(())
261         },
262     );
263 }
264 
265 // Test for `primitive::verify()`. Read public key parts from a file
266 // and use them to verify a signature.
267 #[cfg(feature = "alloc")]
268 #[test]
269 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm32_c"), wasm_bindgen_test)]
test_signature_rsa_primitive_verification()270 fn test_signature_rsa_primitive_verification() {
271     test::run(
272         test_file!("rsa_primitive_verify_tests.txt"),
273         |section, test_case| {
274             assert_eq!(section, "");
275             let n = test_case.consume_bytes("n");
276             let e = test_case.consume_bytes("e");
277             let msg = test_case.consume_bytes("Msg");
278             let sig = test_case.consume_bytes("Sig");
279             let expected = test_case.consume_string("Result");
280             let public_key = signature::RsaPublicKeyComponents { n: &n, e: &e };
281             let result = public_key.verify(&signature::RSA_PKCS1_2048_8192_SHA256, &msg, &sig);
282             assert_eq!(result.is_ok(), expected == "Pass");
283             Ok(())
284         },
285     )
286 }
287 
288 #[cfg(feature = "alloc")]
289 #[test]
290 #[cfg_attr(all(target_arch = "wasm32", feature = "wasm32_c"), wasm_bindgen_test)]
rsa_test_public_key_coverage()291 fn rsa_test_public_key_coverage() {
292     const PRIVATE_KEY: &[u8] = include_bytes!("rsa_test_private_key_2048.p8");
293     const PUBLIC_KEY: &[u8] = include_bytes!("rsa_test_public_key_2048.der");
294     const PUBLIC_KEY_DEBUG: &str = include_str!("rsa_test_public_key_2048_debug.txt");
295 
296     let key_pair = signature::RsaKeyPair::from_pkcs8(PRIVATE_KEY).unwrap();
297 
298     // Test `AsRef<[u8]>`
299     assert_eq!(key_pair.public_key().as_ref(), PUBLIC_KEY);
300 
301     // Test `Clone`.
302     let _ = key_pair.public_key().clone();
303 
304     // Test `exponent()`.
305     assert_eq!(
306         &[0x01, 0x00, 0x01],
307         key_pair
308             .public_key()
309             .exponent()
310             .big_endian_without_leading_zero()
311     );
312 
313     // Test `Debug`
314     assert_eq!(PUBLIC_KEY_DEBUG, format!("{:?}", key_pair.public_key()));
315     assert_eq!(
316         format!("RsaKeyPair {{ public_key: {:?} }}", key_pair.public_key()),
317         format!("{:?}", key_pair)
318     );
319 }
320