• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 as 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]
rsa_from_pkcs8_test()33 fn rsa_from_pkcs8_test() {
34     test::run(
35         test_file!("rsa_from_pkcs8_tests.txt"),
36         |section, test_case| {
37             assert_eq!(section, "");
38 
39             let input = test_case.consume_bytes("Input");
40             let error = test_case.consume_optional_string("Error");
41 
42             match (signature::RsaKeyPair::from_pkcs8(&input), error) {
43                 (Ok(_), None) => (),
44                 (Err(e), None) => panic!("Failed with error \"{}\", but expected to succeed", e),
45                 (Ok(_), Some(e)) => panic!("Succeeded, but expected error \"{}\"", e),
46                 (Err(actual), Some(expected)) => assert_eq!(format!("{}", actual), expected),
47             };
48 
49             Ok(())
50         },
51     );
52 }
53 
54 #[cfg(feature = "alloc")]
55 #[test]
test_signature_rsa_pkcs1_sign()56 fn test_signature_rsa_pkcs1_sign() {
57     let rng = rand::SystemRandom::new();
58     test::run(
59         test_file!("rsa_pkcs1_sign_tests.txt"),
60         |section, test_case| {
61             assert_eq!(section, "");
62 
63             let digest_name = test_case.consume_string("Digest");
64             let alg = match digest_name.as_ref() {
65                 "SHA256" => &signature::RSA_PKCS1_SHA256,
66                 "SHA384" => &signature::RSA_PKCS1_SHA384,
67                 "SHA512" => &signature::RSA_PKCS1_SHA512,
68                 _ => panic!("Unsupported digest: {}", digest_name),
69             };
70 
71             let private_key = test_case.consume_bytes("Key");
72             let msg = test_case.consume_bytes("Msg");
73             let expected = test_case.consume_bytes("Sig");
74             let result = test_case.consume_string("Result");
75 
76             let key_pair = signature::RsaKeyPair::from_der(&private_key);
77             if result == "Fail-Invalid-Key" {
78                 assert!(key_pair.is_err());
79                 return Ok(());
80             }
81             let key_pair = key_pair.unwrap();
82 
83             // XXX: This test is too slow on Android ARM Travis CI builds.
84             // TODO: re-enable these tests on Android ARM.
85             let mut actual = vec![0u8; key_pair.public().n().len()];
86             key_pair
87                 .sign(alg, &rng, &msg, actual.as_mut_slice())
88                 .unwrap();
89             assert_eq!(actual.as_slice() == &expected[..], result == "Pass");
90             Ok(())
91         },
92     );
93 }
94 
95 #[cfg(feature = "alloc")]
96 #[test]
test_signature_rsa_pss_sign()97 fn test_signature_rsa_pss_sign() {
98     test::run(
99         test_file!("rsa_pss_sign_tests.txt"),
100         |section, test_case| {
101             assert_eq!(section, "");
102 
103             let digest_name = test_case.consume_string("Digest");
104             let alg = match digest_name.as_ref() {
105                 "SHA256" => &signature::RSA_PSS_SHA256,
106                 "SHA384" => &signature::RSA_PSS_SHA384,
107                 "SHA512" => &signature::RSA_PSS_SHA512,
108                 _ => panic!("Unsupported digest: {}", digest_name),
109             };
110 
111             let result = test_case.consume_string("Result");
112             let private_key = test_case.consume_bytes("Key");
113             let key_pair = signature::RsaKeyPair::from_der(&private_key);
114             if key_pair.is_err() && result == "Fail-Invalid-Key" {
115                 return Ok(());
116             }
117             let key_pair = key_pair.unwrap();
118             let msg = test_case.consume_bytes("Msg");
119             let salt = test_case.consume_bytes("Salt");
120             let expected = test_case.consume_bytes("Sig");
121 
122             let rng = test::rand::FixedSliceRandom { bytes: &salt };
123 
124             let mut actual = vec![0u8; key_pair.public().n().len()];
125             key_pair.sign(alg, &rng, &msg, actual.as_mut_slice())?;
126             assert_eq!(actual.as_slice() == &expected[..], result == "Pass");
127             Ok(())
128         },
129     );
130 }
131 
132 #[cfg(feature = "alloc")]
133 #[test]
test_signature_rsa_pkcs1_verify()134 fn test_signature_rsa_pkcs1_verify() {
135     let sha1_params = &[
136         (
137             &signature::RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
138             1024,
139         ),
140         (
141             &signature::RSA_PKCS1_2048_8192_SHA1_FOR_LEGACY_USE_ONLY,
142             2048,
143         ),
144     ];
145     let sha256_params = &[
146         (
147             &signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
148             1024,
149         ),
150         (&signature::RSA_PKCS1_2048_8192_SHA256, 2048),
151     ];
152     let sha384_params = &[
153         (&signature::RSA_PKCS1_2048_8192_SHA384, 2048),
154         (&signature::RSA_PKCS1_3072_8192_SHA384, 3072),
155     ];
156     let sha512_params = &[
157         (
158             &signature::RSA_PKCS1_1024_8192_SHA512_FOR_LEGACY_USE_ONLY,
159             1024,
160         ),
161         (&signature::RSA_PKCS1_2048_8192_SHA512, 2048),
162     ];
163     test::run(
164         test_file!("rsa_pkcs1_verify_tests.txt"),
165         |section, test_case| {
166             assert_eq!(section, "");
167 
168             let digest_name = test_case.consume_string("Digest");
169             let params: &[_] = match digest_name.as_ref() {
170                 "SHA1" => sha1_params,
171                 "SHA256" => sha256_params,
172                 "SHA384" => sha384_params,
173                 "SHA512" => sha512_params,
174                 _ => panic!("Unsupported digest: {}", digest_name),
175             };
176 
177             let public_key = test_case.consume_bytes("Key");
178 
179             // Sanity check that we correctly DER-encoded the originally-
180             // provided separate (n, e) components. When we add test vectors
181             // for improperly-encoded signatures, we'll have to revisit this.
182             let key_bits = untrusted::Input::from(&public_key)
183                 .read_all(error::Unspecified, |input| {
184                     der::nested(input, der::Tag::Sequence, error::Unspecified, |input| {
185                         let n_bytes =
186                             der::positive_integer(input)?.big_endian_without_leading_zero();
187                         let _e = der::positive_integer(input)?;
188 
189                         // Because `n_bytes` has the leading zeros stripped and is big-endian, there
190                         // must be less than 8 leading zero bits.
191                         let n_leading_zeros = usize::try_from(n_bytes[0].leading_zeros()).unwrap();
192                         assert!(n_leading_zeros < 8);
193                         Ok((n_bytes.len() * 8) - n_leading_zeros)
194                     })
195                 })
196                 .expect("invalid DER");
197 
198             let msg = test_case.consume_bytes("Msg");
199             let sig = test_case.consume_bytes("Sig");
200             let is_valid = test_case.consume_string("Result") == "P";
201             for &(alg, min_bits) in params {
202                 let width_ok = key_bits >= min_bits;
203                 let actual_result =
204                     signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
205                 assert_eq!(actual_result.is_ok(), is_valid && width_ok);
206             }
207 
208             Ok(())
209         },
210     );
211 }
212 
213 #[cfg(feature = "alloc")]
214 #[test]
test_signature_rsa_pss_verify()215 fn test_signature_rsa_pss_verify() {
216     test::run(
217         test_file!("rsa_pss_verify_tests.txt"),
218         |section, test_case| {
219             assert_eq!(section, "");
220 
221             let digest_name = test_case.consume_string("Digest");
222             let alg = match digest_name.as_ref() {
223                 "SHA256" => &signature::RSA_PSS_2048_8192_SHA256,
224                 "SHA384" => &signature::RSA_PSS_2048_8192_SHA384,
225                 "SHA512" => &signature::RSA_PSS_2048_8192_SHA512,
226                 _ => panic!("Unsupported digest: {}", digest_name),
227             };
228 
229             let public_key = test_case.consume_bytes("Key");
230 
231             // Sanity check that we correctly DER-encoded the originally-
232             // provided separate (n, e) components. When we add test vectors
233             // for improperly-encoded signatures, we'll have to revisit this.
234             assert!(untrusted::Input::from(&public_key)
235                 .read_all(error::Unspecified, |input| der::nested(
236                     input,
237                     der::Tag::Sequence,
238                     error::Unspecified,
239                     |input| {
240                         let _ = der::positive_integer(input)?;
241                         let _ = der::positive_integer(input)?;
242                         Ok(())
243                     }
244                 ))
245                 .is_ok());
246 
247             let msg = test_case.consume_bytes("Msg");
248             let sig = test_case.consume_bytes("Sig");
249             let is_valid = test_case.consume_string("Result") == "P";
250 
251             let actual_result =
252                 signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
253             assert_eq!(actual_result.is_ok(), is_valid);
254 
255             Ok(())
256         },
257     );
258 }
259 
260 // Test for `primitive::verify()`. Read public key parts from a file
261 // and use them to verify a signature.
262 #[cfg(feature = "alloc")]
263 #[test]
test_signature_rsa_primitive_verification()264 fn test_signature_rsa_primitive_verification() {
265     test::run(
266         test_file!("rsa_primitive_verify_tests.txt"),
267         |section, test_case| {
268             assert_eq!(section, "");
269             let n = test_case.consume_bytes("n");
270             let e = test_case.consume_bytes("e");
271             let msg = test_case.consume_bytes("Msg");
272             let sig = test_case.consume_bytes("Sig");
273             let expected = test_case.consume_string("Result");
274             let public_key = signature::RsaPublicKeyComponents { n: &n, e: &e };
275             let result = public_key.verify(&signature::RSA_PKCS1_2048_8192_SHA256, &msg, &sig);
276             assert_eq!(result.is_ok(), expected == "Pass");
277             Ok(())
278         },
279     )
280 }
281 
282 #[cfg(feature = "alloc")]
283 #[test]
rsa_test_public_key_coverage()284 fn rsa_test_public_key_coverage() {
285     const PRIVATE_KEY: &[u8] = include_bytes!("rsa_test_private_key_2048.p8");
286     const PUBLIC_KEY: &[u8] = include_bytes!("rsa_test_public_key_2048.der");
287     //TODO:
288     //const SUBJECT_PUBLIC_KEY_DEBUG: &str =
289     //    include_str!("rsa_test_subject_public_key_2048_debug.txt");
290     const PUBLIC_KEY_DEBUG: &str = include_str!("rsa_test_public_key_2048_debug.txt");
291 
292     let key_pair = signature::RsaKeyPair::from_pkcs8(PRIVATE_KEY).unwrap();
293 
294     {
295         // Test `RsaSubjectPublicKey`.
296         let spk = key_pair.public_key();
297 
298         // Test `AsRef<[u8]>`
299         assert_eq!(spk.as_ref(), PUBLIC_KEY);
300 
301         // Test `Clone`.
302         let _ = spk.clone();
303 
304         // Test `exponent()`.
305         assert_eq!(
306             &[0x01, 0x00, 0x01],
307             spk.exponent().big_endian_without_leading_zero()
308         );
309 
310         // Test `Debug`
311         // TODO: assert_eq!(SUBJECT_PUBLIC_KEY_DEBUG, format!("{:?}", spk));
312     }
313 
314     {
315         // Test `public::Key`
316         let public_key = key_pair.public();
317 
318         // Test `Clone`.
319         let _ = public_key.clone();
320 
321         // Test `exponent()`.
322         assert_eq!(&[0x01, 0x00, 0x01], public_key.e().to_be_bytes().as_ref());
323 
324         // Test `Debug`
325         assert_eq!(PUBLIC_KEY_DEBUG, format!("{:?}", public_key));
326     }
327 
328     // Test `Debug`
329     assert_eq!(
330         format!("RsaKeyPair {{ public: {:?} }}", key_pair.public()),
331         format!("{:?}", key_pair)
332     );
333 }
334