OLD | NEW |
| (Empty) |
1 commit ed5845e49b3c76f8735ec00e151a7b234acc266c | |
2 Author: Adam Langley <agl@chromium.org> | |
3 Date: Thu Nov 4 16:06:58 2010 -0400 | |
4 | |
5 next_proto_neg.patch | |
6 | |
7 diff --git a/apps/apps.c b/apps/apps.c | |
8 index ab60b70..eede8a8 100644 | |
9 --- a/apps/apps.c | |
10 +++ b/apps/apps.c | |
11 @@ -2579,3 +2579,45 @@ void jpake_server_auth(BIO *out, BIO *conn, const char *s
ecret) | |
12 } | |
13 | |
14 #endif | |
15 + | |
16 +/* next_protos_parse parses a comma separated list of strings into a string | |
17 + * in a format suitable for passing to SSL_CTX_set_next_protos_advertised. | |
18 + * outlen: (output) set to the length of the resulting buffer on success. | |
19 + * err: (maybe NULL) on failure, an error message line is written to this BIO
. | |
20 + * in: a NUL termianted string like "abc,def,ghi" | |
21 + * | |
22 + * returns: a malloced buffer | |
23 + */ | |
24 +unsigned char *next_protos_parse(unsigned short *outlen, const char *in) | |
25 + { | |
26 + size_t len; | |
27 + unsigned char *out; | |
28 + size_t i, start = 0; | |
29 + | |
30 + len = strlen(in); | |
31 + if (len > 65535) | |
32 + return NULL; | |
33 + | |
34 + out = OPENSSL_malloc(strlen(in) + 1); | |
35 + if (!out) | |
36 + return NULL; | |
37 + | |
38 + for (i = 0; i <= len; ++i) | |
39 + { | |
40 + if (i == len || in[i] == ',') | |
41 + { | |
42 + if (i - start > 255) | |
43 + { | |
44 + OPENSSL_free(out); | |
45 + return NULL; | |
46 + } | |
47 + out[start] = i - start; | |
48 + start = i + 1; | |
49 + } | |
50 + else | |
51 + out[i+1] = in[i]; | |
52 + } | |
53 + | |
54 + *outlen = len + 1; | |
55 + return out; | |
56 + } | |
57 diff --git a/apps/s_apps.h b/apps/s_apps.h | |
58 index f5a39ba..513bcfe 100644 | |
59 --- a/apps/s_apps.h | |
60 +++ b/apps/s_apps.h | |
61 @@ -174,3 +174,5 @@ void MS_CALLBACK tlsext_cb(SSL *s, int client_server, int ty
pe, | |
62 | |
63 int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsig
ned int *cookie_len); | |
64 int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigne
d int cookie_len); | |
65 + | |
66 +unsigned char *next_protos_parse(unsigned short *outlen, const char *in); | |
67 diff --git a/apps/s_client.c b/apps/s_client.c | |
68 index c071658..6033e77 100644 | |
69 --- a/apps/s_client.c | |
70 +++ b/apps/s_client.c | |
71 @@ -249,6 +249,7 @@ static void sc_usage(void) | |
72 BIO_printf(bio_err," -status - request certificate status from
server\n"); | |
73 BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis sessi
on tickets\n"); | |
74 BIO_printf(bio_err," -cutthrough - enable 1-RTT full-handshake for
strong ciphers\n"); | |
75 + BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, consideri
ng named protocols supported (comma-separated list)\n"); | |
76 #endif | |
77 BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renego
tiation (dangerous)\n"); | |
78 } | |
79 @@ -284,6 +285,38 @@ enum | |
80 PROTO_XMPP | |
81 }; | |
82 | |
83 +/* This the context that we pass to next_proto_cb */ | |
84 +typedef struct tlsextnextprotoctx_st { | |
85 + unsigned char *data; | |
86 + unsigned short len; | |
87 + int status; | |
88 +} tlsextnextprotoctx; | |
89 + | |
90 +static tlsextnextprotoctx next_proto; | |
91 + | |
92 +static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, co
nst unsigned char *in, unsigned int inlen, void *arg) | |
93 + { | |
94 + tlsextnextprotoctx *ctx = arg; | |
95 + | |
96 + if (!c_quiet) | |
97 + { | |
98 + /* We can assume that |in| is syntactically valid. */ | |
99 + unsigned i; | |
100 + BIO_printf(bio_c_out, "Protocols advertised by server: "); | |
101 + for (i = 0; i < inlen; ) | |
102 + { | |
103 + if (i) | |
104 + BIO_write(bio_c_out, ", ", 2); | |
105 + BIO_write(bio_c_out, &in[i + 1], in[i]); | |
106 + i += in[i] + 1; | |
107 + } | |
108 + BIO_write(bio_c_out, "\n", 1); | |
109 + } | |
110 + | |
111 + ctx->status = SSL_select_next_proto(out, outlen, in, inlen, ctx->data, c
tx->len); | |
112 + return SSL_TLSEXT_ERR_OK; | |
113 + } | |
114 + | |
115 int MAIN(int, char **); | |
116 | |
117 int MAIN(int argc, char **argv) | |
118 @@ -336,6 +369,7 @@ int MAIN(int argc, char **argv) | |
119 char *servername = NULL; | |
120 tlsextctx tlsextcbp = | |
121 {NULL,0}; | |
122 + const char *next_proto_neg_in = NULL; | |
123 #endif | |
124 char *sess_in = NULL; | |
125 char *sess_out = NULL; | |
126 @@ -536,6 +570,11 @@ int MAIN(int argc, char **argv) | |
127 #ifndef OPENSSL_NO_TLSEXT | |
128 else if (strcmp(*argv,"-no_ticket") == 0) | |
129 { off|=SSL_OP_NO_TICKET; } | |
130 + else if (strcmp(*argv,"-nextprotoneg") == 0) | |
131 + { | |
132 + if (--argc < 1) goto bad; | |
133 + next_proto_neg_in = *(++argv); | |
134 + } | |
135 #endif | |
136 else if (strcmp(*argv,"-cutthrough") == 0) | |
137 cutthrough=1; | |
138 @@ -624,6 +663,21 @@ bad: | |
139 OpenSSL_add_ssl_algorithms(); | |
140 SSL_load_error_strings(); | |
141 | |
142 +#ifndef OPENSSL_NO_TLSEXT | |
143 + next_proto.status = -1; | |
144 + if (next_proto_neg_in) | |
145 + { | |
146 + next_proto.data = next_protos_parse(&next_proto.len, next_proto_
neg_in); | |
147 + if (next_proto.data == NULL) | |
148 + { | |
149 + BIO_printf(bio_err, "Error parsing -nextprotoneg argumen
t\n"); | |
150 + goto end; | |
151 + } | |
152 + } | |
153 + else | |
154 + next_proto.data = NULL; | |
155 +#endif | |
156 + | |
157 #ifndef OPENSSL_NO_ENGINE | |
158 e = setup_engine(bio_err, engine_id, 1); | |
159 if (ssl_client_engine_id) | |
160 @@ -738,6 +792,9 @@ bad: | |
161 SSL_CTX_set_mode(ctx, ssl_mode); | |
162 } | |
163 | |
164 + if (next_proto.data) | |
165 + SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto
); | |
166 + | |
167 if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); | |
168 if (cipher != NULL) | |
169 if(!SSL_CTX_set_cipher_list(ctx,cipher)) { | |
170 @@ -1555,6 +1612,20 @@ static void print_stuff(BIO *bio, SSL *s, int full) | |
171 BIO_printf(bio,"Expansion: %s\n", | |
172 expansion ? SSL_COMP_get_name(expansion) : "NONE"); | |
173 #endif | |
174 + | |
175 +#ifndef OPENSSL_NO_TLSEXT | |
176 + { | |
177 + if (next_proto.status != -1) { | |
178 + const unsigned char *proto; | |
179 + unsigned int proto_len; | |
180 + SSL_get0_next_proto_negotiated(s, &proto, &proto_len); | |
181 + BIO_printf(bio, "Next protocol: (%d) ", next_proto.statu
s); | |
182 + BIO_write(bio, proto, proto_len); | |
183 + BIO_write(bio, "\n", 1); | |
184 + } | |
185 + } | |
186 +#endif | |
187 + | |
188 SSL_SESSION_print(bio,SSL_get_session(s)); | |
189 BIO_printf(bio,"---\n"); | |
190 if (peer != NULL) | |
191 diff --git a/apps/s_server.c b/apps/s_server.c | |
192 index 88b308c..c4e19c9 100644 | |
193 --- a/apps/s_server.c | |
194 +++ b/apps/s_server.c | |
195 @@ -405,6 +405,7 @@ static void sv_usage(void) | |
196 BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions rece
ived\n"); | |
197 BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session t
ickets\n"); | |
198 BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renego
tiation (dangerous)\n"); | |
199 + BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols fo
r the NPN extension (comma-separated list)\n"); | |
200 #endif | |
201 } | |
202 | |
203 @@ -740,6 +741,26 @@ BIO_printf(err, "cert_status: received %d ids\n", sk_OCSP_R
ESPID_num(ids)); | |
204 goto done; | |
205 } | |
206 #endif | |
207 + | |
208 + | |
209 +/* This the context that we pass to next_proto_cb */ | |
210 +typedef struct tlsextnextprotoctx_st { | |
211 + unsigned char *data; | |
212 + unsigned int len; | |
213 +} tlsextnextprotoctx; | |
214 + | |
215 + | |
216 +static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
void *arg) | |
217 + { | |
218 + tlsextnextprotoctx *next_proto = arg; | |
219 + | |
220 + *data = next_proto->data; | |
221 + *len = next_proto->len; | |
222 + | |
223 + return SSL_TLSEXT_ERR_OK; | |
224 + } | |
225 + | |
226 + | |
227 int MAIN(int, char **); | |
228 | |
229 #ifndef OPENSSL_NO_JPAKE | |
230 @@ -779,6 +800,8 @@ int MAIN(int argc, char *argv[]) | |
231 #endif | |
232 #ifndef OPENSSL_NO_TLSEXT | |
233 tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING}; | |
234 + const char *next_proto_neg_in = NULL; | |
235 + tlsextnextprotoctx next_proto; | |
236 #endif | |
237 | |
238 #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) | |
239 @@ -1077,7 +1100,11 @@ int MAIN(int argc, char *argv[]) | |
240 if (--argc < 1) goto bad; | |
241 s_key_file2= *(++argv); | |
242 } | |
243 - | |
244 + else if (strcmp(*argv,"-nextprotoneg") == 0) | |
245 + { | |
246 + if (--argc < 1) goto bad; | |
247 + next_proto_neg_in = *(++argv); | |
248 + } | |
249 #endif | |
250 #ifndef OPENSSL_NO_JPAKE | |
251 else if (strcmp(*argv,"-jpake") == 0) | |
252 @@ -1162,6 +1189,20 @@ bad: | |
253 goto end; | |
254 } | |
255 } | |
256 + | |
257 + if (next_proto_neg_in) | |
258 + { | |
259 + unsigned short len; | |
260 + next_proto.data = next_protos_parse(&len, | |
261 + next_proto_neg_in); | |
262 + if (next_proto.data == NULL) | |
263 + goto end; | |
264 + next_proto.len = len; | |
265 + } | |
266 + else | |
267 + { | |
268 + next_proto.data = NULL; | |
269 + } | |
270 #endif | |
271 } | |
272 if (s_dcert_file) | |
273 @@ -1341,6 +1382,11 @@ bad: | |
274 store = SSL_CTX_get_cert_store(ctx2); | |
275 X509_STORE_set_flags(store, vflags); | |
276 } | |
277 + | |
278 + if (next_proto.data) | |
279 + { | |
280 + SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_
proto); | |
281 + } | |
282 #endif | |
283 | |
284 | |
285 @@ -1980,6 +2026,10 @@ static int init_ssl_connection(SSL *con) | |
286 X509 *peer; | |
287 long verify_error; | |
288 MS_STATIC char buf[BUFSIZ]; | |
289 +#ifndef OPENSSL_NO_TLSEXT | |
290 + const unsigned char *next_proto_neg; | |
291 + unsigned next_proto_neg_len; | |
292 +#endif | |
293 | |
294 if ((i=SSL_accept(con)) <= 0) | |
295 { | |
296 @@ -2019,6 +2069,14 @@ static int init_ssl_connection(SSL *con) | |
297 BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf); | |
298 str=SSL_CIPHER_get_name(SSL_get_current_cipher(con)); | |
299 BIO_printf(bio_s_out,"CIPHER is %s\n",(str != NULL)?str:"(NONE)"); | |
300 +#ifndef OPENSSL_NO_TLSEXT | |
301 + SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len
); | |
302 + if (next_proto_neg) { | |
303 + BIO_printf(bio_s_out,"NEXTPROTO is "); | |
304 + BIO_write(bio_s_out, next_proto_neg, next_proto_neg_len); | |
305 + BIO_printf(bio_s_out, "\n"); | |
306 + } | |
307 +#endif | |
308 if (con->hit) BIO_printf(bio_s_out,"Reused session-id\n"); | |
309 if (SSL_ctrl(con,SSL_CTRL_GET_FLAGS,0,NULL) & | |
310 TLS1_FLAGS_TLS_PADDING_BUG) | |
311 diff --git a/ssl/s3_both.c b/ssl/s3_both.c | |
312 index 869a25d..b88288e 100644 | |
313 --- a/ssl/s3_both.c | |
314 +++ b/ssl/s3_both.c | |
315 @@ -204,16 +204,34 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *s
ender, int slen) | |
316 return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); | |
317 } | |
318 | |
319 +/* ssl3_take_mac calculates the Finished MAC for the handshakes messages seen t
o far. */ | |
320 +void ssl3_take_mac(SSL *s) { | |
321 + const char *sender; | |
322 + int slen; | |
323 + | |
324 + if (s->state & SSL_ST_CONNECT) | |
325 + { | |
326 + sender=s->method->ssl3_enc->server_finished_label; | |
327 + slen=s->method->ssl3_enc->server_finished_label_len; | |
328 + } | |
329 + else | |
330 + { | |
331 + sender=s->method->ssl3_enc->client_finished_label; | |
332 + slen=s->method->ssl3_enc->client_finished_label_len; | |
333 + } | |
334 + | |
335 + s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s, | |
336 + &(s->s3->finish_dgst1), | |
337 + &(s->s3->finish_dgst2), | |
338 + sender,slen,s->s3->tmp.peer_finish_md); | |
339 +} | |
340 + | |
341 int ssl3_get_finished(SSL *s, int a, int b) | |
342 { | |
343 int al,i,ok; | |
344 long n; | |
345 unsigned char *p; | |
346 | |
347 - /* the mac has already been generated when we received the | |
348 - * change cipher spec message and is in s->s3->tmp.peer_finish_md | |
349 - */ | |
350 - | |
351 n=s->method->ssl_get_message(s, | |
352 a, | |
353 b, | |
354 @@ -516,6 +534,11 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, lon
g max, int *ok) | |
355 s->init_num += i; | |
356 n -= i; | |
357 } | |
358 + /* If receiving Finished, record MAC of prior handshake messages for | |
359 + * Finished verification. */ | |
360 + if (*s->init_buf->data == SSL3_MT_FINISHED) | |
361 + ssl3_take_mac(s); | |
362 + /* Feed this message into MAC computation. */ | |
363 ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num + 4); | |
364 if (s->msg_callback) | |
365 s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->d
ata, (size_t)s->init_num + 4, s, s->msg_callback_arg); | |
366 diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c | |
367 index 6173dbe..f9e1554 100644 | |
368 --- a/ssl/s3_clnt.c | |
369 +++ b/ssl/s3_clnt.c | |
370 @@ -404,7 +404,11 @@ int ssl3_connect(SSL *s) | |
371 ret=ssl3_send_change_cipher_spec(s, | |
372 SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); | |
373 if (ret <= 0) goto end; | |
374 - s->state=SSL3_ST_CW_FINISHED_A; | |
375 + | |
376 + if (s->next_proto_negotiated) | |
377 + s->state=SSL3_ST_CW_NEXT_PROTO_A; | |
378 + else | |
379 + s->state=SSL3_ST_CW_FINISHED_A; | |
380 s->init_num=0; | |
381 | |
382 s->session->cipher=s->s3->tmp.new_cipher; | |
383 @@ -432,6 +436,13 @@ int ssl3_connect(SSL *s) | |
384 | |
385 break; | |
386 | |
387 + case SSL3_ST_CW_NEXT_PROTO_A: | |
388 + case SSL3_ST_CW_NEXT_PROTO_B: | |
389 + ret=ssl3_send_next_proto(s); | |
390 + if (ret <= 0) goto end; | |
391 + s->state=SSL3_ST_CW_FINISHED_A; | |
392 + break; | |
393 + | |
394 case SSL3_ST_CW_FINISHED_A: | |
395 case SSL3_ST_CW_FINISHED_B: | |
396 ret=ssl3_send_finished(s, | |
397 @@ -2752,6 +2763,30 @@ static int curve_id2nid(int curve_id) | |
398 } | |
399 #endif | |
400 | |
401 +int ssl3_send_next_proto(SSL *s) | |
402 + { | |
403 + unsigned int len, padding_len; | |
404 + unsigned char *d; | |
405 + | |
406 + if (s->state == SSL3_ST_CW_NEXT_PROTO_A) | |
407 + { | |
408 + len = s->next_proto_negotiated_len; | |
409 + padding_len = 32 - ((len + 2) % 32); | |
410 + d = (unsigned char *)s->init_buf->data; | |
411 + d[4] = len; | |
412 + memcpy(d + 5, s->next_proto_negotiated, len); | |
413 + d[5 + len] = padding_len; | |
414 + memset(d + 6 + len, 0, padding_len); | |
415 + *(d++)=SSL3_MT_NEXT_PROTO; | |
416 + l2n3(2 + len + padding_len, d); | |
417 + s->state = SSL3_ST_CW_NEXT_PROTO_B; | |
418 + s->init_num = 4 + 2 + len + padding_len; | |
419 + s->init_off = 0; | |
420 + } | |
421 + | |
422 + return ssl3_do_write(s, SSL3_RT_HANDSHAKE); | |
423 +} | |
424 + | |
425 /* Check to see if handshake is full or resumed. Usually this is just a | |
426 * case of checking to see if a cache hit has occurred. In the case of | |
427 * session tickets we have to check the next message to be sure. | |
428 diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c | |
429 index 2c44bde..84bff8d 100644 | |
430 --- a/ssl/s3_lib.c | |
431 +++ b/ssl/s3_lib.c | |
432 @@ -1751,6 +1751,14 @@ void ssl3_clear(SSL *s) | |
433 s->s3->num_renegotiations=0; | |
434 s->s3->in_read_app_data=0; | |
435 s->version=SSL3_VERSION; | |
436 + | |
437 +#ifndef OPENSSL_NO_TLSEXT | |
438 + if (s->next_proto_negotiated) { | |
439 + OPENSSL_free(s->next_proto_negotiated); | |
440 + s->next_proto_negotiated = 0; | |
441 + s->next_proto_negotiated_len = 0; | |
442 + } | |
443 +#endif | |
444 } | |
445 | |
446 long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) | |
447 diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c | |
448 index 5e3583c..6853058 100644 | |
449 --- a/ssl/s3_pkt.c | |
450 +++ b/ssl/s3_pkt.c | |
451 @@ -1264,8 +1264,6 @@ err: | |
452 int ssl3_do_change_cipher_spec(SSL *s) | |
453 { | |
454 int i; | |
455 - const char *sender; | |
456 - int slen; | |
457 | |
458 if (s->state & SSL_ST_ACCEPT) | |
459 i=SSL3_CHANGE_CIPHER_SERVER_READ; | |
460 @@ -1288,25 +1286,6 @@ int ssl3_do_change_cipher_spec(SSL *s) | |
461 if (!s->method->ssl3_enc->change_cipher_state(s,i)) | |
462 return(0); | |
463 | |
464 - /* we have to record the message digest at | |
465 - * this point so we can get it before we read | |
466 - * the finished message */ | |
467 - if (s->state & SSL_ST_CONNECT) | |
468 - { | |
469 - sender=s->method->ssl3_enc->server_finished_label; | |
470 - slen=s->method->ssl3_enc->server_finished_label_len; | |
471 - } | |
472 - else | |
473 - { | |
474 - sender=s->method->ssl3_enc->client_finished_label; | |
475 - slen=s->method->ssl3_enc->client_finished_label_len; | |
476 - } | |
477 - | |
478 - s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s, | |
479 - &(s->s3->finish_dgst1), | |
480 - &(s->s3->finish_dgst2), | |
481 - sender,slen,s->s3->tmp.peer_finish_md); | |
482 - | |
483 return(1); | |
484 } | |
485 | |
486 diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c | |
487 index e696450..8e0a504 100644 | |
488 --- a/ssl/s3_srvr.c | |
489 +++ b/ssl/s3_srvr.c | |
490 @@ -499,7 +499,10 @@ int ssl3_accept(SSL *s) | |
491 * a certificate, the CertificateVerify | |
492 * message is not sent. | |
493 */ | |
494 - s->state=SSL3_ST_SR_FINISHED_A; | |
495 + if (s->s3->next_proto_neg_seen) | |
496 + s->state=SSL3_ST_SR_NEXT_PROTO_A; | |
497 + else | |
498 + s->state=SSL3_ST_SR_FINISHED_A; | |
499 s->init_num = 0; | |
500 } | |
501 else | |
502 @@ -526,10 +529,21 @@ int ssl3_accept(SSL *s) | |
503 ret=ssl3_get_cert_verify(s); | |
504 if (ret <= 0) goto end; | |
505 | |
506 - s->state=SSL3_ST_SR_FINISHED_A; | |
507 + if (s->s3->next_proto_neg_seen) | |
508 + s->state=SSL3_ST_SR_NEXT_PROTO_A; | |
509 + else | |
510 + s->state=SSL3_ST_SR_FINISHED_A; | |
511 s->init_num=0; | |
512 break; | |
513 | |
514 + case SSL3_ST_SR_NEXT_PROTO_A: | |
515 + case SSL3_ST_SR_NEXT_PROTO_B: | |
516 + ret=ssl3_get_next_proto(s); | |
517 + if (ret <= 0) goto end; | |
518 + s->init_num = 0; | |
519 + s->state=SSL3_ST_SR_FINISHED_A; | |
520 + break; | |
521 + | |
522 case SSL3_ST_SR_FINISHED_A: | |
523 case SSL3_ST_SR_FINISHED_B: | |
524 ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A, | |
525 @@ -597,7 +611,12 @@ int ssl3_accept(SSL *s) | |
526 if (ret <= 0) goto end; | |
527 s->state=SSL3_ST_SW_FLUSH; | |
528 if (s->hit) | |
529 - s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A; | |
530 + { | |
531 + if (s->s3->next_proto_neg_seen) | |
532 + s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PR
OTO_A; | |
533 + else | |
534 + s->s3->tmp.next_state=SSL3_ST_SR_FINISHE
D_A; | |
535 + } | |
536 else | |
537 s->s3->tmp.next_state=SSL_ST_OK; | |
538 s->init_num=0; | |
539 @@ -2324,6 +2343,70 @@ err: | |
540 return(-1); | |
541 } | |
542 | |
543 +/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It | |
544 + * sets the next_proto member in s if found */ | |
545 +int ssl3_get_next_proto(SSL *s) | |
546 + { | |
547 + int ok; | |
548 + unsigned proto_len, padding_len; | |
549 + long n; | |
550 + const unsigned char *p; | |
551 + | |
552 + /* Clients cannot send a NextProtocol message if we didn't see the | |
553 + * extension in their ClientHello */ | |
554 + if (!s->s3->next_proto_neg_seen) { | |
555 + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_WITHOUT_EX
TENSION); | |
556 + return -1; | |
557 + } | |
558 + | |
559 + n=s->method->ssl_get_message(s, | |
560 + SSL3_ST_SR_NEXT_PROTO_A, | |
561 + SSL3_ST_SR_NEXT_PROTO_B, | |
562 + SSL3_MT_NEXT_PROTO, | |
563 + 129, | |
564 + &ok); | |
565 + | |
566 + if (!ok) | |
567 + return((int)n); | |
568 + | |
569 + /* s->state doesn't reflect whether ChangeCipherSpec has been received | |
570 + * in this handshake, but s->s3->change_cipher_spec does (will be reset | |
571 + * by ssl3_get_finished). */ | |
572 + if (!s->s3->change_cipher_spec) | |
573 + { | |
574 + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_BEFORE_A_C
CS); | |
575 + return -1; | |
576 + } | |
577 + | |
578 + if (n < 2) | |
579 + return 0; // The body must be > 1 bytes long */ | |
580 + | |
581 + p=(unsigned char *)s->init_msg; | |
582 + | |
583 + /* The payload looks like: | |
584 + * uint8 proto_len; | |
585 + * uint8 proto[proto_len]; | |
586 + * uint8 padding_len; | |
587 + * uint8 padding[padding_len]; | |
588 + */ | |
589 + proto_len = p[0]; | |
590 + if (proto_len + 2 > s->init_num) | |
591 + return 0; | |
592 + padding_len = p[proto_len + 1]; | |
593 + if (proto_len + padding_len + 2 != s->init_num) | |
594 + return 0; | |
595 + | |
596 + s->next_proto_negotiated = OPENSSL_malloc(proto_len); | |
597 + if (!s->next_proto_negotiated) { | |
598 + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,ERR_R_MALLOC_FAILURE); | |
599 + return 0; | |
600 + } | |
601 + memcpy(s->next_proto_negotiated, p + 1, proto_len); | |
602 + s->next_proto_negotiated_len = proto_len; | |
603 + | |
604 + return 1; | |
605 + } | |
606 + | |
607 int ssl3_get_cert_verify(SSL *s) | |
608 { | |
609 EVP_PKEY *pkey=NULL; | |
610 diff --git a/ssl/ssl.h b/ssl/ssl.h | |
611 index 9ab9495..dc8dff8 100644 | |
612 --- a/ssl/ssl.h | |
613 +++ b/ssl/ssl.h | |
614 @@ -801,6 +801,23 @@ struct ssl_ctx_st | |
615 /* Callback for status request */ | |
616 int (*tlsext_status_cb)(SSL *ssl, void *arg); | |
617 void *tlsext_status_arg; | |
618 + | |
619 + /* Next protocol negotiation information */ | |
620 + /* (for experimental NPN extension). */ | |
621 + | |
622 + /* For a server, this contains a callback function by which the set of | |
623 + * advertised protocols can be provided. */ | |
624 + int (*next_protos_advertised_cb)(SSL *s, const unsigned char **buf, | |
625 + unsigned int *len, void *arg); | |
626 + void *next_protos_advertised_cb_arg; | |
627 + /* For a client, this contains a callback function that selects the | |
628 + * next protocol from the list provided by the server. */ | |
629 + int (*next_proto_select_cb)(SSL *s, unsigned char **out, | |
630 + unsigned char *outlen, | |
631 + const unsigned char *in, | |
632 + unsigned int inlen, | |
633 + void *arg); | |
634 + void *next_proto_select_cb_arg; | |
635 #endif | |
636 | |
637 }; | |
638 @@ -857,6 +874,15 @@ int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e)
; | |
639 #endif | |
640 void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL
*ssl, unsigned char *cookie, unsigned int *cookie_len)); | |
641 void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL
*ssl, unsigned char *cookie, unsigned int cookie_len)); | |
642 +void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s, int (*cb) (SSL *ssl, con
st unsigned char **out, unsigned int *outlen, void *arg), void *arg); | |
643 +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *s, int (*cb) (SSL *ssl, unsigned
char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen,
void *arg), void *arg); | |
644 + | |
645 +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const uns
igned char *in, unsigned int inlen, const unsigned char *client, unsigned int cl
ient_len); | |
646 +void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, u
nsigned *len); | |
647 + | |
648 +#define OPENSSL_NPN_UNSUPPORTED 0 | |
649 +#define OPENSSL_NPN_NEGOTIATED 1 | |
650 +#define OPENSSL_NPN_NO_OVERLAP 2 | |
651 | |
652 #define SSL_NOTHING 1 | |
653 #define SSL_WRITING 2 | |
654 @@ -1054,6 +1080,16 @@ struct ssl_st | |
655 /* RFC4507 session ticket expected to be received or sent */ | |
656 int tlsext_ticket_expected; | |
657 SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ | |
658 + | |
659 + /* Next protocol negotiation. For the client, this is the protocol that | |
660 + * we sent in NextProtocol and is set when handling ServerHello | |
661 + * extensions. | |
662 + * | |
663 + * For a server, this is the client's selected_protocol from | |
664 + * NextProtocol and is set when handling the NextProtocol message, | |
665 + * before the Finished message. */ | |
666 + unsigned char *next_proto_negotiated; | |
667 + unsigned char next_proto_negotiated_len; | |
668 #define session_ctx initial_ctx | |
669 #else | |
670 #define session_ctx ctx | |
671 @@ -1761,6 +1797,7 @@ void ERR_load_SSL_strings(void); | |
672 #define SSL_F_SSL3_GET_KEY_EXCHANGE 141 | |
673 #define SSL_F_SSL3_GET_MESSAGE 142 | |
674 #define SSL_F_SSL3_GET_NEW_SESSION_TICKET 283 | |
675 +#define SSL_F_SSL3_GET_NEXT_PROTO 297 | |
676 #define SSL_F_SSL3_GET_RECORD 143 | |
677 #define SSL_F_SSL3_GET_SERVER_CERTIFICATE 144 | |
678 #define SSL_F_SSL3_GET_SERVER_DONE 145 | |
679 @@ -1827,6 +1864,7 @@ void ERR_load_SSL_strings(void); | |
680 #define SSL_F_SSL_INIT_WBIO_BUFFER 184 | |
681 #define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185 | |
682 #define SSL_F_SSL_NEW 186 | |
683 +#define SSL_F_SSL_NEXT_PROTOS_PARSE 298 | |
684 #define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 287 | |
685 #define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 290 | |
686 #define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 289 | |
687 @@ -1869,6 +1907,7 @@ void ERR_load_SSL_strings(void); | |
688 #define SSL_F_TLS1_ENC 210 | |
689 #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 | |
690 #define SSL_F_WRITE_PENDING 212 | |
691 +/* Next entry: 299 */ | |
692 | |
693 /* Reason codes. */ | |
694 #define SSL_R_APP_DATA_IN_HANDSHAKE 100 | |
695 @@ -1939,6 +1978,8 @@ void ERR_load_SSL_strings(void); | |
696 #define SSL_R_EXCESSIVE_MESSAGE_SIZE 152 | |
697 #define SSL_R_EXTRA_DATA_IN_MESSAGE 153 | |
698 #define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154 | |
699 +#define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 334 | |
700 +#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 335 | |
701 #define SSL_R_HTTPS_PROXY_REQUEST 155 | |
702 #define SSL_R_HTTP_REQUEST 156 | |
703 #define SSL_R_ILLEGAL_PADDING 283 | |
704 @@ -2120,6 +2161,7 @@ void ERR_load_SSL_strings(void); | |
705 #define SSL_R_WRONG_VERSION_NUMBER 267 | |
706 #define SSL_R_X509_LIB 268 | |
707 #define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269 | |
708 +/* Next entry: 335 or 1115 */ | |
709 | |
710 #ifdef __cplusplus | |
711 } | |
712 diff --git a/ssl/ssl3.h b/ssl/ssl3.h | |
713 index afbdd70..54b73b7 100644 | |
714 --- a/ssl/ssl3.h | |
715 +++ b/ssl/ssl3.h | |
716 @@ -394,6 +394,9 @@ typedef struct ssl3_state_st | |
717 | |
718 int in_read_app_data; | |
719 | |
720 + /* Set if we saw the Next Protocol Negotiation extension from our peer.
*/ | |
721 + int next_proto_neg_seen; | |
722 + | |
723 struct { | |
724 /* actually only needs to be 16+20 */ | |
725 unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2]; | |
726 @@ -484,6 +487,8 @@ typedef struct ssl3_state_st | |
727 #define SSL3_ST_CW_CERT_VRFY_B (0x191|SSL_ST_CONNECT) | |
728 #define SSL3_ST_CW_CHANGE_A (0x1A0|SSL_ST_CONNECT) | |
729 #define SSL3_ST_CW_CHANGE_B (0x1A1|SSL_ST_CONNECT) | |
730 +#define SSL3_ST_CW_NEXT_PROTO_A (0x200|SSL_ST_CONNECT) | |
731 +#define SSL3_ST_CW_NEXT_PROTO_B (0x201|SSL_ST_CONNECT) | |
732 #define SSL3_ST_CW_FINISHED_A (0x1B0|SSL_ST_CONNECT) | |
733 #define SSL3_ST_CW_FINISHED_B (0x1B1|SSL_ST_CONNECT) | |
734 /* read from server */ | |
735 @@ -529,6 +534,8 @@ typedef struct ssl3_state_st | |
736 #define SSL3_ST_SR_CERT_VRFY_B (0x1A1|SSL_ST_ACCEPT) | |
737 #define SSL3_ST_SR_CHANGE_A (0x1B0|SSL_ST_ACCEPT) | |
738 #define SSL3_ST_SR_CHANGE_B (0x1B1|SSL_ST_ACCEPT) | |
739 +#define SSL3_ST_SR_NEXT_PROTO_A (0x210|SSL_ST_ACCEPT) | |
740 +#define SSL3_ST_SR_NEXT_PROTO_B (0x211|SSL_ST_ACCEPT) | |
741 #define SSL3_ST_SR_FINISHED_A (0x1C0|SSL_ST_ACCEPT) | |
742 #define SSL3_ST_SR_FINISHED_B (0x1C1|SSL_ST_ACCEPT) | |
743 /* write to client */ | |
744 @@ -553,6 +560,7 @@ typedef struct ssl3_state_st | |
745 #define SSL3_MT_CLIENT_KEY_EXCHANGE 16 | |
746 #define SSL3_MT_FINISHED 20 | |
747 #define SSL3_MT_CERTIFICATE_STATUS 22 | |
748 +#define SSL3_MT_NEXT_PROTO 67 | |
749 #define DTLS1_MT_HELLO_VERIFY_REQUEST 3 | |
750 | |
751 | |
752 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c | |
753 index 7eb5202..ff9c856 100644 | |
754 --- a/ssl/ssl_err.c | |
755 +++ b/ssl/ssl_err.c | |
756 @@ -154,6 +154,7 @@ static ERR_STRING_DATA SSL_str_functs[]= | |
757 {ERR_FUNC(SSL_F_SSL3_GET_KEY_EXCHANGE), "SSL3_GET_KEY_EXCHANGE"}, | |
758 {ERR_FUNC(SSL_F_SSL3_GET_MESSAGE), "SSL3_GET_MESSAGE"}, | |
759 {ERR_FUNC(SSL_F_SSL3_GET_NEW_SESSION_TICKET), "SSL3_GET_NEW_SESSION_TICKET"}, | |
760 +{ERR_FUNC(SSL_F_SSL3_GET_NEXT_PROTO), "SSL3_GET_NEXT_PROTO"}, | |
761 {ERR_FUNC(SSL_F_SSL3_GET_RECORD), "SSL3_GET_RECORD"}, | |
762 {ERR_FUNC(SSL_F_SSL3_GET_SERVER_CERTIFICATE), "SSL3_GET_SERVER_CERTIFICATE"}, | |
763 {ERR_FUNC(SSL_F_SSL3_GET_SERVER_DONE), "SSL3_GET_SERVER_DONE"}, | |
764 @@ -220,6 +221,7 @@ static ERR_STRING_DATA SSL_str_functs[]= | |
765 {ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "SSL_INIT_WBIO_BUFFER"}, | |
766 {ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE), "SSL_load_client_CA_file"}, | |
767 {ERR_FUNC(SSL_F_SSL_NEW), "SSL_new"}, | |
768 +{ERR_FUNC(SSL_F_SSL_NEXT_PROTOS_PARSE), "SSL_next_protos_parse"}, | |
769 {ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT), "SSL_PARSE_CLIEN
THELLO_RENEGOTIATE_EXT"}, | |
770 {ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT), "SSL_PARSE_CLIENTHELLO_TLSEXT"}, | |
771 {ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT), "SSL_PARSE_SERVE
RHELLO_RENEGOTIATE_EXT"}, | |
772 @@ -335,6 +337,8 @@ static ERR_STRING_DATA SSL_str_reasons[]= | |
773 {ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE),"excessive message size"}, | |
774 {ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE) ,"extra data in message"}, | |
775 {ERR_REASON(SSL_R_GOT_A_FIN_BEFORE_A_CCS),"got a fin before a ccs"}, | |
776 +{ERR_REASON(SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS),"got next proto before a ccs"}, | |
777 +{ERR_REASON(SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION),"got next proto without see
ing extension"}, | |
778 {ERR_REASON(SSL_R_HTTPS_PROXY_REQUEST) ,"https proxy request"}, | |
779 {ERR_REASON(SSL_R_HTTP_REQUEST) ,"http request"}, | |
780 {ERR_REASON(SSL_R_ILLEGAL_PADDING) ,"illegal padding"}, | |
781 diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c | |
782 index 96e056d..cfa70ec 100644 | |
783 --- a/ssl/ssl_lib.c | |
784 +++ b/ssl/ssl_lib.c | |
785 @@ -323,6 +323,7 @@ SSL *SSL_new(SSL_CTX *ctx) | |
786 s->tlsext_ocsp_resplen = -1; | |
787 CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); | |
788 s->initial_ctx=ctx; | |
789 + s->next_proto_negotiated = NULL; | |
790 #endif | |
791 s->verify_result=X509_V_OK; | |
792 | |
793 @@ -532,6 +533,11 @@ void SSL_free(SSL *s) | |
794 kssl_ctx_free(s->kssl_ctx); | |
795 #endif /* OPENSSL_NO_KRB5 */ | |
796 | |
797 +#ifndef OPENSSL_NO_TLSEXT | |
798 + if (s->next_proto_negotiated) | |
799 + OPENSSL_free(s->next_proto_negotiated); | |
800 +#endif | |
801 + | |
802 OPENSSL_free(s); | |
803 } | |
804 | |
805 @@ -1576,6 +1582,8 @@ SSL_CTX *SSL_CTX_new(SSL_METHOD *meth) | |
806 ret->tlsext_status_cb = 0; | |
807 ret->tlsext_status_arg = NULL; | |
808 | |
809 + ret->next_protos_advertised_cb = 0; | |
810 + ret->next_proto_select_cb = 0; | |
811 #endif | |
812 | |
813 #ifndef OPENSSL_NO_ENGINE | |
814 @@ -1677,6 +1685,7 @@ void SSL_CTX_free(SSL_CTX *a) | |
815 if (a->client_cert_engine) | |
816 ENGINE_finish(a->client_cert_engine); | |
817 #endif | |
818 + | |
819 OPENSSL_free(a); | |
820 } | |
821 | |
822 @@ -2752,6 +2761,123 @@ void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write
_p, int version, int con | |
823 SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); | |
824 } | |
825 | |
826 +#ifndef OPENSSL_NO_TLSEXT | |
827 +/* SSL_select_next_proto implements the standard protocol selection. It is | |
828 + * expected that this function is called from the callback set by | |
829 + * SSL_CTX_set_next_proto_select_cb. | |
830 + * | |
831 + * The protocol data is assumed to be a vector of 8-bit, length prefixed byte | |
832 + * strings. The length byte itself is not included in the length. A byte | |
833 + * string of length 0 is invalid. No byte string may be truncated. | |
834 + * | |
835 + * The current, but experimental algorithm for selecting the protocol is: | |
836 + * | |
837 + * 1) If the server doesn't support NPN then this is indicated to the | |
838 + * callback. In this case, the client application has to abort the connection | |
839 + * or have a default application level protocol. | |
840 + * | |
841 + * 2) If the server supports NPN, but advertises an empty list then the | |
842 + * client selects the first protcol in its list, but indicates via the | |
843 + * API that this fallback case was enacted. | |
844 + * | |
845 + * 3) Otherwise, the client finds the first protocol in the server's list | |
846 + * that it supports and selects this protocol. This is because it's | |
847 + * assumed that the server has better information about which protocol | |
848 + * a client should use. | |
849 + * | |
850 + * 4) If the client doesn't support any of the server's advertised | |
851 + * protocols, then this is treated the same as case 2. | |
852 + * | |
853 + * It returns either | |
854 + * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or | |
855 + * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached. | |
856 + */ | |
857 +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const uns
igned char *server, unsigned int server_len, const unsigned char *client, unsign
ed int client_len) | |
858 + { | |
859 + unsigned int i, j; | |
860 + const unsigned char *result; | |
861 + int status = OPENSSL_NPN_UNSUPPORTED; | |
862 + | |
863 + /* For each protocol in server preference order, see if we support it. *
/ | |
864 + for (i = 0; i < server_len; ) | |
865 + { | |
866 + for (j = 0; j < client_len; ) | |
867 + { | |
868 + if (server[i] == client[j] && | |
869 + memcmp(&server[i+1], &client[j+1], server[i]) == 0) | |
870 + { | |
871 + /* We found a match */ | |
872 + result = &server[i]; | |
873 + status = OPENSSL_NPN_NEGOTIATED; | |
874 + goto found; | |
875 + } | |
876 + j += client[j]; | |
877 + j++; | |
878 + } | |
879 + i += server[i]; | |
880 + i++; | |
881 + } | |
882 + | |
883 + /* There's no overlap between our protocols and the server's list. */ | |
884 + result = client; | |
885 + status = OPENSSL_NPN_NO_OVERLAP; | |
886 + | |
887 + found: | |
888 + *out = (unsigned char *) result + 1; | |
889 + *outlen = result[0]; | |
890 + return status; | |
891 + } | |
892 + | |
893 +/* SSL_get0_next_proto_negotiated sets *data and *len to point to the client's | |
894 + * requested protocol for this connection and returns 0. If the client didn't | |
895 + * request any protocol, then *data is set to NULL. | |
896 + * | |
897 + * Note that the client can request any protocol it chooses. The value returned | |
898 + * from this function need not be a member of the list of supported protocols | |
899 + * provided by the callback. | |
900 + */ | |
901 +void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, u
nsigned *len) | |
902 + { | |
903 + *data = s->next_proto_negotiated; | |
904 + if (!*data) { | |
905 + *len = 0; | |
906 + } else { | |
907 + *len = s->next_proto_negotiated_len; | |
908 + } | |
909 +} | |
910 + | |
911 +/* SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when a | |
912 + * TLS server needs a list of supported protocols for Next Protocol | |
913 + * Negotiation. The returned list must be in wire format. The list is returned | |
914 + * by setting |out| to point to it and |outlen| to its length. This memory will | |
915 + * not be modified, but one should assume that the SSL* keeps a reference to | |
916 + * it. | |
917 + * | |
918 + * The callback should return SSL_TLSEXT_ERR_OK if it wishes to advertise. Othe
rwise, no | |
919 + * such extension will be included in the ServerHello. */ | |
920 +void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *ctx, int (*cb) (SSL *ssl, c
onst unsigned char **out, unsigned int *outlen, void *arg), void *arg) | |
921 + { | |
922 + ctx->next_protos_advertised_cb = cb; | |
923 + ctx->next_protos_advertised_cb_arg = arg; | |
924 + } | |
925 + | |
926 +/* SSL_CTX_set_next_proto_select_cb sets a callback that is called when a | |
927 + * client needs to select a protocol from the server's provided list. |out| | |
928 + * must be set to point to the selected protocol (which may be within |in|). | |
929 + * The length of the protocol name must be written into |outlen|. The server's | |
930 + * advertised protocols are provided in |in| and |inlen|. The callback can | |
931 + * assume that |in| is syntactically valid. | |
932 + * | |
933 + * The client must select a protocol. It is fatal to the connection if this | |
934 + * callback returns a value other than SSL_TLSEXT_ERR_OK. | |
935 + */ | |
936 +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned
char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen,
void *arg), void *arg) | |
937 + { | |
938 + ctx->next_proto_select_cb = cb; | |
939 + ctx->next_proto_select_cb_arg = arg; | |
940 + } | |
941 +#endif | |
942 + | |
943 int SSL_cutthrough_complete(const SSL *s) | |
944 { | |
945 return (!s->server && /* cutthrough only applies to clie
nts */ | |
946 diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h | |
947 index e305db4..a9183ff 100644 | |
948 --- a/ssl/ssl_locl.h | |
949 +++ b/ssl/ssl_locl.h | |
950 @@ -895,6 +895,7 @@ int ssl3_get_server_certificate(SSL *s); | |
951 int ssl3_check_cert_and_algorithm(SSL *s); | |
952 #ifndef OPENSSL_NO_TLSEXT | |
953 int ssl3_check_finished(SSL *s); | |
954 +int ssl3_send_next_proto(SSL *s); | |
955 #endif | |
956 | |
957 int dtls1_client_hello(SSL *s); | |
958 @@ -913,6 +914,7 @@ int ssl3_check_client_hello(SSL *s); | |
959 int ssl3_get_client_certificate(SSL *s); | |
960 int ssl3_get_client_key_exchange(SSL *s); | |
961 int ssl3_get_cert_verify(SSL *s); | |
962 +int ssl3_get_next_proto(SSL *s); | |
963 | |
964 int dtls1_send_hello_request(SSL *s); | |
965 int dtls1_send_server_hello(SSL *s); | |
966 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c | |
967 index 8b53112..fd35b18 100644 | |
968 --- a/ssl/t1_lib.c | |
969 +++ b/ssl/t1_lib.c | |
970 @@ -271,6 +271,16 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned
char *p, unsigned cha | |
971 i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); | |
972 } | |
973 | |
974 + if (s->ctx->next_proto_select_cb) | |
975 + { | |
976 + /* The client advertises an emtpy extension to indicate its | |
977 + * support for Next Protocol Negotiation */ | |
978 + if (limit - ret - 4 < 0) | |
979 + return NULL; | |
980 + s2n(TLSEXT_TYPE_next_proto_neg,ret); | |
981 + s2n(0,ret); | |
982 + } | |
983 + | |
984 if ((extdatalen = ret-p-2)== 0) | |
985 return p; | |
986 | |
987 @@ -282,6 +292,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned c
har *p, unsigned cha | |
988 { | |
989 int extdatalen=0; | |
990 unsigned char *ret = p; | |
991 + char next_proto_neg_seen; | |
992 | |
993 /* don't add extensions for SSLv3, unless doing secure renegotiation */ | |
994 if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) | |
995 @@ -337,6 +348,26 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned
char *p, unsigned cha | |
996 s2n(0,ret); | |
997 } | |
998 | |
999 + next_proto_neg_seen = s->s3->next_proto_neg_seen; | |
1000 + s->s3->next_proto_neg_seen = 0; | |
1001 + if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) | |
1002 + { | |
1003 + const unsigned char *npa; | |
1004 + unsigned int npalen; | |
1005 + int r; | |
1006 + | |
1007 + r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, s->ctx->
next_protos_advertised_cb_arg); | |
1008 + if (r == SSL_TLSEXT_ERR_OK) | |
1009 + { | |
1010 + if ((long)(limit - ret - 4 - npalen) < 0) return NULL; | |
1011 + s2n(TLSEXT_TYPE_next_proto_neg,ret); | |
1012 + s2n(npalen,ret); | |
1013 + memcpy(ret, npa, npalen); | |
1014 + ret += npalen; | |
1015 + s->s3->next_proto_neg_seen = 1; | |
1016 + } | |
1017 + } | |
1018 + | |
1019 if ((extdatalen = ret-p-2)== 0) | |
1020 return p; | |
1021 | |
1022 @@ -576,6 +607,25 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
unsigned char *d, in | |
1023 else | |
1024 s->tlsext_status_type = -1; | |
1025 } | |
1026 + else if (type == TLSEXT_TYPE_next_proto_neg) | |
1027 + { | |
1028 + /* We shouldn't accept this extension on a | |
1029 + * renegotiation, but we currently do. | |
1030 + * | |
1031 + * s->new_session will be set on renegotiation, but we | |
1032 + * probably shouldn't rely that it couldn't be set on | |
1033 + * the initial renegotation too in certain cases (when | |
1034 + * there's some other reason to disallow resuming an | |
1035 + * earlier session -- the current code won't be doing | |
1036 + * anything like that, but this might change). | |
1037 + | |
1038 + * A valid sign that there's been a previous handshake | |
1039 + * in this connection is if s->s3->tmp.finish_md_len > | |
1040 + * 0. (We are talking about a check that will happen | |
1041 + * in the Hello protocol round, well before a new | |
1042 + * Finished message could have been computed.) */ | |
1043 + s->s3->next_proto_neg_seen = 1; | |
1044 + } | |
1045 | |
1046 /* session ticket processed earlier */ | |
1047 | |
1048 @@ -599,6 +649,24 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
unsigned char *d, in | |
1049 return 1; | |
1050 } | |
1051 | |
1052 +/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No | |
1053 + * elements of zero length are allowed and the set of elements must exactly fil
l | |
1054 + * the length of the block. */ | |
1055 +static char ssl_next_proto_validate(unsigned char *d, unsigned len) | |
1056 + { | |
1057 + unsigned int off = 0; | |
1058 + | |
1059 + while (off < len) | |
1060 + { | |
1061 + if (d[off] == 0) | |
1062 + return 0; | |
1063 + off += d[off]; | |
1064 + off++; | |
1065 + } | |
1066 + | |
1067 + return off == len; | |
1068 + } | |
1069 + | |
1070 int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, i
nt n, int *al) | |
1071 { | |
1072 unsigned short type; | |
1073 @@ -658,6 +726,37 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p,
unsigned char *d, in | |
1074 /* Set flag to expect CertificateStatus message */ | |
1075 s->tlsext_status_expected = 1; | |
1076 } | |
1077 + else if (type == TLSEXT_TYPE_next_proto_neg) | |
1078 + { | |
1079 + unsigned char *selected; | |
1080 + unsigned char selected_len; | |
1081 + | |
1082 + /* We must have requested it. */ | |
1083 + if ((s->ctx->next_proto_select_cb == NULL)) | |
1084 + { | |
1085 + *al = TLS1_AD_UNSUPPORTED_EXTENSION; | |
1086 + return 0; | |
1087 + } | |
1088 + /* The data must be valid */ | |
1089 + if (!ssl_next_proto_validate(data, size)) | |
1090 + { | |
1091 + *al = TLS1_AD_DECODE_ERROR; | |
1092 + return 0; | |
1093 + } | |
1094 + if (s->ctx->next_proto_select_cb(s, &selected, &selected
_len, data, size, s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) | |
1095 + { | |
1096 + *al = TLS1_AD_INTERNAL_ERROR; | |
1097 + return 0; | |
1098 + } | |
1099 + s->next_proto_negotiated = OPENSSL_malloc(selected_len); | |
1100 + if (!s->next_proto_negotiated) | |
1101 + { | |
1102 + *al = TLS1_AD_INTERNAL_ERROR; | |
1103 + return 0; | |
1104 + } | |
1105 + memcpy(s->next_proto_negotiated, selected, selected_len)
; | |
1106 + s->next_proto_negotiated_len = selected_len; | |
1107 + } | |
1108 else if (type == TLSEXT_TYPE_renegotiate) | |
1109 { | |
1110 if(!ssl_parse_serverhello_renegotiate_ext(s, data, size,
al)) | |
1111 diff --git a/ssl/tls1.h b/ssl/tls1.h | |
1112 index afe4807..71d76de 100644 | |
1113 --- a/ssl/tls1.h | |
1114 +++ b/ssl/tls1.h | |
1115 @@ -118,6 +118,9 @@ extern "C" { | |
1116 /* Temporary extension type */ | |
1117 #define TLSEXT_TYPE_renegotiate 0xff01 | |
1118 | |
1119 +/* This is not an IANA defined extension number */ | |
1120 +#define TLSEXT_TYPE_next_proto_neg 13172 | |
1121 + | |
1122 /* NameType value from RFC 3546 */ | |
1123 #define TLSEXT_NAMETYPE_host_name 0 | |
1124 /* status request value from RFC 3546 */ | |
OLD | NEW |