--- /dev/null
+/*
+ * 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
IF[{- ($target{perlasm_scheme} // '') eq '31' -}]
$BNASM_s390x=bn_asm.c s390x-mont.S
ELSE
- $BNASM_s390x=asm/s390x.S s390x-mont.S
+ $BNASM_s390x=asm/s390x.S s390x-mont.S bn_s390x.c
ENDIF
$BNDEF_s390x=OPENSSL_BN_ASM_MONT
$BNASM_s390x_ec2m=s390x-gf2m.s
const BIGNUM *a, const BIGNUM *p,
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
{
+#ifdef S390X_MOD_EXP
+ return s390x_mod_exp(r, a, p, m, ctx, m_ctx);
+#else
return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
+#endif
}
static int dh_init(DH *dh)
BN_CTX *ctx);
static int rsa_ossl_init(RSA *rsa);
static int rsa_ossl_finish(RSA *rsa);
+#ifdef S390X_MOD_EXP
+static int rsa_ossl_s390x_mod_exp(BIGNUM *r0, const BIGNUM *i, RSA *rsa,
+ BN_CTX *ctx);
+static RSA_METHOD rsa_pkcs1_ossl_meth = {
+ "OpenSSL PKCS#1 RSA",
+ rsa_ossl_public_encrypt,
+ rsa_ossl_public_decrypt, /* signature verification */
+ rsa_ossl_private_encrypt, /* signing */
+ rsa_ossl_private_decrypt,
+ rsa_ossl_s390x_mod_exp,
+ s390x_mod_exp,
+ rsa_ossl_init,
+ rsa_ossl_finish,
+ RSA_FLAG_FIPS_METHOD, /* flags */
+ NULL,
+ 0, /* rsa_sign */
+ 0, /* rsa_verify */
+ NULL, /* rsa_keygen */
+ NULL /* rsa_multi_prime_keygen */
+};
+#else
static RSA_METHOD rsa_pkcs1_ossl_meth = {
"OpenSSL PKCS#1 RSA",
rsa_ossl_public_encrypt,
NULL, /* rsa_keygen */
NULL /* rsa_multi_prime_keygen */
};
+#endif
static const RSA_METHOD *default_RSA_meth = &rsa_pkcs1_ossl_meth;
BN_MONT_CTX_free(rsa->_method_mod_q);
return 1;
}
+
+#ifdef S390X_MOD_EXP
+static int rsa_ossl_s390x_mod_exp(BIGNUM *r0, const BIGNUM *i, RSA *rsa,
+ BN_CTX *ctx)
+{
+ if (rsa->version != RSA_ASN1_VERSION_MULTI) {
+ if (s390x_crt(r0, i, rsa->p, rsa->q, rsa->dmp1, rsa->dmq1, rsa->iqmp) == 1)
+ return 1;
+ }
+ return rsa_ossl_mod_exp(r0, i, rsa, ctx);
+}
+
+#endif
# ifndef __ASSEMBLER__
+#include "crypto/bn.h"
+
void s390x_kimd(const unsigned char *in, size_t len, unsigned int fc,
void *param);
void s390x_klmd(const unsigned char *in, size_t inlen, unsigned char *out,
#endif
extern struct OPENSSL_s390xcap_st OPENSSL_s390xcap_P;
+#ifdef S390X_MOD_EXP
+# if defined(__GNUC__) && defined(__linux)
+__attribute__ ((visibility("hidden")))
+# endif
+extern int OPENSSL_s390xcex;
+#endif
+
/* Max number of 64-bit words currently returned by STFLE */
# define S390X_STFLE_MAX 3
#include "crypto/ctype.h"
#include "s390x_arch.h"
+#if defined(OPENSSL_SYS_LINUX) && !defined(FIPS_MODULE)
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <asm/zcrypt.h>
+# include <sys/ioctl.h>
+# include <unistd.h>
+#endif
+
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
# if __GLIBC_PREREQ(2, 16)
# include <sys/auxv.h>
#endif
static const char *env;
-static int parse_env(struct OPENSSL_s390xcap_st *cap);
+static int parse_env(struct OPENSSL_s390xcap_st *cap, int *cex);
void OPENSSL_s390x_facilities(void);
void OPENSSL_s390x_functions(void);
struct OPENSSL_s390xcap_st OPENSSL_s390xcap_P;
+#ifdef S390X_MOD_EXP
+static int probe_cex(void);
+int OPENSSL_s390xcex;
+
+#if defined(__GNUC__)
+__attribute__ ((visibility("hidden")))
+#endif
+void OPENSSL_s390x_cleanup(void);
+
+#if defined(__GNUC__)
+__attribute__ ((visibility("hidden")))
+#endif
+void OPENSSL_s390x_cleanup(void)
+{
+ if (OPENSSL_s390xcex != -1) {
+ (void)close(OPENSSL_s390xcex);
+ OPENSSL_s390xcex = -1;
+ }
+}
+#endif
+
#if defined(__GNUC__) && defined(__linux)
__attribute__ ((visibility("hidden")))
#endif
void OPENSSL_cpuid_setup(void)
{
struct OPENSSL_s390xcap_st cap;
+ int cex = 1;
if (OPENSSL_s390xcap_P.stfle[0])
return;
env = getenv("OPENSSL_s390xcap");
if (env != NULL) {
- if (!parse_env(&cap))
+ if (!parse_env(&cap, &cex))
env = NULL;
}
OPENSSL_s390xcap_P.kdsa[0] &= cap.kdsa[0];
OPENSSL_s390xcap_P.kdsa[1] &= cap.kdsa[1];
}
+
+#ifdef S390X_MOD_EXP
+ if (cex == 0) {
+ OPENSSL_s390xcex = -1;
+ } else {
+ OPENSSL_s390xcex = open("/dev/z90crypt", O_RDWR | O_CLOEXEC);
+ if (probe_cex() == 1)
+ OPENSSL_atexit(OPENSSL_s390x_cleanup);
+ }
+#endif
}
-static int parse_env(struct OPENSSL_s390xcap_st *cap)
+#ifdef S390X_MOD_EXP
+static int probe_cex(void)
+{
+ struct ica_rsa_modexpo me;
+ const unsigned char inval[16] = {
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,2
+ };
+ const unsigned char modulus[16] = {
+ 0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,3
+ };
+ unsigned char res[16];
+ int olderrno;
+ int rc = 1;
+
+ me.inputdata = (unsigned char *)inval;
+ me.inputdatalength = sizeof(inval);
+ me.outputdata = (unsigned char *)res;
+ me.outputdatalength = sizeof(res);
+ me.b_key = (unsigned char *)inval;
+ me.n_modulus = (unsigned char *)modulus;
+ olderrno = errno;
+ if (ioctl(OPENSSL_s390xcex, ICARSAMODEXPO, &me) == -1) {
+ (void)close(OPENSSL_s390xcex);
+ OPENSSL_s390xcex = -1;
+ rc = 0;
+ }
+ errno = olderrno;
+ return rc;
+}
+#endif
+
+static int parse_env(struct OPENSSL_s390xcap_st *cap, int *cex)
{
/*-
* CPU model data
else if TOK_CPU(z15)
else if TOK_CPU(z16)
+ /* nocex to deactivate cex support */
+ else if (sscanf(tok_begin, " %" STR(LEN) "s %" STR(LEN) "s ",
+ tok[0], tok[1]) == 1
+ && !strcmp(tok[0], "nocex")) {
+ *cex = 0;
+ }
+
/* whitespace(ignored) or invalid tokens */
else {
while (*tok_begin != '\0') {
OPENSSL_s390xcap="<tok1>;<tok2>;..."
-There are three types of tokens:
+There are four types of tokens:
=over 4
part of the environment variable's mask corresponding to the stfle
instruction is set to the specified 192-bit mask.
+=item nocex
+
+Deactivate modular exponentiation and CRT operation offloading to
+Crypto Express Adapters.
+
=back
The 64-bit masks are specified in hexadecimal notation. The 0x prefix is
const BIGNUM *to_mod, BN_CTX *ctx,
unsigned char *buf, int num);
+#if defined(OPENSSL_SYS_LINUX) && !defined(FIPS_MODULE) && defined (__s390x__)
+# define S390X_MOD_EXP
+#endif
+
+int s390x_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_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);
+
#endif