[openssl] master update

Dr. Paul Dale pauli at openssl.org
Tue Jun 8 04:33:22 UTC 2021


The branch master has been updated
       via  063e019738b90fcf0a3ab7b1654ce8976805b0b3 (commit)
       via  ff555f81365d1c09a408019924cace4a0f457ef6 (commit)
      from  6d2e0076e6a8146f3bdaa60151b2fa6e4df0d1bf (commit)


- Log -----------------------------------------------------------------
commit 063e019738b90fcf0a3ab7b1654ce8976805b0b3
Author: Juergen Christ <jchrist at linux.ibm.com>
Date:   Wed Jun 2 19:33:50 2021 +0200

    Test EVP_CipherInit sequences and resets
    
    Various EVP_CipherInit sequences including partial inits and initializations
    with different "enc" flags caused problems on s390x.  Similarly, cipher
    reinitialization and especially GCM reinitialization with different tag length
    led to wrong results.  Add some unit tests to cover these rather exotic use
    cases.
    
    Signed-off-by: Juergen Christ <jchrist at linux.ibm.com>
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15521)

commit ff555f81365d1c09a408019924cace4a0f457ef6
Author: Juergen Christ <jchrist at linux.ibm.com>
Date:   Fri May 28 15:02:52 2021 +0200

    Fix CipherInit on s390x.
    
    Various different initialization sequences led to bugs on s390x due to caching
    and processing during key setting.  Since, e.g., the direction does not
    necessarily have to be correct during initialization, this produced bugs in
    s390x which were not present on other architectures.  Fix this by recomputing
    the function codes on the fly during updates and final operations.
    
    Signed-off-by: Juergen Christ <jchrist at linux.ibm.com>
    
    Reviewed-by: Tomas Mraz <tomas at openssl.org>
    Reviewed-by: Paul Dale <pauli at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/15521)

-----------------------------------------------------------------------

Summary of changes:
 providers/implementations/ciphers/cipher_aes_gcm.h |   1 +
 .../ciphers/cipher_aes_gcm_hw_s390x.inc            |  46 +-
 .../ciphers/cipher_aes_hw_s390x.inc                |  27 +-
 test/evp_extra_test.c                              | 474 +++++++++++++++++++++
 4 files changed, 517 insertions(+), 31 deletions(-)

diff --git a/providers/implementations/ciphers/cipher_aes_gcm.h b/providers/implementations/ciphers/cipher_aes_gcm.h
index bcffa15871..46b5ee3859 100644
--- a/providers/implementations/ciphers/cipher_aes_gcm.h
+++ b/providers/implementations/ciphers/cipher_aes_gcm.h
@@ -29,6 +29,7 @@ typedef struct prov_aes_gcm_ctx_st {
                 S390X_KMA_PARAMS kma;
             } param;
             unsigned int fc;
+            unsigned int hsflag;    /* hash subkey set flag */
             unsigned char ares[16];
             unsigned char mres[16];
             unsigned char kres[16];
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc
index f797093928..c45657952b 100644
--- a/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc
+++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc
@@ -15,6 +15,12 @@
 /* iv + padding length for iv lengths != 12 */
 #define S390X_gcm_ivpadlen(i)  ((((i) + 15) >> 4 << 4) + 16)
 
+/* Additional flag or'ed to fc for decryption */
+#define S390X_gcm_decrypt_flag(ctx) (((ctx)->enc) ? 0 : S390X_DECRYPT)
+
+#define S390X_gcm_fc(A,C) ((A)->plat.s390x.fc | (A)->plat.s390x.hsflag |\
+                            S390X_gcm_decrypt_flag((C)))
+
 static int s390x_aes_gcm_initkey(PROV_GCM_CTX *ctx,
                                  const unsigned char *key, size_t keylen)
 {
@@ -23,8 +29,6 @@ static int s390x_aes_gcm_initkey(PROV_GCM_CTX *ctx,
     ctx->key_set = 1;
     memcpy(&actx->plat.s390x.param.kma.k, key, keylen);
     actx->plat.s390x.fc = S390X_AES_FC(keylen);
-    if (!ctx->enc)
-        actx->plat.s390x.fc |= S390X_DECRYPT;
     return 1;
 }
 
@@ -46,6 +50,7 @@ static int s390x_aes_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv,
         memcpy(&kma->j0, iv, ivlen);
         kma->j0.w[3] = 1;
         kma->cv.w = 1;
+        actx->plat.s390x.hsflag = 0;
     } else {
         unsigned long long ivbits = ivlen << 3;
         size_t len = S390X_gcm_ivpadlen(ivlen);
@@ -63,7 +68,7 @@ static int s390x_aes_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv,
          * param.
          */
         s390x_kma(iv_zero_pad, len, NULL, 0, NULL, actx->plat.s390x.fc, kma);
-        actx->plat.s390x.fc |= S390X_KMA_HS; /* The hash subkey is set */
+        actx->plat.s390x.hsflag = S390X_KMA_HS; /* The hash subkey is set */
 
         /* Copy the 128 bit GHASH result into J0 and clear the tag */
         kma->j0.g[0] = kma->t.g[0];
@@ -81,13 +86,15 @@ static int s390x_aes_gcm_cipher_final(PROV_GCM_CTX *ctx, unsigned char *tag)
     PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
     S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
     unsigned char out[AES_BLOCK_SIZE];
+    unsigned int fc;
     int rc;
 
     kma->taadl <<= 3;
     kma->tpcl <<= 3;
+    fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD | S390X_KMA_LPC;
     s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen,
               actx->plat.s390x.mres, actx->plat.s390x.mreslen, out,
-              actx->plat.s390x.fc | S390X_KMA_LAAD | S390X_KMA_LPC, kma);
+              fc, kma);
 
     /* gctx->mres already returned to the caller */
     OPENSSL_cleanse(out, actx->plat.s390x.mreslen);
@@ -110,12 +117,13 @@ static int s390x_aes_gcm_one_shot(PROV_GCM_CTX *ctx,
 {
     PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
     S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
+    unsigned int fc;
     int rc;
 
     kma->taadl = aad_len << 3;
     kma->tpcl = in_len << 3;
-    s390x_kma(aad, aad_len, in, in_len, out,
-              actx->plat.s390x.fc | S390X_KMA_LAAD | S390X_KMA_LPC, kma);
+    fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD | S390X_KMA_LPC;
+    s390x_kma(aad, aad_len, in, in_len, out, fc, kma);
 
     if (ctx->enc) {
         memcpy(tag, kma->t.b, taglen);
@@ -136,6 +144,7 @@ static int s390x_aes_gcm_aad_update(PROV_GCM_CTX *ctx,
     PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
     S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
     unsigned long long alen;
+    unsigned int fc;
     int n, rem;
 
     /* If already processed pt/ct then error */
@@ -160,9 +169,9 @@ static int s390x_aes_gcm_aad_update(PROV_GCM_CTX *ctx,
         }
         /* ctx->ares contains a complete block if offset has wrapped around */
         if (!n) {
-            s390x_kma(actx->plat.s390x.ares, 16, NULL, 0, NULL,
-                      actx->plat.s390x.fc, kma);
-            actx->plat.s390x.fc |= S390X_KMA_HS;
+            fc = S390X_gcm_fc(actx, ctx);
+            s390x_kma(actx->plat.s390x.ares, 16, NULL, 0, NULL, fc, kma);
+            actx->plat.s390x.hsflag = S390X_KMA_HS;
         }
         actx->plat.s390x.areslen = n;
     }
@@ -172,8 +181,9 @@ static int s390x_aes_gcm_aad_update(PROV_GCM_CTX *ctx,
     /* Add any remaining 16 byte blocks (128 bit each) */
     len &= ~(size_t)0xf;
     if (len) {
-        s390x_kma(aad, len, NULL, 0, NULL, actx->plat.s390x.fc, kma);
-        actx->plat.s390x.fc |= S390X_KMA_HS;
+        fc = S390X_gcm_fc(actx, ctx);
+        s390x_kma(aad, len, NULL, 0, NULL, fc, kma);
+        actx->plat.s390x.hsflag = S390X_KMA_HS;
         aad += len;
     }
 
@@ -200,6 +210,7 @@ static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx,
     S390X_KMA_PARAMS *kma = &actx->plat.s390x.param.kma;
     const unsigned char *inptr;
     unsigned long long mlen;
+    unsigned int fc;
     union {
         unsigned int w[4];
         unsigned char b[16];
@@ -212,6 +223,7 @@ static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx,
         return 0;
     kma->tpcl = mlen;
 
+    fc = S390X_gcm_fc(actx, ctx) | S390X_KMA_LAAD;
     n = actx->plat.s390x.mreslen;
     if (n) {
         inptr = in;
@@ -225,9 +237,9 @@ static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx,
         /* ctx->mres contains a complete block if offset has wrapped around */
         if (!n) {
             s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen,
-                      actx->plat.s390x.mres, 16, buf.b,
-                      actx->plat.s390x.fc | S390X_KMA_LAAD, kma);
-            actx->plat.s390x.fc |= S390X_KMA_HS;
+                      actx->plat.s390x.mres, 16, buf.b, fc, kma);
+            actx->plat.s390x.hsflag = S390X_KMA_HS;
+            fc |= S390X_KMA_HS;
             actx->plat.s390x.areslen = 0;
 
             /* previous call already encrypted/decrypted its remainder,
@@ -249,10 +261,10 @@ static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx,
     len &= ~(size_t)0xf;
     if (len) {
         s390x_kma(actx->plat.s390x.ares, actx->plat.s390x.areslen, in, len, out,
-                  actx->plat.s390x.fc | S390X_KMA_LAAD, kma);
+                  fc, kma);
         in += len;
         out += len;
-        actx->plat.s390x.fc |= S390X_KMA_HS;
+        actx->plat.s390x.hsflag = S390X_KMA_HS;
         actx->plat.s390x.areslen = 0;
     }
 
@@ -268,7 +280,7 @@ static int s390x_aes_gcm_cipher_update(PROV_GCM_CTX *ctx,
             buf.w[2] = kma->j0.w[2];
             buf.w[3] = kma->cv.w + 1;
             s390x_km(buf.b, 16, actx->plat.s390x.kres,
-                     actx->plat.s390x.fc & 0x1f, &kma->k);
+                     fc & 0x1f, &kma->k);
         }
 
         n = actx->plat.s390x.mreslen;
diff --git a/providers/implementations/ciphers/cipher_aes_hw_s390x.inc b/providers/implementations/ciphers/cipher_aes_hw_s390x.inc
index c298dfafd7..c8282dbd08 100644
--- a/providers/implementations/ciphers/cipher_aes_hw_s390x.inc
+++ b/providers/implementations/ciphers/cipher_aes_hw_s390x.inc
@@ -14,6 +14,8 @@
 
 #include "s390x_arch.h"
 
+#include <stdio.h>
+
 #define s390x_aes_cbc_initkey    cipher_hw_aes_initkey
 #define s390x_aes_cfb1_initkey   cipher_hw_aes_initkey
 #define s390x_aes_ctr_initkey    cipher_hw_aes_initkey
@@ -34,9 +36,6 @@ static int s390x_aes_ecb_initkey(PROV_CIPHER_CTX *dat,
     PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
 
     adat->plat.s390x.fc = S390X_AES_FC(keylen);
-    if (!dat->enc)
-        adat->plat.s390x.fc |= S390X_DECRYPT;
-
     memcpy(adat->plat.s390x.param.km.k, key, keylen);
     return 1;
 }
@@ -45,8 +44,10 @@ static int s390x_aes_ecb_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
                                    const unsigned char *in, size_t len)
 {
     PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+    unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT;
 
-    s390x_km(in, len, out, adat->plat.s390x.fc, &adat->plat.s390x.param.km);
+    s390x_km(in, len, out, adat->plat.s390x.fc | modifier,
+             &adat->plat.s390x.param.km);
     return 1;
 }
 
@@ -90,7 +91,8 @@ static int s390x_aes_ofb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
 
     if (rem) {
         s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16,
-                 adat->plat.s390x.param.kmo_kmf.cv, adat->plat.s390x.fc,
+                 adat->plat.s390x.param.kmo_kmf.cv,
+                 adat->plat.s390x.fc,
                  adat->plat.s390x.param.kmo_kmf.k);
 
         while (rem--) {
@@ -111,9 +113,6 @@ static int s390x_aes_cfb128_initkey(PROV_CIPHER_CTX *dat,
 
     adat->plat.s390x.fc = S390X_AES_FC(keylen);
     adat->plat.s390x.fc |= 16 << 24;   /* 16 bytes cipher feedback */
-    if (!dat->enc)
-        adat->plat.s390x.fc |= S390X_DECRYPT;
-
     adat->plat.s390x.res = 0;
     memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
     return 1;
@@ -123,6 +122,7 @@ static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
                                       const unsigned char *in, size_t len)
 {
     PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+    unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT;
     int n = adat->plat.s390x.res;
     int rem;
     unsigned char tmp;
@@ -142,7 +142,7 @@ static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
 
     len &= ~(size_t)0xf;
     if (len) {
-        s390x_kmf(in, len, out, adat->plat.s390x.fc,
+        s390x_kmf(in, len, out, adat->plat.s390x.fc | modifier,
                   &adat->plat.s390x.param.kmo_kmf);
 
         out += len;
@@ -152,7 +152,8 @@ static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
     if (rem) {
         s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16,
                  adat->plat.s390x.param.kmo_kmf.cv,
-                 S390X_AES_FC(dat->keylen), adat->plat.s390x.param.kmo_kmf.k);
+                 S390X_AES_FC(dat->keylen),
+                 adat->plat.s390x.param.kmo_kmf.k);
 
         while (rem--) {
             tmp = in[n];
@@ -174,9 +175,6 @@ static int s390x_aes_cfb8_initkey(PROV_CIPHER_CTX *dat,
 
     adat->plat.s390x.fc = S390X_AES_FC(keylen);
     adat->plat.s390x.fc |= 1 << 24;   /* 1 byte cipher feedback */
-    if (!dat->enc)
-        adat->plat.s390x.fc |= S390X_DECRYPT;
-
     memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
     return 1;
 }
@@ -185,9 +183,10 @@ static int s390x_aes_cfb8_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
                                     const unsigned char *in, size_t len)
 {
     PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
+    unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT;
 
     memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
-    s390x_kmf(in, len, out, adat->plat.s390x.fc,
+    s390x_kmf(in, len, out, adat->plat.s390x.fc | modifier,
               &adat->plat.s390x.param.kmo_kmf);
     memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen);
     return 1;
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index f26330b5d8..61f6b4ce00 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -402,6 +402,95 @@ static const unsigned char kExampleED25519PubKeyDER[] = {
 
 #endif
 
+static const unsigned char kCFBDefaultKey[] = {
+    0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
+    0x09, 0xCF, 0x4F, 0x3C
+};
+
+static const unsigned char kGCMDefaultKey[32] = { 0 };
+
+static const unsigned char kGCMResetKey[] = {
+    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
+    0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
+};
+
+static const unsigned char iCFBIV[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+    0x0C, 0x0D, 0x0E, 0x0F
+};
+
+static const unsigned char iGCMDefaultIV[12] = { 0 };
+
+static const unsigned char iGCMResetIV1[] = {
+    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad
+};
+
+static const unsigned char iGCMResetIV2[] = {
+    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88
+};
+
+static const unsigned char cfbPlaintext[] = {
+    0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11,
+    0x73, 0x93, 0x17, 0x2A
+};
+
+static const unsigned char gcmDefaultPlaintext[16] = { 0 };
+
+static const unsigned char gcmResetPlaintext[] = {
+    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5,
+    0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95,
+    0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39
+};
+
+static const unsigned char cfbCiphertext[] = {
+    0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, 0x33, 0x34, 0x49, 0xF8,
+    0xE8, 0x3C, 0xFB, 0x4A
+};
+
+static const unsigned char gcmDefaultCiphertext[] = {
+    0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, 0x07, 0x4e, 0xc5, 0xd3,
+    0xba, 0xf3, 0x9d, 0x18
+};
+
+static const unsigned char gcmResetCiphertext1[] = {
+    0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, 0xae, 0x47, 0xc1, 0x3b,
+    0xf1, 0x98, 0x44, 0xcb, 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa,
+    0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0, 0xfe, 0xb5, 0x82, 0xd3,
+    0x39, 0x34, 0xa4, 0xf0, 0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78,
+    0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99, 0xf4, 0x7c, 0x9b, 0x1f
+};
+
+static const unsigned char gcmResetCiphertext2[] = {
+    0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3,
+    0x2a, 0x84, 0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
+    0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48,
+    0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
+    0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, 0xbc, 0xc9, 0xf6, 0x62
+};
+
+static const unsigned char gcmAAD[] = {
+    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce,
+    0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2
+};
+
+static const unsigned char gcmDefaultTag[] = {
+    0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, 0x26, 0x5b, 0x98, 0xb5,
+    0xd4, 0x8a, 0xb9, 0x19
+};
+
+static const unsigned char gcmResetTag1[] = {
+    0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, 0x5e, 0x45, 0x49, 0x13,
+    0xfe, 0x2e, 0xa8, 0xf2
+};
+
+static const unsigned char gcmResetTag2[] = {
+    0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, 0xcd, 0xdf, 0x88, 0x53,
+    0xbb, 0x2d, 0x55, 0x1b
+};
+
 typedef struct APK_DATA_st {
     const unsigned char *kder;
     size_t size;
@@ -2895,6 +2984,387 @@ static int test_names_do_all(void)
     return testresult;
 }
 
+typedef struct {
+    const char *cipher;
+    const unsigned char *key;
+    const unsigned char *iv;
+    const unsigned char *input;
+    const unsigned char *expected;
+    const unsigned char *tag;
+    size_t ivlen; /* 0 if we do not need to set a specific IV len */
+    size_t inlen;
+    size_t expectedlen;
+    size_t taglen;
+    int keyfirst;
+    int initenc;
+    int finalenc;
+} EVP_INIT_TEST_st;
+
+static const EVP_INIT_TEST_st evp_init_tests[] = {
+    {
+        "aes-128-cfb", kCFBDefaultKey, iCFBIV, cfbPlaintext,
+        cfbCiphertext, NULL, 0, sizeof(cfbPlaintext), sizeof(cfbCiphertext),
+        0, 1, 0, 1
+    },
+    {
+        "aes-256-gcm", kGCMDefaultKey, iGCMDefaultIV, gcmDefaultPlaintext,
+        gcmDefaultCiphertext, gcmDefaultTag, sizeof(iGCMDefaultIV),
+        sizeof(gcmDefaultPlaintext), sizeof(gcmDefaultCiphertext),
+        sizeof(gcmDefaultTag), 1, 0, 1
+    },
+    {
+        "aes-128-cfb", kCFBDefaultKey, iCFBIV, cfbPlaintext,
+        cfbCiphertext, NULL, 0, sizeof(cfbPlaintext), sizeof(cfbCiphertext),
+        0, 0, 0, 1
+    },
+    {
+        "aes-256-gcm", kGCMDefaultKey, iGCMDefaultIV, gcmDefaultPlaintext,
+        gcmDefaultCiphertext, gcmDefaultTag, sizeof(iGCMDefaultIV),
+        sizeof(gcmDefaultPlaintext), sizeof(gcmDefaultCiphertext),
+        sizeof(gcmDefaultTag), 0, 0, 1
+    },
+    {
+        "aes-128-cfb", kCFBDefaultKey, iCFBIV, cfbCiphertext,
+        cfbPlaintext, NULL, 0, sizeof(cfbCiphertext), sizeof(cfbPlaintext),
+        0, 1, 1, 0
+    },
+    {
+        "aes-256-gcm", kGCMDefaultKey, iGCMDefaultIV, gcmDefaultCiphertext,
+        gcmDefaultPlaintext, gcmDefaultTag, sizeof(iGCMDefaultIV),
+        sizeof(gcmDefaultCiphertext), sizeof(gcmDefaultPlaintext),
+        sizeof(gcmDefaultTag), 1, 1, 0
+    },
+    {
+        "aes-128-cfb", kCFBDefaultKey, iCFBIV, cfbCiphertext,
+        cfbPlaintext, NULL, 0, sizeof(cfbCiphertext), sizeof(cfbPlaintext),
+        0, 0, 1, 0
+    },
+    {
+        "aes-256-gcm", kGCMDefaultKey, iGCMDefaultIV, gcmDefaultCiphertext,
+        gcmDefaultPlaintext, gcmDefaultTag, sizeof(iGCMDefaultIV),
+        sizeof(gcmDefaultCiphertext), sizeof(gcmDefaultPlaintext),
+        sizeof(gcmDefaultTag), 0, 1, 0
+    }
+};
+
+static int evp_init_seq_set_iv(EVP_CIPHER_CTX *ctx, const EVP_INIT_TEST_st *t)
+{
+    int res = 0;
+    
+    if (t->ivlen != 0) {
+        if (!TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, t->ivlen, NULL)))
+            goto err;
+    }
+    if (!TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, NULL, t->iv, -1)))
+        goto err;
+    res = 1;
+ err:
+    return res;
+}
+
+/*
+ * Test step-wise cipher initialization via EVP_CipherInit_ex where the
+ * arguments are given one at a time and a final adjustment to the enc
+ * parameter sets the correct operation.
+ */
+static int test_evp_init_seq(int idx)
+{
+    int outlen1, outlen2;
+    int testresult = 0;
+    unsigned char outbuf[1024];
+    unsigned char tag[16];
+    const EVP_INIT_TEST_st *t = &evp_init_tests[idx];
+    EVP_CIPHER_CTX *ctx = NULL;
+    EVP_CIPHER *type = NULL;
+    size_t taglen = sizeof(tag);
+    char *errmsg = NULL;
+
+    ctx = EVP_CIPHER_CTX_new();
+    if (ctx == NULL) {
+        errmsg = "CTX_ALLOC";
+        goto err;
+    }
+    if (!TEST_ptr(type = EVP_CIPHER_fetch(testctx, t->cipher, testpropq))) {
+        errmsg = "CIPHER_FETCH";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherInit_ex(ctx, type, NULL, NULL, NULL, t->initenc))) {
+        errmsg = "EMPTY_ENC_INIT";
+        goto err;
+    }
+    if (!TEST_true(EVP_CIPHER_CTX_set_padding(ctx, 0))) {
+        errmsg = "PADDING";
+        goto err;
+    }
+    if (t->keyfirst && !TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, t->key, NULL, -1))) {
+        errmsg = "KEY_INIT (before iv)";
+        goto err;
+    }
+    if (!evp_init_seq_set_iv(ctx, t)) {
+        errmsg = "IV_INIT";
+        goto err;
+    }
+    if (t->keyfirst == 0 &&  !TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, t->key, NULL, -1))) {
+        errmsg = "KEY_INIT (after iv)";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, t->finalenc))) {
+        errmsg = "FINAL_ENC_INIT";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherUpdate(ctx, outbuf, &outlen1, t->input, t->inlen))) {
+        errmsg = "CIPHER_UPDATE";
+        goto err;
+    }
+    if (t->finalenc == 0 && t->tag != NULL) {
+        /* Set expected tag */
+        if (!TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
+                                           t->taglen, (void *)t->tag))) {
+            errmsg = "SET_TAG";
+            goto err;
+        }
+    }
+    if (!TEST_true(EVP_CipherFinal_ex(ctx, outbuf + outlen1, &outlen2))) {
+        errmsg = "CIPHER_FINAL";
+        goto err;
+    }
+    if (!TEST_mem_eq(t->expected, t->expectedlen, outbuf, outlen1 + outlen2)) {
+        errmsg = "WRONG_RESULT";
+        goto err;
+    }
+    if (t->finalenc != 0 && t->tag != NULL) {
+        if (!TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, tag))) {
+            errmsg = "GET_TAG";
+            goto err;
+        }
+        if (!TEST_mem_eq(t->tag, t->taglen, tag, taglen)) {
+            errmsg = "TAG_ERROR";
+            goto err;
+        }
+    }
+    testresult = 1;
+ err:
+    if (errmsg != NULL)
+        TEST_info("evp_init_test %d: %s", idx, errmsg);
+    EVP_CIPHER_CTX_free(ctx);
+    EVP_CIPHER_free(type);
+    return testresult;
+}
+
+typedef struct {
+    const unsigned char *input;
+    const unsigned char *expected;
+    size_t inlen;
+    size_t expectedlen;
+    int enc;
+} EVP_RESET_TEST_st;
+
+static const EVP_RESET_TEST_st evp_reset_tests[] = {
+    {
+        cfbPlaintext, cfbCiphertext,
+        sizeof(cfbPlaintext), sizeof(cfbCiphertext), 1
+    },
+    {
+        cfbCiphertext, cfbPlaintext,
+        sizeof(cfbCiphertext), sizeof(cfbPlaintext), 0
+    }
+};
+
+/*
+ * Test a reset of a cipher via EVP_CipherInit_ex after the cipher has already
+ * been used.
+ */
+static int test_evp_reset(int idx)
+{
+    const EVP_RESET_TEST_st *t = &evp_reset_tests[idx];
+    int outlen1, outlen2;
+    int testresult = 0;
+    unsigned char outbuf[1024];
+    EVP_CIPHER_CTX *ctx = NULL;
+    EVP_CIPHER *type = NULL;
+    char *errmsg = NULL;
+
+    if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())) {
+        errmsg = "CTX_ALLOC";
+        goto err;
+    }
+    if (!TEST_ptr(type = EVP_CIPHER_fetch(testctx, "aes-128-cfb", testpropq))) {
+        errmsg = "CIPHER_FETCH";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherInit_ex(ctx, type, NULL, kCFBDefaultKey, iCFBIV, t->enc))) {
+        errmsg = "CIPHER_INIT";
+        goto err;
+    }
+    if (!TEST_true(EVP_CIPHER_CTX_set_padding(ctx, 0))) {
+        errmsg = "PADDING";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherUpdate(ctx, outbuf, &outlen1, t->input, t->inlen))) {
+        errmsg = "CIPHER_UPDATE";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherFinal_ex(ctx, outbuf + outlen1, &outlen2))) {
+        errmsg = "CIPHER_FINAL";
+        goto err;
+    }
+    if (!TEST_mem_eq(t->expected, t->expectedlen, outbuf, outlen1 + outlen2)) {
+        errmsg = "WRONG_RESULT";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1))) {
+        errmsg = "CIPHER_REINIT";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherUpdate(ctx, outbuf, &outlen1, t->input, t->inlen))) {
+        errmsg = "CIPHER_UPDATE (reinit)";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherFinal_ex(ctx, outbuf + outlen1, &outlen2))) {
+        errmsg = "CIPHER_FINAL (reinit)";
+        goto err;
+    }
+    if (!TEST_mem_eq(t->expected, t->expectedlen, outbuf, outlen1 + outlen2)) {
+        errmsg = "WRONG_RESULT (reinit)";
+        goto err;
+    }
+    testresult = 1;
+ err:
+    if (errmsg != NULL)
+        TEST_info("test_evp_reset %d: %s", idx, errmsg);
+    EVP_CIPHER_CTX_free(ctx);
+    EVP_CIPHER_free(type);
+    return testresult;    
+}
+
+typedef struct {
+    const unsigned char *iv1;
+    const unsigned char *iv2;
+    const unsigned char *expected1;
+    const unsigned char *expected2;
+    const unsigned char *tag1;
+    const unsigned char *tag2;
+    size_t ivlen1;
+    size_t ivlen2;
+    size_t expectedlen1;
+    size_t expectedlen2;
+} TEST_GCM_IV_REINIT_st;
+
+static const TEST_GCM_IV_REINIT_st gcm_reinit_tests[] = {
+    {
+        iGCMResetIV1, iGCMResetIV2, gcmResetCiphertext1, gcmResetCiphertext2,
+        gcmResetTag1, gcmResetTag2, sizeof(iGCMResetIV1), sizeof(iGCMResetIV2),
+        sizeof(gcmResetCiphertext1), sizeof(gcmResetCiphertext2)
+    },
+    {
+        iGCMResetIV2, iGCMResetIV1, gcmResetCiphertext2, gcmResetCiphertext1,
+        gcmResetTag2, gcmResetTag1, sizeof(iGCMResetIV2), sizeof(iGCMResetIV1),
+        sizeof(gcmResetCiphertext2), sizeof(gcmResetCiphertext1)
+    }
+};
+
+static int test_gcm_reinit(int idx)
+{
+    int outlen1, outlen2, outlen3;
+    int testresult = 0;
+    unsigned char outbuf[1024];
+    unsigned char tag[16];
+    const TEST_GCM_IV_REINIT_st *t = &gcm_reinit_tests[idx];
+    EVP_CIPHER_CTX *ctx = NULL;
+    EVP_CIPHER *type = NULL;
+    size_t taglen = sizeof(tag);
+    char *errmsg = NULL;
+
+    if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())) {
+        errmsg = "CTX_ALLOC";
+        goto err;
+    }
+    if (!TEST_ptr(type = EVP_CIPHER_fetch(testctx, "aes-256-gcm", testpropq))) {
+        errmsg = "CIPHER_FETCH";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherInit_ex(ctx, type, NULL, NULL, NULL, 1))) {
+        errmsg = "ENC_INIT";
+        goto err;
+    }
+    if (!TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, t->ivlen1, NULL))) {
+        errmsg = "SET_IVLEN1";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, kGCMResetKey, t->iv1, 1))) {
+        errmsg = "SET_IV1";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherUpdate(ctx, NULL, &outlen3, gcmAAD, sizeof(gcmAAD)))) {
+        errmsg = "AAD1";
+        goto err;
+    }
+    EVP_CIPHER_CTX_set_padding(ctx, 0);
+    if (!TEST_true(EVP_CipherUpdate(ctx, outbuf, &outlen1, gcmResetPlaintext,
+                                    sizeof(gcmResetPlaintext)))) {
+        errmsg = "CIPHER_UPDATE1";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherFinal_ex(ctx, outbuf + outlen1, &outlen2))) {
+        errmsg = "CIPHER_FINAL1";
+        goto err;
+    }
+    if (!TEST_mem_eq(t->expected1, t->expectedlen1, outbuf, outlen1 + outlen2)) {
+        errmsg = "WRONG_RESULT1";
+        goto err;
+    }
+    if (!TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, tag))) {
+        errmsg = "GET_TAG1";
+        goto err;
+    }
+    if (!TEST_mem_eq(t->tag1, taglen, tag, taglen)) {
+        errmsg = "TAG_ERROR1";
+        goto err;
+    }
+    /* Now reinit */
+    if (!TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, t->ivlen2, NULL))) {
+        errmsg = "SET_IVLEN2";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherInit_ex(ctx, NULL, NULL, NULL, t->iv2, -1))) {
+        errmsg = "SET_IV2";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherUpdate(ctx, NULL, &outlen3, gcmAAD, sizeof(gcmAAD)))) {
+        errmsg = "AAD2";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherUpdate(ctx, outbuf, &outlen1, gcmResetPlaintext,
+                                    sizeof(gcmResetPlaintext)))) {
+        errmsg = "CIPHER_UPDATE2";
+        goto err;
+    }
+    if (!TEST_true(EVP_CipherFinal_ex(ctx, outbuf + outlen1, &outlen2))) {
+        errmsg = "CIPHER_FINAL2";
+        goto err;
+    }
+    if (!TEST_mem_eq(t->expected2, t->expectedlen2, outbuf, outlen1 + outlen2)) {
+        errmsg = "WRONG_RESULT2";
+        goto err;
+    }
+    if (!TEST_true(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, tag))) {
+        errmsg = "GET_TAG2";
+        goto err;
+    }
+    if (!TEST_mem_eq(t->tag2, taglen, tag, taglen)) {
+        errmsg = "TAG_ERROR2";
+        goto err;
+    }
+    testresult = 1;
+ err:
+    if (errmsg != NULL)
+        TEST_info("evp_init_test %d: %s", idx, errmsg);
+    EVP_CIPHER_CTX_free(ctx);
+    EVP_CIPHER_free(type);
+    return testresult;
+}
+
+
 typedef enum OPTION_choice {
     OPT_ERR = -1,
     OPT_EOF = 0,
@@ -3011,6 +3481,10 @@ int setup_tests(void)
 
     ADD_TEST(test_names_do_all);
 
+    ADD_ALL_TESTS(test_evp_init_seq, OSSL_NELEM(evp_init_tests));
+    ADD_ALL_TESTS(test_evp_reset, OSSL_NELEM(evp_reset_tests));
+    ADD_ALL_TESTS(test_gcm_reinit, OSSL_NELEM(gcm_reinit_tests));
+
     return 1;
 }
 


More information about the openssl-commits mailing list