Extra Makefile hack for compatibility with OpenBSD 'make'.
[BearSSL] / src / ssl / ssl_engine.c
index 32bc406..529b107 100644 (file)
@@ -1091,6 +1091,9 @@ jump_handshake(br_ssl_engine_context *cc, int action)
                cc->hlen_out = hlen_out;
                cc->action = action;
                cc->hsrun(&cc->cpu);
+               if (br_ssl_engine_closed(cc)) {
+                       return;
+               }
                if (cc->hbuf_out != cc->saved_hbuf_out) {
                        sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
                }
@@ -1129,7 +1132,7 @@ br_ssl_engine_flush_record(br_ssl_engine_context *cc)
 unsigned char *
 br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len)
 {
-       if (!cc->application_data) {
+       if (!(cc->application_data & 1)) {
                *len = 0;
                return NULL;
        }
@@ -1147,7 +1150,7 @@ br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len)
 unsigned char *
 br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len)
 {
-       if (!cc->application_data
+       if (!(cc->application_data & 1)
                || cc->record_type_in != BR_SSL_APPLICATION_DATA)
        {
                *len = 0;
@@ -1177,7 +1180,7 @@ br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len)
        sendrec_ack(cc, len);
        if (len != 0 && !has_rec_tosend(cc)
                && (cc->record_type_out != BR_SSL_APPLICATION_DATA
-               || cc->application_data == 0))
+               || (cc->application_data & 1) == 0))
        {
                jump_handshake(cc, 0);
        }
@@ -1215,9 +1218,20 @@ br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len)
                        jump_handshake(cc, 0);
                        break;
                case BR_SSL_APPLICATION_DATA:
-                       if (cc->application_data) {
+                       if (cc->application_data == 1) {
+                               break;
+                       }
+
+                       /*
+                        * If we are currently closing, and waiting for
+                        * a close_notify from the peer, then incoming
+                        * application data should be discarded.
+                        */
+                       if (cc->application_data == 2) {
+                               recvpld_ack(cc, len);
                                break;
                        }
+
                        /* Fall through */
                default:
                        br_ssl_engine_fail(cc, BR_ERR_UNEXPECTED);
@@ -1239,8 +1253,11 @@ br_ssl_engine_close(br_ssl_engine_context *cc)
 int
 br_ssl_engine_renegotiate(br_ssl_engine_context *cc)
 {
+       size_t len;
+
        if (br_ssl_engine_closed(cc) || cc->reneg == 1
-               || (cc->flags & BR_OPT_NO_RENEGOTIATION) != 0)
+               || (cc->flags & BR_OPT_NO_RENEGOTIATION) != 0
+               || br_ssl_engine_recvapp_buf(cc, &len) != NULL)
        {
                return 0;
        }
@@ -1279,7 +1296,7 @@ br_ssl_engine_current_state(const br_ssl_engine_context *cc)
 void
 br_ssl_engine_flush(br_ssl_engine_context *cc, int force)
 {
-       if (!br_ssl_engine_closed(cc) && cc->application_data) {
+       if (!br_ssl_engine_closed(cc) && (cc->application_data & 1) != 0) {
                sendpld_flush(cc, force);
        }
 }
@@ -1296,6 +1313,7 @@ br_ssl_engine_hs_reset(br_ssl_engine_context *cc,
        cc->hsrun = hsrun;
        cc->shutdown_recv = 0;
        cc->application_data = 0;
+       cc->alert = 0;
        jump_handshake(cc, 0);
 }
 
@@ -1320,13 +1338,14 @@ br_ssl_engine_compute_master(br_ssl_engine_context *cc,
        int prf_id, const void *pms, size_t pms_len)
 {
        br_tls_prf_impl iprf;
-       unsigned char seed[64];
+       br_tls_prf_seed_chunk seed[2] = {
+               { cc->client_random, sizeof cc->client_random },
+               { cc->server_random, sizeof cc->server_random }
+       };
 
        iprf = br_ssl_engine_get_PRF(cc, prf_id);
-       memcpy(seed, cc->client_random, 32);
-       memcpy(seed + 32, cc->server_random, 32);
        iprf(cc->session.master_secret, sizeof cc->session.master_secret,
-               pms, pms_len, "master secret", seed, sizeof seed);
+               pms, pms_len, "master secret", 2, seed);
 }
 
 /*
@@ -1337,14 +1356,15 @@ compute_key_block(br_ssl_engine_context *cc, int prf_id,
        size_t half_len, unsigned char *kb)
 {
        br_tls_prf_impl iprf;
-       unsigned char seed[64];
+       br_tls_prf_seed_chunk seed[2] = {
+               { cc->server_random, sizeof cc->server_random },
+               { cc->client_random, sizeof cc->client_random }
+       };
 
        iprf = br_ssl_engine_get_PRF(cc, prf_id);
-       memcpy(seed, cc->server_random, 32);
-       memcpy(seed + 32, cc->client_random, 32);
        iprf(kb, half_len << 1,
                cc->session.master_secret, sizeof cc->session.master_secret,
-               "key expansion", seed, sizeof seed);
+               "key expansion", 2, seed);
 }
 
 /* see inner.h */
@@ -1474,3 +1494,44 @@ br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc,
        cc->igcm_out->init(&cc->out.gcm.vtable.out,
                bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
 }
+
+/* see inner.h */
+void
+br_ssl_engine_switch_chapol_in(br_ssl_engine_context *cc,
+       int is_client, int prf_id)
+{
+       unsigned char kb[88];
+       unsigned char *cipher_key, *iv;
+
+       compute_key_block(cc, prf_id, 44, kb);
+       if (is_client) {
+               cipher_key = &kb[32];
+               iv = &kb[76];
+       } else {
+               cipher_key = &kb[0];
+               iv = &kb[64];
+       }
+       cc->ichapol_in->init(&cc->in.chapol.vtable.in,
+               cc->ichacha, cc->ipoly, cipher_key, iv);
+       cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_chapol_out(br_ssl_engine_context *cc,
+       int is_client, int prf_id)
+{
+       unsigned char kb[88];
+       unsigned char *cipher_key, *iv;
+
+       compute_key_block(cc, prf_id, 44, kb);
+       if (is_client) {
+               cipher_key = &kb[0];
+               iv = &kb[64];
+       } else {
+               cipher_key = &kb[32];
+               iv = &kb[76];
+       }
+       cc->ichapol_out->init(&cc->out.chapol.vtable.out,
+               cc->ichacha, cc->ipoly, cipher_key, iv);
+}