Make libssl start using the TLS provider CBC support
authorMatt Caswell <matt@openssl.org>
Wed, 17 Jun 2020 16:16:22 +0000 (17:16 +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/ssl3_record.c
ssl/t1_enc.c

index 5efa77a5b351d20b3bd9fd4ee60333922a3a16fa..0c5ecae1a2afa69dc58c64075424879777fb64dc 100644 (file)
@@ -10,6 +10,7 @@
 #include "../ssl_local.h"
 #include <openssl/trace.h>
 #include <openssl/rand.h>
+#include <openssl/core_names.h>
 #include "record_local.h"
 #include "internal/cryptlib.h"
 
@@ -1140,63 +1141,121 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending,
             }
         }
 
-        /* TODO(size_t): Convert this call */
-        tmpr = EVP_Cipher(ds, recs[0].data, recs[0].input,
-                          (unsigned int)reclen[0]);
-        if ((EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ds))
-             & EVP_CIPH_FLAG_CUSTOM_CIPHER)
-            ? (tmpr < 0)
-            : (tmpr == 0)) {
-            /* AEAD can fail to verify MAC */
-            return 0;
-        }
+        if (EVP_CIPHER_provider(enc) != NULL) {
+            int outlen;
 
-        if (sending == 0) {
-            if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE) {
-                for (ctr = 0; ctr < n_recs; ctr++) {
-                    recs[ctr].data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
-                    recs[ctr].input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
-                    recs[ctr].length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+            /* Provided cipher - we do not support pipelining on this path */
+            if (n_recs > 1)  {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                         ERR_R_INTERNAL_ERROR);
+                return 0;
+            }
+
+            if (!EVP_CipherUpdate(ds, recs[0].data, &outlen, recs[0].input,
+                                  (unsigned int)reclen[0]))
+                return 0;
+            recs[0].length = outlen;
+
+            /*
+             * The length returned from EVP_CipherUpdate above is the actual
+             * payload length. We need to adjust the data/input ptr to skip over
+             * any explicit IV
+             */
+            if (!sending) {
+                if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE) {
+                        recs[0].data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                        recs[0].input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                } else if (EVP_CIPHER_mode(enc) == EVP_CIPH_CCM_MODE) {
+                        recs[0].data += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                        recs[0].input += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                } else if (bs != 1 && SSL_USE_EXPLICIT_IV(s)) {
+                    recs[0].data += bs;
+                    recs[0].input += bs;
+                    recs[0].orig_len -= bs;
                 }
-            } else if (EVP_CIPHER_mode(enc) == EVP_CIPH_CCM_MODE) {
-                for (ctr = 0; ctr < n_recs; ctr++) {
-                    recs[ctr].data += EVP_CCM_TLS_EXPLICIT_IV_LEN;
-                    recs[ctr].input += EVP_CCM_TLS_EXPLICIT_IV_LEN;
-                    recs[ctr].length -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
+
+                /* Now get a pointer to the MAC (if applicable) */
+                if (macs != NULL) {
+                    OSSL_PARAM params[2], *p = params;
+
+                    /* Get the MAC */
+                    macs[0].alloced = 0;
+
+                    *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_CIPHER_PARAM_TLS_MAC,
+                                                          (void **)&macs[0].mac,
+                                                          macsize);
+                    *p = OSSL_PARAM_construct_end();
+
+                    if (!EVP_CIPHER_CTX_get_params(ds, params)) {
+                        /* Shouldn't normally happen */
+                        SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_ENC,
+                                 ERR_R_INTERNAL_ERROR);
+                        return 0;
+                    }
                 }
             }
-        }
+        } else {
+            /* Legacy cipher */
+
+            /* TODO(size_t): Convert this call */
+            tmpr = EVP_Cipher(ds, recs[0].data, recs[0].input,
+                              (unsigned int)reclen[0]);
+            if ((EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ds))
+                 & EVP_CIPH_FLAG_CUSTOM_CIPHER)
+                ? (tmpr < 0)
+                : (tmpr == 0)) {
+                /* AEAD can fail to verify MAC */
+                return 0;
+            }
 
-        if (!sending) {
-            for (ctr = 0; ctr < n_recs; ctr++) {
-                if (bs != 1 && SSL_USE_EXPLICIT_IV(s)) {
-                    if (recs[ctr].length < bs)
+            if (!sending) {
+                /* Adjust the record to remove the explicit IV/MAC/Tag */
+                if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE) {
+                    for (ctr = 0; ctr < n_recs; ctr++) {
+                        recs[ctr].data += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                        recs[ctr].input += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                        recs[ctr].length -= EVP_GCM_TLS_EXPLICIT_IV_LEN;
+                    }
+                } else if (EVP_CIPHER_mode(enc) == EVP_CIPH_CCM_MODE) {
+                    for (ctr = 0; ctr < n_recs; ctr++) {
+                        recs[ctr].data += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                        recs[ctr].input += EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                        recs[ctr].length -= EVP_CCM_TLS_EXPLICIT_IV_LEN;
+                    }
+                }
+
+                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(&recs[ctr].length,
+                                         recs[ctr].orig_len,
+                                         recs[ctr].data,
+                                         (macs != NULL) ? &macs[ctr].mac : NULL,
+                                         (macs != NULL) ? &macs[ctr].alloced
+                                                        : NULL,
+                                         bs,
+                                         macsize,
+                                         (EVP_CIPHER_CTX_flags(s->enc_read_ctx)
+                                         & EVP_CIPH_FLAG_AEAD_CIPHER) != 0,
+                                         s->ctx->libctx))
                         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(&recs[ctr].length,
-                                     recs[ctr].orig_len,
-                                     recs[ctr].data,
-                                     (macs != NULL) ? &macs[ctr].mac : NULL,
-                                     (macs != NULL) ? &macs[ctr].alloced : NULL,
-                                     bs,
-                                     macsize,
-                                     (EVP_CIPHER_CTX_flags(s->enc_read_ctx)
-                                     & EVP_CIPH_FLAG_AEAD_CIPHER) != 0,
-                                     s->ctx->libctx))
-                    return 0;
-            }
-        }
-        if (pad && !sending) {
-            for (ctr = 0; ctr < n_recs; ctr++) {
-                recs[ctr].length -= pad;
+                if (pad) {
+                    for (ctr = 0; ctr < n_recs; ctr++) {
+                        recs[ctr].length -= pad;
+                    }
+                }
             }
         }
     }
index e929121cd288e4b821bdd9acad20df94d7f6547f..9a6c1799f75daa327ee57850094ba33353699a19 100644 (file)
@@ -396,6 +396,38 @@ int tls1_change_cipher_state(SSL *s, int which)
                  ERR_R_INTERNAL_ERROR);
         goto err;
     }
+    if (EVP_CIPHER_provider(c) != NULL) {
+        /*
+         * Provided cipher, the TLS padding/MAC removal is performed provider
+         * side so we need to tell the ctx about our TLS version and mac size
+         */
+        OSSL_PARAM params[3], *pprm = params;
+        size_t macsize = 0;
+        int imacsize = -1;
+
+        if ((EVP_CIPHER_flags(c) & EVP_CIPH_FLAG_AEAD_CIPHER) == 0
+                   /*
+                    * We look at s->ext.use_etm instead of SSL_READ_ETM() or
+                    * SSL_WRITE_ETM() because this test applies to both reading
+                    * and writing.
+                    */
+                && !s->ext.use_etm)
+            imacsize = EVP_MD_size(m);
+        if (imacsize >= 0)
+            macsize = (size_t)imacsize;
+
+        *pprm++ = OSSL_PARAM_construct_int(OSSL_CIPHER_PARAM_TLS_VERSION,
+                                           &s->version);
+        *pprm++ = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_TLS_MAC_SIZE,
+                                              &macsize);
+        *pprm = OSSL_PARAM_construct_end();
+
+        if (!EVP_CIPHER_CTX_set_params(dd, params)) {
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE,
+                     ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
 #ifndef OPENSSL_NO_KTLS
     if (s->compress)
         goto skip_ktls;