Source file src/crypto/internal/fips140test/acvp_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 fipstest
     6  
     7  // A module wrapper adapting the Go FIPS module to the protocol used by the
     8  // BoringSSL project's `acvptool`.
     9  //
    10  // The `acvptool` "lowers" the NIST ACVP server JSON test vectors into a simpler
    11  // stdin/stdout protocol that can be implemented by a module shim. The tool
    12  // will fork this binary, request the supported configuration, and then provide
    13  // test cases over stdin, expecting results to be returned on stdout.
    14  //
    15  // See "Testing other FIPS modules"[0] from the BoringSSL ACVP.md documentation
    16  // for a more detailed description of the protocol used between the acvptool
    17  // and module wrappers.
    18  //
    19  // [0]: https://boringssl.googlesource.com/boringssl/+/refs/heads/master/util/fipstools/acvp/ACVP.md#testing-other-fips-modules
    20  
    21  import (
    22  	"bufio"
    23  	"bytes"
    24  	"crypto/elliptic"
    25  	"crypto/internal/cryptotest"
    26  	"crypto/internal/fips140"
    27  	"crypto/internal/fips140/aes"
    28  	"crypto/internal/fips140/aes/gcm"
    29  	"crypto/internal/fips140/bigmod"
    30  	"crypto/internal/fips140/drbg"
    31  	"crypto/internal/fips140/ecdh"
    32  	"crypto/internal/fips140/ecdsa"
    33  	"crypto/internal/fips140/ed25519"
    34  	"crypto/internal/fips140/edwards25519"
    35  	"crypto/internal/fips140/hkdf"
    36  	"crypto/internal/fips140/hmac"
    37  	"crypto/internal/fips140/mlkem"
    38  	"crypto/internal/fips140/pbkdf2"
    39  	"crypto/internal/fips140/rsa"
    40  	"crypto/internal/fips140/sha256"
    41  	"crypto/internal/fips140/sha3"
    42  	"crypto/internal/fips140/sha512"
    43  	"crypto/internal/fips140/ssh"
    44  	"crypto/internal/fips140/subtle"
    45  	"crypto/internal/fips140/tls12"
    46  	"crypto/internal/fips140/tls13"
    47  	"crypto/internal/impl"
    48  	"crypto/rand"
    49  	_ "embed"
    50  	"encoding/binary"
    51  	"errors"
    52  	"fmt"
    53  	"internal/testenv"
    54  	"io"
    55  	"math/big"
    56  	"os"
    57  	"path/filepath"
    58  	"strings"
    59  	"testing"
    60  )
    61  
    62  var noPAAPAI = os.Getenv("GONOPAAPAI") == "1"
    63  
    64  func TestMain(m *testing.M) {
    65  	if noPAAPAI {
    66  		for _, p := range impl.Packages() {
    67  			impl.Select(p, "")
    68  		}
    69  	}
    70  	if os.Getenv("ACVP_WRAPPER") == "1" {
    71  		wrapperMain()
    72  	} else {
    73  		os.Exit(m.Run())
    74  	}
    75  }
    76  
    77  func wrapperMain() {
    78  	if !fips140.Enabled {
    79  		fmt.Fprintln(os.Stderr, "ACVP wrapper must be run with GODEBUG=fips140=on")
    80  		os.Exit(2)
    81  	}
    82  	if err := processingLoop(bufio.NewReader(os.Stdin), os.Stdout); err != nil {
    83  		fmt.Fprintf(os.Stderr, "processing error: %v\n", err)
    84  		os.Exit(1)
    85  	}
    86  }
    87  
    88  type request struct {
    89  	name string
    90  	args [][]byte
    91  }
    92  
    93  type commandHandler func([][]byte) ([][]byte, error)
    94  
    95  type command struct {
    96  	// requiredArgs enforces that an exact number of arguments are provided to the handler.
    97  	requiredArgs int
    98  	handler      commandHandler
    99  }
   100  
   101  type ecdsaSigType int
   102  
   103  const (
   104  	ecdsaSigTypeNormal ecdsaSigType = iota
   105  	ecdsaSigTypeDeterministic
   106  )
   107  
   108  type aesDirection int
   109  
   110  const (
   111  	aesEncrypt aesDirection = iota
   112  	aesDecrypt
   113  )
   114  
   115  var (
   116  	// SHA2 algorithm capabilities:
   117  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2
   118  	// SHA3 and SHAKE algorithm capabilities:
   119  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-sha3-and-shake-algorithm-ca
   120  	// cSHAKE algorithm capabilities:
   121  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-7.2
   122  	// HMAC algorithm capabilities:
   123  	//   https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7
   124  	// PBKDF2 algorithm capabilities:
   125  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html#section-7.3
   126  	// ML-KEM algorithm capabilities:
   127  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-ml-kem.html#section-7.3
   128  	// HMAC DRBG algorithm capabilities:
   129  	//   https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2
   130  	// EDDSA algorithm capabilities:
   131  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-7
   132  	// ECDSA and DetECDSA algorithm capabilities:
   133  	//   https://pages.nist.gov/ACVP/draft-fussell-acvp-ecdsa.html#section-7
   134  	// AES algorithm capabilities:
   135  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html#section-7.3
   136  	// HKDF KDA algorithm capabilities:
   137  	//   https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-hkdf.html#section-7.3
   138  	// OneStepNoCounter KDA algorithm capabilities:
   139  	//   https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-onestepnocounter.html#section-7.2
   140  	// TLS 1.2 KDF algorithm capabilities:
   141  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#section-7.2
   142  	// TLS 1.3 KDF algorithm capabilities:
   143  	//   https://pages.nist.gov/ACVP/draft-hammett-acvp-kdf-tls-v1.3.html#section-7.2
   144  	// SSH KDF algorithm capabilities:
   145  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#section-7.2
   146  	// ECDH algorithm capabilities:
   147  	//   https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ssc-ecc.html#section-7.3
   148  	// HMAC DRBG and CTR DRBG algorithm capabilities:
   149  	//   https://pages.nist.gov/ACVP/draft-vassilev-acvp-drbg.html#section-7.2
   150  	// KDF-Counter and KDF-Feedback algorithm capabilities:
   151  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html#section-7.3
   152  	// RSA algorithm capabilities:
   153  	//   https://pages.nist.gov/ACVP/draft-celi-acvp-rsa.html#section-7.3
   154  	//go:embed acvp_capabilities.json
   155  	capabilitiesJson []byte
   156  
   157  	// commands should reflect what config says we support. E.g. adding a command here will be a NOP
   158  	// unless the configuration/acvp_capabilities.json indicates the command's associated algorithm
   159  	// is supported.
   160  	commands = map[string]command{
   161  		"getConfig": cmdGetConfig(),
   162  
   163  		"SHA2-224":         cmdHashAft(sha256.New224()),
   164  		"SHA2-224/MCT":     cmdHashMct(sha256.New224()),
   165  		"SHA2-256":         cmdHashAft(sha256.New()),
   166  		"SHA2-256/MCT":     cmdHashMct(sha256.New()),
   167  		"SHA2-384":         cmdHashAft(sha512.New384()),
   168  		"SHA2-384/MCT":     cmdHashMct(sha512.New384()),
   169  		"SHA2-512":         cmdHashAft(sha512.New()),
   170  		"SHA2-512/MCT":     cmdHashMct(sha512.New()),
   171  		"SHA2-512/224":     cmdHashAft(sha512.New512_224()),
   172  		"SHA2-512/224/MCT": cmdHashMct(sha512.New512_224()),
   173  		"SHA2-512/256":     cmdHashAft(sha512.New512_256()),
   174  		"SHA2-512/256/MCT": cmdHashMct(sha512.New512_256()),
   175  
   176  		"SHA3-256":     cmdHashAft(sha3.New256()),
   177  		"SHA3-256/MCT": cmdSha3Mct(sha3.New256()),
   178  		"SHA3-224":     cmdHashAft(sha3.New224()),
   179  		"SHA3-224/MCT": cmdSha3Mct(sha3.New224()),
   180  		"SHA3-384":     cmdHashAft(sha3.New384()),
   181  		"SHA3-384/MCT": cmdSha3Mct(sha3.New384()),
   182  		"SHA3-512":     cmdHashAft(sha3.New512()),
   183  		"SHA3-512/MCT": cmdSha3Mct(sha3.New512()),
   184  
   185  		// Note: SHAKE AFT and VOT test types can be handled by the same command
   186  		// handler impl, but use distinct acvptool command names, and so are
   187  		// registered twice with the same digest: once under "SHAKE-xxx" for AFT,
   188  		// and once under"SHAKE-xxx/VOT" for VOT.
   189  		"SHAKE-128":     cmdShakeAftVot(sha3.NewShake128()),
   190  		"SHAKE-128/VOT": cmdShakeAftVot(sha3.NewShake128()),
   191  		"SHAKE-128/MCT": cmdShakeMct(sha3.NewShake128()),
   192  		"SHAKE-256":     cmdShakeAftVot(sha3.NewShake256()),
   193  		"SHAKE-256/VOT": cmdShakeAftVot(sha3.NewShake256()),
   194  		"SHAKE-256/MCT": cmdShakeMct(sha3.NewShake256()),
   195  
   196  		"cSHAKE-128":     cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }),
   197  		"cSHAKE-128/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }),
   198  		"cSHAKE-256":     cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }),
   199  		"cSHAKE-256/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }),
   200  
   201  		"HMAC-SHA2-224":     cmdHmacAft(func() fips140.Hash { return sha256.New224() }),
   202  		"HMAC-SHA2-256":     cmdHmacAft(func() fips140.Hash { return sha256.New() }),
   203  		"HMAC-SHA2-384":     cmdHmacAft(func() fips140.Hash { return sha512.New384() }),
   204  		"HMAC-SHA2-512":     cmdHmacAft(func() fips140.Hash { return sha512.New() }),
   205  		"HMAC-SHA2-512/224": cmdHmacAft(func() fips140.Hash { return sha512.New512_224() }),
   206  		"HMAC-SHA2-512/256": cmdHmacAft(func() fips140.Hash { return sha512.New512_256() }),
   207  		"HMAC-SHA3-224":     cmdHmacAft(func() fips140.Hash { return sha3.New224() }),
   208  		"HMAC-SHA3-256":     cmdHmacAft(func() fips140.Hash { return sha3.New256() }),
   209  		"HMAC-SHA3-384":     cmdHmacAft(func() fips140.Hash { return sha3.New384() }),
   210  		"HMAC-SHA3-512":     cmdHmacAft(func() fips140.Hash { return sha3.New512() }),
   211  
   212  		"HKDF/SHA2-224":     cmdHkdfAft(func() fips140.Hash { return sha256.New224() }),
   213  		"HKDF/SHA2-256":     cmdHkdfAft(func() fips140.Hash { return sha256.New() }),
   214  		"HKDF/SHA2-384":     cmdHkdfAft(func() fips140.Hash { return sha512.New384() }),
   215  		"HKDF/SHA2-512":     cmdHkdfAft(func() fips140.Hash { return sha512.New() }),
   216  		"HKDF/SHA2-512/224": cmdHkdfAft(func() fips140.Hash { return sha512.New512_224() }),
   217  		"HKDF/SHA2-512/256": cmdHkdfAft(func() fips140.Hash { return sha512.New512_256() }),
   218  		"HKDF/SHA3-224":     cmdHkdfAft(func() fips140.Hash { return sha3.New224() }),
   219  		"HKDF/SHA3-256":     cmdHkdfAft(func() fips140.Hash { return sha3.New256() }),
   220  		"HKDF/SHA3-384":     cmdHkdfAft(func() fips140.Hash { return sha3.New384() }),
   221  		"HKDF/SHA3-512":     cmdHkdfAft(func() fips140.Hash { return sha3.New512() }),
   222  
   223  		"HKDFExtract/SHA2-256":     cmdHkdfExtractAft(func() fips140.Hash { return sha256.New() }),
   224  		"HKDFExtract/SHA2-384":     cmdHkdfExtractAft(func() fips140.Hash { return sha512.New384() }),
   225  		"HKDFExpandLabel/SHA2-256": cmdHkdfExpandLabelAft(func() fips140.Hash { return sha256.New() }),
   226  		"HKDFExpandLabel/SHA2-384": cmdHkdfExpandLabelAft(func() fips140.Hash { return sha512.New384() }),
   227  
   228  		"PBKDF": cmdPbkdf(),
   229  
   230  		"ML-KEM-768/keyGen":  cmdMlKem768KeyGenAft(),
   231  		"ML-KEM-768/encap":   cmdMlKem768EncapAft(),
   232  		"ML-KEM-768/decap":   cmdMlKem768DecapAft(),
   233  		"ML-KEM-1024/keyGen": cmdMlKem1024KeyGenAft(),
   234  		"ML-KEM-1024/encap":  cmdMlKem1024EncapAft(),
   235  		"ML-KEM-1024/decap":  cmdMlKem1024DecapAft(),
   236  
   237  		"hmacDRBG/SHA2-224":     cmdHmacDrbgAft(func() fips140.Hash { return sha256.New224() }),
   238  		"hmacDRBG/SHA2-256":     cmdHmacDrbgAft(func() fips140.Hash { return sha256.New() }),
   239  		"hmacDRBG/SHA2-384":     cmdHmacDrbgAft(func() fips140.Hash { return sha512.New384() }),
   240  		"hmacDRBG/SHA2-512":     cmdHmacDrbgAft(func() fips140.Hash { return sha512.New() }),
   241  		"hmacDRBG/SHA2-512/224": cmdHmacDrbgAft(func() fips140.Hash { return sha512.New512_224() }),
   242  		"hmacDRBG/SHA2-512/256": cmdHmacDrbgAft(func() fips140.Hash { return sha512.New512_256() }),
   243  		"hmacDRBG/SHA3-224":     cmdHmacDrbgAft(func() fips140.Hash { return sha3.New224() }),
   244  		"hmacDRBG/SHA3-256":     cmdHmacDrbgAft(func() fips140.Hash { return sha3.New256() }),
   245  		"hmacDRBG/SHA3-384":     cmdHmacDrbgAft(func() fips140.Hash { return sha3.New384() }),
   246  		"hmacDRBG/SHA3-512":     cmdHmacDrbgAft(func() fips140.Hash { return sha3.New512() }),
   247  
   248  		"EDDSA/keyGen": cmdEddsaKeyGenAft(),
   249  		"EDDSA/keyVer": cmdEddsaKeyVerAft(),
   250  		"EDDSA/sigGen": cmdEddsaSigGenAftBft(),
   251  		"EDDSA/sigVer": cmdEddsaSigVerAft(),
   252  
   253  		"ECDSA/keyGen":    cmdEcdsaKeyGenAft(),
   254  		"ECDSA/keyVer":    cmdEcdsaKeyVerAft(),
   255  		"ECDSA/sigGen":    cmdEcdsaSigGenAft(ecdsaSigTypeNormal),
   256  		"ECDSA/sigVer":    cmdEcdsaSigVerAft(),
   257  		"DetECDSA/sigGen": cmdEcdsaSigGenAft(ecdsaSigTypeDeterministic),
   258  
   259  		"AES-CBC/encrypt":        cmdAesCbc(aesEncrypt),
   260  		"AES-CBC/decrypt":        cmdAesCbc(aesDecrypt),
   261  		"AES-CTR/encrypt":        cmdAesCtr(aesEncrypt),
   262  		"AES-CTR/decrypt":        cmdAesCtr(aesDecrypt),
   263  		"AES-GCM/seal":           cmdAesGcmSeal(false),
   264  		"AES-GCM/open":           cmdAesGcmOpen(false),
   265  		"AES-GCM-randnonce/seal": cmdAesGcmSeal(true),
   266  		"AES-GCM-randnonce/open": cmdAesGcmOpen(true),
   267  
   268  		"CMAC-AES":        cmdCmacAesAft(),
   269  		"CMAC-AES/verify": cmdCmacAesVerifyAft(),
   270  
   271  		// Note: Only SHA2-256, SHA2-384 and SHA2-512 are valid hash functions for TLSKDF.
   272  		// 		 See https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#section-7.2.1
   273  		"TLSKDF/1.2/SHA2-256": cmdTlsKdf12Aft(func() fips140.Hash { return sha256.New() }),
   274  		"TLSKDF/1.2/SHA2-384": cmdTlsKdf12Aft(func() fips140.Hash { return sha512.New384() }),
   275  		"TLSKDF/1.2/SHA2-512": cmdTlsKdf12Aft(func() fips140.Hash { return sha512.New() }),
   276  
   277  		// Note: only SHA2-224, SHA2-256, SHA2-384 and SHA2-512 are valid hash functions for SSHKDF.
   278  		// 		 See https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-ssh.html#section-7.2.1
   279  		"SSHKDF/SHA2-224/client": cmdSshKdfAft(func() fips140.Hash { return sha256.New224() }, ssh.ClientKeys),
   280  		"SSHKDF/SHA2-224/server": cmdSshKdfAft(func() fips140.Hash { return sha256.New224() }, ssh.ServerKeys),
   281  		"SSHKDF/SHA2-256/client": cmdSshKdfAft(func() fips140.Hash { return sha256.New() }, ssh.ClientKeys),
   282  		"SSHKDF/SHA2-256/server": cmdSshKdfAft(func() fips140.Hash { return sha256.New() }, ssh.ServerKeys),
   283  		"SSHKDF/SHA2-384/client": cmdSshKdfAft(func() fips140.Hash { return sha512.New384() }, ssh.ClientKeys),
   284  		"SSHKDF/SHA2-384/server": cmdSshKdfAft(func() fips140.Hash { return sha512.New384() }, ssh.ServerKeys),
   285  		"SSHKDF/SHA2-512/client": cmdSshKdfAft(func() fips140.Hash { return sha512.New() }, ssh.ClientKeys),
   286  		"SSHKDF/SHA2-512/server": cmdSshKdfAft(func() fips140.Hash { return sha512.New() }, ssh.ServerKeys),
   287  
   288  		"ECDH/P-224": cmdEcdhAftVal(ecdh.P224()),
   289  		"ECDH/P-256": cmdEcdhAftVal(ecdh.P256()),
   290  		"ECDH/P-384": cmdEcdhAftVal(ecdh.P384()),
   291  		"ECDH/P-521": cmdEcdhAftVal(ecdh.P521()),
   292  
   293  		"ctrDRBG/AES-256":        cmdCtrDrbgAft(),
   294  		"ctrDRBG-reseed/AES-256": cmdCtrDrbgReseedAft(),
   295  
   296  		"RSA/keyGen": cmdRsaKeyGenAft(),
   297  
   298  		"RSA/sigGen/SHA2-224/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", false),
   299  		"RSA/sigGen/SHA2-256/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha256.New() }, "SHA-256", false),
   300  		"RSA/sigGen/SHA2-384/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", false),
   301  		"RSA/sigGen/SHA2-512/pkcs1v1.5": cmdRsaSigGenAft(func() fips140.Hash { return sha512.New() }, "SHA-512", false),
   302  		"RSA/sigGen/SHA2-224/pss":       cmdRsaSigGenAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", true),
   303  		"RSA/sigGen/SHA2-256/pss":       cmdRsaSigGenAft(func() fips140.Hash { return sha256.New() }, "SHA-256", true),
   304  		"RSA/sigGen/SHA2-384/pss":       cmdRsaSigGenAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", true),
   305  		"RSA/sigGen/SHA2-512/pss":       cmdRsaSigGenAft(func() fips140.Hash { return sha512.New() }, "SHA-512", true),
   306  
   307  		"RSA/sigVer/SHA2-224/pkcs1v1.5": cmdRsaSigVerAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", false),
   308  		"RSA/sigVer/SHA2-256/pkcs1v1.5": cmdRsaSigVerAft(func() fips140.Hash { return sha256.New() }, "SHA-256", false),
   309  		"RSA/sigVer/SHA2-384/pkcs1v1.5": cmdRsaSigVerAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", false),
   310  		"RSA/sigVer/SHA2-512/pkcs1v1.5": cmdRsaSigVerAft(func() fips140.Hash { return sha512.New() }, "SHA-512", false),
   311  		"RSA/sigVer/SHA2-224/pss":       cmdRsaSigVerAft(func() fips140.Hash { return sha256.New224() }, "SHA-224", true),
   312  		"RSA/sigVer/SHA2-256/pss":       cmdRsaSigVerAft(func() fips140.Hash { return sha256.New() }, "SHA-256", true),
   313  		"RSA/sigVer/SHA2-384/pss":       cmdRsaSigVerAft(func() fips140.Hash { return sha512.New384() }, "SHA-384", true),
   314  		"RSA/sigVer/SHA2-512/pss":       cmdRsaSigVerAft(func() fips140.Hash { return sha512.New() }, "SHA-512", true),
   315  
   316  		"KDF-counter":  cmdKdfCounterAft(),
   317  		"KDF-feedback": cmdKdfFeedbackAft(),
   318  
   319  		"OneStepNoCounter/HMAC-SHA2-224":     cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha256.New224() }),
   320  		"OneStepNoCounter/HMAC-SHA2-256":     cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha256.New() }),
   321  		"OneStepNoCounter/HMAC-SHA2-384":     cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha512.New384() }),
   322  		"OneStepNoCounter/HMAC-SHA2-512":     cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha512.New() }),
   323  		"OneStepNoCounter/HMAC-SHA2-512/224": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha512.New512_224() }),
   324  		"OneStepNoCounter/HMAC-SHA2-512/256": cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha512.New512_256() }),
   325  		"OneStepNoCounter/HMAC-SHA3-224":     cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New224() }),
   326  		"OneStepNoCounter/HMAC-SHA3-256":     cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New256() }),
   327  		"OneStepNoCounter/HMAC-SHA3-384":     cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New384() }),
   328  		"OneStepNoCounter/HMAC-SHA3-512":     cmdOneStepNoCounterHmacAft(func() fips140.Hash { return sha3.New512() }),
   329  
   330  		"KTS-IFC/SHA2-224/initiator":     cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha256.New224() }),
   331  		"KTS-IFC/SHA2-224/responder":     cmdKtsIfcResponderAft(func() fips140.Hash { return sha256.New224() }),
   332  		"KTS-IFC/SHA2-256/initiator":     cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha256.New() }),
   333  		"KTS-IFC/SHA2-256/responder":     cmdKtsIfcResponderAft(func() fips140.Hash { return sha256.New() }),
   334  		"KTS-IFC/SHA2-384/initiator":     cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha512.New384() }),
   335  		"KTS-IFC/SHA2-384/responder":     cmdKtsIfcResponderAft(func() fips140.Hash { return sha512.New384() }),
   336  		"KTS-IFC/SHA2-512/initiator":     cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha512.New() }),
   337  		"KTS-IFC/SHA2-512/responder":     cmdKtsIfcResponderAft(func() fips140.Hash { return sha512.New() }),
   338  		"KTS-IFC/SHA2-512/224/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha512.New512_224() }),
   339  		"KTS-IFC/SHA2-512/224/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha512.New512_224() }),
   340  		"KTS-IFC/SHA2-512/256/initiator": cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha512.New512_256() }),
   341  		"KTS-IFC/SHA2-512/256/responder": cmdKtsIfcResponderAft(func() fips140.Hash { return sha512.New512_256() }),
   342  		"KTS-IFC/SHA3-224/initiator":     cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha3.New224() }),
   343  		"KTS-IFC/SHA3-224/responder":     cmdKtsIfcResponderAft(func() fips140.Hash { return sha3.New224() }),
   344  		"KTS-IFC/SHA3-256/initiator":     cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha3.New256() }),
   345  		"KTS-IFC/SHA3-256/responder":     cmdKtsIfcResponderAft(func() fips140.Hash { return sha3.New256() }),
   346  		"KTS-IFC/SHA3-384/initiator":     cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha3.New384() }),
   347  		"KTS-IFC/SHA3-384/responder":     cmdKtsIfcResponderAft(func() fips140.Hash { return sha3.New384() }),
   348  		"KTS-IFC/SHA3-512/initiator":     cmdKtsIfcInitiatorAft(func() fips140.Hash { return sha3.New512() }),
   349  		"KTS-IFC/SHA3-512/responder":     cmdKtsIfcResponderAft(func() fips140.Hash { return sha3.New512() }),
   350  	}
   351  )
   352  
   353  func processingLoop(reader io.Reader, writer io.Writer) error {
   354  	// Per ACVP.md:
   355  	//   The protocol is request–response: the subprocess only speaks in response to a request
   356  	//   and there is exactly one response for every request.
   357  	for {
   358  		req, err := readRequest(reader)
   359  		if errors.Is(err, io.EOF) {
   360  			break
   361  		} else if err != nil {
   362  			return fmt.Errorf("reading request: %w", err)
   363  		}
   364  
   365  		cmd, exists := commands[req.name]
   366  		if !exists {
   367  			return fmt.Errorf("unknown command: %q", req.name)
   368  		}
   369  
   370  		if gotArgs := len(req.args); gotArgs != cmd.requiredArgs {
   371  			return fmt.Errorf("command %q expected %d args, got %d", req.name, cmd.requiredArgs, gotArgs)
   372  		}
   373  
   374  		response, err := cmd.handler(req.args)
   375  		if err != nil {
   376  			return fmt.Errorf("command %q failed: %w", req.name, err)
   377  		}
   378  
   379  		if err = writeResponse(writer, response); err != nil {
   380  			return fmt.Errorf("command %q response failed: %w", req.name, err)
   381  		}
   382  	}
   383  
   384  	return nil
   385  }
   386  
   387  func readRequest(reader io.Reader) (*request, error) {
   388  	// Per ACVP.md:
   389  	//   Requests consist of one or more byte strings and responses consist
   390  	//   of zero or more byte strings. A request contains: the number of byte
   391  	//   strings, the length of each byte string, and the contents of each byte
   392  	//   string. All numbers are 32-bit little-endian and values are
   393  	//   concatenated in the order specified.
   394  	var numArgs uint32
   395  	if err := binary.Read(reader, binary.LittleEndian, &numArgs); err != nil {
   396  		return nil, err
   397  	}
   398  	if numArgs == 0 {
   399  		return nil, errors.New("invalid request: zero args")
   400  	}
   401  
   402  	args, err := readArgs(reader, numArgs)
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  
   407  	return &request{
   408  		name: string(args[0]),
   409  		args: args[1:],
   410  	}, nil
   411  }
   412  
   413  func readArgs(reader io.Reader, requiredArgs uint32) ([][]byte, error) {
   414  	argLengths := make([]uint32, requiredArgs)
   415  	args := make([][]byte, requiredArgs)
   416  
   417  	for i := range argLengths {
   418  		if err := binary.Read(reader, binary.LittleEndian, &argLengths[i]); err != nil {
   419  			return nil, fmt.Errorf("invalid request: failed to read %d-th arg len: %w", i, err)
   420  		}
   421  	}
   422  
   423  	for i, length := range argLengths {
   424  		buf := make([]byte, length)
   425  		if _, err := io.ReadFull(reader, buf); err != nil {
   426  			return nil, fmt.Errorf("invalid request: failed to read %d-th arg data: %w", i, err)
   427  		}
   428  		args[i] = buf
   429  	}
   430  
   431  	return args, nil
   432  }
   433  
   434  func writeResponse(writer io.Writer, args [][]byte) error {
   435  	// See `readRequest` for details on the base format. Per ACVP.md:
   436  	//   A response has the same format except that there may be zero byte strings
   437  	//   and the first byte string has no special meaning.
   438  	numArgs := uint32(len(args))
   439  	if err := binary.Write(writer, binary.LittleEndian, numArgs); err != nil {
   440  		return fmt.Errorf("writing arg count: %w", err)
   441  	}
   442  
   443  	for i, arg := range args {
   444  		if err := binary.Write(writer, binary.LittleEndian, uint32(len(arg))); err != nil {
   445  			return fmt.Errorf("writing %d-th arg length: %w", i, err)
   446  		}
   447  	}
   448  
   449  	for i, b := range args {
   450  		if _, err := writer.Write(b); err != nil {
   451  			return fmt.Errorf("writing %d-th arg data: %w", i, err)
   452  		}
   453  	}
   454  
   455  	return nil
   456  }
   457  
   458  // "All implementations must support the getConfig command
   459  // which takes no arguments and returns a single byte string
   460  // which is a JSON blob of ACVP algorithm configuration."
   461  func cmdGetConfig() command {
   462  	return command{
   463  		handler: func(args [][]byte) ([][]byte, error) {
   464  			return [][]byte{capabilitiesJson}, nil
   465  		},
   466  	}
   467  }
   468  
   469  // cmdHashAft returns a command handler for the specified hash
   470  // algorithm for algorithm functional test (AFT) test cases.
   471  //
   472  // This shape of command expects a message as the sole argument,
   473  // and writes the resulting digest as a response.
   474  //
   475  // See https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html
   476  func cmdHashAft(h fips140.Hash) command {
   477  	return command{
   478  		requiredArgs: 1, // Message to hash.
   479  		handler: func(args [][]byte) ([][]byte, error) {
   480  			h.Reset()
   481  			h.Write(args[0])
   482  			digest := make([]byte, 0, h.Size())
   483  			digest = h.Sum(digest)
   484  
   485  			return [][]byte{digest}, nil
   486  		},
   487  	}
   488  }
   489  
   490  // cmdHashMct returns a command handler for the specified hash
   491  // algorithm for monte carlo test (MCT) test cases.
   492  //
   493  // This shape of command expects a seed as the sole argument,
   494  // and writes the resulting digest as a response. It implements
   495  // the "standard" flavour of the MCT, not the "alternative".
   496  //
   497  // This algorithm was ported from `HashMCT` in BSSL's `modulewrapper.cc`
   498  // Note that it differs slightly from the upstream NIST MCT[0] algorithm
   499  // in that it does not perform the outer 100 iterations itself. See
   500  // footnote #1 in the ACVP.md docs[1], the acvptool handles this.
   501  //
   502  // [0]: https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-6.2
   503  // [1]: https://boringssl.googlesource.com/boringssl/+/refs/heads/master/util/fipstools/acvp/ACVP.md#testing-other-fips-modules
   504  func cmdHashMct(h fips140.Hash) command {
   505  	return command{
   506  		requiredArgs: 1, // Seed message.
   507  		handler: func(args [][]byte) ([][]byte, error) {
   508  			hSize := h.Size()
   509  			seed := args[0]
   510  
   511  			if seedLen := len(seed); seedLen != hSize {
   512  				return nil, fmt.Errorf("invalid seed size: expected %d got %d", hSize, seedLen)
   513  			}
   514  
   515  			digest := make([]byte, 0, hSize)
   516  			buf := make([]byte, 0, 3*hSize)
   517  			buf = append(buf, seed...)
   518  			buf = append(buf, seed...)
   519  			buf = append(buf, seed...)
   520  
   521  			for i := 0; i < 1000; i++ {
   522  				h.Reset()
   523  				h.Write(buf)
   524  				digest = h.Sum(digest[:0])
   525  
   526  				copy(buf, buf[hSize:])
   527  				copy(buf[2*hSize:], digest)
   528  			}
   529  
   530  			return [][]byte{buf[hSize*2:]}, nil
   531  		},
   532  	}
   533  }
   534  
   535  // cmdSha3Mct returns a command handler for the specified hash
   536  // algorithm for SHA-3 monte carlo test (MCT) test cases.
   537  //
   538  // This shape of command expects a seed as the sole argument,
   539  // and writes the resulting digest as a response. It implements
   540  // the "standard" flavour of the MCT, not the "alternative".
   541  //
   542  // This algorithm was ported from the "standard" MCT algorithm
   543  // specified in  draft-celi-acvp-sha3[0]. Note this differs from
   544  // the SHA2-* family of MCT tests handled by cmdHashMct. However,
   545  // like that handler it does not perform the outer 100 iterations.
   546  //
   547  // [0]: https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#section-6.2.1
   548  func cmdSha3Mct(h fips140.Hash) command {
   549  	return command{
   550  		requiredArgs: 1, // Seed message.
   551  		handler: func(args [][]byte) ([][]byte, error) {
   552  			seed := args[0]
   553  			md := make([][]byte, 1001)
   554  			md[0] = seed
   555  
   556  			for i := 1; i <= 1000; i++ {
   557  				h.Reset()
   558  				h.Write(md[i-1])
   559  				md[i] = h.Sum(nil)
   560  			}
   561  
   562  			return [][]byte{md[1000]}, nil
   563  		},
   564  	}
   565  }
   566  
   567  func cmdShakeAftVot(h *sha3.SHAKE) command {
   568  	return command{
   569  		requiredArgs: 2, // Message, output length (bytes)
   570  		handler: func(args [][]byte) ([][]byte, error) {
   571  			msg := args[0]
   572  
   573  			outLenBytes := binary.LittleEndian.Uint32(args[1])
   574  			digest := make([]byte, outLenBytes)
   575  
   576  			h.Reset()
   577  			h.Write(msg)
   578  			h.Read(digest)
   579  
   580  			return [][]byte{digest}, nil
   581  		},
   582  	}
   583  }
   584  
   585  func cmdShakeMct(h *sha3.SHAKE) command {
   586  	return command{
   587  		requiredArgs: 4, // Seed message, min output length (bytes), max output length (bytes), output length (bytes)
   588  		handler: func(args [][]byte) ([][]byte, error) {
   589  			md := args[0]
   590  			minOutBytes := binary.LittleEndian.Uint32(args[1])
   591  			maxOutBytes := binary.LittleEndian.Uint32(args[2])
   592  
   593  			outputLenBytes := binary.LittleEndian.Uint32(args[3])
   594  			if outputLenBytes < 2 {
   595  				return nil, fmt.Errorf("invalid output length: %d", outputLenBytes)
   596  			}
   597  
   598  			rangeBytes := maxOutBytes - minOutBytes + 1
   599  			if rangeBytes == 0 {
   600  				return nil, fmt.Errorf("invalid maxOutBytes and minOutBytes: %d, %d", maxOutBytes, minOutBytes)
   601  			}
   602  
   603  			for i := 0; i < 1000; i++ {
   604  				// "The MSG[i] input to SHAKE MUST always contain at least 128 bits. If this is not the case
   605  				// as the previous digest was too short, append empty bits to the rightmost side of the digest."
   606  				boundary := min(len(md), 16)
   607  				msg := make([]byte, 16)
   608  				copy(msg, md[:boundary])
   609  
   610  				//  MD[i] = SHAKE(MSG[i], OutputLen * 8)
   611  				h.Reset()
   612  				h.Write(msg)
   613  				digest := make([]byte, outputLenBytes)
   614  				h.Read(digest)
   615  				md = digest
   616  
   617  				// RightmostOutputBits = 16 rightmost bits of MD[i] as an integer
   618  				// OutputLen = minOutBytes + (RightmostOutputBits % Range)
   619  				rightmostOutput := uint32(md[outputLenBytes-2])<<8 | uint32(md[outputLenBytes-1])
   620  				outputLenBytes = minOutBytes + (rightmostOutput % rangeBytes)
   621  			}
   622  
   623  			encodedOutputLenBytes := make([]byte, 4)
   624  			binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes)
   625  
   626  			return [][]byte{md, encodedOutputLenBytes}, nil
   627  		},
   628  	}
   629  }
   630  
   631  func cmdCShakeAft(hFn func(N, S []byte) *sha3.SHAKE) command {
   632  	return command{
   633  		requiredArgs: 4, // Message, output length bytes, function name, customization
   634  		handler: func(args [][]byte) ([][]byte, error) {
   635  			msg := args[0]
   636  			outLenBytes := binary.LittleEndian.Uint32(args[1])
   637  			functionName := args[2]
   638  			customization := args[3]
   639  
   640  			h := hFn(functionName, customization)
   641  			h.Write(msg)
   642  
   643  			out := make([]byte, outLenBytes)
   644  			h.Read(out)
   645  
   646  			return [][]byte{out}, nil
   647  		},
   648  	}
   649  }
   650  
   651  func cmdCShakeMct(hFn func(N, S []byte) *sha3.SHAKE) command {
   652  	return command{
   653  		requiredArgs: 6, // Message, min output length (bits), max output length (bits), output length (bits), increment (bits), customization
   654  		handler: func(args [][]byte) ([][]byte, error) {
   655  			message := args[0]
   656  			minOutLenBytes := binary.LittleEndian.Uint32(args[1])
   657  			maxOutLenBytes := binary.LittleEndian.Uint32(args[2])
   658  			outputLenBytes := binary.LittleEndian.Uint32(args[3])
   659  			incrementBytes := binary.LittleEndian.Uint32(args[4])
   660  			customization := args[5]
   661  
   662  			if outputLenBytes < 2 {
   663  				return nil, fmt.Errorf("invalid output length: %d", outputLenBytes)
   664  			}
   665  
   666  			rangeBits := (maxOutLenBytes*8 - minOutLenBytes*8) + 1
   667  			if rangeBits == 0 {
   668  				return nil, fmt.Errorf("invalid maxOutLenBytes and minOutLenBytes: %d, %d", maxOutLenBytes, minOutLenBytes)
   669  			}
   670  
   671  			// cSHAKE Monte Carlo test inner loop:
   672  			//   https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-6.2.1
   673  			for i := 0; i < 1000; i++ {
   674  				// InnerMsg = Left(Output[i-1] || ZeroBits(128), 128);
   675  				boundary := min(len(message), 16)
   676  				innerMsg := make([]byte, 16)
   677  				copy(innerMsg, message[:boundary])
   678  
   679  				// Output[i] = CSHAKE(InnerMsg, OutputLen, FunctionName, Customization);
   680  				h := hFn(nil, customization) // Note: function name fixed to "" for MCT.
   681  				h.Write(innerMsg)
   682  				digest := make([]byte, outputLenBytes)
   683  				h.Read(digest)
   684  				message = digest
   685  
   686  				// Rightmost_Output_bits = Right(Output[i], 16);
   687  				rightmostOutput := digest[outputLenBytes-2:]
   688  				// IMPORTANT: the specification says:
   689  				//   NOTE: For the "Rightmost_Output_bits % Range" operation, the Rightmost_Output_bits bit string
   690  				//   should be interpretted as a little endian-encoded number.
   691  				// This is **a lie**! It has to be interpreted as a big-endian number.
   692  				rightmostOutputBE := binary.BigEndian.Uint16(rightmostOutput)
   693  
   694  				// OutputLen = MinOutLen + (floor((Rightmost_Output_bits % Range) / OutLenIncrement) * OutLenIncrement);
   695  				incrementBits := incrementBytes * 8
   696  				outputLenBits := (minOutLenBytes * 8) + (((uint32)(rightmostOutputBE)%rangeBits)/incrementBits)*incrementBits
   697  				outputLenBytes = outputLenBits / 8
   698  
   699  				// Customization = BitsToString(InnerMsg || Rightmost_Output_bits);
   700  				msgWithBits := append(innerMsg, rightmostOutput...)
   701  				customization = make([]byte, len(msgWithBits))
   702  				for i, b := range msgWithBits {
   703  					customization[i] = (b % 26) + 65
   704  				}
   705  			}
   706  
   707  			encodedOutputLenBytes := make([]byte, 4)
   708  			binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes)
   709  
   710  			return [][]byte{message, encodedOutputLenBytes, customization}, nil
   711  		},
   712  	}
   713  }
   714  
   715  func cmdHmacAft(h func() fips140.Hash) command {
   716  	return command{
   717  		requiredArgs: 2, // Message and key
   718  		handler: func(args [][]byte) ([][]byte, error) {
   719  			msg := args[0]
   720  			key := args[1]
   721  			mac := hmac.New(h, key)
   722  			mac.Write(msg)
   723  			return [][]byte{mac.Sum(nil)}, nil
   724  		},
   725  	}
   726  }
   727  
   728  func cmdHkdfAft(h func() fips140.Hash) command {
   729  	return command{
   730  		requiredArgs: 4, // Key, salt, info, length bytes
   731  		handler: func(args [][]byte) ([][]byte, error) {
   732  			key := args[0]
   733  			salt := args[1]
   734  			info := args[2]
   735  			keyLen := int(binary.LittleEndian.Uint32(args[3]))
   736  
   737  			return [][]byte{hkdf.Key(h, key, salt, string(info), keyLen)}, nil
   738  		},
   739  	}
   740  }
   741  
   742  func cmdHkdfExtractAft(h func() fips140.Hash) command {
   743  	return command{
   744  		requiredArgs: 2, // secret, salt
   745  		handler: func(args [][]byte) ([][]byte, error) {
   746  			secret := args[0]
   747  			salt := args[1]
   748  
   749  			return [][]byte{hkdf.Extract(h, secret, salt)}, nil
   750  		},
   751  	}
   752  }
   753  
   754  func cmdHkdfExpandLabelAft(h func() fips140.Hash) command {
   755  	return command{
   756  		requiredArgs: 4, // output length, secret, label, transcript hash
   757  		handler: func(args [][]byte) ([][]byte, error) {
   758  			keyLen := int(binary.LittleEndian.Uint32(args[0]))
   759  			secret := args[1]
   760  			label := args[2]
   761  			transcriptHash := args[3]
   762  
   763  			return [][]byte{tls13.ExpandLabel(h, secret, string(label), transcriptHash, keyLen)}, nil
   764  		},
   765  	}
   766  }
   767  
   768  func cmdPbkdf() command {
   769  	return command{
   770  		// Hash name, key length, salt, password, iteration count
   771  		requiredArgs: 5,
   772  		handler: func(args [][]byte) ([][]byte, error) {
   773  			h, err := lookupHash(string(args[0]))
   774  			if err != nil {
   775  				return nil, fmt.Errorf("PBKDF2 failed: %w", err)
   776  			}
   777  
   778  			keyLen := binary.LittleEndian.Uint32(args[1]) / 8
   779  			salt := args[2]
   780  			password := args[3]
   781  			iterationCount := binary.LittleEndian.Uint32(args[4])
   782  
   783  			derivedKey, err := pbkdf2.Key(h, string(password), salt, int(iterationCount), int(keyLen))
   784  			if err != nil {
   785  				return nil, fmt.Errorf("PBKDF2 failed: %w", err)
   786  			}
   787  
   788  			return [][]byte{derivedKey}, nil
   789  		},
   790  	}
   791  }
   792  
   793  func cmdEddsaKeyGenAft() command {
   794  	return command{
   795  		requiredArgs: 1, // Curve name
   796  		handler: func(args [][]byte) ([][]byte, error) {
   797  			if string(args[0]) != "ED-25519" {
   798  				return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
   799  			}
   800  
   801  			sk, err := ed25519.GenerateKey()
   802  			if err != nil {
   803  				return nil, fmt.Errorf("generating EDDSA keypair: %w", err)
   804  			}
   805  
   806  			// EDDSA/keyGen/AFT responses are d & q, described[0] as:
   807  			//   d	The encoded private key point
   808  			//   q	The encoded public key point
   809  			//
   810  			// Contrary to the description of a "point", d is the private key
   811  			// seed bytes per FIPS.186-5[1] A.2.3.
   812  			//
   813  			// [0]: https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-9.1
   814  			// [1]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf
   815  			return [][]byte{sk.Seed(), sk.PublicKey()}, nil
   816  		},
   817  	}
   818  }
   819  
   820  func cmdEddsaKeyVerAft() command {
   821  	return command{
   822  		requiredArgs: 2, // Curve name, Q
   823  		handler: func(args [][]byte) ([][]byte, error) {
   824  			if string(args[0]) != "ED-25519" {
   825  				return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
   826  			}
   827  
   828  			// Verify the point is on the curve. The higher-level ed25519 API does
   829  			// this at signature verification time so we have to use the lower-level
   830  			// edwards25519 package to do it here in absence of a signature to verify.
   831  			if _, err := new(edwards25519.Point).SetBytes(args[1]); err != nil {
   832  				return [][]byte{{0}}, nil
   833  			}
   834  
   835  			return [][]byte{{1}}, nil
   836  		},
   837  	}
   838  }
   839  
   840  func cmdEddsaSigGenAftBft() command {
   841  	return command{
   842  		requiredArgs: 5, // Curve name, private key seed, message, prehash, context
   843  		handler: func(args [][]byte) ([][]byte, error) {
   844  			if string(args[0]) != "ED-25519" {
   845  				return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
   846  			}
   847  
   848  			sk, err := ed25519.NewPrivateKeyFromSeed(args[1])
   849  			if err != nil {
   850  				return nil, fmt.Errorf("error creating private key: %w", err)
   851  			}
   852  			msg := args[2]
   853  			prehash := args[3]
   854  			context := string(args[4])
   855  
   856  			var sig []byte
   857  			if prehash[0] == 1 {
   858  				h := sha512.New()
   859  				h.Write(msg)
   860  				msg = h.Sum(nil)
   861  
   862  				// With ed25519 the context is only specified for sigGen tests when using prehashing.
   863  				// See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6
   864  				sig, err = ed25519.SignPH(sk, msg, context)
   865  				if err != nil {
   866  					return nil, fmt.Errorf("error signing message: %w", err)
   867  				}
   868  			} else {
   869  				sig = ed25519.Sign(sk, msg)
   870  			}
   871  
   872  			return [][]byte{sig}, nil
   873  		},
   874  	}
   875  }
   876  
   877  func cmdEddsaSigVerAft() command {
   878  	return command{
   879  		requiredArgs: 5, // Curve name, message, public key, signature, prehash
   880  		handler: func(args [][]byte) ([][]byte, error) {
   881  			if string(args[0]) != "ED-25519" {
   882  				return nil, fmt.Errorf("unsupported EDDSA curve: %q", args[0])
   883  			}
   884  
   885  			msg := args[1]
   886  			pk, err := ed25519.NewPublicKey(args[2])
   887  			if err != nil {
   888  				return nil, fmt.Errorf("invalid public key: %w", err)
   889  			}
   890  			sig := args[3]
   891  			prehash := args[4]
   892  
   893  			if prehash[0] == 1 {
   894  				h := sha512.New()
   895  				h.Write(msg)
   896  				msg = h.Sum(nil)
   897  				// Context is only specified for sigGen, not sigVer.
   898  				// See https://pages.nist.gov/ACVP/draft-celi-acvp-eddsa.html#section-8.6
   899  				err = ed25519.VerifyPH(pk, msg, sig, "")
   900  			} else {
   901  				err = ed25519.Verify(pk, msg, sig)
   902  			}
   903  
   904  			if err != nil {
   905  				return [][]byte{{0}}, nil
   906  			}
   907  
   908  			return [][]byte{{1}}, nil
   909  		},
   910  	}
   911  }
   912  
   913  func cmdEcdsaKeyGenAft() command {
   914  	return command{
   915  		requiredArgs: 1, // Curve name
   916  		handler: func(args [][]byte) ([][]byte, error) {
   917  			curve, err := lookupCurve(string(args[0]))
   918  			if err != nil {
   919  				return nil, err
   920  			}
   921  
   922  			var sk *ecdsa.PrivateKey
   923  			switch curve.Params() {
   924  			case elliptic.P224().Params():
   925  				sk, err = ecdsa.GenerateKey(ecdsa.P224(), rand.Reader)
   926  			case elliptic.P256().Params():
   927  				sk, err = ecdsa.GenerateKey(ecdsa.P256(), rand.Reader)
   928  			case elliptic.P384().Params():
   929  				sk, err = ecdsa.GenerateKey(ecdsa.P384(), rand.Reader)
   930  			case elliptic.P521().Params():
   931  				sk, err = ecdsa.GenerateKey(ecdsa.P521(), rand.Reader)
   932  			default:
   933  				return nil, fmt.Errorf("unsupported curve: %v", curve)
   934  			}
   935  
   936  			if err != nil {
   937  				return nil, err
   938  			}
   939  
   940  			pubBytes := sk.PublicKey().Bytes()
   941  			byteLen := (curve.Params().BitSize + 7) / 8
   942  
   943  			return [][]byte{
   944  				sk.Bytes(),
   945  				pubBytes[1 : 1+byteLen],
   946  				pubBytes[1+byteLen:],
   947  			}, nil
   948  		},
   949  	}
   950  }
   951  
   952  func cmdEcdsaKeyVerAft() command {
   953  	return command{
   954  		requiredArgs: 3, // Curve name, X, Y
   955  		handler: func(args [][]byte) ([][]byte, error) {
   956  			curve, err := lookupCurve(string(args[0]))
   957  			if err != nil {
   958  				return nil, err
   959  			}
   960  
   961  			x := new(big.Int).SetBytes(args[1])
   962  			y := new(big.Int).SetBytes(args[2])
   963  
   964  			if curve.IsOnCurve(x, y) {
   965  				return [][]byte{{1}}, nil
   966  			}
   967  
   968  			return [][]byte{{0}}, nil
   969  		},
   970  	}
   971  }
   972  
   973  // pointFromAffine is used to convert the PublicKey to a nistec SetBytes input.
   974  // Duplicated from crypto/ecdsa.go's pointFromAffine.
   975  func pointFromAffine(curve elliptic.Curve, x, y *big.Int) ([]byte, error) {
   976  	bitSize := curve.Params().BitSize
   977  	// Reject values that would not get correctly encoded.
   978  	if x.Sign() < 0 || y.Sign() < 0 {
   979  		return nil, errors.New("negative coordinate")
   980  	}
   981  	if x.BitLen() > bitSize || y.BitLen() > bitSize {
   982  		return nil, errors.New("overflowing coordinate")
   983  	}
   984  	// Encode the coordinates and let SetBytes reject invalid points.
   985  	byteLen := (bitSize + 7) / 8
   986  	buf := make([]byte, 1+2*byteLen)
   987  	buf[0] = 4 // uncompressed point
   988  	x.FillBytes(buf[1 : 1+byteLen])
   989  	y.FillBytes(buf[1+byteLen : 1+2*byteLen])
   990  	return buf, nil
   991  }
   992  
   993  func signEcdsa[P ecdsa.Point[P], H fips140.Hash](c *ecdsa.Curve[P], h func() H, sigType ecdsaSigType, q []byte, sk []byte, digest []byte) (*ecdsa.Signature, error) {
   994  	priv, err := ecdsa.NewPrivateKey(c, sk, q)
   995  	if err != nil {
   996  		return nil, fmt.Errorf("invalid private key: %w", err)
   997  	}
   998  
   999  	var sig *ecdsa.Signature
  1000  	switch sigType {
  1001  	case ecdsaSigTypeNormal:
  1002  		sig, err = ecdsa.Sign(c, h, priv, rand.Reader, digest)
  1003  	case ecdsaSigTypeDeterministic:
  1004  		sig, err = ecdsa.SignDeterministic(c, h, priv, digest)
  1005  	default:
  1006  		return nil, fmt.Errorf("unsupported signature type: %v", sigType)
  1007  	}
  1008  	if err != nil {
  1009  		return nil, fmt.Errorf("signing failed: %w", err)
  1010  	}
  1011  
  1012  	return sig, nil
  1013  }
  1014  
  1015  func cmdEcdsaSigGenAft(sigType ecdsaSigType) command {
  1016  	return command{
  1017  		requiredArgs: 4, // Curve name, private key, hash name, message
  1018  		handler: func(args [][]byte) ([][]byte, error) {
  1019  			curve, err := lookupCurve(string(args[0]))
  1020  			if err != nil {
  1021  				return nil, err
  1022  			}
  1023  
  1024  			sk := args[1]
  1025  
  1026  			newH, err := lookupHash(string(args[2]))
  1027  			if err != nil {
  1028  				return nil, err
  1029  			}
  1030  
  1031  			msg := args[3]
  1032  			hashFunc := newH()
  1033  			hashFunc.Write(msg)
  1034  			digest := hashFunc.Sum(nil)
  1035  
  1036  			d := new(big.Int).SetBytes(sk)
  1037  			x, y := curve.ScalarBaseMult(d.Bytes())
  1038  			q, err := pointFromAffine(curve, x, y)
  1039  			if err != nil {
  1040  				return nil, err
  1041  			}
  1042  
  1043  			var sig *ecdsa.Signature
  1044  			switch curve.Params() {
  1045  			case elliptic.P224().Params():
  1046  				sig, err = signEcdsa(ecdsa.P224(), newH, sigType, q, sk, digest)
  1047  			case elliptic.P256().Params():
  1048  				sig, err = signEcdsa(ecdsa.P256(), newH, sigType, q, sk, digest)
  1049  			case elliptic.P384().Params():
  1050  				sig, err = signEcdsa(ecdsa.P384(), newH, sigType, q, sk, digest)
  1051  			case elliptic.P521().Params():
  1052  				sig, err = signEcdsa(ecdsa.P521(), newH, sigType, q, sk, digest)
  1053  			default:
  1054  				return nil, fmt.Errorf("unsupported curve: %v", curve)
  1055  			}
  1056  			if err != nil {
  1057  				return nil, err
  1058  			}
  1059  
  1060  			return [][]byte{sig.R, sig.S}, nil
  1061  		},
  1062  	}
  1063  }
  1064  
  1065  func cmdEcdsaSigVerAft() command {
  1066  	return command{
  1067  		requiredArgs: 7, // Curve name, hash name, message, X, Y, R, S
  1068  		handler: func(args [][]byte) ([][]byte, error) {
  1069  			curve, err := lookupCurve(string(args[0]))
  1070  			if err != nil {
  1071  				return nil, err
  1072  			}
  1073  
  1074  			newH, err := lookupHash(string(args[1]))
  1075  			if err != nil {
  1076  				return nil, err
  1077  			}
  1078  
  1079  			msg := args[2]
  1080  			hashFunc := newH()
  1081  			hashFunc.Write(msg)
  1082  			digest := hashFunc.Sum(nil)
  1083  
  1084  			x, y := args[3], args[4]
  1085  			q, err := pointFromAffine(curve, new(big.Int).SetBytes(x), new(big.Int).SetBytes(y))
  1086  			if err != nil {
  1087  				return nil, fmt.Errorf("invalid x/y coordinates: %v", err)
  1088  			}
  1089  
  1090  			signature := &ecdsa.Signature{R: args[5], S: args[6]}
  1091  
  1092  			switch curve.Params() {
  1093  			case elliptic.P224().Params():
  1094  				err = verifyEcdsa(ecdsa.P224(), q, digest, signature)
  1095  			case elliptic.P256().Params():
  1096  				err = verifyEcdsa(ecdsa.P256(), q, digest, signature)
  1097  			case elliptic.P384().Params():
  1098  				err = verifyEcdsa(ecdsa.P384(), q, digest, signature)
  1099  			case elliptic.P521().Params():
  1100  				err = verifyEcdsa(ecdsa.P521(), q, digest, signature)
  1101  			default:
  1102  				return nil, fmt.Errorf("unsupported curve: %v", curve)
  1103  			}
  1104  
  1105  			if err == nil {
  1106  				return [][]byte{{1}}, nil
  1107  			}
  1108  
  1109  			return [][]byte{{0}}, nil
  1110  		},
  1111  	}
  1112  }
  1113  
  1114  func verifyEcdsa[P ecdsa.Point[P]](c *ecdsa.Curve[P], q []byte, digest []byte, sig *ecdsa.Signature) error {
  1115  	pub, err := ecdsa.NewPublicKey(c, q)
  1116  	if err != nil {
  1117  		return fmt.Errorf("invalid public key: %w", err)
  1118  	}
  1119  
  1120  	return ecdsa.Verify(c, pub, digest, sig)
  1121  }
  1122  
  1123  func lookupHash(name string) (func() fips140.Hash, error) {
  1124  	var h func() fips140.Hash
  1125  
  1126  	switch name {
  1127  	case "SHA2-224":
  1128  		h = func() fips140.Hash { return sha256.New224() }
  1129  	case "SHA2-256":
  1130  		h = func() fips140.Hash { return sha256.New() }
  1131  	case "SHA2-384":
  1132  		h = func() fips140.Hash { return sha512.New384() }
  1133  	case "SHA2-512":
  1134  		h = func() fips140.Hash { return sha512.New() }
  1135  	case "SHA2-512/224":
  1136  		h = func() fips140.Hash { return sha512.New512_224() }
  1137  	case "SHA2-512/256":
  1138  		h = func() fips140.Hash { return sha512.New512_256() }
  1139  	case "SHA3-224":
  1140  		h = func() fips140.Hash { return sha3.New224() }
  1141  	case "SHA3-256":
  1142  		h = func() fips140.Hash { return sha3.New256() }
  1143  	case "SHA3-384":
  1144  		h = func() fips140.Hash { return sha3.New384() }
  1145  	case "SHA3-512":
  1146  		h = func() fips140.Hash { return sha3.New512() }
  1147  	default:
  1148  		return nil, fmt.Errorf("unknown hash name: %q", name)
  1149  	}
  1150  
  1151  	return h, nil
  1152  }
  1153  
  1154  func cmdMlKem768KeyGenAft() command {
  1155  	return command{
  1156  		requiredArgs: 1, // Seed
  1157  		handler: func(args [][]byte) ([][]byte, error) {
  1158  			seed := args[0]
  1159  
  1160  			dk, err := mlkem.NewDecapsulationKey768(seed)
  1161  			if err != nil {
  1162  				return nil, fmt.Errorf("generating ML-KEM 768 decapsulation key: %w", err)
  1163  			}
  1164  
  1165  			// Important: we must return the full encoding of dk, not the seed.
  1166  			return [][]byte{dk.EncapsulationKey().Bytes(), mlkem.TestingOnlyExpandedBytes768(dk)}, nil
  1167  		},
  1168  	}
  1169  }
  1170  
  1171  func cmdMlKem768EncapAft() command {
  1172  	return command{
  1173  		requiredArgs: 2, // Public key, entropy
  1174  		handler: func(args [][]byte) ([][]byte, error) {
  1175  			pk := args[0]
  1176  			entropy := args[1]
  1177  
  1178  			ek, err := mlkem.NewEncapsulationKey768(pk)
  1179  			if err != nil {
  1180  				return nil, fmt.Errorf("generating ML-KEM 768 encapsulation key: %w", err)
  1181  			}
  1182  
  1183  			if len(entropy) != 32 {
  1184  				return nil, fmt.Errorf("wrong entropy length: got %d, want 32", len(entropy))
  1185  			}
  1186  
  1187  			sharedKey, ct := ek.EncapsulateInternal((*[32]byte)(entropy[:32]))
  1188  
  1189  			return [][]byte{ct, sharedKey}, nil
  1190  		},
  1191  	}
  1192  }
  1193  
  1194  func cmdMlKem768DecapAft() command {
  1195  	return command{
  1196  		requiredArgs: 2, // Private key, ciphertext
  1197  		handler: func(args [][]byte) ([][]byte, error) {
  1198  			pk := args[0]
  1199  			ct := args[1]
  1200  
  1201  			dk, err := mlkem.TestingOnlyNewDecapsulationKey768(pk)
  1202  			if err != nil {
  1203  				return nil, fmt.Errorf("generating ML-KEM 768 decapsulation key: %w", err)
  1204  			}
  1205  
  1206  			sharedKey, err := dk.Decapsulate(ct)
  1207  			if err != nil {
  1208  				return nil, fmt.Errorf("decapsulating ML-KEM 768 ciphertext: %w", err)
  1209  			}
  1210  
  1211  			return [][]byte{sharedKey}, nil
  1212  		},
  1213  	}
  1214  }
  1215  
  1216  func cmdMlKem1024KeyGenAft() command {
  1217  	return command{
  1218  		requiredArgs: 1, // Seed
  1219  		handler: func(args [][]byte) ([][]byte, error) {
  1220  			seed := args[0]
  1221  
  1222  			dk, err := mlkem.NewDecapsulationKey1024(seed)
  1223  			if err != nil {
  1224  				return nil, fmt.Errorf("generating ML-KEM 1024 decapsulation key: %w", err)
  1225  			}
  1226  
  1227  			// Important: we must return the full encoding of dk, not the seed.
  1228  			return [][]byte{dk.EncapsulationKey().Bytes(), mlkem.TestingOnlyExpandedBytes1024(dk)}, nil
  1229  		},
  1230  	}
  1231  }
  1232  
  1233  func cmdMlKem1024EncapAft() command {
  1234  	return command{
  1235  		requiredArgs: 2, // Public key, entropy
  1236  		handler: func(args [][]byte) ([][]byte, error) {
  1237  			pk := args[0]
  1238  			entropy := args[1]
  1239  
  1240  			ek, err := mlkem.NewEncapsulationKey1024(pk)
  1241  			if err != nil {
  1242  				return nil, fmt.Errorf("generating ML-KEM 1024 encapsulation key: %w", err)
  1243  			}
  1244  
  1245  			if len(entropy) != 32 {
  1246  				return nil, fmt.Errorf("wrong entropy length: got %d, want 32", len(entropy))
  1247  			}
  1248  
  1249  			sharedKey, ct := ek.EncapsulateInternal((*[32]byte)(entropy[:32]))
  1250  
  1251  			return [][]byte{ct, sharedKey}, nil
  1252  		},
  1253  	}
  1254  }
  1255  
  1256  func cmdMlKem1024DecapAft() command {
  1257  	return command{
  1258  		requiredArgs: 2, // Private key, ciphertext
  1259  		handler: func(args [][]byte) ([][]byte, error) {
  1260  			pk := args[0]
  1261  			ct := args[1]
  1262  
  1263  			dk, err := mlkem.TestingOnlyNewDecapsulationKey1024(pk)
  1264  			if err != nil {
  1265  				return nil, fmt.Errorf("generating ML-KEM 1024 decapsulation key: %w", err)
  1266  			}
  1267  
  1268  			sharedKey, err := dk.Decapsulate(ct)
  1269  			if err != nil {
  1270  				return nil, fmt.Errorf("decapsulating ML-KEM 1024 ciphertext: %w", err)
  1271  			}
  1272  
  1273  			return [][]byte{sharedKey}, nil
  1274  		},
  1275  	}
  1276  }
  1277  
  1278  func lookupCurve(name string) (elliptic.Curve, error) {
  1279  	var c elliptic.Curve
  1280  
  1281  	switch name {
  1282  	case "P-224":
  1283  		c = elliptic.P224()
  1284  	case "P-256":
  1285  		c = elliptic.P256()
  1286  	case "P-384":
  1287  		c = elliptic.P384()
  1288  	case "P-521":
  1289  		c = elliptic.P521()
  1290  	default:
  1291  		return nil, fmt.Errorf("unknown curve name: %q", name)
  1292  	}
  1293  
  1294  	return c, nil
  1295  }
  1296  
  1297  func cmdAesCbc(direction aesDirection) command {
  1298  	return command{
  1299  		requiredArgs: 4, // Key, ciphertext or plaintext, IV, num iterations
  1300  		handler: func(args [][]byte) ([][]byte, error) {
  1301  			if direction != aesEncrypt && direction != aesDecrypt {
  1302  				panic("invalid AES direction")
  1303  			}
  1304  
  1305  			key := args[0]
  1306  			input := args[1]
  1307  			iv := args[2]
  1308  			numIterations := binary.LittleEndian.Uint32(args[3])
  1309  
  1310  			blockCipher, err := aes.New(key)
  1311  			if err != nil {
  1312  				return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err)
  1313  			}
  1314  
  1315  			if len(input)%blockCipher.BlockSize() != 0 || len(input) == 0 {
  1316  				return nil, fmt.Errorf("invalid ciphertext/plaintext size %d: not a multiple of block size %d",
  1317  					len(input), blockCipher.BlockSize())
  1318  			}
  1319  
  1320  			if blockCipher.BlockSize() != len(iv) {
  1321  				return nil, fmt.Errorf("invalid IV size: expected %d, got %d", blockCipher.BlockSize(), len(iv))
  1322  			}
  1323  
  1324  			result := make([]byte, len(input))
  1325  			prevResult := make([]byte, len(input))
  1326  			prevInput := make([]byte, len(input))
  1327  
  1328  			for i := uint32(0); i < numIterations; i++ {
  1329  				copy(prevResult, result)
  1330  
  1331  				if i > 0 {
  1332  					if direction == aesEncrypt {
  1333  						copy(iv, result)
  1334  					} else {
  1335  						copy(iv, prevInput)
  1336  					}
  1337  				}
  1338  
  1339  				if direction == aesEncrypt {
  1340  					cbcEnc := aes.NewCBCEncrypter(blockCipher, [16]byte(iv))
  1341  					cbcEnc.CryptBlocks(result, input)
  1342  				} else {
  1343  					cbcDec := aes.NewCBCDecrypter(blockCipher, [16]byte(iv))
  1344  					cbcDec.CryptBlocks(result, input)
  1345  				}
  1346  
  1347  				if direction == aesDecrypt {
  1348  					copy(prevInput, input)
  1349  				}
  1350  
  1351  				if i == 0 {
  1352  					copy(input, iv)
  1353  				} else {
  1354  					copy(input, prevResult)
  1355  				}
  1356  			}
  1357  
  1358  			return [][]byte{result, prevResult}, nil
  1359  		},
  1360  	}
  1361  }
  1362  
  1363  func cmdAesCtr(direction aesDirection) command {
  1364  	return command{
  1365  		requiredArgs: 4, // Key, ciphertext or plaintext, initial counter, num iterations (constant 1)
  1366  		handler: func(args [][]byte) ([][]byte, error) {
  1367  			if direction != aesEncrypt && direction != aesDecrypt {
  1368  				panic("invalid AES direction")
  1369  			}
  1370  
  1371  			key := args[0]
  1372  			input := args[1]
  1373  			iv := args[2]
  1374  			numIterations := binary.LittleEndian.Uint32(args[3])
  1375  			if numIterations != 1 {
  1376  				return nil, fmt.Errorf("invalid num iterations: expected 1, got %d", numIterations)
  1377  			}
  1378  
  1379  			if len(iv) != aes.BlockSize {
  1380  				return nil, fmt.Errorf("invalid IV size: expected %d, got %d", aes.BlockSize, len(iv))
  1381  			}
  1382  
  1383  			blockCipher, err := aes.New(key)
  1384  			if err != nil {
  1385  				return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err)
  1386  			}
  1387  
  1388  			result := make([]byte, len(input))
  1389  			stream := aes.NewCTR(blockCipher, iv)
  1390  			stream.XORKeyStream(result, input)
  1391  
  1392  			return [][]byte{result}, nil
  1393  		},
  1394  	}
  1395  }
  1396  
  1397  func cmdAesGcmSeal(randNonce bool) command {
  1398  	return command{
  1399  		requiredArgs: 5, // tag len, key, plaintext, nonce (empty for randNonce), additional data
  1400  		handler: func(args [][]byte) ([][]byte, error) {
  1401  			tagLen := binary.LittleEndian.Uint32(args[0])
  1402  			key := args[1]
  1403  			plaintext := args[2]
  1404  			nonce := args[3]
  1405  			additionalData := args[4]
  1406  
  1407  			blockCipher, err := aes.New(key)
  1408  			if err != nil {
  1409  				return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err)
  1410  			}
  1411  
  1412  			aesGCM, err := gcm.New(blockCipher, 12, int(tagLen))
  1413  			if err != nil {
  1414  				return nil, fmt.Errorf("creating AES-GCM with tag len %d: %w", tagLen, err)
  1415  			}
  1416  
  1417  			var ct []byte
  1418  			if !randNonce {
  1419  				ct = aesGCM.Seal(nil, nonce, plaintext, additionalData)
  1420  			} else {
  1421  				var internalNonce [12]byte
  1422  				ct = make([]byte, len(plaintext)+16)
  1423  				gcm.SealWithRandomNonce(aesGCM, internalNonce[:], ct, plaintext, additionalData)
  1424  				// acvptool expects the internally generated nonce to be appended to the end of the ciphertext.
  1425  				ct = append(ct, internalNonce[:]...)
  1426  			}
  1427  
  1428  			return [][]byte{ct}, nil
  1429  		},
  1430  	}
  1431  }
  1432  
  1433  func cmdAesGcmOpen(randNonce bool) command {
  1434  	return command{
  1435  		requiredArgs: 5, // tag len, key, ciphertext, nonce (empty for randNonce), additional data
  1436  		handler: func(args [][]byte) ([][]byte, error) {
  1437  
  1438  			tagLen := binary.LittleEndian.Uint32(args[0])
  1439  			key := args[1]
  1440  			ciphertext := args[2]
  1441  			nonce := args[3]
  1442  			additionalData := args[4]
  1443  
  1444  			blockCipher, err := aes.New(key)
  1445  			if err != nil {
  1446  				return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err)
  1447  			}
  1448  
  1449  			aesGCM, err := gcm.New(blockCipher, 12, int(tagLen))
  1450  			if err != nil {
  1451  				return nil, fmt.Errorf("creating AES-GCM with tag len %d: %w", tagLen, err)
  1452  			}
  1453  
  1454  			if randNonce {
  1455  				// for randNonce tests acvptool appends the nonce to the end of the ciphertext.
  1456  				nonce = ciphertext[len(ciphertext)-12:]
  1457  				ciphertext = ciphertext[:len(ciphertext)-12]
  1458  			}
  1459  
  1460  			pt, err := aesGCM.Open(nil, nonce, ciphertext, additionalData)
  1461  			if err != nil {
  1462  				return [][]byte{{0}, nil}, nil
  1463  			}
  1464  
  1465  			return [][]byte{{1}, pt}, nil
  1466  		},
  1467  	}
  1468  }
  1469  
  1470  func cmdCmacAesAft() command {
  1471  	return command{
  1472  		requiredArgs: 3, // Number of output bytes, key, message
  1473  		handler: func(args [][]byte) ([][]byte, error) {
  1474  			// safe to truncate to int based on our capabilities describing a max MAC output len of 128 bits.
  1475  			outputLen := int(binary.LittleEndian.Uint32(args[0]))
  1476  			key := args[1]
  1477  			message := args[2]
  1478  
  1479  			blockCipher, err := aes.New(key)
  1480  			if err != nil {
  1481  				return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err)
  1482  			}
  1483  
  1484  			cmac := gcm.NewCMAC(blockCipher)
  1485  			tag := cmac.MAC(message)
  1486  
  1487  			if outputLen > len(tag) {
  1488  				return nil, fmt.Errorf("invalid output length: expected %d, got %d", outputLen, len(tag))
  1489  			}
  1490  
  1491  			return [][]byte{tag[:outputLen]}, nil
  1492  		},
  1493  	}
  1494  }
  1495  
  1496  func cmdCmacAesVerifyAft() command {
  1497  	return command{
  1498  		requiredArgs: 3, // Key, message, claimed MAC
  1499  		handler: func(args [][]byte) ([][]byte, error) {
  1500  			key := args[0]
  1501  			message := args[1]
  1502  			claimedMAC := args[2]
  1503  
  1504  			blockCipher, err := aes.New(key)
  1505  			if err != nil {
  1506  				return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err)
  1507  			}
  1508  
  1509  			cmac := gcm.NewCMAC(blockCipher)
  1510  			tag := cmac.MAC(message)
  1511  
  1512  			if subtle.ConstantTimeCompare(tag[:len(claimedMAC)], claimedMAC) != 1 {
  1513  				return [][]byte{{0}}, nil
  1514  			}
  1515  
  1516  			return [][]byte{{1}}, nil
  1517  		},
  1518  	}
  1519  }
  1520  
  1521  func cmdTlsKdf12Aft(h func() fips140.Hash) command {
  1522  	return command{
  1523  		requiredArgs: 5, // Number output bytes, secret, label, seed1, seed2
  1524  		handler: func(args [][]byte) ([][]byte, error) {
  1525  			outputLen := binary.LittleEndian.Uint32(args[0])
  1526  			secret := args[1]
  1527  			label := string(args[2])
  1528  			seed1 := args[3]
  1529  			seed2 := args[4]
  1530  
  1531  			return [][]byte{tls12.PRF(h, secret, label, append(seed1, seed2...), int(outputLen))}, nil
  1532  		},
  1533  	}
  1534  }
  1535  
  1536  func cmdSshKdfAft(hFunc func() fips140.Hash, direction ssh.Direction) command {
  1537  	return command{
  1538  		requiredArgs: 4, // K, H, SessionID, cipher
  1539  		handler: func(args [][]byte) ([][]byte, error) {
  1540  			k := args[0]
  1541  			h := args[1]
  1542  			sessionID := args[2]
  1543  			cipher := string(args[3])
  1544  
  1545  			var keyLen int
  1546  			switch cipher {
  1547  			case "AES-128":
  1548  				keyLen = 16
  1549  			case "AES-192":
  1550  				keyLen = 24
  1551  			case "AES-256":
  1552  				keyLen = 32
  1553  			default:
  1554  				return nil, fmt.Errorf("unsupported cipher: %q", cipher)
  1555  			}
  1556  
  1557  			ivKey, encKey, intKey := ssh.Keys(hFunc, direction, k, h, sessionID, 16, keyLen, hFunc().Size())
  1558  			return [][]byte{ivKey, encKey, intKey}, nil
  1559  		},
  1560  	}
  1561  }
  1562  
  1563  func cmdEcdhAftVal[P ecdh.Point[P]](curve *ecdh.Curve[P]) command {
  1564  	return command{
  1565  		requiredArgs: 3, // X, Y, private key (empty for Val type tests)
  1566  		handler: func(args [][]byte) ([][]byte, error) {
  1567  			peerX := args[0]
  1568  			peerY := args[1]
  1569  			rawSk := args[2]
  1570  
  1571  			uncompressedPk := append([]byte{4}, append(peerX, peerY...)...) // 4 for uncompressed point format
  1572  			pk, err := ecdh.NewPublicKey(curve, uncompressedPk)
  1573  			if err != nil {
  1574  				return nil, fmt.Errorf("invalid peer public key x,y: %v", err)
  1575  			}
  1576  
  1577  			var sk *ecdh.PrivateKey
  1578  			if len(rawSk) > 0 {
  1579  				sk, err = ecdh.NewPrivateKey(curve, rawSk)
  1580  			} else {
  1581  				sk, err = ecdh.GenerateKey(curve, rand.Reader)
  1582  			}
  1583  			if err != nil {
  1584  				return nil, fmt.Errorf("private key error: %v", err)
  1585  			}
  1586  
  1587  			pubBytes := sk.PublicKey().Bytes()
  1588  			coordLen := (len(pubBytes) - 1) / 2
  1589  			x := pubBytes[1 : 1+coordLen]
  1590  			y := pubBytes[1+coordLen:]
  1591  
  1592  			secret, err := ecdh.ECDH(curve, sk, pk)
  1593  			if err != nil {
  1594  				return nil, fmt.Errorf("key agreement failed: %v", err)
  1595  			}
  1596  
  1597  			return [][]byte{x, y, secret}, nil
  1598  		},
  1599  	}
  1600  }
  1601  
  1602  func cmdHmacDrbgAft(h func() fips140.Hash) command {
  1603  	return command{
  1604  		requiredArgs: 6, // Output length, entropy, personalization, ad1, ad2, nonce
  1605  		handler: func(args [][]byte) ([][]byte, error) {
  1606  			outLen := binary.LittleEndian.Uint32(args[0])
  1607  			entropy := args[1]
  1608  			personalization := args[2]
  1609  			ad1 := args[3]
  1610  			ad2 := args[4]
  1611  			nonce := args[5]
  1612  
  1613  			// Our capabilities describe no additional data support.
  1614  			if len(ad1) != 0 || len(ad2) != 0 {
  1615  				return nil, errors.New("additional data not supported")
  1616  			}
  1617  
  1618  			// Our capabilities describe no prediction resistance (requires reseed) and no reseed.
  1619  			// So the test procedure is:
  1620  			//   * Instantiate DRBG
  1621  			//   * Generate but don't output
  1622  			//   * Generate output
  1623  			//   * Uninstantiate
  1624  			// See Table 7 in draft-vassilev-acvp-drbg
  1625  			out := make([]byte, outLen)
  1626  			drbg := ecdsa.TestingOnlyNewDRBG(h, entropy, nonce, personalization)
  1627  			drbg.Generate(out)
  1628  			drbg.Generate(out)
  1629  
  1630  			return [][]byte{out}, nil
  1631  		},
  1632  	}
  1633  }
  1634  
  1635  func cmdCtrDrbgAft() command {
  1636  	return command{
  1637  		requiredArgs: 6, // Output length, entropy, personalization, ad1, ad2, nonce
  1638  		handler: func(args [][]byte) ([][]byte, error) {
  1639  			return acvpCtrDrbg{
  1640  				outLen:          binary.LittleEndian.Uint32(args[0]),
  1641  				entropy:         args[1],
  1642  				personalization: args[2],
  1643  				ad1:             args[3],
  1644  				ad2:             args[4],
  1645  				nonce:           args[5],
  1646  			}.process()
  1647  		},
  1648  	}
  1649  }
  1650  
  1651  func cmdCtrDrbgReseedAft() command {
  1652  	return command{
  1653  		requiredArgs: 8, // Output length, entropy, personalization, reseedAD, reseedEntropy, ad1, ad2, nonce
  1654  		handler: func(args [][]byte) ([][]byte, error) {
  1655  			return acvpCtrDrbg{
  1656  				outLen:          binary.LittleEndian.Uint32(args[0]),
  1657  				entropy:         args[1],
  1658  				personalization: args[2],
  1659  				reseedAd:        args[3],
  1660  				reseedEntropy:   args[4],
  1661  				ad1:             args[5],
  1662  				ad2:             args[6],
  1663  				nonce:           args[7],
  1664  			}.process()
  1665  		},
  1666  	}
  1667  }
  1668  
  1669  type acvpCtrDrbg struct {
  1670  	outLen          uint32
  1671  	entropy         []byte
  1672  	personalization []byte
  1673  	ad1             []byte
  1674  	ad2             []byte
  1675  	nonce           []byte
  1676  	reseedAd        []byte // May be empty for no reseed
  1677  	reseedEntropy   []byte // May be empty for no reseed
  1678  }
  1679  
  1680  func (args acvpCtrDrbg) process() ([][]byte, error) {
  1681  	// Our capability describes no personalization support.
  1682  	if len(args.personalization) > 0 {
  1683  		return nil, errors.New("personalization string not supported")
  1684  	}
  1685  
  1686  	// Our capability describes no derivation function support, so the nonce
  1687  	// should be empty.
  1688  	if len(args.nonce) > 0 {
  1689  		return nil, errors.New("unexpected nonce value")
  1690  	}
  1691  
  1692  	// Our capability describes entropy input len of 384 bits.
  1693  	entropy, err := require48Bytes(args.entropy)
  1694  	if err != nil {
  1695  		return nil, fmt.Errorf("entropy: %w", err)
  1696  	}
  1697  
  1698  	// Our capability describes additional input len of 384 bits.
  1699  	ad1, err := require48Bytes(args.ad1)
  1700  	if err != nil {
  1701  		return nil, fmt.Errorf("AD1: %w", err)
  1702  	}
  1703  	ad2, err := require48Bytes(args.ad2)
  1704  	if err != nil {
  1705  		return nil, fmt.Errorf("AD2: %w", err)
  1706  	}
  1707  
  1708  	withReseed := len(args.reseedAd) > 0
  1709  	var reseedAd, reseedEntropy *[48]byte
  1710  	if withReseed {
  1711  		// Ditto RE: entropy and additional data lengths for reseeding.
  1712  		if reseedAd, err = require48Bytes(args.reseedAd); err != nil {
  1713  			return nil, fmt.Errorf("reseed AD: %w", err)
  1714  		}
  1715  		if reseedEntropy, err = require48Bytes(args.reseedEntropy); err != nil {
  1716  			return nil, fmt.Errorf("reseed entropy: %w", err)
  1717  		}
  1718  	}
  1719  
  1720  	// Our capabilities describe no prediction resistance and allow both
  1721  	// reseed and no reseed, so the test procedure is:
  1722  	//   * Instantiate DRBG
  1723  	//   * Reseed (if enabled)
  1724  	//   * Generate but don't output
  1725  	//   * Generate output
  1726  	//   * Uninstantiate
  1727  	// See Table 7 in draft-vassilev-acvp-drbg
  1728  	out := make([]byte, args.outLen)
  1729  	ctrDrbg := drbg.NewCounter(entropy)
  1730  	if withReseed {
  1731  		ctrDrbg.Reseed(reseedEntropy, reseedAd)
  1732  	}
  1733  	ctrDrbg.Generate(out, ad1)
  1734  	ctrDrbg.Generate(out, ad2)
  1735  
  1736  	return [][]byte{out}, nil
  1737  }
  1738  
  1739  // Verify input is 48 byte slice, and cast it to a pointer to a fixed-size array
  1740  // of 48 bytes, or return an error.
  1741  func require48Bytes(input []byte) (*[48]byte, error) {
  1742  	if inputLen := len(input); inputLen != 48 {
  1743  		return nil, fmt.Errorf("invalid length: %d", inputLen)
  1744  	}
  1745  	return (*[48]byte)(input), nil
  1746  }
  1747  
  1748  func cmdKdfCounterAft() command {
  1749  	return command{
  1750  		requiredArgs: 5, // Number output bytes, PRF name, counter location string, key, number of counter bits
  1751  		handler: func(args [][]byte) ([][]byte, error) {
  1752  			outputBytes := binary.LittleEndian.Uint32(args[0])
  1753  			prf := args[1]
  1754  			counterLocation := args[2]
  1755  			key := args[3]
  1756  			counterBits := binary.LittleEndian.Uint32(args[4])
  1757  
  1758  			if outputBytes != 32 {
  1759  				return nil, fmt.Errorf("KDF received unsupported output length %d bytes", outputBytes)
  1760  			}
  1761  			if !bytes.Equal(prf, []byte("CMAC-AES128")) && !bytes.Equal(prf, []byte("CMAC-AES192")) && !bytes.Equal(prf, []byte("CMAC-AES256")) {
  1762  				return nil, fmt.Errorf("KDF received unsupported PRF %q", string(prf))
  1763  			}
  1764  			if !bytes.Equal(counterLocation, []byte("before fixed data")) {
  1765  				return nil, fmt.Errorf("KDF received unsupported counter location %q", string(counterLocation))
  1766  			}
  1767  			// The spec doesn't describe the "deferred" property for a KDF counterMode test case.
  1768  			// BoringSSL's acvptool sends an empty key when deferred=true, but with the capabilities
  1769  			// we register all test cases ahve deferred=false and provide a key from the populated
  1770  			// keyIn property.
  1771  			if len(key) == 0 {
  1772  				return nil, errors.New("deferred test cases are not supported")
  1773  			}
  1774  			if counterBits != 16 {
  1775  				return nil, fmt.Errorf("KDF received unsupported counter length %d", counterBits)
  1776  			}
  1777  
  1778  			block, err := aes.New(key)
  1779  			if err != nil {
  1780  				return nil, fmt.Errorf("failed to create cipher: %v", err)
  1781  			}
  1782  			kdf := gcm.NewCounterKDF(block)
  1783  
  1784  			var label byte
  1785  			var context [12]byte
  1786  			rand.Reader.Read(context[:])
  1787  
  1788  			result := kdf.DeriveKey(label, context)
  1789  
  1790  			fixedData := make([]byte, 1+1+12) // 1 byte label, 1 null byte, 12 bytes context.
  1791  			fixedData[0] = label
  1792  			copy(fixedData[2:], context[:])
  1793  
  1794  			return [][]byte{key, fixedData, result[:]}, nil
  1795  		},
  1796  	}
  1797  }
  1798  
  1799  func cmdKdfFeedbackAft() command {
  1800  	return command{
  1801  		requiredArgs: 5, // Number output bytes, PRF name, counter location string, key, number of counter bits, IV
  1802  		handler: func(args [][]byte) ([][]byte, error) {
  1803  			// The max supported output len for the KDF algorithm type is 4096 bits, making an int cast
  1804  			// here safe.
  1805  			// See https://pages.nist.gov/ACVP/draft-celi-acvp-kbkdf.html#section-7.3.2
  1806  			outputBytes := int(binary.LittleEndian.Uint32(args[0]))
  1807  			prf := string(args[1])
  1808  			counterLocation := args[2]
  1809  			key := args[3]
  1810  			counterBits := binary.LittleEndian.Uint32(args[4])
  1811  
  1812  			if !strings.HasPrefix(prf, "HMAC-") {
  1813  				return nil, fmt.Errorf("feedback KDF received unsupported PRF %q", prf)
  1814  			}
  1815  			prf = prf[len("HMAC-"):]
  1816  
  1817  			h, err := lookupHash(prf)
  1818  			if err != nil {
  1819  				return nil, fmt.Errorf("feedback KDF received unsupported PRF %q: %w", prf, err)
  1820  			}
  1821  
  1822  			if !bytes.Equal(counterLocation, []byte("after fixed data")) {
  1823  				return nil, fmt.Errorf("feedback KDF received unsupported counter location %q", string(counterLocation))
  1824  			}
  1825  
  1826  			// The spec doesn't describe the "deferred" property for a KDF counterMode test case.
  1827  			// BoringSSL's acvptool sends an empty key when deferred=true, but with the capabilities
  1828  			// we register all test cases have deferred=false and provide a key from the populated
  1829  			// keyIn property.
  1830  			if len(key) == 0 {
  1831  				return nil, errors.New("deferred test cases are not supported")
  1832  			}
  1833  
  1834  			if counterBits != 8 {
  1835  				return nil, fmt.Errorf("feedback KDF received unsupported counter length %d", counterBits)
  1836  			}
  1837  
  1838  			var context [12]byte
  1839  			rand.Reader.Read(context[:])
  1840  			fixedData := make([]byte, 1+1+12) // 1 byte label (we pick null), 1 null byte, 12 bytes context.
  1841  			copy(fixedData[2:], context[:])
  1842  
  1843  			result := hkdf.Expand(h, key, string(fixedData[:]), outputBytes)
  1844  
  1845  			return [][]byte{key, fixedData[:], result[:]}, nil
  1846  		},
  1847  	}
  1848  }
  1849  
  1850  func cmdRsaKeyGenAft() command {
  1851  	return command{
  1852  		requiredArgs: 1, // Modulus bit-size
  1853  		handler: func(args [][]byte) ([][]byte, error) {
  1854  			bitSize := binary.LittleEndian.Uint32(args[0])
  1855  
  1856  			key, err := getRSAKey((int)(bitSize))
  1857  			if err != nil {
  1858  				return nil, fmt.Errorf("generating RSA key: %w", err)
  1859  			}
  1860  
  1861  			N, e, d, P, Q, _, _, _ := key.Export()
  1862  
  1863  			eBytes := make([]byte, 4)
  1864  			binary.BigEndian.PutUint32(eBytes, uint32(e))
  1865  
  1866  			return [][]byte{eBytes, P, Q, N, d}, nil
  1867  		},
  1868  	}
  1869  }
  1870  
  1871  func cmdRsaSigGenAft(hashFunc func() fips140.Hash, hashName string, pss bool) command {
  1872  	return command{
  1873  		requiredArgs: 2, // Modulus bit-size, message
  1874  		handler: func(args [][]byte) ([][]byte, error) {
  1875  			bitSize := binary.LittleEndian.Uint32(args[0])
  1876  			msg := args[1]
  1877  
  1878  			key, err := getRSAKey((int)(bitSize))
  1879  			if err != nil {
  1880  				return nil, fmt.Errorf("generating RSA key: %w", err)
  1881  			}
  1882  
  1883  			h := hashFunc()
  1884  			h.Write(msg)
  1885  			digest := h.Sum(nil)
  1886  
  1887  			var sig []byte
  1888  			if !pss {
  1889  				sig, err = rsa.SignPKCS1v15(key, hashName, digest)
  1890  				if err != nil {
  1891  					return nil, fmt.Errorf("signing RSA message: %w", err)
  1892  				}
  1893  			} else {
  1894  				sig, err = rsa.SignPSS(rand.Reader, key, hashFunc(), digest, h.Size())
  1895  				if err != nil {
  1896  					return nil, fmt.Errorf("signing RSA message: %w", err)
  1897  				}
  1898  			}
  1899  
  1900  			N, e, _, _, _, _, _, _ := key.Export()
  1901  			eBytes := make([]byte, 4)
  1902  			binary.BigEndian.PutUint32(eBytes, uint32(e))
  1903  
  1904  			return [][]byte{N, eBytes, sig}, nil
  1905  		},
  1906  	}
  1907  }
  1908  
  1909  func cmdRsaSigVerAft(hashFunc func() fips140.Hash, hashName string, pss bool) command {
  1910  	return command{
  1911  		requiredArgs: 4, // n, e, message, signature
  1912  		handler: func(args [][]byte) ([][]byte, error) {
  1913  			nBytes := args[0]
  1914  			eBytes := args[1]
  1915  			msg := args[2]
  1916  			sig := args[3]
  1917  
  1918  			paddedE := make([]byte, 4)
  1919  			copy(paddedE[4-len(eBytes):], eBytes)
  1920  			e := int(binary.BigEndian.Uint32(paddedE))
  1921  
  1922  			n, err := bigmod.NewModulus(nBytes)
  1923  			if err != nil {
  1924  				return nil, fmt.Errorf("invalid RSA modulus: %w", err)
  1925  			}
  1926  
  1927  			pub := &rsa.PublicKey{
  1928  				N: n,
  1929  				E: e,
  1930  			}
  1931  
  1932  			h := hashFunc()
  1933  			h.Write(msg)
  1934  			digest := h.Sum(nil)
  1935  
  1936  			if !pss {
  1937  				err = rsa.VerifyPKCS1v15(pub, hashName, digest, sig)
  1938  			} else {
  1939  				err = rsa.VerifyPSS(pub, hashFunc(), digest, sig)
  1940  			}
  1941  			if err != nil {
  1942  				return [][]byte{{0}}, nil
  1943  			}
  1944  
  1945  			return [][]byte{{1}}, nil
  1946  		},
  1947  	}
  1948  }
  1949  
  1950  // rsaKeyCache caches generated keys by modulus bit-size.
  1951  var rsaKeyCache = map[int]*rsa.PrivateKey{}
  1952  
  1953  // getRSAKey returns a cached RSA private key with the specified modulus bit-size
  1954  // or generates one if necessary.
  1955  func getRSAKey(bits int) (*rsa.PrivateKey, error) {
  1956  	if key, exists := rsaKeyCache[bits]; exists {
  1957  		return key, nil
  1958  	}
  1959  
  1960  	key, err := rsa.GenerateKey(rand.Reader, bits)
  1961  	if err != nil {
  1962  		return nil, err
  1963  	}
  1964  
  1965  	rsaKeyCache[bits] = key
  1966  	return key, nil
  1967  }
  1968  
  1969  func cmdOneStepNoCounterHmacAft(h func() fips140.Hash) command {
  1970  	return command{
  1971  		requiredArgs: 4, // key, info, salt, outBytes
  1972  		handler: func(args [][]byte) ([][]byte, error) {
  1973  			key := args[0]
  1974  			info := args[1]
  1975  			salt := args[2]
  1976  			outBytes := binary.LittleEndian.Uint32(args[3])
  1977  
  1978  			mac := hmac.New(h, salt)
  1979  			mac.Size()
  1980  
  1981  			if outBytes != uint32(mac.Size()) {
  1982  				return nil, fmt.Errorf("invalid output length: got %d, want %d", outBytes, mac.Size())
  1983  			}
  1984  
  1985  			data := make([]byte, 0, len(key)+len(info))
  1986  			data = append(data, key...)
  1987  			data = append(data, info...)
  1988  
  1989  			mac.Write(data)
  1990  			out := mac.Sum(nil)
  1991  
  1992  			return [][]byte{out}, nil
  1993  		},
  1994  	}
  1995  }
  1996  
  1997  func cmdKtsIfcInitiatorAft(h func() fips140.Hash) command {
  1998  	return command{
  1999  		requiredArgs: 3, // output bytes, n bytes, e bytes
  2000  		handler: func(args [][]byte) ([][]byte, error) {
  2001  			outputBytes := binary.LittleEndian.Uint32(args[0])
  2002  			nBytes := args[1]
  2003  			eBytes := args[2]
  2004  
  2005  			n, err := bigmod.NewModulus(nBytes)
  2006  			if err != nil {
  2007  				return nil, fmt.Errorf("invalid RSA modulus: %w", err)
  2008  			}
  2009  
  2010  			paddedE := make([]byte, 4)
  2011  			copy(paddedE[4-len(eBytes):], eBytes)
  2012  			e := int(binary.BigEndian.Uint32(paddedE))
  2013  			if e != 0x10001 {
  2014  				return nil, errors.New("e must be 0x10001")
  2015  			}
  2016  
  2017  			pub := &rsa.PublicKey{
  2018  				N: n,
  2019  				E: e,
  2020  			}
  2021  
  2022  			dkm := make([]byte, outputBytes)
  2023  			if _, err := rand.Read(dkm); err != nil {
  2024  				return nil, fmt.Errorf("failed to generate random DKM: %v", err)
  2025  			}
  2026  
  2027  			iutC, err := rsa.EncryptOAEP(h(), h(), rand.Reader, pub, dkm, nil)
  2028  			if err != nil {
  2029  				return nil, fmt.Errorf("OAEP encryption failed: %v", err)
  2030  			}
  2031  
  2032  			return [][]byte{iutC, dkm}, nil
  2033  		},
  2034  	}
  2035  }
  2036  
  2037  func cmdKtsIfcResponderAft(h func() fips140.Hash) command {
  2038  	return command{
  2039  		requiredArgs: 6, // n bytes, e bytes, p bytes, q bytes, d bytes, c bytes
  2040  		handler: func(args [][]byte) ([][]byte, error) {
  2041  			nBytes := args[0]
  2042  			eBytes := args[1]
  2043  
  2044  			pBytes := args[2]
  2045  			qBytes := args[3]
  2046  			dBytes := args[4]
  2047  
  2048  			cBytes := args[5]
  2049  
  2050  			paddedE := make([]byte, 4)
  2051  			copy(paddedE[4-len(eBytes):], eBytes)
  2052  			e := int(binary.BigEndian.Uint32(paddedE))
  2053  			if e != 0x10001 {
  2054  				return nil, errors.New("e must be 0x10001")
  2055  			}
  2056  
  2057  			priv, err := rsa.NewPrivateKey(nBytes, int(e), dBytes, pBytes, qBytes)
  2058  			if err != nil {
  2059  				return nil, fmt.Errorf("failed to create private key: %v", err)
  2060  			}
  2061  
  2062  			dkm, err := rsa.DecryptOAEP(h(), h(), priv, cBytes, nil)
  2063  			if err != nil {
  2064  				return nil, fmt.Errorf("OAEP decryption failed: %v", err)
  2065  			}
  2066  
  2067  			return [][]byte{dkm}, nil
  2068  		},
  2069  	}
  2070  }
  2071  
  2072  func TestACVP(t *testing.T) {
  2073  	testenv.SkipIfShortAndSlow(t)
  2074  
  2075  	const (
  2076  		bsslModule    = "boringssl.googlesource.com/boringssl.git"
  2077  		bsslVersion   = "v0.0.0-20250207174145-0bb19f6126cb"
  2078  		goAcvpModule  = "github.com/cpu/go-acvp"
  2079  		goAcvpVersion = "v0.0.0-20250126154732-de1ba727a0be"
  2080  	)
  2081  
  2082  	// In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows"
  2083  	// due to flaky networking. It may be necessary to do the same here.
  2084  
  2085  	// Stat the acvp test config file so the test will be re-run if it changes, invalidating cached results
  2086  	// from the old config.
  2087  	if _, err := os.Stat("acvp_test.config.json"); err != nil {
  2088  		t.Fatalf("failed to stat config file: %s", err)
  2089  	}
  2090  
  2091  	// Fetch the BSSL module and use the JSON output to find the absolute path to the dir.
  2092  	bsslDir := cryptotest.FetchModule(t, bsslModule, bsslVersion)
  2093  
  2094  	t.Log("building acvptool")
  2095  
  2096  	// Build the acvptool binary.
  2097  	toolPath := filepath.Join(t.TempDir(), "acvptool.exe")
  2098  	goTool := testenv.GoToolPath(t)
  2099  	cmd := testenv.Command(t, goTool,
  2100  		"build",
  2101  		"-o", toolPath,
  2102  		"./util/fipstools/acvp/acvptool")
  2103  	cmd.Dir = bsslDir
  2104  	out := &strings.Builder{}
  2105  	cmd.Stderr = out
  2106  	if err := cmd.Run(); err != nil {
  2107  		t.Fatalf("failed to build acvptool: %s\n%s", err, out.String())
  2108  	}
  2109  
  2110  	// Similarly, fetch the ACVP data module that has vectors/expected answers.
  2111  	dataDir := cryptotest.FetchModule(t, goAcvpModule, goAcvpVersion)
  2112  
  2113  	cwd, err := os.Getwd()
  2114  	if err != nil {
  2115  		t.Fatalf("failed to fetch cwd: %s", err)
  2116  	}
  2117  	configPath := filepath.Join(cwd, "acvp_test.config.json")
  2118  	t.Logf("running check_expected.go\ncwd: %q\ndata_dir: %q\nconfig: %q\ntool: %q\nmodule-wrapper: %q\n",
  2119  		cwd, dataDir, configPath, toolPath, os.Args[0])
  2120  
  2121  	// Run the check_expected test driver using the acvptool we built, and this test binary as the
  2122  	// module wrapper. The file paths in the config file are specified relative to the dataDir root
  2123  	// so we run the command from that dir.
  2124  	args := []string{
  2125  		"run",
  2126  		filepath.Join(bsslDir, "util/fipstools/acvp/acvptool/test/check_expected.go"),
  2127  		"-tool",
  2128  		toolPath,
  2129  		// Note: module prefix must match Wrapper value in acvp_test.config.json.
  2130  		"-module-wrappers", "go:" + os.Args[0],
  2131  		"-tests", configPath,
  2132  	}
  2133  	cmd = testenv.Command(t, goTool, args...)
  2134  	cmd.Dir = dataDir
  2135  	cmd.Env = append(os.Environ(),
  2136  		"ACVP_WRAPPER=1",
  2137  		"GODEBUG=fips140=on",
  2138  	)
  2139  	output, err := cmd.CombinedOutput()
  2140  	if err != nil {
  2141  		t.Fatalf("failed to run acvp tests: %s\n%s", err, string(output))
  2142  	}
  2143  	t.Log(string(output))
  2144  }
  2145  
  2146  func TestTooFewArgs(t *testing.T) {
  2147  	commands["test"] = command{
  2148  		requiredArgs: 1,
  2149  		handler: func(args [][]byte) ([][]byte, error) {
  2150  			if gotArgs := len(args); gotArgs != 1 {
  2151  				return nil, fmt.Errorf("expected 1 args, got %d", gotArgs)
  2152  			}
  2153  			return nil, nil
  2154  		},
  2155  	}
  2156  
  2157  	var output bytes.Buffer
  2158  	err := processingLoop(mockRequest(t, "test", nil), &output)
  2159  	if err == nil {
  2160  		t.Fatalf("expected error, got nil")
  2161  	}
  2162  	expectedErr := "expected 1 args, got 0"
  2163  	if !strings.Contains(err.Error(), expectedErr) {
  2164  		t.Errorf("expected error to contain %q, got %v", expectedErr, err)
  2165  	}
  2166  }
  2167  
  2168  func TestTooManyArgs(t *testing.T) {
  2169  	commands["test"] = command{
  2170  		requiredArgs: 1,
  2171  		handler: func(args [][]byte) ([][]byte, error) {
  2172  			if gotArgs := len(args); gotArgs != 1 {
  2173  				return nil, fmt.Errorf("expected 1 args, got %d", gotArgs)
  2174  			}
  2175  			return nil, nil
  2176  		},
  2177  	}
  2178  
  2179  	var output bytes.Buffer
  2180  	err := processingLoop(mockRequest(
  2181  		t, "test", [][]byte{[]byte("one"), []byte("two")}), &output)
  2182  	if err == nil {
  2183  		t.Fatalf("expected error, got nil")
  2184  	}
  2185  	expectedErr := "expected 1 args, got 2"
  2186  	if !strings.Contains(err.Error(), expectedErr) {
  2187  		t.Errorf("expected error to contain %q, got %v", expectedErr, err)
  2188  	}
  2189  }
  2190  
  2191  func TestGetConfig(t *testing.T) {
  2192  	var output bytes.Buffer
  2193  	err := processingLoop(mockRequest(t, "getConfig", nil), &output)
  2194  	if err != nil {
  2195  		t.Errorf("unexpected error: %v", err)
  2196  	}
  2197  
  2198  	respArgs := readResponse(t, &output)
  2199  	if len(respArgs) != 1 {
  2200  		t.Fatalf("expected 1 response arg, got %d", len(respArgs))
  2201  	}
  2202  
  2203  	if !bytes.Equal(respArgs[0], capabilitiesJson) {
  2204  		t.Errorf("expected config %q, got %q", string(capabilitiesJson), string(respArgs[0]))
  2205  	}
  2206  }
  2207  
  2208  func TestSha2256(t *testing.T) {
  2209  	testMessage := []byte("gophers eat grass")
  2210  	expectedDigest := []byte{
  2211  		188, 142, 10, 214, 48, 236, 72, 143, 70, 216, 223, 205, 219, 69, 53, 29,
  2212  		205, 207, 162, 6, 14, 70, 113, 60, 251, 170, 201, 236, 119, 39, 141, 172,
  2213  	}
  2214  
  2215  	var output bytes.Buffer
  2216  	err := processingLoop(mockRequest(t, "SHA2-256", [][]byte{testMessage}), &output)
  2217  	if err != nil {
  2218  		t.Errorf("unexpected error: %v", err)
  2219  	}
  2220  
  2221  	respArgs := readResponse(t, &output)
  2222  	if len(respArgs) != 1 {
  2223  		t.Fatalf("expected 1 response arg, got %d", len(respArgs))
  2224  	}
  2225  
  2226  	if !bytes.Equal(respArgs[0], expectedDigest) {
  2227  		t.Errorf("expected digest %v, got %v", expectedDigest, respArgs[0])
  2228  	}
  2229  }
  2230  
  2231  func mockRequest(t *testing.T, cmd string, args [][]byte) io.Reader {
  2232  	t.Helper()
  2233  
  2234  	msgData := append([][]byte{[]byte(cmd)}, args...)
  2235  
  2236  	var buf bytes.Buffer
  2237  	if err := writeResponse(&buf, msgData); err != nil {
  2238  		t.Fatalf("writeResponse error: %v", err)
  2239  	}
  2240  
  2241  	return &buf
  2242  }
  2243  
  2244  func readResponse(t *testing.T, reader io.Reader) [][]byte {
  2245  	var numArgs uint32
  2246  	if err := binary.Read(reader, binary.LittleEndian, &numArgs); err != nil {
  2247  		t.Fatalf("failed to read response args count: %v", err)
  2248  	}
  2249  
  2250  	args, err := readArgs(reader, numArgs)
  2251  	if err != nil {
  2252  		t.Fatalf("failed to read %d response args: %v", numArgs, err)
  2253  	}
  2254  
  2255  	return args
  2256  }
  2257  

View as plain text