| Index: patches/snap_start.patch
|
| ===================================================================
|
| --- patches/snap_start.patch (revision 105093)
|
| +++ patches/snap_start.patch (working copy)
|
| @@ -1,780 +0,0 @@
|
| -commit ca77729f0395a16f08ff5d54968e05dbd84b331f
|
| -Author: Adam Langley <agl@chromium.org>
|
| -Date: Thu Nov 4 16:09:48 2010 -0400
|
| -
|
| - snap_start.patch
|
| -
|
| -diff --git a/apps/s_server.c b/apps/s_server.c
|
| -index c4e19c9..37db8f9 100644
|
| ---- a/apps/s_server.c
|
| -+++ b/apps/s_server.c
|
| -@@ -802,6 +802,7 @@ int MAIN(int argc, char *argv[])
|
| - tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING};
|
| - const char *next_proto_neg_in = NULL;
|
| - tlsextnextprotoctx next_proto;
|
| -+ char snapstart = 0;
|
| - #endif
|
| -
|
| - #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3)
|
| -@@ -1105,6 +1106,10 @@ int MAIN(int argc, char *argv[])
|
| - if (--argc < 1) goto bad;
|
| - next_proto_neg_in = *(++argv);
|
| - }
|
| -+ else if (strcmp(*argv,"-snapstart") == 0)
|
| -+ {
|
| -+ snapstart = 1;
|
| -+ }
|
| - #endif
|
| - #ifndef OPENSSL_NO_JPAKE
|
| - else if (strcmp(*argv,"-jpake") == 0)
|
| -@@ -1389,6 +1394,11 @@ bad:
|
| - }
|
| - #endif
|
| -
|
| -+ if (snapstart)
|
| -+ {
|
| -+ static const unsigned char orbit[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
| -+ SSL_CTX_set_snap_start_orbit(ctx, orbit);
|
| -+ }
|
| -
|
| - #ifndef OPENSSL_NO_DH
|
| - if (!no_dhe)
|
| -@@ -2031,6 +2041,7 @@ static int init_ssl_connection(SSL *con)
|
| - unsigned next_proto_neg_len;
|
| - #endif
|
| -
|
| -+again:
|
| - if ((i=SSL_accept(con)) <= 0)
|
| - {
|
| - if (BIO_sock_should_retry(i))
|
| -@@ -2039,6 +2050,12 @@ static int init_ssl_connection(SSL *con)
|
| - return(1);
|
| - }
|
| -
|
| -+ if (SSL_get_error(con, i) == SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING)
|
| -+ {
|
| -+ SSL_set_suggested_server_random_validity(con, 1);
|
| -+ goto again;
|
| -+ }
|
| -+
|
| - BIO_printf(bio_err,"ERROR\n");
|
| - verify_error=SSL_get_verify_result(con);
|
| - if (verify_error != X509_V_OK)
|
| -@@ -2224,6 +2241,9 @@ static int www_body(char *hostname, int s, unsigned char *context)
|
| - case SSL_ERROR_WANT_READ:
|
| - case SSL_ERROR_WANT_X509_LOOKUP:
|
| - continue;
|
| -+ case SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING:
|
| -+ SSL_set_suggested_server_random_validity(con, 1);
|
| -+ continue;
|
| - case SSL_ERROR_SYSCALL:
|
| - case SSL_ERROR_SSL:
|
| - case SSL_ERROR_ZERO_RETURN:
|
| -diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
|
| -index 06e5466..e32f97d 100644
|
| ---- a/ssl/s3_enc.c
|
| -+++ b/ssl/s3_enc.c
|
| -@@ -111,6 +111,7 @@
|
| -
|
| - #include <stdio.h>
|
| - #include "ssl_locl.h"
|
| -+#include "fnv1a64.h"
|
| - #include <openssl/evp.h>
|
| - #include <openssl/md5.h>
|
| -
|
| -@@ -529,6 +530,11 @@ void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
|
| - {
|
| - EVP_DigestUpdate(&(s->s3->finish_dgst1),buf,len);
|
| - EVP_DigestUpdate(&(s->s3->finish_dgst2),buf,len);
|
| -+ if (s->s3->snap_start_requested)
|
| -+ {
|
| -+ /* Compute Fowler-Noll-Vo (FNV) hash for Snap Start handshake */
|
| -+ fnv1a64_update((FNV1A64*) s->s3->response_hash, buf, len);
|
| -+ }
|
| - }
|
| -
|
| - int ssl3_cert_verify_mac(SSL *s, EVP_MD_CTX *ctx, unsigned char *p)
|
| -diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
|
| -index 84bff8d..1058b4e 100644
|
| ---- a/ssl/s3_lib.c
|
| -+++ b/ssl/s3_lib.c
|
| -@@ -1701,6 +1701,12 @@ void ssl3_free(SSL *s)
|
| - pq_64bit_free(&(s->s3->rrec.seq_num));
|
| - pq_64bit_free(&(s->s3->wrec.seq_num));
|
| -
|
| -+ if (s->s3->snap_start_client_hello.buf)
|
| -+ {
|
| -+ /* s->s3->snap_start_records, if set, uses the same buffer */
|
| -+ OPENSSL_free(s->s3->snap_start_client_hello.buf);
|
| -+ }
|
| -+
|
| - OPENSSL_cleanse(s->s3,sizeof *s->s3);
|
| - OPENSSL_free(s->s3);
|
| - s->s3=NULL;
|
| -diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
|
| -index 6853058..61774b2 100644
|
| ---- a/ssl/s3_pkt.c
|
| -+++ b/ssl/s3_pkt.c
|
| -@@ -120,8 +120,51 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
|
| - unsigned int len, int create_empty_fragment);
|
| - static int ssl3_get_record(SSL *s);
|
| -
|
| -+/* ssl3_read_snap_start_n reads from the opportunistic records contained within
|
| -+ * a Snap Start extension. |s->packet| and |s->packet_length| are set to frame
|
| -+ * a record within this area. Partial records are not allowed. The Snap Start
|
| -+ * records are held in |s->s3->snap_start_records| and the |left| member must
|
| -+ * be non-zero on entry.
|
| -+ *
|
| -+ * If |extend| is true then we'll expand the currently framed record by |n|
|
| -+ * bytes, otherwise we frame a new record. */
|
| -+static int ssl3_read_snap_start_n(SSL *s, int n, int extend)
|
| -+ {
|
| -+ if (!extend)
|
| -+ {
|
| -+ s->packet = s->s3->snap_start_records.buf + s->s3->snap_start_records.offset;
|
| -+ s->packet_length = 0;
|
| -+ }
|
| -+
|
| -+ if (s->s3->snap_start_records.left < n)
|
| -+ {
|
| -+ /* We aren't called unless .left is non-zero, therefore this
|
| -+ * means that we wanted to read more than we have. Since
|
| -+ * partial records aren't allowed, this is fatal. */
|
| -+ SSLerr(SSL_F_SSL3_READ_SNAP_START_N,SSL_R_BAD_PACKET_LENGTH);
|
| -+ return -1;
|
| -+ }
|
| -+
|
| -+ s->packet_length += n;
|
| -+ s->s3->snap_start_records.left -= n;
|
| -+ s->s3->snap_start_records.offset += n;
|
| -+
|
| -+ return n;
|
| -+ }
|
| -+
|
| - int ssl3_read_n(SSL *s, int n, int max, int extend)
|
| - {
|
| -+ if (s->s3->snap_start_records.left)
|
| -+ return ssl3_read_snap_start_n(s, n, extend);
|
| -+ else if (s->s3->snap_start_client_hello.buf && !extend)
|
| -+ {
|
| -+ /* If we started reading the opportunistic records then we know
|
| -+ * that we didn't enter recovery. Thus it's safe to free the
|
| -+ * copy of the ClientHello now because we'll not need it again. */
|
| -+ OPENSSL_free(s->s3->snap_start_client_hello.buf);
|
| -+ s->s3->snap_start_client_hello.buf = NULL;
|
| -+ }
|
| -+
|
| - /* If extend == 0, obtain new n-byte packet; if extend == 1, increase
|
| - * packet by another n bytes.
|
| - * The packet will be in the sub-array of s->s3->rbuf.buf specified
|
| -diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
|
| -index 8e0a504..315b8f3 100644
|
| ---- a/ssl/s3_srvr.c
|
| -+++ b/ssl/s3_srvr.c
|
| -@@ -144,6 +144,7 @@
|
| - #include <openssl/md5.h>
|
| -
|
| - static SSL_METHOD *ssl3_get_server_method(int ver);
|
| -+static int ssl3_snap_start_evaluate_handshake(SSL* s);
|
| - #ifndef OPENSSL_NO_ECDH
|
| - static int nid2curve_id(int nid);
|
| - #endif
|
| -@@ -300,10 +301,36 @@ int ssl3_accept(SSL *s)
|
| - case SSL3_ST_SW_SRVR_HELLO_A:
|
| - case SSL3_ST_SW_SRVR_HELLO_B:
|
| - ret=ssl3_send_server_hello(s);
|
| -+ if (ret == SERVER_RANDOM_VALIDATION_PENDING)
|
| -+ {
|
| -+ s->rwstate = SSL_SERVER_RANDOM_VALIDATE;
|
| -+ s->state = SSL3_ST_SW_SRVR_HELLO_A;
|
| -+ s->init_num = 0;
|
| -+ goto end;
|
| -+ }
|
| - if (ret <= 0) goto end;
|
| - #ifndef OPENSSL_NO_TLSEXT
|
| -+ if ((s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kRSA &&
|
| -+ (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kKRB5 &&
|
| -+ (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kDHr &&
|
| -+ (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kDHd &&
|
| -+ (s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK) != SSL_kECDH &&
|
| -+ s->s3->snap_start_requested)
|
| -+ {
|
| -+ /* There's no point in carrying on with a Snap
|
| -+ * Start handshake if we're using a cipher
|
| -+ * suite which is going to send a
|
| -+ * ServerKeyExchange message. */
|
| -+ ssl3_snap_start_reset_for_recovery(s);
|
| -+ s->state = SSL3_ST_SW_SRVR_HELLO_A;
|
| -+ break;
|
| -+ }
|
| -+
|
| - if (s->hit)
|
| - {
|
| -+ if (ssl3_snap_start_evaluate_handshake(s))
|
| -+ break;
|
| -+
|
| - if (s->tlsext_ticket_expected)
|
| - s->state=SSL3_ST_SW_SESSION_TICKET_A;
|
| - else
|
| -@@ -440,8 +467,19 @@ int ssl3_accept(SSL *s)
|
| - case SSL3_ST_SW_SRVR_DONE_B:
|
| - ret=ssl3_send_server_done(s);
|
| - if (ret <= 0) goto end;
|
| -- s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
|
| -- s->state=SSL3_ST_SW_FLUSH;
|
| -+
|
| -+ if (s->s3->snap_start_requested)
|
| -+ {
|
| -+ if (ssl3_snap_start_evaluate_handshake(s))
|
| -+ break;
|
| -+ s->state = SSL3_ST_SR_CERT_A;
|
| -+ }
|
| -+ else
|
| -+ {
|
| -+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
|
| -+ s->state=SSL3_ST_SW_FLUSH;
|
| -+ }
|
| -+
|
| - s->init_num=0;
|
| - break;
|
| -
|
| -@@ -1152,11 +1190,19 @@ int ssl3_send_server_hello(SSL *s)
|
| - if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
|
| - {
|
| - buf=(unsigned char *)s->init_buf->data;
|
| -- p=s->s3->server_random;
|
| -- Time=(unsigned long)time(NULL); /* Time */
|
| -- l2n(Time,p);
|
| -- if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
|
| -- return -1;
|
| -+ if (!s->s3->snap_start_requested)
|
| -+ {
|
| -+ p=s->s3->server_random;
|
| -+ Time=(unsigned long)time(NULL); /* Time */
|
| -+ l2n(Time,p);
|
| -+ if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
|
| -+ return -1;
|
| -+ }
|
| -+ else if (s->s3->server_random_suggestion_valid == 0)
|
| -+ {
|
| -+ return SERVER_RANDOM_VALIDATION_PENDING;
|
| -+ }
|
| -+
|
| - /* Do the message type and length last */
|
| - d=p= &(buf[4]);
|
| -
|
| -@@ -2952,3 +2998,55 @@ int ssl3_send_cert_status(SSL *s)
|
| - return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
|
| - }
|
| - #endif
|
| -+
|
| -+/* ssl3_snap_start_evaluate_handshake verifies the Snap Start prediction (if
|
| -+ * this is a Snap Start handshake). If it returns non-zero, then we are
|
| -+ * entering recovery and |s->state| has been set accordingly. */
|
| -+static int ssl3_snap_start_evaluate_handshake(SSL* s)
|
| -+ {
|
| -+ unsigned char digest[8];
|
| -+
|
| -+ if (!s->s3->snap_start_requested)
|
| -+ return 0;
|
| -+
|
| -+ /* Drop the currently queued messages. Either we're entering recovery,
|
| -+ * in which case they're wrong, or we're doing snap start, in which
|
| -+ * case we don't want to send them. */
|
| -+ if (!ssl_init_wbio_buffer(s, 1 /* push new BIO */))
|
| -+ return -1;
|
| -+
|
| -+ fnv1a64_final(digest, (FNV1A64*) s->s3->response_hash);
|
| -+
|
| -+ /* Turn off FNV hashing of handshake messages. */
|
| -+ s->s3->snap_start_requested = 0;
|
| -+
|
| -+ if (memcmp(digest, s->s3->predicted_response_hash, sizeof(digest)) != 0)
|
| -+ {
|
| -+ /* The predicted handshake didn't match. */
|
| -+ ssl3_snap_start_reset_for_recovery(s);
|
| -+ s->state = SSL3_ST_SW_SRVR_HELLO_A;
|
| -+ return 1;
|
| -+ }
|
| -+
|
| -+ return 0;
|
| -+ }
|
| -+
|
| -+/* ssl3_snap_start_reset_for_recovery is called is called when a Snap Start
|
| -+ * handshake is impossible because either the application layer has rejected
|
| -+ * the client's suggested server random, or predicated_response_hash failed to
|
| -+ * match response_hash */
|
| -+int ssl3_snap_start_reset_for_recovery(SSL* s)
|
| -+ {
|
| -+ s->s3->snap_start_requested = 0;
|
| -+ s->s3->snap_start_records.left = 0;
|
| -+ s->init_num = 0;
|
| -+
|
| -+ /* Reset the handshake hash and hash in the original ClientHello. */
|
| -+ ssl3_init_finished_mac(s);
|
| -+ ssl3_finish_mac(s, s->s3->snap_start_client_hello.buf, s->s3->snap_start_client_hello.left);
|
| -+
|
| -+ OPENSSL_free(s->s3->snap_start_client_hello.buf);
|
| -+ s->s3->snap_start_client_hello.buf = NULL;
|
| -+
|
| -+ return 0;
|
| -+ }
|
| -diff --git a/ssl/ssl.h b/ssl/ssl.h
|
| -index dc8dff8..bbe2543 100644
|
| ---- a/ssl/ssl.h
|
| -+++ b/ssl/ssl.h
|
| -@@ -770,6 +770,11 @@ struct ssl_ctx_st
|
| -
|
| - X509_VERIFY_PARAM *param;
|
| -
|
| -+ /* The configured Snap Start orbit value, if set. */
|
| -+ char snap_start_orbit_valid;
|
| -+ unsigned char snap_start_orbit[8];
|
| -+
|
| -+
|
| - #if 0
|
| - int purpose; /* Purpose setting */
|
| - int trust; /* Trust setting */
|
| -@@ -876,10 +881,14 @@ void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL *
|
| - void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len));
|
| - void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s, int (*cb) (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg), void *arg);
|
| - 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);
|
| -+void SSL_CTX_set_snap_start_orbit(SSL_CTX *s, const unsigned char orbit[8]);
|
| -
|
| - int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, const unsigned char *client, unsigned int client_len);
|
| - void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, unsigned *len);
|
| -
|
| -+void SSL_get0_suggested_server_random(const SSL *s, const unsigned char **data, unsigned *len);
|
| -+void SSL_set_suggested_server_random_validity(SSL *s, char is_valid);
|
| -+
|
| - #define OPENSSL_NPN_UNSUPPORTED 0
|
| - #define OPENSSL_NPN_NEGOTIATED 1
|
| - #define OPENSSL_NPN_NO_OVERLAP 2
|
| -@@ -888,12 +897,14 @@ void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, un
|
| - #define SSL_WRITING 2
|
| - #define SSL_READING 3
|
| - #define SSL_X509_LOOKUP 4
|
| -+#define SSL_SERVER_RANDOM_VALIDATE 6
|
| -
|
| - /* These will only be used when doing non-blocking IO */
|
| - #define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING)
|
| - #define SSL_want_read(s) (SSL_want(s) == SSL_READING)
|
| - #define SSL_want_write(s) (SSL_want(s) == SSL_WRITING)
|
| - #define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP)
|
| -+#define SSL_want_server_random_validation(s) (SSL_want(s) == SSL_SERVER_RANDOM_VALIDATE)
|
| -
|
| - struct ssl_st
|
| - {
|
| -@@ -1255,6 +1266,7 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
|
| - #define SSL_ERROR_ZERO_RETURN 6
|
| - #define SSL_ERROR_WANT_CONNECT 7
|
| - #define SSL_ERROR_WANT_ACCEPT 8
|
| -+#define SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING 10
|
| -
|
| - #define SSL_CTRL_NEED_TMP_RSA 1
|
| - #define SSL_CTRL_SET_TMP_RSA 2
|
| -@@ -1754,6 +1766,7 @@ void ERR_load_SSL_strings(void);
|
| - #define SSL_F_GET_SERVER_VERIFY 110
|
| - #define SSL_F_I2D_SSL_SESSION 111
|
| - #define SSL_F_READ_N 112
|
| -+#define SSL_F_SSL3_READ_SNAP_START_N 300
|
| - #define SSL_F_REQUEST_CERTIFICATE 113
|
| - #define SSL_F_SERVER_FINISH 239
|
| - #define SSL_F_SERVER_HELLO 114
|
| -@@ -1907,7 +1920,7 @@ void ERR_load_SSL_strings(void);
|
| - #define SSL_F_TLS1_ENC 210
|
| - #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
|
| - #define SSL_F_WRITE_PENDING 212
|
| --/* Next entry: 299 */
|
| -+/* Next entry: 300 */
|
| -
|
| - /* Reason codes. */
|
| - #define SSL_R_APP_DATA_IN_HANDSHAKE 100
|
| -diff --git a/ssl/ssl3.h b/ssl/ssl3.h
|
| -index 54b73b7..4a6e8cf 100644
|
| ---- a/ssl/ssl3.h
|
| -+++ b/ssl/ssl3.h
|
| -@@ -452,6 +452,48 @@ typedef struct ssl3_state_st
|
| - unsigned char previous_server_finished[EVP_MAX_MD_SIZE];
|
| - unsigned char previous_server_finished_len;
|
| - int send_connection_binding; /* TODOEKR */
|
| -+
|
| -+ /* Snap Start support (server-side only):
|
| -+ *
|
| -+ * Snap Start allows the client to 'suggest' the value of our random
|
| -+ * nonce. Assuming that we accept this suggestion, then the client can
|
| -+ * predict our exact reply and calculate a complete handshake based on
|
| -+ * that. These opportunistic handshake messages are embedded in the
|
| -+ * Snap Start extension, possibly including application data.
|
| -+ *
|
| -+ * (Note that if the handshake doesn't resume a session, the client
|
| -+ * couldn't hope to predict the exact server reply unless it uses the
|
| -+ * session ticket extension to suppress session ID generation.)
|
| -+ *
|
| -+ * All this allows for a TLS handshake that doesn't incur additional
|
| -+ * latency if the client side sends application data first. */
|
| -+
|
| -+ /* Set if the client presented a Snap Start extension (empty or
|
| -+ * otherwise and the SSL_CTX has a cell configured. Server side only. */
|
| -+ int snap_start_ext_seen;
|
| -+ /* Set if the client-suggested a server random value (which is stored
|
| -+ * in |server_random|) */
|
| -+ char snap_start_requested;
|
| -+ /* Set if the appplication has indicated that the client's
|
| -+ * server_random suggestion is acceptable (see
|
| -+ * SSL_set_suggested_server_random_validity). If so, a Snap Start
|
| -+ * handshake will be attempted. */
|
| -+ char server_random_suggestion_valid;
|
| -+ /* Client's predicted response_hash from client snap start extension.
|
| -+ * Valid if |snap_start_requested| is set. */
|
| -+ unsigned char predicted_response_hash[8];
|
| -+ /* Actual server handshake message hash. A Snap Start handshake is
|
| -+ * possible only if predicated_response_hash matches this. */
|
| -+ unsigned char response_hash[8];
|
| -+ /* If we need to enter snap start recovery then we need to reset the
|
| -+ * Finished hash with a different value for the ClientHello. Thus, we
|
| -+ * need a copy of the whole ClientHello: */
|
| -+ SSL3_BUFFER snap_start_client_hello;
|
| -+ /* A snap start ClientHello can contain records embedded in an
|
| -+ * extension. If we wish to read them then this points to the records
|
| -+ * within |snap_start_client_hello|. */
|
| -+ SSL3_BUFFER snap_start_records;
|
| -+
|
| - } SSL3_STATE;
|
| -
|
| -
|
| -diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
|
| -index cfa70ec..88358fb 100644
|
| ---- a/ssl/ssl_lib.c
|
| -+++ b/ssl/ssl_lib.c
|
| -@@ -2119,6 +2119,9 @@ int SSL_get_error(const SSL *s,int i)
|
| - return(SSL_ERROR_SSL);
|
| - }
|
| -
|
| -+ if ((i < 0) && SSL_want_server_random_validation(s))
|
| -+ return(SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING);
|
| -+
|
| - if ((i < 0) && SSL_want_read(s))
|
| - {
|
| - bio=SSL_get_rbio(s);
|
| -@@ -2876,6 +2879,61 @@ void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned
|
| - ctx->next_proto_select_cb = cb;
|
| - ctx->next_proto_select_cb_arg = arg;
|
| - }
|
| -+
|
| -+/* SSL_CTX_set_snap_start_orbit sets the orbit value which will be echoed back
|
| -+ * to the client and enables Snap Start for this context.
|
| -+ *
|
| -+ * An orbit value can be used to spatially partition the state needed to support
|
| -+ * Snap Start. See the comments above SSL_set_suggested_server_random_validity
|
| -+ * (below). */
|
| -+void SSL_CTX_set_snap_start_orbit(SSL_CTX *ctx, const unsigned char orbit[8])
|
| -+ {
|
| -+ memcpy(ctx->snap_start_orbit, orbit, sizeof(ctx->snap_start_orbit));
|
| -+ ctx->snap_start_orbit_valid = 1;
|
| -+ }
|
| -+
|
| -+/* Once SSL_accept has returned with SSL_SERVER_RANDOM_VALIDATE, then one can
|
| -+ * call this function in order to get the client's suggested server random
|
| -+ * value. */
|
| -+void SSL_get0_suggested_server_random(const SSL* s, const unsigned char **data, unsigned *length)
|
| -+ {
|
| -+ if (!s->s3->snap_start_requested)
|
| -+ {
|
| -+ *data = NULL;
|
| -+ *length = 0;
|
| -+ return;
|
| -+ }
|
| -+ *length = 32;
|
| -+ *data = s->s3->server_random;
|
| -+ }
|
| -+
|
| -+/* SSL_set_suggested_server_random_validity passes judgement on a
|
| -+ * client-suggested random value (obtained from
|
| -+ * SSL_get0_suggested_server_random). Rejecting the value triggers a recovery,
|
| -+ * while accepting the value /may/ result in a successful Snap Start, as long
|
| -+ * as the client predicted the handshake correctly.
|
| -+ *
|
| -+ * In order to accept a random value the user must ensure that it has NEVER
|
| -+ * been used before by this server, or any server configured with any of the
|
| -+ * same certificates. It may reject more if necessary.
|
| -+ *
|
| -+ * The first four bytes of the random value contain a timestamp (UNIX seconds
|
| -+ * since the epoch) which can be used to manage a time window. Additionally,
|
| -+ * the following eight bytes contain the orbit which which can also bound the
|
| -+ * state required if geographically separate servers share certificates.
|
| -+ *
|
| -+ * It's recommended that the time window have a maximum size, independent of
|
| -+ * the resources available, in order to prevent an attacker from arbitrarily
|
| -+ * delaying a Snap Start handshake.
|
| -+ */
|
| -+void SSL_set_suggested_server_random_validity(SSL *s, char is_valid)
|
| -+ {
|
| -+ if (is_valid)
|
| -+ s->s3->server_random_suggestion_valid = 1;
|
| -+ else
|
| -+ ssl3_snap_start_reset_for_recovery(s);
|
| -+ }
|
| -+
|
| - #endif
|
| -
|
| - int SSL_cutthrough_complete(const SSL *s)
|
| -diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
|
| -index a9183ff..639a185 100644
|
| ---- a/ssl/ssl_locl.h
|
| -+++ b/ssl/ssl_locl.h
|
| -@@ -392,6 +392,11 @@
|
| - #define CERT_PRIVATE_KEY 2
|
| - */
|
| -
|
| -+/* This can be returned from ssl3_send_server_hello to indicate that an
|
| -+ * offline validation of a client-suggested server_random needs to be
|
| -+ * performed. */
|
| -+#define SERVER_RANDOM_VALIDATION_PENDING -(TLSEXT_TYPE_snap_start)
|
| -+
|
| - #ifndef OPENSSL_NO_EC
|
| - /* From ECC-TLS draft, used in encoding the curve type in
|
| - * ECParameters
|
| -@@ -915,6 +920,7 @@ int ssl3_get_client_certificate(SSL *s);
|
| - int ssl3_get_client_key_exchange(SSL *s);
|
| - int ssl3_get_cert_verify(SSL *s);
|
| - int ssl3_get_next_proto(SSL *s);
|
| -+int ssl3_snap_start_reset_for_recovery(SSL* s);
|
| -
|
| - int dtls1_send_hello_request(SSL *s);
|
| - int dtls1_send_server_hello(SSL *s);
|
| -diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
|
| -index fd35b18..ce33f16 100644
|
| ---- a/ssl/t1_lib.c
|
| -+++ b/ssl/t1_lib.c
|
| -@@ -62,6 +62,7 @@
|
| - #include <openssl/hmac.h>
|
| - #include <openssl/ocsp.h>
|
| - #include "ssl_locl.h"
|
| -+#include "fnv1a64.h"
|
| -
|
| - const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT;
|
| -
|
| -@@ -368,6 +369,21 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
| - }
|
| - }
|
| -
|
| -+ if (s->s3->snap_start_ext_seen)
|
| -+ {
|
| -+ if ((long)(limit - ret - 14) < 0) return NULL;
|
| -+ s2n(TLSEXT_TYPE_snap_start,ret);
|
| -+ s2n(10,ret); /* extension length */
|
| -+ memcpy(ret, s->ctx->snap_start_orbit, 8);
|
| -+ ret += 8;
|
| -+ /* This is the ciphersuite that we would pick in the event of a
|
| -+ * Snap Start handshake. (Maybe the server wants to do EDH
|
| -+ * unless the client is Snap Start capable). At the moment we
|
| -+ * don't have any logic to pick a different cipher suite so we
|
| -+ * repeat the choice from the ServerHello. */
|
| -+ s2n(s->s3->tmp.new_cipher->id & 0xffff,ret);
|
| -+ }
|
| -+
|
| - if ((extdatalen = ret-p-2)== 0)
|
| - return p;
|
| -
|
| -@@ -375,6 +391,174 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
| - return ret;
|
| - }
|
| -
|
| -+
|
| -+static int ssl_hash_snap_start_client_hello(SSL* s,
|
| -+ const char* data,
|
| -+ unsigned len,
|
| -+ unsigned ext_len)
|
| -+ {
|
| -+ /* We walk the ClientHello from the beginning, writing
|
| -+ * adjusted lengths into |b| and hashing as we go.
|
| -+ *
|
| -+ * The resulting ClientHello is going to be shorter by the length of
|
| -+ * this extension, which is |ext_len + 4| (two bytes for the type and two for
|
| -+ * the length). */
|
| -+
|
| -+ const unsigned char *p;
|
| -+ unsigned remaining;
|
| -+ unsigned char b[3], *c;
|
| -+ unsigned long l;
|
| -+
|
| -+ p = (unsigned char*) data;
|
| -+ remaining = len;
|
| -+ /* Handshake header: type */
|
| -+ if (!remaining)
|
| -+ return 0;
|
| -+ ssl3_finish_mac(s, p, 1);
|
| -+ p++;
|
| -+ remaining--;
|
| -+ /* Handshake header: length */
|
| -+ if (remaining < 3)
|
| -+ return 0;
|
| -+ n2l3(p, l);
|
| -+ l -= ext_len + 4;
|
| -+ c = b;
|
| -+ l2n3(l, c);
|
| -+ ssl3_finish_mac(s, b, 3);
|
| -+ remaining -= 3;
|
| -+ /* ClientHello: version and random */
|
| -+ if (remaining < 34)
|
| -+ return 0;
|
| -+ ssl3_finish_mac(s, p, 34);
|
| -+ p += 34;
|
| -+ remaining -= 34;
|
| -+ /* ClientHello: session id length */
|
| -+ if (!remaining)
|
| -+ return 0;
|
| -+ l = *p;
|
| -+ ssl3_finish_mac(s, p, 1);
|
| -+ p++;
|
| -+ remaining--;
|
| -+ /* ClientHello: session id */
|
| -+ if (remaining < l)
|
| -+ return 0;
|
| -+ ssl3_finish_mac(s, p, l);
|
| -+ p += l;
|
| -+ remaining -= l;
|
| -+ /* ClientHello: cipher suites length */
|
| -+ if (remaining < 2)
|
| -+ return 0;
|
| -+ ssl3_finish_mac(s, p, 2);
|
| -+ n2s(p, l);
|
| -+ remaining -= 2;
|
| -+ /* ClientHello: cipher suites */
|
| -+ if (remaining < l)
|
| -+ return 0;
|
| -+ ssl3_finish_mac(s, p, l);
|
| -+ p += l;
|
| -+ remaining -= l;
|
| -+ /* ClientHello: compression methods length */
|
| -+ if (!remaining)
|
| -+ return 0;
|
| -+ l = *p;
|
| -+ ssl3_finish_mac(s, p, 1);
|
| -+ p++;
|
| -+ remaining--;
|
| -+ /* ClientHello: compression methods */
|
| -+ if (remaining < l)
|
| -+ return 0;
|
| -+ ssl3_finish_mac(s, p, l);
|
| -+ p += l;
|
| -+ remaining -= l;
|
| -+ /* ClientHello: extensions length (must exist given that we're already
|
| -+ * parsing the extensions from it */
|
| -+ if (remaining < 2)
|
| -+ return 0;
|
| -+ n2s(p, l);
|
| -+ remaining -= 2;
|
| -+ if (l != remaining || l < ext_len + 4)
|
| -+ return 0;
|
| -+ l -= ext_len + 4;
|
| -+ c = b;
|
| -+ s2n(l, c);
|
| -+ ssl3_finish_mac(s, b, 2);
|
| -+
|
| -+ while (remaining)
|
| -+ {
|
| -+ unsigned long extension_type, extension_len;
|
| -+ if (remaining < 4)
|
| -+ return 0;
|
| -+ n2s(p, extension_type);
|
| -+ n2s(p, extension_len);
|
| -+ remaining -= 4;
|
| -+ if (remaining < extension_len)
|
| -+ return 0;
|
| -+ if (extension_type != TLSEXT_TYPE_snap_start)
|
| -+ ssl3_finish_mac(s, p - 4, extension_len + 4);
|
| -+ p += extension_len;
|
| -+ remaining -= extension_len;
|
| -+ }
|
| -+
|
| -+ return 1;
|
| -+ }
|
| -+
|
| -+static char ssl_parse_snap_start_tlsext(SSL *s, const unsigned char *data, unsigned short len)
|
| -+ {
|
| -+ ptrdiff_t extension_offset = data - (unsigned char *) s->init_buf->data;
|
| -+
|
| -+ if (len > 0 && len < 36)
|
| -+ return 0;
|
| -+ s->s3->snap_start_ext_seen = 1;
|
| -+ if (len == 0)
|
| -+ return 1;
|
| -+
|
| -+ fnv1a64_init((FNV1A64*) s->s3->response_hash);
|
| -+
|
| -+ /* We need to make a copy of the ClientHello because we'll be hashing a
|
| -+ * modified version. However, if we enter recovery then we need to hash
|
| -+ * the unchanged message.
|
| -+ *
|
| -+ * We are adding 4 bytes to the length here because we're including the
|
| -+ * handshake header. */
|
| -+ s->s3->snap_start_client_hello.left = s->init_num + 4;
|
| -+ s->s3->snap_start_client_hello.offset = 0;
|
| -+ s->s3->snap_start_client_hello.buf = OPENSSL_malloc(s->init_num + 4);
|
| -+ if (!s->s3->snap_start_client_hello.buf)
|
| -+ {
|
| -+ /* If we're out of memory then we pretend that we
|
| -+ * didn't see the extension. */
|
| -+ s->s3->snap_start_ext_seen = 0;
|
| -+ return 1;
|
| -+ }
|
| -+
|
| -+ memcpy(s->s3->snap_start_client_hello.buf, s->init_buf->data, s->init_num + 4);
|
| -+ memcpy(s->s3->server_random, s->s3->client_random, 4); /* time */
|
| -+ memcpy(s->s3->server_random + 4, data, 28); /* orbit and random bytes */
|
| -+ memcpy(s->s3->predicted_response_hash, data + 28, 8);
|
| -+
|
| -+ /* Point snap_start_records to within the copy of the ClientHello */
|
| -+ s->s3->snap_start_records.offset = 0;
|
| -+ s->s3->snap_start_records.left = len - 36;
|
| -+ s->s3->snap_start_records.buf = s->s3->snap_start_client_hello.buf + extension_offset + 36;
|
| -+
|
| -+ /* Reset the handshake hash */
|
| -+ ssl3_init_finished_mac(s);
|
| -+
|
| -+ /* Need to hash the ClientHello as if the snap start extension wasn't
|
| -+ * included. */
|
| -+ if (!ssl_hash_snap_start_client_hello(
|
| -+ s,
|
| -+ s->init_buf->data,
|
| -+ s->init_num + 4 /* four bytes of handshake header */,
|
| -+ len))
|
| -+ {
|
| -+ return 0;
|
| -+ }
|
| -+
|
| -+ s->s3->snap_start_requested = 1;
|
| -+ return 1;
|
| -+ }
|
| -+
|
| - int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
|
| - {
|
| - unsigned short type;
|
| -@@ -627,6 +811,12 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in
|
| - s->s3->next_proto_neg_seen = 1;
|
| - }
|
| -
|
| -+ else if (type == TLSEXT_TYPE_snap_start && s->ctx->snap_start_orbit_valid)
|
| -+ {
|
| -+ if (ssl_parse_snap_start_tlsext(s, data, size) == 0)
|
| -+ return 0;
|
| -+ }
|
| -+
|
| - /* session ticket processed earlier */
|
| -
|
| - data+=size;
|
| -diff --git a/ssl/tls1.h b/ssl/tls1.h
|
| -index 71d76de..52ff325 100644
|
| ---- a/ssl/tls1.h
|
| -+++ b/ssl/tls1.h
|
| -@@ -120,6 +120,8 @@ extern "C" {
|
| -
|
| - /* This is not an IANA defined extension number */
|
| - #define TLSEXT_TYPE_next_proto_neg 13172
|
| -+ /* http://tools.ietf.org/html/draft-agl-tls-snapstart-00 */
|
| -+#define TLSEXT_TYPE_snap_start 13174
|
| -
|
| - /* NameType value from RFC 3546 */
|
| - #define TLSEXT_NAMETYPE_host_name 0
|
|
|