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

View as plain text