crypto/evp: harden AEAD ciphers.
[openssl.git] / crypto / evp / e_chacha20_poly1305.c
index bce247d7b5ee2d24863b375e3480b423c7b9142e..46bc2cb44fb323748685a4e5a09ef8c6b478259b 100644 (file)
@@ -1,51 +1,10 @@
-/* ====================================================================
- * Copyright (c) 2014 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
+/*
+ * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
  *
  *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
  */
 
 #include <stdio.h>
  */
 
 #include <stdio.h>
@@ -168,7 +127,7 @@ static const EVP_CIPHER chacha20 = {
     1,                      /* block_size */
     CHACHA_KEY_SIZE,        /* key_len */
     CHACHA_CTR_SIZE,        /* iv_len, 128-bit counter in the context */
     1,                      /* block_size */
     CHACHA_KEY_SIZE,        /* key_len */
     CHACHA_CTR_SIZE,        /* iv_len, 128-bit counter in the context */
-    0,                      /* flags */
+    EVP_CIPH_CUSTOM_IV | EVP_CIPH_ALWAYS_CALL_INIT,
     chacha_init_key,
     chacha_cipher,
     NULL,
     chacha_init_key,
     chacha_cipher,
     NULL,
@@ -205,7 +164,6 @@ static int chacha20_poly1305_init_key(EVP_CIPHER_CTX *ctx,
                                       const unsigned char *iv, int enc)
 {
     EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
                                       const unsigned char *iv, int enc)
 {
     EVP_CHACHA_AEAD_CTX *actx = aead_data(ctx);
-    unsigned char temp[CHACHA_CTR_SIZE];
 
     if (!inkey && !iv)
         return 1;
 
     if (!inkey && !iv)
         return 1;
@@ -216,16 +174,21 @@ static int chacha20_poly1305_init_key(EVP_CIPHER_CTX *ctx,
     actx->mac_inited = 0;
     actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
 
     actx->mac_inited = 0;
     actx->tls_payload_length = NO_TLS_PAYLOAD_LENGTH;
 
-    /* pad on the left */
-    memset(temp, 0, sizeof(temp));
-    if (actx->nonce_len <= CHACHA_CTR_SIZE)
-        memcpy(temp + CHACHA_CTR_SIZE - actx->nonce_len, iv, actx->nonce_len);
+    if (iv != NULL) {
+        unsigned char temp[CHACHA_CTR_SIZE] = { 0 };
+
+        /* pad on the left */
+        if (actx->nonce_len <= CHACHA_CTR_SIZE)
+            memcpy(temp + CHACHA_CTR_SIZE - actx->nonce_len, iv, actx->nonce_len);
 
 
-    chacha_init_key(ctx, inkey, temp, enc);
+        chacha_init_key(ctx, inkey, temp, enc);
 
 
-    actx->nonce[0] = actx->key.counter[1];
-    actx->nonce[1] = actx->key.counter[2];
-    actx->nonce[2] = actx->key.counter[3];
+        actx->nonce[0] = actx->key.counter[1];
+        actx->nonce[1] = actx->key.counter[2];
+        actx->nonce[2] = actx->key.counter[3];
+    } else {
+        chacha_init_key(ctx, inkey, NULL, enc);
+    }
 
     return 1;
 }
 
     return 1;
 }
@@ -244,6 +207,8 @@ static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
                        actx->key.key.d, actx->key.counter);
         Poly1305_Init(POLY1305_ctx(actx), actx->key.buf);
         actx->key.counter[0] = 1;
                        actx->key.key.d, actx->key.counter);
         Poly1305_Init(POLY1305_ctx(actx), actx->key.buf);
         actx->key.counter[0] = 1;
+        actx->key.partial_len = 0;
+        actx->len.aad = actx->len.text = 0;
         actx->mac_inited = 1;
     }
 
         actx->mac_inited = 1;
     }
 
@@ -334,7 +299,7 @@ static int chacha20_poly1305_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
                 memcpy(out, actx->tag, POLY1305_BLOCK_SIZE);
             } else {
                 if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) {
                 memcpy(out, actx->tag, POLY1305_BLOCK_SIZE);
             } else {
                 if (CRYPTO_memcmp(temp, in, POLY1305_BLOCK_SIZE)) {
-                    memset(out, 0, plen);
+                    memset(out - plen, 0, plen);
                     return -1;
                 }
             }
                     return -1;
                 }
             }
@@ -380,9 +345,11 @@ static int chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
 
     case EVP_CTRL_COPY:
         if (actx) {
 
     case EVP_CTRL_COPY:
         if (actx) {
-            if ((((EVP_CIPHER_CTX *)ptr)->cipher_data =
-                   BUF_memdup(actx,sizeof(*actx) + Poly1305_ctx_size()))
-                == NULL) {
+            EVP_CIPHER_CTX *dst = (EVP_CIPHER_CTX *)ptr;
+
+            dst->cipher_data =
+                   OPENSSL_memdup(actx, sizeof(*actx) + Poly1305_ctx_size());
+            if (dst->cipher_data == NULL) {
                 EVPerr(EVP_F_CHACHA20_POLY1305_CTRL, EVP_R_COPY_ERROR);
                 return 0;
             }
                 EVPerr(EVP_F_CHACHA20_POLY1305_CTRL, EVP_R_COPY_ERROR);
                 return 0;
             }
@@ -426,32 +393,29 @@ static int chacha20_poly1305_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg,
             return 0;
         {
             unsigned int len;
             return 0;
         {
             unsigned int len;
-            unsigned char temp[POLY1305_BLOCK_SIZE];
-
-            /*
-             * compose padded aad
-             */
-            memset(temp, 0, sizeof(temp));
-            memcpy(temp, ptr, EVP_AEAD_TLS1_AAD_LEN);
+            unsigned char *aad = ptr, temp[POLY1305_BLOCK_SIZE];
 
 
-            len = temp[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 |
-                  temp[EVP_AEAD_TLS1_AAD_LEN - 1];
+            len = aad[EVP_AEAD_TLS1_AAD_LEN - 2] << 8 |
+                  aad[EVP_AEAD_TLS1_AAD_LEN - 1];
             if (!ctx->encrypt) {
             if (!ctx->encrypt) {
+                if (len < POLY1305_BLOCK_SIZE)
+                    return 0;
                 len -= POLY1305_BLOCK_SIZE;     /* discount attached tag */
                 len -= POLY1305_BLOCK_SIZE;     /* discount attached tag */
+                memcpy(temp, aad, EVP_AEAD_TLS1_AAD_LEN - 2);
+                aad = temp;
                 temp[EVP_AEAD_TLS1_AAD_LEN - 2] = (unsigned char)(len >> 8);
                 temp[EVP_AEAD_TLS1_AAD_LEN - 1] = (unsigned char)len;
             }
             actx->tls_payload_length = len;
 
             /*
                 temp[EVP_AEAD_TLS1_AAD_LEN - 2] = (unsigned char)(len >> 8);
                 temp[EVP_AEAD_TLS1_AAD_LEN - 1] = (unsigned char)len;
             }
             actx->tls_payload_length = len;
 
             /*
-             * merge record sequence number as per
-             * draft-ietf-tls-chacha20-poly1305-03
+             * merge record sequence number as per RFC7905
              */
             actx->key.counter[1] = actx->nonce[0];
              */
             actx->key.counter[1] = actx->nonce[0];
-            actx->key.counter[2] = actx->nonce[1] ^ CHACHA_U8TOU32(temp);
-            actx->key.counter[3] = actx->nonce[2] ^ CHACHA_U8TOU32(temp+4);
+            actx->key.counter[2] = actx->nonce[1] ^ CHACHA_U8TOU32(aad);
+            actx->key.counter[3] = actx->nonce[2] ^ CHACHA_U8TOU32(aad+4);
             actx->mac_inited = 0;
             actx->mac_inited = 0;
-            chacha20_poly1305_cipher(ctx, NULL, temp, POLY1305_BLOCK_SIZE);
+            chacha20_poly1305_cipher(ctx, NULL, aad, EVP_AEAD_TLS1_AAD_LEN);
             return POLY1305_BLOCK_SIZE;         /* tag length */
         }
 
             return POLY1305_BLOCK_SIZE;         /* tag length */
         }