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