Commit 68b33cc5 authored by Ben Laurie's avatar Ben Laurie
Browse files

Add Next Protocol Negotiation.

parent 4c02cf8e
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -2693,6 +2693,50 @@ void jpake_server_auth(BIO *out, BIO *conn, const char *secret)

#endif

#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
/* 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.
 */
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_NEXTPROTONEG */

/*
 * Platform-specific sections
 */
+4 −0
Original line number Diff line number Diff line
@@ -331,6 +331,10 @@ void jpake_client_auth(BIO *out, BIO *conn, const char *secret);
void jpake_server_auth(BIO *out, BIO *conn, const char *secret);
#endif

#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
unsigned char *next_protos_parse(unsigned short *outlen, const char *in);
#endif  /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */

#define FORMAT_UNDEF    0
#define FORMAT_ASN1     1
#define FORMAT_TEXT     2
+78 −0
Original line number Diff line number Diff line
@@ -354,6 +354,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");
# if !defined(OPENSSL_NO_NEXTPROTONEG)
	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");
	}
@@ -484,6 +487,40 @@ static char * MS_CALLBACK missing_srp_username_callback(SSL *s, void *arg)
	}

#endif

# ifndef OPENSSL_NO_NEXTPROTONEG
/* 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
#endif

enum
@@ -550,6 +587,9 @@ int MAIN(int argc, char **argv)
	char *servername = NULL; 
        tlsextctx tlsextcbp = 
        {NULL,0};
# ifndef OPENSSL_NO_NEXTPROTONEG
	const char *next_proto_neg_in = NULL;
# endif
#endif
	char *sess_in = NULL;
	char *sess_out = NULL;
@@ -821,6 +861,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_NEXTPROTONEG
		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;
@@ -927,6 +974,21 @@ bad:
	OpenSSL_add_ssl_algorithms();
	SSL_load_error_strings();

#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
	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)
@@ -1056,6 +1118,11 @@ bad:
	 */
	if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);

#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
	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)) {
@@ -1949,6 +2016,17 @@ static void print_stuff(BIO *bio, SSL *s, int full)
	}
#endif

#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
	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)
+68 −3
Original line number Diff line number Diff line
@@ -537,6 +537,9 @@ static void sv_usage(void)
	BIO_printf(bio_err," -tlsextdebug  - hex dump of all TLS extensions received\n");
	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");
# ifndef OPENSSL_NO_NEXTPROTONEG
	BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n");
# endif
#endif
	}

@@ -871,6 +874,26 @@ 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_NEXTPROTONEG
/* 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_NEXTPROTONEG */


#endif

int MAIN(int, char **);
@@ -909,9 +932,11 @@ int MAIN(int argc, char *argv[])
#ifndef OPENSSL_NO_TLSEXT
	EVP_PKEY *s_key2 = NULL;
	X509 *s_cert2 = NULL;
#endif
#ifndef OPENSSL_NO_TLSEXT
        tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING};
# ifndef OPENSSL_NO_NEXTPROTONEG
	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 */
@@ -1267,7 +1292,13 @@ int MAIN(int argc, char *argv[])
			if (--argc < 1) goto bad;
			s_key_file2= *(++argv);
			}
			
# ifndef OPENSSL_NO_NEXTPROTONEG
		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)
@@ -1372,6 +1403,22 @@ bad:
				goto end;
				}
			}

# ifndef OPENSSL_NO_NEXTPROTONEG
		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
		}

@@ -1552,6 +1599,11 @@ bad:
		if (vpm)
			SSL_CTX_set1_param(ctx2, vpm);
		}

# ifndef OPENSSL_NO_NEXTPROTONEG
	if (next_proto.data)
		SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto);
# endif
#endif 

#ifndef OPENSSL_NO_DH
@@ -2257,6 +2309,10 @@ static int init_ssl_connection(SSL *con)
#ifndef OPENSSL_NO_KRB5
	char *client_princ;
#endif
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
	const unsigned char *next_proto_neg;
	unsigned next_proto_neg_len;
#endif

	if ((i=SSL_accept(con)) <= 0)
		{
@@ -2296,6 +2352,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_NEXTPROTONEG)
	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 (SSL_cache_hit(con)) BIO_printf(bio_s_out,"Reused session-id\n");
	if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) &
		TLS1_FLAGS_TLS_PADDING_BUG)
+33 −3
Original line number Diff line number Diff line
@@ -202,15 +202,38 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen)
	return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
	}

#ifndef OPENSSL_NO_NEXTPROTONEG
/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen to far. */
static void ssl3_take_mac(SSL *s) {
	const char *sender;
	int slen;

	if (s->state & SSL_ST_CONNECT)
		{
		sender=s->method->ssl3_enc->server_finished_label;
		slen=s->method->ssl3_enc->server_finished_label_len;
		}
	else
		{
		sender=s->method->ssl3_enc->client_finished_label;
		slen=s->method->ssl3_enc->client_finished_label_len;
		}

	s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
		sender,slen,s->s3->tmp.peer_finish_md);
}
#endif

int ssl3_get_finished(SSL *s, int a, int b)
	{
	int al,i,ok;
	long n;
	unsigned char *p;

	/* the mac has already been generated when we received the
	 * change cipher spec message and is in s->s3->tmp.peer_finish_md
	 */ 
#ifdef OPENSSL_NO_NEXTPROTONEG
	/* the mac has already been generated when we received the change
	 * cipher spec message and is in s->s3->tmp.peer_finish_md. */
#endif

	n=s->method->ssl_get_message(s,
		a,
@@ -514,6 +537,13 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok)
		s->init_num += i;
		n -= i;
		}
#ifndef OPENSSL_NO_NEXTPROTONEG
	/* If receiving Finished, record MAC of prior handshake messages for
	 * Finished verification. */
	if (*s->init_buf->data == SSL3_MT_FINISHED)
		ssl3_take_mac(s);
#endif
	/* Feed this message into MAC computation. */
	ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num + 4);
	if (s->msg_callback)
		s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, (size_t)s->init_num + 4, s, s->msg_callback_arg);
Loading