OLD | NEW |
| (Empty) |
1 commit ca77729f0395a16f08ff5d54968e05dbd84b331f | |
2 Author: Adam Langley <agl@chromium.org> | |
3 Date: Thu Nov 4 16:09:48 2010 -0400 | |
4 | |
5 snap_start.patch | |
6 | |
7 diff --git a/apps/s_server.c b/apps/s_server.c | |
8 index c4e19c9..37db8f9 100644 | |
9 --- a/apps/s_server.c | |
10 +++ b/apps/s_server.c | |
11 @@ -802,6 +802,7 @@ int MAIN(int argc, char *argv[]) | |
12 tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING}; | |
13 const char *next_proto_neg_in = NULL; | |
14 tlsextnextprotoctx next_proto; | |
15 + char snapstart = 0; | |
16 #endif | |
17 | |
18 #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) | |
19 @@ -1105,6 +1106,10 @@ int MAIN(int argc, char *argv[]) | |
20 if (--argc < 1) goto bad; | |
21 next_proto_neg_in = *(++argv); | |
22 } | |
23 + else if (strcmp(*argv,"-snapstart") == 0) | |
24 + { | |
25 + snapstart = 1; | |
26 + } | |
27 #endif | |
28 #ifndef OPENSSL_NO_JPAKE | |
29 else if (strcmp(*argv,"-jpake") == 0) | |
30 @@ -1389,6 +1394,11 @@ bad: | |
31 } | |
32 #endif | |
33 | |
34 + if (snapstart) | |
35 + { | |
36 + static const unsigned char orbit[8] = {1, 2, 3, 4, 5, 6, 7, 8}; | |
37 + SSL_CTX_set_snap_start_orbit(ctx, orbit); | |
38 + } | |
39 | |
40 #ifndef OPENSSL_NO_DH | |
41 if (!no_dhe) | |
42 @@ -2031,6 +2041,7 @@ static int init_ssl_connection(SSL *con) | |
43 unsigned next_proto_neg_len; | |
44 #endif | |
45 | |
46 +again: | |
47 if ((i=SSL_accept(con)) <= 0) | |
48 { | |
49 if (BIO_sock_should_retry(i)) | |
50 @@ -2039,6 +2050,12 @@ static int init_ssl_connection(SSL *con) | |
51 return(1); | |
52 } | |
53 | |
54 + if (SSL_get_error(con, i) == SSL_ERROR_SERVER_RANDOM_VALIDATION_
PENDING) | |
55 + { | |
56 + SSL_set_suggested_server_random_validity(con, 1); | |
57 + goto again; | |
58 + } | |
59 + | |
60 BIO_printf(bio_err,"ERROR\n"); | |
61 verify_error=SSL_get_verify_result(con); | |
62 if (verify_error != X509_V_OK) | |
63 @@ -2224,6 +2241,9 @@ static int www_body(char *hostname, int s, unsigned char *
context) | |
64 case SSL_ERROR_WANT_READ: | |
65 case SSL_ERROR_WANT_X509_LOOKUP: | |
66 continue; | |
67 + case SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING: | |
68 + SSL_set_suggested_server_random_validity(con, 1)
; | |
69 + continue; | |
70 case SSL_ERROR_SYSCALL: | |
71 case SSL_ERROR_SSL: | |
72 case SSL_ERROR_ZERO_RETURN: | |
73 diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c | |
74 index 06e5466..e32f97d 100644 | |
75 --- a/ssl/s3_enc.c | |
76 +++ b/ssl/s3_enc.c | |
77 @@ -111,6 +111,7 @@ | |
78 | |
79 #include <stdio.h> | |
80 #include "ssl_locl.h" | |
81 +#include "fnv1a64.h" | |
82 #include <openssl/evp.h> | |
83 #include <openssl/md5.h> | |
84 | |
85 @@ -529,6 +530,11 @@ void ssl3_finish_mac(SSL *s, const unsigned char *buf, int
len) | |
86 { | |
87 EVP_DigestUpdate(&(s->s3->finish_dgst1),buf,len); | |
88 EVP_DigestUpdate(&(s->s3->finish_dgst2),buf,len); | |
89 + if (s->s3->snap_start_requested) | |
90 + { | |
91 + /* Compute Fowler-Noll-Vo (FNV) hash for Snap Start handshake */ | |
92 + fnv1a64_update((FNV1A64*) s->s3->response_hash, buf, len); | |
93 + } | |
94 } | |
95 | |
96 int ssl3_cert_verify_mac(SSL *s, EVP_MD_CTX *ctx, unsigned char *p) | |
97 diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c | |
98 index 84bff8d..1058b4e 100644 | |
99 --- a/ssl/s3_lib.c | |
100 +++ b/ssl/s3_lib.c | |
101 @@ -1701,6 +1701,12 @@ void ssl3_free(SSL *s) | |
102 pq_64bit_free(&(s->s3->rrec.seq_num)); | |
103 pq_64bit_free(&(s->s3->wrec.seq_num)); | |
104 | |
105 + if (s->s3->snap_start_client_hello.buf) | |
106 + { | |
107 + /* s->s3->snap_start_records, if set, uses the same buffer */ | |
108 + OPENSSL_free(s->s3->snap_start_client_hello.buf); | |
109 + } | |
110 + | |
111 OPENSSL_cleanse(s->s3,sizeof *s->s3); | |
112 OPENSSL_free(s->s3); | |
113 s->s3=NULL; | |
114 diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c | |
115 index 6853058..61774b2 100644 | |
116 --- a/ssl/s3_pkt.c | |
117 +++ b/ssl/s3_pkt.c | |
118 @@ -120,8 +120,51 @@ static int do_ssl3_write(SSL *s, int type, const unsigned c
har *buf, | |
119 unsigned int len, int create_empty_fragment); | |
120 static int ssl3_get_record(SSL *s); | |
121 | |
122 +/* ssl3_read_snap_start_n reads from the opportunistic records contained within | |
123 + * a Snap Start extension. |s->packet| and |s->packet_length| are set to frame | |
124 + * a record within this area. Partial records are not allowed. The Snap Start | |
125 + * records are held in |s->s3->snap_start_records| and the |left| member must | |
126 + * be non-zero on entry. | |
127 + * | |
128 + * If |extend| is true then we'll expand the currently framed record by |n| | |
129 + * bytes, otherwise we frame a new record. */ | |
130 +static int ssl3_read_snap_start_n(SSL *s, int n, int extend) | |
131 + { | |
132 + if (!extend) | |
133 + { | |
134 + s->packet = s->s3->snap_start_records.buf + s->s3->snap_start_re
cords.offset; | |
135 + s->packet_length = 0; | |
136 + } | |
137 + | |
138 + if (s->s3->snap_start_records.left < n) | |
139 + { | |
140 + /* We aren't called unless .left is non-zero, therefore this | |
141 + * means that we wanted to read more than we have. Since | |
142 + * partial records aren't allowed, this is fatal. */ | |
143 + SSLerr(SSL_F_SSL3_READ_SNAP_START_N,SSL_R_BAD_PACKET_LENGTH); | |
144 + return -1; | |
145 + } | |
146 + | |
147 + s->packet_length += n; | |
148 + s->s3->snap_start_records.left -= n; | |
149 + s->s3->snap_start_records.offset += n; | |
150 + | |
151 + return n; | |
152 + } | |
153 + | |
154 int ssl3_read_n(SSL *s, int n, int max, int extend) | |
155 { | |
156 + if (s->s3->snap_start_records.left) | |
157 + return ssl3_read_snap_start_n(s, n, extend); | |
158 + else if (s->s3->snap_start_client_hello.buf && !extend) | |
159 + { | |
160 + /* If we started reading the opportunistic records then we know | |
161 + * that we didn't enter recovery. Thus it's safe to free the | |
162 + * copy of the ClientHello now because we'll not need it again.
*/ | |
163 + OPENSSL_free(s->s3->snap_start_client_hello.buf); | |
164 + s->s3->snap_start_client_hello.buf = NULL; | |
165 + } | |
166 + | |
167 /* If extend == 0, obtain new n-byte packet; if extend == 1, increase | |
168 * packet by another n bytes. | |
169 * The packet will be in the sub-array of s->s3->rbuf.buf specified | |
170 diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c | |
171 index 8e0a504..315b8f3 100644 | |
172 --- a/ssl/s3_srvr.c | |
173 +++ b/ssl/s3_srvr.c | |
174 @@ -144,6 +144,7 @@ | |
175 #include <openssl/md5.h> | |
176 | |
177 static SSL_METHOD *ssl3_get_server_method(int ver); | |
178 +static int ssl3_snap_start_evaluate_handshake(SSL* s); | |
179 #ifndef OPENSSL_NO_ECDH | |
180 static int nid2curve_id(int nid); | |
181 #endif | |
182 @@ -300,10 +301,36 @@ int ssl3_accept(SSL *s) | |
183 case SSL3_ST_SW_SRVR_HELLO_A: | |
184 case SSL3_ST_SW_SRVR_HELLO_B: | |
185 ret=ssl3_send_server_hello(s); | |
186 + if (ret == SERVER_RANDOM_VALIDATION_PENDING) | |
187 + { | |
188 + s->rwstate = SSL_SERVER_RANDOM_VALIDATE; | |
189 + s->state = SSL3_ST_SW_SRVR_HELLO_A; | |
190 + s->init_num = 0; | |
191 + goto end; | |
192 + } | |
193 if (ret <= 0) goto end; | |
194 #ifndef OPENSSL_NO_TLSEXT | |
195 + if ((s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK)
!= SSL_kRSA && | |
196 + (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK)
!= SSL_kKRB5 && | |
197 + (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK)
!= SSL_kDHr && | |
198 + (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK)
!= SSL_kDHd && | |
199 + (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK)
!= SSL_kECDH && | |
200 + s->s3->snap_start_requested) | |
201 + { | |
202 + /* There's no point in carrying on with a Snap | |
203 + * Start handshake if we're using a cipher | |
204 + * suite which is going to send a | |
205 + * ServerKeyExchange message. */ | |
206 + ssl3_snap_start_reset_for_recovery(s); | |
207 + s->state = SSL3_ST_SW_SRVR_HELLO_A; | |
208 + break; | |
209 + } | |
210 + | |
211 if (s->hit) | |
212 { | |
213 + if (ssl3_snap_start_evaluate_handshake(s)) | |
214 + break; | |
215 + | |
216 if (s->tlsext_ticket_expected) | |
217 s->state=SSL3_ST_SW_SESSION_TICKET_A; | |
218 else | |
219 @@ -440,8 +467,19 @@ int ssl3_accept(SSL *s) | |
220 case SSL3_ST_SW_SRVR_DONE_B: | |
221 ret=ssl3_send_server_done(s); | |
222 if (ret <= 0) goto end; | |
223 - s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; | |
224 - s->state=SSL3_ST_SW_FLUSH; | |
225 + | |
226 + if (s->s3->snap_start_requested) | |
227 + { | |
228 + if (ssl3_snap_start_evaluate_handshake(s)) | |
229 + break; | |
230 + s->state = SSL3_ST_SR_CERT_A; | |
231 + } | |
232 + else | |
233 + { | |
234 + s->s3->tmp.next_state=SSL3_ST_SR_CERT_A; | |
235 + s->state=SSL3_ST_SW_FLUSH; | |
236 + } | |
237 + | |
238 s->init_num=0; | |
239 break; | |
240 | |
241 @@ -1152,11 +1190,19 @@ int ssl3_send_server_hello(SSL *s) | |
242 if (s->state == SSL3_ST_SW_SRVR_HELLO_A) | |
243 { | |
244 buf=(unsigned char *)s->init_buf->data; | |
245 - p=s->s3->server_random; | |
246 - Time=(unsigned long)time(NULL); /* Time */ | |
247 - l2n(Time,p); | |
248 - if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) | |
249 - return -1; | |
250 + if (!s->s3->snap_start_requested) | |
251 + { | |
252 + p=s->s3->server_random; | |
253 + Time=(unsigned long)time(NULL); /* Time
*/ | |
254 + l2n(Time,p); | |
255 + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) | |
256 + return -1; | |
257 + } | |
258 + else if (s->s3->server_random_suggestion_valid == 0) | |
259 + { | |
260 + return SERVER_RANDOM_VALIDATION_PENDING; | |
261 + } | |
262 + | |
263 /* Do the message type and length last */ | |
264 d=p= &(buf[4]); | |
265 | |
266 @@ -2952,3 +2998,55 @@ int ssl3_send_cert_status(SSL *s) | |
267 return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); | |
268 } | |
269 #endif | |
270 + | |
271 +/* ssl3_snap_start_evaluate_handshake verifies the Snap Start prediction (if | |
272 + * this is a Snap Start handshake). If it returns non-zero, then we are | |
273 + * entering recovery and |s->state| has been set accordingly. */ | |
274 +static int ssl3_snap_start_evaluate_handshake(SSL* s) | |
275 + { | |
276 + unsigned char digest[8]; | |
277 + | |
278 + if (!s->s3->snap_start_requested) | |
279 + return 0; | |
280 + | |
281 + /* Drop the currently queued messages. Either we're entering recovery, | |
282 + * in which case they're wrong, or we're doing snap start, in which | |
283 + * case we don't want to send them. */ | |
284 + if (!ssl_init_wbio_buffer(s, 1 /* push new BIO */)) | |
285 + return -1; | |
286 + | |
287 + fnv1a64_final(digest, (FNV1A64*) s->s3->response_hash); | |
288 + | |
289 + /* Turn off FNV hashing of handshake messages. */ | |
290 + s->s3->snap_start_requested = 0; | |
291 + | |
292 + if (memcmp(digest, s->s3->predicted_response_hash, sizeof(digest)) != 0) | |
293 + { | |
294 + /* The predicted handshake didn't match. */ | |
295 + ssl3_snap_start_reset_for_recovery(s); | |
296 + s->state = SSL3_ST_SW_SRVR_HELLO_A; | |
297 + return 1; | |
298 + } | |
299 + | |
300 + return 0; | |
301 + } | |
302 + | |
303 +/* ssl3_snap_start_reset_for_recovery is called is called when a Snap Start | |
304 + * handshake is impossible because either the application layer has rejected | |
305 + * the client's suggested server random, or predicated_response_hash failed to | |
306 + * match response_hash */ | |
307 +int ssl3_snap_start_reset_for_recovery(SSL* s) | |
308 + { | |
309 + s->s3->snap_start_requested = 0; | |
310 + s->s3->snap_start_records.left = 0; | |
311 + s->init_num = 0; | |
312 + | |
313 + /* Reset the handshake hash and hash in the original ClientHello. */ | |
314 + ssl3_init_finished_mac(s); | |
315 + ssl3_finish_mac(s, s->s3->snap_start_client_hello.buf, s->s3->snap_start
_client_hello.left); | |
316 + | |
317 + OPENSSL_free(s->s3->snap_start_client_hello.buf); | |
318 + s->s3->snap_start_client_hello.buf = NULL; | |
319 + | |
320 + return 0; | |
321 + } | |
322 diff --git a/ssl/ssl.h b/ssl/ssl.h | |
323 index dc8dff8..bbe2543 100644 | |
324 --- a/ssl/ssl.h | |
325 +++ b/ssl/ssl.h | |
326 @@ -770,6 +770,11 @@ struct ssl_ctx_st | |
327 | |
328 X509_VERIFY_PARAM *param; | |
329 | |
330 + /* The configured Snap Start orbit value, if set. */ | |
331 + char snap_start_orbit_valid; | |
332 + unsigned char snap_start_orbit[8]; | |
333 + | |
334 + | |
335 #if 0 | |
336 int purpose; /* Purpose setting */ | |
337 int trust; /* Trust setting */ | |
338 @@ -876,10 +881,14 @@ void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*ap
p_gen_cookie_cb)(SSL * | |
339 void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL
*ssl, unsigned char *cookie, unsigned int cookie_len)); | |
340 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); | |
341 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); | |
342 +void SSL_CTX_set_snap_start_orbit(SSL_CTX *s, const unsigned char orbit[8]); | |
343 | |
344 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); | |
345 void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, u
nsigned *len); | |
346 | |
347 +void SSL_get0_suggested_server_random(const SSL *s, const unsigned char **data,
unsigned *len); | |
348 +void SSL_set_suggested_server_random_validity(SSL *s, char is_valid); | |
349 + | |
350 #define OPENSSL_NPN_UNSUPPORTED 0 | |
351 #define OPENSSL_NPN_NEGOTIATED 1 | |
352 #define OPENSSL_NPN_NO_OVERLAP 2 | |
353 @@ -888,12 +897,14 @@ void SSL_get0_next_proto_negotiated(const SSL *s, const un
signed char **data, un | |
354 #define SSL_WRITING 2 | |
355 #define SSL_READING 3 | |
356 #define SSL_X509_LOOKUP 4 | |
357 +#define SSL_SERVER_RANDOM_VALIDATE 6 | |
358 | |
359 /* These will only be used when doing non-blocking IO */ | |
360 #define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) | |
361 #define SSL_want_read(s) (SSL_want(s) == SSL_READING) | |
362 #define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) | |
363 #define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP) | |
364 +#define SSL_want_server_random_validation(s) (SSL_want(s) == SSL_SERVER_RANDO
M_VALIDATE) | |
365 | |
366 struct ssl_st | |
367 { | |
368 @@ -1255,6 +1266,7 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size
_t count); | |
369 #define SSL_ERROR_ZERO_RETURN 6 | |
370 #define SSL_ERROR_WANT_CONNECT 7 | |
371 #define SSL_ERROR_WANT_ACCEPT 8 | |
372 +#define SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING 10 | |
373 | |
374 #define SSL_CTRL_NEED_TMP_RSA 1 | |
375 #define SSL_CTRL_SET_TMP_RSA 2 | |
376 @@ -1754,6 +1766,7 @@ void ERR_load_SSL_strings(void); | |
377 #define SSL_F_GET_SERVER_VERIFY 110 | |
378 #define SSL_F_I2D_SSL_SESSION 111 | |
379 #define SSL_F_READ_N 112 | |
380 +#define SSL_F_SSL3_READ_SNAP_START_N 300 | |
381 #define SSL_F_REQUEST_CERTIFICATE 113 | |
382 #define SSL_F_SERVER_FINISH 239 | |
383 #define SSL_F_SERVER_HELLO 114 | |
384 @@ -1907,7 +1920,7 @@ void ERR_load_SSL_strings(void); | |
385 #define SSL_F_TLS1_ENC 210 | |
386 #define SSL_F_TLS1_SETUP_KEY_BLOCK 211 | |
387 #define SSL_F_WRITE_PENDING 212 | |
388 -/* Next entry: 299 */ | |
389 +/* Next entry: 300 */ | |
390 | |
391 /* Reason codes. */ | |
392 #define SSL_R_APP_DATA_IN_HANDSHAKE 100 | |
393 diff --git a/ssl/ssl3.h b/ssl/ssl3.h | |
394 index 54b73b7..4a6e8cf 100644 | |
395 --- a/ssl/ssl3.h | |
396 +++ b/ssl/ssl3.h | |
397 @@ -452,6 +452,48 @@ typedef struct ssl3_state_st | |
398 unsigned char previous_server_finished[EVP_MAX_MD_SIZE]; | |
399 unsigned char previous_server_finished_len; | |
400 int send_connection_binding; /* TODOEKR */ | |
401 + | |
402 + /* Snap Start support (server-side only): | |
403 + * | |
404 + * Snap Start allows the client to 'suggest' the value of our random | |
405 + * nonce. Assuming that we accept this suggestion, then the client can | |
406 + * predict our exact reply and calculate a complete handshake based on | |
407 + * that. These opportunistic handshake messages are embedded in the | |
408 + * Snap Start extension, possibly including application data. | |
409 + * | |
410 + * (Note that if the handshake doesn't resume a session, the client | |
411 + * couldn't hope to predict the exact server reply unless it uses the | |
412 + * session ticket extension to suppress session ID generation.) | |
413 + * | |
414 + * All this allows for a TLS handshake that doesn't incur additional | |
415 + * latency if the client side sends application data first. */ | |
416 + | |
417 + /* Set if the client presented a Snap Start extension (empty or | |
418 + * otherwise and the SSL_CTX has a cell configured. Server side only. */ | |
419 + int snap_start_ext_seen; | |
420 + /* Set if the client-suggested a server random value (which is stored | |
421 + * in |server_random|) */ | |
422 + char snap_start_requested; | |
423 + /* Set if the appplication has indicated that the client's | |
424 + * server_random suggestion is acceptable (see | |
425 + * SSL_set_suggested_server_random_validity). If so, a Snap Start | |
426 + * handshake will be attempted. */ | |
427 + char server_random_suggestion_valid; | |
428 + /* Client's predicted response_hash from client snap start extension. | |
429 + * Valid if |snap_start_requested| is set. */ | |
430 + unsigned char predicted_response_hash[8]; | |
431 + /* Actual server handshake message hash. A Snap Start handshake is | |
432 + * possible only if predicated_response_hash matches this. */ | |
433 + unsigned char response_hash[8]; | |
434 + /* If we need to enter snap start recovery then we need to reset the | |
435 + * Finished hash with a different value for the ClientHello. Thus, we | |
436 + * need a copy of the whole ClientHello: */ | |
437 + SSL3_BUFFER snap_start_client_hello; | |
438 + /* A snap start ClientHello can contain records embedded in an | |
439 + * extension. If we wish to read them then this points to the records | |
440 + * within |snap_start_client_hello|. */ | |
441 + SSL3_BUFFER snap_start_records; | |
442 + | |
443 } SSL3_STATE; | |
444 | |
445 | |
446 diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c | |
447 index cfa70ec..88358fb 100644 | |
448 --- a/ssl/ssl_lib.c | |
449 +++ b/ssl/ssl_lib.c | |
450 @@ -2119,6 +2119,9 @@ int SSL_get_error(const SSL *s,int i) | |
451 return(SSL_ERROR_SSL); | |
452 } | |
453 | |
454 + if ((i < 0) && SSL_want_server_random_validation(s)) | |
455 + return(SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING); | |
456 + | |
457 if ((i < 0) && SSL_want_read(s)) | |
458 { | |
459 bio=SSL_get_rbio(s); | |
460 @@ -2876,6 +2879,61 @@ void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (
*cb) (SSL *s, unsigned | |
461 ctx->next_proto_select_cb = cb; | |
462 ctx->next_proto_select_cb_arg = arg; | |
463 } | |
464 + | |
465 +/* SSL_CTX_set_snap_start_orbit sets the orbit value which will be echoed back | |
466 + * to the client and enables Snap Start for this context. | |
467 + * | |
468 + * An orbit value can be used to spatially partition the state needed to suppor
t | |
469 + * Snap Start. See the comments above SSL_set_suggested_server_random_validity | |
470 + * (below). */ | |
471 +void SSL_CTX_set_snap_start_orbit(SSL_CTX *ctx, const unsigned char orbit[8]) | |
472 + { | |
473 + memcpy(ctx->snap_start_orbit, orbit, sizeof(ctx->snap_start_orbit)); | |
474 + ctx->snap_start_orbit_valid = 1; | |
475 + } | |
476 + | |
477 +/* Once SSL_accept has returned with SSL_SERVER_RANDOM_VALIDATE, then one can | |
478 + * call this function in order to get the client's suggested server random | |
479 + * value. */ | |
480 +void SSL_get0_suggested_server_random(const SSL* s, const unsigned char **data,
unsigned *length) | |
481 + { | |
482 + if (!s->s3->snap_start_requested) | |
483 + { | |
484 + *data = NULL; | |
485 + *length = 0; | |
486 + return; | |
487 + } | |
488 + *length = 32; | |
489 + *data = s->s3->server_random; | |
490 + } | |
491 + | |
492 +/* SSL_set_suggested_server_random_validity passes judgement on a | |
493 + * client-suggested random value (obtained from | |
494 + * SSL_get0_suggested_server_random). Rejecting the value triggers a recovery, | |
495 + * while accepting the value /may/ result in a successful Snap Start, as long | |
496 + * as the client predicted the handshake correctly. | |
497 + * | |
498 + * In order to accept a random value the user must ensure that it has NEVER | |
499 + * been used before by this server, or any server configured with any of the | |
500 + * same certificates. It may reject more if necessary. | |
501 + * | |
502 + * The first four bytes of the random value contain a timestamp (UNIX seconds | |
503 + * since the epoch) which can be used to manage a time window. Additionally, | |
504 + * the following eight bytes contain the orbit which which can also bound the | |
505 + * state required if geographically separate servers share certificates. | |
506 + * | |
507 + * It's recommended that the time window have a maximum size, independent of | |
508 + * the resources available, in order to prevent an attacker from arbitrarily | |
509 + * delaying a Snap Start handshake. | |
510 + */ | |
511 +void SSL_set_suggested_server_random_validity(SSL *s, char is_valid) | |
512 + { | |
513 + if (is_valid) | |
514 + s->s3->server_random_suggestion_valid = 1; | |
515 + else | |
516 + ssl3_snap_start_reset_for_recovery(s); | |
517 + } | |
518 + | |
519 #endif | |
520 | |
521 int SSL_cutthrough_complete(const SSL *s) | |
522 diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h | |
523 index a9183ff..639a185 100644 | |
524 --- a/ssl/ssl_locl.h | |
525 +++ b/ssl/ssl_locl.h | |
526 @@ -392,6 +392,11 @@ | |
527 #define CERT_PRIVATE_KEY 2 | |
528 */ | |
529 | |
530 +/* This can be returned from ssl3_send_server_hello to indicate that an | |
531 + * offline validation of a client-suggested server_random needs to be | |
532 + * performed. */ | |
533 +#define SERVER_RANDOM_VALIDATION_PENDING -(TLSEXT_TYPE_snap_start) | |
534 + | |
535 #ifndef OPENSSL_NO_EC | |
536 /* From ECC-TLS draft, used in encoding the curve type in | |
537 * ECParameters | |
538 @@ -915,6 +920,7 @@ int ssl3_get_client_certificate(SSL *s); | |
539 int ssl3_get_client_key_exchange(SSL *s); | |
540 int ssl3_get_cert_verify(SSL *s); | |
541 int ssl3_get_next_proto(SSL *s); | |
542 +int ssl3_snap_start_reset_for_recovery(SSL* s); | |
543 | |
544 int dtls1_send_hello_request(SSL *s); | |
545 int dtls1_send_server_hello(SSL *s); | |
546 diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c | |
547 index fd35b18..ce33f16 100644 | |
548 --- a/ssl/t1_lib.c | |
549 +++ b/ssl/t1_lib.c | |
550 @@ -62,6 +62,7 @@ | |
551 #include <openssl/hmac.h> | |
552 #include <openssl/ocsp.h> | |
553 #include "ssl_locl.h" | |
554 +#include "fnv1a64.h" | |
555 | |
556 const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; | |
557 | |
558 @@ -368,6 +369,21 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned
char *p, unsigned cha | |
559 } | |
560 } | |
561 | |
562 + if (s->s3->snap_start_ext_seen) | |
563 + { | |
564 + if ((long)(limit - ret - 14) < 0) return NULL; | |
565 + s2n(TLSEXT_TYPE_snap_start,ret); | |
566 + s2n(10,ret); /* extension length */ | |
567 + memcpy(ret, s->ctx->snap_start_orbit, 8); | |
568 + ret += 8; | |
569 + /* This is the ciphersuite that we would pick in the event of a | |
570 + * Snap Start handshake. (Maybe the server wants to do EDH | |
571 + * unless the client is Snap Start capable). At the moment we | |
572 + * don't have any logic to pick a different cipher suite so we | |
573 + * repeat the choice from the ServerHello. */ | |
574 + s2n(s->s3->tmp.new_cipher->id & 0xffff,ret); | |
575 + } | |
576 + | |
577 if ((extdatalen = ret-p-2)== 0) | |
578 return p; | |
579 | |
580 @@ -375,6 +391,174 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned
char *p, unsigned cha | |
581 return ret; | |
582 } | |
583 | |
584 + | |
585 +static int ssl_hash_snap_start_client_hello(SSL* s, | |
586 + const char* data, | |
587 + unsigned len, | |
588 + unsigned ext_len) | |
589 + { | |
590 + /* We walk the ClientHello from the beginning, writing | |
591 + * adjusted lengths into |b| and hashing as we go. | |
592 + * | |
593 + * The resulting ClientHello is going to be shorter by the length of | |
594 + * this extension, which is |ext_len + 4| (two bytes for the type and tw
o for | |
595 + * the length). */ | |
596 + | |
597 + const unsigned char *p; | |
598 + unsigned remaining; | |
599 + unsigned char b[3], *c; | |
600 + unsigned long l; | |
601 + | |
602 + p = (unsigned char*) data; | |
603 + remaining = len; | |
604 + /* Handshake header: type */ | |
605 + if (!remaining) | |
606 + return 0; | |
607 + ssl3_finish_mac(s, p, 1); | |
608 + p++; | |
609 + remaining--; | |
610 + /* Handshake header: length */ | |
611 + if (remaining < 3) | |
612 + return 0; | |
613 + n2l3(p, l); | |
614 + l -= ext_len + 4; | |
615 + c = b; | |
616 + l2n3(l, c); | |
617 + ssl3_finish_mac(s, b, 3); | |
618 + remaining -= 3; | |
619 + /* ClientHello: version and random */ | |
620 + if (remaining < 34) | |
621 + return 0; | |
622 + ssl3_finish_mac(s, p, 34); | |
623 + p += 34; | |
624 + remaining -= 34; | |
625 + /* ClientHello: session id length */ | |
626 + if (!remaining) | |
627 + return 0; | |
628 + l = *p; | |
629 + ssl3_finish_mac(s, p, 1); | |
630 + p++; | |
631 + remaining--; | |
632 + /* ClientHello: session id */ | |
633 + if (remaining < l) | |
634 + return 0; | |
635 + ssl3_finish_mac(s, p, l); | |
636 + p += l; | |
637 + remaining -= l; | |
638 + /* ClientHello: cipher suites length */ | |
639 + if (remaining < 2) | |
640 + return 0; | |
641 + ssl3_finish_mac(s, p, 2); | |
642 + n2s(p, l); | |
643 + remaining -= 2; | |
644 + /* ClientHello: cipher suites */ | |
645 + if (remaining < l) | |
646 + return 0; | |
647 + ssl3_finish_mac(s, p, l); | |
648 + p += l; | |
649 + remaining -= l; | |
650 + /* ClientHello: compression methods length */ | |
651 + if (!remaining) | |
652 + return 0; | |
653 + l = *p; | |
654 + ssl3_finish_mac(s, p, 1); | |
655 + p++; | |
656 + remaining--; | |
657 + /* ClientHello: compression methods */ | |
658 + if (remaining < l) | |
659 + return 0; | |
660 + ssl3_finish_mac(s, p, l); | |
661 + p += l; | |
662 + remaining -= l; | |
663 + /* ClientHello: extensions length (must exist given that we're already | |
664 + * parsing the extensions from it */ | |
665 + if (remaining < 2) | |
666 + return 0; | |
667 + n2s(p, l); | |
668 + remaining -= 2; | |
669 + if (l != remaining || l < ext_len + 4) | |
670 + return 0; | |
671 + l -= ext_len + 4; | |
672 + c = b; | |
673 + s2n(l, c); | |
674 + ssl3_finish_mac(s, b, 2); | |
675 + | |
676 + while (remaining) | |
677 + { | |
678 + unsigned long extension_type, extension_len; | |
679 + if (remaining < 4) | |
680 + return 0; | |
681 + n2s(p, extension_type); | |
682 + n2s(p, extension_len); | |
683 + remaining -= 4; | |
684 + if (remaining < extension_len) | |
685 + return 0; | |
686 + if (extension_type != TLSEXT_TYPE_snap_start) | |
687 + ssl3_finish_mac(s, p - 4, extension_len + 4); | |
688 + p += extension_len; | |
689 + remaining -= extension_len; | |
690 + } | |
691 + | |
692 + return 1; | |
693 + } | |
694 + | |
695 +static char ssl_parse_snap_start_tlsext(SSL *s, const unsigned char *data, unsi
gned short len) | |
696 + { | |
697 + ptrdiff_t extension_offset = data - (unsigned char *) s->init_buf->data; | |
698 + | |
699 + if (len > 0 && len < 36) | |
700 + return 0; | |
701 + s->s3->snap_start_ext_seen = 1; | |
702 + if (len == 0) | |
703 + return 1; | |
704 + | |
705 + fnv1a64_init((FNV1A64*) s->s3->response_hash); | |
706 + | |
707 + /* We need to make a copy of the ClientHello because we'll be hashing a | |
708 + * modified version. However, if we enter recovery then we need to hash | |
709 + * the unchanged message. | |
710 + * | |
711 + * We are adding 4 bytes to the length here because we're including the | |
712 + * handshake header. */ | |
713 + s->s3->snap_start_client_hello.left = s->init_num + 4; | |
714 + s->s3->snap_start_client_hello.offset = 0; | |
715 + s->s3->snap_start_client_hello.buf = OPENSSL_malloc(s->init_num + 4); | |
716 + if (!s->s3->snap_start_client_hello.buf) | |
717 + { | |
718 + /* If we're out of memory then we pretend that we | |
719 + * didn't see the extension. */ | |
720 + s->s3->snap_start_ext_seen = 0; | |
721 + return 1; | |
722 + } | |
723 + | |
724 + memcpy(s->s3->snap_start_client_hello.buf, s->init_buf->data, s->init_nu
m + 4); | |
725 + memcpy(s->s3->server_random, s->s3->client_random, 4); /* time */ | |
726 + memcpy(s->s3->server_random + 4, data, 28); /* orbit and random bytes */ | |
727 + memcpy(s->s3->predicted_response_hash, data + 28, 8); | |
728 + | |
729 + /* Point snap_start_records to within the copy of the ClientHello */ | |
730 + s->s3->snap_start_records.offset = 0; | |
731 + s->s3->snap_start_records.left = len - 36; | |
732 + s->s3->snap_start_records.buf = s->s3->snap_start_client_hello.buf + ext
ension_offset + 36; | |
733 + | |
734 + /* Reset the handshake hash */ | |
735 + ssl3_init_finished_mac(s); | |
736 + | |
737 + /* Need to hash the ClientHello as if the snap start extension wasn't | |
738 + * included. */ | |
739 + if (!ssl_hash_snap_start_client_hello( | |
740 + s, | |
741 + s->init_buf->data, | |
742 + s->init_num + 4 /* four bytes of handshake header */, | |
743 + len)) | |
744 + { | |
745 + return 0; | |
746 + } | |
747 + | |
748 + s->s3->snap_start_requested = 1; | |
749 + return 1; | |
750 + } | |
751 + | |
752 int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, i
nt n, int *al) | |
753 { | |
754 unsigned short type; | |
755 @@ -627,6 +811,12 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p,
unsigned char *d, in | |
756 s->s3->next_proto_neg_seen = 1; | |
757 } | |
758 | |
759 + else if (type == TLSEXT_TYPE_snap_start && s->ctx->snap_start_or
bit_valid) | |
760 + { | |
761 + if (ssl_parse_snap_start_tlsext(s, data, size) == 0) | |
762 + return 0; | |
763 + } | |
764 + | |
765 /* session ticket processed earlier */ | |
766 | |
767 data+=size; | |
768 diff --git a/ssl/tls1.h b/ssl/tls1.h | |
769 index 71d76de..52ff325 100644 | |
770 --- a/ssl/tls1.h | |
771 +++ b/ssl/tls1.h | |
772 @@ -120,6 +120,8 @@ extern "C" { | |
773 | |
774 /* This is not an IANA defined extension number */ | |
775 #define TLSEXT_TYPE_next_proto_neg 13172 | |
776 + /* http://tools.ietf.org/html/draft-agl-tls-snapstart-00 */ | |
777 +#define TLSEXT_TYPE_snap_start 13174 | |
778 | |
779 /* NameType value from RFC 3546 */ | |
780 #define TLSEXT_NAMETYPE_host_name 0 | |
OLD | NEW |