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

View as plain text