January 23, 2019·5 min read·engineeringgosecuritycryptography

Go 1.11.5 bounds elliptic curve arithmetic

A modular subtraction loop in P-384 and P-521 could consume excessive CPU. Go 1.11.5 reduces the intermediate value before subtraction and removes the repeated correction.

An elliptic curve calculation can produce the right mathematical answer and still be unsafe to expose to a remote caller. The problem in Go's latest security release sits in the work required to reach that answer. A subtraction could leave an intermediate integer so far below zero that repeatedly adding the field modulus consumed excessive CPU. Go 1.11.5 changes the calculation so that this repeated correction is unnecessary.

The release history dates the release to January 23, 2019 and identifies the affected package as crypto/elliptic. Julie Qiu's release announcement also announces Go 1.10.8 with the security fix. The Go team recommends updating to one of these releases and choosing Go 1.11.5 when there is no reason to prefer the older branch.

I value Go's readable implementations because they make changes like this possible to inspect without reconstructing a large abstraction framework. Here the security consequence depends on a short arithmetic sequence. Understanding that sequence explains why a small patch warrants rebuilding programs that depend on it.

The expensive part of modular subtraction

The Go 1.11.5 elliptic implementation represents a curve's field modulus as P. Its generic arithmetic uses arbitrary precision integers from math/big. Calculations take place internally in Jacobian coordinates, with a conversion back to ordinary affine coordinates when required. The source comments explain that keeping calculations in this representation saves work during scalar multiplication.

Inside doubleJacobian, the implementation calculates an intermediate named beta8 by shifting beta left by three bits. It then subtracts that value from another intermediate, x3. The release comparison shows that the previous implementation corrected a negative result by adding P in a loop. A final modular reduction followed that loop.

The arithmetic issue is the size of the negative intermediate. Adding a positive modulus moves the value toward zero, but the number of additions depends on how far below zero the subtraction went. An unusually large beta8 therefore makes the loop expensive. The commit message explicitly identifies crafted inputs to ScalarMult as the route to excessive CPU consumption in the P-384 and P-521 implementations.

The fix reduces beta8 modulo P before subtracting it. It also replaces the repeated addition with one conditional addition. In the patched source, the relevant sequence is short enough to read directly.

beta8 := new(big.Int).Lsh(beta, 3)
beta8.Mod(beta8, curve.P)
x3.Sub(x3, beta8)
if x3.Sign() == -1 {
    x3.Add(x3, curve.P)
}
x3.Mod(x3, curve.P)

Reducing the subtraction term preserves its value in the finite field while limiting its magnitude. That removes the reason for repeatedly adding the modulus to compensate for this term. The change belongs before the subtraction because a reduction after the old loop cannot recover the CPU time already spent inside it.

This distinction matters when reading cryptographic code. An eventual modular reduction does not by itself bound the cost of every operation that precedes it. The order of the operations determines whether an attacker can make an intermediate representation expensive even when the final field element has a small, fixed size.

The affected inputs extend beyond a TLS server

The security issue identifies the vulnerability as CVE-2019-6486 and credits the Wycheproof project with finding and reporting it. The disclosure names TLS handshakes and X.509 certificates among the possible carriers of malicious inputs. It also includes JWT tokens, ECDH shares and ECDSA signatures.

Those examples describe ways data can reach the affected arithmetic. They do not establish that every program handling any of these formats is vulnerable. A useful assessment follows the actual curve operation and implementation used by a program. The disclosure specifically names P-384 and P-521, so describing the issue as a defect in every Go elliptic curve would overstate the published finding.

Authentication code is relevant even when an application never calls ScalarMult directly. A program may reach cryptographic operations through protocol or verification code. Conversely, the presence of a token parser alone does not prove that it reaches this implementation. The advisory's list is a reason to examine these paths, with the affected curves as the concrete criterion.

The immediate availability risk is excessive CPU consumption. A request that causes disproportionately expensive arithmetic can occupy processing capacity needed by other work. This is an inference from the documented denial-of-service mechanism, not a claim about a measured slowdown or a particular deployment. The disclosure gives no universal request cost, and the patch provides no basis for inventing one.

Key recovery has an additional condition

The Go team also warns that the attack can lead to key recovery in some cases when an ECDH private key is reused more than once. That statement deserves separate treatment from the CPU problem. It adds a condition involving how a private key is used, and it does not say that every affected handshake exposes a key.

The public issue repeats the conditional warning without presenting a complete key-recovery procedure. A post about this release should preserve that limit. There is enough information to treat repeated use of an ECDH private key as a serious concern in affected code, but insufficient information in these disclosures to claim a general compromise of all ECDSA keys or all certificates.

I prefer this precision because operational decisions depend on the difference. Rebuilding affected software addresses the arithmetic defect. Assessing possible key exposure also requires knowing whether the deployment used the affected ECDH operation and reused its private key under the conditions described by the advisory. Those are related questions with different evidence requirements.

What changes for a deployed program

The release supplies corrected standard library code. The source comparison makes the scope concrete, with the arithmetic change in crypto/elliptic and release bookkeeping alongside it. Application authors do not need to introduce a new curve interface to receive this fix. They need a program built with a corrected implementation.

For a program that incorporates the affected Go standard library code in its executable, installing a new compiler beside an existing executable does not replace that executable's arithmetic. The practical response includes rebuilding and deploying the program with the patched toolchain. This follows from where the changed code lives, rather than from any new application-level configuration in the advisory.

The readable patch is also a useful reminder of what code review must establish in numeric code. Modular equivalence explains the result of the calculation, while the range of each intermediate explains its cost. Go 1.11.5 changes that range before subtraction, so the correction no longer requires an attacker-influenced number of repeated additions.