summaryrefslogtreecommitdiffstats
path: root/providers
diff options
context:
space:
mode:
authorJuergen Christ <jchrist@linux.ibm.com>2021-05-28 15:02:52 +0200
committerPauli <pauli@openssl.org>2021-06-08 14:32:44 +1000
commitff555f81365d1c09a408019924cace4a0f457ef6 (patch)
treec99b031f83fe6ee47d9f2d7e4bb0f86e41181c1d /providers
parent6d2e0076e6a8146f3bdaa60151b2fa6e4df0d1bf (diff)
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@linux.ibm.com> Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/15521)
Diffstat (limited to 'providers')
-rw-r--r--providers/implementations/ciphers/cipher_aes_gcm.h1
-rw-r--r--providers/implementations/ciphers/cipher_aes_gcm_hw_s390x.inc46
-rw-r--r--providers/implementations/ciphers/cipher_aes_hw_s390x.inc27
3 files changed, 43 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;