Skip to content

Commit 68b33cc

Browse files
author
Ben Laurie
committed
Add Next Protocol Negotiation.
1 parent 4c02cf8 commit 68b33cc

File tree

16 files changed

+712
-7
lines changed

16 files changed

+712
-7
lines changed

apps/apps.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2693,6 +2693,50 @@ void jpake_server_auth(BIO *out, BIO *conn, const char *secret)
26932693

26942694
#endif
26952695

2696+
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
2697+
/* next_protos_parse parses a comma separated list of strings into a string
2698+
* in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
2699+
* outlen: (output) set to the length of the resulting buffer on success.
2700+
* err: (maybe NULL) on failure, an error message line is written to this BIO.
2701+
* in: a NUL termianted string like "abc,def,ghi"
2702+
*
2703+
* returns: a malloced buffer or NULL on failure.
2704+
*/
2705+
unsigned char *next_protos_parse(unsigned short *outlen, const char *in)
2706+
{
2707+
size_t len;
2708+
unsigned char *out;
2709+
size_t i, start = 0;
2710+
2711+
len = strlen(in);
2712+
if (len >= 65535)
2713+
return NULL;
2714+
2715+
out = OPENSSL_malloc(strlen(in) + 1);
2716+
if (!out)
2717+
return NULL;
2718+
2719+
for (i = 0; i <= len; ++i)
2720+
{
2721+
if (i == len || in[i] == ',')
2722+
{
2723+
if (i - start > 255)
2724+
{
2725+
OPENSSL_free(out);
2726+
return NULL;
2727+
}
2728+
out[start] = i - start;
2729+
start = i + 1;
2730+
}
2731+
else
2732+
out[i+1] = in[i];
2733+
}
2734+
2735+
*outlen = len + 1;
2736+
return out;
2737+
}
2738+
#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
2739+
26962740
/*
26972741
* Platform-specific sections
26982742
*/

apps/apps.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,10 @@ void jpake_client_auth(BIO *out, BIO *conn, const char *secret);
331331
void jpake_server_auth(BIO *out, BIO *conn, const char *secret);
332332
#endif
333333

334+
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
335+
unsigned char *next_protos_parse(unsigned short *outlen, const char *in);
336+
#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
337+
334338
#define FORMAT_UNDEF 0
335339
#define FORMAT_ASN1 1
336340
#define FORMAT_TEXT 2

apps/s_client.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ static void sc_usage(void)
354354
BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n");
355355
BIO_printf(bio_err," -status - request certificate status from server\n");
356356
BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n");
357+
# if !defined(OPENSSL_NO_NEXTPROTONEG)
358+
BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n");
359+
# endif
357360
#endif
358361
BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
359362
}
@@ -484,6 +487,40 @@ static char * MS_CALLBACK missing_srp_username_callback(SSL *s, void *arg)
484487
}
485488

486489
#endif
490+
491+
# ifndef OPENSSL_NO_NEXTPROTONEG
492+
/* This the context that we pass to next_proto_cb */
493+
typedef struct tlsextnextprotoctx_st {
494+
unsigned char *data;
495+
unsigned short len;
496+
int status;
497+
} tlsextnextprotoctx;
498+
499+
static tlsextnextprotoctx next_proto;
500+
501+
static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
502+
{
503+
tlsextnextprotoctx *ctx = arg;
504+
505+
if (!c_quiet)
506+
{
507+
/* We can assume that |in| is syntactically valid. */
508+
unsigned i;
509+
BIO_printf(bio_c_out, "Protocols advertised by server: ");
510+
for (i = 0; i < inlen; )
511+
{
512+
if (i)
513+
BIO_write(bio_c_out, ", ", 2);
514+
BIO_write(bio_c_out, &in[i + 1], in[i]);
515+
i += in[i] + 1;
516+
}
517+
BIO_write(bio_c_out, "\n", 1);
518+
}
519+
520+
ctx->status = SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len);
521+
return SSL_TLSEXT_ERR_OK;
522+
}
523+
# endif
487524
#endif
488525

489526
enum
@@ -550,6 +587,9 @@ int MAIN(int argc, char **argv)
550587
char *servername = NULL;
551588
tlsextctx tlsextcbp =
552589
{NULL,0};
590+
# ifndef OPENSSL_NO_NEXTPROTONEG
591+
const char *next_proto_neg_in = NULL;
592+
# endif
553593
#endif
554594
char *sess_in = NULL;
555595
char *sess_out = NULL;
@@ -821,6 +861,13 @@ int MAIN(int argc, char **argv)
821861
#ifndef OPENSSL_NO_TLSEXT
822862
else if (strcmp(*argv,"-no_ticket") == 0)
823863
{ off|=SSL_OP_NO_TICKET; }
864+
# ifndef OPENSSL_NO_NEXTPROTONEG
865+
else if (strcmp(*argv,"-nextprotoneg") == 0)
866+
{
867+
if (--argc < 1) goto bad;
868+
next_proto_neg_in = *(++argv);
869+
}
870+
# endif
824871
#endif
825872
else if (strcmp(*argv,"-serverpref") == 0)
826873
off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
@@ -927,6 +974,21 @@ int MAIN(int argc, char **argv)
927974
OpenSSL_add_ssl_algorithms();
928975
SSL_load_error_strings();
929976

977+
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
978+
next_proto.status = -1;
979+
if (next_proto_neg_in)
980+
{
981+
next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in);
982+
if (next_proto.data == NULL)
983+
{
984+
BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n");
985+
goto end;
986+
}
987+
}
988+
else
989+
next_proto.data = NULL;
990+
#endif
991+
930992
#ifndef OPENSSL_NO_ENGINE
931993
e = setup_engine(bio_err, engine_id, 1);
932994
if (ssl_client_engine_id)
@@ -1056,6 +1118,11 @@ int MAIN(int argc, char **argv)
10561118
*/
10571119
if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
10581120

1121+
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
1122+
if (next_proto.data)
1123+
SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto);
1124+
#endif
1125+
10591126
if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback);
10601127
if (cipher != NULL)
10611128
if(!SSL_CTX_set_cipher_list(ctx,cipher)) {
@@ -1949,6 +2016,17 @@ static void print_stuff(BIO *bio, SSL *s, int full)
19492016
}
19502017
#endif
19512018

2019+
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
2020+
if (next_proto.status != -1) {
2021+
const unsigned char *proto;
2022+
unsigned int proto_len;
2023+
SSL_get0_next_proto_negotiated(s, &proto, &proto_len);
2024+
BIO_printf(bio, "Next protocol: (%d) ", next_proto.status);
2025+
BIO_write(bio, proto, proto_len);
2026+
BIO_write(bio, "\n", 1);
2027+
}
2028+
#endif
2029+
19522030
SSL_SESSION_print(bio,SSL_get_session(s));
19532031
BIO_printf(bio,"---\n");
19542032
if (peer != NULL)

apps/s_server.c

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,9 @@ static void sv_usage(void)
537537
BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n");
538538
BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n");
539539
BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n");
540+
# ifndef OPENSSL_NO_NEXTPROTONEG
541+
BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n");
542+
# endif
540543
#endif
541544
}
542545

@@ -871,6 +874,26 @@ BIO_printf(err, "cert_status: received %d ids\n", sk_OCSP_RESPID_num(ids));
871874
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
872875
goto done;
873876
}
877+
878+
# ifndef OPENSSL_NO_NEXTPROTONEG
879+
/* This is the context that we pass to next_proto_cb */
880+
typedef struct tlsextnextprotoctx_st {
881+
unsigned char *data;
882+
unsigned int len;
883+
} tlsextnextprotoctx;
884+
885+
static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len, void *arg)
886+
{
887+
tlsextnextprotoctx *next_proto = arg;
888+
889+
*data = next_proto->data;
890+
*len = next_proto->len;
891+
892+
return SSL_TLSEXT_ERR_OK;
893+
}
894+
# endif /* ndef OPENSSL_NO_NEXTPROTONEG */
895+
896+
874897
#endif
875898

876899
int MAIN(int, char **);
@@ -909,9 +932,11 @@ int MAIN(int argc, char *argv[])
909932
#ifndef OPENSSL_NO_TLSEXT
910933
EVP_PKEY *s_key2 = NULL;
911934
X509 *s_cert2 = NULL;
912-
#endif
913-
#ifndef OPENSSL_NO_TLSEXT
914935
tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING};
936+
# ifndef OPENSSL_NO_NEXTPROTONEG
937+
const char *next_proto_neg_in = NULL;
938+
tlsextnextprotoctx next_proto;
939+
# endif
915940
#endif
916941
#ifndef OPENSSL_NO_PSK
917942
/* by default do not send a PSK identity hint */
@@ -1267,7 +1292,13 @@ int MAIN(int argc, char *argv[])
12671292
if (--argc < 1) goto bad;
12681293
s_key_file2= *(++argv);
12691294
}
1270-
1295+
# ifndef OPENSSL_NO_NEXTPROTONEG
1296+
else if (strcmp(*argv,"-nextprotoneg") == 0)
1297+
{
1298+
if (--argc < 1) goto bad;
1299+
next_proto_neg_in = *(++argv);
1300+
}
1301+
# endif
12711302
#endif
12721303
#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
12731304
else if (strcmp(*argv,"-jpake") == 0)
@@ -1372,6 +1403,22 @@ int MAIN(int argc, char *argv[])
13721403
goto end;
13731404
}
13741405
}
1406+
1407+
# ifndef OPENSSL_NO_NEXTPROTONEG
1408+
if (next_proto_neg_in)
1409+
{
1410+
unsigned short len;
1411+
next_proto.data = next_protos_parse(&len,
1412+
next_proto_neg_in);
1413+
if (next_proto.data == NULL)
1414+
goto end;
1415+
next_proto.len = len;
1416+
}
1417+
else
1418+
{
1419+
next_proto.data = NULL;
1420+
}
1421+
# endif
13751422
#endif
13761423
}
13771424

@@ -1552,6 +1599,11 @@ int MAIN(int argc, char *argv[])
15521599
if (vpm)
15531600
SSL_CTX_set1_param(ctx2, vpm);
15541601
}
1602+
1603+
# ifndef OPENSSL_NO_NEXTPROTONEG
1604+
if (next_proto.data)
1605+
SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto);
1606+
# endif
15551607
#endif
15561608

15571609
#ifndef OPENSSL_NO_DH
@@ -2257,6 +2309,10 @@ static int init_ssl_connection(SSL *con)
22572309
#ifndef OPENSSL_NO_KRB5
22582310
char *client_princ;
22592311
#endif
2312+
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
2313+
const unsigned char *next_proto_neg;
2314+
unsigned next_proto_neg_len;
2315+
#endif
22602316

22612317
if ((i=SSL_accept(con)) <= 0)
22622318
{
@@ -2296,6 +2352,15 @@ static int init_ssl_connection(SSL *con)
22962352
BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf);
22972353
str=SSL_CIPHER_get_name(SSL_get_current_cipher(con));
22982354
BIO_printf(bio_s_out,"CIPHER is %s\n",(str != NULL)?str:"(NONE)");
2355+
#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
2356+
SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len);
2357+
if (next_proto_neg)
2358+
{
2359+
BIO_printf(bio_s_out,"NEXTPROTO is ");
2360+
BIO_write(bio_s_out, next_proto_neg, next_proto_neg_len);
2361+
BIO_printf(bio_s_out, "\n");
2362+
}
2363+
#endif
22992364
if (SSL_cache_hit(con)) BIO_printf(bio_s_out,"Reused session-id\n");
23002365
if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) &
23012366
TLS1_FLAGS_TLS_PADDING_BUG)

ssl/s3_both.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,38 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen)
202202
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
203203
}
204204

205+
#ifndef OPENSSL_NO_NEXTPROTONEG
206+
/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen to far. */
207+
static void ssl3_take_mac(SSL *s) {
208+
const char *sender;
209+
int slen;
210+
211+
if (s->state & SSL_ST_CONNECT)
212+
{
213+
sender=s->method->ssl3_enc->server_finished_label;
214+
slen=s->method->ssl3_enc->server_finished_label_len;
215+
}
216+
else
217+
{
218+
sender=s->method->ssl3_enc->client_finished_label;
219+
slen=s->method->ssl3_enc->client_finished_label_len;
220+
}
221+
222+
s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s,
223+
sender,slen,s->s3->tmp.peer_finish_md);
224+
}
225+
#endif
226+
205227
int ssl3_get_finished(SSL *s, int a, int b)
206228
{
207229
int al,i,ok;
208230
long n;
209231
unsigned char *p;
210232

211-
/* the mac has already been generated when we received the
212-
* change cipher spec message and is in s->s3->tmp.peer_finish_md
213-
*/
233+
#ifdef OPENSSL_NO_NEXTPROTONEG
234+
/* the mac has already been generated when we received the change
235+
* cipher spec message and is in s->s3->tmp.peer_finish_md. */
236+
#endif
214237

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

0 commit comments

Comments
 (0)