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 
17 use super::digest_scalar::digest_scalar;
18 use crate::{
19     arithmetic::montgomery::*,
20     digest,
21     ec::suite_b::{ops::*, public_key::*, verify_jacobian_point_is_on_the_curve},
22     error,
23     io::der,
24     limb, sealed, signature,
25 };
26 
27 /// An ECDSA verification algorithm.
28 pub struct EcdsaVerificationAlgorithm {
29     ops: &'static PublicScalarOps,
30     digest_alg: &'static digest::Algorithm,
31     split_rs:
32         for<'a> fn(
33             ops: &'static ScalarOps,
34             input: &mut untrusted::Reader<'a>,
35         )
36             -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified>,
37     id: AlgorithmID,
38 }
39 
40 #[derive(Debug)]
41 enum AlgorithmID {
42     ECDSA_P256_SHA256_ASN1,
43     ECDSA_P256_SHA256_FIXED,
44     ECDSA_P256_SHA384_ASN1,
45     ECDSA_P384_SHA256_ASN1,
46     ECDSA_P384_SHA384_ASN1,
47     ECDSA_P384_SHA384_FIXED,
48 }
49 
50 derive_debug_via_id!(EcdsaVerificationAlgorithm);
51 
52 impl signature::VerificationAlgorithm for EcdsaVerificationAlgorithm {
verify( &self, public_key: untrusted::Input, msg: untrusted::Input, signature: untrusted::Input, ) -> Result<(), error::Unspecified>53     fn verify(
54         &self,
55         public_key: untrusted::Input,
56         msg: untrusted::Input,
57         signature: untrusted::Input,
58     ) -> Result<(), error::Unspecified> {
59         let e = {
60             // NSA Guide Step 2: "Use the selected hash function to compute H =
61             // Hash(M)."
62             let h = digest::digest(self.digest_alg, msg.as_slice_less_safe());
63 
64             // NSA Guide Step 3: "Convert the bit string H to an integer e as
65             // described in Appendix B.2."
66             digest_scalar(self.ops.scalar_ops, h)
67         };
68 
69         self.verify_digest(public_key, e, signature)
70     }
71 }
72 
73 impl EcdsaVerificationAlgorithm {
74     /// This is intentionally not public.
verify_digest( &self, public_key: untrusted::Input, e: Scalar, signature: untrusted::Input, ) -> Result<(), error::Unspecified>75     fn verify_digest(
76         &self,
77         public_key: untrusted::Input,
78         e: Scalar,
79         signature: untrusted::Input,
80     ) -> Result<(), error::Unspecified> {
81         // NSA Suite B Implementer's Guide to ECDSA Section 3.4.2.
82 
83         let public_key_ops = self.ops.public_key_ops;
84         let scalar_ops = self.ops.scalar_ops;
85 
86         // NSA Guide Prerequisites:
87         //
88         //    Prior to accepting a verified digital signature as valid the
89         //    verifier shall have:
90         //
91         //    1. assurance of the signatory’s claimed identity,
92         //    2. an authentic copy of the domain parameters, (q, FR, a, b, SEED,
93         //       G, n, h),
94         //    3. assurance of the validity of the public key, and
95         //    4. assurance that the claimed signatory actually possessed the
96         //       private key that was used to generate the digital signature at
97         //       the time that the signature was generated.
98         //
99         // Prerequisites #1 and #4 are outside the scope of what this function
100         // can do. Prerequisite #2 is handled implicitly as the domain
101         // parameters are hard-coded into the source. Prerequisite #3 is
102         // handled by `parse_uncompressed_point`.
103         let peer_pub_key = parse_uncompressed_point(public_key_ops, public_key)?;
104 
105         let (r, s) = signature.read_all(error::Unspecified, |input| {
106             (self.split_rs)(scalar_ops, input)
107         })?;
108 
109         // NSA Guide Step 1: "If r and s are not both integers in the interval
110         // [1, n − 1], output INVALID."
111         let r = scalar_parse_big_endian_variable(public_key_ops.common, limb::AllowZero::No, r)?;
112         let s = scalar_parse_big_endian_variable(public_key_ops.common, limb::AllowZero::No, s)?;
113 
114         // NSA Guide Step 4: "Compute w = s**−1 mod n, using the routine in
115         // Appendix B.1."
116         let w = scalar_ops.scalar_inv_to_mont(&s);
117 
118         // NSA Guide Step 5: "Compute u1 = (e * w) mod n, and compute
119         // u2 = (r * w) mod n."
120         let u1 = scalar_ops.scalar_product(&e, &w);
121         let u2 = scalar_ops.scalar_product(&r, &w);
122 
123         // NSA Guide Step 6: "Compute the elliptic curve point
124         // R = (xR, yR) = u1*G + u2*Q, using EC scalar multiplication and EC
125         // addition. If R is equal to the point at infinity, output INVALID."
126         let product = twin_mul(self.ops.private_key_ops, &u1, &u2, &peer_pub_key);
127 
128         // Verify that the point we computed is on the curve; see
129         // `verify_affine_point_is_on_the_curve_scaled` for details on why. It
130         // would be more secure to do the check on the affine coordinates if we
131         // were going to convert to affine form (again, see
132         // `verify_affine_point_is_on_the_curve_scaled` for details on why).
133         // But, we're going to avoid converting to affine for performance
134         // reasons, so we do the verification using the Jacobian coordinates.
135         let z2 = verify_jacobian_point_is_on_the_curve(public_key_ops.common, &product)?;
136 
137         // NSA Guide Step 7: "Compute v = xR mod n."
138         // NSA Guide Step 8: "Compare v and r0. If v = r0, output VALID;
139         // otherwise, output INVALID."
140         //
141         // Instead, we use Greg Maxwell's trick to avoid the inversion mod `q`
142         // that would be necessary to compute the affine X coordinate.
143         let x = public_key_ops.common.point_x(&product);
144         fn sig_r_equals_x(
145             ops: &PublicScalarOps,
146             r: &Elem<Unencoded>,
147             x: &Elem<R>,
148             z2: &Elem<R>,
149         ) -> bool {
150             let cops = ops.public_key_ops.common;
151             let r_jacobian = cops.elem_product(z2, r);
152             let x = cops.elem_unencoded(x);
153             ops.elem_equals(&r_jacobian, &x)
154         }
155         let r = self.ops.scalar_as_elem(&r);
156         if sig_r_equals_x(self.ops, &r, &x, &z2) {
157             return Ok(());
158         }
159         if self.ops.elem_less_than(&r, &self.ops.q_minus_n) {
160             let r_plus_n = self.ops.elem_sum(&r, &public_key_ops.common.n);
161             if sig_r_equals_x(self.ops, &r_plus_n, &x, &z2) {
162                 return Ok(());
163             }
164         }
165 
166         Err(error::Unspecified)
167     }
168 }
169 
170 impl sealed::Sealed for EcdsaVerificationAlgorithm {}
171 
split_rs_fixed<'a>( ops: &'static ScalarOps, input: &mut untrusted::Reader<'a>, ) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified>172 fn split_rs_fixed<'a>(
173     ops: &'static ScalarOps,
174     input: &mut untrusted::Reader<'a>,
175 ) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified> {
176     let scalar_len = ops.scalar_bytes_len();
177     let r = input.read_bytes(scalar_len)?;
178     let s = input.read_bytes(scalar_len)?;
179     Ok((r, s))
180 }
181 
split_rs_asn1<'a>( _ops: &'static ScalarOps, input: &mut untrusted::Reader<'a>, ) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified>182 fn split_rs_asn1<'a>(
183     _ops: &'static ScalarOps,
184     input: &mut untrusted::Reader<'a>,
185 ) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified> {
186     der::nested(input, der::Tag::Sequence, error::Unspecified, |input| {
187         let r = der::positive_integer(input)?.big_endian_without_leading_zero_as_input();
188         let s = der::positive_integer(input)?.big_endian_without_leading_zero_as_input();
189         Ok((r, s))
190     })
191 }
192 
twin_mul( ops: &PrivateKeyOps, g_scalar: &Scalar, p_scalar: &Scalar, p_xy: &(Elem<R>, Elem<R>), ) -> Point193 fn twin_mul(
194     ops: &PrivateKeyOps,
195     g_scalar: &Scalar,
196     p_scalar: &Scalar,
197     p_xy: &(Elem<R>, Elem<R>),
198 ) -> Point {
199     // XXX: Inefficient. TODO: implement interleaved wNAF multiplication.
200     let scaled_g = ops.point_mul_base(g_scalar);
201     let scaled_p = ops.point_mul(p_scalar, p_xy);
202     ops.common.point_sum(&scaled_g, &scaled_p)
203 }
204 
205 /// Verification of fixed-length (PKCS#11 style) ECDSA signatures using the
206 /// P-256 curve and SHA-256.
207 ///
208 /// See "`ECDSA_*_FIXED` Details" in `ring::signature`'s module-level
209 /// documentation for more details.
210 pub static ECDSA_P256_SHA256_FIXED: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
211     ops: &p256::PUBLIC_SCALAR_OPS,
212     digest_alg: &digest::SHA256,
213     split_rs: split_rs_fixed,
214     id: AlgorithmID::ECDSA_P256_SHA256_FIXED,
215 };
216 
217 /// Verification of fixed-length (PKCS#11 style) ECDSA signatures using the
218 /// P-384 curve and SHA-384.
219 ///
220 /// See "`ECDSA_*_FIXED` Details" in `ring::signature`'s module-level
221 /// documentation for more details.
222 pub static ECDSA_P384_SHA384_FIXED: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
223     ops: &p384::PUBLIC_SCALAR_OPS,
224     digest_alg: &digest::SHA384,
225     split_rs: split_rs_fixed,
226     id: AlgorithmID::ECDSA_P384_SHA384_FIXED,
227 };
228 
229 /// Verification of ASN.1 DER-encoded ECDSA signatures using the P-256 curve
230 /// and SHA-256.
231 ///
232 /// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
233 /// documentation for more details.
234 pub static ECDSA_P256_SHA256_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
235     ops: &p256::PUBLIC_SCALAR_OPS,
236     digest_alg: &digest::SHA256,
237     split_rs: split_rs_asn1,
238     id: AlgorithmID::ECDSA_P256_SHA256_ASN1,
239 };
240 
241 /// *Not recommended*. Verification of ASN.1 DER-encoded ECDSA signatures using
242 /// the P-256 curve and SHA-384.
243 ///
244 /// In most situations, P-256 should be used only with SHA-256 and P-384
245 /// should be used only with SHA-384. However, in some cases, particularly TLS
246 /// on the web, it is necessary to support P-256 with SHA-384 for compatibility
247 /// with widely-deployed implementations that do not follow these guidelines.
248 ///
249 /// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
250 /// documentation for more details.
251 pub static ECDSA_P256_SHA384_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
252     ops: &p256::PUBLIC_SCALAR_OPS,
253     digest_alg: &digest::SHA384,
254     split_rs: split_rs_asn1,
255     id: AlgorithmID::ECDSA_P256_SHA384_ASN1,
256 };
257 
258 /// *Not recommended*. Verification of ASN.1 DER-encoded ECDSA signatures using
259 /// the P-384 curve and SHA-256.
260 ///
261 /// In most situations, P-256 should be used only with SHA-256 and P-384
262 /// should be used only with SHA-384. However, in some cases, particularly TLS
263 /// on the web, it is necessary to support P-256 with SHA-384 for compatibility
264 /// with widely-deployed implementations that do not follow these guidelines.
265 ///
266 /// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
267 /// documentation for more details.
268 pub static ECDSA_P384_SHA256_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
269     ops: &p384::PUBLIC_SCALAR_OPS,
270     digest_alg: &digest::SHA256,
271     split_rs: split_rs_asn1,
272     id: AlgorithmID::ECDSA_P384_SHA256_ASN1,
273 };
274 
275 /// Verification of ASN.1 DER-encoded ECDSA signatures using the P-384 curve
276 /// and SHA-384.
277 ///
278 /// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
279 /// documentation for more details.
280 pub static ECDSA_P384_SHA384_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
281     ops: &p384::PUBLIC_SCALAR_OPS,
282     digest_alg: &digest::SHA384,
283     split_rs: split_rs_asn1,
284     id: AlgorithmID::ECDSA_P384_SHA384_ASN1,
285 };
286 
287 #[cfg(test)]
288 mod tests {
289     use super::*;
290     use crate::test;
291     use alloc::vec::Vec;
292 
293     #[test]
test_digest_based_test_vectors()294     fn test_digest_based_test_vectors() {
295         test::run(
296             test_file!("../../../../crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt"),
297             |section, test_case| {
298                 assert_eq!(section, "");
299 
300                 let curve_name = test_case.consume_string("Curve");
301 
302                 let public_key = {
303                     let mut public_key = Vec::new();
304                     public_key.push(0x04);
305                     public_key.extend(&test_case.consume_bytes("X"));
306                     public_key.extend(&test_case.consume_bytes("Y"));
307                     public_key
308                 };
309 
310                 let digest = test_case.consume_bytes("Digest");
311 
312                 let sig = {
313                     let mut sig = Vec::new();
314                     sig.extend(&test_case.consume_bytes("R"));
315                     sig.extend(&test_case.consume_bytes("S"));
316                     sig
317                 };
318 
319                 let invalid = test_case.consume_optional_string("Invalid");
320 
321                 let alg = match curve_name.as_str() {
322                     "P-256" => &ECDSA_P256_SHA256_FIXED,
323                     "P-384" => &ECDSA_P384_SHA384_FIXED,
324                     _ => {
325                         panic!("Unsupported curve: {}", curve_name);
326                     }
327                 };
328 
329                 let digest = super::super::digest_scalar::digest_bytes_scalar(
330                     &alg.ops.scalar_ops,
331                     &digest[..],
332                 );
333                 let actual_result = alg.verify_digest(
334                     untrusted::Input::from(&public_key[..]),
335                     digest,
336                     untrusted::Input::from(&sig[..]),
337                 );
338                 assert_eq!(actual_result.is_ok(), invalid.is_none());
339 
340                 Ok(())
341             },
342         );
343     }
344 }
345