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.
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
}
Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest
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>
make v1.0.0.zip
make v1.0.0.test
make updatesum
Changed the v%.zip Makefile target to use the default of origin/master,
as per its comment and intention, instead of the local master.
Change-Id: I6a6a4656c097d11b8cdc96766394c984f9c47f82
Reviewed-on: https://go-review.googlesource.com/c/go/+/644645
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Sometimes we've used the 140 suffix (GOFIPS140, crypto/fips140)
and sometimes not (crypto/internal/fips, cmd/go/internal/fips).
Use it always, to avoid having to remember which is which.
Also, there are other FIPS standards, like AES (FIPS 197), SHA-2 (FIPS 180),
and so on, which have nothing to do with FIPS 140. Best to be clear.
For #70123.
Change-Id: I33b29dabd9e8b2703d2af25e428f88bc81c7c307
Reviewed-on: https://go-review.googlesource.com/c/go/+/630115
Reviewed-by: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Russ Cox <rsc@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
This directory will hold the fips140 snapshots.
Add a README, helpful Makefile, and a test that
the checksums are correct (once we have zip files).
Change-Id: I735540ad1ce7da9a24c3a0b57b054c8340708da1
Reviewed-on: https://go-review.googlesource.com/c/go/+/629955
Reviewed-by: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Matloob <matloob@golang.org>