File 0012-s390x-assembly-pack-add-KMA-code-path-for-aes-gcm.patch of Package openssl-1_1.13606

From acef148f0aac18d78c3c857065b3a1274279b2df Mon Sep 17 00:00:00 2001
From: Patrick Steuer <patrick.steuer@de.ibm.com>
Date: Sat, 25 Feb 2017 10:05:12 +0100
Subject: [PATCH 12/44] s390x assembly pack: add KMA code path for aes-gcm.

Signed-off-by: Patrick Steuer <patrick.steuer@de.ibm.com>
---
 crypto/aes/asm/aes-s390x.pl |  52 ++++++++++++
 crypto/evp/e_aes.c          | 200 ++++++++++++++++++++++++++++++++++++++++++--
 crypto/modes/gcm128.c       |   4 +
 crypto/s390x_arch.h         |   5 ++
 4 files changed, 253 insertions(+), 8 deletions(-)

Index: openssl-1.1.0g/crypto/aes/asm/aes-s390x.pl
===================================================================
--- openssl-1.1.0g.orig/crypto/aes/asm/aes-s390x.pl	2018-01-09 17:35:12.231011406 +0100
+++ openssl-1.1.0g/crypto/aes/asm/aes-s390x.pl	2018-01-09 17:35:16.795082242 +0100
@@ -2257,6 +2257,58 @@ $code.=<<___;
 .size	AES_xts_decrypt,.-AES_xts_decrypt
 ___
 }
+
+################
+# void s390x_aes_gcm_blocks(unsigned char *out, GCM128_CONTEXT *ctx,
+#                           const unsigned char *in, size_t len,
+#                           const unsigned char *aad, size_t alen,
+#                           const AES_KEY *key, int enc)
+{
+my ($out,$ctx,$in,$len,$aad,$alen,$key,$enc) = map("%r$_",(2..9));
+$code.=<<___ if (!$softonly);
+.globl	s390x_aes_gcm_blocks
+.type	s390x_aes_gcm_blocks,\@function
+.align	16
+s390x_aes_gcm_blocks:
+	stm$g	$alen,$enc,7*$SIZE_T($sp)
+	lm$g	$alen,$enc,$stdframe($sp)
+
+	aghi	$sp,-112
+
+	lmg	%r0,%r1,0($ctx)
+	ahi	%r1,-1
+
+	mvc	16(32,$sp),64($ctx)	# copy Xi/H
+	#mvc	48(16,$sp),48($ctx)	# copy len
+	mvc	80(32,$sp),0($key)	# copy key
+	st	%r1,12($sp)		# copy Yi
+	stmg	%r0,%r1,64($sp)
+
+	lhi	%r1,128
+	l	%r0,240($key)	# kma capability vector checked by caller
+	sll	$enc,7
+	xr	$enc,%r1
+	or	%r0,$enc
+
+	la	%r1,0($sp)
+
+	.long	0xb9296024	# kma $out,$aad,$in
+	brc	1,.-4		# pay attention to "partial completion"
+
+	l	%r0,12($sp)
+	mvc	64(16,$ctx),16($sp)	# update Xi
+	xc	0(112,$sp),0($sp)	# wipe stack
+
+	la	$sp,112($sp)
+	ahi	%r0,1
+	st	%r0,12($ctx)
+
+	lm$g	$alen,$enc,7*$SIZE_T($sp)
+	br	$ra
+.size	s390x_aes_gcm_blocks,.-s390x_aes_gcm_blocks
+___
+}
+
 $code.=<<___;
 .string	"AES for s390x, CRYPTOGAMS by <appro\@openssl.org>"
 ___
Index: openssl-1.1.0g/crypto/evp/e_aes.c
===================================================================
--- openssl-1.1.0g.orig/crypto/evp/e_aes.c	2018-01-09 17:35:12.199010909 +0100
+++ openssl-1.1.0g/crypto/evp/e_aes.c	2018-01-09 17:35:12.239011531 +0100
@@ -960,7 +960,7 @@ const EVP_CIPHER *EVP_aes_##keylen##_##m
  * If KM and KMC support the function code, AES_KEY structure holds
  * key/function code (instead of key schedule/number of rounds).
  */
-# define S390X_AES_FC (((AES_KEY *)(key))->rounds)
+# define S390X_AES_FC(key)	(((AES_KEY *)(key))->rounds)
 
 # define S390X_aes_128_CAPABLE ((OPENSSL_s390xcap_P[5]&S390X_KM_AES_128)&&\
                                 (OPENSSL_s390xcap_P[7]&S390X_KMC_AES_128))
@@ -969,6 +969,11 @@ const EVP_CIPHER *EVP_aes_##keylen##_##m
 # define S390X_aes_256_CAPABLE ((OPENSSL_s390xcap_P[5]&S390X_KM_AES_256)&&\
                                 (OPENSSL_s390xcap_P[7]&S390X_KMC_AES_256))
 
+void s390x_aes_gcm_blocks(unsigned char *out, GCM128_CONTEXT *ctx,
+                          const unsigned char *in, size_t len,
+                          const unsigned char *aad, size_t alen,
+                          const AES_KEY *key, int enc);
+
 # define s390x_aes_init_key aes_init_key
 static int s390x_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
                               const unsigned char *iv, int enc);
@@ -1029,18 +1034,197 @@ static int s390x_aes_cfb1_cipher(EVP_CIP
 static int s390x_aes_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
                                 const unsigned char *in, size_t len);
 
-# define S390X_aes_128_gcm_CAPABLE	0
-# define S390X_aes_192_gcm_CAPABLE	0
-# define S390X_aes_256_gcm_CAPABLE	0
+# define S390X_aes_128_gcm_CAPABLE (S390X_aes_128_CAPABLE&&\
+                                    OPENSSL_s390xcap_P[17]\
+                                    &S390X_KMA_GCM_AES_128)
+# define S390X_aes_192_gcm_CAPABLE (S390X_aes_192_CAPABLE&&\
+                                    OPENSSL_s390xcap_P[17]\
+                                    &S390X_KMA_GCM_AES_192)
+# define S390X_aes_256_gcm_CAPABLE (S390X_aes_256_CAPABLE&&\
+                                    OPENSSL_s390xcap_P[17]\
+                                    &S390X_KMA_GCM_AES_256)
+
+static int s390x_aes_gcm(GCM128_CONTEXT *ctx, const unsigned char *in,
+                         unsigned char *out, size_t len, int enc)
+{
+    int n;
+    size_t rem;
+    u64 mlen = ctx->len.u[1];
+    unsigned char tmp;
+
+    mlen += len;
+
+    if (mlen > ((1ULL << 36) - 32) || (sizeof(len) == 8 && mlen < len))
+        return -1;
+
+    ctx->len.u[1] = mlen;
+
+    if (ctx->ares) {
+        (*ctx->gmult)(ctx->Xi.u, ctx->Htable);
+        ctx->ares = 0;
+    }
+    S390X_AES_FC(ctx->key) |= S390X_KMA_LAAD;
+    n = ctx->mres;
+
+    if (n) {
+        while (n && len) {
+            tmp = *in;
+            *out = tmp ^ ctx->EKi.c[n];
+            ctx->Xi.c[n] ^= enc ? *out : tmp;
+            n = (n + 1) % AES_BLOCK_SIZE;
+            --len;
+            ++in;
+            ++out;
+        }
+        if (n == 0) {
+            (*ctx->gmult)(ctx->Xi.u, ctx->Htable);
+        } else {
+            ctx->mres = n;
+            return 0;
+        }
+    }
+    rem = len % AES_BLOCK_SIZE;
+    len -= rem;
+
+    s390x_aes_gcm_blocks(out, ctx, in, len, NULL, 0, ctx->key, enc);
+
+    if (rem) {
+        in += len;
+        out += len;
+        (*ctx->block)(ctx->Yi.c, ctx->EKi.c, ctx->key);
+        ++ctx->Yi.d[3];
+        while (rem--) {
+            tmp = in[n];
+            out[n] = tmp ^ ctx->EKi.c[n];
+            ctx->Xi.c[n] ^= enc ? out[n] : tmp;
+            ++n;
+        }
+    }
+
+    ctx->mres = n;
+    return 0;
+}
 
-# define s390x_aes_gcm_init_key aes_gcm_init_key
 static int s390x_aes_gcm_init_key(EVP_CIPHER_CTX *ctx,
                                   const unsigned char *key,
-                                  const unsigned char *iv, int enc);
+                                  const unsigned char *iv, int enc)
+{
+    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,ctx);
+    const int keybitlen = EVP_CIPHER_CTX_key_length(ctx) * 8;
+
+    if (!iv && !key)
+        return 1;
+
+    if (key) {
+        AES_set_encrypt_key(key, keybitlen, &gctx->ks.ks);
+        CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)AES_encrypt);
+        S390X_AES_FC(&gctx->ks) |= S390X_KMA_HS;
+
+        if (iv == NULL && gctx->iv_set)
+            iv = gctx->iv;
+
+        if (iv) {
+            CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+            gctx->iv_set = 1;
+        }
+        gctx->key_set = 1;
+    } else {
+        if (gctx->key_set)
+            CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
+        else
+            memcpy(gctx->iv, iv, gctx->ivlen);
+
+        gctx->iv_set = 1;
+        gctx->iv_gen = 0;
+    }
+    return 1;
+}
+
+static int s390x_aes_gcm_tls_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+                                    const unsigned char *in, size_t len)
+{
+    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,ctx);
+    unsigned char *buf = EVP_CIPHER_CTX_buf_noconst(ctx);
+    int enc = EVP_CIPHER_CTX_encrypting(ctx);
+    int rv = -1;
+
+    if (out != in || len < (EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN))
+        return -1;
+
+    if (EVP_CIPHER_CTX_ctrl(ctx, enc ? EVP_CTRL_GCM_IV_GEN :
+                            EVP_CTRL_GCM_SET_IV_INV,
+                            EVP_GCM_TLS_EXPLICIT_IV_LEN, out) <= 0)
+        goto err;
+
+    if (CRYPTO_gcm128_aad(&gctx->gcm, buf, gctx->tls_aad_len))
+        goto err;
+
+    in += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+    out += EVP_GCM_TLS_EXPLICIT_IV_LEN;
+    len -= EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
+
+    if (s390x_aes_gcm(&gctx->gcm, in, out, len, enc))
+        goto err;
+
+    if (enc) {
+        out += len;
+        CRYPTO_gcm128_tag(&gctx->gcm, out, EVP_GCM_TLS_TAG_LEN);
+        rv = len + EVP_GCM_TLS_EXPLICIT_IV_LEN + EVP_GCM_TLS_TAG_LEN;
+    } else {
+        CRYPTO_gcm128_tag(&gctx->gcm, buf, EVP_GCM_TLS_TAG_LEN);
+
+        if (CRYPTO_memcmp(buf, in + len, EVP_GCM_TLS_TAG_LEN)) {
+            OPENSSL_cleanse(out, len);
+            goto err;
+        }
+        rv = len;
+    }
+ err:
+    gctx->iv_set = 0;
+    gctx->tls_aad_len = -1;
+    return rv;
+}
 
-# define s390x_aes_gcm_cipher aes_gcm_cipher
 static int s390x_aes_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
-                                const unsigned char *in, size_t len);
+                                const unsigned char *in, size_t len)
+{
+    EVP_AES_GCM_CTX *gctx = EVP_C_DATA(EVP_AES_GCM_CTX,ctx);
+    unsigned char *buf = EVP_CIPHER_CTX_buf_noconst(ctx);
+    int enc = EVP_CIPHER_CTX_encrypting(ctx);
+
+    if (!gctx->key_set)
+        return -1;
+
+    if (gctx->tls_aad_len >= 0)
+        return s390x_aes_gcm_tls_cipher(ctx, out, in, len);
+
+    if (!gctx->iv_set)
+        return -1;
+
+    if (in) {
+        if (out == NULL) {
+            if (CRYPTO_gcm128_aad(&gctx->gcm, in, len))
+                return -1;
+        } else {
+            if (s390x_aes_gcm(&gctx->gcm, in, out, len, enc))
+                return -1;
+        }
+        return len;
+    } else {
+        if (enc) {
+            gctx->taglen = 16;
+            CRYPTO_gcm128_tag(&gctx->gcm, buf, gctx->taglen);
+        } else {
+            if (gctx->taglen < 0)
+                return -1;
+
+            if (CRYPTO_gcm128_finish(&gctx->gcm, buf, gctx->taglen))
+                return -1;
+        }
+        gctx->iv_set = 0;
+        return 0;
+    }
+}
 
 # define S390X_aes_128_xts_CAPABLE	1	/* checked by callee */
 # define S390X_aes_256_xts_CAPABLE	1
Index: openssl-1.1.0g/crypto/modes/gcm128.c
===================================================================
--- openssl-1.1.0g.orig/crypto/modes/gcm128.c	2017-11-02 15:29:03.000000000 +0100
+++ openssl-1.1.0g/crypto/modes/gcm128.c	2018-01-09 17:35:12.239011531 +0100
@@ -817,6 +817,10 @@ void CRYPTO_gcm128_init(GCM128_CONTEXT *
         ctx->gmult = gcm_gmult_4bit;
         CTX__GHASH(gcm_ghash_4bit);
     }
+# elif defined(GHASH_ASM)
+    gcm_init_4bit(ctx->Htable, ctx->H.u);
+    ctx->gmult = gcm_gmult_4bit;
+    CTX__GHASH(gcm_ghash_4bit);
 # else
     gcm_init_4bit(ctx->Htable, ctx->H.u);
 # endif
Index: openssl-1.1.0g/crypto/s390x_arch.h
===================================================================
--- openssl-1.1.0g.orig/crypto/s390x_arch.h	2018-01-09 17:35:12.207011034 +0100
+++ openssl-1.1.0g/crypto/s390x_arch.h	2018-01-09 17:35:12.239011531 +0100
@@ -45,4 +45,9 @@ extern uint64_t OPENSSL_s390xcap_P[];
 # define S390X_KMA_GCM_AES_192	(1ULL << 44)
 # define S390X_KMA_GCM_AES_128	(1ULL << 45)
 
+/* %r0 flags */
+# define S390X_KMA_LPC		(1ULL <<  8)
+# define S390X_KMA_LAAD		(1ULL <<  9)
+# define S390X_KMA_HS		(1ULL << 10)
+
 #endif