Path: blob/main/crypto/openssl/engines/e_devcrypto.c
104653 views
/*1* Copyright 2017-2023 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/* We need to use some deprecated APIs */10#define OPENSSL_SUPPRESS_DEPRECATED1112#include "internal/e_os.h"13#include <string.h>14#include <sys/types.h>15#include <sys/stat.h>16#include <fcntl.h>17#include <sys/ioctl.h>18#include <unistd.h>19#include <assert.h>2021#include <openssl/conf.h>22#include <openssl/evp.h>23#include <openssl/err.h>24#include <openssl/engine.h>25#include <openssl/objects.h>26#include "crypto/cryptodev.h"27#include "internal/nelem.h"2829/* #define ENGINE_DEVCRYPTO_DEBUG */3031#if CRYPTO_ALGORITHM_MIN < CRYPTO_ALGORITHM_MAX32#define CHECK_BSD_STYLE_MACROS33#endif3435#define engine_devcrypto_id "devcrypto"3637/*38* Use session2_op on FreeBSD which permits requesting specific39* drivers or classes of drivers at session creation time.40*/41#ifdef CIOCGSESSION242typedef struct session2_op session_op_t;43#else44typedef struct session_op session_op_t;45#endif4647/*48* ONE global file descriptor for all sessions. This allows operations49* such as digest session data copying (see digest_copy()), but is also50* saner... why re-open /dev/crypto for every session?51*/52static int cfd = -1;53#define DEVCRYPTO_REQUIRE_ACCELERATED 0 /* require confirmation of acceleration */54#define DEVCRYPTO_USE_SOFTWARE 1 /* allow software drivers */55#define DEVCRYPTO_REJECT_SOFTWARE 2 /* only disallow confirmed software drivers */5657#define DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS DEVCRYPTO_REJECT_SOFTWARE58static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS;5960/*61* cipher/digest status & acceleration definitions62* Make sure the defaults are set to 063*/64struct driver_info_st {65enum devcrypto_status_t {66DEVCRYPTO_STATUS_FAILURE = -3, /* unusable for other reason */67DEVCRYPTO_STATUS_NO_CIOCCPHASH = -2, /* hash state copy not supported */68DEVCRYPTO_STATUS_NO_CIOCGSESSION = -1, /* session open failed */69DEVCRYPTO_STATUS_UNKNOWN = 0, /* not tested yet */70DEVCRYPTO_STATUS_USABLE = 1 /* algo can be used */71} status;7273enum devcrypto_accelerated_t {74DEVCRYPTO_NOT_ACCELERATED = -1, /* software implemented */75DEVCRYPTO_ACCELERATION_UNKNOWN = 0, /* acceleration support unknown */76DEVCRYPTO_ACCELERATED = 1 /* hardware accelerated */77} accelerated;7879char *driver_name;80};8182#ifdef OPENSSL_NO_DYNAMIC_ENGINE83void engine_load_devcrypto_int(void);84#endif8586static int clean_devcrypto_session(session_op_t *sess)87{88if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) {89ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");90return 0;91}92memset(sess, 0, sizeof(*sess));93return 1;94}9596/******************************************************************************97*98* Ciphers99*100* Because they all do the same basic operation, we have only one set of101* method functions for them all to share, and a mapping table between102* NIDs and cryptodev IDs, with all the necessary size data.103*104*****/105106struct cipher_ctx {107session_op_t sess;108int op; /* COP_ENCRYPT or COP_DECRYPT */109unsigned long mode; /* EVP_CIPH_*_MODE */110111/* to handle ctr mode being a stream cipher */112unsigned char partial[EVP_MAX_BLOCK_LENGTH];113unsigned int blocksize, num;114};115116static const struct cipher_data_st {117int nid;118int blocksize;119int keylen;120int ivlen;121int flags;122int devcryptoid;123} cipher_data[] = {124#ifndef OPENSSL_NO_DES125{ NID_des_cbc, 8, 8, 8, EVP_CIPH_CBC_MODE, CRYPTO_DES_CBC },126{ NID_des_ede3_cbc, 8, 24, 8, EVP_CIPH_CBC_MODE, CRYPTO_3DES_CBC },127#endif128#ifndef OPENSSL_NO_BF129{ NID_bf_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_BLF_CBC },130#endif131#ifndef OPENSSL_NO_CAST132{ NID_cast5_cbc, 8, 16, 8, EVP_CIPH_CBC_MODE, CRYPTO_CAST_CBC },133#endif134{ NID_aes_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },135{ NID_aes_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },136{ NID_aes_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE, CRYPTO_AES_CBC },137#ifndef OPENSSL_NO_RC4138{ NID_rc4, 1, 16, 0, EVP_CIPH_STREAM_CIPHER, CRYPTO_ARC4 },139#endif140#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_CTR)141{ NID_aes_128_ctr, 16, 128 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },142{ NID_aes_192_ctr, 16, 192 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },143{ NID_aes_256_ctr, 16, 256 / 8, 16, EVP_CIPH_CTR_MODE, CRYPTO_AES_CTR },144#endif145#if 0 /* Not yet supported */146{ NID_aes_128_xts, 16, 128 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },147{ NID_aes_256_xts, 16, 256 / 8 * 2, 16, EVP_CIPH_XTS_MODE, CRYPTO_AES_XTS },148#endif149#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_AES_ECB)150{ NID_aes_128_ecb, 16, 128 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },151{ NID_aes_192_ecb, 16, 192 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },152{ NID_aes_256_ecb, 16, 256 / 8, 0, EVP_CIPH_ECB_MODE, CRYPTO_AES_ECB },153#endif154#if 0 /* Not yet supported */155{ NID_aes_128_gcm, 16, 128 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },156{ NID_aes_192_gcm, 16, 192 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },157{ NID_aes_256_gcm, 16, 256 / 8, 16, EVP_CIPH_GCM_MODE, CRYPTO_AES_GCM },158#endif159#ifndef OPENSSL_NO_CAMELLIA160{ NID_camellia_128_cbc, 16, 128 / 8, 16, EVP_CIPH_CBC_MODE,161CRYPTO_CAMELLIA_CBC },162{ NID_camellia_192_cbc, 16, 192 / 8, 16, EVP_CIPH_CBC_MODE,163CRYPTO_CAMELLIA_CBC },164{ NID_camellia_256_cbc, 16, 256 / 8, 16, EVP_CIPH_CBC_MODE,165CRYPTO_CAMELLIA_CBC },166#endif167};168169static size_t find_cipher_data_index(int nid)170{171size_t i;172173for (i = 0; i < OSSL_NELEM(cipher_data); i++)174if (nid == cipher_data[i].nid)175return i;176return (size_t)-1;177}178179static size_t get_cipher_data_index(int nid)180{181size_t i = find_cipher_data_index(nid);182183if (i != (size_t)-1)184return i;185186/*187* Code further down must make sure that only NIDs in the table above188* are used. If any other NID reaches this function, there's a grave189* coding error further down.190*/191assert("Code that never should be reached" == NULL);192return -1;193}194195static const struct cipher_data_st *get_cipher_data(int nid)196{197return &cipher_data[get_cipher_data_index(nid)];198}199200/*201* Following are the three necessary functions to map OpenSSL functionality202* with cryptodev.203*/204205static int cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,206const unsigned char *iv, int enc)207{208struct cipher_ctx *cipher_ctx = (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);209const struct cipher_data_st *cipher_d = get_cipher_data(EVP_CIPHER_CTX_get_nid(ctx));210int ret;211212/* cleanup a previous session */213if (cipher_ctx->sess.ses != 0 && clean_devcrypto_session(&cipher_ctx->sess) == 0)214return 0;215216cipher_ctx->sess.cipher = cipher_d->devcryptoid;217cipher_ctx->sess.keylen = cipher_d->keylen;218cipher_ctx->sess.key = (void *)key;219cipher_ctx->op = enc ? COP_ENCRYPT : COP_DECRYPT;220cipher_ctx->mode = cipher_d->flags & EVP_CIPH_MODE;221cipher_ctx->blocksize = cipher_d->blocksize;222#ifdef CIOCGSESSION2223cipher_ctx->sess.crid = (use_softdrivers == DEVCRYPTO_USE_SOFTWARE) ? CRYPTO_FLAG_SOFTWARE | CRYPTO_FLAG_HARDWARE : CRYPTO_FLAG_HARDWARE;224ret = ioctl(cfd, CIOCGSESSION2, &cipher_ctx->sess);225#else226ret = ioctl(cfd, CIOCGSESSION, &cipher_ctx->sess);227#endif228if (ret < 0) {229ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");230return 0;231}232233return 1;234}235236static int cipher_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,237const unsigned char *in, size_t inl)238{239struct cipher_ctx *cipher_ctx = (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);240struct crypt_op cryp;241unsigned char *iv = EVP_CIPHER_CTX_iv_noconst(ctx);242#if !defined(COP_FLAG_WRITE_IV)243unsigned char saved_iv[EVP_MAX_IV_LENGTH];244const unsigned char *ivptr;245size_t nblocks, ivlen;246#endif247248memset(&cryp, 0, sizeof(cryp));249cryp.ses = cipher_ctx->sess.ses;250cryp.len = inl;251cryp.src = (void *)in;252cryp.dst = (void *)out;253cryp.iv = (void *)iv;254cryp.op = cipher_ctx->op;255#if !defined(COP_FLAG_WRITE_IV)256cryp.flags = 0;257258ivlen = EVP_CIPHER_CTX_get_iv_length(ctx);259if (ivlen > 0)260switch (cipher_ctx->mode) {261case EVP_CIPH_CBC_MODE:262assert(inl >= ivlen);263if (!EVP_CIPHER_CTX_is_encrypting(ctx)) {264ivptr = in + inl - ivlen;265memcpy(saved_iv, ivptr, ivlen);266}267break;268269case EVP_CIPH_CTR_MODE:270break;271272default: /* should not happen */273return 0;274}275#else276cryp.flags = COP_FLAG_WRITE_IV;277#endif278279if (ioctl(cfd, CIOCCRYPT, &cryp) < 0) {280ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");281return 0;282}283284#if !defined(COP_FLAG_WRITE_IV)285if (ivlen > 0)286switch (cipher_ctx->mode) {287case EVP_CIPH_CBC_MODE:288assert(inl >= ivlen);289if (EVP_CIPHER_CTX_is_encrypting(ctx))290ivptr = out + inl - ivlen;291else292ivptr = saved_iv;293294memcpy(iv, ivptr, ivlen);295break;296297case EVP_CIPH_CTR_MODE:298nblocks = (inl + cipher_ctx->blocksize - 1)299/ cipher_ctx->blocksize;300do {301ivlen--;302nblocks += iv[ivlen];303iv[ivlen] = (uint8_t)nblocks;304nblocks >>= 8;305} while (ivlen);306break;307308default: /* should not happen */309return 0;310}311#endif312313return 1;314}315316static int ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,317const unsigned char *in, size_t inl)318{319struct cipher_ctx *cipher_ctx = (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);320size_t nblocks, len;321322/* initial partial block */323while (cipher_ctx->num && inl) {324(*out++) = *(in++) ^ cipher_ctx->partial[cipher_ctx->num];325--inl;326cipher_ctx->num = (cipher_ctx->num + 1) % cipher_ctx->blocksize;327}328329/* full blocks */330if (inl > cipher_ctx->blocksize) {331nblocks = inl / cipher_ctx->blocksize;332len = nblocks * cipher_ctx->blocksize;333if (cipher_do_cipher(ctx, out, in, len) < 1)334return 0;335inl -= len;336out += len;337in += len;338}339340/* final partial block */341if (inl) {342memset(cipher_ctx->partial, 0, cipher_ctx->blocksize);343if (cipher_do_cipher(ctx, cipher_ctx->partial, cipher_ctx->partial,344cipher_ctx->blocksize)345< 1)346return 0;347while (inl--) {348out[cipher_ctx->num] = in[cipher_ctx->num]349^ cipher_ctx->partial[cipher_ctx->num];350cipher_ctx->num++;351}352}353354return 1;355}356357static int cipher_ctrl(EVP_CIPHER_CTX *ctx, int type, int p1, void *p2)358{359struct cipher_ctx *cipher_ctx = (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);360EVP_CIPHER_CTX *to_ctx = (EVP_CIPHER_CTX *)p2;361struct cipher_ctx *to_cipher_ctx;362363switch (type) {364365case EVP_CTRL_COPY:366if (cipher_ctx == NULL)367return 1;368/* when copying the context, a new session needs to be initialized */369to_cipher_ctx = (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(to_ctx);370memset(&to_cipher_ctx->sess, 0, sizeof(to_cipher_ctx->sess));371return cipher_init(to_ctx, (void *)cipher_ctx->sess.key, EVP_CIPHER_CTX_iv(ctx),372(cipher_ctx->op == COP_ENCRYPT));373374case EVP_CTRL_INIT:375memset(&cipher_ctx->sess, 0, sizeof(cipher_ctx->sess));376return 1;377378default:379break;380}381382return -1;383}384385static int cipher_cleanup(EVP_CIPHER_CTX *ctx)386{387struct cipher_ctx *cipher_ctx = (struct cipher_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);388389return clean_devcrypto_session(&cipher_ctx->sess);390}391392/*393* Keep tables of known nids, associated methods, selected ciphers, and driver394* info.395* Note that known_cipher_nids[] isn't necessarily indexed the same way as396* cipher_data[] above, which the other tables are.397*/398static int known_cipher_nids[OSSL_NELEM(cipher_data)];399static int known_cipher_nids_amount = -1; /* -1 indicates not yet initialised */400static EVP_CIPHER *known_cipher_methods[OSSL_NELEM(cipher_data)] = {401NULL,402};403static int selected_ciphers[OSSL_NELEM(cipher_data)];404static struct driver_info_st cipher_driver_info[OSSL_NELEM(cipher_data)];405406static int devcrypto_test_cipher(size_t cipher_data_index)407{408return (cipher_driver_info[cipher_data_index].status == DEVCRYPTO_STATUS_USABLE409&& selected_ciphers[cipher_data_index] == 1410&& (cipher_driver_info[cipher_data_index].accelerated411== DEVCRYPTO_ACCELERATED412|| use_softdrivers == DEVCRYPTO_USE_SOFTWARE413|| (cipher_driver_info[cipher_data_index].accelerated414!= DEVCRYPTO_NOT_ACCELERATED415&& use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));416}417418static void prepare_cipher_methods(void)419{420size_t i;421session_op_t sess;422unsigned long cipher_mode;423#ifdef CIOCGSESSION2424struct crypt_find_op fop;425enum devcrypto_accelerated_t accelerated;426#elif defined(CIOCGSESSINFO)427struct session_info_op siop;428#endif429430memset(&cipher_driver_info, 0, sizeof(cipher_driver_info));431432memset(&sess, 0, sizeof(sess));433sess.key = (void *)"01234567890123456789012345678901234567890123456789";434435for (i = 0, known_cipher_nids_amount = 0;436i < OSSL_NELEM(cipher_data); i++) {437438selected_ciphers[i] = 1;439/*440* Check that the cipher is usable441*/442sess.cipher = cipher_data[i].devcryptoid;443sess.keylen = cipher_data[i].keylen;444#ifdef CIOCGSESSION2445/*446* When using CIOCGSESSION2, first try to allocate a hardware447* ("accelerated") session. If that fails, fall back to448* allocating a software session.449*/450sess.crid = CRYPTO_FLAG_HARDWARE;451if (ioctl(cfd, CIOCGSESSION2, &sess) == 0) {452accelerated = DEVCRYPTO_ACCELERATED;453} else {454sess.crid = CRYPTO_FLAG_SOFTWARE;455if (ioctl(cfd, CIOCGSESSION2, &sess) < 0) {456cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;457continue;458}459accelerated = DEVCRYPTO_NOT_ACCELERATED;460}461#else462if (ioctl(cfd, CIOCGSESSION, &sess) < 0) {463cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;464continue;465}466#endif467468cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE;469470if ((known_cipher_methods[i] = EVP_CIPHER_meth_new(cipher_data[i].nid,471cipher_mode == EVP_CIPH_CTR_MODE ? 1 : cipher_data[i].blocksize,472cipher_data[i].keylen))473== NULL474|| !EVP_CIPHER_meth_set_iv_length(known_cipher_methods[i],475cipher_data[i].ivlen)476|| !EVP_CIPHER_meth_set_flags(known_cipher_methods[i],477cipher_data[i].flags478| EVP_CIPH_CUSTOM_COPY479| EVP_CIPH_CTRL_INIT480| EVP_CIPH_FLAG_DEFAULT_ASN1)481|| !EVP_CIPHER_meth_set_init(known_cipher_methods[i], cipher_init)482|| !EVP_CIPHER_meth_set_do_cipher(known_cipher_methods[i],483cipher_mode == EVP_CIPH_CTR_MODE ? ctr_do_cipher : cipher_do_cipher)484|| !EVP_CIPHER_meth_set_ctrl(known_cipher_methods[i], cipher_ctrl)485|| !EVP_CIPHER_meth_set_cleanup(known_cipher_methods[i],486cipher_cleanup)487|| !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i],488sizeof(struct cipher_ctx))) {489cipher_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;490EVP_CIPHER_meth_free(known_cipher_methods[i]);491known_cipher_methods[i] = NULL;492} else {493cipher_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;494#ifdef CIOCGSESSION2495cipher_driver_info[i].accelerated = accelerated;496fop.crid = sess.crid;497if (ioctl(cfd, CIOCFINDDEV, &fop) == 0) {498cipher_driver_info[i].driver_name = OPENSSL_strndup(fop.name, sizeof(fop.name));499}500#elif defined(CIOCGSESSINFO)501siop.ses = sess.ses;502if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {503cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;504} else {505cipher_driver_info[i].driver_name = OPENSSL_strndup(siop.cipher_info.cra_driver_name,506CRYPTODEV_MAX_ALG_NAME);507if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))508cipher_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;509else510cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;511}512#endif /* CIOCGSESSINFO */513}514ioctl(cfd, CIOCFSESSION, &sess.ses);515if (devcrypto_test_cipher(i)) {516known_cipher_nids[known_cipher_nids_amount++] = cipher_data[i].nid;517}518}519}520521static void rebuild_known_cipher_nids(ENGINE *e)522{523size_t i;524525for (i = 0, known_cipher_nids_amount = 0; i < OSSL_NELEM(cipher_data); i++) {526if (devcrypto_test_cipher(i))527known_cipher_nids[known_cipher_nids_amount++] = cipher_data[i].nid;528}529ENGINE_unregister_ciphers(e);530ENGINE_register_ciphers(e);531}532533static const EVP_CIPHER *get_cipher_method(int nid)534{535size_t i = get_cipher_data_index(nid);536537if (i == (size_t)-1)538return NULL;539return known_cipher_methods[i];540}541542static int get_cipher_nids(const int **nids)543{544*nids = known_cipher_nids;545return known_cipher_nids_amount;546}547548static void destroy_cipher_method(int nid)549{550size_t i = get_cipher_data_index(nid);551552EVP_CIPHER_meth_free(known_cipher_methods[i]);553known_cipher_methods[i] = NULL;554}555556static void destroy_all_cipher_methods(void)557{558size_t i;559560for (i = 0; i < OSSL_NELEM(cipher_data); i++) {561destroy_cipher_method(cipher_data[i].nid);562OPENSSL_free(cipher_driver_info[i].driver_name);563cipher_driver_info[i].driver_name = NULL;564}565}566567static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,568const int **nids, int nid)569{570if (cipher == NULL)571return get_cipher_nids(nids);572573*cipher = get_cipher_method(nid);574575return *cipher != NULL;576}577578static void devcrypto_select_all_ciphers(int *cipher_list)579{580size_t i;581582for (i = 0; i < OSSL_NELEM(cipher_data); i++)583cipher_list[i] = 1;584}585586static int cryptodev_select_cipher_cb(const char *str, int len, void *usr)587{588int *cipher_list = (int *)usr;589char *name;590const EVP_CIPHER *EVP;591size_t i;592593if (len == 0)594return 1;595if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)596return 0;597EVP = EVP_get_cipherbyname(name);598if (EVP == NULL)599fprintf(stderr, "devcrypto: unknown cipher %s\n", name);600else if ((i = find_cipher_data_index(EVP_CIPHER_get_nid(EVP))) != (size_t)-1)601cipher_list[i] = 1;602else603fprintf(stderr, "devcrypto: cipher %s not available\n", name);604OPENSSL_free(name);605return 1;606}607608static void dump_cipher_info(void)609{610size_t i;611const char *name;612613fprintf(stderr, "Information about ciphers supported by the /dev/crypto"614" engine:\n");615#ifndef CIOCGSESSINFO616fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");617#endif618for (i = 0; i < OSSL_NELEM(cipher_data); i++) {619name = OBJ_nid2sn(cipher_data[i].nid);620fprintf(stderr, "Cipher %s, NID=%d, /dev/crypto info: id=%d, ",621name ? name : "unknown", cipher_data[i].nid,622cipher_data[i].devcryptoid);623if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION) {624fprintf(stderr, "CIOCGSESSION (session open call) failed\n");625continue;626}627fprintf(stderr, "driver=%s ", cipher_driver_info[i].driver_name ? cipher_driver_info[i].driver_name : "unknown");628if (cipher_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)629fprintf(stderr, "(hw accelerated)");630else if (cipher_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)631fprintf(stderr, "(software)");632else633fprintf(stderr, "(acceleration status unknown)");634if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)635fprintf(stderr, ". Cipher setup failed");636fprintf(stderr, "\n");637}638fprintf(stderr, "\n");639}640641/*642* We only support digests if the cryptodev implementation supports multiple643* data updates and session copying. Otherwise, we would be forced to maintain644* a cache, which is perilous if there's a lot of data coming in (if someone645* wants to checksum an OpenSSL tarball, for example).646*/647#if defined(CIOCCPHASH) && defined(COP_FLAG_UPDATE) && defined(COP_FLAG_FINAL)648#define IMPLEMENT_DIGEST649650/******************************************************************************651*652* Digests653*654* Because they all do the same basic operation, we have only one set of655* method functions for them all to share, and a mapping table between656* NIDs and cryptodev IDs, with all the necessary size data.657*658*****/659660struct digest_ctx {661session_op_t sess;662/* This signals that the init function was called, not that it succeeded. */663int init_called;664unsigned char digest_res[HASH_MAX_LEN];665};666667static const struct digest_data_st {668int nid;669int blocksize;670int digestlen;671int devcryptoid;672} digest_data[] = {673#ifndef OPENSSL_NO_MD5674{ NID_md5, /* MD5_CBLOCK */ 64, 16, CRYPTO_MD5 },675#endif676{ NID_sha1, SHA_CBLOCK, 20, CRYPTO_SHA1 },677#ifndef OPENSSL_NO_RMD160678#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_RIPEMD160)679{ NID_ripemd160, /* RIPEMD160_CBLOCK */ 64, 20, CRYPTO_RIPEMD160 },680#endif681#endif682#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_224)683{ NID_sha224, SHA256_CBLOCK, 224 / 8, CRYPTO_SHA2_224 },684#endif685#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_256)686{ NID_sha256, SHA256_CBLOCK, 256 / 8, CRYPTO_SHA2_256 },687#endif688#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_384)689{ NID_sha384, SHA512_CBLOCK, 384 / 8, CRYPTO_SHA2_384 },690#endif691#if !defined(CHECK_BSD_STYLE_MACROS) || defined(CRYPTO_SHA2_512)692{ NID_sha512, SHA512_CBLOCK, 512 / 8, CRYPTO_SHA2_512 },693#endif694};695696static size_t find_digest_data_index(int nid)697{698size_t i;699700for (i = 0; i < OSSL_NELEM(digest_data); i++)701if (nid == digest_data[i].nid)702return i;703return (size_t)-1;704}705706static size_t get_digest_data_index(int nid)707{708size_t i = find_digest_data_index(nid);709710if (i != (size_t)-1)711return i;712713/*714* Code further down must make sure that only NIDs in the table above715* are used. If any other NID reaches this function, there's a grave716* coding error further down.717*/718assert("Code that never should be reached" == NULL);719return -1;720}721722static const struct digest_data_st *get_digest_data(int nid)723{724return &digest_data[get_digest_data_index(nid)];725}726727/*728* Following are the five necessary functions to map OpenSSL functionality729* with cryptodev: init, update, final, cleanup, and copy.730*/731732static int digest_init(EVP_MD_CTX *ctx)733{734struct digest_ctx *digest_ctx = (struct digest_ctx *)EVP_MD_CTX_get0_md_data(ctx);735const struct digest_data_st *digest_d = get_digest_data(EVP_MD_CTX_get_type(ctx));736737digest_ctx->init_called = 1;738739memset(&digest_ctx->sess, 0, sizeof(digest_ctx->sess));740digest_ctx->sess.mac = digest_d->devcryptoid;741if (ioctl(cfd, CIOCGSESSION, &digest_ctx->sess) < 0) {742ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");743return 0;744}745return 1;746}747748static int digest_op(struct digest_ctx *ctx, const void *src, size_t srclen,749void *res, unsigned int flags)750{751struct crypt_op cryp;752753memset(&cryp, 0, sizeof(cryp));754cryp.ses = ctx->sess.ses;755cryp.len = srclen;756cryp.src = (void *)src;757cryp.dst = NULL;758cryp.mac = res;759cryp.flags = flags;760return ioctl(cfd, CIOCCRYPT, &cryp);761}762763static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)764{765struct digest_ctx *digest_ctx = (struct digest_ctx *)EVP_MD_CTX_get0_md_data(ctx);766767if (count == 0)768return 1;769770if (digest_ctx == NULL)771return 0;772773if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {774if (digest_op(digest_ctx, data, count, digest_ctx->digest_res, 0) >= 0)775return 1;776} else if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) >= 0) {777return 1;778}779780ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");781return 0;782}783784static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)785{786struct digest_ctx *digest_ctx = (struct digest_ctx *)EVP_MD_CTX_get0_md_data(ctx);787788if (md == NULL || digest_ctx == NULL)789return 0;790791if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {792memcpy(md, digest_ctx->digest_res, EVP_MD_CTX_get_size(ctx));793} else if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {794ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");795return 0;796}797798return 1;799}800801static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from)802{803struct digest_ctx *digest_from = (struct digest_ctx *)EVP_MD_CTX_get0_md_data(from);804struct digest_ctx *digest_to = (struct digest_ctx *)EVP_MD_CTX_get0_md_data(to);805struct cphash_op cphash;806807if (digest_from == NULL || digest_from->init_called != 1)808return 1;809810if (!digest_init(to)) {811ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");812return 0;813}814815cphash.src_ses = digest_from->sess.ses;816cphash.dst_ses = digest_to->sess.ses;817if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {818ERR_raise_data(ERR_LIB_SYS, errno, "calling ioctl()");819return 0;820}821return 1;822}823824static int digest_cleanup(EVP_MD_CTX *ctx)825{826struct digest_ctx *digest_ctx = (struct digest_ctx *)EVP_MD_CTX_get0_md_data(ctx);827828if (digest_ctx == NULL)829return 1;830831return clean_devcrypto_session(&digest_ctx->sess);832}833834/*835* Keep tables of known nids, associated methods, selected digests, and836* driver info.837* Note that known_digest_nids[] isn't necessarily indexed the same way as838* digest_data[] above, which the other tables are.839*/840static int known_digest_nids[OSSL_NELEM(digest_data)];841static int known_digest_nids_amount = -1; /* -1 indicates not yet initialised */842static EVP_MD *known_digest_methods[OSSL_NELEM(digest_data)] = {843NULL,844};845static int selected_digests[OSSL_NELEM(digest_data)];846static struct driver_info_st digest_driver_info[OSSL_NELEM(digest_data)];847848static int devcrypto_test_digest(size_t digest_data_index)849{850return (digest_driver_info[digest_data_index].status == DEVCRYPTO_STATUS_USABLE851&& selected_digests[digest_data_index] == 1852&& (digest_driver_info[digest_data_index].accelerated853== DEVCRYPTO_ACCELERATED854|| use_softdrivers == DEVCRYPTO_USE_SOFTWARE855|| (digest_driver_info[digest_data_index].accelerated856!= DEVCRYPTO_NOT_ACCELERATED857&& use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));858}859860static void rebuild_known_digest_nids(ENGINE *e)861{862size_t i;863864for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data); i++) {865if (devcrypto_test_digest(i))866known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;867}868ENGINE_unregister_digests(e);869ENGINE_register_digests(e);870}871872static void prepare_digest_methods(void)873{874size_t i;875session_op_t sess1, sess2;876#ifdef CIOCGSESSINFO877struct session_info_op siop;878#endif879struct cphash_op cphash;880881memset(&digest_driver_info, 0, sizeof(digest_driver_info));882883memset(&sess1, 0, sizeof(sess1));884memset(&sess2, 0, sizeof(sess2));885886for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data);887i++) {888889selected_digests[i] = 1;890891/*892* Check that the digest is usable893*/894sess1.mac = digest_data[i].devcryptoid;895sess2.ses = 0;896if (ioctl(cfd, CIOCGSESSION, &sess1) < 0) {897digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;898goto finish;899}900901#ifdef CIOCGSESSINFO902/* gather hardware acceleration info from the driver */903siop.ses = sess1.ses;904if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {905digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;906} else {907digest_driver_info[i].driver_name = OPENSSL_strndup(siop.hash_info.cra_driver_name,908CRYPTODEV_MAX_ALG_NAME);909if (siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)910digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;911else912digest_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;913}914#endif915916/* digest must be capable of hash state copy */917sess2.mac = sess1.mac;918if (ioctl(cfd, CIOCGSESSION, &sess2) < 0) {919digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;920goto finish;921}922cphash.src_ses = sess1.ses;923cphash.dst_ses = sess2.ses;924if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {925digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCCPHASH;926goto finish;927}928if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid,929NID_undef))930== NULL931|| !EVP_MD_meth_set_input_blocksize(known_digest_methods[i],932digest_data[i].blocksize)933|| !EVP_MD_meth_set_result_size(known_digest_methods[i],934digest_data[i].digestlen)935|| !EVP_MD_meth_set_init(known_digest_methods[i], digest_init)936|| !EVP_MD_meth_set_update(known_digest_methods[i], digest_update)937|| !EVP_MD_meth_set_final(known_digest_methods[i], digest_final)938|| !EVP_MD_meth_set_copy(known_digest_methods[i], digest_copy)939|| !EVP_MD_meth_set_cleanup(known_digest_methods[i], digest_cleanup)940|| !EVP_MD_meth_set_app_datasize(known_digest_methods[i],941sizeof(struct digest_ctx))) {942digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;943EVP_MD_meth_free(known_digest_methods[i]);944known_digest_methods[i] = NULL;945goto finish;946}947digest_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;948finish:949ioctl(cfd, CIOCFSESSION, &sess1.ses);950if (sess2.ses != 0)951ioctl(cfd, CIOCFSESSION, &sess2.ses);952if (devcrypto_test_digest(i))953known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;954}955}956957static const EVP_MD *get_digest_method(int nid)958{959size_t i = get_digest_data_index(nid);960961if (i == (size_t)-1)962return NULL;963return known_digest_methods[i];964}965966static int get_digest_nids(const int **nids)967{968*nids = known_digest_nids;969return known_digest_nids_amount;970}971972static void destroy_digest_method(int nid)973{974size_t i = get_digest_data_index(nid);975976EVP_MD_meth_free(known_digest_methods[i]);977known_digest_methods[i] = NULL;978}979980static void destroy_all_digest_methods(void)981{982size_t i;983984for (i = 0; i < OSSL_NELEM(digest_data); i++) {985destroy_digest_method(digest_data[i].nid);986OPENSSL_free(digest_driver_info[i].driver_name);987digest_driver_info[i].driver_name = NULL;988}989}990991static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,992const int **nids, int nid)993{994if (digest == NULL)995return get_digest_nids(nids);996997*digest = get_digest_method(nid);998999return *digest != NULL;1000}10011002static void devcrypto_select_all_digests(int *digest_list)1003{1004size_t i;10051006for (i = 0; i < OSSL_NELEM(digest_data); i++)1007digest_list[i] = 1;1008}10091010static int cryptodev_select_digest_cb(const char *str, int len, void *usr)1011{1012int *digest_list = (int *)usr;1013char *name;1014const EVP_MD *EVP;1015size_t i;10161017if (len == 0)1018return 1;1019if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)1020return 0;1021EVP = EVP_get_digestbyname(name);1022if (EVP == NULL)1023fprintf(stderr, "devcrypto: unknown digest %s\n", name);1024else if ((i = find_digest_data_index(EVP_MD_get_type(EVP))) != (size_t)-1)1025digest_list[i] = 1;1026else1027fprintf(stderr, "devcrypto: digest %s not available\n", name);1028OPENSSL_free(name);1029return 1;1030}10311032static void dump_digest_info(void)1033{1034size_t i;1035const char *name;10361037fprintf(stderr, "Information about digests supported by the /dev/crypto"1038" engine:\n");1039#ifndef CIOCGSESSINFO1040fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");1041#endif10421043for (i = 0; i < OSSL_NELEM(digest_data); i++) {1044name = OBJ_nid2sn(digest_data[i].nid);1045fprintf(stderr, "Digest %s, NID=%d, /dev/crypto info: id=%d, driver=%s",1046name ? name : "unknown", digest_data[i].nid,1047digest_data[i].devcryptoid,1048digest_driver_info[i].driver_name ? digest_driver_info[i].driver_name : "unknown");1049if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION) {1050fprintf(stderr, ". CIOCGSESSION (session open) failed\n");1051continue;1052}1053if (digest_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)1054fprintf(stderr, " (hw accelerated)");1055else if (digest_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)1056fprintf(stderr, " (software)");1057else1058fprintf(stderr, " (acceleration status unknown)");1059if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)1060fprintf(stderr, ". Cipher setup failed\n");1061else if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCCPHASH)1062fprintf(stderr, ", CIOCCPHASH failed\n");1063else1064fprintf(stderr, ", CIOCCPHASH capable\n");1065}1066fprintf(stderr, "\n");1067}10681069#endif10701071/******************************************************************************1072*1073* CONTROL COMMANDS1074*1075*****/10761077#define DEVCRYPTO_CMD_USE_SOFTDRIVERS ENGINE_CMD_BASE1078#define DEVCRYPTO_CMD_CIPHERS (ENGINE_CMD_BASE + 1)1079#define DEVCRYPTO_CMD_DIGESTS (ENGINE_CMD_BASE + 2)1080#define DEVCRYPTO_CMD_DUMP_INFO (ENGINE_CMD_BASE + 3)10811082static const ENGINE_CMD_DEFN devcrypto_cmds[] = {1083#if defined(CIOCGSESSINFO) || defined(CIOCGSESSION2)1084{ DEVCRYPTO_CMD_USE_SOFTDRIVERS,1085"USE_SOFTDRIVERS",1086"specifies whether to use software (not accelerated) drivers (" OPENSSL_MSTR(DEVCRYPTO_REQUIRE_ACCELERATED) "=use only accelerated drivers, " OPENSSL_MSTR(DEVCRYPTO_USE_SOFTWARE) "=allow all drivers, " OPENSSL_MSTR(DEVCRYPTO_REJECT_SOFTWARE) "=use if acceleration can't be determined) [default=" OPENSSL_MSTR(DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS) "]",1087ENGINE_CMD_FLAG_NUMERIC },1088#endif10891090{ DEVCRYPTO_CMD_CIPHERS,1091"CIPHERS",1092"either ALL, NONE, or a comma-separated list of ciphers to enable [default=ALL]",1093ENGINE_CMD_FLAG_STRING },10941095#ifdef IMPLEMENT_DIGEST1096{ DEVCRYPTO_CMD_DIGESTS,1097"DIGESTS",1098"either ALL, NONE, or a comma-separated list of digests to enable [default=ALL]",1099ENGINE_CMD_FLAG_STRING },1100#endif11011102{ DEVCRYPTO_CMD_DUMP_INFO,1103"DUMP_INFO",1104"dump info about each algorithm to stderr; use 'openssl engine -pre DUMP_INFO devcrypto'",1105ENGINE_CMD_FLAG_NO_INPUT },11061107{ 0, NULL, NULL, 0 }1108};11091110static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))1111{1112int *new_list;1113switch (cmd) {1114#if defined(CIOCGSESSINFO) || defined(CIOCGSESSION2)1115case DEVCRYPTO_CMD_USE_SOFTDRIVERS:1116switch (i) {1117case DEVCRYPTO_REQUIRE_ACCELERATED:1118case DEVCRYPTO_USE_SOFTWARE:1119case DEVCRYPTO_REJECT_SOFTWARE:1120break;1121default:1122fprintf(stderr, "devcrypto: invalid value (%ld) for USE_SOFTDRIVERS\n", i);1123return 0;1124}1125if (use_softdrivers == i)1126return 1;1127use_softdrivers = i;1128#ifdef IMPLEMENT_DIGEST1129rebuild_known_digest_nids(e);1130#endif1131rebuild_known_cipher_nids(e);1132return 1;1133#endif /* CIOCGSESSINFO || CIOCGSESSION2 */11341135case DEVCRYPTO_CMD_CIPHERS:1136if (p == NULL)1137return 1;1138if (OPENSSL_strcasecmp((const char *)p, "ALL") == 0) {1139devcrypto_select_all_ciphers(selected_ciphers);1140} else if (OPENSSL_strcasecmp((const char *)p, "NONE") == 0) {1141memset(selected_ciphers, 0, sizeof(selected_ciphers));1142} else {1143new_list = OPENSSL_zalloc(sizeof(selected_ciphers));1144if (!CONF_parse_list(p, ',', 1, cryptodev_select_cipher_cb, new_list)) {1145OPENSSL_free(new_list);1146return 0;1147}1148memcpy(selected_ciphers, new_list, sizeof(selected_ciphers));1149OPENSSL_free(new_list);1150}1151rebuild_known_cipher_nids(e);1152return 1;11531154#ifdef IMPLEMENT_DIGEST1155case DEVCRYPTO_CMD_DIGESTS:1156if (p == NULL)1157return 1;1158if (OPENSSL_strcasecmp((const char *)p, "ALL") == 0) {1159devcrypto_select_all_digests(selected_digests);1160} else if (OPENSSL_strcasecmp((const char *)p, "NONE") == 0) {1161memset(selected_digests, 0, sizeof(selected_digests));1162} else {1163new_list = OPENSSL_zalloc(sizeof(selected_digests));1164if (!CONF_parse_list(p, ',', 1, cryptodev_select_digest_cb, new_list)) {1165OPENSSL_free(new_list);1166return 0;1167}1168memcpy(selected_digests, new_list, sizeof(selected_digests));1169OPENSSL_free(new_list);1170}1171rebuild_known_digest_nids(e);1172return 1;1173#endif /* IMPLEMENT_DIGEST */11741175case DEVCRYPTO_CMD_DUMP_INFO:1176dump_cipher_info();1177#ifdef IMPLEMENT_DIGEST1178dump_digest_info();1179#endif1180return 1;11811182default:1183break;1184}1185return 0;1186}11871188/******************************************************************************1189*1190* LOAD / UNLOAD1191*1192*****/11931194/*1195* Opens /dev/crypto1196*/1197static int open_devcrypto(void)1198{1199int fd;12001201if (cfd >= 0)1202return 1;12031204if ((fd = open("/dev/crypto", O_RDWR, 0)) < 0) {1205#ifndef ENGINE_DEVCRYPTO_DEBUG1206if (errno != ENOENT && errno != ENXIO)1207#endif1208fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));1209return 0;1210}12111212#ifdef CRIOGET1213if (ioctl(fd, CRIOGET, &cfd) < 0) {1214fprintf(stderr, "Could not create crypto fd: %s\n", strerror(errno));1215close(fd);1216cfd = -1;1217return 0;1218}1219close(fd);1220#else1221cfd = fd;1222#endif12231224return 1;1225}12261227static int close_devcrypto(void)1228{1229int ret;12301231if (cfd < 0)1232return 1;1233ret = close(cfd);1234cfd = -1;1235if (ret != 0) {1236fprintf(stderr, "Error closing /dev/crypto: %s\n", strerror(errno));1237return 0;1238}1239return 1;1240}12411242static int devcrypto_unload(ENGINE *e)1243{1244destroy_all_cipher_methods();1245#ifdef IMPLEMENT_DIGEST1246destroy_all_digest_methods();1247#endif12481249close_devcrypto();12501251return 1;1252}12531254static int bind_devcrypto(ENGINE *e)1255{12561257if (!ENGINE_set_id(e, engine_devcrypto_id)1258|| !ENGINE_set_name(e, "/dev/crypto engine")1259|| !ENGINE_set_destroy_function(e, devcrypto_unload)1260|| !ENGINE_set_cmd_defns(e, devcrypto_cmds)1261|| !ENGINE_set_ctrl_function(e, devcrypto_ctrl))1262return 0;12631264prepare_cipher_methods();1265#ifdef IMPLEMENT_DIGEST1266prepare_digest_methods();1267#endif12681269return (ENGINE_set_ciphers(e, devcrypto_ciphers)1270#ifdef IMPLEMENT_DIGEST1271&& ENGINE_set_digests(e, devcrypto_digests)1272#endif1273/*1274* Asymmetric ciphers aren't well supported with /dev/crypto. Among the BSD1275* implementations, it seems to only exist in FreeBSD, and regarding the1276* parameters in its crypt_kop, the manual crypto(4) has this to say:1277*1278* The semantics of these arguments are currently undocumented.1279*1280* Reading through the FreeBSD source code doesn't give much more than1281* their CRK_MOD_EXP implementation for ubsec.1282*1283* It doesn't look much better with cryptodev-linux. They have the crypt_kop1284* structure as well as the command (CRK_*) in cryptodev.h, but no support1285* seems to be implemented at all for the moment.1286*1287* At the time of writing, it seems impossible to write proper support for1288* FreeBSD's asym features without some very deep knowledge and access to1289* specific kernel modules.1290*1291* /Richard Levitte, 2017-05-111292*/1293#if 01294&& ENGINE_set_RSA(e, devcrypto_rsa)1295#ifndef OPENSSL_NO_DSA1296&& ENGINE_set_DSA(e, devcrypto_dsa)1297#endif1298#ifndef OPENSSL_NO_DH1299&& ENGINE_set_DH(e, devcrypto_dh)1300#endif1301#ifndef OPENSSL_NO_EC1302&& ENGINE_set_EC(e, devcrypto_ec)1303#endif1304#endif1305);1306}13071308#ifdef OPENSSL_NO_DYNAMIC_ENGINE1309/*1310* In case this engine is built into libcrypto, then it doesn't offer any1311* ability to be dynamically loadable.1312*/1313void engine_load_devcrypto_int(void)1314{1315ENGINE *e = NULL;13161317if (!open_devcrypto())1318return;13191320if ((e = ENGINE_new()) == NULL1321|| !bind_devcrypto(e)) {1322close_devcrypto();1323ENGINE_free(e);1324return;1325}13261327ERR_set_mark();1328ENGINE_add(e);1329/*1330* If the "add" worked, it gets a structural reference. So either way, we1331* release our just-created reference.1332*/1333ENGINE_free(e); /* Loose our local reference */1334/*1335* If the "add" didn't work, it was probably a conflict because it was1336* already added (eg. someone calling ENGINE_load_blah then calling1337* ENGINE_load_builtin_engines() perhaps).1338*/1339ERR_pop_to_mark();1340}13411342#else13431344static int bind_helper(ENGINE *e, const char *id)1345{1346if ((id && (strcmp(id, engine_devcrypto_id) != 0))1347|| !open_devcrypto())1348return 0;1349if (!bind_devcrypto(e)) {1350close_devcrypto();1351return 0;1352}1353return 1;1354}13551356IMPLEMENT_DYNAMIC_CHECK_FN()1357IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)13581359#endif136013611362