acvp: update to newer FFDH test.

Revision 1.0 is this test is reportedly no longer acceptable and we have
to use the “SSC” version now. The documentation for this test doesn't
mention that a “z” field is possible, but that's what the test vectors
from the demo server contain and, after guessing at the correct response
format, this makes the NIST server happy.

Change-Id: Ic63d9e19998dc015733d847cd0330a3af1d5e7e6
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/45224
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/util/fipstools/acvp/ACVP.md b/util/fipstools/acvp/ACVP.md
index a477492..fd64984 100644
--- a/util/fipstools/acvp/ACVP.md
+++ b/util/fipstools/acvp/ACVP.md
@@ -70,7 +70,7 @@
 | ECDSA/keyVer         | Curve name, X, Y | Single-byte valid flag |
 | ECDSA/sigGen         | Curve name, private key, hash name, message | R, S |
 | ECDSA/sigVer         | Curve name, hash name, message, X, Y, R, S | Single-byte validity flag |
-| FFDH/&lt;HASH&gt;    | p, q, g, peer public key, local private key (or empty),  local public key (or empty) | Local public key, shared key |
+| FFDH                 | p, q, g, peer public key, local private key (or empty),  local public key (or empty) | Local public key, shared key |
 | HMAC-SHA-1           | Value to hash, key        | Digest  |
 | HMAC-SHA2-224        | Value to hash, key        | Digest  |
 | HMAC-SHA2-256        | Value to hash, key        | Digest  |
diff --git a/util/fipstools/acvp/acvptool/subprocess/kasdh.go b/util/fipstools/acvp/acvptool/subprocess/kasdh.go
index 8251b7f..a21d4ee 100644
--- a/util/fipstools/acvp/acvptool/subprocess/kasdh.go
+++ b/util/fipstools/acvp/acvptool/subprocess/kasdh.go
@@ -30,7 +30,6 @@
 	Type   string      `json:"testType"`
 	Role   string      `json:"kasRole"`
 	Mode   string      `json:"kasMode"`
-	Hash   string      `json:"hashAlg"`
 	Scheme string      `json:"scheme"`
 	PHex   string      `json:"p"`
 	QHex   string      `json:"q"`
@@ -43,7 +42,7 @@
 	PeerPublicHex string `json:"ephemeralPublicServer"`
 	PrivateKeyHex string `json:"ephemeralPrivateIut"`
 	PublicKeyHex  string `json:"ephemeralPublicIut"`
-	ResultHex     string `json:"hashZIut"`
+	ResultHex     string `json:"z"`
 }
 
 type kasDHTestGroupResponse struct {
@@ -54,7 +53,7 @@
 type kasDHTestResponse struct {
 	ID             uint64 `json:"tcId"`
 	LocalPublicHex string `json:"ephemeralPublicIut,omitempty"`
-	ResultHex      string `json:"hashZIut,omitempty"`
+	ResultHex      string `json:"z,omitempty"`
 	Passed         *bool  `json:"testPassed,omitempty"`
 }
 
@@ -66,7 +65,7 @@
 		return nil, err
 	}
 
-	// See https://usnistgov.github.io/ACVP/draft-fussell-acvp-kas-ffc.html
+	// See https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ffc-sp800-56ar3.html
 	var ret []kasDHTestGroupResponse
 	for _, group := range parsed.Groups {
 		response := kasDHTestGroupResponse{
@@ -83,13 +82,6 @@
 			return nil, fmt.Errorf("unknown test type %q", group.Type)
 		}
 
-		switch group.Hash {
-		case "SHA2-224", "SHA2-256", "SHA2-384", "SHA2-512":
-			break
-		default:
-			return nil, fmt.Errorf("unknown hash function %q", group.Hash)
-		}
-
 		switch group.Role {
 		case "initiator", "responder":
 			break
@@ -116,8 +108,7 @@
 			return nil, err
 		}
 
-		method := "FFDH/" + group.Hash
-
+		const method = "FFDH"
 		for _, test := range group.Tests {
 			if len(test.PeerPublicHex) == 0 {
 				return nil, fmt.Errorf("%d/%d is missing peer's key", group.ID, test.ID)
diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go
index 785e7b2..e7a6de9 100644
--- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go
+++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go
@@ -99,7 +99,7 @@
 		"RSA":            &rsa{},
 		"kdf-components": &tlsKDF{},
 		"KAS-ECC-SSC":    &kas{},
-		"KAS-FFC":        &kasDH{},
+		"KAS-FFC-SSC":    &kasDH{},
 	}
 	m.primitives["ECDSA"] = &ecdsa{"ECDSA", map[string]bool{"P-224": true, "P-256": true, "P-384": true, "P-521": true}, m.primitives}
 
diff --git a/util/fipstools/acvp/acvptool/test/tests.json b/util/fipstools/acvp/acvptool/test/tests.json
index f0bafd8..1291adf 100644
--- a/util/fipstools/acvp/acvptool/test/tests.json
+++ b/util/fipstools/acvp/acvptool/test/tests.json
@@ -18,7 +18,7 @@
 {"Wrapper": "modulewrapper", "In": "vectors/HMAC-SHA2-384.bz2", "Out": "expected/HMAC-SHA2-384.bz2"},
 {"Wrapper": "modulewrapper", "In": "vectors/HMAC-SHA2-512.bz2", "Out": "expected/HMAC-SHA2-512.bz2"},
 {"Wrapper": "modulewrapper", "In": "vectors/KAS-ECC-SSC.bz2"},
-{"Wrapper": "modulewrapper", "In": "vectors/KAS-FFC.bz2"},
+{"Wrapper": "modulewrapper", "In": "vectors/KAS-FFC-SSC.bz2"},
 {"Wrapper": "testmodulewrapper", "In": "vectors/KDF.bz2"},
 {"Wrapper": "modulewrapper", "In": "vectors/kdf-components.bz2", "Out": "expected/kdf-components.bz2"},
 {"Wrapper": "modulewrapper", "In": "vectors/RSA.bz2", "Out": "expected/RSA.bz2"},
diff --git a/util/fipstools/acvp/acvptool/test/vectors/KAS-FFC-SSC.bz2 b/util/fipstools/acvp/acvptool/test/vectors/KAS-FFC-SSC.bz2
new file mode 100644
index 0000000..e4594e7
--- /dev/null
+++ b/util/fipstools/acvp/acvptool/test/vectors/KAS-FFC-SSC.bz2
Binary files differ
diff --git a/util/fipstools/acvp/acvptool/test/vectors/KAS-FFC.bz2 b/util/fipstools/acvp/acvptool/test/vectors/KAS-FFC.bz2
deleted file mode 100644
index d5f1edc..0000000
--- a/util/fipstools/acvp/acvptool/test/vectors/KAS-FFC.bz2
+++ /dev/null
Binary files differ
diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
index 650d408..e3d05c7 100644
--- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc
+++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -725,33 +725,19 @@
         ]
       },
       {
-        "algorithm": "KAS-FFC",
-        "revision": "1.0",
-        "mode": "Component",
-        "function": [
-          "keyPairGen"
-        ],
+        "algorithm": "KAS-FFC-SSC",
+        "revision": "Sp800-56Ar3",
         "scheme": {
           "dhEphem": {
             "kasRole": [
               "initiator"
-            ],
-            "noKdfNoKc": {
-              "parameterSet": {
-                "fb": {
-                  "hashAlg": [
-                    "SHA2-256"
-                  ]
-                },
-                "fc": {
-                  "hashAlg": [
-                    "SHA2-256"
-                  ]
-                }
-              }
-            }
+            ]
           }
-        }
+        },
+        "domainParameterGenerationMethods": [
+          "FB",
+          "FC"
+        ]
       }
     ])";
   return WriteReply(
@@ -1700,7 +1686,6 @@
                     output);
 }
 
-template<const EVP_MD* (*HashFunc)()>
 static bool FFDH(const Span<const uint8_t> args[]) {
   bssl::UniquePtr<BIGNUM> p(BytesToBIGNUM(args[0]));
   bssl::UniquePtr<BIGNUM> q(BytesToBIGNUM(args[1]));
@@ -1737,16 +1722,14 @@
     return false;
   }
 
-  uint8_t digest[EVP_MAX_MD_SIZE];
-  size_t digest_len;
-  if (!DH_compute_key_hashed(dh.get(), digest, &digest_len, sizeof(digest),
-                             their_pub.get(), HashFunc())) {
+  std::vector<uint8_t> z(DH_size(dh.get()));
+  if (DH_compute_key_padded(z.data(), their_pub.get(), dh.get()) !=
+      static_cast<int>(z.size())) {
     fprintf(stderr, "DH_compute_key_hashed failed.\n");
     return false;
   }
 
-  return WriteReply(STDOUT_FILENO, BIGNUMBytes(DH_get0_pub_key(dh.get())),
-                    Span<const uint8_t>(digest, digest_len));
+  return WriteReply(STDOUT_FILENO, BIGNUMBytes(DH_get0_pub_key(dh.get())), z);
 }
 
 static constexpr struct {
@@ -1819,7 +1802,7 @@
     {"ECDH/P-256", 3, ECDH<NID_X9_62_prime256v1>},
     {"ECDH/P-384", 3, ECDH<NID_secp384r1>},
     {"ECDH/P-521", 3, ECDH<NID_secp521r1>},
-    {"FFDH/SHA2-256", 6, FFDH<EVP_sha256>},
+    {"FFDH", 6, FFDH},
 };
 
 int main() {