Remove SSL dependencies from tls_pad.c
authorMatt Caswell <matt@openssl.org>
Wed, 10 Jun 2020 14:34:04 +0000 (15:34 +0100)
committerMatt Caswell <matt@openssl.org>
Mon, 6 Jul 2020 08:26:09 +0000 (09:26 +0100)
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12288)

ssl/record/record_local.h
ssl/record/ssl3_record.c
ssl/record/tls_pad.c

index dc92732243173dffed11cbe48fecc831343bc190..9047c23fd5dc69efc37d063d0b2b6e48b58be936 100644 (file)
@@ -107,16 +107,21 @@ void SSL3_RECORD_set_seq_num(SSL3_RECORD *r, const unsigned char *seq_num);
 int ssl3_get_record(SSL *s);
 __owur int ssl3_do_compress(SSL *ssl, SSL3_RECORD *wr);
 __owur int ssl3_do_uncompress(SSL *ssl, SSL3_RECORD *rr);
-__owur int ssl3_cbc_remove_padding_and_mac(SSL *s,
-                                           SSL3_RECORD *rec,
+__owur int ssl3_cbc_remove_padding_and_mac(size_t *reclen,
+                                           size_t origreclen,
+                                           unsigned char *recdata,
                                            unsigned char **mac,
                                            int *alloced,
-                                           size_t block_size, size_t mac_size);
-__owur int tls1_cbc_remove_padding_and_mac(const SSL *s,
-                                           SSL3_RECORD *rec,
+                                           size_t block_size, size_t mac_size,
+                                           OPENSSL_CTX *libctx);
+__owur int tls1_cbc_remove_padding_and_mac(size_t *reclen,
+                                           size_t origreclen,
+                                           unsigned char *recdata,
                                            unsigned char **mac,
                                            int *alloced,
-                                           size_t block_size, size_t mac_size);
+                                           size_t block_size, size_t mac_size,
+                                           int aead,
+                                           OPENSSL_CTX *libctx);
 int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap);
 __owur int dtls1_get_record(SSL *s);
 int early_data_count_ok(SSL *s, size_t length, size_t overhead, int send);
index 55a3a3b6e64a7c937a1bebe13bbcadebd1b50406..5efa77a5b351d20b3bd9fd4ee60333922a3a16fa 100644 (file)
@@ -904,11 +904,14 @@ int ssl3_enc(SSL *s, SSL3_RECORD *inrecs, size_t n_recs, int sending,
         }
 
         if (!sending)
-            return !ssl3_cbc_remove_padding_and_mac(s, rec,
-                                        (mac != NULL) ? &mac->mac : NULL,
-                                        (mac != NULL) ? &mac->alloced : NULL,
-                                        bs,
-                                        macsize);
+            return ssl3_cbc_remove_padding_and_mac(&rec->length,
+                                       rec->orig_len,
+                                       rec->data,
+                                       (mac != NULL) ? &mac->mac : NULL,
+                                       (mac != NULL) ? &mac->alloced : NULL,
+                                       bs,
+                                       macsize,
+                                       s->ctx->libctx);
     }
     return 1;
 }
@@ -1166,15 +1169,28 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending,
 
         if (!sending) {
             for (ctr = 0; ctr < n_recs; ctr++) {
+                if (bs != 1 && SSL_USE_EXPLICIT_IV(s)) {
+                    if (recs[ctr].length < bs)
+                        return 0;
+                    recs[ctr].data += bs;
+                    recs[ctr].input += bs;
+                    recs[ctr].length -= bs;
+                    recs[ctr].orig_len -= bs;
+                }
                 /*
                  * If using Mac-then-encrypt, then this will succeed but with a
                  * random MAC if padding is invalid
                  */
-                if (!tls1_cbc_remove_padding_and_mac(s, &recs[ctr],
+                if (!tls1_cbc_remove_padding_and_mac(&recs[ctr].length,
+                                     recs[ctr].orig_len,
+                                     recs[ctr].data,
                                      (macs != NULL) ? &macs[ctr].mac : NULL,
                                      (macs != NULL) ? &macs[ctr].alloced : NULL,
                                      bs,
-                                     macsize))
+                                     macsize,
+                                     (EVP_CIPHER_CTX_flags(s->enc_read_ctx)
+                                     & EVP_CIPH_FLAG_AEAD_CIPHER) != 0,
+                                     s->ctx->libctx))
                     return 0;
             }
         }
index 2e6a6e89714d1aec0a6875d67170ab6b5c57b90f..9f698483f1c1a69788436f150e0b85d7b1ff59e6 100644 (file)
@@ -8,35 +8,70 @@
  */
 
 #include <openssl/rand.h>
+#include <openssl/evp.h>
 #include "internal/constant_time.h"
 #include "internal/cryptlib.h"
-#include "../ssl_local.h"
-#include "record_local.h"
 
-static int ssl3_cbc_copy_mac(const SSL *s,
-                             SSL3_RECORD *rec,
+/*
+ * This file has no dependencies on the rest of libssl because it is shared
+ * with the providers. It contains functions for low level CBC TLS padding
+ * removal. Responsibility for this lies with the cipher implementations in the
+ * providers. However there are legacy code paths in libssl which also need to
+ * do this. In time those legacy code paths can be removed and this file can be
+ * moved out of libssl.
+ */
+
+static int ssl3_cbc_copy_mac(size_t *reclen,
+                             size_t origreclen,
+                             unsigned char *recdata,
                              unsigned char **mac,
                              int *alloced,
                              size_t block_size,
                              size_t mac_size,
-                             size_t good);
+                             size_t good,
+                             OPENSSL_CTX *libctx);
+
+int ssl3_cbc_remove_padding_and_mac(size_t *reclen,
+                                    size_t origreclen,
+                                    unsigned char *recdata,
+                                    unsigned char **mac,
+                                    int *alloced,
+                                    size_t block_size, size_t mac_size,
+                                    OPENSSL_CTX *libctx);
+
+int tls1_cbc_remove_padding_and_mac(size_t *reclen,
+                                    size_t origreclen,
+                                    unsigned char *recdata,
+                                    unsigned char **mac,
+                                    int *alloced,
+                                    size_t block_size, size_t mac_size,
+                                    int aead,
+                                    OPENSSL_CTX *libctx);
 
 /*-
  * ssl3_cbc_remove_padding removes padding from the decrypted, SSLv3, CBC
- * record in |rec| by updating |rec->length| in constant time. It also extracts
- * the MAC from the underlying record.
+ * record in |recdata| by updating |reclen| in constant time. It also extracts
+ * the MAC from the underlying record and places a pointer to it in |mac|. The
+ * MAC data can either be newly allocated memory, or a pointer inside the
+ * |recdata| buffer. If allocated then |*alloced| is set to 1, otherwise it is
+ * set to 0.
  *
+ * origreclen: the original record length before any changes were made
  * block_size: the block size of the cipher used to encrypt the record.
+ * mac_size: the size of the MAC to be extracted
+ * aead: 1 if an AEAD cipher is in use, or 0 otherwise
  * returns:
  *   0: if the record is publicly invalid.
  *   1: if the record is publicly valid. If the padding removal fails then the
  *      MAC returned is random.
  */
-int ssl3_cbc_remove_padding_and_mac(SSL *s,
-                                    SSL3_RECORD *rec,
+int ssl3_cbc_remove_padding_and_mac(size_t *reclen,
+                                    size_t origreclen,
+                                    unsigned char *recdata,
                                     unsigned char **mac,
                                     int *alloced,
-                                    size_t block_size, size_t mac_size)
+                                    size_t block_size, size_t mac_size,
+                                    OPENSSL_CTX *libctx)
 {
     size_t padding_length;
     size_t good;
@@ -45,71 +80,70 @@ int ssl3_cbc_remove_padding_and_mac(SSL *s,
     /*
      * These lengths are all public so we can test them in non-constant time.
      */
-    if (overhead > rec->length)
+    if (overhead > *reclen)
         return 0;
 
-    padding_length = rec->data[rec->length - 1];
-    good = constant_time_ge_s(rec->length, padding_length + overhead);
+    padding_length = recdata[*reclen - 1];
+    good = constant_time_ge_s(*reclen, padding_length + overhead);
     /* SSLv3 requires that the padding is minimal. */
     good &= constant_time_ge_s(block_size, padding_length + 1);
-    rec->length -= good & (padding_length + 1);
+    *reclen -= good & (padding_length + 1);
 
-    return ssl3_cbc_copy_mac(s, rec, mac, alloced, block_size, mac_size, good);
+    return ssl3_cbc_copy_mac(reclen, origreclen, recdata, mac, alloced,
+                             block_size, mac_size, good, libctx);
 }
 
 /*-
- * tls1_cbc_remove_padding removes the CBC padding from the decrypted, TLS, CBC
- * record in |rec| in constant time. It also removes any explicit IV from the
- * start of the record without leaking any timing about whether there was enough
- * space after the padding was removed, as well as extracting the embedded MAC
- * (also in constant time). For Mac-then-encrypt, if the padding is invalid then
- * a success result will occur and a randomised MAC will be returned.
+ * tls1_cbc_remove_padding_and_mac removes padding from the decrypted, TLS, CBC
+ * record in |recdata| by updating |reclen| in constant time. It also extracts
+ * the MAC from the underlying record and places a pointer to it in |mac|. The
+ * MAC data can either be newly allocated memory, or a pointer inside the
+ * |recdata| buffer. If allocated then |*alloced| is set to 1, otherwise it is
+ * set to 0.
  *
+ * origreclen: the original record length before any changes were made
  * block_size: the block size of the cipher used to encrypt the record.
+ * mac_size: the size of the MAC to be extracted
+ * aead: 1 if an AEAD cipher is in use, or 0 otherwise
  * returns:
- *    0: if the record is publicly invalid, or an internal error
- *    1: Success or Mac-then-encrypt decryption failed (MAC will be randomised)
+ *   0: if the record is publicly invalid.
+ *   1: if the record is publicly valid. If the padding removal fails then the
+ *      MAC returned is random.
  */
-int tls1_cbc_remove_padding_and_mac(const SSL *s,
-                                    SSL3_RECORD *rec,
+int tls1_cbc_remove_padding_and_mac(size_t *reclen,
+                                    size_t origreclen,
+                                    unsigned char *recdata,
                                     unsigned char **mac,
                                     int *alloced,
-                                    size_t block_size, size_t mac_size)
+                                    size_t block_size, size_t mac_size,
+                                    int aead,
+                                    OPENSSL_CTX *libctx)
 {
-    size_t good;
+    size_t good = -1;
     size_t padding_length, to_check, i;
     size_t overhead = ((block_size == 1) ? 0 : 1) /* padding length byte */
-                      + (SSL_USE_EXPLICIT_IV(s) ? block_size : 0)
                       + mac_size;
 
     /*
      * These lengths are all public so we can test them in non-constant
      * time.
      */
-    if (overhead > rec->length)
+    if (overhead > *reclen)
         return 0;
 
     if (block_size != 1) {
-        if (SSL_USE_EXPLICIT_IV(s)) {
-            rec->data += block_size;
-            rec->input += block_size;
-            rec->length -= block_size;
-            rec->orig_len -= block_size;
-            overhead -= block_size;
-        }
 
-        padding_length = rec->data[rec->length - 1];
+        padding_length = recdata[*reclen - 1];
 
-        if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_read_ctx)) &
-            EVP_CIPH_FLAG_AEAD_CIPHER) {
+        if (aead) {
             /* padding is already verified and we don't need to check the MAC */
-            rec->length -= padding_length + 1 + mac_size;
+            *reclen -= padding_length + 1 + mac_size;
             *mac = NULL;
             *alloced = 0;
             return 1;
         }
 
-        good = constant_time_ge_s(rec->length, overhead + padding_length);
+        good = constant_time_ge_s(*reclen, overhead + padding_length);
         /*
          * The padding consists of a length byte at the end of the record and
          * then that many bytes of padding, all with the same value as the
@@ -120,12 +154,12 @@ int tls1_cbc_remove_padding_and_mac(const SSL *s,
          * is public information so we can use it.)
          */
         to_check = 256;        /* maximum amount of padding, inc length byte. */
-        if (to_check > rec->length)
-            to_check = rec->length;
+        if (to_check > *reclen)
+            to_check = *reclen;
 
         for (i = 0; i < to_check; i++) {
             unsigned char mask = constant_time_ge_8_s(padding_length, i);
-            unsigned char b = rec->data[rec->length - 1 - i];
+            unsigned char b = recdata[*reclen - 1 - i];
             /*
              * The final |padding_length+1| bytes should all have the value
              * |padding_length|. Therefore the XOR should be zero.
@@ -138,20 +172,21 @@ int tls1_cbc_remove_padding_and_mac(const SSL *s,
          * or more of the lower eight bits of |good| will be cleared.
          */
         good = constant_time_eq_s(0xff, good & 0xff);
-        rec->length -= good & (padding_length + 1);
+        *reclen -= good & (padding_length + 1);
     }
 
-    return ssl3_cbc_copy_mac(s, rec, mac, alloced, block_size, mac_size, good);
+    return ssl3_cbc_copy_mac(reclen, origreclen, recdata, mac, alloced,
+                             block_size, mac_size, good, libctx);
 }
 
 /*-
- * ssl3_cbc_copy_mac copies |md_size| bytes from the end of |rec| to |out| in
- * constant time (independent of the concrete value of rec->length, which may
- * vary within a 256-byte window).
+ * ssl3_cbc_copy_mac copies |md_size| bytes from the end of the record in
+ * |recdata| to |*mac| in constant time (independent of the concrete value of
+ * the record length |reclen|, which may vary within a 256-byte window).
  *
  * On entry:
- *   rec->orig_len >= md_size
- *   md_size <= EVP_MAX_MD_SIZE
+ *   origreclen >= mac_size
+ *   mac_size <= EVP_MAX_MD_SIZE
  *
  * If CBC_MAC_ROTATE_IN_PLACE is defined then the rotation is performed with
  * variable accesses in a 64-byte-aligned buffer. Assuming that this fits into
@@ -161,13 +196,15 @@ int tls1_cbc_remove_padding_and_mac(const SSL *s,
  */
 #define CBC_MAC_ROTATE_IN_PLACE
 
-static int ssl3_cbc_copy_mac(const SSL *s,
-                             SSL3_RECORD *rec,
+static int ssl3_cbc_copy_mac(size_t *reclen,
+                             size_t origreclen,
+                             unsigned char *recdata,
                              unsigned char **mac,
                              int *alloced,
                              size_t block_size,
                              size_t mac_size,
-                             size_t good)
+                             size_t good,
+                             OPENSSL_CTX *libctx)
 {
 #if defined(CBC_MAC_ROTATE_IN_PLACE)
     unsigned char rotated_mac_buf[64 + EVP_MAX_MD_SIZE];
@@ -179,9 +216,9 @@ static int ssl3_cbc_copy_mac(const SSL *s,
     unsigned char *out;
 
     /*
-     * mac_end is the index of |rec->data| just after the end of the MAC.
+     * mac_end is the index of |recdata| just after the end of the MAC.
      */
-    size_t mac_end = rec->length;
+    size_t mac_end = *reclen;
     size_t mac_start = mac_end - mac_size;
     size_t in_mac;
     /*
@@ -192,7 +229,7 @@ static int ssl3_cbc_copy_mac(const SSL *s,
     size_t i, j;
     size_t rotate_offset;
 
-    if (!ossl_assert(rec->orig_len >= mac_size
+    if (!ossl_assert(origreclen >= mac_size
                      && mac_size <= EVP_MAX_MD_SIZE))
         return 0;
 
@@ -204,19 +241,19 @@ static int ssl3_cbc_copy_mac(const SSL *s,
         return 1;
     }
 
-    rec->length -= mac_size;
+    *reclen -= mac_size;
 
     if (block_size == 1) {
         /* There's no padding so the position of the MAC is fixed */
         if (mac != NULL)
-            *mac = &rec->data[rec->length];
+            *mac = &recdata[*reclen];
         if (alloced != NULL)
             *alloced = 0;
         return 1;
     }
 
     /* Create the random MAC we will emit if padding is bad */
-    if (!RAND_bytes_ex(s->ctx->libctx, randmac, mac_size))
+    if (!RAND_bytes_ex(libctx, randmac, mac_size))
         return 0;
 
     if (!ossl_assert(mac != NULL && alloced != NULL))
@@ -231,16 +268,16 @@ static int ssl3_cbc_copy_mac(const SSL *s,
 #endif
 
     /* This information is public so it's safe to branch based on it. */
-    if (rec->orig_len > mac_size + 255 + 1)
-        scan_start = rec->orig_len - (mac_size + 255 + 1);
+    if (origreclen > mac_size + 255 + 1)
+        scan_start = origreclen - (mac_size + 255 + 1);
 
     in_mac = 0;
     rotate_offset = 0;
     memset(rotated_mac, 0, mac_size);
-    for (i = scan_start, j = 0; i < rec->orig_len; i++) {
+    for (i = scan_start, j = 0; i < origreclen; i++) {
         size_t mac_started = constant_time_eq_s(i, mac_start);
         size_t mac_ended = constant_time_lt_s(i, mac_end);
-        unsigned char b = rec->data[i];
+        unsigned char b = recdata[i];
 
         in_mac |= mac_started;
         in_mac &= mac_ended;