Fix a leak in SSL_clear()
[openssl.git] / ssl / record / rec_layer_s3.c
index c74799598db1adf163252e3037262b98464d421e..93b7d05b8d93580c550c6cd216e78d133d080354 100644 (file)
@@ -39,8 +39,6 @@ void RECORD_LAYER_init(RECORD_LAYER *rl, SSL *s)
 
 void RECORD_LAYER_clear(RECORD_LAYER *rl)
 {
-    unsigned int pipes;
-
     rl->rstate = SSL_ST_READ_HEADER;
 
     /*
@@ -62,9 +60,7 @@ void RECORD_LAYER_clear(RECORD_LAYER *rl)
     rl->wpend_buf = NULL;
 
     SSL3_BUFFER_clear(&rl->rbuf);
-    for (pipes = 0; pipes < rl->numwpipes; pipes++)
-        SSL3_BUFFER_clear(&rl->wbuf[pipes]);
-    rl->numwpipes = 0;
+    ssl3_release_write_buffer(rl->s);
     rl->numrpipes = 0;
     SSL3_RECORD_clear(rl->rrec, SSL_MAX_PIPELINES);
 
@@ -122,10 +118,9 @@ void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl)
     memset(rl->write_sequence, 0, sizeof(rl->write_sequence));
 }
 
-int ssl3_pending(const SSL *s)
+size_t ssl3_pending(const SSL *s)
 {
-    unsigned int i;
-    int num = 0;
+    size_t i, num = 0;
 
     if (s->rlayer.rstate == SSL_ST_READ_BODY)
         return 0;
@@ -179,13 +174,10 @@ const char *SSL_rstate_string(const SSL *s)
 }
 
 /*
- * Return values are as per SSL_read(), i.e.
- *  1 Success
- *  0 Failure (not retryable)
- * <0 Failure (may be retryable)
+ * Return values are as per SSL_read()
  */
 int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold,
-                size_t *read)
+                size_t *readbytes)
 {
     /*
      * If extend == 0, obtain new n-byte packet; if extend == 1, increase
@@ -271,13 +263,13 @@ int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold,
         s->rlayer.packet_length += n;
         rb->left = left - n;
         rb->offset += n;
-        *read = n;
+        *readbytes = n;
         return 1;
     }
 
     /* else we need to read more data */
 
-    if (n > (rb->len - rb->offset)) { /* does not happen */
+    if (n > rb->len - rb->offset) { /* does not happen */
         SSLerr(SSL_F_SSL3_READ_N, ERR_R_INTERNAL_ERROR);
         return -1;
     }
@@ -289,12 +281,12 @@ int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold,
     else {
         if (max < n)
             max = n;
-        if (max > (rb->len - rb->offset))
+        if (max > rb->len - rb->offset)
             max = rb->len - rb->offset;
     }
 
     while (left < n) {
-        size_t bioread;
+        size_t bioread = 0;
         int ret;
 
         /*
@@ -320,7 +312,7 @@ int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold,
             if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s))
                 if (len + left == 0)
                     ssl3_release_read_buffer(s);
-            return -1;
+            return ret;
         }
         left += bioread;
         /*
@@ -339,7 +331,7 @@ int ssl3_read_n(SSL *s, size_t n, size_t max, int extend, int clearold,
     rb->left = left - n;
     s->rlayer.packet_length += n;
     s->rwstate = SSL_NOTHING;
-    *read = n;
+    *readbytes = n;
     return 1;
 }
 
@@ -429,7 +421,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len,
 
             packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx,
                                           EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE,
-                                          max_send_fragment, NULL);
+                                          (int)max_send_fragment, NULL);
 
             if (len >= 8 * max_send_fragment)
                 packlen *= 8;
@@ -443,7 +435,8 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len,
         } else if (tot == len) { /* done? */
             /* free jumbo buffer */
             ssl3_release_write_buffer(s);
-            return tot;
+            *written = tot;
+            return 1;
         }
 
         n = (len - tot);
@@ -610,7 +603,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len,
             return i;
         }
 
-        if ((tmpwrit == n) ||
+        if (tmpwrit == n ||
             (type == SSL3_RT_APPLICATION_DATA &&
              (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) {
             /*
@@ -636,15 +629,18 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                   size_t *pipelens, size_t numpipes,
                   int create_empty_fragment, size_t *written)
 {
-    unsigned char *outbuf[SSL_MAX_PIPELINES], *plen[SSL_MAX_PIPELINES];
+    WPACKET pkt[SSL_MAX_PIPELINES];
     SSL3_RECORD wr[SSL_MAX_PIPELINES];
+    WPACKET *thispkt;
+    SSL3_RECORD *thiswr;
+    unsigned char *recordstart;
     int i, mac_size, clear = 0;
     size_t prefix_len = 0;
-    int eivlen;
+    int eivlen = 0;
     size_t align = 0;
     SSL3_BUFFER *wb;
     SSL_SESSION *sess;
-    size_t totlen = 0;
+    size_t totlen = 0, len, wpinited = 0;
     size_t j;
 
     for (j = 0; j < numpipes; j++)
@@ -729,21 +725,42 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
         align = (size_t)SSL3_BUFFER_get_buf(wb) + 2 * SSL3_RT_HEADER_LENGTH;
         align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
 #endif
-        outbuf[0] = SSL3_BUFFER_get_buf(wb) + align;
         SSL3_BUFFER_set_offset(wb, align);
+        if (!WPACKET_init_static_len(&pkt[0], SSL3_BUFFER_get_buf(wb),
+                                     SSL3_BUFFER_get_len(wb), 0)
+                || !WPACKET_allocate_bytes(&pkt[0], align, NULL)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        wpinited = 1;
     } else if (prefix_len) {
         wb = &s->rlayer.wbuf[0];
-        outbuf[0] = SSL3_BUFFER_get_buf(wb) + SSL3_BUFFER_get_offset(wb)
-            + prefix_len;
+        if (!WPACKET_init_static_len(&pkt[0],
+                                     SSL3_BUFFER_get_buf(wb),
+                                     SSL3_BUFFER_get_len(wb), 0)
+                || !WPACKET_allocate_bytes(&pkt[0], SSL3_BUFFER_get_offset(wb)
+                                                    + prefix_len, NULL)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        wpinited = 1;
     } else {
         for (j = 0; j < numpipes; j++) {
+            thispkt = &pkt[j];
+
             wb = &s->rlayer.wbuf[j];
-#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
+#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0
             align = (size_t)SSL3_BUFFER_get_buf(wb) + SSL3_RT_HEADER_LENGTH;
             align = SSL3_ALIGN_PAYLOAD - 1 - ((align - 1) % SSL3_ALIGN_PAYLOAD);
 #endif
-            outbuf[j] = SSL3_BUFFER_get_buf(wb) + align;
             SSL3_BUFFER_set_offset(wb, align);
+            if (!WPACKET_init_static_len(thispkt, SSL3_BUFFER_get_buf(wb),
+                                         SSL3_BUFFER_get_len(wb), 0)
+                    || !WPACKET_allocate_bytes(thispkt, align, NULL)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            wpinited++;
         }
     }
 
@@ -755,111 +772,197 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
             eivlen = EVP_CIPHER_CTX_iv_length(s->enc_write_ctx);
             if (eivlen <= 1)
                 eivlen = 0;
-        }
-        /* Need explicit part of IV for GCM mode */
-        else if (mode == EVP_CIPH_GCM_MODE)
+        } else if (mode == EVP_CIPH_GCM_MODE) {
+            /* Need explicit part of IV for GCM mode */
             eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN;
-        else if (mode == EVP_CIPH_CCM_MODE)
+        } else if (mode == EVP_CIPH_CCM_MODE) {
             eivlen = EVP_CCM_TLS_EXPLICIT_IV_LEN;
-        else
-            eivlen = 0;
-    } else
-        eivlen = 0;
+        }
+    }
 
     totlen = 0;
     /* Clear our SSL3_RECORD structures */
     memset(wr, 0, sizeof wr);
     for (j = 0; j < numpipes; j++) {
-        /* write the header */
-        *(outbuf[j]++) = type & 0xff;
-        SSL3_RECORD_set_type(&wr[j], type);
+        unsigned int version = s->version;
+        unsigned char *compressdata = NULL;
+        size_t maxcomplen;
+        unsigned int rectype;
+
+        thispkt = &pkt[j];
+        thiswr = &wr[j];
 
-        *(outbuf[j]++) = (s->version >> 8);
+        SSL3_RECORD_set_type(thiswr, type);
+        /*
+         * In TLSv1.3, once encrypting, we always use application data for the
+         * record type
+         */
+        if (SSL_IS_TLS13(s) && s->enc_write_ctx != NULL)
+            rectype = SSL3_RT_APPLICATION_DATA;
+        else
+            rectype = type;
         /*
          * Some servers hang if initial client hello is larger than 256 bytes
          * and record version number > TLS 1.0
          */
         if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO
             && !s->renegotiate && TLS1_get_version(s) > TLS1_VERSION)
-            *(outbuf[j]++) = 0x1;
-        else
-            *(outbuf[j]++) = s->version & 0xff;
+            version = TLS1_VERSION;
 
-        /* field where we are to write out packet length */
-        plen[j] = outbuf[j];
-        outbuf[j] += 2;
+        maxcomplen = pipelens[j];
+        if (s->compress != NULL)
+            pipelens[j] += SSL3_RT_MAX_COMPRESSED_OVERHEAD;
+
+        /* write the header */
+        if (!WPACKET_put_bytes_u8(thispkt, rectype)
+                || !WPACKET_put_bytes_u16(thispkt, version)
+                || !WPACKET_start_sub_packet_u16(thispkt)
+                || (eivlen > 0
+                    && !WPACKET_allocate_bytes(thispkt, eivlen, NULL))
+                || (maxcomplen > 0
+                    && !WPACKET_reserve_bytes(thispkt, maxcomplen,
+                                              &compressdata))) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
 
         /* lets setup the record stuff. */
-        SSL3_RECORD_set_data(&wr[j], outbuf[j] + eivlen);
-        SSL3_RECORD_set_length(&wr[j], pipelens[j]);
-        SSL3_RECORD_set_input(&wr[j], (unsigned char *)&buf[totlen]);
+        SSL3_RECORD_set_data(thiswr, compressdata);
+        SSL3_RECORD_set_length(thiswr, pipelens[j]);
+        SSL3_RECORD_set_input(thiswr, (unsigned char *)&buf[totlen]);
         totlen += pipelens[j];
 
         /*
-         * we now 'read' from wr->input, wr->length bytes into wr->data
+         * we now 'read' from thiswr->input, thiswr->length bytes into
+         * thiswr->data
          */
 
         /* first we compress */
         if (s->compress != NULL) {
-            if (!ssl3_do_compress(s, &wr[j])) {
+            /*
+             * TODO(TLS1.3): Make sure we prevent compression!!!
+             */
+            if (!ssl3_do_compress(s, thiswr)
+                    || !WPACKET_allocate_bytes(thispkt, thiswr->length, NULL)) {
                 SSLerr(SSL_F_DO_SSL3_WRITE, SSL_R_COMPRESSION_FAILURE);
                 goto err;
             }
         } else {
-            memcpy(wr[j].data, wr[j].input, wr[j].length);
+            if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
             SSL3_RECORD_reset_input(&wr[j]);
         }
 
+        if (SSL_IS_TLS13(s) && s->enc_write_ctx != NULL) {
+            if (!WPACKET_put_bytes_u8(thispkt, type)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+                goto err;
+            }
+            SSL3_RECORD_add_length(thiswr, 1);
+            /*
+             * TODO(TLS1.3): Padding goes here. Do we need an API to add this?
+             * For now, use no padding
+             */
+        }
+
         /*
-         * we should still have the output to wr->data and the input from
-         * wr->input.  Length should be wr->length. wr->data still points in the
-         * wb->buf
+         * we should still have the output to thiswr->data and the input from
+         * wr->input. Length should be thiswr->length. thiswr->data still points
+         * in the wb->buf
          */
 
         if (!SSL_USE_ETM(s) && mac_size != 0) {
-            if (s->method->ssl3_enc->mac(s, &wr[j],
-                                         &(outbuf[j][wr[j].length + eivlen]),
-                                         1) < 0)
+            unsigned char *mac;
+
+            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+                    || !s->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
                 goto err;
-            SSL3_RECORD_add_length(&wr[j], mac_size);
+            }
         }
 
-        SSL3_RECORD_set_data(&wr[j], outbuf[j]);
-        SSL3_RECORD_reset_input(&wr[j]);
-
-        if (eivlen) {
-            /*
-             * if (RAND_pseudo_bytes(p, eivlen) <= 0) goto err;
-             */
-            SSL3_RECORD_add_length(&wr[j], eivlen);
+        /*
+         * Reserve some bytes for any growth that may occur during encryption.
+         * This will be at most one cipher block or the tag length if using
+         * AEAD. SSL_RT_MAX_CIPHER_BLOCK_SIZE covers either case.
+         */
+        if(!WPACKET_reserve_bytes(thispkt, SSL_RT_MAX_CIPHER_BLOCK_SIZE,
+                                  NULL)
+                   /*
+                    * We also need next the amount of bytes written to this
+                    * sub-packet
+                    */
+                || !WPACKET_get_length(thispkt, &len)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
         }
+
+        /* Get a pointer to the start of this record excluding header */
+        recordstart = WPACKET_get_curr(thispkt) - len;
+
+        SSL3_RECORD_set_data(thiswr, recordstart);
+        SSL3_RECORD_reset_input(thiswr);
+        SSL3_RECORD_set_length(thiswr, len);
     }
 
     if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1)
         goto err;
 
     for (j = 0; j < numpipes; j++) {
+        size_t origlen;
+
+        thispkt = &pkt[j];
+        thiswr = &wr[j];
+
+        /* Allocate bytes for the encryption overhead */
+        if (!WPACKET_get_length(thispkt, &origlen)
+                   /* Encryption should never shrink the data! */
+                || origlen > thiswr->length
+                || (thiswr->length > origlen
+                    && !WPACKET_allocate_bytes(thispkt,
+                                               thiswr->length - origlen, NULL))) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
         if (SSL_USE_ETM(s) && mac_size != 0) {
-            if (s->method->ssl3_enc->mac(s, &wr[j],
-                                         outbuf[j] + wr[j].length, 1) < 0)
+            unsigned char *mac;
+
+            if (!WPACKET_allocate_bytes(thispkt, mac_size, &mac)
+                    || !s->method->ssl3_enc->mac(s, thiswr, mac, 1)) {
+                SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
                 goto err;
-            SSL3_RECORD_add_length(&wr[j], mac_size);
+            }
+            SSL3_RECORD_add_length(thiswr, mac_size);
         }
 
-        /* record length after mac and block padding */
-        s2n(SSL3_RECORD_get_length(&wr[j]), plen[j]);
+        if (!WPACKET_get_length(thispkt, &len)
+                || !WPACKET_close(thispkt)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
 
-        if (s->msg_callback)
-            s->msg_callback(1, 0, SSL3_RT_HEADER, plen[j] - 5, 5, s,
+        if (s->msg_callback) {
+            recordstart = WPACKET_get_curr(thispkt) - len
+                          - SSL3_RT_HEADER_LENGTH;
+            s->msg_callback(1, 0, SSL3_RT_HEADER, recordstart,
+                            SSL3_RT_HEADER_LENGTH, s,
                             s->msg_callback_arg);
+        }
+
+        if (!WPACKET_finish(thispkt)) {
+            SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
 
         /*
-         * we should now have wr->data pointing to the encrypted data, which is
-         * wr->length long
+         * we should now have thiswr->data pointing to the encrypted data, which
+         * is thiswr->length long
          */
-        SSL3_RECORD_set_type(&wr[j], type); /* not needed but helps for
+        SSL3_RECORD_set_type(thiswr, type); /* not needed but helps for
                                              * debugging */
-        SSL3_RECORD_add_length(&wr[j], SSL3_RT_HEADER_LENGTH);
+        SSL3_RECORD_add_length(thiswr, SSL3_RT_HEADER_LENGTH);
 
         if (create_empty_fragment) {
             /*
@@ -871,13 +974,13 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                 SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR);
                 goto err;
             }
-            *written = SSL3_RECORD_get_length(wr);
+            *written = SSL3_RECORD_get_length(thiswr);
             return 1;
         }
 
         /* now let's set up wb */
         SSL3_BUFFER_set_left(&s->rlayer.wbuf[j],
-                             prefix_len + SSL3_RECORD_get_length(&wr[j]));
+                             prefix_len + SSL3_RECORD_get_length(thiswr));
     }
 
     /*
@@ -892,15 +995,14 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
     /* we now just need to write the buffer */
     return ssl3_write_pending(s, type, buf, totlen, written);
  err:
+    for (j = 0; j < wpinited; j++)
+        WPACKET_cleanup(&pkt[j]);
     return -1;
 }
 
 /* if s->s3->wbuf.left != 0, we need to call this
  *
- * Return values are as per SSL_read(), i.e.
- *  1 Success
- *  0 Failure (not retryable)
- * <0 Failure (may be retryable)
+ * Return values are as per SSL_write()
  */
 int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
                        size_t *written)
@@ -908,7 +1010,7 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
     int i;
     SSL3_BUFFER *wb = s->rlayer.wbuf;
     size_t currbuf = 0;
-    size_t tmpwrit;
+    size_t tmpwrit = 0;
 
     if ((s->rlayer.wpend_tot > len)
         || ((s->rlayer.wpend_buf != buf) &&
@@ -955,7 +1057,7 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
                  */
                 SSL3_BUFFER_set_left(&wb[currbuf], 0);
             }
-            return -1;
+            return (i);
         }
         SSL3_BUFFER_add_offset(&wb[currbuf], tmpwrit);
         SSL3_BUFFER_sub_left(&wb[currbuf], tmpwrit);
@@ -992,10 +1094,10 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
  *             none of our business
  */
 int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
-                    size_t len, int peek, size_t *read)
+                    size_t len, int peek, size_t *readbytes)
 {
     int al, i, j, ret;
-    size_t n, curr_rec, num_recs, read_bytes;
+    size_t n, curr_rec, num_recs, totalbytes;
     SSL3_RECORD *rr;
     SSL3_BUFFER *rbuf;
     void (*cb) (const SSL *ssl, int type2, int val) = NULL;
@@ -1038,7 +1140,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
         if (recvd_type != NULL)
             *recvd_type = SSL3_RT_HANDSHAKE;
 
-        *read = n;
+        *readbytes = n;
         return 1;
     }
 
@@ -1156,12 +1258,12 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
         if (len == 0)
             return 0;
 
-        read_bytes = 0;
+        totalbytes = 0;
         do {
-            if (len - read_bytes > SSL3_RECORD_get_length(rr))
+            if (len - totalbytes > SSL3_RECORD_get_length(rr))
                 n = SSL3_RECORD_get_length(rr);
             else
-                n = len - read_bytes;
+                n = len - totalbytes;
 
             memcpy(buf, &(rr->data[rr->off]), n);
             buf += n;
@@ -1183,10 +1285,10 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
                 curr_rec++;
                 rr++;
             }
-            read_bytes += n;
+            totalbytes += n;
         } while (type == SSL3_RT_APPLICATION_DATA && curr_rec < num_recs
-                 && read_bytes < len);
-        if (read_bytes == 0) {
+                 && totalbytes < len);
+        if (totalbytes == 0) {
             /* We must have read empty records. Get more data */
             goto start;
         }
@@ -1194,7 +1296,7 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
             && (s->mode & SSL_MODE_RELEASE_BUFFERS)
             && SSL3_BUFFER_get_left(rbuf) == 0)
             ssl3_release_read_buffer(s);
-        *read = read_bytes;
+        *readbytes = totalbytes;
         return 1;
     }