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

View as plain text