Source file src/crypto/internal/fips140test/acvp_test.go

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

View as plain text