ring/ec/suite_b/ecdsa/
verification.rs

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    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.
28pub 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)]
41enum 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
50derive_debug_via_id!(EcdsaVerificationAlgorithm);
51
52impl signature::VerificationAlgorithm for EcdsaVerificationAlgorithm {
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
73impl EcdsaVerificationAlgorithm {
74    /// This is intentionally not public.
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_vartime(&r_jacobian, &x)
154        }
155        let mut 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            self.ops
161                .private_key_ops
162                .common
163                .elem_add(&mut r, &public_key_ops.common.n);
164            if sig_r_equals_x(self.ops, &r, &x, &z2) {
165                return Ok(());
166            }
167        }
168
169        Err(error::Unspecified)
170    }
171}
172
173impl sealed::Sealed for EcdsaVerificationAlgorithm {}
174
175fn split_rs_fixed<'a>(
176    ops: &'static ScalarOps,
177    input: &mut untrusted::Reader<'a>,
178) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified> {
179    let scalar_len = ops.scalar_bytes_len();
180    let r = input.read_bytes(scalar_len)?;
181    let s = input.read_bytes(scalar_len)?;
182    Ok((r, s))
183}
184
185fn split_rs_asn1<'a>(
186    _ops: &'static ScalarOps,
187    input: &mut untrusted::Reader<'a>,
188) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified> {
189    der::nested(input, der::Tag::Sequence, error::Unspecified, |input| {
190        let r = der::positive_integer(input)?.big_endian_without_leading_zero_as_input();
191        let s = der::positive_integer(input)?.big_endian_without_leading_zero_as_input();
192        Ok((r, s))
193    })
194}
195
196fn twin_mul(
197    ops: &PrivateKeyOps,
198    g_scalar: &Scalar,
199    p_scalar: &Scalar,
200    p_xy: &(Elem<R>, Elem<R>),
201) -> Point {
202    // XXX: Inefficient. TODO: implement interleaved wNAF multiplication.
203    let scaled_g = ops.point_mul_base(g_scalar);
204    let scaled_p = ops.point_mul(p_scalar, p_xy);
205    ops.common.point_sum(&scaled_g, &scaled_p)
206}
207
208/// Verification of fixed-length (PKCS#11 style) ECDSA signatures using the
209/// P-256 curve and SHA-256.
210///
211/// See "`ECDSA_*_FIXED` Details" in `ring::signature`'s module-level
212/// documentation for more details.
213pub static ECDSA_P256_SHA256_FIXED: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
214    ops: &p256::PUBLIC_SCALAR_OPS,
215    digest_alg: &digest::SHA256,
216    split_rs: split_rs_fixed,
217    id: AlgorithmID::ECDSA_P256_SHA256_FIXED,
218};
219
220/// Verification of fixed-length (PKCS#11 style) ECDSA signatures using the
221/// P-384 curve and SHA-384.
222///
223/// See "`ECDSA_*_FIXED` Details" in `ring::signature`'s module-level
224/// documentation for more details.
225pub static ECDSA_P384_SHA384_FIXED: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
226    ops: &p384::PUBLIC_SCALAR_OPS,
227    digest_alg: &digest::SHA384,
228    split_rs: split_rs_fixed,
229    id: AlgorithmID::ECDSA_P384_SHA384_FIXED,
230};
231
232/// Verification of ASN.1 DER-encoded ECDSA signatures using the P-256 curve
233/// and SHA-256.
234///
235/// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
236/// documentation for more details.
237pub static ECDSA_P256_SHA256_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
238    ops: &p256::PUBLIC_SCALAR_OPS,
239    digest_alg: &digest::SHA256,
240    split_rs: split_rs_asn1,
241    id: AlgorithmID::ECDSA_P256_SHA256_ASN1,
242};
243
244/// *Not recommended*. Verification of ASN.1 DER-encoded ECDSA signatures using
245/// the P-256 curve and SHA-384.
246///
247/// In most situations, P-256 should be used only with SHA-256 and P-384
248/// should be used only with SHA-384. However, in some cases, particularly TLS
249/// on the web, it is necessary to support P-256 with SHA-384 for compatibility
250/// with widely-deployed implementations that do not follow these guidelines.
251///
252/// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
253/// documentation for more details.
254pub static ECDSA_P256_SHA384_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
255    ops: &p256::PUBLIC_SCALAR_OPS,
256    digest_alg: &digest::SHA384,
257    split_rs: split_rs_asn1,
258    id: AlgorithmID::ECDSA_P256_SHA384_ASN1,
259};
260
261/// *Not recommended*. Verification of ASN.1 DER-encoded ECDSA signatures using
262/// the P-384 curve and SHA-256.
263///
264/// In most situations, P-256 should be used only with SHA-256 and P-384
265/// should be used only with SHA-384. However, in some cases, particularly TLS
266/// on the web, it is necessary to support P-256 with SHA-384 for compatibility
267/// with widely-deployed implementations that do not follow these guidelines.
268///
269/// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
270/// documentation for more details.
271pub static ECDSA_P384_SHA256_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
272    ops: &p384::PUBLIC_SCALAR_OPS,
273    digest_alg: &digest::SHA256,
274    split_rs: split_rs_asn1,
275    id: AlgorithmID::ECDSA_P384_SHA256_ASN1,
276};
277
278/// Verification of ASN.1 DER-encoded ECDSA signatures using the P-384 curve
279/// and SHA-384.
280///
281/// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level
282/// documentation for more details.
283pub static ECDSA_P384_SHA384_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm {
284    ops: &p384::PUBLIC_SCALAR_OPS,
285    digest_alg: &digest::SHA384,
286    split_rs: split_rs_asn1,
287    id: AlgorithmID::ECDSA_P384_SHA384_ASN1,
288};
289
290#[cfg(test)]
291mod tests {
292    use super::*;
293    use crate::test;
294    use alloc::vec::Vec;
295
296    #[test]
297    fn test_digest_based_test_vectors() {
298        test::run(
299            test_file!("../../../../crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt"),
300            |section, test_case| {
301                assert_eq!(section, "");
302
303                let curve_name = test_case.consume_string("Curve");
304
305                let public_key = {
306                    let mut public_key = Vec::new();
307                    public_key.push(0x04);
308                    public_key.extend(&test_case.consume_bytes("X"));
309                    public_key.extend(&test_case.consume_bytes("Y"));
310                    public_key
311                };
312
313                let digest = test_case.consume_bytes("Digest");
314
315                let sig = {
316                    let mut sig = Vec::new();
317                    sig.extend(&test_case.consume_bytes("R"));
318                    sig.extend(&test_case.consume_bytes("S"));
319                    sig
320                };
321
322                let invalid = test_case.consume_optional_string("Invalid");
323
324                let alg = match curve_name.as_str() {
325                    "P-256" => &ECDSA_P256_SHA256_FIXED,
326                    "P-384" => &ECDSA_P384_SHA384_FIXED,
327                    _ => {
328                        panic!("Unsupported curve: {}", curve_name);
329                    }
330                };
331
332                let digest = super::super::digest_scalar::digest_bytes_scalar(
333                    &alg.ops.scalar_ops,
334                    &digest[..],
335                );
336                let actual_result = alg.verify_digest(
337                    untrusted::Input::from(&public_key[..]),
338                    digest,
339                    untrusted::Input::from(&sig[..]),
340                );
341                assert_eq!(actual_result.is_ok(), invalid.is_none());
342
343                Ok(())
344            },
345        );
346    }
347}