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