acvptool: create fresh variables in loops.

Referencing a variable in a closure captures it by _address_. So
referencing a loop variable can go horribly wrong:
https://go.dev/play/p/f2ivPAIN_bG

This is accepted as essentially a bug by Go and will be fixed in a
future release (https://github.com/golang/go/wiki/LoopvarExperiment).
But, for now at least, work around it.

Our tests trim the ACVP inputs to only have a single test case per group
in many cases, which hides most of this issue from tests. When we run
run full ACVP sets, our modulewrapper is seemingly fast enough not to
notice there either. But I've updated one of the tests here by
duplicating a test case enough that it catches this a meaningful amount
of the time.

Change-Id: I8216c00f67636ab7dad927eae4b49ae45ae3cf31
Bug: 646
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/62965
Reviewed-by: David Benjamin <davidben@google.com>
Auto-Submit: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/util/fipstools/acvp/acvptool/subprocess/aead.go b/util/fipstools/acvp/acvptool/subprocess/aead.go
index ba0eee9..c38b170 100644
--- a/util/fipstools/acvp/acvptool/subprocess/aead.go
+++ b/util/fipstools/acvp/acvptool/subprocess/aead.go
@@ -72,6 +72,7 @@
 	// versions of the ACVP documents. You can find fragments in
 	// https://github.com/usnistgov/ACVP.)
 	for _, group := range parsed.Groups {
+		group := group
 		response := aeadTestGroupResponse{
 			ID: group.ID,
 		}
@@ -102,6 +103,8 @@
 		tagBytes := group.TagBits / 8
 
 		for _, test := range group.Tests {
+			test := test
+
 			if len(test.KeyHex) != keyBytes*2 {
 				return nil, fmt.Errorf("test case %d/%d contains key %q of length %d, but expected %d-bit key", group.ID, test.ID, test.KeyHex, len(test.KeyHex), group.KeyBits)
 			}
diff --git a/util/fipstools/acvp/acvptool/subprocess/block.go b/util/fipstools/acvp/acvptool/subprocess/block.go
index 2f05802..bcc6613 100644
--- a/util/fipstools/acvp/acvptool/subprocess/block.go
+++ b/util/fipstools/acvp/acvptool/subprocess/block.go
@@ -299,6 +299,7 @@
 	// http://usnistgov.github.io/ACVP/artifacts/draft-celi-acvp-block-ciph-00.html#rfc.section.5.2
 	// for details about the tests.
 	for _, group := range parsed.Groups {
+		group := group
 		response := blockCipherTestGroupResponse{
 			ID: group.ID,
 		}
@@ -346,6 +347,8 @@
 		}
 
 		for _, test := range group.Tests {
+			test := test
+
 			if len(test.KeyHex) == 0 && len(test.Key1Hex) > 0 {
 				// 3DES encodes the key differently.
 				test.KeyHex = test.Key1Hex + test.Key2Hex + test.Key3Hex
diff --git a/util/fipstools/acvp/acvptool/subprocess/drbg.go b/util/fipstools/acvp/acvptool/subprocess/drbg.go
index b403f04..87584d6 100644
--- a/util/fipstools/acvp/acvptool/subprocess/drbg.go
+++ b/util/fipstools/acvp/acvptool/subprocess/drbg.go
@@ -84,6 +84,7 @@
 	// https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#name-test-vectors
 	// for details about the tests.
 	for _, group := range parsed.Groups {
+		group := group
 		response := drbgTestGroupResponse{
 			ID: group.ID,
 		}
@@ -97,6 +98,8 @@
 		}
 
 		for _, test := range group.Tests {
+			test := test
+
 			ent, err := extractField(test.EntropyHex, group.EntropyBits)
 			if err != nil {
 				return nil, fmt.Errorf("failed to extract entropy hex from test case %d/%d: %s", group.ID, test.ID, err)
diff --git a/util/fipstools/acvp/acvptool/subprocess/ecdsa.go b/util/fipstools/acvp/acvptool/subprocess/ecdsa.go
index 16d3a83..69706bd 100644
--- a/util/fipstools/acvp/acvptool/subprocess/ecdsa.go
+++ b/util/fipstools/acvp/acvptool/subprocess/ecdsa.go
@@ -83,6 +83,8 @@
 	// https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#name-test-vectors
 	// for details about the tests.
 	for _, group := range parsed.Groups {
+		group := group
+
 		if _, ok := e.curves[group.Curve]; !ok {
 			return nil, fmt.Errorf("curve %q in test group %d not supported", group.Curve, group.ID)
 		}
@@ -93,6 +95,8 @@
 		var sigGenPrivateKey []byte
 
 		for _, test := range group.Tests {
+			test := test
+
 			var testResp ecdsaTestResponse
 			testResp.ID = test.ID
 
diff --git a/util/fipstools/acvp/acvptool/subprocess/hash.go b/util/fipstools/acvp/acvptool/subprocess/hash.go
index 1f34d1a..aeac6d6 100644
--- a/util/fipstools/acvp/acvptool/subprocess/hash.go
+++ b/util/fipstools/acvp/acvptool/subprocess/hash.go
@@ -73,11 +73,14 @@
 	// https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#name-test-vectors
 	// for details about the tests.
 	for _, group := range parsed.Groups {
+		group := group
 		response := hashTestGroupResponse{
 			ID: group.ID,
 		}
 
 		for _, test := range group.Tests {
+			test := test
+
 			if uint64(len(test.MsgHex))*4 != test.BitLength {
 				return nil, fmt.Errorf("test case %d/%d contains hex message of length %d but specifies a bit length of %d", group.ID, test.ID, len(test.MsgHex), test.BitLength)
 			}
diff --git a/util/fipstools/acvp/acvptool/subprocess/hkdf.go b/util/fipstools/acvp/acvptool/subprocess/hkdf.go
index 3a6ba04..c64e2b8 100644
--- a/util/fipstools/acvp/acvptool/subprocess/hkdf.go
+++ b/util/fipstools/acvp/acvptool/subprocess/hkdf.go
@@ -124,6 +124,7 @@
 
 	var respGroups []hkdfTestGroupResponse
 	for _, group := range parsed.Groups {
+		group := group
 		groupResp := hkdfTestGroupResponse{ID: group.ID}
 
 		var isValidationTest bool
@@ -142,6 +143,7 @@
 		}
 
 		for _, test := range group.Tests {
+			test := test
 			testResp := hkdfTestResponse{ID: test.ID}
 
 			key, salt, err := test.Params.extract()
diff --git a/util/fipstools/acvp/acvptool/subprocess/hmac.go b/util/fipstools/acvp/acvptool/subprocess/hmac.go
index 8fc7695..6b8a3cf 100644
--- a/util/fipstools/acvp/acvptool/subprocess/hmac.go
+++ b/util/fipstools/acvp/acvptool/subprocess/hmac.go
@@ -87,6 +87,7 @@
 	// https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#name-test-vectors
 	// for details about the tests.
 	for _, group := range parsed.Groups {
+		group := group
 		response := hmacTestGroupResponse{
 			ID: group.ID,
 		}
@@ -99,6 +100,8 @@
 		outBytes := group.MACBits / 8
 
 		for _, test := range group.Tests {
+			test := test
+
 			if len(test.MsgHex)*4 != group.MsgBits {
 				return nil, fmt.Errorf("test case %d/%d contains hex message of length %d but specifies a bit length of %d", group.ID, test.ID, len(test.MsgHex), group.MsgBits)
 			}
diff --git a/util/fipstools/acvp/acvptool/subprocess/kas.go b/util/fipstools/acvp/acvptool/subprocess/kas.go
index cbc99ed..4c99f8a 100644
--- a/util/fipstools/acvp/acvptool/subprocess/kas.go
+++ b/util/fipstools/acvp/acvptool/subprocess/kas.go
@@ -77,6 +77,7 @@
 	// See https://pages.nist.gov/ACVP/draft-fussell-acvp-kas-ecc.html#name-test-vectors
 	var ret []kasTestGroupResponse
 	for _, group := range parsed.Groups {
+		group := group
 		response := kasTestGroupResponse{
 			ID: group.ID,
 		}
@@ -119,6 +120,8 @@
 		method := "ECDH/" + group.Curve
 
 		for _, test := range group.Tests {
+			test := test
+
 			var xHex, yHex, privateKeyHex string
 			if useStaticNamedFields {
 				xHex, yHex, privateKeyHex = test.StaticXHex, test.StaticYHex, test.StaticPrivateKeyHex
diff --git a/util/fipstools/acvp/acvptool/subprocess/kasdh.go b/util/fipstools/acvp/acvptool/subprocess/kasdh.go
index f262b82..212dd31 100644
--- a/util/fipstools/acvp/acvptool/subprocess/kasdh.go
+++ b/util/fipstools/acvp/acvptool/subprocess/kasdh.go
@@ -68,6 +68,7 @@
 	// See https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ffc-sp800-56ar3.html
 	var ret []kasDHTestGroupResponse
 	for _, group := range parsed.Groups {
+		group := group
 		response := kasDHTestGroupResponse{
 			ID: group.ID,
 		}
@@ -110,6 +111,8 @@
 
 		const method = "FFDH"
 		for _, test := range group.Tests {
+			test := test
+
 			if len(test.PeerPublicHex) == 0 {
 				return nil, fmt.Errorf("%d/%d is missing peer's key", group.ID, test.ID)
 			}
diff --git a/util/fipstools/acvp/acvptool/subprocess/kdf.go b/util/fipstools/acvp/acvptool/subprocess/kdf.go
index e27fcaa..6e41458 100644
--- a/util/fipstools/acvp/acvptool/subprocess/kdf.go
+++ b/util/fipstools/acvp/acvptool/subprocess/kdf.go
@@ -68,6 +68,7 @@
 
 	var respGroups []kdfTestGroupResponse
 	for _, group := range parsed.Groups {
+		group := group
 		groupResp := kdfTestGroupResponse{ID: group.ID}
 
 		if group.OutputBits%8 != 0 {
@@ -91,6 +92,7 @@
 		outputBytes := uint32le(group.OutputBits / 8)
 
 		for _, test := range group.Tests {
+			test := test
 			testResp := kdfTestResponse{ID: test.ID}
 
 			var key []byte
diff --git a/util/fipstools/acvp/acvptool/subprocess/keyedMac.go b/util/fipstools/acvp/acvptool/subprocess/keyedMac.go
index e43ab5d..c91bb41 100644
--- a/util/fipstools/acvp/acvptool/subprocess/keyedMac.go
+++ b/util/fipstools/acvp/acvptool/subprocess/keyedMac.go
@@ -65,6 +65,7 @@
 
 	var respGroups []keyedMACTestGroupResponse
 	for _, group := range vs.Groups {
+		group := group
 		respGroup := keyedMACTestGroupResponse{ID: group.ID}
 
 		if group.KeyBits%8 != 0 {
@@ -90,6 +91,7 @@
 		outputBytes := uint32le(group.MACBits / 8)
 
 		for _, test := range group.Tests {
+			test := test
 			respTest := keyedMACTestResponse{ID: test.ID}
 
 			// Validate input.
diff --git a/util/fipstools/acvp/acvptool/subprocess/rsa.go b/util/fipstools/acvp/acvptool/subprocess/rsa.go
index d975026..923cdad 100644
--- a/util/fipstools/acvp/acvptool/subprocess/rsa.go
+++ b/util/fipstools/acvp/acvptool/subprocess/rsa.go
@@ -126,6 +126,8 @@
 	var ret []rsaKeyGenTestGroupResponse
 
 	for _, group := range parsed.Groups {
+		group := group
+
 		// GDT means "Generated data test", i.e. "please generate an RSA key".
 		const expectedType = "GDT"
 		if group.Type != expectedType {
@@ -137,6 +139,8 @@
 		}
 
 		for _, test := range group.Tests {
+			test := test
+
 			m.TransactAsync("RSA/keyGen", 5, [][]byte{uint32le(group.ModulusBits)}, func(result [][]byte) error {
 				response.Tests = append(response.Tests, rsaKeyGenTestResponse{
 					ID: test.ID,
@@ -171,6 +175,8 @@
 	var ret []rsaSigGenTestGroupResponse
 
 	for _, group := range parsed.Groups {
+		group := group
+
 		// GDT means "Generated data test", i.e. "please generate an RSA signature".
 		const expectedType = "GDT"
 		if group.Type != expectedType {
@@ -184,6 +190,8 @@
 		operation := "RSA/sigGen/" + group.Hash + "/" + group.SigType
 
 		for _, test := range group.Tests {
+			test := test
+
 			msg, err := hex.DecodeString(test.MessageHex)
 			if err != nil {
 				return nil, fmt.Errorf("test case %d/%d contains invalid hex: %s", group.ID, test.ID, err)
@@ -226,6 +234,8 @@
 	var ret []rsaSigVerTestGroupResponse
 
 	for _, group := range parsed.Groups {
+		group := group
+
 		// GDT means "Generated data test", which makes no sense in this context.
 		const expectedType = "GDT"
 		if group.Type != expectedType {
@@ -248,6 +258,7 @@
 		operation := "RSA/sigVer/" + group.Hash + "/" + group.SigType
 
 		for _, test := range group.Tests {
+			test := test
 			msg, err := hex.DecodeString(test.MessageHex)
 			if err != nil {
 				return nil, fmt.Errorf("test case %d/%d contains invalid hex: %s", group.ID, test.ID, err)
diff --git a/util/fipstools/acvp/acvptool/subprocess/tls13.go b/util/fipstools/acvp/acvptool/subprocess/tls13.go
index af2aae8..bd12142 100644
--- a/util/fipstools/acvp/acvptool/subprocess/tls13.go
+++ b/util/fipstools/acvp/acvptool/subprocess/tls13.go
@@ -77,9 +77,11 @@
 
 	var respGroups []tls13TestGroupResponse
 	for _, group := range parsed.Groups {
+		group := group
 		groupResp := tls13TestGroupResponse{ID: group.ID}
 
 		for _, test := range group.Tests {
+			test := test
 			testResp := tls13TestResponse{ID: test.ID}
 
 			clientHello, err := hex.DecodeString(test.ClientHelloHex)
diff --git a/util/fipstools/acvp/acvptool/subprocess/tlskdf.go b/util/fipstools/acvp/acvptool/subprocess/tlskdf.go
index 3a0d7ce..251b53e 100644
--- a/util/fipstools/acvp/acvptool/subprocess/tlskdf.go
+++ b/util/fipstools/acvp/acvptool/subprocess/tlskdf.go
@@ -64,6 +64,7 @@
 	// See https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html
 	var ret []tlsKDFTestGroupResponse
 	for _, group := range parsed.Groups {
+		group := group
 		response := tlsKDFTestGroupResponse{
 			ID: group.ID,
 		}
@@ -82,6 +83,7 @@
 		method := "TLSKDF/1.2/" + group.Hash
 
 		for _, test := range group.Tests {
+			test := test
 			pms, err := hex.DecodeString(test.PMSHex)
 			if err != nil {
 				return nil, err
diff --git a/util/fipstools/acvp/acvptool/subprocess/xts.go b/util/fipstools/acvp/acvptool/subprocess/xts.go
index e813409..5a9e740 100644
--- a/util/fipstools/acvp/acvptool/subprocess/xts.go
+++ b/util/fipstools/acvp/acvptool/subprocess/xts.go
@@ -67,6 +67,7 @@
 
 	var ret []xtsTestGroupResponse
 	for _, group := range parsed.Groups {
+		group := group
 		response := xtsTestGroupResponse{
 			ID: group.ID,
 		}
@@ -88,6 +89,7 @@
 		funcName := "AES-XTS/" + group.Direction
 
 		for _, test := range group.Tests {
+			test := test
 			if group.KeyLen != len(test.KeyHex)*4/2 {
 				return nil, fmt.Errorf("test case %d/%d contains hex message of length %d but specifies a key length of %d (remember that XTS keys are twice the length of the underlying key size)", group.ID, test.ID, len(test.KeyHex), group.KeyLen)
 			}
diff --git a/util/fipstools/acvp/acvptool/test/expected/TLS12.bz2 b/util/fipstools/acvp/acvptool/test/expected/TLS12.bz2
index d83b691..ff4ded0 100644
--- a/util/fipstools/acvp/acvptool/test/expected/TLS12.bz2
+++ b/util/fipstools/acvp/acvptool/test/expected/TLS12.bz2
Binary files differ
diff --git a/util/fipstools/acvp/acvptool/test/vectors/TLS12.bz2 b/util/fipstools/acvp/acvptool/test/vectors/TLS12.bz2
index d1911ab..00d9bbb 100644
--- a/util/fipstools/acvp/acvptool/test/vectors/TLS12.bz2
+++ b/util/fipstools/acvp/acvptool/test/vectors/TLS12.bz2
Binary files differ