static BIO *bio_err=NULL;
static BIO *bio_stdout=NULL;
+#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
+
static char *cipher=NULL;
static int verbose=0;
static int debug=0;
" (default is sect163r2).\n");
#endif
fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
+#ifndef OPENSSL_NO_NPN
+ fprintf(stderr," -npn_client - have client side offer NPN\n");
+ fprintf(stderr," -npn_server - have server side offer NPN\n");
+ fprintf(stderr," -npn_server_reject - have server reject NPN\n");
+#endif
}
static void print_details(SSL *c_ssl, const char *prefix)
{
test_cipherlist = 1;
}
+#ifndef OPENSSL_NO_NPN
+ else if (strcmp(*argv,"-npn_client") == 0)
+ {
+ npn_client = 1;
+ }
+ else if (strcmp(*argv,"-npn_server") == 0)
+ {
+ npn_server = 1;
+ }
+ else if (strcmp(*argv,"-npn_server_reject") == 0)
+ {
+ npn_server_reject = 1;
+ }
+#endif
else
{
fprintf(stderr,"unknown option %s\n",*argv);
#endif
}
+#ifndef OPENSSL_NO_NPN
+ if (npn_client)
+ {
+ SSL_CTX_set_next_proto_select_cb(c_ctx, cb_client_npn, NULL);
+ }
+ if (npn_server)
+ {
+ if (npn_server_reject)
+ {
+ BIO_printf(bio_err, "Can't have both -npn_server and -npn_server_reject\n");
+ goto end;
+ }
+ SSL_CTX_set_next_protos_advertised_cb(s_ctx, cb_server_npn, NULL);
+ }
+ if (npn_server_reject)
+ {
+ SSL_CTX_set_next_protos_advertised_cb(s_ctx, cb_server_rejects_npn, NULL);
+ }
+#endif
+
c_ssl=SSL_new(c_ctx);
s_ssl=SSL_new(s_ctx);
if (verbose)
print_details(c_ssl, "DONE via BIO pair: ");
+#ifndef OPENSSL_NO_NPN
+ if (verify_npn(c_ssl, s_ssl) < 0)
+ {
+ ret = 1;
+ goto end;
+ }
+#endif
end:
ret = 0;
if (verbose)
print_details(c_ssl, "DONE: ");
+#ifndef OPENSSL_NO_NPN
+ if (verify_npn(c_ssl, s_ssl) < 0)
+ {
+ ret = 1;
+ goto err;
+ }
+#endif
ret=0;
err:
/* We have to set the BIO's to NULL otherwise they will be