Support session information on FreeBSD.

FreeBSD's /dev/crypto does not provide a CIOCGSESSINFO ioctl, but it
does provide other ioctls that can be used to provide similar
functionality.

First, FreeBSD's /dev/crypto defines a CIOCGESSION2 ioctl which accepts
a 'struct session2_op'.  This structure extends 'struct session_op'
with a 'crid' member which can be used to either request an individual
driver by id, or a class of drivers via flags.

To determine if the available drivers for a given algorithm are
accelerated or not, use CIOCGESSION2 to first attempt to create an
accelerated (hardware) session.  If that fails, fall back to
attempting a software session.  In addition, when requesting a new
cipher session, use the current setting of the 'use_softdrivers' flag
to determine the value assigned to 'crid' when invoking CIOCGSESSION2.

Finally, use the returned 'crid' value from CIOCGSESSION2 to look up
the name of the associated driver via the CIOCFINDDEV ioctl.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Ben Kaduk <kaduk@mit.edu>
(Merged from https://github.com/openssl/openssl/pull/13468)
This commit is contained in:
John Baldwin 2020-11-20 17:45:48 -08:00 committed by Benjamin Kaduk
parent b39c215dec
commit 7fd1ca723a

View File

@ -34,6 +34,16 @@
#define engine_devcrypto_id "devcrypto"
/*
* Use session2_op on FreeBSD which permits requesting specific
* drivers or classes of drivers at session creation time.
*/
#ifdef CIOCGSESSION2
typedef struct session2_op session_op_t;
#else
typedef struct session_op session_op_t;
#endif
/*
* ONE global file descriptor for all sessions. This allows operations
* such as digest session data copying (see digest_copy()), but is also
@ -73,12 +83,12 @@ struct driver_info_st {
void engine_load_devcrypto_int(void);
#endif
static int clean_devcrypto_session(struct session_op *sess) {
static int clean_devcrypto_session(session_op_t *sess) {
if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) {
ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");
return 0;
}
memset(sess, 0, sizeof(struct session_op));
memset(sess, 0, sizeof(*sess));
return 1;
}
@ -93,7 +103,7 @@ static int clean_devcrypto_session(struct session_op *sess) {
*****/
struct cipher_ctx {
struct session_op sess;
session_op_t sess;
int op; /* COP_ENCRYPT or COP_DECRYPT */
unsigned long mode; /* EVP_CIPH_*_MODE */
@ -198,6 +208,7 @@ static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
(struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
const struct cipher_data_st *cipher_d =
get_cipher_data(EVP_CIPHER_CTX_nid(ctx));
int ret;
/* cleanup a previous session */
if (cipher_ctx->sess.ses != 0 &&
@ -210,7 +221,15 @@ static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
cipher_ctx->op = enc ? COP_ENCRYPT : COP_DECRYPT;
cipher_ctx->mode = cipher_d->flags & EVP_CIPH_MODE;
cipher_ctx->blocksize = cipher_d->blocksize;
if (ioctl(cfd, CIOCGSESSION, &cipher_ctx->sess) < 0) {
#ifdef CIOCGSESSION2
cipher_ctx->sess.crid = (use_softdrivers == DEVCRYPTO_USE_SOFTWARE) ?
CRYPTO_FLAG_SOFTWARE | CRYPTO_FLAG_HARDWARE :
CRYPTO_FLAG_HARDWARE;
ret = ioctl(cfd, CIOCGSESSION2, &cipher_ctx->sess);
#else
ret = ioctl(cfd, CIOCGSESSION, &cipher_ctx->sess);
#endif
if (ret < 0) {
ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");
return 0;
}
@ -406,9 +425,12 @@ static int devcrypto_test_cipher(size_t cipher_data_index)
static void prepare_cipher_methods(void)
{
size_t i;
struct session_op sess;
session_op_t sess;
unsigned long cipher_mode;
#ifdef CIOCGSESSINFO
#ifdef CIOCGSESSION2
struct crypt_find_op fop;
enum devcrypto_accelerated_t accelerated;
#elif defined(CIOCGSESSINFO)
struct session_info_op siop;
#endif
@ -426,10 +448,29 @@ static void prepare_cipher_methods(void)
*/
sess.cipher = cipher_data[i].devcryptoid;
sess.keylen = cipher_data[i].keylen;
#ifdef CIOCGSESSION2
/*
* When using CIOCGSESSION2, first try to allocate a hardware
* ("accelerated") session. If that fails, fall back to
* allocating a software session.
*/
sess.crid = CRYPTO_FLAG_HARDWARE;
if (ioctl(cfd, CIOCGSESSION2, &sess) == 0) {
accelerated = DEVCRYPTO_ACCELERATED;
} else {
sess.crid = CRYPTO_FLAG_SOFTWARE;
if (ioctl(cfd, CIOCGSESSION2, &sess) < 0) {
cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
continue;
}
accelerated = DEVCRYPTO_NOT_ACCELERATED;
}
#else
if (ioctl(cfd, CIOCGSESSION, &sess) < 0) {
cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
continue;
}
#endif
cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE;
@ -460,7 +501,14 @@ static void prepare_cipher_methods(void)
known_cipher_methods[i] = NULL;
} else {
cipher_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
#ifdef CIOCGSESSINFO
#ifdef CIOCGSESSION2
cipher_driver_info[i].accelerated = accelerated;
fop.crid = sess.crid;
if (ioctl(cfd, CIOCFINDDEV, &fop) == 0) {
cipher_driver_info[i].driver_name =
OPENSSL_strndup(fop.name, sizeof(fop.name));
}
#elif defined(CIOCGSESSINFO)
siop.ses = sess.ses;
if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
@ -624,7 +672,7 @@ static void dump_cipher_info(void)
*****/
struct digest_ctx {
struct session_op sess;
session_op_t sess;
/* This signals that the init function was called, not that it succeeded. */
int init_called;
unsigned char digest_res[HASH_MAX_LEN];
@ -843,7 +891,7 @@ static void rebuild_known_digest_nids(ENGINE *e)
static void prepare_digest_methods(void)
{
size_t i;
struct session_op sess1, sess2;
session_op_t sess1, sess2;
#ifdef CIOCGSESSINFO
struct session_info_op siop;
#endif
@ -1051,7 +1099,7 @@ static void dump_digest_info(void)
#define DEVCRYPTO_CMD_DUMP_INFO (ENGINE_CMD_BASE + 3)
static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
#ifdef CIOCGSESSINFO
#if defined(CIOCGSESSINFO) || defined(CIOCGSESSION2)
{DEVCRYPTO_CMD_USE_SOFTDRIVERS,
"USE_SOFTDRIVERS",
"specifies whether to use software (not accelerated) drivers ("
@ -1087,7 +1135,7 @@ static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
{
int *new_list;
switch (cmd) {
#ifdef CIOCGSESSINFO
#if defined(CIOCGSESSINFO) || defined(CIOCGSESSION2)
case DEVCRYPTO_CMD_USE_SOFTDRIVERS:
switch (i) {
case DEVCRYPTO_REQUIRE_ACCELERATED:
@ -1106,7 +1154,7 @@ static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
#endif
rebuild_known_cipher_nids(e);
return 1;
#endif /* CIOCGSESSINFO */
#endif /* CIOCGSESSINFO || CIOCGSESSION2 */
case DEVCRYPTO_CMD_CIPHERS:
if (p == NULL)