| 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 |