openssl/crypto/bn/bn_s390x.c
Juergen Christ 79040cf29e S390x: Support ME and CRT offloading
S390x has to ability to offload modular exponentiation and CRT operations to
Crypto Express Adapters.  This possible performance optimization was not yet
used by OpenSSL.  Add support for offloading and implement an optimized
version of RSA and DH with it.

The environment variable OPENSSL_s390xcap now recognizes the token "nocex" to
prevent offloading.

Signed-off-by: Juergen Christ <jchrist@linux.ibm.com>

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20113)
2023-02-08 16:53:12 +01:00

144 lines
4.2 KiB
C

/*
* Copyright 2023-2023 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 "crypto/bn.h"
#include "crypto/s390x_arch.h"
#ifdef S390X_MOD_EXP
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <asm/zcrypt.h>
# include <sys/ioctl.h>
# include <unistd.h>
# include <errno.h>
static int s390x_mod_exp_hw(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m)
{
struct ica_rsa_modexpo me;
unsigned char *buffer;
size_t size;
int res = 0;
if (OPENSSL_s390xcex == -1)
return 0;
size = BN_num_bytes(m);
buffer = OPENSSL_zalloc(4 * size);
if (buffer == NULL)
return 0;
me.inputdata = buffer;
me.inputdatalength = size;
me.outputdata = buffer + size;
me.outputdatalength = size;
me.b_key = buffer + 2 * size;
me.n_modulus = buffer + 3 * size;
if (BN_bn2binpad(a, me.inputdata, size) == -1
|| BN_bn2binpad(p, me.b_key, size) == -1
|| BN_bn2binpad(m, me.n_modulus, size) == -1)
goto dealloc;
if (ioctl(OPENSSL_s390xcex, ICARSAMODEXPO, &me) != -1) {
if (BN_bin2bn(me.outputdata, size, r) != NULL)
res = 1;
} else if (errno == EBADF) {
/*-
* In this cases, someone (e.g. a sandbox) closed the fd.
* Make sure to not further use this hardware acceleration.
*/
OPENSSL_s390xcex = -1;
}
dealloc:
OPENSSL_clear_free(buffer, 4 * size);
return res;
}
int s390x_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
{
if (s390x_mod_exp_hw(r, a, p, m) == 1)
return 1;
return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
}
int s390x_crt(BIGNUM *r, const BIGNUM *i, const BIGNUM *p, const BIGNUM *q,
const BIGNUM *dmp, const BIGNUM *dmq, const BIGNUM *iqmp)
{
struct ica_rsa_modexpo_crt crt;
unsigned char *buffer, *part;
size_t size, plen, qlen;
int res = 0;
if (OPENSSL_s390xcex == -1)
return 0;
/*-
* Hardware-accelerated CRT can only deal with p>q. Fall back to
* software in the (hopefully rare) other cases.
*/
if (BN_ucmp(p, q) != 1)
return 0;
plen = BN_num_bytes(p);
qlen = BN_num_bytes(q);
size = (plen > qlen ? plen : qlen);
buffer = OPENSSL_zalloc(9 * size + 24);
if (buffer == NULL)
return 0;
part = buffer;
crt.inputdata = part;
crt.inputdatalength = 2 * size;
part += 2 * size;
crt.outputdata = part;
crt.outputdatalength = 2 * size;
part += 2 * size;
crt.bp_key = part;
part += size + 8;
crt.bq_key = part;
part += size;
crt.np_prime = part;
part += size + 8;
crt.nq_prime = part;
part += size;
crt.u_mult_inv = part;
if (BN_bn2binpad(i, crt.inputdata, crt.inputdatalength) == -1
|| BN_bn2binpad(p, crt.np_prime, size + 8) == -1
|| BN_bn2binpad(q, crt.nq_prime, size) == -1
|| BN_bn2binpad(dmp, crt.bp_key, size + 8) == -1
|| BN_bn2binpad(dmq, crt.bq_key, size) == -1
|| BN_bn2binpad(iqmp, crt.u_mult_inv, size + 8) == -1)
goto dealloc;
if (ioctl(OPENSSL_s390xcex, ICARSACRT, &crt) != -1) {
if (BN_bin2bn(crt.outputdata, crt.outputdatalength, r) != NULL)
res = 1;
} else if (errno == EBADF) {
/*-
* In this cases, someone (e.g. a sandbox) closed the fd.
* Make sure to not further use this hardware acceleration.
*/
OPENSSL_s390xcex = -1;
}
dealloc:
OPENSSL_clear_free(buffer, 9 * size + 24);
return res;
}
#else
int s390x_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
{
return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
}
int s390x_crt(BIGNUM *r, const BIGNUM *i, const BIGNUM *p, const BIGNUM *q,
const BIGNUM *dmp, const BIGNUM *dmq, const BIGNUM *iqmp)
{
return 0;
}
#endif