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//! ECDSA Signatures using the P-256 and P-384 curves.
16
17use super::digest_scalar::digest_scalar;
18use crate::{
19 arithmetic::montgomery::*,
20 cpu, digest,
21 ec::{
22 self,
23 suite_b::{ops::*, private_key},
24 },
25 error,
26 io::der,
27 limb, pkcs8, rand, sealed, signature,
28};
29/// An ECDSA signing algorithm.
30pub struct EcdsaSigningAlgorithm {
31 curve: &'static ec::Curve,
32 private_scalar_ops: &'static PrivateScalarOps,
33 private_key_ops: &'static PrivateKeyOps,
34 digest_alg: &'static digest::Algorithm,
35 pkcs8_template: &'static pkcs8::Template,
36 format_rs: fn(ops: &'static ScalarOps, r: &Scalar, s: &Scalar, out: &mut [u8]) -> usize,
37 id: AlgorithmID,
38}
39
40#[derive(Debug, Eq, PartialEq)]
41enum AlgorithmID {
42 ECDSA_P256_SHA256_FIXED_SIGNING,
43 ECDSA_P384_SHA384_FIXED_SIGNING,
44 ECDSA_P256_SHA256_ASN1_SIGNING,
45 ECDSA_P384_SHA384_ASN1_SIGNING,
46}
47
48derive_debug_via_id!(EcdsaSigningAlgorithm);
49
50impl PartialEq for EcdsaSigningAlgorithm {
51 fn eq(&self, other: &Self) -> bool {
52 self.id == other.id
53 }
54}
55
56impl Eq for EcdsaSigningAlgorithm {}
57
58impl sealed::Sealed for EcdsaSigningAlgorithm {}
59
60/// An ECDSA key pair, used for signing.
61pub struct EcdsaKeyPair {
62 d: Scalar<R>,
63 nonce_key: NonceRandomKey,
64 alg: &'static EcdsaSigningAlgorithm,
65 public_key: PublicKey,
66}
67
68derive_debug_via_field!(EcdsaKeyPair, stringify!(EcdsaKeyPair), public_key);
69
70impl EcdsaKeyPair {
71 /// Generates a new key pair and returns the key pair serialized as a
72 /// PKCS#8 document.
73 ///
74 /// The PKCS#8 document will be a v1 `OneAsymmetricKey` with the public key
75 /// included in the `ECPrivateKey` structure, as described in
76 /// [RFC 5958 Section 2] and [RFC 5915]. The `ECPrivateKey` structure will
77 /// not have a `parameters` field so the generated key is compatible with
78 /// PKCS#11.
79 ///
80 /// [RFC 5915]: https://tools.ietf.org/html/rfc5915
81 /// [RFC 5958 Section 2]: https://tools.ietf.org/html/rfc5958#section-2
82 pub fn generate_pkcs8(
83 alg: &'static EcdsaSigningAlgorithm,
84 rng: &dyn rand::SecureRandom,
85 ) -> Result<pkcs8::Document, error::Unspecified> {
86 let cpu = cpu::features();
87 let private_key = ec::Seed::generate(alg.curve, rng, cpu)?;
88 let public_key = private_key.compute_public_key(cpu)?;
89 Ok(pkcs8::wrap_key(
90 alg.pkcs8_template,
91 private_key.bytes_less_safe(),
92 public_key.as_ref(),
93 ))
94 }
95
96 /// Constructs an ECDSA key pair by parsing an unencrypted PKCS#8 v1
97 /// id-ecPublicKey `ECPrivateKey` key.
98 ///
99 /// The input must be in PKCS#8 v1 format. It must contain the public key in
100 /// the `ECPrivateKey` structure; `from_pkcs8()` will verify that the public
101 /// key and the private key are consistent with each other. The algorithm
102 /// identifier must identify the curve by name; it must not use an
103 /// "explicit" encoding of the curve. The `parameters` field of the
104 /// `ECPrivateKey`, if present, must be the same named curve that is in the
105 /// algorithm identifier in the PKCS#8 header.
106 pub fn from_pkcs8(
107 alg: &'static EcdsaSigningAlgorithm,
108 pkcs8: &[u8],
109 rng: &dyn rand::SecureRandom,
110 ) -> Result<Self, error::KeyRejected> {
111 let key_pair = ec::suite_b::key_pair_from_pkcs8(
112 alg.curve,
113 alg.pkcs8_template,
114 untrusted::Input::from(pkcs8),
115 cpu::features(),
116 )?;
117 Self::new(alg, key_pair, rng)
118 }
119
120 /// Constructs an ECDSA key pair from the private key and public key bytes
121 ///
122 /// The private key must encoded as a big-endian fixed-length integer. For
123 /// example, a P-256 private key must be 32 bytes prefixed with leading
124 /// zeros as needed.
125 ///
126 /// The public key is encoding in uncompressed form using the
127 /// Octet-String-to-Elliptic-Curve-Point algorithm in
128 /// [SEC 1: Elliptic Curve Cryptography, Version 2.0].
129 ///
130 /// This is intended for use by code that deserializes key pairs. It is
131 /// recommended to use `EcdsaKeyPair::from_pkcs8()` (with a PKCS#8-encoded
132 /// key) instead.
133 ///
134 /// [SEC 1: Elliptic Curve Cryptography, Version 2.0]:
135 /// http://www.secg.org/sec1-v2.pdf
136 pub fn from_private_key_and_public_key(
137 alg: &'static EcdsaSigningAlgorithm,
138 private_key: &[u8],
139 public_key: &[u8],
140 rng: &dyn rand::SecureRandom,
141 ) -> Result<Self, error::KeyRejected> {
142 let key_pair = ec::suite_b::key_pair_from_bytes(
143 alg.curve,
144 untrusted::Input::from(private_key),
145 untrusted::Input::from(public_key),
146 cpu::features(),
147 )?;
148 Self::new(alg, key_pair, rng)
149 }
150
151 fn new(
152 alg: &'static EcdsaSigningAlgorithm,
153 key_pair: ec::KeyPair,
154 rng: &dyn rand::SecureRandom,
155 ) -> Result<Self, error::KeyRejected> {
156 let cpu = cpu::features();
157
158 let (seed, public_key) = key_pair.split();
159 let n = &alg.private_scalar_ops.scalar_ops.scalar_modulus(cpu);
160 let d = private_key::private_key_as_scalar(n, &seed);
161 let d = alg.private_scalar_ops.to_mont(&d, cpu);
162
163 let nonce_key = NonceRandomKey::new(alg, &seed, rng)?;
164 Ok(Self {
165 d,
166 nonce_key,
167 alg,
168 public_key: PublicKey(public_key),
169 })
170 }
171
172 /// Returns the signature of the `message` using a random nonce generated by `rng`.
173 pub fn sign(
174 &self,
175 rng: &dyn rand::SecureRandom,
176 message: &[u8],
177 ) -> Result<signature::Signature, error::Unspecified> {
178 let cpu = cpu::features();
179
180 // Step 4 (out of order).
181 let h = digest::digest(self.alg.digest_alg, message);
182
183 // Incorporate `h` into the nonce to hedge against faulty RNGs. (This
184 // is not an approved random number generator that is mandated in
185 // the spec.)
186 let nonce_rng = NonceRandom {
187 key: &self.nonce_key,
188 message_digest: &h,
189 rng,
190 };
191
192 self.sign_digest(h, &nonce_rng, cpu)
193 }
194
195 #[cfg(test)]
196 fn sign_with_fixed_nonce_during_test(
197 &self,
198 rng: &dyn rand::SecureRandom,
199 message: &[u8],
200 ) -> Result<signature::Signature, error::Unspecified> {
201 // Step 4 (out of order).
202 let h = digest::digest(self.alg.digest_alg, message);
203
204 self.sign_digest(h, rng, cpu::features())
205 }
206
207 /// Returns the signature of message digest `h` using a "random" nonce
208 /// generated by `rng`.
209 fn sign_digest(
210 &self,
211 h: digest::Digest,
212 rng: &dyn rand::SecureRandom,
213 cpu: cpu::Features,
214 ) -> Result<signature::Signature, error::Unspecified> {
215 // NSA Suite B Implementer's Guide to ECDSA Section 3.4.1: ECDSA
216 // Signature Generation.
217
218 // NSA Guide Prerequisites:
219 //
220 // Prior to generating an ECDSA signature, the signatory shall
221 // obtain:
222 //
223 // 1. an authentic copy of the domain parameters,
224 // 2. a digital signature key pair (d,Q), either generated by a
225 // method from Appendix A.1, or obtained from a trusted third
226 // party,
227 // 3. assurance of the validity of the public key Q (see Appendix
228 // A.3), and
229 // 4. assurance that he/she/it actually possesses the associated
230 // private key d (see [SP800-89] Section 6).
231 //
232 // The domain parameters are hard-coded into the source code.
233 // `EcdsaKeyPair::generate_pkcs8()` can be used to meet the second
234 // requirement; otherwise, it is up to the user to ensure the key pair
235 // was obtained from a trusted private key. The constructors for
236 // `EcdsaKeyPair` ensure that #3 and #4 are met subject to the caveats
237 // in SP800-89 Section 6.
238
239 let ops = self.alg.private_scalar_ops;
240 let scalar_ops = ops.scalar_ops;
241 let cops = scalar_ops.common;
242 let private_key_ops = self.alg.private_key_ops;
243 let q = &cops.elem_modulus(cpu);
244 let n = &scalar_ops.scalar_modulus(cpu);
245
246 for _ in 0..100 {
247 // XXX: iteration conut?
248 // Step 1.
249 let k = private_key::random_scalar(self.alg.private_key_ops, n, rng)?;
250 let k_inv = ops.scalar_inv_to_mont(&k, cpu);
251
252 // Step 2.
253 let r = private_key_ops.point_mul_base(&k, cpu);
254
255 // Step 3.
256 let r = {
257 let (x, _) = private_key::affine_from_jacobian(private_key_ops, q, &r)?;
258 let x = q.elem_unencoded(&x);
259 n.elem_reduced_to_scalar(&x)
260 };
261 if n.is_zero(&r) {
262 continue;
263 }
264
265 // Step 4 is done by the caller.
266
267 // Step 5.
268 let e = digest_scalar(n, h);
269
270 // Step 6.
271 let s = {
272 let mut e_plus_dr = scalar_ops.scalar_product(&self.d, &r, cpu);
273 n.add_assign(&mut e_plus_dr, &e);
274 scalar_ops.scalar_product(&k_inv, &e_plus_dr, cpu)
275 };
276 if n.is_zero(&s) {
277 continue;
278 }
279
280 // Step 7 with encoding.
281 return Ok(signature::Signature::new(|sig_bytes| {
282 (self.alg.format_rs)(scalar_ops, &r, &s, sig_bytes)
283 }));
284 }
285
286 Err(error::Unspecified)
287 }
288}
289
290/// Generates an ECDSA nonce in a way that attempts to protect against a faulty
291/// `SecureRandom`.
292struct NonceRandom<'a> {
293 key: &'a NonceRandomKey,
294 message_digest: &'a digest::Digest,
295 rng: &'a dyn rand::SecureRandom,
296}
297
298impl core::fmt::Debug for NonceRandom<'_> {
299 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
300 f.debug_struct(name:"NonceRandom").finish()
301 }
302}
303
304impl rand::sealed::SecureRandom for NonceRandom<'_> {
305 fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> {
306 // Use the same digest algorithm that will be used to digest the
307 // message. The digest algorithm's output is exactly the right size;
308 // this is checked below.
309 //
310 // XXX(perf): The single iteration will require two digest block
311 // operations because the amount of data digested is larger than one
312 // block.
313 let digest_alg = self.key.0.algorithm();
314 let mut ctx = digest::Context::new(digest_alg);
315
316 // Digest the randomized digest of the private key.
317 let key = self.key.0.as_ref();
318 ctx.update(key);
319
320 // The random value is digested between the key and the message so that
321 // the key and the message are not directly digested in the same digest
322 // block.
323 assert!(key.len() <= digest_alg.block_len() / 2);
324 {
325 let mut rand = [0u8; digest::MAX_BLOCK_LEN];
326 let rand = &mut rand[..digest_alg.block_len() - key.len()];
327 assert!(rand.len() >= dest.len());
328 self.rng.fill(rand)?;
329 ctx.update(rand);
330 }
331
332 ctx.update(self.message_digest.as_ref());
333
334 let nonce = ctx.finish();
335
336 // `copy_from_slice()` panics if the lengths differ, so we don't have
337 // to separately assert that the lengths are the same.
338 dest.copy_from_slice(nonce.as_ref());
339
340 Ok(())
341 }
342}
343
344impl sealed::Sealed for NonceRandom<'_> {}
345
346struct NonceRandomKey(digest::Digest);
347
348impl NonceRandomKey {
349 fn new(
350 alg: &EcdsaSigningAlgorithm,
351 seed: &ec::Seed,
352 rng: &dyn rand::SecureRandom,
353 ) -> Result<Self, error::KeyRejected> {
354 let mut rand: [u8; 64] = [0; digest::MAX_OUTPUT_LEN];
355 let rand: &mut [u8] = &mut rand[0..alg.curve.elem_scalar_seed_len];
356
357 // XXX: `KeyRejected` isn't the right way to model failure of the RNG,
358 // but to fix that we'd need to break the API by changing the result type.
359 // TODO: Fix the API in the next breaking release.
360 rng.fill(rand)
361 .map_err(|error::Unspecified| error::KeyRejected::rng_failed())?;
362
363 let mut ctx: Context = digest::Context::new(algorithm:alg.digest_alg);
364 ctx.update(data:rand);
365 ctx.update(data:seed.bytes_less_safe());
366 Ok(Self(ctx.finish()))
367 }
368}
369
370impl signature::KeyPair for EcdsaKeyPair {
371 type PublicKey = PublicKey;
372
373 fn public_key(&self) -> &Self::PublicKey {
374 &self.public_key
375 }
376}
377
378#[derive(Clone, Copy)]
379pub struct PublicKey(ec::PublicKey);
380
381derive_debug_self_as_ref_hex_bytes!(PublicKey);
382
383impl AsRef<[u8]> for PublicKey {
384 fn as_ref(&self) -> &[u8] {
385 self.0.as_ref()
386 }
387}
388
389fn format_rs_fixed(ops: &'static ScalarOps, r: &Scalar, s: &Scalar, out: &mut [u8]) -> usize {
390 let scalar_len: usize = ops.scalar_bytes_len();
391
392 let (r_out: &mut [u8], rest: &mut [u8]) = out.split_at_mut(mid:scalar_len);
393 limb::big_endian_from_limbs(ops.leak_limbs(r), r_out);
394
395 let (s_out: &mut [u8], _) = rest.split_at_mut(mid:scalar_len);
396 limb::big_endian_from_limbs(ops.leak_limbs(s), s_out);
397
398 2 * scalar_len
399}
400
401fn format_rs_asn1(ops: &'static ScalarOps, r: &Scalar, s: &Scalar, out: &mut [u8]) -> usize {
402 // This assumes `a` is not zero since neither `r` or `s` is allowed to be
403 // zero.
404 fn format_integer_tlv(ops: &ScalarOps, a: &Scalar, out: &mut [u8]) -> usize {
405 let mut fixed = [0u8; ec::SCALAR_MAX_BYTES + 1];
406 let fixed = &mut fixed[..(ops.scalar_bytes_len() + 1)];
407 limb::big_endian_from_limbs(ops.leak_limbs(a), &mut fixed[1..]);
408
409 // Since `a_fixed_out` is an extra byte long, it is guaranteed to start
410 // with a zero.
411 debug_assert_eq!(fixed[0], 0);
412
413 // There must be at least one non-zero byte since `a` isn't zero.
414 let first_index = fixed.iter().position(|b| *b != 0).unwrap();
415
416 // If the first byte has its high bit set, it needs to be prefixed with 0x00.
417 let first_index = if fixed[first_index] & 0x80 != 0 {
418 first_index - 1
419 } else {
420 first_index
421 };
422 let value = &fixed[first_index..];
423
424 out[0] = der::Tag::Integer.into();
425
426 // Lengths less than 128 are encoded in one byte.
427 assert!(value.len() < 128);
428 #[allow(clippy::cast_possible_truncation)]
429 {
430 out[1] = value.len() as u8;
431 }
432
433 out[2..][..value.len()].copy_from_slice(value);
434
435 2 + value.len()
436 }
437
438 out[0] = der::Tag::Sequence.into();
439 let r_tlv_len = format_integer_tlv(ops, r, &mut out[2..]);
440 let s_tlv_len = format_integer_tlv(ops, s, &mut out[2..][r_tlv_len..]);
441
442 // Lengths less than 128 are encoded in one byte.
443 let value_len = r_tlv_len + s_tlv_len;
444 assert!(value_len < 128);
445 #[allow(clippy::cast_possible_truncation)]
446 {
447 out[1] = value_len as u8;
448 }
449
450 2 + value_len
451}
452
453/// Signing of fixed-length (PKCS#11 style) ECDSA signatures using the
454/// P-256 curve and SHA-256.
455///
456/// See "`ECDSA_*_FIXED` Details" in `ring::signature`'s module-level
457/// documentation for more details.
458pub static ECDSA_P256_SHA256_FIXED_SIGNING: EcdsaSigningAlgorithm = EcdsaSigningAlgorithm {
459 curve: &ec::suite_b::curve::P256,
460 private_scalar_ops: &p256::PRIVATE_SCALAR_OPS,
461 private_key_ops: &p256::PRIVATE_KEY_OPS,
462 digest_alg: &digest::SHA256,
463 pkcs8_template: &EC_PUBLIC_KEY_P256_PKCS8_V1_TEMPLATE,
464 format_rs: format_rs_fixed,
465 id: AlgorithmID::ECDSA_P256_SHA256_FIXED_SIGNING,
466};
467
468/// Signing of fixed-length (PKCS#11 style) ECDSA signatures using the
469/// P-384 curve and SHA-384.
470///
471/// See "`ECDSA_*_FIXED` Details" in `ring::signature`'s module-level
472/// documentation for more details.
473pub static ECDSA_P384_SHA384_FIXED_SIGNING: EcdsaSigningAlgorithm = EcdsaSigningAlgorithm {
474 curve: &ec::suite_b::curve::P384,
475 private_scalar_ops: &p384::PRIVATE_SCALAR_OPS,
476 private_key_ops: &p384::PRIVATE_KEY_OPS,
477 digest_alg: &digest::SHA384,
478 pkcs8_template: &EC_PUBLIC_KEY_P384_PKCS8_V1_TEMPLATE,
479 format_rs: format_rs_fixed,
480 id: AlgorithmID::ECDSA_P384_SHA384_FIXED_SIGNING,
481};
482
483/// Signing of ASN.1 DER-encoded ECDSA signatures using the P-256 curve and
484/// SHA-256.
485///
486/// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
487/// documentation for more details.
488pub static ECDSA_P256_SHA256_ASN1_SIGNING: EcdsaSigningAlgorithm = EcdsaSigningAlgorithm {
489 curve: &ec::suite_b::curve::P256,
490 private_scalar_ops: &p256::PRIVATE_SCALAR_OPS,
491 private_key_ops: &p256::PRIVATE_KEY_OPS,
492 digest_alg: &digest::SHA256,
493 pkcs8_template: &EC_PUBLIC_KEY_P256_PKCS8_V1_TEMPLATE,
494 format_rs: format_rs_asn1,
495 id: AlgorithmID::ECDSA_P256_SHA256_ASN1_SIGNING,
496};
497
498/// Signing of ASN.1 DER-encoded ECDSA signatures using the P-384 curve and
499/// SHA-384.
500///
501/// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
502/// documentation for more details.
503pub static ECDSA_P384_SHA384_ASN1_SIGNING: EcdsaSigningAlgorithm = EcdsaSigningAlgorithm {
504 curve: &ec::suite_b::curve::P384,
505 private_scalar_ops: &p384::PRIVATE_SCALAR_OPS,
506 private_key_ops: &p384::PRIVATE_KEY_OPS,
507 digest_alg: &digest::SHA384,
508 pkcs8_template: &EC_PUBLIC_KEY_P384_PKCS8_V1_TEMPLATE,
509 format_rs: format_rs_asn1,
510 id: AlgorithmID::ECDSA_P384_SHA384_ASN1_SIGNING,
511};
512
513static EC_PUBLIC_KEY_P256_PKCS8_V1_TEMPLATE: pkcs8::Template = pkcs8::Template {
514 bytes: include_bytes!("ecPublicKey_p256_pkcs8_v1_template.der"),
515 alg_id_range: core::ops::Range { start: 8, end: 27 },
516 curve_id_index: 9,
517 private_key_index: 0x24,
518};
519
520static EC_PUBLIC_KEY_P384_PKCS8_V1_TEMPLATE: pkcs8::Template = pkcs8::Template {
521 bytes: include_bytes!("ecPublicKey_p384_pkcs8_v1_template.der"),
522 alg_id_range: core::ops::Range { start: 8, end: 24 },
523 curve_id_index: 9,
524 private_key_index: 0x23,
525};
526
527#[cfg(test)]
528mod tests {
529 use crate::{rand, signature, test};
530
531 #[test]
532 fn signature_ecdsa_sign_fixed_test() {
533 let rng = rand::SystemRandom::new();
534
535 test::run(
536 test_file!("ecdsa_sign_fixed_tests.txt"),
537 |section, test_case| {
538 assert_eq!(section, "");
539
540 let curve_name = test_case.consume_string("Curve");
541 let digest_name = test_case.consume_string("Digest");
542 let msg = test_case.consume_bytes("Msg");
543 let d = test_case.consume_bytes("d");
544 let q = test_case.consume_bytes("Q");
545 let k = test_case.consume_bytes("k");
546
547 let expected_result = test_case.consume_bytes("Sig");
548
549 let alg = match (curve_name.as_str(), digest_name.as_str()) {
550 ("P-256", "SHA256") => &signature::ECDSA_P256_SHA256_FIXED_SIGNING,
551 ("P-384", "SHA384") => &signature::ECDSA_P384_SHA384_FIXED_SIGNING,
552 _ => {
553 panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
554 }
555 };
556
557 let private_key =
558 signature::EcdsaKeyPair::from_private_key_and_public_key(alg, &d, &q, &rng)
559 .unwrap();
560 let rng = test::rand::FixedSliceRandom { bytes: &k };
561
562 let actual_result = private_key
563 .sign_with_fixed_nonce_during_test(&rng, &msg)
564 .unwrap();
565
566 assert_eq!(actual_result.as_ref(), &expected_result[..]);
567
568 Ok(())
569 },
570 );
571 }
572
573 #[test]
574 fn signature_ecdsa_sign_asn1_test() {
575 let rng = rand::SystemRandom::new();
576
577 test::run(
578 test_file!("ecdsa_sign_asn1_tests.txt"),
579 |section, test_case| {
580 assert_eq!(section, "");
581
582 let curve_name = test_case.consume_string("Curve");
583 let digest_name = test_case.consume_string("Digest");
584 let msg = test_case.consume_bytes("Msg");
585 let d = test_case.consume_bytes("d");
586 let q = test_case.consume_bytes("Q");
587 let k = test_case.consume_bytes("k");
588
589 let expected_result = test_case.consume_bytes("Sig");
590
591 let alg = match (curve_name.as_str(), digest_name.as_str()) {
592 ("P-256", "SHA256") => &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
593 ("P-384", "SHA384") => &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
594 _ => {
595 panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
596 }
597 };
598
599 let private_key =
600 signature::EcdsaKeyPair::from_private_key_and_public_key(alg, &d, &q, &rng)
601 .unwrap();
602 let rng = test::rand::FixedSliceRandom { bytes: &k };
603
604 let actual_result = private_key
605 .sign_with_fixed_nonce_during_test(&rng, &msg)
606 .unwrap();
607
608 assert_eq!(actual_result.as_ref(), &expected_result[..]);
609
610 Ok(())
611 },
612 );
613 }
614}
615