aboutsummaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorBen Laurie <ben@openssl.org>2010-07-28 10:06:55 +0000
committerBen Laurie <ben@openssl.org>2010-07-28 10:06:55 +0000
commitee2ffc279417f15fef3b1073c7dc81a908991516 (patch)
treee2af21f279101d5a8f8e841bf7f70b940496907f /apps
parentb122e482f94f1dbda6a93b4c53ccdc92b4046deb (diff)
downloadopenssl-ee2ffc279417f15fef3b1073c7dc81a908991516.zip
openssl-ee2ffc279417f15fef3b1073c7dc81a908991516.tar.gz
openssl-ee2ffc279417f15fef3b1073c7dc81a908991516.tar.bz2
Add Next Protocol Negotiation.
Diffstat (limited to 'apps')
-rw-r--r--apps/apps.c43
-rw-r--r--apps/apps.h4
-rw-r--r--apps/s_client.c79
-rw-r--r--apps/s_server.c66
4 files changed, 191 insertions, 1 deletions
diff --git a/apps/apps.c b/apps/apps.c
index 3a3009d..5bd19c5 100644
--- a/apps/apps.c
+++ b/apps/apps.c
@@ -3031,3 +3031,46 @@ int raw_write_stdout(const void *buf,int siz)
int raw_write_stdout(const void *buf,int siz)
{ return write(fileno(stdout),buf,siz); }
#endif
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NPN)
+/* 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.
+ * in: a NUL termianted string like "abc,def,ghi"
+ *
+ * returns: a malloced buffer or NULL on failure.
+ */
+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;
+ }
+#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NPN */
diff --git a/apps/apps.h b/apps/apps.h
index b1b7e97..bc4d6ee 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -364,3 +364,7 @@ int raw_write_stdout(const void *,int);
#define TM_STOP 1
double app_tminterval (int stop,int usertime);
#endif
+
+#ifndef OPENSSL_NO_NPN
+unsigned char *next_protos_parse(unsigned short *outlen, const char *in);
+#endif
diff --git a/apps/s_client.c b/apps/s_client.c
index 484d009..11da205 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -343,6 +343,9 @@ static void sc_usage(void)
BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n");
BIO_printf(bio_err," -status - request certificate status from server\n");
BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n");
+# ifndef OPENSSL_NO_NPN
+ BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n");
+# endif
#endif
BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
}
@@ -367,6 +370,40 @@ static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg)
return SSL_TLSEXT_ERR_OK;
}
+
+# ifndef OPENSSL_NO_NPN
+/* This the context that we pass to next_proto_cb */
+typedef struct tlsextnextprotoctx_st {
+ unsigned char *data;
+ unsigned short len;
+ int status;
+} tlsextnextprotoctx;
+
+static tlsextnextprotoctx next_proto;
+
+static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
+ {
+ tlsextnextprotoctx *ctx = arg;
+
+ if (!c_quiet)
+ {
+ /* We can assume that |in| is syntactically valid. */
+ unsigned i;
+ BIO_printf(bio_c_out, "Protocols advertised by server: ");
+ for (i = 0; i < inlen; )
+ {
+ if (i)
+ BIO_write(bio_c_out, ", ", 2);
+ BIO_write(bio_c_out, &in[i + 1], in[i]);
+ i += in[i] + 1;
+ }
+ BIO_write(bio_c_out, "\n", 1);
+ }
+
+ ctx->status = SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len);
+ return SSL_TLSEXT_ERR_OK;
+ }
+# endif /* ndef OPENSSL_NO_NPN */
#endif
enum
@@ -430,6 +467,9 @@ int MAIN(int argc, char **argv)
char *servername = NULL;
tlsextctx tlsextcbp =
{NULL,0};
+# ifndef OPENSSL_NO_NPN
+ const char *next_proto_neg_in = NULL;
+# endif
#endif
char *sess_in = NULL;
char *sess_out = NULL;
@@ -661,6 +701,13 @@ int MAIN(int argc, char **argv)
#ifndef OPENSSL_NO_TLSEXT
else if (strcmp(*argv,"-no_ticket") == 0)
{ off|=SSL_OP_NO_TICKET; }
+# ifndef OPENSSL_NO_NPN
+ else if (strcmp(*argv,"-nextprotoneg") == 0)
+ {
+ if (--argc < 1) goto bad;
+ next_proto_neg_in = *(++argv);
+ }
+# endif
#endif
else if (strcmp(*argv,"-serverpref") == 0)
off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
@@ -767,6 +814,21 @@ bad:
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NPN)
+ next_proto.status = -1;
+ if (next_proto_neg_in)
+ {
+ next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in);
+ if (next_proto.data == NULL)
+ {
+ BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n");
+ goto end;
+ }
+ }
+ else
+ next_proto.data = NULL;
+#endif
+
#ifndef OPENSSL_NO_ENGINE
e = setup_engine(bio_err, engine_id, 1);
if (ssl_client_engine_id)
@@ -888,6 +950,11 @@ bad:
*/
if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NPN)
+ if (next_proto.data)
+ SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto);
+#endif
+
if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
if (cipher != NULL)
if(!SSL_CTX_set_cipher_list(ctx,cipher)) {
@@ -1747,6 +1814,18 @@ static void print_stuff(BIO *bio, SSL *s, int full)
BIO_printf(bio,"Expansion: %s\n",
expansion ? SSL_COMP_get_name(expansion) : "NONE");
#endif
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NPN)
+ if (next_proto.status != -1) {
+ const unsigned char *proto;
+ unsigned int proto_len;
+ SSL_get0_next_proto_negotiated(s, &proto, &proto_len);
+ BIO_printf(bio, "Next protocol: (%d) ", next_proto.status);
+ BIO_write(bio, proto, proto_len);
+ BIO_write(bio, "\n", 1);
+ }
+#endif
+
SSL_SESSION_print(bio,SSL_get_session(s));
BIO_printf(bio,"---\n");
if (peer != NULL)
diff --git a/apps/s_server.c b/apps/s_server.c
index e4a9a2b..d339968 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -493,9 +493,12 @@ static void sv_usage(void)
BIO_printf(bio_err," (default is %s)\n",TEST_CERT2);
BIO_printf(bio_err," -key2 arg - Private Key file to use for servername, in cert file if\n");
BIO_printf(bio_err," not specified (default is %s)\n",TEST_CERT2);
+# ifndef OPENSSL_NO_NPN
BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n");
+# endif
BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n");
BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
+ BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n");
#endif
}
@@ -830,6 +833,24 @@ BIO_printf(err, "cert_status: received %d ids\n", sk_OCSP_RESPID_num(ids));
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
goto done;
}
+
+# ifndef OPENSSL_NO_NPN
+/* This is the context that we pass to next_proto_cb */
+typedef struct tlsextnextprotoctx_st {
+ unsigned char *data;
+ unsigned int len;
+} tlsextnextprotoctx;
+
+static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len, void *arg)
+ {
+ tlsextnextprotoctx *next_proto = arg;
+
+ *data = next_proto->data;
+ *len = next_proto->len;
+
+ return SSL_TLSEXT_ERR_OK;
+ }
+# endif /* ndef OPENSSL_NO_NPN */
#endif
int MAIN(int, char **);
@@ -871,6 +892,10 @@ int MAIN(int argc, char *argv[])
#endif
#ifndef OPENSSL_NO_TLSEXT
tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING};
+# ifndef OPENSSL_NO_NPN
+ const char *next_proto_neg_in = NULL;
+ tlsextnextprotoctx next_proto;
+# endif
#endif
#ifndef OPENSSL_NO_PSK
/* by default do not send a PSK identity hint */
@@ -1201,7 +1226,13 @@ int MAIN(int argc, char *argv[])
if (--argc < 1) goto bad;
s_key_file2= *(++argv);
}
-
+# ifndef OPENSSL_NO_NPN
+ else if (strcmp(*argv,"-nextprotoneg") == 0)
+ {
+ if (--argc < 1) goto bad;
+ next_proto_neg_in = *(++argv);
+ }
+# endif
#endif
#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
else if (strcmp(*argv,"-jpake") == 0)
@@ -1306,6 +1337,21 @@ bad:
goto end;
}
}
+# ifndef OPENSSL_NO_NPN
+ if (next_proto_neg_in)
+ {
+ unsigned short len;
+ next_proto.data = next_protos_parse(&len,
+ next_proto_neg_in);
+ if (next_proto.data == NULL)
+ goto end;
+ next_proto.len = len;
+ }
+ else
+ {
+ next_proto.data = NULL;
+ }
+# endif
#endif
}
@@ -1490,6 +1536,11 @@ bad:
if (vpm)
SSL_CTX_set1_param(ctx2, vpm);
}
+
+# ifndef OPENSSL_NO_NPN
+ if (next_proto.data)
+ SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto);
+# endif
#endif
#ifndef OPENSSL_NO_DH
@@ -2174,6 +2225,10 @@ static int init_ssl_connection(SSL *con)
X509 *peer;
long verify_error;
MS_STATIC char buf[BUFSIZ];
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NPN)
+ const unsigned char *next_proto_neg;
+ unsigned next_proto_neg_len;
+#endif
if ((i=SSL_accept(con)) <= 0)
{
@@ -2213,6 +2268,15 @@ static int init_ssl_connection(SSL *con)
BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf);
str=SSL_CIPHER_get_name(SSL_get_current_cipher(con));
BIO_printf(bio_s_out,"CIPHER is %s\n",(str != NULL)?str:"(NONE)");
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NPN)
+ SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len);
+ if (next_proto_neg)
+ {
+ BIO_printf(bio_s_out,"NEXTPROTO is ");
+ BIO_write(bio_s_out, next_proto_neg, next_proto_neg_len);
+ BIO_printf(bio_s_out, "\n");
+ }
+#endif
if (con->hit) BIO_printf(bio_s_out,"Reused session-id\n");
if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) &
TLS1_FLAGS_TLS_PADDING_BUG)