+#ifndef OPENSSL_NO_NPN
+/* Note that this code assumes that this is only a one element list: */
+static const char NEXT_PROTO_STRING[] = "\x09testproto";
+int npn_client = 0;
+int npn_server = 0;
+int npn_server_reject = 0;
+
+static int cb_client_npn(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
+ {
+ /* This callback only returns the protocol string, rather than a length
+ prefixed set. We assume that NEXT_PROTO_STRING is a one element list and
+ remove the first byte to chop off the length prefix. */
+ *out = (unsigned char*) NEXT_PROTO_STRING + 1;
+ *outlen = sizeof(NEXT_PROTO_STRING) - 2;
+ return SSL_TLSEXT_ERR_OK;
+ }
+
+static int cb_server_npn(SSL *s, const unsigned char **data, unsigned int *len, void *arg)
+ {
+ *data = (const unsigned char *) NEXT_PROTO_STRING;
+ *len = sizeof(NEXT_PROTO_STRING) - 1;
+ return SSL_TLSEXT_ERR_OK;
+ }
+
+static int cb_server_rejects_npn(SSL *s, const unsigned char **data, unsigned int *len, void *arg)
+ {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+static int verify_npn(SSL *client, SSL *server)
+ {
+ const unsigned char *client_s;
+ unsigned client_len;
+ const unsigned char *server_s;
+ unsigned server_len;
+
+ SSL_get0_next_proto_negotiated(client, &client_s, &client_len);
+ SSL_get0_next_proto_negotiated(server, &server_s, &server_len);
+
+ if (client_len)
+ {
+ BIO_printf(bio_stdout, "Client NPN: ");
+ BIO_write(bio_stdout, client_s, client_len);
+ BIO_printf(bio_stdout, "\n");
+ }
+
+ if (server_len)
+ {
+ BIO_printf(bio_stdout, "Server NPN: ");
+ BIO_write(bio_stdout, server_s, server_len);
+ BIO_printf(bio_stdout, "\n");
+ }
+
+ /* If an NPN string was returned, it must be the protocol that we
+ * expected to negotiate. */
+ if (client_len && (client_len != sizeof(NEXT_PROTO_STRING) - 2 ||
+ memcmp(client_s, NEXT_PROTO_STRING + 1, client_len)))
+ return -1;
+ if (server_len && (server_len != sizeof(NEXT_PROTO_STRING) - 2 ||
+ memcmp(server_s, NEXT_PROTO_STRING + 1, server_len)))
+ return -1;
+
+ if (!npn_client && client_len)
+ return -1;
+ if (!npn_server && server_len)
+ return -1;
+ if (npn_server_reject && server_len)
+ return -1;
+ if (npn_client && npn_server && (!client_len || !server_len))
+ return -1;
+
+ return 0;
+ }
+#endif
+
+#define SCT_EXT_TYPE 18
+
+/* WARNING : below extension types are *NOT* IETF assigned, and
+ could conflict if these types are reassigned and handled
+ specially by OpenSSL in the future */
+#define TACK_EXT_TYPE 62208
+#define CUSTOM_EXT_TYPE_0 1000
+#define CUSTOM_EXT_TYPE_1 1001
+#define CUSTOM_EXT_TYPE_2 1002
+#define CUSTOM_EXT_TYPE_3 1003
+
+const char custom_ext_cli_string[] = "abc";
+const char custom_ext_srv_string[] = "defg";
+
+/* These set from cmdline */
+char* serverinfo_file = NULL;
+int serverinfo_sct = 0;
+int serverinfo_tack = 0;
+
+/* These set based on extension callbacks */
+int serverinfo_sct_seen = 0;
+int serverinfo_tack_seen = 0;
+int serverinfo_other_seen = 0;
+
+/* This set from cmdline */
+int custom_ext = 0;
+
+/* This set based on extension callbacks */
+int custom_ext_error = 0;
+
+static int serverinfo_cli_cb(SSL* s, unsigned short ext_type,
+ const unsigned char* in, unsigned short inlen,
+ int* al, void* arg)
+ {
+ if (ext_type == SCT_EXT_TYPE)
+ serverinfo_sct_seen++;
+ else if (ext_type == TACK_EXT_TYPE)
+ serverinfo_tack_seen++;
+ else
+ serverinfo_other_seen++;
+ return 1;
+ }
+
+static int verify_serverinfo()
+ {
+ if (serverinfo_sct != serverinfo_sct_seen)
+ return -1;
+ if (serverinfo_tack != serverinfo_tack_seen)
+ return -1;
+ if (serverinfo_other_seen)
+ return -1;
+ return 0;
+ }
+
+/* Four test cases for custom extensions:
+ * 0 - no ClientHello extension or ServerHello response
+ * 1 - ClientHello with "abc", no response
+ * 2 - ClientHello with "abc", empty response
+ * 3 - ClientHello with "abc", "defg" response
+ */
+
+static int custom_ext_0_cli_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_0)
+ custom_ext_error = 1;
+ return -1; /* Don't send an extension */
+ }
+
+static int custom_ext_0_cli_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ custom_ext_error = 1; /* Shouldn't be called */
+ return 0;
+ }
+
+static int custom_ext_1_cli_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_1)
+ custom_ext_error = 1;
+ *out = (const unsigned char*)custom_ext_cli_string;
+ *outlen = strlen(custom_ext_cli_string);
+ return 1; /* Send "abc" */
+ }
+
+static int custom_ext_1_cli_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ custom_ext_error = 1; /* Shouldn't be called */
+ return 0;
+ }
+
+static int custom_ext_2_cli_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_2)
+ custom_ext_error = 1;
+ *out = (const unsigned char*)custom_ext_cli_string;
+ *outlen = strlen(custom_ext_cli_string);
+ return 1; /* Send "abc" */
+ }
+
+static int custom_ext_2_cli_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_2)
+ custom_ext_error = 1;
+ if (inlen != 0)
+ custom_ext_error = 1; /* Should be empty response */
+ return 1;
+ }
+
+static int custom_ext_3_cli_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_3)
+ custom_ext_error = 1;
+ *out = (const unsigned char*)custom_ext_cli_string;
+ *outlen = strlen(custom_ext_cli_string);
+ return 1; /* Send "abc" */
+ }
+
+static int custom_ext_3_cli_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_3)
+ custom_ext_error = 1;
+ if (inlen != strlen(custom_ext_srv_string))
+ custom_ext_error = 1;
+ if (memcmp(custom_ext_srv_string, in, inlen) != 0)
+ custom_ext_error = 1; /* Check for "defg" */
+ return 1;
+ }
+
+
+static int custom_ext_0_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ custom_ext_error = 1;
+ return 0; /* Shouldn't be called */
+ }
+
+static int custom_ext_0_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ custom_ext_error = 1;
+ return 0; /* Shouldn't be called */
+ }
+
+static int custom_ext_1_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_1)
+ custom_ext_error = 1;
+ /* Check for "abc" */
+ if (inlen != strlen(custom_ext_cli_string))
+ custom_ext_error = 1;
+ if (memcmp(in, custom_ext_cli_string, inlen) != 0)
+ custom_ext_error = 1;
+ return 1;
+ }
+
+static int custom_ext_1_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ return -1; /* Don't send an extension */
+ }
+
+static int custom_ext_2_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_2)
+ custom_ext_error = 1;
+ /* Check for "abc" */
+ if (inlen != strlen(custom_ext_cli_string))
+ custom_ext_error = 1;
+ if (memcmp(in, custom_ext_cli_string, inlen) != 0)
+ custom_ext_error = 1;
+ return 1;
+ }
+
+static int custom_ext_2_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ *out = NULL;
+ *outlen = 0;
+ return 1; /* Send empty extension */
+ }
+
+static int custom_ext_3_srv_first_cb(SSL *s, unsigned short ext_type,
+ const unsigned char *in,
+ unsigned short inlen, int *al,
+ void *arg)
+ {
+ if (ext_type != CUSTOM_EXT_TYPE_3)
+ custom_ext_error = 1;
+ /* Check for "abc" */
+ if (inlen != strlen(custom_ext_cli_string))
+ custom_ext_error = 1;
+ if (memcmp(in, custom_ext_cli_string, inlen) != 0)
+ custom_ext_error = 1;
+ return 1;
+ }
+
+static int custom_ext_3_srv_second_cb(SSL *s, unsigned short ext_type,
+ const unsigned char **out,
+ unsigned short *outlen, void *arg)
+ {
+ *out = (const unsigned char*)custom_ext_srv_string;
+ *outlen = strlen(custom_ext_srv_string);
+ return 1; /* Send "defg" */
+ }
+
+