Source file src/crypto/internal/fips140deps/fipsdeps_test.go

     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 fipsdeps
     6  
     7  import (
     8  	"internal/testenv"
     9  	"strings"
    10  	"testing"
    11  )
    12  
    13  // AllowedInternalPackages are internal packages that can be imported from the
    14  // FIPS module. The API of these packages ends up locked for the lifetime of the
    15  // validated module, which can be years.
    16  //
    17  // DO NOT add new packages here just to make the tests pass.
    18  var AllowedInternalPackages = map[string]bool{
    19  	// entropy.Depleted is the external passive entropy source, and sysrand.Read
    20  	// is the actual (but uncredited!) random bytes source.
    21  	"crypto/internal/entropy": true,
    22  	"crypto/internal/sysrand": true,
    23  
    24  	// impl.Register is how the packages expose their alternative
    25  	// implementations to tests outside the module.
    26  	"crypto/internal/impl": true,
    27  
    28  	// randutil.MaybeReadByte is used in non-FIPS mode by GenerateKey functions.
    29  	"crypto/internal/randutil": true,
    30  }
    31  
    32  func TestImports(t *testing.T) {
    33  	cmd := testenv.Command(t, testenv.GoToolPath(t), "list", "-f", `{{$path := .ImportPath -}}
    34  {{range .Imports -}}
    35  {{$path}} {{.}}
    36  {{end -}}
    37  {{range .TestImports -}}
    38  {{$path}} {{.}}
    39  {{end -}}
    40  {{range .XTestImports -}}
    41  {{$path}} {{.}}
    42  {{end -}}`, "crypto/internal/fips140/...")
    43  	bout, err := cmd.CombinedOutput()
    44  	if err != nil {
    45  		t.Fatalf("go list: %v\n%s", err, bout)
    46  	}
    47  	out := string(bout)
    48  
    49  	// In a snapshot, all the paths are crypto/internal/fips140/v1.2.3/...
    50  	// Determine the version number and remove it for the test.
    51  	_, v, _ := strings.Cut(out, "crypto/internal/fips140/")
    52  	v, _, _ = strings.Cut(v, "/")
    53  	v, _, _ = strings.Cut(v, " ")
    54  	if strings.HasPrefix(v, "v") && strings.Count(v, ".") == 2 {
    55  		out = strings.ReplaceAll(out, "crypto/internal/fips140/"+v, "crypto/internal/fips140")
    56  	}
    57  
    58  	allPackages := make(map[string]bool)
    59  
    60  	// importCheck is the set of packages that import crypto/internal/fips140/check.
    61  	importCheck := make(map[string]bool)
    62  
    63  	for _, line := range strings.Split(out, "\n") {
    64  		if line == "" {
    65  			continue
    66  		}
    67  		pkg, importedPkg, _ := strings.Cut(line, " ")
    68  
    69  		allPackages[pkg] = true
    70  
    71  		if importedPkg == "crypto/internal/fips140/check" {
    72  			importCheck[pkg] = true
    73  		}
    74  
    75  		// Ensure we don't import any unexpected internal package from the FIPS
    76  		// module, since we can't change the module source after it starts
    77  		// validation. This locks in the API of otherwise internal packages.
    78  		if importedPkg == "crypto/internal/fips140" ||
    79  			strings.HasPrefix(importedPkg, "crypto/internal/fips140/") ||
    80  			strings.HasPrefix(importedPkg, "crypto/internal/fips140deps/") {
    81  			continue
    82  		}
    83  		if AllowedInternalPackages[importedPkg] {
    84  			continue
    85  		}
    86  		if strings.Contains(importedPkg, "internal") {
    87  			t.Errorf("unexpected import of internal package: %s -> %s", pkg, importedPkg)
    88  		}
    89  	}
    90  
    91  	// Ensure that all packages except check and check's dependencies import check.
    92  	for pkg := range allPackages {
    93  		switch pkg {
    94  		case "crypto/internal/fips140/check":
    95  		case "crypto/internal/fips140":
    96  		case "crypto/internal/fips140/alias":
    97  		case "crypto/internal/fips140/subtle":
    98  		case "crypto/internal/fips140/hmac":
    99  		case "crypto/internal/fips140/sha3":
   100  		case "crypto/internal/fips140/sha256":
   101  		case "crypto/internal/fips140/sha512":
   102  		default:
   103  			if !importCheck[pkg] {
   104  				t.Errorf("package %s does not import crypto/internal/fips140/check", pkg)
   105  			}
   106  		}
   107  	}
   108  }
   109  

View as plain text