Make it possible to tell what curve was used on the server.

We don't actually have an API to let you know if the value is legal to
interpret as a curve ID. (This was kind of a poor API. Oh well.) Also add tests
for key_exchange_info. I've intentionally left server-side plain RSA missing
for now because the SSL_PRIVATE_KEY_METHOD abstraction only gives you bytes and
it's probably better to tweak this API instead.

(key_exchange_info also wasn't populated on the server, though due to a
rebasing error, that fix ended up in the parent CL. Oh well.)

Change-Id: I74a322c8ad03f25b02059da7568c9e1a78419069
Reviewed-on: https://boringssl-review.googlesource.com/6783
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 562e6c5..74674a4 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -12,6 +12,10 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
+#if !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
 #include <openssl/base.h>
 
 #if !defined(OPENSSL_WINDOWS)
@@ -32,6 +36,7 @@
 #pragma comment(lib, "Ws2_32.lib")
 #endif
 
+#include <inttypes.h>
 #include <string.h>
 
 #include <openssl/bio.h>
@@ -1087,6 +1092,15 @@
     return false;
   }
 
+  if (config->expect_key_exchange_info != 0) {
+    uint32_t info = SSL_SESSION_get_key_exchange_info(SSL_get_session(ssl));
+    if (static_cast<uint32_t>(config->expect_key_exchange_info) != info) {
+      fprintf(stderr, "key_exchange_info was %" PRIu32 ", wanted %" PRIu32 "\n",
+              info, static_cast<uint32_t>(config->expect_key_exchange_info));
+      return false;
+    }
+  }
+
   if (!config->is_server) {
     /* Clients should expect a peer certificate chain iff this was not a PSK
      * cipher suite. */
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 5600ec6..45bb0b7 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -4670,6 +4670,61 @@
 	}
 }
 
+func addKeyExchangeInfoTests() {
+	testCases = append(testCases, testCase{
+		name: "KeyExchangeInfo-RSA-Client",
+		config: Config{
+			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+		},
+		// key.pem is a 1024-bit RSA key.
+		flags: []string{"-expect-key-exchange-info", "1024"},
+	})
+	// TODO(davidben): key_exchange_info doesn't work for plain RSA on the
+	// server. Either fix this or change the API as it's not very useful in
+	// this case.
+
+	testCases = append(testCases, testCase{
+		name: "KeyExchangeInfo-DHE-Client",
+		config: Config{
+			CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+			Bugs: ProtocolBugs{
+				// This is a 1234-bit prime number, generated
+				// with:
+				// openssl gendh 1234 | openssl asn1parse -i
+				DHGroupPrime: bigFromHex("0215C589A86BE450D1255A86D7A08877A70E124C11F0C75E476BA6A2186B1C830D4A132555973F2D5881D5F737BB800B7F417C01EC5960AEBF79478F8E0BBB6A021269BD10590C64C57F50AD8169D5488B56EE38DC5E02DA1A16ED3B5F41FEB2AD184B78A31F3A5B2BEC8441928343DA35DE3D4F89F0D4CEDE0034045084A0D1E6182E5EF7FCA325DD33CE81BE7FA87D43613E8FA7A1457099AB53"),
+			},
+		},
+		flags: []string{"-expect-key-exchange-info", "1234"},
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "KeyExchangeInfo-DHE-Server",
+		config: Config{
+			CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+		},
+		// bssl_shim as a server configures a 2048-bit DHE group.
+		flags: []string{"-expect-key-exchange-info", "2048"},
+	})
+
+	testCases = append(testCases, testCase{
+		name: "KeyExchangeInfo-ECDHE-Client",
+		config: Config{
+			CipherSuites:     []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			CurvePreferences: []CurveID{CurveX25519},
+		},
+		flags: []string{"-expect-key-exchange-info", "29", "-enable-all-curves"},
+	})
+	testCases = append(testCases, testCase{
+		testType: serverTest,
+		name:     "KeyExchangeInfo-ECDHE-Server",
+		config: Config{
+			CipherSuites:     []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			CurvePreferences: []CurveID{CurveX25519},
+		},
+		flags: []string{"-expect-key-exchange-info", "29", "-enable-all-curves"},
+	})
+}
+
 func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
 	defer wg.Done()
 
@@ -4768,6 +4823,7 @@
 	addCustomExtensionTests()
 	addRSAClientKeyExchangeTests()
 	addCurveTests()
+	addKeyExchangeInfoTests()
 	for _, async := range []bool{false, true} {
 		for _, splitHandshake := range []bool{false, true} {
 			for _, protocol := range []protocol{tls, dtls} {
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 46991fa..1cf316d 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -143,6 +143,8 @@
   { "-expect-total-renegotiations", &TestConfig::expect_total_renegotiations },
   { "-expect-server-key-exchange-hash",
     &TestConfig::expect_server_key_exchange_hash },
+  { "-expect-key-exchange-info",
+    &TestConfig::expect_key_exchange_info },
 };
 
 }  // namespace
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 685f92d..4e0a46a 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -101,6 +101,7 @@
   bool p384_only = false;
   bool enable_all_curves = false;
   bool use_sparse_dh_prime = false;
+  int expect_key_exchange_info = 0;
 };
 
 bool ParseConfig(int argc, char **argv, TestConfig *out_config);