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