...

Source file src/cmd/go/internal/fips140/fips_test.go

Documentation: cmd/go/internal/fips140

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fips140
     6  
     7  import (
     8  	"crypto/sha256"
     9  	"flag"
    10  	"fmt"
    11  	"internal/testenv"
    12  	"maps"
    13  	"os"
    14  	"path/filepath"
    15  	"slices"
    16  	"strings"
    17  	"testing"
    18  )
    19  
    20  var update = flag.Bool("update", false, "update GOROOT/lib/fips140/fips140.sum")
    21  
    22  func TestSums(t *testing.T) {
    23  	lib := filepath.Join(testenv.GOROOT(t), "lib/fips140")
    24  	file := filepath.Join(lib, "fips140.sum")
    25  	sums, err := os.ReadFile(file)
    26  	if err != nil {
    27  		t.Fatal(err)
    28  	}
    29  	lines := strings.SplitAfter(string(sums), "\n")
    30  
    31  	zips, err := filepath.Glob(filepath.Join(lib, "*.zip"))
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  
    36  	format := func(name string, sum [32]byte) string {
    37  		return fmt.Sprintf("%s %x\n", name, sum[:])
    38  	}
    39  
    40  	want := make(map[string]string)
    41  	for _, zip := range zips {
    42  		data, err := os.ReadFile(zip)
    43  		if err != nil {
    44  			t.Fatal(err)
    45  		}
    46  		name := filepath.Base(zip)
    47  		want[name] = format(name, sha256.Sum256(data))
    48  	}
    49  
    50  	// Process diff, deleting or correcting stale lines.
    51  	var diff []string
    52  	have := make(map[string]bool)
    53  	for i, line := range lines {
    54  		if line == "" {
    55  			continue
    56  		}
    57  		if strings.HasPrefix(line, "#") || line == "\n" {
    58  			// comment, preserve
    59  			diff = append(diff, " "+line)
    60  			continue
    61  		}
    62  		name, _, _ := strings.Cut(line, " ")
    63  		if want[name] == "" {
    64  			lines[i] = ""
    65  			diff = append(diff, "-"+line)
    66  			continue
    67  		}
    68  		have[name] = true
    69  		fixed := want[name]
    70  		delete(want, name)
    71  		if line == fixed {
    72  			diff = append(diff, " "+line)
    73  		} else {
    74  			// zip hashes should never change once listed
    75  			t.Errorf("policy violation: zip file hash is changing:\n-%s+%s", line, fixed)
    76  			lines[i] = fixed
    77  			diff = append(diff, "-"+line, "+"+fixed)
    78  		}
    79  	}
    80  
    81  	// Add missing lines.
    82  	// Sort keys to avoid non-determinism, but overall file is not sorted.
    83  	// It will end up time-ordered instead.
    84  	for _, name := range slices.Sorted(maps.Keys(want)) {
    85  		line := want[name]
    86  		lines = append(lines, line)
    87  		diff = append(diff, "+"+line)
    88  	}
    89  
    90  	// Show diffs or update file.
    91  	fixed := strings.Join(lines, "")
    92  	if fixed != string(sums) {
    93  		if *update && !t.Failed() {
    94  			t.Logf("updating GOROOT/lib/fips140/fips140.sum:\n%s", strings.Join(diff, ""))
    95  			if err := os.WriteFile(file, []byte(fixed), 0666); err != nil {
    96  				t.Fatal(err)
    97  			}
    98  			return
    99  		}
   100  		t.Errorf("GOROOT/lib/fips140/fips140.sum out of date. changes needed:\n%s", strings.Join(diff, ""))
   101  	}
   102  }
   103  
   104  func TestVerifyZipSum(t *testing.T) {
   105  	dir := t.TempDir()
   106  	zipfile := filepath.Join(dir, "v1.2.3.zip")
   107  	data := []byte("not really a zip, but it does not matter here")
   108  	if err := os.WriteFile(zipfile, data, 0666); err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	sum := sha256.Sum256(data)
   112  
   113  	sumfile := filepath.Join(dir, "fips140.sum")
   114  	write := func(contents string) {
   115  		if err := os.WriteFile(sumfile, []byte(contents), 0666); err != nil {
   116  			t.Fatal(err)
   117  		}
   118  	}
   119  
   120  	// Matching hash with comments and a second entry passes.
   121  	write(fmt.Sprintf("# comment\n\nv1.2.3.zip %x\nother.zip 0000000000000000000000000000000000000000000000000000000000000000\n", sum[:]))
   122  	if err := verifyZipSum(zipfile, sumfile); err != nil {
   123  		t.Errorf("unexpected error: %v", err)
   124  	}
   125  
   126  	// Missing entry for this zip fails.
   127  	write("# only comments\n")
   128  	if err := verifyZipSum(zipfile, sumfile); err == nil {
   129  		t.Errorf("expected error when hash entry is missing")
   130  	}
   131  
   132  	// Wrong hash fails.
   133  	write("v1.2.3.zip 0000000000000000000000000000000000000000000000000000000000000000\n")
   134  	if err := verifyZipSum(zipfile, sumfile); err == nil {
   135  		t.Errorf("expected error when hash does not match")
   136  	}
   137  
   138  	// Missing sum file fails.
   139  	if err := verifyZipSum(zipfile, filepath.Join(dir, "does-not-exist.sum")); err == nil {
   140  		t.Errorf("expected error when sum file is missing")
   141  	}
   142  }
   143  

View as plain text