Add a maximum output length to update and final calls
authorMatt Caswell <matt@openssl.org>
Wed, 10 Apr 2019 12:43:45 +0000 (13:43 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 19 Apr 2019 08:31:54 +0000 (09:31 +0100)
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/8700)

crypto/evp/evp_enc.c
include/openssl/core_numbers.h
providers/common/ciphers/aes.c

index 6d4e033..69cd577 100644 (file)
@@ -562,6 +562,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
 {
     int ret;
     size_t soutl;
+    int blocksize;
 
     /* Prevent accidental use of decryption context when encrypting */
     if (!ctx->encrypt) {
@@ -572,11 +573,15 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
     if (ctx->cipher == NULL || ctx->cipher->prov == NULL)
         goto legacy;
 
-    if (ctx->cipher->cupdate == NULL) {
+    blocksize = EVP_CIPHER_CTX_block_size(ctx);
+
+    if (ctx->cipher->cupdate == NULL  || blocksize < 1) {
         EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_UPDATE_ERROR);
         return 0;
     }
-    ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl, in, (size_t)inl);
+    ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl,
+                               inl + (blocksize == 1 ? 0 : blocksize), in,
+                               (size_t)inl);
 
     if (soutl > INT_MAX) {
         EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_UPDATE_ERROR);
@@ -603,6 +608,7 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
     int n, ret;
     unsigned int i, b, bl;
     size_t soutl;
+    int blocksize;
 
     /* Prevent accidental use of decryption context when encrypting */
     if (!ctx->encrypt) {
@@ -613,12 +619,15 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
     if (ctx->cipher == NULL || ctx->cipher->prov == NULL)
         goto legacy;
 
-    if (ctx->cipher->cfinal == NULL) {
+    blocksize = EVP_CIPHER_CTX_block_size(ctx);
+
+    if (blocksize < 1 || ctx->cipher->cfinal == NULL) {
         EVPerr(EVP_F_EVP_ENCRYPTFINAL_EX, EVP_R_FINAL_ERROR);
         return 0;
     }
 
-    ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl);
+    ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl,
+                              blocksize == 1 ? 0 : blocksize);
 
     if (soutl > INT_MAX) {
         EVPerr(EVP_F_EVP_ENCRYPTFINAL_EX, EVP_R_FINAL_ERROR);
@@ -674,6 +683,7 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
     int fix_len, cmpl = inl, ret;
     unsigned int b;
     size_t soutl;
+    int blocksize;
 
     /* Prevent accidental use of encryption context when decrypting */
     if (ctx->encrypt) {
@@ -684,11 +694,15 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
     if (ctx->cipher == NULL || ctx->cipher->prov == NULL)
         goto legacy;
 
-    if (ctx->cipher->cupdate == NULL) {
+    blocksize = EVP_CIPHER_CTX_block_size(ctx);
+
+    if (ctx->cipher->cupdate == NULL || blocksize < 1) {
         EVPerr(EVP_F_EVP_DECRYPTUPDATE, EVP_R_UPDATE_ERROR);
         return 0;
     }
-    ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl, in, (size_t)inl);
+    ret = ctx->cipher->cupdate(ctx->provctx, out, &soutl,
+                               inl + (blocksize == 1 ? 0 : blocksize), in,
+                               (size_t)inl);
 
     if (ret) {
         if (soutl > INT_MAX) {
@@ -779,6 +793,7 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
     unsigned int b;
     size_t soutl;
     int ret;
+    int blocksize;
 
     /* Prevent accidental use of encryption context when decrypting */
     if (ctx->encrypt) {
@@ -789,12 +804,15 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
     if (ctx->cipher == NULL || ctx->cipher->prov == NULL)
         goto legacy;
 
-    if (ctx->cipher->cfinal == NULL) {
+    blocksize = EVP_CIPHER_CTX_block_size(ctx);
+
+    if (blocksize < 1 || ctx->cipher->cfinal == NULL) {
         EVPerr(EVP_F_EVP_DECRYPTFINAL_EX, EVP_R_FINAL_ERROR);
         return 0;
     }
 
-    ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl);
+    ret = ctx->cipher->cfinal(ctx->provctx, out, &soutl,
+                              blocksize == 1 ? 0 : blocksize);
 
     if (ret) {
         if (soutl > INT_MAX) {
index e56909a..d588886 100644 (file)
@@ -135,10 +135,10 @@ OSSL_CORE_MAKE_FUNC(int, OP_cipher_decrypt_init, (void *vctx,
                                                   const unsigned char *iv,
                                                   size_t ivlen))
 OSSL_CORE_MAKE_FUNC(int, OP_cipher_update,
-                    (void *, unsigned char *out, size_t *outl,
+                    (void *, unsigned char *out, size_t *outl, size_t outsize,
                      const unsigned char *in, size_t inl))
 OSSL_CORE_MAKE_FUNC(int, OP_cipher_final,
-                    (void *, unsigned char *out, size_t *outl))
+                    (void *, unsigned char *out, size_t *outl, size_t outsize))
 OSSL_CORE_MAKE_FUNC(int, OP_cipher_cipher,
                     (void *, unsigned char *out, const unsigned char *in,
                      size_t inl))
index 21ecc2b..a70facc 100644 (file)
@@ -65,7 +65,7 @@ static int aes_dinit(void *vctx, const unsigned char *key, size_t keylen,
 }
 
 static int aes_block_update(void *vctx, unsigned char *out, size_t *outl,
-                            const unsigned char *in, size_t inl)
+                            size_t outsize, const unsigned char *in, size_t inl)
 {
     PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx;
     size_t nextblocks = fillblock(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE, &in,
@@ -79,6 +79,8 @@ static int aes_block_update(void *vctx, unsigned char *out, size_t *outl,
      */
     if (ctx->bufsz == AES_BLOCK_SIZE
             && (ctx->enc || inl > 0 || !ctx->pad)) {
+        if (outsize < AES_BLOCK_SIZE)
+            return 0;
         if (!ctx->ciph->cipher(ctx, out, ctx->buf, AES_BLOCK_SIZE))
             return 0;
         ctx->bufsz = 0;
@@ -91,11 +93,13 @@ static int aes_block_update(void *vctx, unsigned char *out, size_t *outl,
                 return 0;
             nextblocks -= AES_BLOCK_SIZE;
         }
+        outlint += nextblocks;
+        if (outsize < outlint)
+            return 0;
         if (!ctx->ciph->cipher(ctx, out, in, nextblocks))
             return 0;
         in += nextblocks;
         inl -= nextblocks;
-        outlint += nextblocks;
     }
     if (!trailingdata(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE, &in, &inl))
         return 0;
@@ -104,7 +108,8 @@ static int aes_block_update(void *vctx, unsigned char *out, size_t *outl,
     return inl == 0;
 }
 
-static int aes_block_final(void *vctx, unsigned char *out, size_t *outl)
+static int aes_block_final(void *vctx, unsigned char *out, size_t *outl,
+                           size_t outsize)
 {
     PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx;
 
@@ -119,6 +124,8 @@ static int aes_block_final(void *vctx, unsigned char *out, size_t *outl)
             return 0;
         }
 
+        if (outsize < AES_BLOCK_SIZE)
+            return 0;
         if (!ctx->ciph->cipher(ctx, out, ctx->buf, AES_BLOCK_SIZE))
             return 0;
         ctx->bufsz = 0;
@@ -143,6 +150,8 @@ static int aes_block_final(void *vctx, unsigned char *out, size_t *outl)
     if (ctx->pad && !unpadblock(ctx->buf, &ctx->bufsz, AES_BLOCK_SIZE))
         return 0;
 
+    if (outsize < ctx->bufsz)
+        return 0;
     memcpy(out, ctx->buf, ctx->bufsz);
     *outl = ctx->bufsz;
     ctx->bufsz = 0;
@@ -150,17 +159,22 @@ static int aes_block_final(void *vctx, unsigned char *out, size_t *outl)
 }
 
 static int aes_stream_update(void *vctx, unsigned char *out, size_t *outl,
-                             const unsigned char *in, size_t inl)
+                             size_t outsize, const unsigned char *in,
+                             size_t inl)
 {
     PROV_AES_KEY *ctx = (PROV_AES_KEY *)vctx;
 
+    if (outsize < inl)
+        return 0;
+
     if (!ctx->ciph->cipher(ctx, out, in, inl))
         return 0;
 
     *outl = inl;
     return 1;
 }
-static int aes_stream_final(void *vctx, unsigned char *out, size_t *outl)
+static int aes_stream_final(void *vctx, unsigned char *out, size_t *outl,
+                            size_t outsize)
 {
     *outl = 0;
     return 1;