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