summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2020-11-20 17:45:48 -0800
committerBenjamin Kaduk <kaduk@mit.edu>2021-01-05 15:16:16 -0800
commit7fd1ca723a06739e76a17d1065ac94bcfcfc4f9f (patch)
tree357317a138c05d6534bb5bab997249468b6b67dd
parentb39c215decf6e68c28cb64dcfaf5ae5a7e8d35b4 (diff)
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)
-rw-r--r--engines/e_devcrypto.c72
1 files changed, 60 insertions, 12 deletions
diff --git a/engines/e_devcrypto.c b/engines/e_devcrypto.c
index 6715ef408e..7f3768d36c 100644
--- a/engines/e_devcrypto.c
+++ b/engines/e_devcrypto.c
@@ -35,6 +35,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
* saner... why re-open /dev/crypto for every session?
@@ -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)