Ensure TLS padding is added during encryption on the provider side
authorMatt Caswell <matt@openssl.org>
Fri, 26 Jun 2020 17:22:18 +0000 (18:22 +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)

providers/implementations/ciphers/ciphercommon.c
ssl/record/ssl3_record.c

index 2cd5b6f571b7efc198fd41a5c784f1b4b8d1573b..a8905d1242c1a27f0e0932bbe95a8362366d36c0 100644 (file)
@@ -11,6 +11,8 @@
  * Generic dispatch table functions for ciphers.
  */
 
+/* For SSL3_VERSION */
+#include <openssl/ssl.h>
 #include "ciphercommon_local.h"
 #include "prov/provider_ctx.h"
 #include "prov/providercommonerr.h"
@@ -181,6 +183,9 @@ int cipher_generic_dinit(void *vctx, const unsigned char *key, size_t keylen,
                                         iv, ivlen, 0);
 }
 
+/* Max padding including padding length byte */
+#define MAX_PADDING 256
+
 int cipher_generic_block_update(void *vctx, unsigned char *out, size_t *outl,
                                 size_t outsize, const unsigned char *in,
                                 size_t inl)
@@ -197,8 +202,7 @@ int cipher_generic_block_update(void *vctx, unsigned char *out, size_t *outl,
          */
 
         /* Sanity check inputs */
-        if (in == 0
-                || (inl % blksz) != 0
+        if (in == NULL
                 || in != out
                 || outsize < inl
                 || !ctx->pad) {
@@ -206,6 +210,42 @@ int cipher_generic_block_update(void *vctx, unsigned char *out, size_t *outl,
             return 0;
         }
 
+        if (ctx->enc) {
+            unsigned char padval;
+            size_t padnum, loop;
+
+            /* Add padding */
+
+            padnum = blksz - (inl % blksz);
+
+            if (outsize < inl + padnum) {
+                ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
+                return 0;
+            }
+
+            if (padnum > MAX_PADDING) {
+                ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
+                return 0;
+            }
+            padval = (unsigned char)(padnum - 1);
+            if (ctx->tlsversion == SSL3_VERSION) {
+                if (padnum > 1)
+                    memset(out + inl, 0, padnum - 1);
+                *(out + inl + padnum - 1) = padval;
+            } else {
+                /* we need to add 'padnum' padding bytes of value padval */
+                for (loop = inl; loop < inl + padnum; loop++)
+                    out[loop] = padval;
+            }
+            inl += padnum;
+        }
+
+        if ((inl % blksz) != 0) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
+            return 0;
+        }
+
+
         /* Shouldn't normally fail */
         if (!ctx->hw->cipher(ctx, out, in, inl)) {
             ERR_raise(ERR_LIB_PROV, PROV_R_CIPHER_OPERATION_FAILED);
index 6359c79bb167332627f318cb4fb21ad3a9f3d97d..80990e829662d0d86a5e7f708071987339fc9adb 100644 (file)
@@ -869,13 +869,19 @@ int ssl3_enc(SSL *s, SSL3_RECORD *inrecs, size_t n_recs, int sending,
         memmove(rec->data, rec->input, rec->length);
         rec->input = rec->data;
     } else {
+        int provided = (EVP_CIPHER_provider(enc) != NULL);
+
         l = rec->length;
         /* TODO(size_t): Convert this call */
         bs = EVP_CIPHER_CTX_block_size(ds);
 
         /* COMPRESS */
 
-        if ((bs != 1) && sending) {
+        if ((bs != 1) && sending && !provided) {
+            /*
+             * We only do this for legacy ciphers. Provided ciphers add the
+             * padding on the provider side.
+             */
             i = bs - (l % bs);
 
             /* we need to add 'i-1' padding bytes */
@@ -1038,6 +1044,8 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending,
             recs[ctr].input = recs[ctr].data;
         }
     } else {
+        int provided = (EVP_CIPHER_provider(enc) != NULL);
+
         bs = EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(ds));
 
         if (n_recs > 1) {
@@ -1097,7 +1105,11 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending,
                     recs[ctr].length += pad;
                 }
 
-            } else if ((bs != 1) && sending) {
+            } else if ((bs != 1) && sending && !provided) {
+                /*
+                 * We only do this for legacy ciphers. Provided ciphers add the
+                 * padding on the provider side.
+                 */
                 padnum = bs - (reclen[ctr] % bs);
 
                 /* Add weird padding of up to 256 bytes */
@@ -1170,7 +1182,7 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending,
             }
         }
 
-        if (EVP_CIPHER_provider(enc) != NULL) {
+        if (provided) {
             int outlen;
 
             /* Provided cipher - we do not support pipelining on this path */
@@ -1275,7 +1287,7 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending,
                                                         : NULL,
                                          bs,
                                          macsize,
-                                         (EVP_CIPHER_CTX_flags(s->enc_read_ctx)
+                                         (EVP_CIPHER_flags(enc)
                                          & EVP_CIPH_FLAG_AEAD_CIPHER) != 0,
                                          s->ctx->libctx))
                         return 0;