crypto/tls: add ALPN support.

Fixes #6736.

LGTM=mikioh.mikioh
R=bradfitz, mikioh.mikioh
CC=golang-codereviews
https://golang.org/cl/108710046
diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go
index 0d73c8e..432308b 100644
--- a/src/pkg/crypto/tls/handshake_client_test.go
+++ b/src/pkg/crypto/tls/handshake_client_test.go
@@ -49,6 +49,10 @@
 	// key, if not nil, contains either a *rsa.PrivateKey or
 	// *ecdsa.PrivateKey which is the private key for the reference server.
 	key interface{}
+	// validate, if not nil, is a function that will be called with the
+	// ConnectionState of the resulting connection. It returns a non-nil
+	// error if the ConnectionState is unacceptable.
+	validate func(ConnectionState) error
 }
 
 var defaultServerCommand = []string{"openssl", "s_server"}
@@ -188,6 +192,11 @@
 		if _, err := client.Write([]byte("hello\n")); err != nil {
 			t.Logf("Client.Write failed: %s", err)
 		}
+		if test.validate != nil {
+			if err := test.validate(client.ConnectionState()); err != nil {
+				t.Logf("validate callback returned error: %s", err)
+			}
+		}
 		client.Close()
 		clientConn.Close()
 		doneChan <- true
@@ -437,3 +446,45 @@
 		t.Fatalf("failed to add nil entry to cache")
 	}
 }
+
+func TestHandshakeClientALPNMatch(t *testing.T) {
+	config := *testConfig
+	config.NextProtos = []string{"proto2", "proto1"}
+
+	test := &clientTest{
+		name: "ALPN",
+		// Note that this needs OpenSSL 1.0.2 because that is the first
+		// version that supports the -alpn flag.
+		command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
+		config:  &config,
+		validate: func(state ConnectionState) error {
+			// The server's preferences should override the client.
+			if state.NegotiatedProtocol != "proto1" {
+				return fmt.Errorf("Got protocol %q, wanted proto1", state.NegotiatedProtocol)
+			}
+			return nil
+		},
+	}
+	runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientALPNNoMatch(t *testing.T) {
+	config := *testConfig
+	config.NextProtos = []string{"proto3"}
+
+	test := &clientTest{
+		name: "ALPN-NoMatch",
+		// Note that this needs OpenSSL 1.0.2 because that is the first
+		// version that supports the -alpn flag.
+		command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
+		config:  &config,
+		validate: func(state ConnectionState) error {
+			// There's no overlap so OpenSSL will not select a protocol.
+			if state.NegotiatedProtocol != "" {
+				return fmt.Errorf("Got protocol %q, wanted ''", state.NegotiatedProtocol)
+			}
+			return nil
+		},
+	}
+	runClientTestTLS12(t, test)
+}