1 // Copyright 2015-2016 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 use ring::{
34     rand,
35     signature::{self, KeyPair},
36     test, test_file,
37 };
38 
39 // ECDSA *signing* tests are in src/ec/ecdsa/signing.rs.
40 
41 #[test]
ecdsa_from_pkcs8_test()42 fn ecdsa_from_pkcs8_test() {
43     test::run(
44         test_file!("ecdsa_from_pkcs8_tests.txt"),
45         |section, test_case| {
46             assert_eq!(section, "");
47 
48             let curve_name = test_case.consume_string("Curve");
49             let ((this_fixed, this_asn1), (other_fixed, other_asn1)) = match curve_name.as_str() {
50                 "P-256" => (
51                     (
52                         &signature::ECDSA_P256_SHA256_FIXED_SIGNING,
53                         &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
54                     ),
55                     (
56                         &signature::ECDSA_P384_SHA384_FIXED_SIGNING,
57                         &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
58                     ),
59                 ),
60                 "P-384" => (
61                     (
62                         &signature::ECDSA_P384_SHA384_FIXED_SIGNING,
63                         &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
64                     ),
65                     (
66                         &signature::ECDSA_P256_SHA256_FIXED_SIGNING,
67                         &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
68                     ),
69                 ),
70                 _ => unreachable!(),
71             };
72 
73             let input = test_case.consume_bytes("Input");
74 
75             let error = test_case.consume_optional_string("Error");
76 
77             match (
78                 signature::EcdsaKeyPair::from_pkcs8(this_fixed, &input),
79                 error.clone(),
80             ) {
81                 (Ok(_), None) => (),
82                 (Err(e), None) => panic!("Failed with error \"{}\", but expected to succeed", e),
83                 (Ok(_), Some(e)) => panic!("Succeeded, but expected error \"{}\"", e),
84                 (Err(actual), Some(expected)) => assert_eq!(format!("{}", actual), expected),
85             };
86 
87             match (
88                 signature::EcdsaKeyPair::from_pkcs8(this_asn1, &input),
89                 error.clone(),
90             ) {
91                 (Ok(_), None) => (),
92                 (Err(e), None) => panic!("Failed with error \"{}\", but expected to succeed", e),
93                 (Ok(_), Some(e)) => panic!("Succeeded, but expected error \"{}\"", e),
94                 (Err(actual), Some(expected)) => assert_eq!(format!("{}", actual), expected),
95             };
96 
97             assert!(signature::EcdsaKeyPair::from_pkcs8(other_fixed, &input).is_err());
98             assert!(signature::EcdsaKeyPair::from_pkcs8(other_asn1, &input).is_err());
99 
100             Ok(())
101         },
102     );
103 }
104 
105 // Verify that, at least, we generate PKCS#8 documents that we can read.
106 #[test]
ecdsa_generate_pkcs8_test()107 fn ecdsa_generate_pkcs8_test() {
108     let rng = rand::SystemRandom::new();
109 
110     for alg in &[
111         &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
112         &signature::ECDSA_P256_SHA256_FIXED_SIGNING,
113         &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
114         &signature::ECDSA_P384_SHA384_FIXED_SIGNING,
115     ] {
116         let pkcs8 = signature::EcdsaKeyPair::generate_pkcs8(alg, &rng).unwrap();
117         println!();
118         for b in pkcs8.as_ref() {
119             print!("{:02x}", *b);
120         }
121         println!();
122         println!();
123 
124         #[cfg(feature = "alloc")]
125         let _ = signature::EcdsaKeyPair::from_pkcs8(*alg, pkcs8.as_ref()).unwrap();
126     }
127 }
128 
129 #[test]
signature_ecdsa_verify_asn1_test()130 fn signature_ecdsa_verify_asn1_test() {
131     test::run(
132         test_file!("ecdsa_verify_asn1_tests.txt"),
133         |section, test_case| {
134             assert_eq!(section, "");
135 
136             let curve_name = test_case.consume_string("Curve");
137             let digest_name = test_case.consume_string("Digest");
138             let msg = test_case.consume_bytes("Msg");
139             let public_key = test_case.consume_bytes("Q");
140             let sig = test_case.consume_bytes("Sig");
141             let is_valid = test_case.consume_string("Result") == "P (0 )";
142 
143             let alg = match (curve_name.as_str(), digest_name.as_str()) {
144                 ("P-256", "SHA256") => &signature::ECDSA_P256_SHA256_ASN1,
145                 ("P-256", "SHA384") => &signature::ECDSA_P256_SHA384_ASN1,
146                 ("P-384", "SHA256") => &signature::ECDSA_P384_SHA256_ASN1,
147                 ("P-384", "SHA384") => &signature::ECDSA_P384_SHA384_ASN1,
148                 _ => {
149                     panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
150                 }
151             };
152 
153             let actual_result =
154                 signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
155             assert_eq!(actual_result.is_ok(), is_valid);
156 
157             Ok(())
158         },
159     );
160 }
161 
162 #[test]
signature_ecdsa_verify_fixed_test()163 fn signature_ecdsa_verify_fixed_test() {
164     test::run(
165         test_file!("ecdsa_verify_fixed_tests.txt"),
166         |section, test_case| {
167             assert_eq!(section, "");
168 
169             let curve_name = test_case.consume_string("Curve");
170             let digest_name = test_case.consume_string("Digest");
171 
172             let msg = test_case.consume_bytes("Msg");
173             let public_key = test_case.consume_bytes("Q");
174             let sig = test_case.consume_bytes("Sig");
175             let expected_result = test_case.consume_string("Result");
176 
177             let alg = match (curve_name.as_str(), digest_name.as_str()) {
178                 ("P-256", "SHA256") => &signature::ECDSA_P256_SHA256_FIXED,
179                 ("P-384", "SHA384") => &signature::ECDSA_P384_SHA384_FIXED,
180                 _ => {
181                     panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
182                 }
183             };
184 
185             let is_valid = expected_result == "P (0 )";
186 
187             let actual_result =
188                 signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
189             assert_eq!(actual_result.is_ok(), is_valid);
190 
191             Ok(())
192         },
193     );
194 }
195 
196 #[test]
ecdsa_test_public_key_coverage()197 fn ecdsa_test_public_key_coverage() {
198     const PRIVATE_KEY: &[u8] = include_bytes!("ecdsa_test_private_key_p256.p8");
199     const PUBLIC_KEY: &[u8] = include_bytes!("ecdsa_test_public_key_p256.der");
200     const PUBLIC_KEY_DEBUG: &str = include_str!("ecdsa_test_public_key_p256_debug.txt");
201 
202     let key_pair = signature::EcdsaKeyPair::from_pkcs8(
203         &signature::ECDSA_P256_SHA256_FIXED_SIGNING,
204         PRIVATE_KEY,
205     )
206     .unwrap();
207 
208     // Test `AsRef<[u8]>`
209     assert_eq!(key_pair.public_key().as_ref(), PUBLIC_KEY);
210 
211     // Test `Clone`.
212     #[allow(clippy::clone_on_copy)]
213     let _: <signature::EcdsaKeyPair as KeyPair>::PublicKey = key_pair.public_key().clone();
214 
215     // Test `Copy`.
216     let _: <signature::EcdsaKeyPair as KeyPair>::PublicKey = *key_pair.public_key();
217 
218     // Test `Debug`.
219     assert_eq!(PUBLIC_KEY_DEBUG, format!("{:?}", key_pair.public_key()));
220     assert_eq!(
221         format!("EcdsaKeyPair {{ public_key: {:?} }}", key_pair.public_key()),
222         format!("{:?}", key_pair)
223     );
224 }
225 
226 // This test is not a known-answer test, though it re-uses the known-answer
227 // test vectors. Because the nonce is randomized, the signature will be
228 // different each time. Because of that, here we simply verify that the
229 // signature verifies correctly. The known-answer tests themselves are in
230 // ecsda/signing.rs.
231 #[test]
signature_ecdsa_sign_fixed_sign_and_verify_test()232 fn signature_ecdsa_sign_fixed_sign_and_verify_test() {
233     let rng = rand::SystemRandom::new();
234 
235     test::run(
236         test_file!("../src/ec/suite_b/ecdsa/ecdsa_sign_fixed_tests.txt"),
237         |section, test_case| {
238             assert_eq!(section, "");
239 
240             let curve_name = test_case.consume_string("Curve");
241             let digest_name = test_case.consume_string("Digest");
242 
243             let msg = test_case.consume_bytes("Msg");
244             let d = test_case.consume_bytes("d");
245             let q = test_case.consume_bytes("Q");
246 
247             // Ignored since the actual signature will use a randomized nonce.
248             let _k = test_case.consume_bytes("k");
249             let _expected_result = test_case.consume_bytes("Sig");
250 
251             let (signing_alg, verification_alg) = match (curve_name.as_str(), digest_name.as_str())
252             {
253                 ("P-256", "SHA256") => (
254                     &signature::ECDSA_P256_SHA256_FIXED_SIGNING,
255                     &signature::ECDSA_P256_SHA256_FIXED,
256                 ),
257                 ("P-384", "SHA384") => (
258                     &signature::ECDSA_P384_SHA384_FIXED_SIGNING,
259                     &signature::ECDSA_P384_SHA384_FIXED,
260                 ),
261                 _ => {
262                     panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
263                 }
264             };
265 
266             let private_key =
267                 signature::EcdsaKeyPair::from_private_key_and_public_key(signing_alg, &d, &q)
268                     .unwrap();
269 
270             let signature = private_key.sign(&rng, &msg).unwrap();
271 
272             let public_key = signature::UnparsedPublicKey::new(verification_alg, q);
273             assert_eq!(public_key.verify(&msg, signature.as_ref()), Ok(()));
274 
275             Ok(())
276         },
277     );
278 }
279 
280 // This test is not a known-answer test, though it re-uses the known-answer
281 // test vectors. Because the nonce is randomized, the signature will be
282 // different each time. Because of that, here we simply verify that the
283 // signature verifies correctly. The known-answer tests themselves are in
284 // ecsda/signing.rs.
285 #[test]
signature_ecdsa_sign_asn1_test()286 fn signature_ecdsa_sign_asn1_test() {
287     let rng = rand::SystemRandom::new();
288 
289     test::run(
290         test_file!("../src/ec/suite_b/ecdsa/ecdsa_sign_asn1_tests.txt"),
291         |section, test_case| {
292             assert_eq!(section, "");
293 
294             let curve_name = test_case.consume_string("Curve");
295             let digest_name = test_case.consume_string("Digest");
296 
297             let msg = test_case.consume_bytes("Msg");
298             let d = test_case.consume_bytes("d");
299             let q = test_case.consume_bytes("Q");
300 
301             // Ignored since the actual signature will use a randomized nonce.
302             let _k = test_case.consume_bytes("k");
303             let _expected_result = test_case.consume_bytes("Sig");
304 
305             let (signing_alg, verification_alg) = match (curve_name.as_str(), digest_name.as_str())
306             {
307                 ("P-256", "SHA256") => (
308                     &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
309                     &signature::ECDSA_P256_SHA256_ASN1,
310                 ),
311                 ("P-384", "SHA384") => (
312                     &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
313                     &signature::ECDSA_P384_SHA384_ASN1,
314                 ),
315                 _ => {
316                     panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
317                 }
318             };
319 
320             let private_key =
321                 signature::EcdsaKeyPair::from_private_key_and_public_key(signing_alg, &d, &q)
322                     .unwrap();
323 
324             let signature = private_key.sign(&rng, &msg).unwrap();
325 
326             let public_key = signature::UnparsedPublicKey::new(verification_alg, q);
327             assert_eq!(public_key.verify(&msg, signature.as_ref()), Ok(()));
328 
329             Ok(())
330         },
331     );
332 }
333