diff options
author | Ben Laurie <ben@openssl.org> | 2010-07-28 10:06:55 +0000 |
---|---|---|
committer | Ben Laurie <ben@openssl.org> | 2010-07-28 10:06:55 +0000 |
commit | ee2ffc279417f15fef3b1073c7dc81a908991516 (patch) | |
tree | e2af21f279101d5a8f8e841bf7f70b940496907f /apps | |
parent | b122e482f94f1dbda6a93b4c53ccdc92b4046deb (diff) | |
download | openssl-ee2ffc279417f15fef3b1073c7dc81a908991516.zip openssl-ee2ffc279417f15fef3b1073c7dc81a908991516.tar.gz openssl-ee2ffc279417f15fef3b1073c7dc81a908991516.tar.bz2 |
Add Next Protocol Negotiation.
Diffstat (limited to 'apps')
-rw-r--r-- | apps/apps.c | 43 | ||||
-rw-r--r-- | apps/apps.h | 4 | ||||
-rw-r--r-- | apps/s_client.c | 79 | ||||
-rw-r--r-- | apps/s_server.c | 66 |
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) |