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 { |
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: Elem = { |
60 | // NSA Guide Step 2: "Use the selected hash function to compute H = |
61 | // Hash(M)." |
62 | let h: Digest = digest::digest(self.digest_alg, data: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, msg:h) |
67 | }; |
68 | |
69 | self.verify_digest(public_key, e, signature) |
70 | } |
71 | } |
72 | |
73 | impl 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 = self.ops.scalar_inv_to_mont_vartime(&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 = (self.ops.twin_mul)(&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.scalar_ops.common.elem_add(&mut r, self.ops.n()); |
161 | if sig_r_equals_x(self.ops, &r, &x, &z2) { |
162 | return Ok(()); |
163 | } |
164 | } |
165 | |
166 | Err(error::Unspecified) |
167 | } |
168 | } |
169 | |
170 | impl sealed::Sealed for EcdsaVerificationAlgorithm {} |
171 | |
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: usize = ops.scalar_bytes_len(); |
177 | let r: Input<'_> = input.read_bytes(num_bytes:scalar_len)?; |
178 | let s: Input<'_> = input.read_bytes(num_bytes:scalar_len)?; |
179 | Ok((r, s)) |
180 | } |
181 | |
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:error::Unspecified, |input: &mut Reader<'_>| { |
187 | let r: Input<'_> = der::positive_integer(input)?.big_endian_without_leading_zero_as_input(); |
188 | let s: Input<'_> = der::positive_integer(input)?.big_endian_without_leading_zero_as_input(); |
189 | Ok((r, s)) |
190 | }) |
191 | } |
192 | |
193 | /// Verification of fixed-length (PKCS#11 style) ECDSA signatures using the |
194 | /// P-256 curve and SHA-256. |
195 | /// |
196 | /// See "`ECDSA_*_FIXED` Details" in `ring::signature`'s module-level |
197 | /// documentation for more details. |
198 | pub static ECDSA_P256_SHA256_FIXED: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm { |
199 | ops: &p256::PUBLIC_SCALAR_OPS, |
200 | digest_alg: &digest::SHA256, |
201 | split_rs: split_rs_fixed, |
202 | id: AlgorithmID::ECDSA_P256_SHA256_FIXED, |
203 | }; |
204 | |
205 | /// Verification of fixed-length (PKCS#11 style) ECDSA signatures using the |
206 | /// P-384 curve and SHA-384. |
207 | /// |
208 | /// See "`ECDSA_*_FIXED` Details" in `ring::signature`'s module-level |
209 | /// documentation for more details. |
210 | pub static ECDSA_P384_SHA384_FIXED: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm { |
211 | ops: &p384::PUBLIC_SCALAR_OPS, |
212 | digest_alg: &digest::SHA384, |
213 | split_rs: split_rs_fixed, |
214 | id: AlgorithmID::ECDSA_P384_SHA384_FIXED, |
215 | }; |
216 | |
217 | /// Verification of ASN.1 DER-encoded ECDSA signatures using the P-256 curve |
218 | /// and SHA-256. |
219 | /// |
220 | /// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level |
221 | /// documentation for more details. |
222 | pub static ECDSA_P256_SHA256_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm { |
223 | ops: &p256::PUBLIC_SCALAR_OPS, |
224 | digest_alg: &digest::SHA256, |
225 | split_rs: split_rs_asn1, |
226 | id: AlgorithmID::ECDSA_P256_SHA256_ASN1, |
227 | }; |
228 | |
229 | /// *Not recommended*. Verification of ASN.1 DER-encoded ECDSA signatures using |
230 | /// the P-256 curve and SHA-384. |
231 | /// |
232 | /// In most situations, P-256 should be used only with SHA-256 and P-384 |
233 | /// should be used only with SHA-384. However, in some cases, particularly TLS |
234 | /// on the web, it is necessary to support P-256 with SHA-384 for compatibility |
235 | /// with widely-deployed implementations that do not follow these guidelines. |
236 | /// |
237 | /// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level |
238 | /// documentation for more details. |
239 | pub static ECDSA_P256_SHA384_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm { |
240 | ops: &p256::PUBLIC_SCALAR_OPS, |
241 | digest_alg: &digest::SHA384, |
242 | split_rs: split_rs_asn1, |
243 | id: AlgorithmID::ECDSA_P256_SHA384_ASN1, |
244 | }; |
245 | |
246 | /// *Not recommended*. Verification of ASN.1 DER-encoded ECDSA signatures using |
247 | /// the P-384 curve and SHA-256. |
248 | /// |
249 | /// In most situations, P-256 should be used only with SHA-256 and P-384 |
250 | /// should be used only with SHA-384. However, in some cases, particularly TLS |
251 | /// on the web, it is necessary to support P-256 with SHA-384 for compatibility |
252 | /// with widely-deployed implementations that do not follow these guidelines. |
253 | /// |
254 | /// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level |
255 | /// documentation for more details. |
256 | pub static ECDSA_P384_SHA256_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm { |
257 | ops: &p384::PUBLIC_SCALAR_OPS, |
258 | digest_alg: &digest::SHA256, |
259 | split_rs: split_rs_asn1, |
260 | id: AlgorithmID::ECDSA_P384_SHA256_ASN1, |
261 | }; |
262 | |
263 | /// Verification of ASN.1 DER-encoded ECDSA signatures using the P-384 curve |
264 | /// and SHA-384. |
265 | /// |
266 | /// See "`ECDSA_*_ASN1` Details" in `ring::signature`'s module-level |
267 | /// documentation for more details. |
268 | pub static ECDSA_P384_SHA384_ASN1: EcdsaVerificationAlgorithm = EcdsaVerificationAlgorithm { |
269 | ops: &p384::PUBLIC_SCALAR_OPS, |
270 | digest_alg: &digest::SHA384, |
271 | split_rs: split_rs_asn1, |
272 | id: AlgorithmID::ECDSA_P384_SHA384_ASN1, |
273 | }; |
274 | |
275 | #[cfg (test)] |
276 | mod tests { |
277 | extern crate alloc; |
278 | use super::*; |
279 | use crate::test; |
280 | use alloc::{vec, vec::Vec}; |
281 | |
282 | #[test ] |
283 | fn test_digest_based_test_vectors() { |
284 | test::run( |
285 | test_file!("../../../../crypto/fipsmodule/ecdsa/ecdsa_verify_tests.txt" ), |
286 | |section, test_case| { |
287 | assert_eq!(section, "" ); |
288 | |
289 | let curve_name = test_case .consume_string("Curve" ); |
290 | |
291 | let public_key = { |
292 | let mut public_key = vec![0x04]; |
293 | public_key.extend(&test_case .consume_bytes("X" )); |
294 | public_key.extend(&test_case .consume_bytes("Y" )); |
295 | public_key |
296 | }; |
297 | |
298 | let digest = test_case .consume_bytes("Digest" ); |
299 | |
300 | let sig = { |
301 | let mut sig = Vec::new(); |
302 | sig.extend(&test_case .consume_bytes("R" )); |
303 | sig.extend(&test_case .consume_bytes("S" )); |
304 | sig |
305 | }; |
306 | |
307 | let invalid = test_case .consume_optional_string("Invalid" ); |
308 | |
309 | let alg = match curve_name.as_str() { |
310 | "P-256" => &ECDSA_P256_SHA256_FIXED, |
311 | "P-384" => &ECDSA_P384_SHA384_FIXED, |
312 | _ => { |
313 | panic!("Unsupported curve: {}" , curve_name); |
314 | } |
315 | }; |
316 | |
317 | let digest = super::super::digest_scalar::digest_bytes_scalar( |
318 | alg.ops.scalar_ops, |
319 | &digest[..], |
320 | ); |
321 | let actual_result = alg.verify_digest( |
322 | untrusted::Input::from(&public_key[..]), |
323 | digest, |
324 | untrusted::Input::from(&sig[..]), |
325 | ); |
326 | assert_eq!(actual_result.is_ok(), invalid.is_none()); |
327 | |
328 | Ok(()) |
329 | }, |
330 | ); |
331 | } |
332 | } |
333 | |