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_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
173 impl sealed::Sealed for EcdsaVerificationAlgorithm {}
174
split_rs_fixed<'a>( ops: &'static ScalarOps, input: &mut untrusted::Reader<'a>, ) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified>175 fn 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
split_rs_asn1<'a>( _ops: &'static ScalarOps, input: &mut untrusted::Reader<'a>, ) -> Result<(untrusted::Input<'a>, untrusted::Input<'a>), error::Unspecified>185 fn 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
twin_mul( ops: &PrivateKeyOps, g_scalar: &Scalar, p_scalar: &Scalar, p_xy: &(Elem<R>, Elem<R>), ) -> Point196 fn 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.
213 pub 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.
225 pub 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.
237 pub 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.
254 pub 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.
271 pub 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.
283 pub 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)]
291 mod tests {
292 extern crate alloc;
293 use super::*;
294 use crate::test;
295 use alloc::{vec, vec::Vec};
296
297 #[test]
test_digest_based_test_vectors()298 fn test_digest_based_test_vectors() {
299 test::run(
300 test_file!("../../../../crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt"),
301 |section, test_case| {
302 assert_eq!(section, "");
303
304 let curve_name = test_case.consume_string("Curve");
305
306 let public_key = {
307 let mut public_key = vec![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 }
348