Fix False Start without session tickets.

One of the state transitions wasn't rewritten to CR_CHANGE. Add a test to
exercise this codepath. Also SSL_cutthrough_complete references the state.

Change-Id: Ib2f7ac5ac3f0348864efa93cf13cfd87454572f0
Reviewed-on: https://boringssl-review.googlesource.com/1337
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 72966c7..13e3ae5 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -554,7 +554,7 @@
 			if (s->tlsext_ticket_expected)
 				s->state=SSL3_ST_CR_SESSION_TICKET_A;
 			else
-				s->state=SSL3_ST_CR_FINISHED_A;
+				s->state=SSL3_ST_CR_CHANGE;
 
 			ssl_free_wbio_buffer(s);
 			ret = 1;
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a360070..c26fca9 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -3237,6 +3237,7 @@
 		ssl3_can_cutthrough(s) &&                                   /* cutthrough allowed */
 		s->s3->previous_server_finished_len == 0 &&                 /* not a renegotiation handshake */
 		(s->state == SSL3_ST_CR_SESSION_TICKET_A ||                 /* ready to write app-data*/
+			s->state == SSL3_ST_CR_CHANGE ||
 			s->state == SSL3_ST_CR_FINISHED_A));
 	}
 
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index f06ccd3..1cfe080 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -77,9 +77,9 @@
 static const char *advertise_npn = NULL;
 
 static int next_protos_advertised_callback(SSL *ssl,
-                                    const uint8_t **out,
-                                    unsigned int *out_len,
-                                    void *arg) {
+                                           const uint8_t **out,
+                                           unsigned int *out_len,
+                                           void *arg) {
   if (!advertise_npn)
     return SSL_TLSEXT_ERR_NOACK;
 
@@ -90,6 +90,22 @@
   return SSL_TLSEXT_ERR_OK;
 }
 
+static const char *select_next_proto = NULL;
+
+static int next_proto_select_callback(SSL* ssl,
+                                      uint8_t** out,
+                                      uint8_t* outlen,
+                                      const uint8_t* in,
+                                      unsigned inlen,
+                                      void* arg) {
+  if (!select_next_proto)
+    return SSL_TLSEXT_ERR_NOACK;
+
+  *out = (uint8_t*)select_next_proto;
+  *outlen = strlen(select_next_proto);
+  return SSL_TLSEXT_ERR_OK;
+}
+
 static SSL_CTX *setup_ctx(int is_server) {
   if (!SSL_library_init()) {
     return NULL;
@@ -117,6 +133,8 @@
 
   SSL_CTX_set_next_protos_advertised_cb(
       ssl_ctx, next_protos_advertised_callback, NULL);
+  SSL_CTX_set_next_proto_select_cb(
+      ssl_ctx, next_proto_select_callback, NULL);
 
   return ssl_ctx;
 
@@ -234,6 +252,15 @@
         return 1;
       }
       expected_next_proto = argv[i];
+    } else if (strcmp(argv[i], "-false-start") == 0) {
+      SSL_set_mode(ssl, SSL_MODE_HANDSHAKE_CUTTHROUGH);
+    } else if (strcmp(argv[i], "-select-next-proto") == 0) {
+      i++;
+      if (i >= argc) {
+        fprintf(stderr, "Missing parameter\n");
+        return 1;
+      }
+      select_next_proto = argv[i];
     } else {
       fprintf(stderr, "Unknown argument: %s\n", argv[i]);
       return 1;
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 1ed733c..eedb2f1 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -343,6 +343,30 @@
 		shouldFail:    true,
 		expectedError: ":CCS_RECEIVED_EARLY:",
 	},
+	{
+		name: "FalseStart",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			NextProtos: []string{"foo"},
+		},
+		flags: []string{
+			"-false-start",
+			"-select-next-proto", "foo",
+		},
+		resumeSession: true,
+	},
+	{
+		name: "FalseStart-SessionTicketsDisabled",
+		config: Config{
+			CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+			NextProtos: []string{"foo"},
+			SessionTicketsDisabled: true,
+		},
+		flags: []string{
+			"-false-start",
+			"-select-next-proto", "foo",
+		},
+	},
 }
 
 func doExchange(testType testType, config *Config, conn net.Conn, messageLen int) error {