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