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