From: Simo Sorce Date: Thu, 11 Jun 2026 17:38:05 +0000 (-0400) Subject: Migrate s390x AES-XTS to standard HW interface X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=774525b38bd4;p=thirdparty%2Fopenssl.git Migrate s390x AES-XTS to standard HW interface Move the s390x-specific AES-XTS implementation from `cipher_aes_xts_s390x.inc` to `cipher_aes_xts_hw.c`, adapting it to use the standard `PROV_CIPHER_HW` dispatch structure. This refactoring removes standalone initialization wrappers and integrates the s390x hardware backend more cleanly with the generic AES-XTS provider code. It also reduces code duplication by relying on the generic layer for common validations (such as the maximum blocks per data unit limit) before invoking the hardware-specific stream cipher. Signed-off-by: Simo Sorce Reviewed-by: Dmitry Belyavskiy Reviewed-by: Norbert Pocs Reviewed-by: Shane Lontis MergeDate: Sat Jun 27 09:05:46 2026 (Merged from https://github.com/openssl/openssl/pull/31472) --- diff --git a/providers/implementations/ciphers/cipher_aes_xts.c b/providers/implementations/ciphers/cipher_aes_xts.c index a630b25eb34..10c99c400e1 100644 --- a/providers/implementations/ciphers/cipher_aes_xts.c +++ b/providers/implementations/ciphers/cipher_aes_xts.c @@ -63,10 +63,6 @@ static int aes_xts_check_keys_differ(const unsigned char *key, size_t bytes, return 1; } -#ifdef AES_XTS_S390X -#include "cipher_aes_xts_s390x.inc" -#endif - /*- * Provider dispatch functions */ @@ -85,6 +81,17 @@ static int aes_xts_init(void *vctx, const unsigned char *key, size_t keylen, if (iv != NULL) { if (!ossl_cipher_generic_initiv(vctx, iv, ivlen)) return 0; +#ifdef AES_XTS_S390X + if (key == NULL) { + /* special handle iv-only update */ + if (ivlen > sizeof(xctx->plat.s390x.param.km.tweak)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + memcpy(xctx->plat.s390x.param.km.tweak, iv, ivlen); + xctx->plat.s390x.iv_set = 1; + } +#endif } if (key != NULL) { if (keylen != ctx->keylen) { @@ -103,10 +110,6 @@ static int aes_xts_einit(void *vctx, const unsigned char *key, size_t keylen, const unsigned char *iv, size_t ivlen, const OSSL_PARAM params[]) { -#ifdef AES_XTS_S390X - if (s390x_aes_xts_einit(vctx, key, keylen, iv, ivlen, params) == 1) - return 1; -#endif return aes_xts_init(vctx, key, keylen, iv, ivlen, params, 1); } @@ -114,10 +117,6 @@ static int aes_xts_dinit(void *vctx, const unsigned char *key, size_t keylen, const unsigned char *iv, size_t ivlen, const OSSL_PARAM params[]) { -#ifdef AES_XTS_S390X - if (s390x_aes_xts_dinit(vctx, key, keylen, iv, ivlen, params) == 1) - return 1; -#endif return aes_xts_init(vctx, key, keylen, iv, ivlen, params, 0); } @@ -152,11 +151,6 @@ static void *aes_xts_dupctx(void *vctx) if (!ossl_prov_is_running()) return NULL; -#ifdef AES_XTS_S390X - if (in->plat.s390x.fc) - return s390x_aes_xts_dupctx(vctx); -#endif - if (in->xts.key1 != NULL) { if (in->xts.key1 != &in->ks1) return NULL; @@ -177,20 +171,23 @@ static int aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl, { PROV_AES_XTS_CTX *ctx = (PROV_AES_XTS_CTX *)vctx; -#ifdef AES_XTS_S390X - if (ctx->plat.s390x.fc) - return s390x_aes_xts_cipher(vctx, out, outl, outsize, in, inl); -#endif - if (!ossl_prov_is_running() - || ctx->xts.key1 == NULL - || ctx->xts.key2 == NULL - || !ctx->base.iv_set - || out == NULL + || inl < AES_BLOCK_SIZE || in == NULL - || inl < AES_BLOCK_SIZE) + || out == NULL) return 0; +#ifdef AES_XTS_S390X + if (ctx->plat.s390x.fc) { + if (!ctx->plat.s390x.iv_set || !ctx->plat.s390x.key_set) + return 0; + } else +#endif + { + if (ctx->xts.key1 == NULL || ctx->xts.key2 == NULL) + return 0; + } + /* * Impose a limit of 2^20 blocks per data unit as specified by * IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007 @@ -202,6 +199,11 @@ static int aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl, return 0; } +#ifdef AES_XTS_S390X + if (ctx->plat.s390x.fc) + return s390x_aes_xts_cipher_stream(ctx, out, outl, in, inl); +#endif + if (ctx->stream != NULL) (*ctx->stream)(in, out, inl, ctx->xts.key1, ctx->xts.key2, ctx->base.iv); else if (CRYPTO_xts128_encrypt(&ctx->xts, ctx->base.iv, in, out, inl, diff --git a/providers/implementations/ciphers/cipher_aes_xts.h b/providers/implementations/ciphers/cipher_aes_xts.h index 18dc295e47a..a2421ae9ef1 100644 --- a/providers/implementations/ciphers/cipher_aes_xts.h +++ b/providers/implementations/ciphers/cipher_aes_xts.h @@ -60,6 +60,12 @@ typedef struct prov_aes_xts_ctx_st { } plat; } PROV_AES_XTS_CTX; +#ifdef AES_XTS_S390X +int s390x_aes_xts_cipher_stream(PROV_AES_XTS_CTX *xctx, + unsigned char *out, size_t *outl, + const unsigned char *in, size_t inl); +#endif + const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts(size_t keybits); #endif /* !defined(OSSL_PROVIDERS_IMPLEMENTATIONS_CIPHERS_CIPHER_AES_XTS_H) */ diff --git a/providers/implementations/ciphers/cipher_aes_xts_hw.c b/providers/implementations/ciphers/cipher_aes_xts_hw.c index 6b8c7ab4b4f..b9e21df4fdf 100644 --- a/providers/implementations/ciphers/cipher_aes_xts_hw.c +++ b/providers/implementations/ciphers/cipher_aes_xts_hw.c @@ -276,6 +276,144 @@ static const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts_rv32i() return NULL; } +#elif defined(AES_XTS_S390X) + +int s390x_aes_xts_cipher_stream(PROV_AES_XTS_CTX *xctx, + unsigned char *out, size_t *outl, + const unsigned char *in, size_t inl) +{ + S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km; + unsigned char *param = (unsigned char *)km + xctx->plat.s390x.offset; + unsigned int fc = xctx->plat.s390x.fc; + unsigned char tmp[2][AES_BLOCK_SIZE]; + unsigned char nap_n1[AES_BLOCK_SIZE]; + unsigned char drop[AES_BLOCK_SIZE]; + size_t len_incomplete, len_complete; + + len_incomplete = inl % AES_BLOCK_SIZE; + len_complete = (len_incomplete == 0) ? inl : (inl / AES_BLOCK_SIZE - 1) * AES_BLOCK_SIZE; + + if (len_complete > 0) + s390x_km(in, len_complete, out, fc, param); + if (len_incomplete == 0) + goto out; + + memcpy(tmp, in + len_complete, AES_BLOCK_SIZE + len_incomplete); + /* swap NAP for decrypt */ + if (fc & S390X_DECRYPT) { + memcpy(nap_n1, km->nap, AES_BLOCK_SIZE); + s390x_km(tmp[0], AES_BLOCK_SIZE, drop, fc, param); + } + s390x_km(tmp[0], AES_BLOCK_SIZE, tmp[0], fc, param); + if (fc & S390X_DECRYPT) + memcpy(km->nap, nap_n1, AES_BLOCK_SIZE); + + memcpy(tmp[1] + len_incomplete, tmp[0] + len_incomplete, + AES_BLOCK_SIZE - len_incomplete); + s390x_km(tmp[1], AES_BLOCK_SIZE, out + len_complete, fc, param); + memcpy(out + len_complete + AES_BLOCK_SIZE, tmp[0], len_incomplete); + + /* do not expose temporary data */ + OPENSSL_cleanse(tmp, sizeof(tmp)); +out: + memcpy(xctx->base.iv, km->tweak, AES_BLOCK_SIZE); + *outl = inl; + + return 1; +} + +static int cipher_hw_aes_xts_s390x_initkey(PROV_CIPHER_CTX *ctx, + const unsigned char *key, size_t keylen) +{ + PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)ctx; + S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km; + unsigned int fc, offs; + unsigned int dec = 0; + int supported = 0; + + switch (keylen) { + case 128 / 8 * 2: + fc = S390X_XTS_AES_128_MSA10; + offs = 32; + break; + case 256 / 8 * 2: + fc = S390X_XTS_AES_256_MSA10; + offs = 0; + break; + default: + fc = 0; + break; + } + + if (fc != 0) + supported = (OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(fc)); + if (!supported) { + xctx->plat.s390x.fc = 0; + xctx->plat.s390x.offset = 0; + return 0; + } + + if (xctx->base.iv_set) { + if (xctx->base.ivlen > sizeof(km->tweak)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return 0; + } + memcpy(km->tweak, xctx->base.iv, xctx->base.ivlen); + xctx->plat.s390x.iv_set = 1; + } + + if (key != NULL) { + memcpy(km->key + offs, key, keylen); + xctx->plat.s390x.key_set = 1; + } + + if (xctx->base.enc == 0) + dec = S390X_DECRYPT; + + xctx->plat.s390x.fc = fc | dec; + xctx->plat.s390x.offset = offs; + + memset(km->nap, 0, sizeof(km->nap)); + km->nap[0] = 0x1; + + return 1; +} + +static void cipher_hw_aes_xts_s390x_copyctx(PROV_CIPHER_CTX *dst, + const PROV_CIPHER_CTX *src) +{ + PROV_AES_XTS_CTX *sctx = (PROV_AES_XTS_CTX *)src; + PROV_AES_XTS_CTX *dctx = (PROV_AES_XTS_CTX *)dst; + + *dctx = *sctx; + dctx->xts.key1 = NULL; + dctx->xts.key2 = NULL; +} + +static const PROV_CIPHER_HW aes_xts_s390x = { + cipher_hw_aes_xts_s390x_initkey, + NULL, + cipher_hw_aes_xts_s390x_copyctx +}; + +static const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts_s390x(size_t keybits) +{ + switch (keybits) { + case (128 * 2): + if (OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(S390X_XTS_AES_128_MSA10)) + return &aes_xts_s390x; + break; + case (256 * 2): + if (OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(S390X_XTS_AES_256_MSA10)) + return &aes_xts_s390x; + break; + default: + break; + } + + return NULL; +} + #endif static const PROV_CIPHER_HW aes_generic_xts = { @@ -296,6 +434,8 @@ const PROV_CIPHER_HW *ossl_prov_cipher_hw_aes_xts(size_t keybits) aes_xts_hw = ossl_prov_cipher_hw_aes_xts_rv64i(); #elif defined(OPENSSL_CPUID_OBJ) && defined(__riscv) && __riscv_xlen == 32 aes_xts_hw = ossl_prov_cipher_hw_aes_xts_rv32i(); +#elif defined(AES_XTS_S390X) + aes_xts_hw = ossl_prov_cipher_hw_aes_xts_s390x(keybits); #endif if (aes_xts_hw == NULL) diff --git a/providers/implementations/ciphers/cipher_aes_xts_s390x.inc b/providers/implementations/ciphers/cipher_aes_xts_s390x.inc deleted file mode 100644 index b13d23581c3..00000000000 --- a/providers/implementations/ciphers/cipher_aes_xts_s390x.inc +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the Apache License 2.0 (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 "arch/s390x_arch.h" - -static OSSL_FUNC_cipher_encrypt_init_fn s390x_aes_xts_einit; -static OSSL_FUNC_cipher_decrypt_init_fn s390x_aes_xts_dinit; -static OSSL_FUNC_cipher_cipher_fn s390x_aes_xts_cipher; -static OSSL_FUNC_cipher_dupctx_fn s390x_aes_xts_dupctx; - -static int s390x_aes_xts_init(void *vctx, const unsigned char *key, - size_t keylen, const unsigned char *iv, - size_t ivlen, const OSSL_PARAM params[], - unsigned int dec) -{ - PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx; - S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km; - unsigned int fc, offs; - - switch (xctx->base.keylen) { - case 128 / 8 * 2: - fc = S390X_XTS_AES_128_MSA10; - offs = 32; - break; - case 256 / 8 * 2: - fc = S390X_XTS_AES_256_MSA10; - offs = 0; - break; - default: - goto not_supported; - } - - if (!(OPENSSL_s390xcap_P.km[1] && S390X_CAPBIT(fc))) - goto not_supported; - - if (iv != NULL) { - if (ivlen != xctx->base.ivlen - || ivlen > sizeof(km->tweak)) { - ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); - return 0; - } - memcpy(km->tweak, iv, ivlen); - xctx->plat.s390x.iv_set = 1; - } - - if (key != NULL) { - if (keylen != xctx->base.keylen) { - ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); - return 0; - } - if (!aes_xts_check_keys_differ(key, keylen / 2, !dec)) - return 0; - - memcpy(km->key + offs, key, keylen); - xctx->plat.s390x.key_set = 1; - } - - xctx->plat.s390x.fc = fc | dec; - xctx->plat.s390x.offset = offs; - - memset(km->nap, 0, sizeof(km->nap)); - km->nap[0] = 0x1; - - return aes_xts_set_ctx_params(xctx, params); - -not_supported: - xctx->plat.s390x.fc = 0; - xctx->plat.s390x.offset = 0; - return 0; -} - -static int s390x_aes_xts_einit(void *vctx, const unsigned char *key, - size_t keylen, const unsigned char *iv, - size_t ivlen, const OSSL_PARAM params[]) -{ - return s390x_aes_xts_init(vctx, key, keylen, iv, ivlen, params, 0); -} - -static int s390x_aes_xts_dinit(void *vctx, const unsigned char *key, - size_t keylen, const unsigned char *iv, - size_t ivlen, const OSSL_PARAM params[]) -{ - return s390x_aes_xts_init(vctx, key, keylen, iv, ivlen, params, - S390X_DECRYPT); -} - -static void *s390x_aes_xts_dupctx(void *vctx) -{ - PROV_AES_XTS_CTX *in = (PROV_AES_XTS_CTX *)vctx; - PROV_AES_XTS_CTX *ret = OPENSSL_zalloc(sizeof(*in)); - - if (ret != NULL) - *ret = *in; - - return ret; -} - -static int s390x_aes_xts_cipher(void *vctx, unsigned char *out, size_t *outl, - size_t outsize, const unsigned char *in, - size_t inl) -{ - PROV_AES_XTS_CTX *xctx = (PROV_AES_XTS_CTX *)vctx; - S390X_KM_XTS_PARAMS *km = &xctx->plat.s390x.param.km; - unsigned char *param = (unsigned char *)km + xctx->plat.s390x.offset; - unsigned int fc = xctx->plat.s390x.fc; - unsigned char tmp[2][AES_BLOCK_SIZE]; - unsigned char nap_n1[AES_BLOCK_SIZE]; - unsigned char drop[AES_BLOCK_SIZE]; - size_t len_incomplete, len_complete; - - if (!ossl_prov_is_running() - || inl < AES_BLOCK_SIZE - || in == NULL - || out == NULL - || !xctx->plat.s390x.iv_set - || !xctx->plat.s390x.key_set) - return 0; - - /* - * Impose a limit of 2^20 blocks per data unit as specified by - * IEEE Std 1619-2018. The earlier and obsolete IEEE Std 1619-2007 - * indicated that this was a SHOULD NOT rather than a MUST NOT. - * NIST SP 800-38E mandates the same limit. - */ - if (inl > XTS_MAX_BLOCKS_PER_DATA_UNIT * AES_BLOCK_SIZE) { - ERR_raise(ERR_LIB_PROV, PROV_R_XTS_DATA_UNIT_IS_TOO_LARGE); - return 0; - } - - len_incomplete = inl % AES_BLOCK_SIZE; - len_complete = (len_incomplete == 0) ? inl : - (inl / AES_BLOCK_SIZE - 1) * AES_BLOCK_SIZE; - - if (len_complete > 0) - s390x_km(in, len_complete, out, fc, param); - if (len_incomplete == 0) - goto out; - - memcpy(tmp, in + len_complete, AES_BLOCK_SIZE + len_incomplete); - /* swap NAP for decrypt */ - if (fc & S390X_DECRYPT) { - memcpy(nap_n1, km->nap, AES_BLOCK_SIZE); - s390x_km(tmp[0], AES_BLOCK_SIZE, drop, fc, param); - } - s390x_km(tmp[0], AES_BLOCK_SIZE, tmp[0], fc, param); - if (fc & S390X_DECRYPT) - memcpy(km->nap, nap_n1, AES_BLOCK_SIZE); - - memcpy(tmp[1] + len_incomplete, tmp[0] + len_incomplete, - AES_BLOCK_SIZE - len_incomplete); - s390x_km(tmp[1], AES_BLOCK_SIZE, out + len_complete, fc, param); - memcpy(out + len_complete + AES_BLOCK_SIZE, tmp[0], len_incomplete); - - /* do not expose temporary data */ - OPENSSL_cleanse(tmp, sizeof(tmp)); -out: - memcpy(xctx->base.iv, km->tweak, AES_BLOCK_SIZE); - *outl = inl; - - return 1; -}