crypto/internal/fips140test: add AES-CMAC Wycheproof coverage

Tests the internal GCM CMAC API using Wycheproof test vectors.
Specifically, aes_cmac_test.json for AES-128, AES-192, and AES-256 key
sizes.

Change-Id: If9e5e841c0c0091e553eedaae7ae823810695883
Reviewed-on: https://go-review.googlesource.com/c/go/+/758862
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>
Reviewed-by: David Chase <drchase@google.com>
diff --git a/src/crypto/internal/fips140test/cmac_wycheproof_test.go b/src/crypto/internal/fips140test/cmac_wycheproof_test.go
new file mode 100644
index 0000000..f342eca
--- /dev/null
+++ b/src/crypto/internal/fips140test/cmac_wycheproof_test.go
@@ -0,0 +1,63 @@
+// Copyright 2026 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fipstest
+
+import (
+	"bytes"
+	"crypto/internal/cryptotest/wycheproof"
+	"crypto/internal/fips140/aes"
+	"crypto/internal/fips140/aes/gcm"
+	"testing"
+)
+
+func TestCMACWycheproof(t *testing.T) {
+	const file = "aes_cmac_test.json"
+	var testdata wycheproof.MacTestSchemaV1Json
+	wycheproof.LoadVectorFile(t, file, &testdata)
+
+	for _, tg := range testdata.TestGroups {
+		// Skip test groups with invalid AES key sizes.
+		// The CMAC API takes an already-constructed aes.Block,
+		// so invalid key sizes are rejected at AES key creation time.
+		switch tg.KeySize {
+		case 128, 192, 256:
+			// Valid AES key sizes.
+		default:
+			continue
+		}
+
+		if tg.TagSize != 128 {
+			continue
+		}
+
+		for _, tv := range tg.Tests {
+			t.Run(wycheproof.TestName(file, tv), func(t *testing.T) {
+				t.Parallel()
+
+				key := wycheproof.MustDecodeHex(tv.Key)
+				msg := wycheproof.MustDecodeHex(tv.Msg)
+				expectedTag := wycheproof.MustDecodeHex(tv.Tag)
+				wantPass := wycheproof.ShouldPass(t, tv.Result, tv.Flags, nil)
+
+				b, err := aes.New(key)
+				if err != nil {
+					t.Fatalf("aes.New: %v", err)
+				}
+				c := gcm.NewCMAC(b)
+				tag := c.MAC(msg)
+
+				if bytes.Equal(tag[:], expectedTag) {
+					if !wantPass {
+						t.Errorf("expected failure but tag matched")
+					}
+				} else {
+					if wantPass {
+						t.Errorf("tag mismatch: got %x, want %x", tag[:], expectedTag)
+					}
+				}
+			})
+		}
+	}
+}