Repository: vmware/govmomi (go)

Issue:
`GODEBUG=fips140=only` Importing `github.com/vmware/govmomi/simulator` panics
Tests that import `github.com/vmware/govmomi/simulator` will panic when loading if `GODEBUG=fips140=only` is set.

This is due to SHA-1 usage in `simulator/vpx`
https://github.com/vmware/govmomi/blob/8d78f546939a329ab18a24e5d50112c5a2a6cf85/simulator/vpx/service_content.go#L32

This failure is also present when running unit tests for simulator:
```
simulator|main ⇒ GODEBUG=fips140=only go test ./...
panic: crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode

goroutine 1 [running]:
crypto/sha1.(*digest).checkSum(0x10145ca80?)
	/usr/local/go/src/crypto/sha1/sha1.go:160 +0x180
crypto/sha1.(*digest).Sum(0x140000928c0, {0x0, 0x0, 0x0})
	/usr/local/go/src/crypto/sha1/sha1.go:154 +0x6c
github.com/google/uuid.NewHash({0x10167d000, 0x140000928c0}, {0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, ...}, ...)
	/Users/mlaterman/go/pkg/mod/github.com/google/uuid@v1.6.0/hash.go:37 +0xbc
github.com/google/uuid.NewSHA1({0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, ...}, ...)
	/Users/mlaterman/go/pkg/mod/github.com/google/uuid@v1.6.0/hash.go:58 +0x98
github.com/vmware/govmomi/simulator/vpx.init()
	/Users/mlaterman/git/govmomi/simulator/vpx/service_content.go:32 +0x2d8
FAIL	github.com/vmware/govmomi/simulator	0.521s
?   	github.com/vmware/govmomi/simulator/esx	[no test files]
?   	github.com/vmware/govmomi/simulator/internal	[no test files]
?   	github.com/vmware/govmomi/simulator/vpx	[no test files]
FAIL
```

Pull request:
vcsim: Avoid use of sha1 for stable UUIDs (OIDs)
api: soap.ThumbprintsSHA1 returns an empty string when GODEBUG contains "fips140=only"

Fixes #3766


Patch:
diff --git a/Makefile b/Makefile
index 6d4267bc..f21e91df 100644
--- a/Makefile
+++ b/Makefile
@@ -152,6 +152,11 @@ go-test: ## Runs go unit tests with race detector enabled
   -v $(TEST_OPTS) \
   ./...
 
+.PHONY: go-fips140-test
+go-fips140-test: ## Test simulator can be used with fips140=only
+	GODEBUG=fips140=only $(GO) test ./property
+
+go-test: ## Runs go unit tests with race detector enabled
 .PHONY: govc-test
 govc-test: install
 govc-test: ## Runs govc bats tests
@@ -159,4 +164,4 @@ govc-test: ## Runs govc bats tests
 	(cd govc/test && ./vendor/github.com/bats-core/bats-core/bin/bats -t .)
 
 .PHONY: test
-test: go-test govc-test	## Runs go-test and govc-test
+test: go-test go-fips140-test govc-test	## Runs go-test and govc-test
diff --git a/gen/Gemfile.lock b/gen/Gemfile.lock
index d942deb2..86a77cf3 100644
--- a/gen/Gemfile.lock
+++ b/gen/Gemfile.lock
@@ -2,12 +2,12 @@ GEM
   remote: https://rubygems.org/
   specs:
     mini_portile2 (2.8.8)
-    nokogiri (1.18.8)
+    nokogiri (1.18.6)
       mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     power_assert (2.0.5)
     racc (1.8.1)
-    test-unit (3.6.8)
+    test-unit (3.6.7)
       power_assert
     yaml (0.4.0)
 
diff --git a/internal/helpers.go b/internal/helpers.go
index d4ee818b..ae381a78 100644
--- a/internal/helpers.go
+++ b/internal/helpers.go
@@ -6,6 +6,7 @@ package internal
 
 import (
 	"context"
+	"crypto/sha256"
 	"encoding/xml"
 	"fmt"
 	"io"
@@ -17,6 +18,8 @@ import (
 	"slices"
 	"strings"
 
+	"github.com/google/uuid"
+
 	"github.com/vmware/govmomi/vim25"
 	"github.com/vmware/govmomi/vim25/mo"
 	"github.com/vmware/govmomi/vim25/soap"
@@ -168,3 +171,8 @@ func (arg ReflectManagedMethodExecuterSoapArgument) Value() []string {
 func EsxcliName(name string) string {
 	return strings.ReplaceAll(strings.Title(name), ".", "")
 }
+
+// OID returns a stable UUID based on input s
+func OID(s string) uuid.UUID {
+	return uuid.NewHash(sha256.New(), uuid.NameSpaceOID, []byte(s), 5)
+}
diff --git a/simulator/object.go b/simulator/object.go
index 82edfa9c..9e6c381e 100644
--- a/simulator/object.go
+++ b/simulator/object.go
@@ -7,8 +7,7 @@ package simulator
 import (
 	"bytes"
 
-	"github.com/google/uuid"
-
+	"github.com/vmware/govmomi/internal"
 	"github.com/vmware/govmomi/vim25/methods"
 	"github.com/vmware/govmomi/vim25/soap"
 	"github.com/vmware/govmomi/vim25/types"
@@ -44,12 +43,7 @@ func SetCustomValue(ctx *Context, req *types.SetCustomValue) soap.HasFault {
 
 // newUUID returns a stable UUID string based on input s
 func newUUID(s string) string {
-	return sha1UUID(s).String()
-}
-
-// sha1UUID returns a stable UUID based on input s
-func sha1UUID(s string) uuid.UUID {
-	return uuid.NewSHA1(uuid.NameSpaceOID, []byte(s))
+	return internal.OID(s).String()
 }
 
 // deepCopy uses xml encode/decode to copy src to dst
diff --git a/simulator/virtual_disk_manager.go b/simulator/virtual_disk_manager.go
index 6e6d8955..ade3f4d1 100644
--- a/simulator/virtual_disk_manager.go
+++ b/simulator/virtual_disk_manager.go
@@ -10,8 +10,6 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/google/uuid"
-
 	"github.com/vmware/govmomi/internal"
 	"github.com/vmware/govmomi/vim25/methods"
 	"github.com/vmware/govmomi/vim25/mo"
@@ -246,7 +244,7 @@ func virtualDiskUUID(dc *types.ManagedObjectReference, file string) string {
 	if dc != nil {
 		file = dc.String() + file
 	}
-	return uuid.NewSHA1(uuid.NameSpaceOID, []byte(file)).String()
+	return newUUID(file)
 }
 
 func (m *VirtualDiskManager) QueryVirtualDiskUuid(ctx *Context, req *types.QueryVirtualDiskUuid) soap.HasFault {
diff --git a/simulator/virtual_machine.go b/simulator/virtual_machine.go
index 53be868d..2820dc53 100644
--- a/simulator/virtual_machine.go
+++ b/simulator/virtual_machine.go
@@ -121,7 +121,7 @@ func NewVirtualMachine(ctx *Context, parent types.ManagedObjectReference, spec *
 	spec.Files.VmPathName = vmx.String()
 
 	dsPath := path.Dir(spec.Files.VmPathName)
-	vm.uid = sha1UUID(spec.Files.VmPathName)
+	vm.uid = internal.OID(spec.Files.VmPathName)
 
 	defaults := types.VirtualMachineConfigSpec{
 		NumCPUs:           1,
diff --git a/simulator/vpx/service_content.go b/simulator/vpx/service_content.go
index f8594850..19dc5d01 100644
--- a/simulator/vpx/service_content.go
+++ b/simulator/vpx/service_content.go
@@ -7,6 +7,7 @@ package vpx
 import (
 	"github.com/google/uuid"
 
+	"github.com/vmware/govmomi/internal"
 	"github.com/vmware/govmomi/vim25/types"
 )
 
@@ -29,7 +30,7 @@ var ServiceContent = types.ServiceContent{
 		ProductLineId:         "vpx",
 		ApiType:               "VirtualCenter",
 		ApiVersion:            "6.5",
-		InstanceUuid:          uuid.NewSHA1(uuid.NameSpaceOID, uuid.NodeID()).String(),
+		InstanceUuid:          internal.OID(string(uuid.NodeID())).String(),
 		LicenseProductName:    "VMware VirtualCenter Server",
 		LicenseProductVersion: "6.0",
 	},
diff --git a/vim25/soap/client.go b/vim25/soap/client.go
index f4be2fb2..013e4b05 100644
--- a/vim25/soap/client.go
+++ b/vim25/soap/client.go
@@ -397,10 +397,16 @@ func (c *Client) loadThumbprints(name string) error {
 	return scanner.Err()
 }
 
+var fips140 = strings.Contains(os.Getenv("GODEBUG"), "fips140=only")
+
 // ThumbprintSHA1 returns the thumbprint of the given cert in the same format used by the SDK and Client.SetThumbprint.
 //
 // See: SSLVerifyFault.Thumbprint, SessionManagerGenericServiceTicket.Thumbprint, HostConnectSpec.SslThumbprint
+// When GODEBUG contains "fips140=only", this function returns an empty string.
 func ThumbprintSHA1(cert *x509.Certificate) string {
+	if fips140 {
+		return ""
+	}
 	sum := sha1.Sum(cert.Raw)
 	hex := make([]string, len(sum))
 	for i, b := range sum {


Test patch:
diff --git a/.github/workflows/govmomi-go-tests.yaml b/.github/workflows/govmomi-go-tests.yaml
index 7995c3a2..578cbc2b 100644
--- a/.github/workflows/govmomi-go-tests.yaml
+++ b/.github/workflows/govmomi-go-tests.yaml
@@ -52,4 +52,4 @@ jobs:
 
       - name: Debug on Failure
         if: ${{ failure() }}
-        uses: mxschmitt/action-tmate@c606f8612a802e46b3742322514c09fbc8c4afee # v3.21
+        uses: mxschmitt/action-tmate@c6f0481d0648e44da05d377e11809430c8685366 # v3.20
diff --git a/.github/workflows/govmomi-govc-tests.yaml b/.github/workflows/govmomi-govc-tests.yaml
index 935e218b..b6e7fb08 100644
--- a/.github/workflows/govmomi-govc-tests.yaml
+++ b/.github/workflows/govmomi-govc-tests.yaml
@@ -56,7 +56,7 @@ jobs:
 
       - name: Debug on Failure
         if: ${{ failure() }}
-        uses: mxschmitt/action-tmate@c606f8612a802e46b3742322514c09fbc8c4afee # v3.21
+        uses: mxschmitt/action-tmate@c6f0481d0648e44da05d377e11809430c8685366 # v3.20
 
   govc-docs:
     name: Verify Updated Docs
diff --git a/govc/test/vcsim.bats b/govc/test/vcsim.bats
index 22e4f7fa..70e4fa3e 100755
--- a/govc/test/vcsim.bats
+++ b/govc/test/vcsim.bats
@@ -212,13 +212,13 @@ EOF
 
   # VM uuids are stable, based on path to .vmx
   run govc object.collect -s vm/DC0_H0_VM0 config.uuid config.instanceUuid
-  assert_success "$(printf "265104de-1472-547c-b873-6dc7883fb6cb\nb4689bed-97f0-5bcd-8a4c-07477cc8f06f")"
+  assert_success "$(printf "63d40cc5-9cba-5cc1-884a-f7f19070ecea\nb170c191-7587-5f8e-9a15-08c6a0a11ca5")"
 
   dups=$(govc object.collect -s -type m / config.uuid | sort | uniq -d | wc -l)
   assert_equal 0 "$dups"
 
   run govc object.collect -s host/DC0_H0/DC0_H0 summary.hardware.uuid
-  assert_success dcf7fb3c-4a1c-5a05-b730-5e09f3704e2f
+  assert_success efc5827c-ee19-5d35-84ef-a77d6ea6ee4c
 
   dups=$(govc object.collect -s -type m / summary.hardware.uuid | sort | uniq -d | wc -l)
   assert_equal 0 "$dups"