In various situations, the toolchain invokes VCS commands. Some of these
commands take arbitrary input, either provided by users or fetched from
external sources. To prevent potential command injection vulnerabilities
or misinterpretation of arguments as flags, this change updates the VCS
commands to use various techniques to separate flags from positional
arguments, and to directly associate flags with their values.
Additionally, we update the environment variable for Mercurial to use
`HGPLAIN=+strictflags`, which is the more explicit way to disable user
configurations (intended or otherwise) that might interfere with command
execution.
We also now disallow version strings from being prefixed with '-' or
'/', as doing so opens us up to making the same mistake again in the
future. As far as we know there are currently ~0 public modules affected
by this.
While I was working on cmd/go/internal/vcs, I also noticed that a
significant portion of the commands being implemented were dead code.
In order to reduce the maintenance burden and surface area for potential
issues, I removed the dead code for unused commands.
We should probably follow up with a more structured change to make it
harder to accidentally re-introduce these issues in the future, but for
now this addresses the issue at hand.
Thanks to splitline (@splitline) from DEVCORE Research Team for
reporting this issue.
Fixes CVE-2025-68119
Fixes#77099
Change-Id: I9d9f4ee05b95be49fe14edf71a1b8e6c0784378e
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3260
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3342
Reviewed-by: Michael Matloob <matloob@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/736721
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Once a tls.Config is used, it is not safe to mutate. We provide the
Clone method in order to allow users to copy and modify a Config that
is in use.
If Config.SessionTicketKey is not populated, and if
Config.SetSessionTicketKeys has not been called, we automatically
populate and rotate session ticket keys. Clone was previously copying
these keys into the new Config, meaning that two Configs could share
the same auto-rotated session ticket keys. This could allow sessions to
be resumed across different Configs, which may have completely different
configurations.
This change updates Clone to not copy the auto-rotated session ticket
keys.
Additionally, when resuming a session, check that not just that the leaf
certificate is unexpired, but that the entire certificate chain is still
unexpired.
Fixes#77113
Fixes CVE-2025-68121
Change-Id: I011df7329de83068d11b3f0c793763692d018a98
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3300
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3321
Reviewed-on: https://go-review.googlesource.com/c/go/+/736720
Auto-Submit: Michael Pratt <mpratt@google.com>
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
For TLS 1.3, after procesesing the server/client hello, if there isn't a
CCS message, reject the trailing messages which were appended to the
hello messages. This prevents an on-path attacker from injecting
plaintext messages into the handshake.
Additionally, check that we don't have any buffered messages before we
switch the read traffic secret regardless, since any buffered messages
would have been under an old key which is no longer appropriate.
We also invert the ordering of setting the read/write secrets so that if
we fail when changing the read secret we send the alert using the
correct write secret.
Updates #76443Fixes#76855
Fixes CVE-2025-61730
Change-Id: If6ba8ad16f48d5cd5db5574824062ad4244a5b52
Reviewed-on: https://go-review.googlesource.com/c/go/+/724120
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
Reviewed-by: Coia Prant <coiaprant@gmail.com>
(cherry picked from commit 5046bdf8a6)
Reviewed-on: https://go-review.googlesource.com/c/go/+/731960
Reviewed-by: Damien Neil <dneil@google.com>
The ppc64x TSAN wrappers for atomic And/Or did not initialize R6 with the Go argument frame before calling racecallatomic. Since racecallatomic expects R6 to point to the argument list and dereferences it unconditionally, this led to a nil-pointer dereference under -race.
Other atomic TSAN wrappers (Load/Store/Add/Swap/CAS) already set up R6 in the expected way. This change aligns the And/Or wrappers with the rest by adding the missing R6 initialisation.
This keeps the behavior consistent across all atomic operations on ppc64x.
Updates #76776.
Change-Id: Iaf578449a6171a0c6f7c33ec6f64c1251297ae6d
Reviewed-on: https://go-review.googlesource.com/c/go/+/718560
Reviewed-by: Mark Freeman <markfreeman@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Paul Murphy <paumurph@redhat.com>
(cherry picked from commit 44cb82449e)
Reviewed-on: https://go-review.googlesource.com/c/go/+/728900
Reviewed-by: David Chase <drchase@google.com>
Constructing HostnameError.Error() takes O(N^2) runtime due to using a
string concatenation in a loop. Additionally, there is no limit on how
many names are included in the error message. As a result, a malicious
attacker could craft a certificate with an infinite amount of names to
unfairly consume resource.
To remediate this, we will now use strings.Builder to construct the
error message, preventing O(N^2) runtime. When a certificate has 100 or
more names, we will also not print each name individually.
Thanks to Philippe Antoine (Catena cyber) for reporting this issue.
Updates #76445Fixes#76461
Fixes CVE-2025-61729
Change-Id: I6343776ec3289577abc76dad71766c491c1a7c81
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3000
Reviewed-by: Neal Patel <nealpatel@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3200
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/725800
TryBot-Bypass: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Mark Freeman <markfreeman@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
CL 641955 changes the Unified IR reader to not doing shapify when
reading reshaping expression, prevent losing of the original type.
This is an oversight, as the main problem isn't about shaping during the
reshaping process itself, but about the specific case of shaping a
pointer shape type. This bug occurs when instantiating a generic
function within another generic function with a pointer shape type as
type parameter, which will convert `*[]go.shape.T` to `*go.shape.uint8`,
resulting in the loss of the original expression's type.
This commit changes Unified IR reader to avoid pointer shaping for
`*[]go.shape.T`, ensures that the original type is preserved when
processing reshaping expressions.
Fixes#75480
Change-Id: Icede6b73247d0d367bb485619f2dafb60ad66806
Reviewed-on: https://go-review.googlesource.com/c/go/+/704095
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/706216
Reviewed-by: Ed Schouten <ed@nuxi.nl>
Reviewed-by: Cherry Mui <cherryyz@google.com>
In CL 709854 we enabled strict validation for a number of properties of
domain names (and their constraints). This caused significant breakage,
since we didn't previously disallow the creation of certificates which
contained these malformed domains.
Rollback a number of the properties we enforced, making domainNameValid
only enforce the same properties that domainToReverseLabels does. Since
this also undoes some of the DoS protections our initial fix enabled,
this change also adds caching of constraints in isValid (which perhaps
is the fix we should've initially chosen).
Updates #75835
Updates #75828Fixes#75861
Change-Id: Ie6ca6b4f30e9b8a143692b64757f7bbf4671ed0e
Reviewed-on: https://go-review.googlesource.com/c/go/+/710735
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
(cherry picked from commit 1cd71689f2)
Reviewed-on: https://go-review.googlesource.com/c/go/+/710677
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Sparse files in tar archives contain only the non-zero components
of the file. There are several different encodings for sparse
files. When reading GNU tar pax 1.0 sparse files, archive/tar did
not set a limit on the size of the sparse region data. A malicious
archive containing a large number of sparse blocks could cause
archive/tar to read an unbounded amount of data from the archive
into memory.
Since a malicious input can be highly compressable, a small
compressed input could cause very large allocations.
Cap the size of the sparse block data to the same limit used
for PAX headers (1 MiB).
Thanks to Harshit Gupta (Mr HAX) (https://www.linkedin.com/in/iam-harshit-gupta/)
for reporting this issue.
Fixes CVE-2025-58183
For #75677Fixes#75711
Change-Id: I70b907b584a7b8676df8a149a1db728ae681a770
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2800
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2987
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/709852
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
Because Decode scanned the input first for the first BEGIN line, and
then the first END line, the complexity of Decode is quadratic. If the
input contained a large number of BEGINs and then a single END right at
the end of the input, we would find the first BEGIN, and then scan the
entire input for the END, and fail to parse the block, so move onto the
next BEGIN, scan the entire input for the END, etc.
Instead, look for the first END in the input, and then the first BEGIN
that precedes the found END. We then process the bytes between the BEGIN
and END, and move onto the bytes after the END for further processing.
This gives us linear complexity.
Fixes CVE-2025-61723
For #75676Fixes#75709
Change-Id: I813c4f63e78bca4054226c53e13865c781564ccf
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2921
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2985
Reviewed-on: https://go-review.googlesource.com/c/go/+/709851
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Within parseSequenceOf, reflect.MakeSlice is being used to pre-allocate
a slice that is needed in order to fully validate the given DER payload.
The size of the slice allocated are also multiple times larger than the
input DER:
- When using asn1.Unmarshal directly, the allocated slice is ~28x
larger.
- When passing in DER using x509.ParseCertificateRequest, the allocated
slice is ~48x larger.
- When passing in DER using ocsp.ParseResponse, the allocated slice is
~137x larger.
As a result, a malicious actor can craft a big empty DER payload,
resulting in an unnecessary large allocation of memories. This can be a
way to cause memory exhaustion.
To prevent this, we now use SliceCapWithSize within internal/saferio to
enforce a memory allocation cap.
Thanks to Jakub Ciolek for reporting this issue.
For #75671Fixes#75705
Fixes CVE-2025-58185
Change-Id: Id50e76187eda43f594be75e516b9ca1d2ae6f428
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2700
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2966
Reviewed-by: Nicholas Husin <husin@google.com>
Commit-Queue: Roland Shoemaker <bracewell@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/709850
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
When handling HTTP headers, net/http does not currently limit the number
of cookies that can be parsed. The only limitation that exists is for
the size of the entire HTTP header, which is controlled by
MaxHeaderBytes (defaults to 1 MB).
Unfortunately, this allows a malicious actor to send HTTP headers which
contain a massive amount of small cookies, such that as much cookies as
possible can be fitted within the MaxHeaderBytes limitation. Internally,
this causes us to allocate a massive number of Cookie struct.
For example, a 1 MB HTTP header with cookies that repeats "a=;" will
cause an allocation of ~66 MB in the heap. This can serve as a way for
malicious actors to induce memory exhaustion.
To fix this, we will now limit the number of cookies we are willing to
parse to 3000 by default. This behavior can be changed by setting a new
GODEBUG option: GODEBUG=httpcookiemaxnum. httpcookiemaxnum can be set to
allow a higher or lower cookie limit. Setting it to 0 will also allow an
infinite number of cookies to be parsed.
Thanks to jub0bs for reporting this issue.
For #75672Fixes#75707
Fixes CVE-2025-58186
Change-Id: Ied58b3bc8acf5d11c880f881f36ecbf1d5d52622
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2720
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2965
Reviewed-by: Nicholas Husin <husin@google.com>
Commit-Queue: Roland Shoemaker <bracewell@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/709849
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Michael Pratt <mpratt@google.com>
Don't use domainToReverseLabels to check if domain names are valid,
since it is not particularly performant, and can contribute to DoS
vectors. Instead just iterate over the name and enforce the properties
we care about.
This also enforces that DNS names, both in SANs and name constraints,
are valid. We previously allowed invalid SANs, because some
intermediates had these weird names (see #23995), but there are
currently no trusted intermediates that have this property, and since we
target the web PKI, supporting this particular case is not a high
priority.
Thank you to Jakub Ciolek for reporting this issue.
Fixes CVE-2025-58187
For #75681Fixes#75715
Change-Id: I6ebce847dcbe5fc63ef2f9a74f53f11c4c56d3d1
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2820
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2981
Commit-Queue: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/709848
Auto-Submit: Michael Pratt <mpratt@google.com>
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
- Previously, url.Parse did not enforce validation of hostnames within
square brackets.
- RFC 3986 stipulates that only IPv6 hostnames can be embedded within
square brackets in a URL.
- Now, the parsing logic should strictly enforce that only IPv6
hostnames can be resolved when in square brackets. IPv4, IPv4-mapped
addresses and other input will be rejected.
- Update url_test to add test cases that cover the above scenarios.
Thanks to Enze Wang, Jingcheng Yang and Zehui Miao of Tsinghua
University for reporting this issue.
Fixes CVE-2025-47912
For #75678Fixes#75713
Change-Id: Iaa41432bf0ee86de95a39a03adae5729e4deb46c
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2680
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2988
Commit-Queue: Roland Shoemaker <bracewell@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/709847
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
RFC 5322 domain-literal parsing built the dtext value one character
at a time with string concatenation, resulting in excessive
resource consumption when parsing very large domain-literal values.
Replace with a subslice.
Benchmark not included in this CL because it's too narrow to be
of general ongoing use, but for:
ParseAddress("alice@[" + strings.Repeat("a", 0x40000) + "]")
goos: darwin
goarch: arm64
pkg: net/mail
cpu: Apple M4 Pro
│ /tmp/bench.0 │ /tmp/bench.1 │
│ sec/op │ sec/op vs base │
ParseAddress-14 1987.732m ± 9% 1.524m ± 5% -99.92% (p=0.000 n=10)
│ /tmp/bench.0 │ /tmp/bench.1 │
│ B/op │ B/op vs base │
ParseAddress-14 33692.767Mi ± 0% 1.282Mi ± 0% -100.00% (p=0.000 n=10)
│ /tmp/bench.0 │ /tmp/bench.1 │
│ allocs/op │ allocs/op vs base │
ParseAddress-14 263711.00 ± 0% 17.00 ± 0% -99.99% (p=0.000 n=10)
Thanks to Philippe Antoine (Catena cyber) for reporting this issue.
Fixes CVE-2025-61725
For #75680Fixes#75701
Change-Id: Id971c2d5b59882bb476e22fceb7e01ec08234bb7
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2840
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2961
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/709844
TryBot-Bypass: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Pratt <mpratt@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Remove a race condition in counting the number of connections per host,
which can cause a connCount underflow and a panic.
The race occurs when:
- A RoundTrip call attempts to use a HTTP/2 roundtripper (pconn.alt != nil)
and receives an isNoCachedConn error. The call removes the pconn from
the idle conn pool and decrements the connCount for its host.
- A second RoundTrip call on the same pconn succeeds,
and delivers the pconn to a third RoundTrip waiting for a conn.
- The third RoundTrip receives the pconn at the same moment its request
context is canceled. It places the pconn back into the idle conn pool.
At this time, the connCount is incorrect, because the conn returned to
the idle pool is not matched by an increment in the connCount.
Fix this by not adding HTTP/2 pconns back to the idle pool in
wantConn.cancel.
For #61474Fixes#75539
Change-Id: I104d6cf85a54d0382eebf3fcf5dda99c69a7c3f6
Reviewed-on: https://go-review.googlesource.com/c/go/+/703936
Auto-Submit: Damien Neil <dneil@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Nicholas Husin <nsh@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
(cherry picked from commit 3203a5da29)
Reviewed-on: https://go-review.googlesource.com/c/go/+/705376
Reviewed-by: Cherry Mui <cherryyz@google.com>
The Context.Err documentation states that it returns nil if the
context's done channel is not closed. Fix a race condition introduced
by CL 653795 where Err could return a non-nil error slightly before
the Done channel is closed.
No impact on Err performance when returning nil.
Slows down Err when returning non-nil by about 3x,
but that's still almost 2x faster than before CL 653795
and the performance of this path is less important.
(A tight loop checking Err for doneness will be terminated
by the first Err call to return a non-nil result.)
goos: darwin
goarch: arm64
pkg: context
cpu: Apple M4 Pro
│ /tmp/bench.0 │ /tmp/bench.1 │
│ sec/op │ sec/op vs base │
ErrOK-14 1.806n ± 1% 1.774n ± 0% -1.77% (p=0.000 n=8)
ErrCanceled-14 1.821n ± 1% 7.525n ± 3% +313.23% (p=0.000 n=8)
geomean 1.813n 3.654n +101.47%
Fixes#75533Fixes#75537
Change-Id: Iea22781a199ace7e7f70cf65168c36e090cd2e2a
Reviewed-on: https://go-review.googlesource.com/c/go/+/705235
TryBot-Bypass: Damien Neil <dneil@google.com>
Reviewed-by: Nicholas Husin <husin@google.com>
Reviewed-by: Nicholas Husin <nsh@golang.org>
Auto-Submit: Damien Neil <dneil@google.com>
(cherry picked from commit 8ca209ec39)
Reviewed-on: https://go-review.googlesource.com/c/go/+/705375
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Exceptionally, we decided to make a compliance-related change following
CMVP's updated Implementation Guidance on September 2nd.
The Security Policy will be updated to reflect the new zip hash.
mkzip.go has been modified to accept versions of the form vX.Y.Z-hash,
where the -hash suffix is ignored for fips140.Version() but used to
name the zip file and the unpacked cache directory.
The new zip is generated with
go run ../../src/cmd/go/internal/fips140/mkzip.go -b c2097c7c v1.0.0-c2097c7c
from c2097c7c which is the current release-branch.go1.24 head.
The full diff between the zip file contents is included below.
Fixes#75524
For #74947
Updates #69536
$ diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/cast.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/cast.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/cast.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/cast.go 1980-01-10 00:00:00.000000000 +0100
@@ -56,9 +56,10 @@
}
// PCT runs the named Pairwise Consistency Test (if operated in FIPS mode) and
-// returns any errors. If an error is returned, the key must not be used.
+// aborts the program (stopping the module input/output and entering the "error
+// state") if the test fails.
//
-// PCTs are mandatory for every key pair that is generated/imported, including
+// PCTs are mandatory for every generated (but not imported) key pair, including
// ephemeral keys (which effectively doubles the cost of key establishment). See
// Implementation Guidance 10.3.A Additional Comment 1.
//
@@ -66,17 +67,23 @@
//
// If a package p calls PCT during key generation, an invocation of that
// function should be added to fipstest.TestConditionals.
-func PCT(name string, f func() error) error {
+func PCT(name string, f func() error) {
if strings.ContainsAny(name, ",#=:") {
panic("fips: invalid self-test name: " + name)
}
if !Enabled {
- return nil
+ return
}
err := f()
if name == failfipscast {
err = errors.New("simulated PCT failure")
}
- return err
+ if err != nil {
+ fatal("FIPS 140-3 self-test failed: " + name + ": " + err.Error())
+ panic("unreachable")
+ }
+ if debug {
+ println("FIPS 140-3 PCT passed:", name)
+ }
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/ecdh/ecdh.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ecdh/ecdh.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/ecdh/ecdh.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ecdh/ecdh.go 1980-01-10 00:00:00.000000000 +0100
@@ -161,6 +161,27 @@
if err != nil {
continue
}
+
+ // A "Pairwise Consistency Test" makes no sense if we just generated the
+ // public key from an ephemeral private key. Moreover, there is no way to
+ // check it aside from redoing the exact same computation again. SP 800-56A
+ // Rev. 3, Section 5.6.2.1.4 acknowledges that, and doesn't require it.
+ // However, ISO 19790:2012, Section 7.10.3.3 has a blanket requirement for a
+ // PCT for all generated keys (AS10.35) and FIPS 140-3 IG 10.3.A, Additional
+ // Comment 1 goes out of its way to say that "the PCT shall be performed
+ // consistent [...], even if the underlying standard does not require a
+ // PCT". So we do it. And make ECDH nearly 50% slower (only) in FIPS mode.
+ fips140.PCT("ECDH PCT", func() error {
+ p1, err := c.newPoint().ScalarBaseMult(privateKey.d)
+ if err != nil {
+ return err
+ }
+ if !bytes.Equal(p1.Bytes(), privateKey.pub.q) {
+ return errors.New("crypto/ecdh: public key does not match private key")
+ }
+ return nil
+ })
+
return privateKey, nil
}
}
@@ -188,28 +209,6 @@
panic("crypto/ecdh: internal error: public key is the identity element")
}
- // A "Pairwise Consistency Test" makes no sense if we just generated the
- // public key from an ephemeral private key. Moreover, there is no way to
- // check it aside from redoing the exact same computation again. SP 800-56A
- // Rev. 3, Section 5.6.2.1.4 acknowledges that, and doesn't require it.
- // However, ISO 19790:2012, Section 7.10.3.3 has a blanket requirement for a
- // PCT for all generated keys (AS10.35) and FIPS 140-3 IG 10.3.A, Additional
- // Comment 1 goes out of its way to say that "the PCT shall be performed
- // consistent [...], even if the underlying standard does not require a
- // PCT". So we do it. And make ECDH nearly 50% slower (only) in FIPS mode.
- if err := fips140.PCT("ECDH PCT", func() error {
- p1, err := c.newPoint().ScalarBaseMult(key)
- if err != nil {
- return err
- }
- if !bytes.Equal(p1.Bytes(), publicKey) {
- return errors.New("crypto/ecdh: public key does not match private key")
- }
- return nil
- }); err != nil {
- panic(err)
- }
-
k := &PrivateKey{d: bytes.Clone(key), pub: PublicKey{curve: c.curve, q: publicKey}}
return k, nil
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/ecdsa/cast.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ecdsa/cast.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/ecdsa/cast.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ecdsa/cast.go 1980-01-10 00:00:00.000000000 +0100
@@ -51,8 +51,8 @@
}
}
-func fipsPCT[P Point[P]](c *Curve[P], k *PrivateKey) error {
- return fips140.PCT("ECDSA PCT", func() error {
+func fipsPCT[P Point[P]](c *Curve[P], k *PrivateKey) {
+ fips140.PCT("ECDSA PCT", func() error {
hash := testHash()
drbg := newDRBG(sha512.New, k.d, bits2octets(P256(), hash), nil)
sig, err := sign(c, k, drbg, hash)
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/ecdsa/ecdsa.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ecdsa/ecdsa.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/ecdsa/ecdsa.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ecdsa/ecdsa.go 1980-01-10 00:00:00.000000000 +0100
@@ -166,11 +166,6 @@
return nil, err
}
priv := &PrivateKey{pub: *pub, d: d.Bytes(c.N)}
- if err := fipsPCT(c, priv); err != nil {
- // This can happen if the application went out of its way to make an
- // ecdsa.PrivateKey with a mismatching PublicKey.
- return nil, err
- }
return priv, nil
}
@@ -203,10 +198,7 @@
},
d: k.Bytes(c.N),
}
- if err := fipsPCT(c, priv); err != nil {
- // This clearly can't happen, but FIPS 140-3 mandates that we check it.
- panic(err)
- }
+ fipsPCT(c, priv)
return priv, nil
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/ecdsa/hmacdrbg.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ecdsa/hmacdrbg.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/ecdsa/hmacdrbg.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ecdsa/hmacdrbg.go 1980-01-10 00:00:00.000000000 +0100
@@ -121,7 +121,7 @@
//
// This should only be used for ACVP testing. hmacDRBG is not intended to be
// used directly.
-func TestingOnlyNewDRBG(hash func() fips140.Hash, entropy, nonce []byte, s []byte) *hmacDRBG {
+func TestingOnlyNewDRBG[H fips140.Hash](hash func() H, entropy, nonce []byte, s []byte) *hmacDRBG {
return newDRBG(hash, entropy, nonce, plainPersonalizationString(s))
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/ed25519/cast.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ed25519/cast.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/ed25519/cast.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ed25519/cast.go 1980-01-10 00:00:00.000000000 +0100
@@ -12,8 +12,8 @@
"sync"
)
-func fipsPCT(k *PrivateKey) error {
- return fips140.PCT("Ed25519 sign and verify PCT", func() error {
+func fipsPCT(k *PrivateKey) {
+ fips140.PCT("Ed25519 sign and verify PCT", func() error {
return pairwiseTest(k)
})
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/ed25519/ed25519.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ed25519/ed25519.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/ed25519/ed25519.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/ed25519/ed25519.go 1980-01-10 00:00:00.000000000 +0100
@@ -69,10 +69,7 @@
fips140.RecordApproved()
drbg.Read(priv.seed[:])
precomputePrivateKey(priv)
- if err := fipsPCT(priv); err != nil {
- // This clearly can't happen, but FIPS 140-3 requires that we check.
- panic(err)
- }
+ fipsPCT(priv)
return priv, nil
}
@@ -88,10 +85,6 @@
}
copy(priv.seed[:], seed)
precomputePrivateKey(priv)
- if err := fipsPCT(priv); err != nil {
- // This clearly can't happen, but FIPS 140-3 requires that we check.
- panic(err)
- }
return priv, nil
}
@@ -137,12 +130,6 @@
copy(priv.prefix[:], h[32:])
- if err := fipsPCT(priv); err != nil {
- // This can happen if the application messed with the private key
- // encoding, and the public key doesn't match the seed anymore.
- return nil, err
- }
-
return priv, nil
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/fips140.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/fips140.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/fips140.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/fips140.go 1980-01-10 00:00:00.000000000 +0100
@@ -62,6 +62,10 @@
return "Go Cryptographic Module"
}
+// Version returns the formal version (such as "v1.0.0") if building against a
+// frozen module with GOFIPS140. Otherwise, it returns "latest".
func Version() string {
- return "v1.0"
+ // This return value is replaced by mkzip.go, it must not be changed or
+ // moved to a different file.
+ return "v1.0.0"
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/mlkem/mlkem1024.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/mlkem/mlkem1024.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/mlkem/mlkem1024.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/mlkem/mlkem1024.go 1980-01-10 00:00:00.000000000 +0100
@@ -118,10 +118,7 @@
var z [32]byte
drbg.Read(z[:])
kemKeyGen1024(dk, &d, &z)
- if err := fips140.PCT("ML-KEM PCT", func() error { return kemPCT1024(dk) }); err != nil {
- // This clearly can't happen, but FIPS 140-3 requires us to check.
- panic(err)
- }
+ fips140.PCT("ML-KEM PCT", func() error { return kemPCT1024(dk) })
fips140.RecordApproved()
return dk, nil
}
@@ -149,10 +146,6 @@
d := (*[32]byte)(seed[:32])
z := (*[32]byte)(seed[32:])
kemKeyGen1024(dk, d, z)
- if err := fips140.PCT("ML-KEM PCT", func() error { return kemPCT1024(dk) }); err != nil {
- // This clearly can't happen, but FIPS 140-3 requires us to check.
- panic(err)
- }
fips140.RecordApproved()
return dk, nil
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/mlkem/mlkem768.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/mlkem/mlkem768.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/mlkem/mlkem768.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/mlkem/mlkem768.go 1980-01-10 00:00:00.000000000 +0100
@@ -177,10 +177,7 @@
var z [32]byte
drbg.Read(z[:])
kemKeyGen(dk, &d, &z)
- if err := fips140.PCT("ML-KEM PCT", func() error { return kemPCT(dk) }); err != nil {
- // This clearly can't happen, but FIPS 140-3 requires us to check.
- panic(err)
- }
+ fips140.PCT("ML-KEM PCT", func() error { return kemPCT(dk) })
fips140.RecordApproved()
return dk, nil
}
@@ -208,10 +205,6 @@
d := (*[32]byte)(seed[:32])
z := (*[32]byte)(seed[32:])
kemKeyGen(dk, d, z)
- if err := fips140.PCT("ML-KEM PCT", func() error { return kemPCT(dk) }); err != nil {
- // This clearly can't happen, but FIPS 140-3 requires us to check.
- panic(err)
- }
fips140.RecordApproved()
return dk, nil
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/rsa/keygen.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/rsa/keygen.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/rsa/keygen.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/rsa/keygen.go 1980-01-10 00:00:00.000000000 +0100
@@ -105,7 +105,28 @@
// negligible chance of failure we can defer the check to the end of key
// generation and return an error if it fails. See [checkPrivateKey].
- return newPrivateKey(N, 65537, d, P, Q)
+ k, err := newPrivateKey(N, 65537, d, P, Q)
+ if err != nil {
+ return nil, err
+ }
+
+ if k.fipsApproved {
+ fips140.PCT("RSA sign and verify PCT", func() error {
+ hash := []byte{
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ }
+ sig, err := signPKCS1v15(k, "SHA-256", hash)
+ if err != nil {
+ return err
+ }
+ return verifyPKCS1v15(k.PublicKey(), "SHA-256", hash, sig)
+ })
+ }
+
+ return k, nil
}
}
diff -ru golang.org/fips140@v1.0.0/fips140/v1.0.0/rsa/rsa.go golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/rsa/rsa.go
--- golang.org/fips140@v1.0.0/fips140/v1.0.0/rsa/rsa.go 1980-01-10 00:00:00.000000000 +0100
+++ golang.org/fips140@v1.0.0-c2097c7c/fips140/v1.0.0-c2097c7c/rsa/rsa.go 1980-01-10 00:00:00.000000000 +0100
@@ -310,26 +310,6 @@
return errors.New("crypto/rsa: d too small")
}
- // If the key is still in scope for FIPS mode, perform a Pairwise
- // Consistency Test.
- if priv.fipsApproved {
- if err := fips140.PCT("RSA sign and verify PCT", func() error {
- hash := []byte{
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- }
- sig, err := signPKCS1v15(priv, "SHA-256", hash)
- if err != nil {
- return err
- }
- return verifyPKCS1v15(priv.PublicKey(), "SHA-256", hash, sig)
- }); err != nil {
- return err
- }
- }
-
return nil
}
Change-Id: I6a6a6964b1780f19ec2b5202052de58b47d9342c
Reviewed-on: https://go-review.googlesource.com/c/go/+/701520
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Commit-Queue: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/706719
CMVP clarified with the September 2nd changes to IG 10.3.A that PCTs
don't need to run on imported keys.
However, PCT failure must enter the error state (which for us is fatal).
Thankfully, now that PCTs only run on key generation, we can be assured
they will never fail.
This change should only affect FIPS 140-3 mode.
While at it, make the CAST/PCT testing more robust, checking
TestConditional is terminated by a fatal error (and not by t.Fatal).
Updates #75524
Updates #74947
Updates #69536
Change-Id: I6a6a696439e1560c10f3cce2cb208fd40c5bc641
Reviewed-on: https://go-review.googlesource.com/c/go/+/706718
TryBot-Bypass: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Reviewed-by: Junyang Shao <shaojunyang@google.com>