Add a server NPN test.

Change-Id: Ib34a24e86bb5de117ecf5609918e130c1ff9532e
Reviewed-on: https://boringssl-review.googlesource.com/1161
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 9dd0edf..8f4cbf8 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -22,10 +22,10 @@
 #include <openssl/bio.h>
 #include <openssl/bytestring.h>
 
-const char *expected_server_name = NULL;
-int early_callback_called = 0;
+static const char *expected_server_name = NULL;
+static int early_callback_called = 0;
 
-int select_certificate_callback(const struct ssl_early_callback_ctx *ctx) {
+static int select_certificate_callback(const struct ssl_early_callback_ctx *ctx) {
   early_callback_called = 1;
 
   if (!expected_server_name) {
@@ -64,11 +64,27 @@
   return 1;
 }
 
-int skip_verify(int preverify_ok, X509_STORE_CTX *store_ctx) {
+static int skip_verify(int preverify_ok, X509_STORE_CTX *store_ctx) {
   return 1;
 }
 
-SSL *setup_test(int is_server) {
+static const char *advertise_npn = NULL;
+
+static int next_protos_advertised_callback(SSL *ssl,
+                                    const uint8_t **out,
+                                    unsigned int *out_len,
+                                    void *arg) {
+  if (!advertise_npn)
+    return SSL_TLSEXT_ERR_NOACK;
+
+  // TODO(davidben): Support passing byte strings with NULs to the
+  // test shim.
+  *out = (const uint8_t*)advertise_npn;
+  *out_len = strlen(advertise_npn);
+  return SSL_TLSEXT_ERR_OK;
+}
+
+static SSL *setup_test(int is_server) {
   if (!SSL_library_init()) {
     return NULL;
   }
@@ -93,6 +109,9 @@
 
   ssl_ctx->select_certificate_cb = select_certificate_callback;
 
+  SSL_CTX_set_next_protos_advertised_cb(
+      ssl_ctx, next_protos_advertised_callback, NULL);
+
   ssl = SSL_new(ssl_ctx);
   if (ssl == NULL) {
     goto err;
@@ -124,6 +143,7 @@
 int main(int argc, char **argv) {
   int i, is_server, ret;
   const char *expected_certificate_types = NULL;
+  const char *expected_next_proto = NULL;
 
   if (argc < 2) {
     fprintf(stderr, "Usage: %s (client|server) [flags...]\n", argv[0]);
@@ -188,6 +208,20 @@
     } else if (strcmp(argv[i], "-require-any-client-certificate") == 0) {
       SSL_set_verify(ssl, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
                      skip_verify);
+    } else if (strcmp(argv[i], "-advertise-npn") == 0) {
+      i++;
+      if (i >= argc) {
+        fprintf(stderr, "Missing parameter\n");
+        return 1;
+      }
+      advertise_npn = argv[i];
+    } else if (strcmp(argv[i], "-expect-next-proto") == 0) {
+      i++;
+      if (i >= argc) {
+        fprintf(stderr, "Missing parameter\n");
+        return 1;
+      }
+      expected_next_proto = argv[i];
     } else {
       fprintf(stderr, "Unknown argument: %s\n", argv[i]);
       return 1;
@@ -233,6 +267,17 @@
     }
   }
 
+  if (expected_next_proto) {
+    const uint8_t *next_proto;
+    unsigned next_proto_len;
+    SSL_get0_next_proto_negotiated(ssl, &next_proto, &next_proto_len);
+    if (next_proto_len != strlen(expected_next_proto) ||
+        memcmp(next_proto, expected_next_proto, next_proto_len) != 0) {
+      fprintf(stderr, "negotiated next proto mismatch\n");
+      return 2;
+    }
+  }
+
   for (;;) {
     uint8_t buf[512];
     int n = SSL_read(ssl, buf, sizeof(buf));
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 0e22623..3d94d1b 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -211,6 +211,17 @@
 		shouldFail:    true,
 		expectedError: ":UNEXPECTED_MESSAGE:",
 	},
+	{
+		testType: serverTest,
+		name:     "NPNServerTest",
+		config: Config{
+			NextProtos: []string{"bar"},
+		},
+		flags: []string{
+			"-advertise-npn", "\x03foo\x03bar\x03baz",
+			"-expect-next-proto", "bar",
+		},
+	},
 }
 
 func doExchange(tlsConn *Conn, messageLen int) error {