/*
- * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2017-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
* https://www.openssl.org/source/license.html
*/
-#include "../e_os.h"
+/* We need to use some deprecated APIs */
+#define OPENSSL_SUPPRESS_DEPRECATED
+
+#include "internal/e_os.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <openssl/err.h>
#include <openssl/engine.h>
#include <openssl/objects.h>
-#include <crypto/cryptodev.h>
+#include "crypto/cryptodev.h"
+#include "internal/nelem.h"
/* #define ENGINE_DEVCRYPTO_DEBUG */
#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
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) {
- SYSerr("ioctl", errno);
+ 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;
}
*****/
struct cipher_ctx {
- struct session_op sess;
+ session_op_t sess;
int op; /* COP_ENCRYPT or COP_DECRYPT */
unsigned long mode; /* EVP_CIPH_*_MODE */
struct cipher_ctx *cipher_ctx =
(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));
+ get_cipher_data(EVP_CIPHER_CTX_get_nid(ctx));
+ int ret;
/* cleanup a previous session */
if (cipher_ctx->sess.ses != 0 &&
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) {
- SYSerr("ioctl", errno);
+#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;
}
#if !defined(COP_FLAG_WRITE_IV)
cryp.flags = 0;
- ivlen = EVP_CIPHER_CTX_iv_length(ctx);
+ ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);
if (ivlen > 0)
switch (cipher_ctx->mode) {
case EVP_CIPH_CBC_MODE:
assert(inl >= ivlen);
- if (!EVP_CIPHER_CTX_encrypting(ctx)) {
+ if (!EVP_CIPHER_CTX_is_encrypting(ctx)) {
ivptr = in + inl - ivlen;
memcpy(saved_iv, ivptr, ivlen);
}
#endif
if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) {
- SYSerr("ioctl", errno);
+ ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");
return 0;
}
switch (cipher_ctx->mode) {
case EVP_CIPH_CBC_MODE:
assert(inl >= ivlen);
- if (EVP_CIPHER_CTX_encrypting(ctx))
+ if (EVP_CIPHER_CTX_is_encrypting(ctx))
ivptr = out + inl - ivlen;
else
ivptr = saved_iv;
}
/* full blocks */
- if (inl > (unsigned int) cipher_ctx->blocksize) {
+ if (inl > cipher_ctx->blocksize) {
nblocks = inl/cipher_ctx->blocksize;
len = nblocks * cipher_ctx->blocksize;
if (cipher_do_cipher(ctx, out, in, len) < 1)
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
*/
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;
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;
EVP = EVP_get_cipherbyname(name);
if (EVP == NULL)
fprintf(stderr, "devcrypto: unknown cipher %s\n", name);
- else if ((i = find_cipher_data_index(EVP_CIPHER_nid(EVP))) != (size_t)-1)
+ else if ((i = find_cipher_data_index(EVP_CIPHER_get_nid(EVP))) != (size_t)-1)
cipher_list[i] = 1;
else
fprintf(stderr, "devcrypto: cipher %s not available\n", name);
fprintf (stderr, "Cipher %s, NID=%d, /dev/crypto info: id=%d, ",
name ? name : "unknown", cipher_data[i].nid,
cipher_data[i].devcryptoid);
- if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION ) {
+ if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION) {
fprintf (stderr, "CIOCGSESSION (session open call) failed\n");
continue;
}
*****/
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];
static int digest_init(EVP_MD_CTX *ctx)
{
struct digest_ctx *digest_ctx =
- (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
+ (struct digest_ctx *)EVP_MD_CTX_get0_md_data(ctx);
const struct digest_data_st *digest_d =
- get_digest_data(EVP_MD_CTX_type(ctx));
+ get_digest_data(EVP_MD_CTX_get_type(ctx));
digest_ctx->init_called = 1;
memset(&digest_ctx->sess, 0, sizeof(digest_ctx->sess));
digest_ctx->sess.mac = digest_d->devcryptoid;
if (ioctl(cfd, CIOCGSESSION, &digest_ctx->sess) < 0) {
- SYSerr("ioctl", errno);
+ ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");
return 0;
}
return 1;
static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
{
struct digest_ctx *digest_ctx =
- (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
+ (struct digest_ctx *)EVP_MD_CTX_get0_md_data(ctx);
if (count == 0)
return 1;
return 1;
}
- SYSerr("ioctl", errno);
+ ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");
return 0;
}
static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
{
struct digest_ctx *digest_ctx =
- (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
+ (struct digest_ctx *)EVP_MD_CTX_get0_md_data(ctx);
if (md == NULL || digest_ctx == NULL)
return 0;
if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
- memcpy(md, digest_ctx->digest_res, EVP_MD_CTX_size(ctx));
+ memcpy(md, digest_ctx->digest_res, EVP_MD_CTX_get_size(ctx));
} else if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {
- SYSerr("ioctl", errno);
+ ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");
return 0;
}
static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)
{
struct digest_ctx *digest_from =
- (struct digest_ctx *)EVP_MD_CTX_md_data(from);
+ (struct digest_ctx *)EVP_MD_CTX_get0_md_data(from);
struct digest_ctx *digest_to =
- (struct digest_ctx *)EVP_MD_CTX_md_data(to);
+ (struct digest_ctx *)EVP_MD_CTX_get0_md_data(to);
struct cphash_op cphash;
if (digest_from == NULL || digest_from->init_called != 1)
return 1;
if (!digest_init(to)) {
- SYSerr("ioctl", errno);
+ ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");
return 0;
}
cphash.src_ses = digest_from->sess.ses;
cphash.dst_ses = digest_to->sess.ses;
if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
- SYSerr("ioctl", errno);
+ ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");
return 0;
}
return 1;
static int digest_cleanup(EVP_MD_CTX *ctx)
{
struct digest_ctx *digest_ctx =
- (struct digest_ctx *)EVP_MD_CTX_md_data(ctx);
+ (struct digest_ctx *)EVP_MD_CTX_get0_md_data(ctx);
if (digest_ctx == NULL)
return 1;
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
EVP = EVP_get_digestbyname(name);
if (EVP == NULL)
fprintf(stderr, "devcrypto: unknown digest %s\n", name);
- else if ((i = find_digest_data_index(EVP_MD_type(EVP))) != (size_t)-1)
+ else if ((i = find_digest_data_index(EVP_MD_get_type(EVP))) != (size_t)-1)
digest_list[i] = 1;
else
fprintf(stderr, "devcrypto: digest %s not available\n", name);
#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 ("
{
int *new_list;
switch (cmd) {
-#ifdef CIOCGSESSINFO
+#if defined(CIOCGSESSINFO) || defined(CIOCGSESSION2)
case DEVCRYPTO_CMD_USE_SOFTDRIVERS:
switch (i) {
case DEVCRYPTO_REQUIRE_ACCELERATED:
#endif
rebuild_known_cipher_nids(e);
return 1;
-#endif /* CIOCGSESSINFO */
+#endif /* CIOCGSESSINFO || CIOCGSESSION2 */
case DEVCRYPTO_CMD_CIPHERS:
if (p == NULL)
return 1;
- if (strcasecmp((const char *)p, "ALL") == 0) {
+ if (OPENSSL_strcasecmp((const char *)p, "ALL") == 0) {
devcrypto_select_all_ciphers(selected_ciphers);
- } else if (strcasecmp((const char*)p, "NONE") == 0) {
+ } else if (OPENSSL_strcasecmp((const char*)p, "NONE") == 0) {
memset(selected_ciphers, 0, sizeof(selected_ciphers));
} else {
new_list=OPENSSL_zalloc(sizeof(selected_ciphers));
case DEVCRYPTO_CMD_DIGESTS:
if (p == NULL)
return 1;
- if (strcasecmp((const char *)p, "ALL") == 0) {
+ if (OPENSSL_strcasecmp((const char *)p, "ALL") == 0) {
devcrypto_select_all_digests(selected_digests);
- } else if (strcasecmp((const char*)p, "NONE") == 0) {
+ } else if (OPENSSL_strcasecmp((const char*)p, "NONE") == 0) {
memset(selected_digests, 0, sizeof(selected_digests));
} else {
new_list=OPENSSL_zalloc(sizeof(selected_digests));
*/
static int open_devcrypto(void)
{
+ int fd;
+
if (cfd >= 0)
return 1;
- if ((cfd = open("/dev/crypto", O_RDWR, 0)) < 0) {
+ if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
#ifndef ENGINE_DEVCRYPTO_DEBUG
- if (errno != ENOENT)
+ if (errno != ENOENT && errno != ENXIO)
#endif
fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
return 0;
}
+#ifdef CRIOGET
+ if (ioctl(fd, CRIOGET, &cfd) < 0) {
+ fprintf(stderr, "Could not create crypto fd: %s\n", strerror(errno));
+ close(fd);
+ cfd = -1;
+ return 0;
+ }
+ close(fd);
+#else
+ cfd = fd;
+#endif
+
return 1;
}
* /Richard Levitte, 2017-05-11
*/
#if 0
-# ifndef OPENSSL_NO_RSA
&& ENGINE_set_RSA(e, devcrypto_rsa)
-# endif
# ifndef OPENSSL_NO_DSA
&& ENGINE_set_DSA(e, devcrypto_dsa)
# endif
return;
}
+ ERR_set_mark();
ENGINE_add(e);
+ /*
+ * If the "add" worked, it gets a structural reference. So either way, we
+ * release our just-created reference.
+ */
ENGINE_free(e); /* Loose our local reference */
- ERR_clear_error();
+ /*
+ * If the "add" didn't work, it was probably a conflict because it was
+ * already added (eg. someone calling ENGINE_load_blah then calling
+ * ENGINE_load_builtin_engines() perhaps).
+ */
+ ERR_pop_to_mark();
}
#else