Add tests for ALPN functionality.

Conflicts:
	ssl/ssltest.c
diff --git a/ssl/ssltest.c b/ssl/ssltest.c
index 1be60c0..cb76439 100644
--- a/ssl/ssltest.c
+++ b/ssl/ssltest.c
@@ -370,6 +370,127 @@
 	}
 #endif
 
+static const char *alpn_client;
+static const char *alpn_server;
+static const char *alpn_expected;
+static unsigned char *alpn_selected;
+
+/* next_protos_parse parses a comma separated list of strings into a string
+ * in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
+ *   outlen: (output) set to the length of the resulting buffer on success.
+ *   err: (maybe NULL) on failure, an error message line is written to this BIO.
+ *   in: a NUL termianted string like "abc,def,ghi"
+ *
+ *   returns: a malloced buffer or NULL on failure.
+ */
+static unsigned char *next_protos_parse(unsigned short *outlen, const char *in)
+	{
+	size_t len;
+	unsigned char *out;
+	size_t i, start = 0;
+
+	len = strlen(in);
+	if (len >= 65535)
+		return NULL;
+
+	out = OPENSSL_malloc(strlen(in) + 1);
+	if (!out)
+		return NULL;
+
+	for (i = 0; i <= len; ++i)
+		{
+		if (i == len || in[i] == ',')
+			{
+			if (i - start > 255)
+				{
+				OPENSSL_free(out);
+				return NULL;
+				}
+			out[start] = i - start;
+			start = i + 1;
+			}
+		else
+			out[i+1] = in[i];
+		}
+
+	*outlen = len + 1;
+	return out;
+	}
+
+static int cb_server_alpn(SSL *s, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
+	{
+	unsigned char *protos;
+	unsigned short protos_len;
+
+	protos = next_protos_parse(&protos_len, alpn_server);
+	if (protos == NULL)
+		{
+		fprintf(stderr, "failed to parser ALPN server protocol string: %s\n", alpn_server);
+		abort();
+		}
+
+	if (SSL_select_next_proto((unsigned char**) out, outlen, protos, protos_len, in, inlen) !=
+	    OPENSSL_NPN_NEGOTIATED)
+		{
+		OPENSSL_free(protos);
+		return SSL_TLSEXT_ERR_NOACK;
+		}
+
+	/* Make a copy of the selected protocol which will be freed in verify_alpn. */
+	alpn_selected = OPENSSL_malloc(*outlen);
+	memcpy(alpn_selected, *out, *outlen);
+	*out = alpn_selected;
+
+	OPENSSL_free(protos);
+	return SSL_TLSEXT_ERR_OK;
+	}
+
+static int verify_alpn(SSL *client, SSL *server)
+	{
+	const unsigned char *client_proto, *server_proto;
+	unsigned int client_proto_len = 0, server_proto_len = 0;
+	SSL_get0_alpn_selected(client, &client_proto, &client_proto_len);
+	SSL_get0_alpn_selected(server, &server_proto, &server_proto_len);
+
+	if (alpn_selected != NULL)
+		{
+		OPENSSL_free(alpn_selected);
+		alpn_selected = NULL;
+		}
+
+	if (client_proto_len != server_proto_len ||
+	    memcmp(client_proto, server_proto, client_proto_len) != 0)
+		{
+		BIO_printf(bio_stdout, "ALPN selected protocols differ!\n");
+		goto err;
+		}
+
+	if (client_proto_len > 0 && alpn_expected == NULL)
+		{
+		BIO_printf(bio_stdout, "ALPN unexpectedly negotiated\n");
+		goto err;
+		}
+
+	if (alpn_expected != NULL &&
+	    (client_proto_len != strlen(alpn_expected) ||
+	     memcmp(client_proto, alpn_expected, client_proto_len) != 0))
+		{
+		BIO_printf(bio_stdout, "ALPN selected protocols not equal to expected protocol: %s\n", alpn_expected);
+		goto err;
+		}
+
+	return 0;
+
+err:
+	BIO_printf(bio_stdout, "ALPN results: client: '");
+	BIO_write(bio_stdout, client_proto, client_proto_len);
+	BIO_printf(bio_stdout, "', server: '");
+	BIO_write(bio_stdout, server_proto, server_proto_len);
+	BIO_printf(bio_stdout, "'\n");
+	BIO_printf(bio_stdout, "ALPN configured: client: '%s', server: '%s'\n", alpn_client, alpn_server);
+	return -1;
+	}
+
 #define SCT_EXT_TYPE 18
 
 /* WARNING : below extension types are *NOT* IETF assigned, and 
@@ -689,6 +810,9 @@
 	fprintf(stderr," -serverinfo_sct  - have client offer and expect SCT\n");
 	fprintf(stderr," -serverinfo_tack - have client offer and expect TACK\n");
 	fprintf(stderr," -custom_ext - try various custom extension callbacks\n");
+	fprintf(stderr," -alpn_client <string> - have client side offer ALPN\n");
+	fprintf(stderr," -alpn_server <string> - have server side offer ALPN\n");
+	fprintf(stderr," -alpn_expected <string> - the ALPN protocol that should be negotiated\n");
 	}
 
 static void print_details(SSL *c_ssl, const char *prefix)
@@ -1118,6 +1242,21 @@
 			{
 			custom_ext = 1;
 			}
+		else if (strcmp(*argv,"-alpn_client") == 0)
+			{
+			if (--argc < 1) goto bad;
+			alpn_client = *(++argv);
+			}
+		else if (strcmp(*argv,"-alpn_server") == 0)
+			{
+			if (--argc < 1) goto bad;
+			alpn_server = *(++argv);
+			}
+		else if (strcmp(*argv,"-alpn_expected") == 0)
+			{
+			if (--argc < 1) goto bad;
+			alpn_expected = *(++argv);
+			}
 		else
 			{
 			fprintf(stderr,"unknown option %s\n",*argv);
@@ -1487,6 +1626,23 @@
 					   custom_ext_3_srv_second_cb, NULL);
 		}
 
+	if (alpn_server)
+		SSL_CTX_set_alpn_select_cb(s_ctx, cb_server_alpn, NULL);
+
+	if (alpn_client)
+		{
+		unsigned short alpn_len;
+		unsigned char *alpn = next_protos_parse(&alpn_len, alpn_client);
+
+		if (alpn == NULL)
+			{
+			BIO_printf(bio_err, "Error parsing -alpn_client argument\n");
+			goto end;
+			}
+		SSL_CTX_set_alpn_protos(c_ctx, alpn, alpn_len);
+		OPENSSL_free(alpn);
+		}
+
 	c_ssl=SSL_new(c_ctx);
 	s_ssl=SSL_new(s_ctx);
 
@@ -1949,6 +2105,11 @@
 		ret = 1;
 		goto err;
 		}
+	if (verify_alpn(c_ssl, s_ssl) < 0)
+		{
+		ret = 1;
+		goto err;
+		}
 
 	if (custom_ext_error)
 		{