This partially fixes a bug where, on x86_64, BN_mod_exp_mont_consttime
would sometimes return m, the modulus, when it should have returned
zero. Thanks to Guido Vranken for reporting it. It is only a partial fix
because the same bug also exists in the "rsaz" codepath. That will be
fixed in the subsequent CL. (See the commented out test.)
The bug only affects zero outputs (with non-zero inputs), so we believe
it has no security impact on our cryptographic functions. BoringSSL
calls BN_mod_exp_mont_consttime in the following cases:
- RSA private key operations
- Primality testing, raising the witness to the odd part of p-1
- DSA keygen and key import, pub = g^priv (mod p)
- DSA signing, r = g^k (mod p)
- DH keygen, pub = g^priv (mod p)
- Diffie-Hellman, secret = peer^priv (mod p)
It is not possible in the RSA private key operation, provided p and q
are primes. If using CRT, we are working modulo a prime, so zero output
with non-zero input is impossible. If not using CRT, we work mod n.
While there are nilpotent values mod n, none of them hit zero by
exponentiating. (Both p and q would need to divide the input, which
means n divides the input.)
In primality testing, this can only be hit when the input was composite.
But as the rest of the loop cannot then hit 1, we'll correctly report it
as composite anyway.
DSA and DH work modulo a prime, where this case cannot happen.
Analysis:
This bug is the result of sloppiness with the looser bounds from "almost
Montgomery multiplication", described in
https://eprint.iacr.org/2011/239. Prior to upstream's
ec9cc70f72454b8d4a84247c86159613cee83b81, I believe x86_64-mont5.pl
implemented standard Montgomery reduction (the left half of figure 3 in
the paper).
Though it did not document this, ec9cc70f7245 changed it to implement
the "almost" variant (the right half of the figure.) The difference is
that, rather than subtracting if T >= m, it subtracts if T >= R. In
code, it is the difference between something like our bn_reduce_once,
vs. subtracting based only on T's carry bit. (Interestingly, the
.Lmul_enter branch of bn_mul_mont_gather5 seems to still implement
normal reduction, but the .Lmul4x_enter branch is an almost reduction.)
That means none of the intermediate values here are bounded by m. They
are only bounded by R. Accordingly, Figure 2 in the paper ends with
step 10: REDUCE h modulo m. BN_mod_exp_mont_consttime is missing this
step. The bn_from_montgomery call only implements step 9, AMM(h, 1).
(x86_64-mont5.pl's bn_from_montgomery only implements an almost
reduction.)
The impact depends on how unreduced AMM(h, 1) can be. Remark 1 of the
paper discusses this, but is ambiguous about the scope of its 2^(n-1) <
m < 2^n precondition. The m+1 bound appears to be unconditional:
Montgomery reduction ultimately adds some 0 <= Y < m*R to T, to get a
multiple of R, and then divides by R. The output, pre-subtraction, is
thus less than m + T/R. MM works because T < mR => T' < m + mR/R = 2m.
A single subtraction of m if T' >= m gives T'' < m. AMM works because
T < R^2 => T' < m + R^2/R = m + R. A single subtraction of m if T' >= R
gives T'' < R. See also Lemma 1, Section 3 and Section 4 of the paper,
though their formulation is more complicated to capture the word-by-word
algorithm. It's ultimately the same adjustment to T.
But in AMM(h, 1), T = h*1 = h < R, so AMM(h, 1) < m + R/R = m + 1. That
is, AMM(h, 1) <= m. So the only case when AMM(h, 1) isn't fully reduced
is if it outputs m. Thus, our limited impact. Indeed, Remark 1 mentions
step 10 isn't necessary because m is a prime and the inputs are
non-zero. But that doesn't apply here because BN_mod_exp_mont_consttime
may be called elsewhere.
Fix:
To fix this, we could add the missing step 10, but a full division would
not be constant-time. The analysis above says it could be a single
subtraction, bn_reduce_once, but then we could integrate it into
the subtraction already in plain Montgomery reduction, implemented by
uppercase BN_from_montgomery. h*1 = h < R <= m*R, so we are within
bounds.
Thus, we delete lowercase bn_from_montgomery altogether, and have the
mont5 path use the same BN_from_montgomery ending as the non-mont5 path.
This only impacts the final step of the whole exponentiation and has no
measurable perf impact.
In doing so, add comments describing these looser bounds. This includes
one subtlety that BN_mod_exp_mont_consttime actually mixes bn_mul_mont
(MM) with bn_mul_mont_gather5/bn_power5 (AMM). But this is fine because
MM is AMM-compatible; when passed AMM's looser inputs, it will still
produce a correct looser output.
Ideally we'd drop the "almost" reduction and stick to the more
straightforward bounds. As this only impacts the final subtraction in
each reduction, I would be surprised if it actually had a real
performance impact. But this would involve deeper change to
x86_64-mont5.pl, so I haven't tried this yet.
I believe this is basically the same bug as
https://github.com/golang/go/issues/13907 from Go.
Change-Id: I06f879777bb2ef181e9da7632ec858582e2afa38
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52825
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Ed25519 was disabled for WebAssembly due to some unrelated issues with
getting the X25519 code working in WebAssembly. Temporarily remove the
`agreement` API when targetting WebAssembly to work around those issues
in a way that lets us enabled Ed25519.
Don't package the inputs of the preassembly; just package the outputs.
Clarify how `mk/package.sh` interacts with `.gitignore`.
Eliminate unnecessary conditional logic in preassembly process.
The assembly headers used for Windows targets need to be generated during packaging so
that the assembly can be preassembled for those targets, but the C header isn't used
during packaging.
I agree to license my contributions to each file under the terms given at the top of each file I changed.
Co-authored-by: Marc-André Moreau <marcandre.moreau@gmail.com>
Localize the use of the "is git" check to a single place and use more
descriptive variables for the various effects that this check has.
As a nice side effect, the loosly-typed `warnings_are_errors` parameters
that were threaded through functions are now gone.
targets.
There is no case where we have .S files for -msvc targets, so this
filter doesn't filter anything out. IIRC, this is stale code from when
the situation was different in the past.
This reduces the amount of logic that is specific to "-msvc" targets and
makes the work to support clang and clang-cl for Windows, and to support
AAarch64 Windows, easier to review.
Now "links" in Cargo.toml is the only thing that needs to be manually modified
when the prefix changes.
build.rs enforces that the package name and version are consistent with the
"links" field.
Eliminate the extra Cargo.toml that was used just for this feature. It was
too error-prone to keep it in sync with the real Cargo.toml. Having one
Cargo.toml will allow us to reliably use the `CARGO_MANIFEST_LINKS` value
to keep the symbol prefix in sync with the `links` field in Cargo.toml in
the near future.
Revert the names used in the BoringSSL C/asm code to the names used in
BoringSSL. This substantially reduces the diff between *ring* and
BoringSSL for these files.
Use a variant of BoringSSL's symbol prefixing machinery to semi-
automatically prefix FFI symbols with the `GFp_` prefix. The names aren't
all exactly the same as before, because previously we *replaced* a
symbol's original prefix with the `GFp_` prefix; now we're prepending
`GFp_`. In the future we'll use a different prefix entirely.
This paves the way for using different prefixes for each version so that
multiple versions of *ring* can be linked into an executable at once.
Assume by default that an operating system does not have an ABI compatible
with the PerlAsm sources. Add all the operating systems that we've
explicitly added support for to the allowlist. Avoid trying to build or
use the PerlAsm code for those targets.
On top of this, we can build fallback logic for using Rust (or C)
implementations for those targets that aren't compatible with the
assembly.
Use Fiat Crypto for non-x86_64 platforms, like BoringSSL. Continue
using the nistz256 code on Windows, differently from BoringSSL.
Make *ring* more consistent with BoringSSL.
The newest Rust Nightly is getting stricter about `forbid(warnings)`
which breaks the build.
Use "deny" instead of "forbid". And only deny when running Clippy in
CI/CD, so that when hacking on *ring* we don't have to deal with
warnings right away; we now only have to deal with them when we're ready
to submit a change to be merged.
Avoid requiring a sysroot for *-linux-musl targets when using Clang.
Add one AAarch64 and one 32-bit ARM MUSL target to GitHub Actions.
Use Rust 1.48's `-Clink-self-contained=yes` in CI for musl targets.
Support the non-default variants of the *-musl targets.
Change the static CPU feature detection logic to assume all aarch64-apple-* targets
have the same capabilities as far as the features we use are concerned.
Use the "ios64" PerlAsm flavour for aarch64-apple-darwin, like OpenSSL upstream does.
Add (build-only) cross-compilation jobs to GitHub Actions.