mirror of
https://github.com/golang/go.git
synced 2026-06-27 03:11:23 +00:00
cmd/go/internal/fips140: verify zip hash before unzipping
Change-Id: Iaa59f7e43ccf5730c7803383ff5a52f76a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/770780 Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> Reviewed-by: Roland Shoemaker <roland@golang.org> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
d876fda088
commit
3ac09d0ab6
2 changed files with 97 additions and 1 deletions
|
|
@ -86,6 +86,9 @@ package fips140
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
|
@ -225,13 +228,66 @@ func initDir() {
|
|||
|
||||
mod := module.Version{Path: "golang.org/fips140", Version: v}
|
||||
file := filepath.Join(cfg.GOROOT, "lib/fips140", v+".zip")
|
||||
zdir, err := modfetch.NewFetcher().Unzip(context.Background(), mod, file)
|
||||
ctx := context.Background()
|
||||
|
||||
// The FIPS 140-3 Security Policy require checking the SHA-256 hash of the
|
||||
// zip file. Verify it once against fips140.sum before unpacking it.
|
||||
if _, err := modfetch.DownloadDir(ctx, mod); err != nil {
|
||||
sumfile := filepath.Join(cfg.GOROOT, "lib/fips140/fips140.sum")
|
||||
if err := verifyZipSum(file, sumfile); err != nil {
|
||||
base.Fatalf("go: verifying GOFIPS140=%v: %v", v, err)
|
||||
}
|
||||
}
|
||||
|
||||
zdir, err := modfetch.NewFetcher().Unzip(ctx, mod, file)
|
||||
if err != nil {
|
||||
base.Fatalf("go: unpacking GOFIPS140=%v: %v", v, err)
|
||||
}
|
||||
dir = filepath.Join(zdir, "fips140")
|
||||
}
|
||||
|
||||
// verifyZipSum checks that the SHA-256 hash of zipfile matches the entry
|
||||
// for its base name in sumfile, which is expected to be in the format of
|
||||
// GOROOT/lib/fips140/fips140.sum: "NAME SHA256HEX" lines, with "#" comments.
|
||||
func verifyZipSum(zipfile, sumfile string) error {
|
||||
sums, err := os.ReadFile(sumfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := filepath.Base(zipfile)
|
||||
var want string
|
||||
for line := range strings.SplitSeq(string(sums), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
n, h, ok := strings.Cut(line, " ")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if n == name {
|
||||
want = strings.TrimSpace(h)
|
||||
break
|
||||
}
|
||||
}
|
||||
if want == "" {
|
||||
return fmt.Errorf("no SHA-256 hash for %s in %s", name, sumfile)
|
||||
}
|
||||
f, err := os.Open(zipfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return err
|
||||
}
|
||||
if got := fmt.Sprintf("%x", h.Sum(nil)); got != want {
|
||||
return fmt.Errorf("SHA-256 hash of %s is %s, want %s (from %s)", name, got, want, sumfile)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResolveImport resolves the import path imp.
|
||||
// If it is of the form crypto/internal/fips140/foo
|
||||
// (not crypto/internal/fips140/v1.2.3/foo)
|
||||
|
|
|
|||
|
|
@ -100,3 +100,43 @@ func TestSums(t *testing.T) {
|
|||
t.Errorf("GOROOT/lib/fips140/fips140.sum out of date. changes needed:\n%s", strings.Join(diff, ""))
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyZipSum(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
zipfile := filepath.Join(dir, "v1.2.3.zip")
|
||||
data := []byte("not really a zip, but it does not matter here")
|
||||
if err := os.WriteFile(zipfile, data, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sum := sha256.Sum256(data)
|
||||
|
||||
sumfile := filepath.Join(dir, "fips140.sum")
|
||||
write := func(contents string) {
|
||||
if err := os.WriteFile(sumfile, []byte(contents), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Matching hash with comments and a second entry passes.
|
||||
write(fmt.Sprintf("# comment\n\nv1.2.3.zip %x\nother.zip 0000000000000000000000000000000000000000000000000000000000000000\n", sum[:]))
|
||||
if err := verifyZipSum(zipfile, sumfile); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Missing entry for this zip fails.
|
||||
write("# only comments\n")
|
||||
if err := verifyZipSum(zipfile, sumfile); err == nil {
|
||||
t.Errorf("expected error when hash entry is missing")
|
||||
}
|
||||
|
||||
// Wrong hash fails.
|
||||
write("v1.2.3.zip 0000000000000000000000000000000000000000000000000000000000000000\n")
|
||||
if err := verifyZipSum(zipfile, sumfile); err == nil {
|
||||
t.Errorf("expected error when hash does not match")
|
||||
}
|
||||
|
||||
// Missing sum file fails.
|
||||
if err := verifyZipSum(zipfile, filepath.Join(dir, "does-not-exist.sum")); err == nil {
|
||||
t.Errorf("expected error when sum file is missing")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue